未经许可,不得转载。
文章目录
引言
一开始,你只是尝试通过 API 与 ChatGPT 进行交互,输入几行上下文,惊讶于它竟然能够响应。随后,你希望它能完成一些实用的任务。再后来——你希望它能稳定可靠地执行这些任务。最终——你希望它能在无人干预的情况下自主完成工作。
这便是智能体的诞生过程。
如果过去一年你也通过脚本和封装工具拼凑智能体,反复试验和调试,却依然在寻找一种更加清晰且可持续的构建方案,那么这篇文章正适合你。它是一份实用的备忘清单——一套工程原则,帮助你将智能体从沙箱环境推进到生产环境,实现从简单的 API 封装到稳定、可控且具备扩展能力的系统演进。
声明
这里我们将“智能体”定义为一种系统,其中大语言模型(LLM)能够动态地引导自身的流程与工具调用,保持对任务执行方式的控制。而通过预定义代码路径来协调 LLM 与工具的系统,则称为“工作流”。这两者均属于更广义的“智能体系统”范畴。
为确保系统的稳定性与可控性,文中多数情况下倾向采用工作流的方式。期望在不远的将来,智能体能经历一至两轮进化,真正意义上的 Agent 能够普及,但目前尚未实现。
1. 设计基础架构
早期版本的智能体通常能够快速搭建:几个函数,几个提示词——竟然就能用。
“既然能用,何必复杂化?”
起初,一切看似稳定。智能体响应合理、能执行代码、表现正常。但一旦更换模型、重启系统,或接入新接口,系统便变得不稳定、难以预测,且调试困难。
而问题根源往往不在逻辑或提示词,而是更早阶段:内存管理混乱、硬编码配置、无法恢复会话,或仅有单一僵硬的入口点。
本节将介绍四项关键原则,帮助你构建坚实的基础架构,确保其他模块能够在此基础上安全稳定地扩展。
1. 将状态存储在外部
问题:
- 无法恢复进度:当智能体遭遇中断(如崩溃、超时等)时,应能够从中断点准确继续执行。
- 可复现性有限:必须具备精确重现执行过程的能力,以便进行测试、调试等操作。
- 并行执行需求:迟早你会需要让智能体的逻辑实现并行处理。比如在对话中比较多个选项(“哪个更好?”),或者实现分支执行——这类需求不可避免。
- (内存管理属于另一个议题,将在后文详细说明)
解决方案:
将状态存储移至智能体之外——例如数据库、缓存层、存储系统,甚至简单的 JSON 文件均可。
检查清单:
- 智能体可从任意步骤启动,仅依赖 session_id 和外部状态(如数据库或 JSON 文件中保存的步骤),即能恢复执行,支持系统重启后继续运行且无异常。
- 测试用例验证:智能体中断后不会丢失上下文,重启后执行结果保持一致。
- 状态在任意时刻均可序列化,且不影响功能完整性。
- 支持在对话进行中,将状态并行注入多个实例,实现并发处理。
2. 将知识外部化
问题:
LLM 本身没有持久记忆能力。即便在单次会话中,模型也可能遗忘已有指令、混淆对话阶段、丢失上下文,甚至产生幻觉式补充内容。尽管上下文窗口不断增大(如 8k、16k 到 128k token),问题仍然存在:
- “中间遗忘”现象:模型更偏重上下文开头与结尾,易忽视中间细节
- 成本随 token 数量增长而上升
- 容量有限,信息丢失、扭曲和幻觉风险依旧存在(Transformer 的自注意力机制复杂度为 O(n²),难以根本解决)
解决方案:
将“工作内存”(context)和“长期存储”分离,类似传统计算系统架构。智能体应利用外部记忆机制,支持存储、检索、摘要与更新模型外的知识。常用架构策略及优缺点如下:
-
内存缓冲区(Memory Buffer)
- 存储最近 k 条消息
- 适合快速原型和短任务
- 简单高效,但不能记忆长时信息,无法跨会话
-
摘要记忆(Summarization Memory)
- 通过摘要压缩历史对话,节省 token
- 扩展记忆容量
- 易引入信息丢失或扭曲,摘要多步迭代易出错
-
检索增强生成(RAG)
- 从外部数据库或文档库检索相关信息辅助生成
- 支持大规模、动态更新知识库
- 复杂度高,依赖检索质量,可能存在响应延迟
-
知识图谱(Knowledge Graphs)
- 结构化实体和关系连接
- 提升逻辑推理和解释能力
- 集成复杂,学习门槛高,且通常配合 RAG 使用
检查清单:
- 所有历史对话和上下文状态均存储于提示之外的专门位置(数据库、缓存、文件等)
- 所有知识来源和检索操作均有日志记录,确保可追溯和复用
- 上下文存储方案能灵活扩展,避免超过 LLM 上下文窗口限制导致信息丢失
- 在设计中合理结合多种存储和检索方式,提升记忆效果与效率
3. 模型即配置项
问题:
LLM 技术更新迅速,Google、Anthropic、OpenAI 等厂商不断推出新模型并优化性能。在这种快速变化的环境中,工程师需要设计智能体系统,能够轻松切换到更优或更经济的模型,以保持竞争力和成本效益。
解决方案:
-
实现 model_id 配置
通过配置文件(如 YAML、JSON)或环境变量指定当前使用的模型 ID,方便随时调整和切换。 -
使用抽象接口
设计统一的模型交互接口或封装类,屏蔽具体模型调用细节,使智能体业务逻辑与模型实现解耦。 -
谨慎应用中间件方案
可引入模型代理层或适配器模式(Adapter Pattern)以管理多模型调用,但需避免引入过多复杂性和性能开销。后续框架选型时详加权衡。
检查清单:
- 替换或切换模型不会影响智能体的核心功能,包括任务调度、状态管理、记忆存储和工具调用链。
- 新模型接入仅需修改配置文件,必要时添加适配器层保证接口一致。
- 模型切换快速且灵活,理想情况下支持同一模型族内的无缝切换(例如 GPT-3.5 到 GPT-4),并可拓展至不同厂商模型。
4. 一个智能体,多种接口:出现在用户所在之处
问题:
最初智能体可能只支持单一通信接口(如网页 UI),但随着需求增长,你会希望它支持多渠道交互(Slack、WhatsApp、SMS 等),甚至提供 CLI 用于调试。若没有从一开始就设计好架构,多渠道支持将变得复杂且难以维护。
解决方案:
设计并实现一个统一输入契约,即通过一个统一的 API 或接口层来接收和处理所有渠道的输入。各渠道仅作为适配器存在,负责转换和转发消息,不包含业务逻辑,核心智能体逻辑与渠道解耦。
检查清单:
- 智能体能通过多种渠道调用:CLI、REST API、网页 UI、消息平台(Slack、WhatsApp、SMS 等)。
- 所有输入数据均通过统一的入口点、统一的解析器或统一的消息模式传入系统。
- 输入格式标准化,确保各渠道数据格式一致,便于统一处理。
- 各渠道适配器仅处理数据转换与传递,核心业务逻辑完全独立。
- 新增渠道时,只需实现对应的适配器模块,无需改动核心智能体逻辑,方便扩展和维护。
二、定义智能体行为
当只有一个任务时,一切看起来很简单,就像 AI 宣传文章中描述的那样。但一旦引入了工具调用、复杂的决策逻辑和多阶段流程,智能体就容易陷入混乱。
它可能迷失方向,不知道如何妥善处理错误,忘记调用正确的工具,最终只剩下日志堆积如山,让你无奈地翻看:“好吧,日志里好像什么都有写。”
为避免这种情况,智能体必须拥有清晰的行为模型,明确以下内容:
- 它负责做什么任务;
- 拥有哪些工具和能力;
- 谁负责做出决策;
- 人类如何在关键节点介入;
- 发生错误时应如何应对。
本节所述原则,旨在帮助你为智能体构建连贯且可控的行动策略,而不是单纯地“指望模型自己搞定一切”。
5. 设计工具使用
问题:
这点虽然看似显而易见,但实际开发中仍常见“纯提示 + 原始 LLM 输出解析”的做法。这相当于用拉一堆杂乱绳索去操控复杂机械,靠运气来奏效。纯文本输出解析面临以下痛点:
- 脆弱性:LLM 输出词句的细微变动(加词、换序)会导致解析失败,陷入解析代码与模型输出不断博弈的“军备竞赛”。
- 模糊性:自然语言天生含糊难辨。对人类一目了然的指令,解析器可能一头雾水。例如,“调用 John Smith”时,数据库里可能有多个 John Smith,难以判定目标。
- 维护复杂:解析逻辑不断膨胀纠缠,新增功能时需要写更多解析规则,维护成本高。
- 能力受限:难以支持多工具调用、复杂数据结构传递,模型输出限制了系统潜能。
解决方案:
让模型返回结构化数据(JSON 或类似格式),由系统负责执行对应操作。
核心理念是:LLM 专注理解用户意图并选择调用工具,系统承担具体执行和验证职责。
目前绝大多数主流模型供应商(OpenAI、Google、Anthropic 等)都支持“函数调用”或输出符合严格 JSON Schema 格式的能力。
流程概述:
- 定义工具:用 JSON Schema 描述函数(工具),包含名称、功能描述、输入参数等,描述越清晰越准确,模型理解越好。
- 传给模型:调用时把工具描述与上下文一并输入给 LLM。
- 模型输出:非自由文本,而是返回符合 Schema 的 JSON,内容包含要调用的函数名及参数。
- 执行调用:系统代码校验 JSON 格式并调用对应工具函数。
- 反馈响应(可选):执行结果返回给 LLM,辅助其生成最终回复。
若无法使用函数调用怎么办?
- 明确提示模型以 JSON 格式输出,并给出示例。
- 使用如 Pydantic 之类工具进行严格解析和校验。
- 这种纯 JSON 解析方法也有支持者,能显著提升稳定性。
检查清单:
- 响应输出严格格式化(例如 JSON)
- 明确使用 Schema(JSON Schema 或 Pydantic)定义格式
- 调用前对返回内容进行校验,确保格式正确
- 对格式错误有完善的处理逻辑,避免系统崩溃
- LLM 负责函数选择,执行由后端代码实现
6. 掌控流程
问题:
智能体通常以“对话”形式运作——用户先发言,智能体回应,如同乒乓球击球回球,虽便捷但局限明显。
这种对话式智能体无法实现:
- 无需请求即可主动行动
- 并行执行多个任务
- 预先规划执行步骤
- 连续执行多步操作
- 检查执行进度并重试失败步骤
相反,智能体应当管理自身的“执行流程”——决定下一步该做什么及如何做,类似任务调度器,按顺序执行待办事项。
这意味着智能体具备:
- 自主决策行动的时机
- 连续多步执行能力
- 失败操作的重试机制
- 任务间的切换能力
- 即使无明确请求也能持续工作
解决方案:
将控制流程从 LLM 中剥离,由代码层负责管理。模型仅在具体步骤中提供辅助或建议下一步。实现从“写提示”向“设计受控行为系统”的转变。
三种主流实现方案:
-
有限状态机(FSM)
- 明确定义状态及状态转换
- LLM 决定下一步动作或在当前状态内执行
- 优点:结构简单、行为可预测,适合线性流程
- 常用工具:StateFlow、YAML 配置、状态模式实现
-
有向无环图(DAG)
- 任务以非线性或并行形式构成图结构,节点代表动作,边表示依赖关系
- LLM 用于节点决策或辅助计划生成
- 优点:灵活,支持并行执行,具备良好可视化
- 常用工具:LangGraph、Trellis、LLMCompiler、自定义 DAG 实现
-
规划器 + 执行器
- LLM 负责整体规划,代码或其他智能体负责具体执行
- 通常“大”模型做规划,“小”模型或代码做执行
- 优点:职责分明、成本可控、易于扩展
- 常用工具:LangChain 的 Plan-and-Execute 模式
重要性:
- 提升系统的可控性、稳定性与扩展性
- 支持多模型协同,加快任务执行
- 任务流程可视化,便于测试与调试
检查清单:
- 采用 FSM、DAG 或显式状态/转换管理流程
- LLM 决策动作,流程控制由代码实现
- 行为流程可视化,便于监控和分析
- 流程中具备完善的错误处理机制
7. 人机协同
问题:
即使智能体采用了结构化工具和清晰流程,现实中让 LLM 智能体完全自主仍属理想(或视情境为噩梦)。LLM 本身缺乏真实洞见,不具备责任意识,尤其在处理复杂、模糊场景时,决策表现常常不尽如人意。
全自主的主要风险包括:
- 永久性错误:智能体可能执行不可逆的破坏性操作(如删除数据、向重要客户发送错误信息、触发自动系统异常等)
- 合规风险:智能体可能无意中违反相关法律法规或服务规范
- 缺乏常识与伦理:忽视人类社会中的行为准则与常理
- 用户信任流失:连续性错误会迅速削弱用户信任
- 审计与问责困难:难以界定错误责任归属
解决方案:
策略性引入“碳基生命体”(人类),在关键节点参与智能体的判断与决策,实现人机协同。
人机协作常见方式:
-
审批流程
- 应用场景: 关键、昂贵或不可逆操作
- 实现方式: 智能体提出操作建议,待人工审批确认后执行
-
置信度感知路由
- 应用场景: 模型不确定或存在歧义时
- 实现方式: 模型进行自我评估(如 logit 分布、由 LLM 充当裁判、基于 P(IK) 等方法),置信度不足则自动请求人工介入
-
人类即工具
- 应用场景: 数据不足、指令模糊或上下文理解困难
- 实现方式: 智能体调用“人类工具”,请求澄清或补充信息(如 CrewAI 中的 HumanTool 模式)
-
备选升级机制
- 应用场景: 智能体重复失败或超出其能力范围
- 实现方式: 将任务及当前上下文转交人工处理或人工复核
-
RLHF(基于人类反馈的强化学习)
- 应用场景: 用于持续迭代与优化模型表现
- 实现方式: 人工对模型输出进行评价,反馈结果用于训练或微调模型
检查清单:
- 关键操作是否设置人工审批机制
- 是否具备置信度评估与分流机制
- 智能体能否主动发起对人类的提问请求
- 所有关键步骤是否需人工确认
- 是否具备人工可操作的界面用于输入与反馈
8. 将错误浓缩进上下文
问题:
大多数系统在遇到错误时的标准行为是“崩溃”或在报错后终止。对于需要自主完成任务的智能体而言,这种行为模式并不理想。然而,也不能接受其在出错后通过“幻觉”方式自行圆场。
常见问题包括:
- 脆弱性:外部工具调用失败或 LLM 响应异常,可能导致整体流程中断或行为偏离目标
- 低效性:频繁的系统重启或依赖人工干预会导致流程效率下降
- 缺乏自适应能力:若智能体无法“感知”自身错误或缺乏错误上下文,便难以实现有效修正
- 幻觉反复出现:在错误处理不当的情况下,模型倾向于虚构合理性解释而非解决问题
解决方案:
将错误信息显式引入到提示词或智能体记忆中,构建具备“自愈”能力的流程,使其尝试自我纠错和行为调整。
推荐流程包括:
-
错误识别
- 智能体或其调用逻辑应能识别常见故障(格式错误、工具不可用、API 异常等)
-
自我纠正机制
-
设计明确的错误处理逻辑,包含:
- 错误检测与分类
- 基于上下文的任务重构或请求参数修改
- 尝试替代工具或途径执行任务
-
-
效果反思与提示增强
- 提示中引入更明确的错误信息和历史记录,能显著提升智能体的修复能力
- 即便仅提示“上次失败,尝试其他方案”也可能改善响应质量
-
内部自纠机制
- 通过训练数据引入“错误-修复”对,使模型具备一定的自我纠错能力
- 某些系统会引导模型在每步决策后“反思是否合理”
-
升级至人工处理
- 若自愈流程多次失败,应触发人工介入机制(参见原则 7)
检查清单:
- 是否将上一步的错误信息写入智能体上下文
- 是否具备自动重试或调整重试逻辑
- 在重复失败后,是否触发备用方案或升级至人工介入
9. 拆解复杂度为多个智能体
问题:
从 LLM 的上下文窗口限制出发,我们换一个角度重新审视。当任务愈发庞大复杂、步骤增多时,整体的上下文长度随之增长。而随着上下文窗口的扩大,LLM 更容易在处理过程中出现信息丢失、注意力分散、逻辑断裂等问题。因此,将智能体聚焦于某一具体任务、限制在 3–10 个步骤(最多不超过 20 步),能够有效控制上下文规模,从而保障模型性能的稳定与输出的一致性。
解决方案:
构建针对具体任务的小型智能体,每个智能体专注完成一项明确职责,由上层系统负责统一编排。
小型专注智能体的优点:
- 上下文可控:上下文窗口更短,更适配模型能力范围
- 职责清晰:每个智能体围绕单一目标展开,逻辑闭环
- 可靠性更高:减少流程混乱、上下文错乱等情况
- 测试简便:功能范围明确,便于设计针对性测试用例
- 调试高效:故障定位更快,便于快速修复和优化
限制与实践观察:
遗憾的是,当前并无统一启发式规则可用于判断何时应将任务拆分为多个智能体。随着技术演进,LLM 的能力持续增强,本文发布时实验室中的模型已变得更为智能,因此任何固定形式的拆分标准都可能在短期内过时。任务越小实现越简单,但任务越大,所蕴含的潜力亦越大。判断的关键仍依赖于经验积累与工程直觉——但这本身也并非绝对可靠。
检查清单:
- 任务场景由多个可独立微服务调用组成
- 每个智能体具备独立运行、测试和重启能力
- 每个智能体的核心逻辑可用一两句话准确描述