「LangChain」使用 LangChain 构建 Agent 的核心步骤?

0 前言

本文内容整理自公众号「小林面试笔记」的文章 4. 使用 LangChain 构建 Agent 的核心步骤是什么?,用于记录与总结 LangChain 框架相关的核心面试知识点。

使用 LangChain 构建 Agent 的核心步骤是什么?」,可以这样作答:

构建一个能上线的 Agent,不是把模型和几个工具组装起来让它跑通一次调用,而是走完一条工程链路:先明确任务边界——能做什么、不能做什么、何时结束、什么结果算成功;再选支持工具调用和结构化输出的模型,把外部能力封装成职责单一、Schema 清晰的 Tools;随后用 system_prompt 约束角色与工具规则,用 response_format 定义结构化输出,通过 create_agent 把模型、工具、提示词和输出格式组装起来,底层由 LangGraph 在「模型判断 → 工具执行 → 结果回传」之间循环;接着补状态与安全——Checkpointer 按 thread_id 保存线程状态,Store 管理跨线程信息,Middleware 承担重试、摘要、权限控制和人工审批;再按场景选择同步、异步或流式调用;最后先单测 Tool,再测工具选择与调用轨迹,用 Trace 做线上监控。

这道题的经典开场是:面试官问「如果让你用 LangChain 构建一个完整的 AI Agent,你会怎么做?」,回答「选个大模型、写好 Prompt、接几个工具就完成了」——那是能跑的 Demo,不是能上线的 Agent。真正的考察点不在几行初始化代码,而在你能否把 Agent 从需求定义一路做到可测试、可观测、可上线。上一篇我们拆解过 LangChain v1 的底层架构(create_agent 编译出的 LangGraph 循环、State/Context/Store 的数据分工),这篇就按构建顺序,把从零做一个 Agent 的完整链路讲透。


1 什么才算一个完整 Agent

先和自己对齐标准:模型成功调用了一次天气工具,这算不算完整 Agent?不算——这只是「Demo 跑通」

把 Agent 放进真实业务里,要回答的问题立刻变多:它到底能做什么、不能做什么;模型选中了一个工具,参数对不对;工具失败或重复调用,会不会产生副作用;会话中断能不能恢复;最终结果能不能稳定地进入业务系统;线上出错了能不能复现。

一句话:完整 Agent 不是一次模型调用,而是一条从任务设计、能力接入、运行控制走到测试监控的工程链路。下面这张图就是这条链路的七个阶段,也是本文的结构——边界、能力、约束、组装、状态、交互、验证,缺一环都不算完整:

构建 Agent 的七个阶段:明确边界、选择模型与工具、约束行为、组装 Agent、补齐状态与安全、选择调用方式、测试与监控


2 第一步:明确任务边界

很多人第一步就选模型,这是本末倒置。先定义任务,再选工具和模型——边界不清楚,后面所有配置都是空中楼阁。

拿「订单客服 Agent」举例,边界长这样:

  • 能做什么:查订单状态、解释物流进度;
  • 不能做什么:不能自行退款(权限只到客服层);
  • 必须让位的情况:订单不存在、身份验证失败、用户要求高风险操作——一律转人工;
  • 什么算成功:最终输出包含「答复 + 订单状态 + 是否转人工」三项。

把边界说清楚,本质是做一遍「产品需求书」:先写目标与允许执行的动作,再划出禁止动作与权限边界,最后约定什么算成功、什么算失败、何时停止、哪些情况必须转人工。边界决定后面的工具设计、Prompt 措辞和测试用例——边界模糊,模型只能靠猜,事后想靠工程配置补回来基本是徒劳。


3 第二步:选择模型与封装 Tools

任务边界定了,才有资格谈选型。

模型看三条:是否支持工具调用、是否支持结构化输出、上下文长度够不够。要记住分工——模型负责判断和规划,访问数据库、搜索、发消息这些动作必须由 Tool 完成,模型本身不碰任何外部系统。

