菜鸟AI - 让提示词生成更简单! 全站导航 全站导航
AI工具安装 新手教程 进阶教程 辅助资源 AI提示词 热点资讯 技术资讯 产业资讯 内容生成 模型技术 AI信息库

已有账号?

首页 > AI教程 > LangChain v1 Agent源码深度解析:执行流程与架构详解
进阶教程

LangChain v1 Agent源码深度解析:执行流程与架构详解

2026-05-28
阅读 0
热度 0
作者 菜鸟AI编辑部
摘要

摘要

LangChainv1中的create_agent函数通过构建StateGraph来创建智能体。它将模型调用、工具执行和中间

create_agent

在 LangChain v1 中,create_agent 函数是构建智能体的核心入口。开发者通过传入语言模型、工具集以及可选配置,即可快速获得一个功能完备的 Agent 实例。

LangChain v1 Agent 执行流程源码解析

agent = create_agent(llm, tools, debug=True)

表面上看,这只是一个简单的构造函数。但深入其源码会发现,create_agent 的职责远超单纯的参数打包。它实质上构建了一套完整的“执行图”——将模型调用、工具执行、中间件处理、结构化输出、状态管理与运行时配置,统一编排进一个 StateGraph 中,最终编译为可执行对象。

因此,理解 create_agent 的关键,在于剖析它如何将 Agent 的复杂行为抽象为一张可编排的状态图。

创建 StateGraph

在完成参数解析、模式整理与中间件预处理后,create_agent 开始构建 Agent 的执行蓝图:

graph: StateGraph[AgentState[ResponseT], ContextT, _InputAgentState, _OutputAgentState[ResponseT]] = StateGraph(
    state_schema=resolved_state_schema,
    input_schema=input_schema,
    output_schema=output_schema,
    context_schema=context_schema,
)

此处的 StateGraph 构成了 Agent 状态机的骨架。它是一种声明式的流程定义:先定义节点,再定义节点间的流转规则,最后将整张图编译为可运行对象。

这一步设计至关重要。LangChain 没有采用简单的 while True 循环配合条件判断来实现 Agent,而是将其抽象为图结构。这带来了三个核心优势:

  1. 状态统一管理:Agent 运行过程中维护的共享状态(如 messagesstructured_responsejump_to 等)可以在多个节点间无缝传递与更新。
  2. 流程统一调度:无论是 LLM 推理、工具执行,还是中间件的前后处理逻辑,最终都以“节点”形式纳入同一套调度框架。
  3. 扩展统一接口:当需要支持更多阶段(如 before_modelafter_model 等钩子)时,无需重写主循环,只需在图中插入新的节点和边即可。

从这个视角看,create_agent 的本质并非“创建一个能调用工具的模型”,而是在构建一张“可动态执行的 Agent 状态图”。

向图中添加节点

创建 StateGraph 后,create_agent 开始向图中注册节点。最核心的两个节点是模型节点和工具节点:

graph.add_node("model", RunnableCallable(model_node, amodel_node, trace=False))
if tool_node is not None:
    graph.add_node("tools", tool_node)

这里的 "model" 节点负责调用模型完成一轮推理;"tools" 节点则负责执行模型产生的工具调用。

需要注意的是,模型节点并非简单的“直接调用 LLM API”。在前置代码中,create_agent 已经封装了完整的模型调用逻辑,包括:

  • 是否绑定工具
  • 是否启用结构化输出
  • 是否自动选择 ProviderStrategyToolStrategy
  • 是否插入 system_message
  • 是否经过 wrap_model_call 中间件的包裹

因此,图中的 "model" 节点代表的是“一次完整的模型调用阶段”,而非一次孤立的 API 请求。

除了 modeltools,源码还会根据中间件的实现情况,动态添加额外节点,例如:

  • before_agent
  • before_model
  • after_model
  • after_agent

这些节点并非固定存在。只有当某个中间件重写了对应钩子时,create_agent 才会将其注册进图。因此,最终生成的 Agent 图结构会随配置动态变化。

节点不是简单堆叠,而是分成“开始、循环、结束”三个层次

如果只看到 add_node,容易误以为这张图只是“将模型和工具塞入容器”。但实际上,create_agent 在后面定义了四个关键概念:

  • entry_node
  • loop_entry_node
  • loop_exit_node
  • exit_node

