news 2026/8/30 4:10:53

LangChain Agent执行流程拆解:从模型决策到中间步骤

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LangChain Agent执行流程拆解:从模型决策到中间步骤

如果你是刚开始接触 Agent 开发,大概率遇到过这种场景:一段“模型调用工具”的示例代码能跑通,但一旦任务变成“先查天气、再查航班、最后形成建议”,Agent 就会乱掉;或者答案看起来合理,却说不清它中间到底调用了几次工具、为什么这么调用。

项目标题里的langchain-6-9不用纠结是版本号还是课程目录编号,真正值得搞清楚的是:LangChain Agent 从接收用户输入,到最终返回结果,中间到底发生了什么。只有把执行流程拆解清楚,你才能真正控制 Agent,而不是靠运气调 Prompt。

先给一个判断:LangChain Agent 的核心不是“给模型加 tool”这个静态动作,而是一个循环调度机制。模型每一步只负责“决策”,真正执行外部动作的是工具,而把这些环节串起来的,是一套明确的执行框架。理解并掌控这个循环,是后续 Agent 开发、调试、面试和生产落地的基础。

文章会从基础概念讲到完整工作流,再给一个最小可运行示例,最后补充 LangGraph、常见报错排查和工程建议。建议收藏后跟着代码跑一遍。

1. 这篇文章真正要解决的问题

搜索“langchain agent 执行流程”的人,通常不是想知道 Agent 的定义,而是遇到了下面这些具体问题:

  • 为什么我的 Agent 有时候调用工具,有时候不调用?
  • Agent 和普通的大模型 Function Calling 到底有什么区别?
  • 一次任务中 Agent 可以调用多少次工具?谁来决定停下来?
  • agent_scratchpadintermediate_stepsAgentActionAgentFinish分别是什么?
  • 既然已经有了 AgentExecutor,为什么社区又在推荐 LangGraph?
  • 面试官问“Agent 的执行流程”,应该怎么回答?

这些问题背后都指向同一个核心:你需要对大模型、工具、执行器三者的协作顺序有确定性理解

这篇文章不打算讲太多 Agent 理论,而是直接拆执行链路,然后给你一份能跑通的代码,再通过代码运行结果反推内部机制。适合以下读者:

  • 刚学 LangChain,想搞懂 Agent 而不是停留在“会调 API”;
  • 已经在项目里使用 AgentExecutor,但遇到迭代次数超限、解析失败、工具参数错误等问题;
  • 准备 Agent 方向面试,需要系统梳理执行流程;
  • 从传统链路(Prompt + LLM)转向 Agent 开发,想建立正确的抽象认知。

读完之后,你应该能回答三个问题:一次 Agent 调用经历了哪些阶段;中间状态存储在哪里;怎么调整执行过程来规避常见坑。

2. 基础概念:Agent、Tool、LLM、AgentExecutor

2.1 一句大白话理解 Agent

Agent 可以理解为“大模型 + 工具 + 循环决策”的组合。

普通 LLM 调用是“输入文本 -> 输出文本”,模型没有能力查数据库、调接口、执行代码。LangChain Agent 做的事情是:让模型在每一步决定“下一步做什么”,如果需要外部信息,就调用工具;拿到工具结果后,再判断是继续调用工具,还是整理结果回答用户。

所以 Agent 不是单个模型请求,而是一连串模型请求和工具调用的循环。

2.2 四个核心角色

概念作用类比
LLM负责理解任务、生成决策,是“大脑”项目负责人
Tool负责执行具体动作,比如查天气、搜索、执行 SQL一线执行员工
Agent负责组织 Prompt、解析模型输出、决定调用哪个工具中间协调层
AgentExecutor负责驱动“思考 -> 行动 -> 观察”的循环,直到完成项目进度盯办人

在实际代码里,create_openai_tools_agent会创建一个 Agent,AgentExecutor再把这个 Agent 和工具列表组合成可执行对象。很多初学者把 AgentExecutor 误认为“Agent”,严格来说它是执行器,不是决策器。

2.3 它和普通 Function Calling 的区别

Function Calling 是模型能力的一种:模型可以根据用户问题输出一个函数名和参数,比如get_weather(city="北京")。但模型只输出一次调用,不会自己拿着结果继续推理。