Tool 为什么要小而清楚?因为模型做选择时能看到的只有三样东西:工具的名称、描述、参数 Schema。一个工具同时管「查询 + 退款 + 通知」,模型很容易选错动作;参数没有类型和范围约束,运行时也拦不住错误输入。这就像银行的窗口:业务全挤在同一个柜台,柜员处理慢、还容易办错,改成「查询专窗」「汇款专窗」分工明细,客户排错队的概率就小了。

这里有两层原则要分开记:

  • 「选对」靠设计:Tool 职责单一、名称清楚、输入输出易理解——帮模型做对决策;
  • 「安全」靠防线:服务端重新检查身份与权限,改外部状态的工具必须有幂等和审计——保证系统即使被误导也不出事。
1
2
3
4
5
6
7
8
from langchain.tools import tool

# 装饰器会把函数名、docstring 和类型注解转换成模型可读的工具说明
@tool
def lookup_order(order_id: str) -> dict[str, str]:
"""根据订单号查询订单状态,只读,不修改订单。"""
# 真实项目应在这里调用经过身份校验的订单服务
return {"order_id": order_id, "status": "已发货"}

注意描述里的「只读」不是写给程序看的,是写给模型看的——工具描述是模型决策的信号;而真正的权限校验由业务服务负责。Prompt 里写再多的「禁止退款」,也替代不了退款接口本身的身份校验:

职责单一的专窗式工具对比:一个工具只做一件事、Schema 清晰,模型更容易选对


4 第三步:约束行为与输出

模型和工具就位,接下来是「立规矩」。

system_prompt 至少要说明五件事:角色(你是谁)、目标(你负责什么)、信息边界(哪些东西你不知道,不许猜)、工具规则(什么时候必须调工具)、失败策略(处理不了怎么办)。继续用订单客服的例子:回答订单状态前必须调用查询工具、不能猜测数据库里不存在的信息、高风险请求必须转人工——这些都是要在提示词里钉死的规则。

输出策略分两种情形:

  • 结果只给人看——自然语言回复就够了;
  • 结果要进前端、进工单系统、进后续工作流——必须定义结构化输出。

结构化输出可以理解为「填表单」:口头汇报随你怎么说,交到系统里的必须按表单字段填,字段类型错了程序直接报错。用 pydantic 定义 Schema,response_format 就会按它校验 Agent 的最终结果:

1
2
3
4
5
6
7
from pydantic import BaseModel, Field

# response_format 会按这三个字段校验 Agent 的最终结果
class SupportReply(BaseModel):
answer: str = Field(description="给用户的简洁答复")
order_status: str | None = Field(default=None, description="订单状态")
needs_human: bool = Field(description="是否需要转人工")

但有一句限制必须说清:结构化输出约束的是「格式」,不是「事实」。它能保证字段存在、类型正确,却保证不了业务内容正确——事实必须来自可信工具,权限必须由业务服务控制。这两条防线和上一节说的一样,不能因为加了 Schema 就放松。


5 第四步:组装 Agent

前面积累的材料(模型、工具、提示词、输出 Schema),这一步在 create_agent 里汇合。先明确立场:LangChain v1 新项目从 create_agent 开始;旧资料里的 create_tool_calling_agentAgentExecutor 只可能出现在存量项目里,网上很多示例还在这么写,那是旧版路径。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from langchain.agents import create_agent

# 将模型、工具、行为约束和输出 Schema 组装成 Agent
agent = create_agent(
model="openai:gpt-5.4-mini",
tools=[lookup_order],
system_prompt=(
"你是订单客服。回答订单状态前必须调用查询工具;"
"不得猜测,无法处理时设置转人工。"
),
response_format=SupportReply,
)

# messages 是 Agent State 的默认输入字段
result = agent.invoke({
"messages": [{"role": "user", "content": "订单 A100 到哪了?"}]
})

# 结构化结果已经通过 SupportReply 的字段校验
reply: SupportReply = result["structured_response"]

create_agent 返回的不是普通函数,而是编译后的 LangGraph 图。它的执行逻辑可以用一句话讲完——模型没有工具调用就输出最终结果;模型请求调用工具,运行时执行工具并把结果写回消息状态,再让模型继续判断:

1
2
3
用户消息 -> 模型判断
模型判断 -> 工具调用 -> ToolMessage -> 模型继续判断
模型判断 -> 最终结果(没有工具调用)

模型判断与工具执行之间的循环:请求工具调用则执行并回传 ToolMessage,否则输出最终结果

为什么强调从 create_agent 开始?因为这张图的循环、路由、状态更新、暂停恢复等生产能力,LangGraph 运行时已经全部给你了——自己用裸 while 循环写模型调用,这些能力一个都没有(上一篇聊架构时详述过这个循环的机制,tool_call_id 的对应关系也在那里讲过)。


6 第五步:补齐状态与安全

组件组装只是骨架,状态和权限才是生产环境的血肉

短期状态存在 Agent State 里。配上 Checkpointer 并稳定传 thread_id 之后,同一线程能续接之前的消息与执行状态——会话中断可以恢复。可以把 Checkpointer 想成游戏存档:跑到第几步、聊到哪一句,中断后再从存盘点继续,而不是一切从头再来。

跨线程信息(用户偏好、长期事实)放 Store,用 namespace + key 隔离租户与用户。它更像档案室里的花名册:不是某个对话的进度,而是这个用户长期不变的档案,任何线程都能查。

这里要专门辨析一句:Checkpointer 和 Store 都能落盘,但作用完全不同,不能混为一谈——一个存「这场对话进行到哪」,一个存「这个用户长期是什么样」,前者的作用域是线程,后者是跨线程。

Middleware 承接的是横切逻辑:重试、摘要、权限、审批这些往往同时影响多个模型/工具调用,散落在各个节点里会重复成灾难。它的典型场景:

  • 模型或只读工具临时失败 → 有上限的重试;
  • 上下文过长 → 模型调用前压缩历史;
  • 用户权限变化 → 动态隐藏工具;
  • 敏感动作 → 工具执行前暂停,等人工审批;
  • 模型输出后 → 补格式或安全检查。

Agent 的生产边界:状态持久化、权限控制与中间件拦截,共同把 Demo 变成可上线的业务系统

最后一条铁律:付款、发邮件、删除数据等工具必须具备幂等、最小权限和审计能力,自动重试绝不能导致重复扣款或重复发信——这是安全底线,不是可选项。


7 第六步:选择调用方式

Agent 组装完成,怎么调用它?按产品形态匹配,三种方式各有适用场景:

调用方式 适用场景
invoke 短任务、后台任务、等待最终结果
异步调用 并发 I/O、异步 Web 服务
stream 长任务,需要展示 Token、步骤或工具进度

一个容易踩的误区:流式输出改善的是等待体验,并不会自动缩短工具执行时间。工具真正要跑 3 秒,流式只是让用户先看到「正在查询」的进度,该等的还是要等。超时、取消、并发限制和缓存,属于另一套设计,需要单独做、单独测。


8 第七步:测试与监控

Agent 的输出是概率性的,所以测试不能只看最终文本对没对上,而要做三层递进:

  1. 第一层:单测 Tool——正常输入、非法参数、权限错误、超时、幂等性,都要覆盖。Tool 是相对确定的业务代码,是整个系统里最该先稳定下来的部分;
  2. 第二层:测 Agent 轨迹——有没有选对工具、参数传得对不对、有没有越权调用、结构化输出是否符合 Schema。这一步校验的不是「答得对不对」,而是过程
  3. 第三层:端到端评测 + 线上监控——把典型问题、边界案例、历史故障整理成数据集,对比模型、Prompt、Tool 不同版本的表现;上线后用 Trace 观察模型调用、工具调用、延迟、Token、失败率和人工转接率,线上出问题能顺着调用链定位到具体环节。

三层测试金字塔:底层单测 Tool,中层验证 Agent 轨迹,顶层做端到端评测与线上 Trace 监控

这就像做质检:零件先单独质检(Tool 单测),再查装配工艺有没有装错(轨迹测试),最后整车路测加售后数据监控(端到端 + Trace)——只测最后一句话,等于整车出厂只看外观。