它们决定了整张图的执行骨架。

entry_node

entry_node 表示图从 START 进入后,首次执行的节点。如果存在 before_agent 中间件,图会先进入 before_agent;否则会直接进入 before_modelmodel

这意味着 before_agent 是一个“仅在整个 Agent 启动时执行一次”的入口阶段。

loop_entry_node

loop_entry_node 表示每一轮循环重新开始时的入口。通常指向 before_modelmodel

这一步至关重要。Agent 的本质是一个循环系统:模型推理一次,可能决定调用工具;工具执行完后,再回到模型继续推理。因此必须明确区分“首次进入图”与“工具返回后重新进入下一轮”的入口。

loop_exit_node

loop_exit_node 表示每一轮模型执行结束后的出口。如果存在 after_model 中间件,模型输出后不会立刻路由,而是先进入 after_model。否则就直接从 model 节点向后判断。

换言之,after_model 是介于“模型推理完成”和“下一步路由判断”之间的一层缓冲区。

exit_node

exit_node 表示整个 Agent 的最终出口。如果存在 after_agent 中间件,流程结束前会先经过 after_agent;否则直接进入 END

这说明 after_agentbefore_agent 类似,属于“整个 Agent 生命周期级别”的钩子,而非每轮推理都执行的阶段。

由此可见,create_agent 并非构建一条简单链路,而是先定义:

  • 整体从哪里开始
  • 每轮循环从哪里开始
  • 每轮循环从哪里结束
  • 最后从哪里退出

只有这四个位置确定下来,后续节点和边的组织才有清晰的结构。

graph.add_edge、add_conditional_edges

定义节点后,需要通过边来描述节点间的流转关系。

最基本的一条边是:

graph.add_edge(START, entry_node)

这条边定义了整个 Agent 从 START 出发,首先进入前面确定的入口节点。

但 Agent 的核心复杂性不在普通边,而在条件边。源码中最重要的是几处 add_conditional_edges,因为 Agent 不是线性流程,而是一个需要根据运行状态动态跳转的系统。

从 model 或 after_model 到下一步

当模型执行完成后,流程不会固定进入工具节点,而是要根据模型输出动态决定:

  • 是否结束
  • 是否进入工具节点
  • 是否重新回到模型节点
  • 是否因中间件的 jump_to 指令跳转到别处

对应的判断逻辑主要在 _make_model_to_tools_edge 中。

这段逻辑可概括为:

  1. 如果状态中显式设置了 jump_to,优先按 jump_to 跳转。
  2. 如果当前没有有效的 AIMessage,直接结束。
  3. 如果模型没有产生任何 tool_calls,说明本轮推理已完成,直接结束。
  4. 如果存在尚未执行的工具调用,则进入 tools 节点。
  5. 如果已经得到 structured_response,则可以结束。
  6. 如果有工具调用但没有待执行工具,通常意味着有中间件插入了额外消息,此时重新回到模型节点继续处理。

这意味着,Agent 的“继续还是结束”并非写死,而是由当前状态中的消息和工具调用结果共同决定。

从 tools 回到 model 还是结束

当工具执行完成后,流程也不一定总是回到模型。源码中 _make_tools_to_model_edge 决定了工具节点之后的走向。

这段逻辑大致总结为:

  1. 如果没有找到最近的 AIMessage,回到模型节点。
  2. 如果本轮工具调用全部是 return_direct=True 的工具,那么可以直接结束。
  3. 如果执行的是结构化输出工具,也可以直接结束。
  4. 否则默认回到模型节点,让模型读取工具结果并继续下一轮推理。

这里的 return_direct=True 很关键。它意味着某些工具不需要再把结果交回模型总结,而是可以直接作为 Agent 的最终结果返回。也正因如此,图中 tools 节点有时会存在一条通往 exit_node 的边。

没有工具时的特殊分支

如果 Agent 未配置任何工具,但启用了结构化输出,那么模型节点之间也可能形成“模型 -> 模型”的循环,这由 _make_model_to_model_edge 控制。

这说明在 create_agent 中,“循环”并不一定依赖工具;只要框架认为还有必要继续生成合法输出,模型也可以自行进入下一轮。

Middleware 如何嵌入主流程

如果说 modeltools 决定了 Agent 的主干,那么 middleware 决定的就是 Agent 的可扩展性。

