AI Agent 智能体开发:从 ReAct 原理到 LangChain 工程落地
AI Agent 智能体开发:从 ReAct 原理到 LangChain 工程落地
一、Agent 到底解决了什么问题
在做智能体开发之前,有必要先把问题定义清楚:什么场景必须用 Agent,什么场景用普通对话链就够。简单对话、单轮问答、固定流程的查询类应用,用 Chain 或直接调 API 反而更可靠。Agent 的核心价值在于自主决策——当任务的执行路径无法预先确定,需要模型根据中间结果动态决定下一步动作时,Agent 才真正发挥优势。
典型的 Agent 场景包括:让模型自己去查资料并整理成报告、让模型操作数据库完成数据分析、让模型调用多个工具解决一个复合问题。这些任务的共同特征是:动作空间大、步骤不确定、需要与环境持续交互。
在投入开发之前还有一个重要的取舍问题:单 Agent 还是多 Agent?我的建议是从单 Agent 起步。单 Agent 的调试成本最低,可观测性最好,对绝大多数业务场景已经足够。只有在任务确实需要专业分工、并行处理或独立校验时,才值得引入多 Agent 架构——这会带来通信开销、状态同步、一致性维护等一系列新问题,后文会详细展开。
二、ReAct:Agent 的思考引擎
当前绝大多数 Agent 框架的底层都是 ReAct 模式,它来自 2022 年 Yao 等人的论文,核心循环是"Thought → Action → Observation":模型先思考下一步该做什么,然后执行一个具体动作(调用工具、查数据库、执行代码),再根据环境返回的观察结果进入下一轮思考。
这里的关键洞察是 Observation 承担了"反馈"功能。相比纯思维链(CoT),ReAct 的推理始终锚定在外部事实之上——API 返回的结果、命令的输出、文件的内容——而不是模型自己编造。这种"接地"机制能大幅抑制幻觉和错误累积,这是 Agent 比单纯提示词工程更可靠的根本原因。
有意思的是,一个完整的 Agent 循环实现起来并不复杂。社区里知名项目的核心 agent-loop 也就几百行代码:读取系统提示 → 拼接上下文 → 调用模型 → 解析动作 → 执行工具 → 返回观察。后续的记忆压缩、Skill 加载、工具注册,本质上都是"上下文管理"层面的优化,并不改变基本工作原理。理解这一点,你就不会被各种框架的复杂性吓倒——框架只是把循环的工程细节标准化了。
三、LangChain Agent 的六大组件
模型层。 Agent 对模型的要求比普通对话高得多:必须支持函数/工具调用协议,推理能力要足够强才能理解复杂指令和多步任务。实践中的选型经验是,小模型做 Agent 容易"失智"——不是不会调用工具,而是分不清该在什么时候调用、调完怎么用结果。生产环境建议至少选择当前主流中大型模型,并用一组固定用例做工具调用回归测试后再定版。
工具层。 工具是 Agent 能力的边界。设计工具时最重要的原则是接口要窄、描述要准:每个工具只做一件事,参数尽量少,docstring 写清楚用途和参数含义。因为模型是靠工具的文本描述来决定是否调用的,描述含糊的工具有时根本不会被选中,有时又会被误用。用 LangChain 声明一个工具非常直观:
from langchain_core.tools import tool
@tool
def query_stock(code: str) -> dict:
"""查询 A 股实时行情。参数 code 为 6 位股票代码,如 '600519'。返回最新价、涨跌幅和成交量。"""
# 内部调用行情 API,注意超时与异常处理
return stock_api.fetch(code)
```
工具层还需要做超时控制、错误码约定、敏感参数脱敏,避免模型把内部配置直接吐给用户。一个实用的做法是为每个工具增加 `retry` 和 `fallback` 配置:工具失败时不直接结束任务,而是把错误信息作为 Observation 返回,让模型决定是否换一种方式重试。
**记忆层。** 单轮 Agent 只需要拼接当前上下文,多轮 Agent 就必须处理记忆。生产环境的记忆设计通常是分层的:短期记忆存对话历史,中期记忆存任务执行轨迹,长期记忆存用户画像和领域知识(通常落到向量库)。记忆不是越多越好——塞满上下文的 Agent 会变得迟钝且昂贵,需要根据 token 预算做摘要压缩或滑动窗口。实践中我习惯给记忆层加一个"重要性评分",只保留高价值的交互记录,其余降级为摘要。
**规划层。** 简单的 ReAct 循环对单工具任务足够,复杂任务需要显式的规划机制:Plan-and-Execute(先整体规划,再逐步执行)、任务分解、子目标管理。规划层引入的代价是延迟和 token 消耗,所以规划粒度要按任务复杂度动态调整。一个低成本的做法是"轻规划":让模型先输出一个简短的步骤清单,然后在 ReAct 循环中逐步勾选,既获得了规划的稳定性,又不至于过度消耗上下文。
**执行器与编排层。** 在 LangChain 生态中,AgentExecutor 负责运行 ReAct 循环;当任务变成有状态的多步骤工作流时,升级到 LangGraph 用图结构显式描述状态转移。这两者的选择边界很清晰:线性任务用 Executor,复杂分支与状态机用 LangGraph。创建带工具的 Agent 只需几行:
```python
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个数据分析助手,只使用提供给你的工具完成任务。"),
("placeholder", "{chat_history}"),
("human", "{input}"),
("placeholder", "{agent_scratchpad}"),
])
agent = create_tool_calling_agent(llm, tools=[query_stock], prompt=prompt)
executor = AgentExecutor(agent=agent, tools=[query_stock], max_iterations=8)
print(executor.invoke({"input": "查一下贵州茅台今天的股价"}))
```
`max_iterations` 这个参数值得单独强调:不设置上限的 Agent 可能陷入无意义的循环,token 和费用都会失控,这是生产事故的高发点。
## 四、工程实践:从 Demo 到生产
**第一步:从简单工具开始。** 先接两三个工具跑通循环,观察模型的调用日志,再逐步扩展。一次接十个工具,模型选择错误的概率会显著上升——工具多了之后,描述区分度就成了瓶颈。工具数量超过十个时,建议按领域分组并启用"工具路由":先由模型或规则选组,再在组内选择具体工具。
**第二步:重视可观测性。** 生产 Agent 项目里最常被忽视的就是日志。每一轮 Thought、每次工具调用参数、每个返回值都应该完整记录,因为 Agent 的失败往往发生在多步之后,没有完整轨迹根本无法定位。这也是 LangSmith 这类追踪工具存在的意义。自建方案也不复杂:在工具外层包一层拦截器,把入参出参和耗时写入结构化日志,配合 trace ID 串联整条链路。
**第三步:设计兜底机制。** 模型调用可能超时、工具可能抛异常、循环可能陷入死循环。生产环境必须设置最大迭代轮数、工具超时、失败重试和人工介入通道。我的经验是:**凡是 Agent 能自主完成的,都要能手动接管**——这是企业级系统的底线。建议实现一个简单的"置信度闸门":Agent 在关键节点输出不确定信号(如工具调用失败次数超阈值)时,主动暂停并请求人工确认。
**第四步:评估先行。** Agent 的评估比传统模型评估复杂得多,因为输出是过程性的。建议从三个维度建立指标:任务完成率(最终目标是否达成)、工具调用正确率(是否选对工具、参数是否合法)、成本效率(token 消耗和延迟)。建立一组固定的测试用例集,每次改动后跑回归。评估集不必很大,但一定要覆盖典型成功路径和典型失败路径两类场景。
## 五、常见失败模式与对策
从大量实践案例中可以总结出几类高频失败:一是**工具误选**,模型在相似工具间犹豫或选错,对策是工具描述里写清适用条件和典型例子;二是**上下文污染**,历史中的噪音信息干扰当前决策,对策是记忆压缩和检索增强;三是**重复劳动**,Agent 反复执行同一动作不推进,对策是设置动作去重和最大轮数;四是**幻觉式完成**,模型没真正执行工具就声称完成了任务,对策是强制要求动作-观察配对,无观察不得进入下一轮。
最后想强调一点方法论:Agent 的能力上限由模型、工具、编排三者共同决定,而多数项目的瓶颈不在模型而在工具设计和上下文管理。把工具接口打磨干净,把上下文控制好,往往比换一个更大的模型更有效。与其追逐框架的新特性,不如先把 ReAct 循环、工具契约、可观测性这三件事做扎实——它们才是智能体工程质量的基本盘。
更多推荐


所有评论(0)