9 上线前检查什么

临门一脚,对照这张清单逐项打勾:

  • ✅ 任务和停止条件是否明确;
  • ✅ Tool 是否职责单一,并在服务端校验权限;
  • ✅ 有副作用的操作是否具备幂等和审批;
  • ✅ Checkpointer 与 Store 是否使用持久化实现并做好用户隔离;
  • ✅ 是否设置超时、重试上限、并发和成本预算;
  • ✅ 是否覆盖工具、轨迹和端到端三层测试;
  • ✅ 是否能追踪一次失败运行的完整调用链。

七步走完 + 清单打勾通过,Agent 才算真正从「能跑的 Demo」变成了「能上线的系统」。


10 面试总结

回答这道题,最大的雷就是把「跑通一次工具调用」当成「构建了一个 Agent」。先避开几个误区:

误区 正解
选模型、写 Prompt、接几个工具就是完整 Agent 那只是 Demo;任务边界、工具权限、状态恢复、结构化输出、测试监控全都要做
第一步是选模型 第一步是明确任务边界——边界决定工具、Prompt 和测试用例,边界模糊后面补不回来
Prompt 里写「禁止退款」就安全了 Prompt 只是行为约束,权限校验与副作用控制必须由服务端负责
结构化输出保证结果正确 只约束字段与类型,不保证业务事实;事实来自可信工具,权限由业务服务控制
网上示例都用 AgentExecutor,照抄就行 那是旧版路径;LangChain v1 新项目从 create_agent 开始

再按这张框架组织答案:

环节 要点
明确边界 定义目标与允许动作、禁止动作与权限边界、成功/失败/停止标准、转人工条件
选择能力 选支持工具调用与结构化输出的模型;工具职责单一、Schema 清晰,服务端做权限与幂等
约束行为 system_prompt 约束角色、信息边界、工具规则、失败策略;response_format 定义结构化输出
组装 Agent create_agent 组合模型 + 工具 + 提示词 + 输出格式;底层 LangGraph 跑「模型判断 → 工具执行 → 结果回传」循环
状态与安全 Checkpointer 按 thread_id 保存线程状态(存档),Store 存跨线程信息(花名册),Middleware 挂重试/摘要/权限/审批
调用方式 invoke(短任务)、异步(并发)、stream(长任务进度);超时、取消、并发、缓存单独设计
测试监控 Tool 单测 → 轨迹测试 → 端到端评测 + 线上 Trace 监控

追问预案

  • 「完整 Agent 和跑通的 Demo 差在哪里?」——Demo 只证明一次调用能通;完整 Agent 还要有任务边界、工具权限、状态恢复、结构化输出与测试监控,是一条可测试、可观测、可上线的工程链路。
  • 「工具为什么必须职责单一?」——模型靠名称、描述、参数 Schema 做选择;一个工具管多件事容易选错动作,参数无类型与范围约束时运行时也拦不住错误输入。
  • 「Checkpointer 和 Store 都能持久化,怎么区分?」——作用域不同:Checkpointer 按 thread_id 保存单线程的会话与执行状态,支撑续接与中断恢复(游戏存档);Store 保存跨线程的长期信息如用户偏好与事实,用 namespace + key 隔离租户和用户(花名册)。
  • 「Prompt 约束和权限控制是什么关系?」——Prompt 只能约束模型行为(比如「禁止退款」);真正的权限与副作用必须由业务服务端校验,且自动重试不能导致重复扣款、重复发信。
  • 「Agent 的输出是概率性的,怎么测试?」——三层:单测 Tool(正常/非法/权限/超时/幂等)→ 轨迹测试(工具选择、参数、越权、Schema)→ 端到端数据集评测 + 线上 Trace 监控调用链。

参考

本文图片均来源于公众号「小林面试笔记」,版权归原作者所有。


「LangChain」使用 LangChain 构建 Agent 的核心步骤?
https://marisamagic.github.io/2026/08/24/20260824_LangChain构建Agent/
作者
MarisaMagic
发布于
2026年8月24日
许可协议