深入学LangChain 官方文档(五)Agent 核心循环首讲 深入学 LangChain 官方文档五Agent 核心循环首讲本篇对应的官方文档LangChain AgentsAgent、harness、create_agent、核心循环与调用方式。LangChain Tools工具请求、执行和ToolMessage回传在循环中的位置。LangChain Runtime运行期 context 与 state 的入口边界。本篇讲解范围本篇只讲 Agent 最核心的一件事一次用户请求怎样在模型与工具之间往返直到形成最终答案或被运行边界截停。工具 schema、ToolRuntime和返回值放在第 06 篇Runtime Context 与 State 的数据边界放在第 07 篇Memory 与 Middleware 还会在后续文章单独展开。前四篇我们已经把 LangChain 的几个基础对象分开了Model 负责推理Message 承载上下文Structured Output 把结果变成可校验对象。下面我们真正进入Agent模块。到了 Agent问题不再是“怎样调用一次模型”而是“当一次推理无法完成任务时谁负责继续往下走”。设想一个售后客服请求用户说耳机右侧没有声音想知道还能不能换货。模型可以解释一般规则却不知道这副耳机什么时候购买、订单是否属于当前用户、是否已经过了售后期。要给出可靠答复系统必须先查订单再查售后规则必要时补问序列号最后才能组织回复。下一步依赖上一步结果路径也无法在请求开始前完全写死这正是 Agent 发挥作用的位置。这条交替链是全文的路线用户消息先进入模型模型可以直接回答也可以提出工具调用工具执行后把事实写回消息序列模型依据新增事实继续判断。循环的价值不在“多调用几次模型”而在每一轮都能获得新的外部信息或完成一个受控动作。本篇会先判断什么任务真的需要 Agent再拆开 Model 与 harness 的职责随后沿一次invoke追踪 messages、tool_calls和ToolMessage怎样推进最后讨论停止条件、权限和排障顺序。读完以后你应该能把“Agent 很聪明”改写成一条可观察、可限制、可定位的执行链。1. 先判断任务是否真的需要 AgentAgent 不是所有 LLM 应用的默认形态。很多需求只需要一次模型调用例如改写一段文案、总结一页文本、按给定 schema 抽取字段。输入已经包含完成任务所需的信息输出也不需要访问外部系统那么增加工具循环只会引入更多延迟、成本和失败点。另一类需求虽然包含多个步骤却仍不一定需要 Agent。比如“读取文件、校验列名、写入数据库、生成报告”可以预先确定严格顺序任何一步失败都应该停止。这种任务更适合普通代码或固定 workflow分支由程序判断状态转换明确执行路径容易测试。让模型临时决定是否跳过校验反而会削弱可靠性。Agent 更适合第三类问题目标明确但下一步需要根据运行时结果决定。售后客服可能先查订单如果订单不存在需要补问如果仍在换货期需要检查库存如果涉及高价值商品还要转人工审批。这里的分支来自语义判断和外部事实组合数量又不适合全部写成硬编码流程。三种形态的关键区别是“下一步由谁决定”。固定代码把路径写在程序里workflow 允许预先定义的分支Agent 把部分选择交给模型但可用工具和执行边界仍由应用控制。是否使用 Agent应该由路径的不确定性决定而不是由任务听起来是否“智能”决定。可以用三个问题做快速筛选完成任务是否缺少运行时事实获得事实后是否可能改变下一步这些变化是否需要自然语言语义判断三个问题都成立Agent 才有明显价值。如果只是为了让代码看起来更像 AI 项目保持简单通常更稳。Agent 解决的是动态决策与受控行动的组合不是替代普通程序。这条边界决定了后面怎样理解核心循环循环不是无条件重复而是在新信息出现后重新选择下一步。还可以从“错误是否允许被模型解释”判断边界。税率计算、库存扣减和权限校验的结果必须由确定性程序给出模型只能决定何时请求、怎样向用户说明如果把计算规则本身交给模型临场发挥Agent 会把本来可测试的逻辑变成概率输出。适合交给模型的是语义路由和信息组织不适合交给模型的是必须逐次一致的业务约束。动态也不等于无限自由。售后 Agent 可以在“查订单、查规则、补问信息、转人工”之间选择但不应拥有任意 SQL、任意 HTTP 请求或任意脚本执行。工具集合越接近最小业务动作模型的选择空间越清楚应用也越容易逐项授权、记录和回放。2.Agent Model Harness到底在分什么LangChain 官方文档用一句很短的话概括 AgentAgent Model Harness。Model 是推理组件harness 是围绕循环的运行系统。两者一起工作但职责不能混在一起。Model 接收当前上下文生成下一步意图。它可能输出自然语言也可能输出结构化的tool_calls。它擅长根据用户目标、系统指令和已有事实做选择却不会因为生成了一个函数名就自动获得数据库连接、文件权限或支付能力。Harness 负责把意图变成一次受控运行。它把 system prompt、messages、可用 tools 和 middleware 组织起来发现tool_calls后调用真实函数把结果转换成ToolMessage再次调用模型还可以增加重试、调用次数限制、人工审批、日志和上下文管理。图中的分界线很重要模型负责“建议下一步”harness 负责“这一步能否以及怎样执行”。工具权限、参数校验、超时、审计和停止条件都不能只靠 prompt 约束它们必须落实在模型之外的运行层。这也解释了一个常见现象同一个模型放进不同 Agent行为差异可能很大。差异未必来自模型能力而可能来自工具描述、system prompt、上下文选择、middleware 或错误处理。反过来一个工具失败也不能简单归因于“模型不够聪明”它可能根本没有被正确注册或者返回结果没有回到对应的调用。把 Model 和 harness 分开后Agent 就不再是一个黑盒名称而是两组可以分别检查的对象。推理错误看模型输入与输出执行错误看工具和权限循环错误看 messages 与状态推进运行边界错误看 harness 配置。这层分工还决定了测试策略。Model 的选择可以用固定输入检查工具命中率、参数完整性和最终回答质量Tool 可以脱离模型做普通单元测试验证异常、超时和权限Harness 则用一条完整 trace 检查节点顺序、状态变化和出口。把三类测试混成一次端到端请求失败时很难知道究竟是哪一层变了。评估也应保留同样的边界。最终答案正确不代表过程安全模型可能调用了不必要的高成本工具或者先访问了无权读取的数据。反过来一次工具调用失败也不必直接判定整体任务失败harness 可能按照明确策略降级到补问或人工处理。结果质量和运行质量需要分别记录。3.create_agent装配的是一套运行关系LangChain 使用create_agent建立 Agent。最基础的三个输入是model、tools和system_prompt。它们不是“配置项列表”而是分别回答三个运行问题谁做推理、允许做什么、按照什么角色和原则做判断。model可以是模型标识或已经初始化的模型实例。本系列统一使用qwen3.7-plus但在 Agent 语境中真正要关注的不是供应商连接字段而是模型每一轮都接收当前 messages 和可用工具定义并返回下一步消息。tools是应用愿意暴露给模型选择的能力集合。工具越多不代表 Agent 越强。名称相近、描述重叠或权限过大的工具会让选择变难也会扩大风险面。第 06 篇会完整讲 tool schema本篇只把它看成循环中的“可选动作集合”。system_prompt用于设定角色、目标和行为原则。例如客服 Agent 可以被要求先核实订单再回答售后结论缺少事实时应明确补问不得编造订单状态。这些指令会影响模型决策但不会自动形成代码权限。即使 prompt 写了“不要执行未经确认的退款”高风险工具仍应在运行层校验身份并要求审批。装配关系形成后create_agent返回的是一个可调用图而不是一段更长的 prompt。模型节点负责推理工具节点负责执行state 在节点之间传递middleware 可以在调用前后介入。底层图结构让循环具备可观察和可扩展的运行位置。动态指令也不应该通过不断修改全局字符串实现。官方文档把运行时动态 prompt 放到 middleware它可以根据用户角色、会话阶段或 state 构造当前轮指令。固定原则适合直接写进system_prompt随运行变化的信息则应进入 Runtime Context、State 或 middleware。把所有内容拼进一个巨型 prompt会在第 08 篇的 Context Engineering 中看到更多问题。create_agent还可以接收response_format、checkpointer、context schema 和 middleware 等配置。它们分别改变结果合同、会话恢复、运行依赖和生命周期行为但不应在首讲里被压成一张“参数大全”。理解扩展项的办法仍然是问它修改了循环的哪个位置进入模型前、工具执行前后、state 写入时还是运行结束后。例如第 04 篇的response_format影响最终结果怎样进入structured_response却不会取消工具循环checkpointer 让同一thread_id的历史能够被恢复却不负责长期用户画像context 把本次运行依赖交给工具和 middleware却不必让模型看到。把配置映射到运行位置比背参数名更能避免误用。4. 一次invoke如何变成多轮循环调用 Agent 时输入不是裸字符串而是对 state 的一次更新。所有 LangChain Agent state 都包含 messages 序列因此最小输入通常是{messages:[{role:user,content:订单 A1024 的耳机右侧没有声音还能换货吗,}]}这条 user message 加入 state 后进入模型节点。模型会看到 system prompt、当前消息历史和工具 schema。如果现有信息足够它可以直接生成最终AIMessage如果缺少订单事实则会生成带tool_calls的AIMessage其中包含工具名称、参数和调用标识。Harness 读取tool_calls找到对应工具并执行。订单查询工具返回购买日期、商品状态和售后记录后结果会包装成ToolMessage并通过tool_call_id与原请求配对。新的消息序列再次进入模型模型这次不再只依赖用户描述而是拥有了订单事实。循环推进的载体是 state而 messages 是其中最基础的字段。每一轮不会抹掉上一轮的意图和结果用户请求、模型的工具调用、工具结果、模型的后续判断按顺序保留。模型因此能够知道“刚才查了什么、返回了什么、现在还缺什么”。这条消息链也带来成本。工具返回整份数据库记录、日志或 HTML会迅速占满上下文窗口错误结果如果没有清楚语义模型可能不断重复同一次调用。因此工具输出既要包含完成下一步所需的事实又要控制大小和敏感信息。循环能否稳定常常取决于结果怎样进入 messages而不仅是工具本身能不能运行。还要区分“一次 run 内的多轮循环”和“用户发起的下一轮会话”。前者发生在同一个invoke中模型与工具可以往返多次后者是用户过一会儿又发送新消息。若希望第二次调用恢复前文需要配置 checkpointer 并复用thread_id。没有持久化配置不能因为第一次 result 里有完整 messages就推断下一次调用会自动记住。这种区分会直接影响故障复现。一次 run 内重复调用工具要检查当前 trace 的节点和消息跨 turn 丢失上下文要检查 checkpointer 与thread_id。两者表面上都像“Agent 忘了”实际位于不同边界。模型生成工具调用应用执行工具结果再作为消息回到模型。这三个动作缺一不可。只打印tool_calls不执行任务不会前进执行工具却不返回ToolMessage模型不知道发生了什么返回结果没有正确配对并发调用时就可能把库存结果当成订单结果。这一次往返是 Agent loop 的最小可执行单元。AIMessage表达模型提出的动作工具节点把动作落到真实系统ToolMessage把可消费的结果送回同一条上下文链。第 06 篇会继续拆开 schema、隐藏参数和不同返回值本篇先把它们放回循环顺序中。5. Agent 怎样知道应该停下来最理想的出口是模型生成最终答案并且不再包含tool_calls。在客服案例中订单事实和售后规则都已获取模型可以明确说明是否在换货期、还需提供什么材料。Harness 识别到没有新的工具请求本次运行结束。但生产系统不能只等待模型“自觉结束”。模型可能因为工具描述含糊而在两个工具间来回选择也可能在外部服务持续失败时重复尝试。调用次数限制、超时、重试预算和总成本预算需要由运行层配置达到边界后系统应返回可识别的失败或转交状态。第三类出口是业务错误。订单不存在、用户无权访问、售后规则服务不可用都不是“继续推理就能自动解决”的问题。工具应返回清楚、可分类的结果模型才能补问、降级或向用户说明。把堆栈信息直接塞进上下文既可能泄露内部实现也无法提供可靠恢复策略。第四类出口是人工介入。退款、删除数据、发送外部消息等高影响动作即使模型参数生成正确也可能需要人确认。人工审批不是一句 system prompt而是工具执行前的程序闸门。审批拒绝后结果同样应回到运行链让 Agent 能够解释当前状态而不是假装动作成功。四个出口对应不同责任最终回答来自模型判断调用限制由 harness 执行业务错误由工具与应用定义人工转交由权限和审批流程决定。把它们都写成“停止条件”没有错但排障时必须知道具体是谁让循环结束。停止以后还要保留可诊断信息。至少应能回答最后一次模型输入包含什么模型请求了哪个工具工具参数是否通过校验外部调用是否成功结果是否进入 state以及最终出口属于哪一类。没有这些证据Agent 一旦在中间停住就只能靠猜。调用限制也应按风险拆开。只设置一个很大的迭代上限无法阻止一次昂贵工具调用或一次不可逆写操作只限制工具次数又可能让模型在没有工具的情况下反复生成。工程上通常同时考虑总运行时间、模型调用次数、特定工具调用次数和单次工具超时并为高影响动作设置独立审批。当边界触发时返回值要能区分“任务没有答案”和“系统选择不再继续”。前者可能需要补充业务数据后者可能是预算耗尽、权限拒绝或等待人工。把所有出口都改写成一句“抱歉处理失败”会丢掉前端提示、重试和运维诊断所需的信息。6. 用qwen3.7-plus跑通最小订单查询循环下面的代码只实现一项只读能力根据订单号查询模拟订单。这样可以看清核心循环又不会把退款写入、权限系统和持久化混进首讲。importosfromlangchain.agentsimportcreate_agentfromlangchain.toolsimporttoolfromlangchain_openaiimportChatOpenAI ORDERS{A1024:{product:无线耳机,purchased_at:2026-07-02,after_sales_days:30,status:delivered,}}tooldeflookup_order(order_id:str)-dict:按订单号查询商品、购买日期、售后期限和订单状态。returnORDERS.get(order_id,{error:order_not_found})modelChatOpenAI(modelqwen3.7-plus,api_keyos.environ[DASHSCOPE_API_KEY],base_urlos.environ[DASHSCOPE_BASE_URL],)agentcreate_agent(modelmodel,tools[lookup_order],system_prompt(你是售后客服助手。涉及具体订单时必须先查询订单没有订单事实就补问信息不得猜测只解释规则不执行退款或换货。),)resultagent.invoke({messages:[{role:user,content:订单 A1024 的耳机右侧没有声音还能换货吗,}]})print(result[messages][-1].content)执行路径可以按四个对象追踪。第一user message 进入 state。第二模型发现问题依赖具体订单生成lookup_order调用。第三harness 执行 Python 函数把字典结果转成工具消息。第四模型结合购买日期和售后期限生成最终回复不再请求工具本次循环结束。这段代码没有证明“用户一定能换货”。订单数据只提供了购买日期和期限真实业务还需要当前日期、故障类型、商品状态以及公司规则。Agent 可以编排查询过程不能替业务系统发明结论。要执行换货还必须有独立的权限校验、幂等键、审批或库存检查。如果输出不符合预期不要先反复修改 system prompt。先打印 messages模型是否产生tool_calls工具名和参数是否正确是否出现对应的ToolMessage结果中有没有模型需要的字段最后一条AIMessage是最终答复还是又一次调用。消息链能把“没调用”“调用失败”“结果不可用”“模型误判”分成不同问题。7. 按运行阶段定位 Agent 故障Agent 报错时最容易做的事情是把整个链统称为“模型问题”。更有效的办法是沿执行顺序检查四层。第一层是 model decision。模型是否看到了正确 system prompt、必要 messages 和合适的工具描述如果它选择了错误工具或参数先检查上下文和 schema而不是检查数据库连接。第二层是 tool execution。函数是否真的被调用参数是否通过验证外部服务是否超时权限是否允许这里的失败属于程序和基础设施即使换更强模型也不会自动恢复失效凭证。第三层是 state transition。tool_calls与ToolMessage是否配对工具结果是否进入 messages自定义字段是否按 reducer 更新运行已经成功但模型仍重复调用经常是结果没有进入下一轮可见上下文。第四层是 harness boundary。调用限制、middleware、checkpointer、人工审批或异常包装是否改变了路径同一模型和工具在两个环境行为不同应比较 harness 配置而不是只比较 prompt。这条排障顺序与核心循环使用同一组对象。模型层解释“为什么选择”工具层解释“是否执行”state 层解释“结果是否推进”harness 层解释“运行为何被改变或停止”。按层保留日志才能把一次看似随机的失败还原成确定步骤。生产环境还应补充两类指标循环长度和工具分布。循环突然变长可能是工具结果不完整、上下文膨胀或外部服务反复失败某个工具调用率异常升高可能是描述重叠或模型策略变化。只统计最终成功率会掩盖成本和风险正在累积。Trace 中还值得保留每轮上下文的摘要而不是无条件记录全部敏感内容。订单号、用户身份和工具返回可能受访问控制约束调试记录同样要脱敏并设置保留期限。可观察性不是把所有数据复制到日志系统而是在必要字段、权限和审计之间取得平衡。回归测试可以从真实失败 trace 提炼最小用例某条描述导致工具误选就固定用户输入并检查 tool name某次结果过长导致循环漂移就固定精简后的返回合同某个权限拒绝没有正确终止就验证对应 ToolMessage 和出口。这样 Agent 的“经验”才会沉淀成可重复验证的工程资产。8. 回到开篇Agent 的核心不是“自动”而是“可控地继续”现在可以重新回答开篇的售后问题。单次模型调用只有用户描述无法知道订单事实Agent 允许模型提出查询请求由 harness 执行工具把结果写回 messages再让模型基于新事实继续判断。每一轮都有明确输入、动作和结果直到生成最终答复或触发运行边界。整条链可以压缩为五步用户目标进入 state模型选择回答或工具harness 执行工具ToolMessage带着结果回流模型依据更新后的上下文继续或结束。create_agent把模型、工具和指令装配起来middleware、权限和调用限制则让这条循环能够进入真实工程。是否采用 Agent仍要回到任务形态。输入已经充分、只需一次推理就直接调用 Model步骤固定、分支可枚举就写 workflow只有下一步依赖运行结果并需要语义判断时才让 Agent 在受控工具集合中选择。最后保留一个最实用的记法Model 决定下一步意图Tool 接触外部世界State 保存运行进展Harness 负责让循环安全地继续或停止。在下一篇 06 篇我们会把其中最容易被误解的一段拆开模型生成的 Tool Calling 到底是什么Python 函数怎样变成工具结果又怎样可靠地回到对应调用。