Agent 的差异在于:

  1. 模型可以连续多轮输出工具调用;
  2. 每一轮工具结果都会作为文本回填到下一轮 Prompt 中;
  3. 当模型认为信息足够时,才输出最终回答。

换句话说,Recursive 循环 + 中间状态维护,是 Agent 执行流程的关键。

3. 核心执行流程拆解:从用户输入到最终回答

不管用经典的AgentExecutor,还是新的LangGraph,Agent 的底层流程都遵循下面这个模式:

3.1 一次完整 Agent 调用的 8 个阶段

阶段发生了什么关键数据
1. 接收输入用户提交 Queryinput
2. 组装 Prompt把 System Prompt、历史对话、用户输入、之前中间步骤组成新 Promptagent_scratchpad
3. 模型决策LLM 输出“动作”或“最终答案”AgentActionAgentFinish
4. 输出解析Agent 解析模型返回的文本或结构化输出解析后的 Action
5. 工具调用根据 Action 选择并执行工具tool.run(tool_input)
6. 生成观察工具返回结果字符串,称为 ObservationObservation
7. 状态回填(AgentAction, Observation)追加到中间步骤intermediate_steps
8. 循环判断如果是AgentFinish则结束,否则回到第 2 步max_iterations
输入 -> 格式化 Prompt -> LLM 决策 -> 解析输出 -> 调用工具 -> 得到 Observation -> 追加中间状态 -> 继续循环 -> 直到 AgentFinish

3.2AgentActionAgentFinish

这两个类是整个执行流程的“出口信号”。

  • AgentAction(tool="get_weather", tool_input={"city": "北京"}, log="..."):表示模型决定调用工具。
  • AgentFinish(return_values={"output": "今天晴,适合出门"}, log="..."):表示模型认为可以结束,直接返回答案。

执行器拿到AgentAction就调用工具;拿到AgentFinish就退出循环。理解这一点后,再看intermediate_steps就很简单了:它就是一个(AgentAction, Observation)的列表,记录整条决策链。

3.3 常见 Agent 范式

LangChain 里的 Agent 不只有一种范式。面试和实际开发中常提的有:

范式思路适合场景
ReAct每一轮输出 Thought / Action / Observation需要逐步推理的工具调用
OpenAI Tools使用原生 Function Calling 结构化调用依赖 OpenAI、通义、智谱等大模型平台
Plan-and-Execute先规划一个多步计划,再逐步执行复杂任务、可拆解业务
Conversational在 ReAct 基础上增加对话记忆需要多轮聊天 + 工具

大多数 LangChain 入门示例使用的create_openai_tools_agent本质上是“OpenAI Tools 风格 + ReAct 循环”的组合。LangChain 中 Agent 可以用不同范式,关键是模型能力是否匹配,以及工具描述是否足够清晰。

4. 环境准备与最小示例

下面用一个最小可运行示例,把“执行流程”变成可见的日志和中间步骤。

4.1 安装依赖

pip install langchain langchain-openai python-dotenv

如果你的环境还没有配置OPENAI_API_KEY,可以通过环境变量或.env文件设置:

export OPENAI_API_KEY=你的_api_key

本文使用 OpenAI 兼容接口的ChatOpenAI。如果你使用其他模型平台,可以把模型类和地址换成平台对应的 LangChain 集成,执行流程思路不变。

4.2 编写最小 Agent

# 文件路径:agent_demo.py import os from dotenv import load_dotenv from langchain.agents import AgentExecutor, create_openai_tools_agent from langchain.tools import tool from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain_openai import ChatOpenAI load_dotenv() @tool def get_weather(city: str) -> str: """查询某个城市的天气。参数 city 是城市名,例如“北京”。""" # 演示用,生产环境请接入真实天气服务 return f"{city} 当前晴,温度 26 度" tools = [get_weather] llm = ChatOpenAI(model="gpt-4o-mini", temperature=0) prompt = ChatPromptTemplate.from_messages( [ ("system", "你是一个友好的助手。请使用提供的工具回答问题。"), ("human", "{input}"), MessagesPlaceholder(variable_name="agent_scratchpad"), ] ) agent = create_openai_tools_agent(llm, tools, prompt) agent_executor = AgentExecutor( agent=agent, tools=tools, verbose=True, return_intermediate_steps=True, max_iterations=5, ) if __name__ == "__main__": result = agent_executor.invoke({"input": "北京今天适合出门吗?需要先查一下天气。"}) print("\n=== 中间步骤 ===") for i, (action, observation) in enumerate(result["intermediate_steps"], 1): print(f"第{i}步:工具={action.tool},参数={action.tool_input},观测={observation}") print("\n=== 最终回答 ===") print(result["output"])