create_agent 并没有把 middleware 当成简单的前后回调,而是将它们显式建模为图中的正式节点,并通过 _add_middleware_edge 将其接入主流程。

这背后反映出一个重要设计思想:middleware 不是“挂在外部的装饰器”,而是 Agent 生命周期中的正式阶段。

具体来说:

  • before_agent 串联在启动阶段
  • before_model 串联在每轮模型调用前
  • after_model 串联在每轮模型调用后
  • after_agent 串联在整个流程结束前

而且 middleware 不只是“顺序执行”。如果某个 middleware 声明了可跳转目标,那么 _add_middleware_edge 会为它创建条件边,使其能够通过状态中的 jump_to 字段改变控制流,例如跳到:

  • model
  • tools
  • end

因此,middleware 在这套设计中实际上拥有了“改变执行路径”的能力,而不仅仅是“修改输入输出”。

结构化输出如何影响图的行为

create_agent 的另一个复杂点在于结构化输出。在源码中,结构化输出并非一个独立插件,而是深度参与模型绑定、工具集合和路由判断。

具体来说:

  1. 模型绑定阶段create_agent 会根据模型能力自动决定使用 ProviderStrategy 还是 ToolStrategy
  2. 工具集合阶段:如果采用 ToolStrategy,结构化输出会被包装成特殊工具,并加入最终的工具列表中。
  3. 输出处理阶段:模型返回结果后,_handle_model_output 会尝试解析结构化输出;如果校验失败,还可能生成错误消息并触发重试。
  4. 路由阶段:一旦状态中已经存在 structured_response,很多条件边都会直接把流程导向结束。

因此,结构化输出不是“模型返回后顺便做一下解析”,而是从绑定模型到决定退出条件,贯穿了整个 create_agent 的执行图设计。

compile

在所有节点和边都定义完成后,create_agent 的最后一步是:

return graph.compile(
    checkpointer=checkpointer,
    store=store,
    interrupt_before=interrupt_before,
    interrupt_after=interrupt_after,
    debug=debug,
    name=name,
    cache=cache,
).with_config(config)

这一步的意义并不只是“把图编译一下”,而是将前面定义好的状态图真正转化为运行时对象。

前面的 StateGraph 仍然是“声明式定义”,描述的是:

  • 有哪些节点
  • 节点之间如何连接
  • 哪些地方需要条件判断
  • 哪些地方需要中间件参与

compile() 之后,图才会变成一个真正可执行的 CompiledStateGraph。与此同时,一些运行时能力也会在这一步被装配进去,例如:

  • checkpointer:负责状态持久化与恢复
  • store:提供外部存储能力
  • interrupt_before / interrupt_after:支持在指定节点前后中断
  • debug:开启调试能力
  • cache:启用缓存能力
  • nameconfig:附加运行时标识和元数据

因此,这一阶段更准确的理解是:前面是在“构图”,这里是在“将图装配成可运行的 Agent”。

总结

综合整个实现过程来看,create_agent 的核心思路可以概括为:

  1. 先整理模型、工具、middleware、schema 和结构化输出配置;
  2. StateGraph 定义一张 Agent 状态图;
  3. 把模型节点、工具节点以及 middleware 节点注册到图中;
  4. 用普通边和条件边把它们连接成完整的执行流程;
  5. 最后调用 compile(),把这张图转化为真正可运行的 Agent。

也正因采用了这种“状态图 + 条件路由”的实现方式,LangChain 的 Agent 不只是一个简单的“模型调用封装”,而是一套可插拔、可扩展、可中断、可持久化的执行框架。

从源码层面看,create_agent 真正做的事,并不是“帮我们调用一次 LLM”,而是把 Agent 的执行过程抽象成了一台状态机:它知道何时进入模型,何时调用工具,何时继续循环,何时提前结束,以及何时允许 middleware 接管控制流。这也是 LangChain v1 中 Agent 架构比传统串行实现更强大的根本原因。

来源:互联网

免责声明

本网站新闻资讯均来自公开渠道,力求准确但不保证绝对无误,内容观点仅代表作者本人,与本站无关。若涉及侵权,请联系我们处理。本站保留对声明的修改权,最终解释权归本站所有。

同类文章推荐

相关文章推荐

更多