Agent(智能体)不是“给大模型接几个工具”这么简单。
普通 Chatbot 更像一个问答系统,用户输入问题,模型直接生成回答;Agent 则要完成一个任务,它需要理解目标、拆解步骤、选择工具、观察结果,并根据中间状态不断调整执行路径。
两者的差别可以简单理解为:
| 类型 | 核心能力 | 典型行为 |
|---|---|---|
| Chatbot | 生成回答 | 解释概念、回答问题、总结文本 |
| Agent | 执行任务 | 查数据、调用 API、处理文件、分步骤完成目标 |
真正能落地的 Agent,至少要把四件事设计清楚:LLM、规划、记忆和工具。
flowchart TB
User[用户请求] --> Agent[Agent 编排逻辑]
Agent --> LLM[LLM 大语言模型]
Agent --> Planning[规划模块]
Agent --> Memory[记忆系统]
Agent --> Tools[工具系统]
Planning --> LLM
Memory --> LLM
LLM --> Tools
Tools --> Observation[观察结果]
Observation --> Agent
Agent --> User
Agent 的四个核心组件
LLM(Large Language Model,大语言模型)负责理解和推理,规划模块负责拆任务,记忆系统负责保存上下文和长期信息,工具系统负责让 Agent 真正操作外部世界。
缺少其中任何一块,Agent 都会退化:
- 没有规划,只能做单轮问答或简单工具调用;
- 没有记忆,多轮任务容易丢状态;
- 没有工具,只能“说”,不能“做”;
- 没有稳定的 LLM,规划和工具调用都会变得不可控。
| 组件 | 作用 | 工程关注点 |
|---|---|---|
| LLM | 理解任务、推理决策、生成输出 | 模型能力、工具调用稳定性、温度参数 |
| 规划 | 把复杂目标拆成可执行步骤 | 静态规划、动态规划、最大迭代次数 |
| 记忆 | 保存历史对话、任务状态、用户偏好 | 短期记忆、长期记忆、上下文压缩 |
| 工具 | 执行搜索、计算、API 调用、文件操作 | 工具描述、参数校验、错误处理 |
1. LLM:Agent 的决策核心
LLM 决定 Agent 能不能理解任务、能不能选对工具、能不能根据工具返回结果继续推理。
在工程实践里,模型选择会直接影响稳定性。支持稳定 Tool Calling 的模型更适合做 Agent,例如 GPT-4o、Claude 3.5 Sonnet 这类模型在工具调用格式遵循方面表现更稳。
Temperature 参数也要控制。Agent 不是写诗,执行任务时更需要确定性。一般可以把 Temperature 设置在 0 ~ 0.3,降低模型随机发挥导致的工具选择漂移。
agent_llm_config = {
"model": "gpt-4o",
"temperature": 0.1,
"max_tokens": 4096,
}
2. 规划模块:Agent 和 Chatbot 的分界线
规划模块负责把“帮我完成某件事”拆成一组可以执行的动作。
常见规划方式有两类。
| 规划方式 | 代表方法 | 特点 | 适合场景 |
|---|---|---|---|
| 静态规划 | CoT(Chain-of-Thought,思维链)、ToT(Tree-of-Thought,思维树) | 执行前生成完整计划 | 步骤明确、变化少的任务 |
| 动态规划 | ReAct、Reflexion | 边执行边观察,边调整计划 | 外部环境不确定、工具结果会影响后续步骤的任务 |
这里的“动态规划”不是算法课里的 Dynamic Programming,而是指 Agent 在执行过程中动态修正计划。
例如用户要求“查一下北京今天的天气,并判断是否适合跑步”,Agent 不应该凭常识回答,而应该先调用天气工具,再根据温度、空气质量、降水情况判断。
3. 记忆系统:让 Agent 不丢上下文
记忆分为短期记忆和长期记忆。
短期记忆保存当前会话里的上下文,例如用户刚刚说过的约束、工具调用结果、当前任务进度。它通常依赖模型的 Context Window,也可以把状态存在 Redis 里。
长期记忆保存跨会话的信息,例如用户偏好、历史任务结果、企业知识库内容。长期记忆常用向量数据库、MongoDB 向量索引、Redis 向量检索或知识图谱实现。
flowchart LR
User[用户输入] --> Short[短期记忆<br/>当前会话状态]
Short --> LLM[LLM 推理]
Long[长期记忆<br/>用户偏好/知识库] --> Retriever[检索模块]
Retriever --> LLM
LLM --> Response[回答或行动]
Response --> Short
Response --> Long
短期记忆不能无限增长。多轮对话后,如果把全部历史都塞进上下文,成本会上升,关键信息也会被无关内容稀释。更稳的做法是:
- 保留最近几轮对话;
- 对较早历史做摘要;
- 把长期价值的信息写入向量库;
- 每次任务只检索相关片段。
4. 工具系统:让 Agent 能执行真实操作
工具是 Agent 和外部世界交互的接口。搜索、查天气、调用企业系统、执行代码、读写文件,本质上都可以封装成工具。
工具定义要清楚,尤其是名称、描述和参数结构。描述模糊会导致模型选错工具,参数约束不清会导致调用失败。
{
"name": "weather_api",
"description": "查询指定城市的实时天气,包括温度、天气状况、空气质量和降水概率。只用于天气查询,不用于查询城市介绍。",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "城市名称,例如北京、上海、深圳"
}
},
"required": ["city"]
}
}
JSON(JavaScript Object Notation,一种结构化数据格式)Schema(用于描述 JSON 数据结构的规范)可以限制工具入参,减少模型生成无效参数的概率。
工具数量也要控制。工具总池可以很大,但单次任务暴露给 Agent 的工具最好控制在 8 ~ 10 个以内。工具太多时,模型容易在语义相近的工具之间摇摆。
更好的结构是加一层 Router:
flowchart LR
Request[用户请求] --> Router[Router 意图路由]
Router --> SearchTools[搜索类工具集]
Router --> DataTools[数据查询工具集]
Router --> FileTools[文件处理工具集]
Router --> BizTools[业务系统工具集]
Router 先判断任务类型,再把对应工具集交给 Agent。这样既能保留完整工具能力,又不会让模型一次面对过多选择。
ReAct:最常见的 Agent 执行循环
ReAct 来自 Reason + Act,核心思想是让模型在“推理”和“行动”之间循环。
一个标准 ReAct 循环包含四个部分:
Thought: 当前要解决什么?已经知道什么?还缺什么?
Action: 要调用哪个工具?
Action Input: 工具参数是什么?
Observation: 工具返回了什么?
Agent 会不断重复这个过程,直到模型判断任务已经完成,然后输出最终答案。
flowchart TD
Start[用户任务] --> Thought[Thought<br/>分析当前状态]
Thought --> Action[Action<br/>选择工具]
Action --> Input[Action Input<br/>生成参数]
Input --> Tool[调用工具]
Tool --> Observation[Observation<br/>读取工具结果]
Observation --> Done{任务完成?}
Done -- 否 --> Thought
Done -- 是 --> Final[Final Answer]
用天气查询举例:
用户:北京今天天气怎么样?适合户外运动吗?
Thought: 用户需要北京天气,并希望判断是否适合户外运动。我需要先查询实时天气。
Action: weather_api
Action Input: {"city": "北京"}
Observation: {"temperature": 25, "weather": "晴", "aqi": 45, "rain_probability": 0.05}
Thought: 温度 25°C,晴天,AQI 45,降水概率很低,空气质量较好,适合户外运动。
Final Answer: 北京今天 25°C,晴天,空气质量较好,降水概率低,适合户外运动。
ReAct 的价值在于,它不是让模型一次性猜完整答案,而是把外部信息纳入推理过程。
| 方法 | 行为 | 缺点 |
|---|---|---|
| 纯 CoT | 只推理,不调用工具 | 无法获取实时信息 |
| 纯工具调用 | 直接调用工具,缺少推理 | 容易选错工具或误用结果 |
| ReAct | 推理、行动、观察交替进行 | 需要控制循环次数和异常处理 |
一个简化版 ReAct 执行器可以这样写:
MAX_ITERATIONS = 10
def run_agent(user_task, llm, tool_registry):
scratchpad = []
for step in range(MAX_ITERATIONS):
decision = llm.plan(
task=user_task,
history=scratchpad,
available_tools=tool_registry.schemas()
)
if decision["type"] == "final":
return decision["answer"]
tool_name = decision["action"]
tool_input = decision["action_input"]
tool = tool_registry.get(tool_name)
if tool is None:
observation = {
"success": False,
"error": f"unknown tool: {tool_name}"
}
else:
try:
result = tool.call(tool_input, timeout=30)
observation = {
"success": True,
"data": result
}
except TimeoutError:
observation = {
"success": False,
"error": "tool timeout"
}
except Exception as e:
observation = {
"success": False,
"error": str(e)
}
scratchpad.append({
"thought": decision.get("thought"),
"action": tool_name,
"action_input": tool_input,
"observation": observation
})
return "暂时无法完成该任务,请稍后重试或缩小任务范围。"
这里有三个关键点:
MAX_ITERATIONS防止 Agent 无限循环;- 工具返回必须区分
success和error; - 异常不能直接当作正常结果塞回模型。
生产环境里,ReAct 还需要加早停策略。例如连续两次选择同一个工具、输入参数也完全相同,并且结果没有变化,就可以判定进入无效循环。
Demo 能跑,不代表生产能稳
Agent 在演示环境里经常表现很好,因为演示通常走的是 happy path:输入清晰,工具正常,网络稳定,任务轮数少。
生产环境完全不同。用户输入可能不完整,API(Application Programming Interface,应用程序编程接口)可能超时,工具可能返回脏数据,多轮对话会让上下文越来越长。Agent 的不稳定,通常来自四类问题。
1. 错误传播:一步错,后面都偏
Agent 是多步执行系统。某一步工具返回错误,如果没有显式标记失败,模型可能会把错误文本当作正常观察结果继续推理。
错误传播的典型链路是:
flowchart LR
A[工具调用失败] --> B[错误信息被当成正常结果]
B --> C[LLM 基于错误结果继续推理]
C --> D[选择错误工具或生成错误答案]
D --> E[任务整体失败]
解决方式是让所有工具返回统一结构:
{
"success": false,
"error_code": "TIMEOUT",
"error_message": "weather_api timeout after 30s",
"retryable": true
}
Agent 看到 success: false 后,要进入错误处理分支,而不是继续按正常流程推理。
关键步骤还要加校验:
| 校验点 | 示例 |
|---|---|
| 输出格式 | JSON 字段是否完整 |
| 参数合法性 | 城市名、日期、金额是否符合业务规则 |
| 业务逻辑 | 库存不能为负,退款金额不能超过订单金额 |
| 权限 | 用户是否有权调用该工具或读取该数据 |
2. 工具选择漂移:工具越多,越容易选错
工具选择漂移指的是 Agent 在执行过程中逐渐偏离原始目标,或者在多个相似工具之间选错。
例如同时提供这些工具:
search_user_ordersearch_order_logquery_order_statusget_order_detail
如果 description 写得都很像,模型很可能选错。
解决方式包括:
- 单次任务只暴露必要工具;
- 工具命名保持明确,不要语义重叠;
- description 写清“适用场景”和“不适用场景”;
- 用 Router 先分流,再提供小工具集。
工具 description 可以这样写:
get_order_detail:
根据订单 ID 查询订单的基础信息,包括商品、金额、收货地址和当前状态。
不用于查询操作日志,不用于查询退款进度。
“不用于什么”很重要,它能减少模型在相近工具之间误选。
3. 上下文爆炸:历史越多,关键信息越淡
多轮 Agent 很容易遇到 Context Explosion,也就是上下文爆炸。问题不是只有“超出模型上下文长度”,还包括“重要信息被大量无关内容稀释”。
可用三层策略处理:
| 策略 | 做法 | 适合内容 |
|---|---|---|
| 滑动窗口 | 保留最近 N 轮对话 | 最新约束、当前任务状态 |
| 对话摘要 | 定期压缩旧历史 | 已确认的需求、阶段性结论 |
| 分层记忆 | 热信息进上下文,冷信息进向量库 | 用户偏好、历史任务、知识库 |
不要把向量检索当成万能记忆。长期记忆写入前要判断是否值得保存,检索后也要做相关性过滤,否则会把噪声重新带回上下文。
4. 缺少降级:外部依赖一挂,Agent 就停
Agent 依赖模型、工具、数据库、网络和第三方服务。任何一环不稳定,都会影响整体结果。
生产级 Agent 至少要有三类降级设计:
| 机制 | 作用 | 示例 |
|---|---|---|
| 超时 | 避免单个工具阻塞整个任务 | 单次工具调用 30 秒超时 |
| 熔断 | 避免持续调用已故障服务 | 连续失败 3 次后临时禁用工具 |
| 兜底 | 在无法完成时给出可解释结果 | 告知用户当前能力不可用,并提供替代路径 |
非幂等操作不能随便重试。例如扣款、下单、发送邮件这类操作,重试可能造成重复执行。重试前要确认操作是否幂等,必要时引入请求 ID 做去重。
Agent 框架怎么选
LangGraph、CrewAI、AutoGen 的定位不一样,不应该只按热度选。
| 维度 | LangGraph | CrewAI | AutoGen |
|---|---|---|---|
| 设计理念 | 图结构工作流 | 角色协作团队 | 对话式协作 |
| 学习曲线 | 较陡 | 较平缓 | 中等 |
| 状态控制 | 强 | 中等 | 中等 |
| 适合场景 | 复杂流程、状态机、生产编排 | 快速原型、多角色任务模拟 | 代码生成、迭代式任务 |
| 生产适配 | 更适合精细控制 | 适合较快验证业务想法 | 需要关注迁移和维护状态 |
选型可以按任务特征判断:
flowchart TD
A[Agent 项目需求] --> B{需要精细控制状态和流程?}
B -- 是 --> LG[LangGraph]
B -- 否 --> C{需要快速搭多角色协作原型?}
C -- 是 --> Crew[CrewAI]
C -- 否 --> D{主要做代码生成和迭代修复?}
D -- 是 --> Auto[AutoGen]
D -- 否 --> E[选择更轻量的自定义 ReAct 或函数调用流程]
更具体一些:
- 复杂企业流程、需要断点续传、状态回放、分支控制时,LangGraph 更合适;
- 需要快速定义“研究员、分析师、执行员”这类角色协作时,CrewAI 上手更快;
- 代码生成、执行、修复循环比较重时,AutoGen 的对话式协作模式有优势。
如果团队已经在使用 LangChain 技术栈,LangGraph 的集成成本会更低。对于 AutoGen,还要关注 Microsoft 相关 Agent Framework 的迁移方向;如果是新项目,要把后续维护和迁移成本算进去。
不同框架的记忆机制也有差异:
| 框架 | 记忆实现思路 |
|---|---|
| LangGraph | 通过 Checkpointing 保存状态,可接 Redis、MongoDB 等存储 |
| CrewAI | 围绕角色和任务组织记忆,支持 RAG(Retrieval-Augmented Generation,检索增强生成) |
| AutoGen | 以多轮对话历史作为主要记忆载体 |
生产级 Agent 的分层架构
企业级智能助手不能只是一段调用模型的脚本。它至少需要接入层、编排层、能力层和基础设施层。
flowchart TB
subgraph Access[接入层]
Web[Web]
API[API]
IM[企业 IM]
Auth[身份与权限]
RateLimit[限流]
end
subgraph Orchestration[编排层]
Router[Router 意图路由]
Orchestrator[Orchestrator 执行编排]
State[State Manager 状态管理]
end
subgraph Capability[能力层]
ToolPool[工具池]
Memory[短期记忆 + 长期记忆]
ModelPool[主模型 + 备用模型]
end
subgraph Infra[基础设施层]
Tracing[Tracing 全链路追踪]
Eval[评估系统]
Monitor[监控告警]
Storage[Redis / MongoDB / 向量库]
end
Access --> Orchestration
Orchestration --> Capability
Capability --> Infra
Infra --> Orchestration
接入层:处理请求进入系统之前的问题
接入层负责多渠道入口和基础安全控制:
- Web、API、企业 IM(Instant Messaging,即时通讯)等多入口接入;
- Session ID 管理;
- 用户身份识别;
- 权限校验;
- 敏感内容过滤;
- 请求限流。
权限校验不能放到工具内部才做。Agent 在规划阶段就应该知道用户能调用哪些工具、能读取哪些数据,否则会生成无法执行的计划。
编排层:生产级 Agent 的核心
编排层决定任务怎么走。
| 模块 | 职责 |
|---|---|
| Router | 判断任务类型,分配 Agent 或工具集 |
| Orchestrator | 控制执行流程,包括分支、循环、并行、重试 |
| State Manager | 保存任务状态,支持中断恢复和问题排查 |
LangGraph 适合放在这一层,因为它用图结构表达流程,节点、边、状态都比较清晰。对于需要审批、回滚、人工介入的企业流程,图结构比单纯 prompt 串联更容易维护。
能力层:模型、工具和记忆的组合
能力层提供 Agent 真正能调用的能力:
- 工具池按领域分组,每组控制在
8 ~ 10个工具以内; - 短期记忆可以放 Redis,并设置 TTL(Time To Live,存活时间),例如 24 小时;
- 长期记忆可以使用 MongoDB 向量索引、专用向量数据库或知识图谱;
- 模型池要支持主备切换,避免单一模型服务故障导致整体不可用。
常见配置可以参考:
| 决策点 | 可选方案 |
|---|---|
| 主模型 | GPT-4o / Claude 3.5 Sonnet |
| 编排框架 | LangGraph |
| 短期记忆 | Redis,TTL 24h |
| 长期记忆 | MongoDB + 向量索引,或专用向量数据库 |
| 可观测性 | LangSmith / Langfuse / OpenTelemetry |
| 评估 | 自动评估覆盖主体场景,人工抽检高风险场景 |
基础设施层:没有可观测性就不要上线
Agent 的问题很难只靠最终答案排查。一次任务里可能包含多次模型调用、多次工具调用、检索、重试和降级。如果没有 Tracing(全链路追踪),线上出错时很难定位是哪一步偏了。
至少要记录这些信息:
| 记录项 | 作用 |
|---|---|
| 用户请求 | 还原任务输入 |
| Router 决策 | 判断任务是否分错类 |
| Prompt 和模型输出 | 排查模型是否误解 |
| 工具调用参数 | 判断工具输入是否正确 |
| 工具返回结果 | 判断外部依赖是否异常 |
| 每一步耗时 | 找出性能瓶颈 |
| Token 消耗 | 控制成本 |
| 最终答案和评分 | 做质量评估 |
评估系统也要提前设计。常见做法是 LLM-as-Judge(用大语言模型做评审)加人工抽检。自动评估适合覆盖格式、完整性、事实一致性等高频场景;人工抽检适合高风险业务,例如财务、法务、医疗和关键企业操作。
稳定性 Checklist
生产级 Agent 至少要满足这些约束:
| 项目 | 推荐配置 |
|---|---|
| 单次工具调用超时 | 30 秒左右,根据业务调整 |
| 最大 ReAct 迭代次数 | 10 ~ 15 |
| 工具调用重试 | 最多 2 次,非幂等操作不自动重试 |
| 熔断阈值 | 连续失败 3 次后触发 |
| 单次对话 Token 预算 | 8k ~ 16k,按模型和成本调整 |
| 工具返回格式 | 必须包含 success / error |
| 上下文管理 | 滑动窗口 + 摘要 + 长期记忆 |
| 可观测性 | 每次模型调用和工具调用都可追踪 |
| 降级响应 | 明确告诉用户当前无法完成什么,并给替代方案 |
还应该专门构造失败用例来测试 Agent:
1. 工具超时
2. 工具返回空数据
3. 工具返回格式错误
4. 用户输入缺少必要参数
5. 用户要求越权操作
6. 上下文超过预算
7. 多个工具描述相似
8. 模型连续选择同一个无效工具
只测正常路径没有意义。Agent 是否可靠,主要看它在异常路径里能不能停得住、说得清、可恢复。
判断 Agent 水平,看这几件事
会调用框架只能说明能搭 Demo,不能说明能做生产系统。真正的 Agent 开发能力,体现在几个问题上:
- 能不能说清 LLM、规划、记忆、工具各自负责什么;
- 能不能解释 ReAct 的 Thought、Action、Observation 循环;
- 能不能处理工具失败、上下文爆炸、工具漂移和降级;
- 能不能把工具池、状态管理、Tracing 和评估系统设计完整;
- 能不能根据业务复杂度选择 LangGraph、CrewAI、AutoGen 或自定义流程。
Agent 的核心不是“用了哪个框架”,而是让一个不确定的大语言模型,在受控的流程、清晰的工具、可追踪的状态和可恢复的异常处理里完成任务。框架会变,工程约束不会变。