这段代码里有两个关键点:

  1. agent_scratchpad是模型之前产生的 Action 和 Observation 的载体,必须放在 Prompt 中,否则执行器无法回填中间状态。
  2. return_intermediate_steps=True会让我们拿到(AgentAction, Observation)列表,这是观察执行流程的直接入口。

4.3 运行与验证

python agent_demo.py

正常执行时,verbose=True会在控制台输出内部决策过程。你可能会看到类似内容:

> Entering new AgentExecutor chain... Invoking: `get_weather` with `{'city': '北京'}` 北京 当前晴,温度 26 度 > Finished chain. === 中间步骤 === 第1步:工具=get_weather,参数={'city': '北京'},观测=北京 当前晴,温度 26 度 === 最终回答 === 北京当前晴天,适合出门。

这里的“中间步骤”就是 Agent 完整执行链路的直接证据:模型先决定调用天气工具,拿到观测后,再根据观测生成最终回答。

如果你的模型没有调用工具,直接返回了答案,需要先检查工具描述是否清晰、System Prompt 是否要求它使用工具,以及模型本身是否支持 Function Calling。

5. 通过 intermediate_steps 理解执行流程的细节

真实项目里,Agent 不会只调用一次工具。一次复杂的任务可能包括:搜索资料 -> 调用计算器 -> 查询数据库 -> 汇总答案。

intermediate_steps会按执行顺序记录每一步:

for i, (action, observation) in enumerate(result["intermediate_steps"], 1): print(f"第{i}步:工具={action.tool}") print(f"参数={action.tool_input}") print(f"模型日志={action.log}") print(f"观察结果={observation}") print("---")

如果 Agent 第一次调用search,第二次调用calculate,那么你会在intermediate_steps中看到两条记录。这个列表也是排错的核心依据:你可以拿到模型的第一步决策、工具返回、第二步决策,全程可回放。

这里真正容易踩坑的地方是:action.logobservation都可能很长。尤其是在接数据库、读文件、调用外部 API 时,工具返回大段文本会迅速占用上下文窗口。后面章节会讲怎么控制。

6. LangGraph 与新一代执行流程

6.1 为什么 LangChain 社区转向 LangGraph

AgentExecutor把执行循环封装成了一个黑盒。它方便,但不够灵活。比如你想在“模型决策之后”插入一个人工确认环节,或者在工具执行前做权限检查,用AgentExecutor很难自然实现。

LangGraph 把执行流程显式建模为一张图:

  • agent节点:负责让模型决策;
  • tools节点:负责执行工具;
  • 条件边:根据模型输出决定继续调用工具还是结束;
  • State:保存 messages 和中间状态,代替intermediate_steps

因此,LangGraph 和 LangChain 的关系不是替代,而是编排层升级:LangChain 提供模型、提示词、工具集成;LangGraph 提供可控的“执行流程编排”。

6.2 AgentExecutor 与 LangGraph 执行流对比

对比维度经典 AgentExecutorLangGraph 执行流
执行逻辑内部循环,黑盒显式图结构,节点和边清晰
中间状态intermediate_steps列表全局State,通常是 messages 列表
人工介入可在任意节点之间插入中断
多 Agent 编排吃力容易
官方建议适合学习和简单业务新项目更推荐

从当前官方文档和社区趋势看,新项目可以优先考虑 LangGraph;但学习AgentExecutor对理解核心执行流程仍然非常有效。

6.3 LangGraph 最小示例

安装依赖:

pip install langgraph

然后用create_react_agent快速创建一个执行图:

# 文件路径:langgraph_demo.py from dotenv import load_dotenv from langchain.tools import tool from langchain_openai import ChatOpenAI from langgraph.prebuilt import create_react_agent load_dotenv() @tool def get_weather(city: str) -> str: """查询某个城市的天气。参数 city 是城市名,例如“北京”。""" return f"{city} 当前晴,温度 26 度" llm = ChatOpenAI(model="gpt-4o-mini", temperature=0) app = create_react_agent(llm, [get_weather]) result = app.invoke({"messages": [("user", "北京今天适合出门吗?")]}) for message in result["messages"]: print(f"{message.type}: {message.content}")

在这个示例里,create_react_agent内部构建了一张图,result["messages"]保存了完整调用链:用户消息、模型行动、工具结果、最终回答。它比intermediate_steps更直观,因为每一步都作为消息保存在状态里。

7. 常见问题与排查思路

在实际开发里,Agent 跑不起来或者结果不对,大多不是模型问题,而是执行流程中的某一环出错。

问题现象可能原因排查方式解决方案
Agent 返回 “provider did not respond in time”模型服务或 Agent 执行服务响应超时看服务方状态页、检查请求日志设置更大的超时时间,检查模型服务可用性,增加重试
报错Could not parse LLM output模型输出不符合 Action 格式打开verbose=True查看原始输出改用 Function Calling 类 Agent,或优化输出解析器
达到最大迭代次数后停止任务太复杂或工具没有提供足够信息检查intermediate_steps是否在重复同一工具增加max_iterations,优化工具描述,让工具返回更结构化
工具参数乱码或缺少字段工具函数签名不明确,模型猜错了参数打印模型输出的tool_input给工具函数写清楚 docstring,尽量使用 pydantic 定义入参结构
Observation 太长导致上下文爆炸工具返回大段文本或日志查看工具返回内容长度在工具内部截断、聚合、只返回关键信息和摘要
模型不调用工具直接回答Prompt 没有强调使用工具,或工具列表太多看模型输出是否直接是答案System Prompt 中明确要求,减少无用工具,给工具加示例
工具执行报错但没有被捕获工具内部抛异常,执行器中断查看工具日志在工具内部捕获异常并返回错误字符串,而不是直接抛出

这里特别想强调一个认知:Agent 的“下一步”不是代码写死的,而是模型根据当前状态生成的。所以排查时不要只盯着模型,要检查工具返回的 Observation 是否能让模型做正确判断。如果工具返回“查询失败”,模型很可能继续重试同一个工具,直到迭代上限。

8. 最佳实践与工程建议

8.1 工具设计决定执行上限

工具是 Agent 感知外部世界的窗口。工具描述写得越清晰,模型越不会用错。

  • 工具名必须动词开头,例如search_newsget_user_order
  • docstring 要写清楚参数含义和返回值样例;
  • 工具返回值尽量精简,返回结构化文本或 JSON;
  • 工具内部要做异常兜底,避免让模型看到异常堆栈。
# 不推荐 def tool_a(s: str) -> str: return query(s) # 推荐 @tool def get_user_order(user_id: str) -> str: """根据用户 ID 查询最近一笔订单。 参数 user_id 是用户唯一标识,例如 U12345。 返回 JSON 字符串:{"order_id": "...", "status": "..."} """ try: data = query_order(user_id) return json.dumps(data, ensure_ascii=False) except Exception as exc: return f"查询失败:{exc}"

8.2 限制迭代,避免失控成本

生产环境一定要设置max_iterations,防止模型陷入死循环或疯狂调用工具。

对于 AgentExecutor:

AgentExecutor( agent=agent, tools=tools, max_iterations=5, early_stopping_method="generate", )

对于 LangGraph,可以通过recursion_limit控制:

app.invoke( {"messages": [("user", "帮我分析这个日志")]}, config={"recursion_limit": 10}, )

同时,建议给工具调用加计数器或日志。如果某个用户在短时间内触发大量工具调用,需要监测是否有异常请求。

8.3 日志与可观测性

不要只依赖最终答案判断 Agent 是否正确。

建议至少记录:

  • 用户原始输入;
  • intermediate_steps或 LangGraph 的messages
  • 每次工具调用的耗时和返回长度;
  • 模型 token 消耗;
  • 是否达到迭代上限。

这些日志既是排查依据,也是后续评估 Prompt 和工具质量的数据来源。

8.4 安全边界与最小权限

如果你的 Agent 可以操作数据库、删除文件、发消息,必须遵守最小权限原则。

  • 不要用高权限账号执行 Agent 工具;
  • 涉及删除、写入等危险操作,增加人工审批节点;
  • 工具入参要做校验和过滤;
  • 生产环境变更前必须先备份,并确保有回滚方案。

尤其在使用 LangGraph 时,可以通过 “human-in-the-loop” 在工具执行前暂停图,让用户确认后再继续。这是 AgentExecutor 不太好做、LangGraph 天生适合做的事情。

8.5 记忆与上下文控制

Agent 的记忆不应该无限增长。对话历史、中间步骤、工具返回值都会占用上下文。

工程上更推荐:

  • 使用 LangGraph 的Checkpointer持久化消息;
  • 对历史消息做滑动窗口截断;
  • 对工具 Observation 做摘要;
  • 避免把大日志、大文件全文塞给模型。

一句话总结:上下文长度是 Agent 的稀缺资源,不要让工具返回垃圾占据窗口

9. 总结与应用建议

这篇内容真正想讲清楚的,是 LangChain Agent 的执行流程:模型负责决策,工具负责执行,执行器负责循环;每一步的决策和观察都会作为下一轮的输入,直到模型输出AgentFinish

从实践角度看,建议你按这个顺序往下推进:

  1. 先跑通上面的最小示例,打开verbose=True,观察每一轮输出;
  2. 给 Agent 加第二个工具,让它在一次任务中连续调用多个工具,感受intermediate_steps的变化;
  3. 改造一版 LangGraph 示例,把执行图显式画出来,加深理解;
  4. 再学习 Agent 记忆、RAG 接入、MCP 工具协议、Skill 封装和多 Agent 编排。

Agent 开发走到后面,拼的并不是谁能把 Prompt 写得更漂亮,而是谁能把“模型决策 + 工具执行 + 状态管理 + 安全边界”这套循环控制得更稳。先把执行流程看透,后面学 LangGraph、MCP、多 Agent 都会轻松很多。

如果你正在准备面试,建议把“从输入到输出经历了哪些阶段”和“中间状态存在哪里”这两个问题作为主线讲清楚,基本就能覆盖大多数 Agent 执行流程的问题。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/30 4:10:51

现代反爬JS逆向:环境检测与补环境全流程解析

如果只看表面,动漫站点的反爬无非是“Cookie里加个签名”。但真正上手之后才发现,卡住你的根本不是某个加密算法,而是一整套环境对抗方案。最近技术社区里频繁讨论的 chameleon 反爬 JS,就是一个典型例子。它不是大家熟悉的 OB 混…

作者头像 李华
网站建设 2026/8/30 4:10:39

Python贪吃蛇开发实战:用pygame巩固编程基础,打造第一款小游戏

用Python写一个贪吃蛇小游戏,最大的价值不是把游戏做完,而是把Python的基础语法串起来跑一遍。输入处理、列表操作、条件判断、循环控制、函数封装,这些平时单独写很容易懂,但一旦放进一个不断变化的游戏循环里,很多隐…

作者头像 李华
网站建设 2026/8/30 4:10:31

数据结构与算法刷题实战:从基础到面试的深度掌握路径

简介:本资源是一套面向求职程序员与算法初学者的系统性刷题实战资料包,聚焦大厂面试核心考点,覆盖数据结构基础、动态规划、树与图算法、字符串处理等高频题型,助力突破笔试与技术面瓶颈。压缩包共969个文件,以468个Ja…

作者头像 李华
网站建设 2026/8/30 4:07:06

零基础前端实战:用原生HTML/CSS/JS打造“狂三 No Idea”主题页

手头只有一个标题:“【狂三】No Idea”。没有设计稿,没有接口文档,也没有明确需求。这种状态在真实前端开发中并不少见,需求方可能只给一句话,剩下的内容要靠自己补全。既然标题里出现了“狂三”,就可以把它…

作者头像 李华
网站建设 2026/8/30 4:06:33

只做MCP和CLI是短视,编排才是产品:AI应用工程化实践

在实际 AI 应用开发中,MCP(Model Context Protocol)和 CLI 工具正在被大量接入,但很多团队把“接入了几个 MCP server”或“封装了一套 CLI 命令”当作项目交付物,等到产品上线才发现,用户真正要的不是一堆…

作者头像 李华
网站建设 2026/8/30 4:05:48

GitHub Actions 中临时数据库环境配置与常见故障排查

一个很常见的场景:本地跑得好好的,一提交代码,CI 却报数据库连接失败。很多开发者第一次把项目接入 GitHub Actions 时,都会在这类问题上卡住。原因是本地开发环境里数据库是“常驻服务”,程序启动就能连上&#xff1b…

作者头像 李华