Agent开发:从接API到生产级系统的工程实践
1. 从接个API就完事说起Agent开发里最容易被低估的认知陷阱Agent网页接个api就万事大吉——这个标题本身就带着一股反问的火药味。我特别理解这种情绪因为过去一年多里我见过太多团队在Agent项目上栽跟头而栽跟头的方式惊人地一致他们真的以为把大模型的API往网页上一接Agent就活了。先说结论接API只是Agent开发的第0步连第1步都算不上。一个能跑通Demo的Agent和一个能在生产环境里稳定干活的Agent中间隔着的距离比很多人想象的要远得多。这个距离不是靠换一个更强的模型就能填平的它涉及到架构设计、状态管理、容错机制、知识库工程、工具调用协议、上下文预算控制等一系列工程问题。我先把话说透如果你现在做的Agent用户问一句它答一句中间不需要调用任何外部工具不需要记住上一轮对话里用户提到的订单号不需要在三个不同的数据源之间做交叉验证那确实接个API就够了。但只要你开始碰下面这些场景中的任何一个事情就会立刻变得复杂用户说帮我查一下上个月那笔退款到哪了Agent需要先识别这是查询意图然后调用订单系统API拿到订单号再调用支付系统API最后把两个结果拼起来用自然语言回复。用户上传了一份50页的PDF合同问第3.2条和第7.1条有没有冲突Agent需要先做文档解析、切片、向量化再检索相关段落最后让模型做推理。用户连续问了5个问题每个问题都依赖前一个问题的答案Agent需要维护一个跨轮次的状态机而不是每次都把全部历史塞进上下文。这些场景里API调用只是最外层的一层皮。真正决定Agent能不能用的是皮下面那套骨架——也就是我接下来要拆解的东西。提示如果你正在评估一个Agent项目能不能落地先别问用哪个模型先问它的状态怎么管、工具怎么调、错了怎么恢复。这三个问题答不上来模型再强也白搭。2. Agent的骨架到底长什么样拆开看四个核心模块很多人对Agent的理解停留在LLM Prompt这个层面这就像把一辆车理解成发动机 方向盘。能跑但跑不远。一个完整的Agent系统至少包含四个核心模块每个模块都有自己独立的工程挑战。2.1 规划模块Agent的大脑皮层规划模块负责把用户的模糊意图拆解成可执行的步骤序列。比如用户说帮我安排下周去北京的行程规划模块要输出的是类似这样的东西查询用户日历确认下周哪些时间段空闲查询航班/高铁信息筛选符合时间窗口的班次查询北京当周的天气判断是否需要提醒带伞查询用户偏好的酒店品牌推荐住宿把以上信息整合成一份行程草案这个拆解过程业界目前主要有三种做法ReAct模式推理-行动交替、Plan-and-Execute模式先出完整计划再执行、Tree-of-Thought模式多路径探索后选最优。三种模式没有绝对优劣选哪种取决于你的任务复杂度和对延迟的容忍度。我实测下来的经验是任务步骤少于5步、步骤之间依赖关系简单的用ReAct就够了步骤超过8步、或者存在条件分支的Plan-and-Execute的稳定性明显更好。但Plan-and-Execute有个坑——如果第一步执行失败整个计划可能全盘作废所以必须配合重规划机制。2.2 记忆模块别再把所有历史都塞进上下文了记忆模块是Agent开发里最容易被做烂的部分。我见过太多项目做法简单粗暴把用户所有历史对话拼成一个字符串每次请求都全量塞进去。结果就是token消耗爆炸而且模型在长上下文里反而容易迷失忘记关键信息。正确的做法是把记忆分层记忆类型存储内容存储位置典型生命周期工作记忆当前任务的中间状态内存/Redis单次会话短期记忆最近N轮对话摘要内存数据库数小时到数天长期记忆用户偏好、历史事实向量库结构化库永久实体记忆订单号、用户ID等关键实体结构化库按业务规则工作记忆和短期记忆的区别在于工作记忆是当前这一步需要什么短期记忆是这个会话里发生过什么。举个例子用户说把刚才那个订单取消掉Agent需要从短期记忆里找到刚才那个订单对应的订单号然后把它放进工作记忆再调用取消接口。注意记忆模块的设计直接决定了Agent的token成本。我做过一个对比同样一个客服Agent全量上下文方案平均每次请求消耗8000 token分层记忆方案只消耗1200 token成本差了将近7倍而且响应速度还更快。2.3 工具调用模块API不是接上就能用工具调用模块负责把LLM的意图翻译成实际的API调用。这里面的坑比大多数人想象的多得多。第一个坑是参数校验。LLM输出的参数格式经常不靠谱比如它可能把日期输出成下周三而不是2025-06-18可能把金额输出成一千块而不是1000。你必须在工具层做严格的参数校验和归一化不能直接信任模型的输出。第二个坑是错误处理。API调用失败是常态不是异常。网络超时、限流、返回格式变更、权限过期这些都会发生。Agent必须能区分可重试错误和不可重试错误前者自动重试后者要么降级要么向用户报错。第三个坑是工具描述的质量。很多人写工具描述就一句话查询订单信息这远远不够。好的工具描述应该包含功能说明、参数含义、参数格式示例、返回值结构、常见错误码。工具描述的质量直接决定了模型能不能正确选择工具和构造参数。2.4 执行循环Agent的心跳执行循环把上面三个模块串起来形成一个感知-决策-行动-观察的闭环。这个循环的设计要点是必须有明确的终止条件。我见过最离谱的案例是一个Agent陷入了无限循环因为它每次调用工具失败后都会重新规划重新规划后又调用同一个工具如此往复一晚上烧掉了几百美元的token。终止条件至少要包含最大迭代次数、最大token预算、最大执行时间、连续失败次数阈值。这四个条件任意一个触发循环都必须停下来要么返回部分结果要么向用户报错。3. RAG不是把文档塞进向量库知识库工程的真实工作量Agent要回答专业问题光靠模型自身的知识是不够的必须外挂知识库。这就是RAG检索增强生成要解决的问题。但RAG的落地难度被严重低估了。3.1 文档解析最脏最累但最关键的环节RAG的第一步是把文档变成可检索的文本。这一步听起来简单实际上是最容易翻车的地方。PDF解析就是第一个拦路虎。很多PDF是扫描件需要OCR有些PDF有复杂的表格和图表普通解析器会把表格结构打乱还有些PDF是多栏排版解析出来文字顺序全乱。我试过市面上主流的几个解析方案对于结构复杂的文档解析准确率能到85%就算不错了。这里有个经验如果你的文档里有大量表格不要指望通用解析器能处理好要么用专门的表格识别方案要么在切片阶段做特殊处理把表格单独抽出来做结构化存储。3.2 切片策略切得好不好直接决定检索质量切片Chunking是RAG里最考验经验的一步。切得太碎语义不完整检索出来的片段没法用切得太粗噪声太多模型容易被无关信息干扰。我常用的策略是语义切片 重叠窗口先按文档的自然结构标题、段落、列表做粗切对超过阈值的长段落按语义相似度做细切相邻切片之间保留10%-20%的重叠内容避免关键信息被切断切片大小没有万能值。技术文档通常300-500 token比较合适法律合同可能需要800-1000 token因为条款之间的关联性强切太碎会丢失上下文。3.3 检索策略向量检索不是银弹很多人做RAG就只用向量检索这在实际场景里经常不够用。向量检索擅长语义匹配但对精确匹配比如订单号、产品型号、人名反而不如关键词检索。我的做法是混合检索向量检索 BM25关键词检索两路结果做融合排序。融合算法可以用RRFReciprocal Rank Fusion简单有效不需要训练。再进一步如果知识库有明确的结构比如产品手册有章节层级可以引入结构化知识库做辅助。结构化知识库和向量知识库的区别在于前者存的是实体-关系-属性这样的三元组适合回答XX产品的保修期是多久这类精确问题后者存的是文本片段适合回答XX产品的使用注意事项有哪些这类开放问题。知识库类型适用问题检索方式典型场景向量知识库开放式、语义类问题向量相似度文档问答、客服结构化知识库精确、关系类问题图查询/SQL产品参数、组织架构混合知识库复合型问题多路召回融合综合咨询3.4 重排序把最相关的片段放到最前面检索出来的片段顺序很重要。模型对上下文开头和结尾的内容注意力更集中所以最相关的片段应该放在最前面。重排序Rerank就是用一个小模型对检索结果做精排。我实测下来加了Rerank之后答案准确率能提升15%-25%尤其是当检索结果里有多个相似片段时效果更明显。提示Rerank模型的选择上不要盲目追求大模型。很多场景下一个几百MB的轻量级Rerank模型效果已经足够好而且延迟低得多。4. 容错与安全Agent从Demo走向生产的分水岭Demo阶段的Agent跑通一次就算成功。生产阶段的Agent要保证在99%的情况下都能给出合理响应哪怕底层服务挂了、模型抽风了、用户输入了奇怪的东西。4.1 模型输出的不确定性怎么兜底LLM的输出本质上是概率性的同样的输入可能得到不同的输出。这在生产环境里是个大问题。我的做法是多层校验第一层格式校验。用JSON Schema约束模型输出格式不对直接重试。第二层业务规则校验。比如金额不能为负、日期不能是过去、订单号必须符合特定格式。第三层一致性校验。如果Agent需要输出多个相关字段检查它们之间是否自洽。如果三层校验都过了但结果仍然可疑可以引入LLM as Judge机制用另一个模型或者同一个模型的不同prompt来评估输出的合理性。这个机制会增加成本所以只在高风险场景下启用。4.2 工具调用失败的恢复策略工具调用失败是常态。我的恢复策略分三级自动重试对于超时、限流这类临时性错误自动重试2-3次每次重试间隔递增。降级处理对于某个工具持续失败的情况切换到备用工具或备用数据源。比如主搜索服务挂了切到备用搜索。优雅报错如果所有尝试都失败向用户返回明确的错误信息并给出替代方案。比如订单查询服务暂时不可用您可以稍后重试或者提供订单号我帮您人工核实。关键是任何一级失败都不能让Agent直接崩溃或者返回一堆乱码。用户看到的应该始终是自然语言而不是堆栈信息。4.3 上下文长度超限的应对上下文长度超限是Agent开发里最常见的报错之一。尤其是当Agent需要处理长文档、多轮对话、大量工具返回结果时很容易就撞上模型的上下文上限。应对策略有四个摘要压缩把历史对话做摘要只保留关键信息。滑动窗口只保留最近N轮对话更早的丢弃或归档。分段处理把长文档拆成多段分段送入模型最后合并结果。外部存储把中间结果存到外部上下文里只放引用ID。我通常组合使用这四种策略。比如一个文档问答Agent文档内容存向量库对话历史做滑动窗口工具返回结果只保留关键字段这样能把上下文控制在合理范围内。5. 多Agent协作什么时候该用什么时候是过度设计多Agent协作是最近很火的话题但我必须泼一盆冷水大多数场景下单Agent 多工具就够了多Agent协作反而会增加复杂度和不确定性。5.1 多Agent真正适用的场景多Agent协作适合以下几种情况任务可以明确分工比如一个Agent负责检索一个Agent负责推理一个Agent负责格式化输出。需要不同角色的视角比如一个Agent扮演支持方一个Agent扮演反对方通过辩论提高决策质量。任务规模超出单Agent的处理能力比如需要同时处理多个独立子任务。但如果你的任务只是查个订单然后回复用户上多Agent就是杀鸡用牛刀而且牛刀还容易砍到自己。5.2 多Agent协作的通信成本多Agent之间通信本质上是在传递上下文。每传递一次就多一次token消耗多一次信息丢失的风险。我做过一个测试一个三Agent协作的系统完成同一个任务token消耗是单Agent方案的3.5倍延迟是2.8倍而任务成功率只提升了不到5%。这个投入产出比在大多数业务场景下是不划算的。所以我的建议是先用单Agent把流程跑通遇到明确的瓶颈再考虑多Agent。不要为了架构好看而引入多Agent。6. 几个我踩过的坑和对应的解法6.1 工具描述写得太简略模型选错工具早期我做Agent的时候工具描述就写一句话。结果模型经常选错工具或者把参数传错。后来我把工具描述写详细了包括功能、参数、示例、错误码工具选择准确率从60%多提升到了90%以上。6.2 没有做幂等重复调用导致数据错乱有一次Agent在重试机制下同一个创建订单的请求被调用了两次结果用户被扣了两次款。后来我在所有写操作的工具上都加了幂等键问题才解决。6.3 上下文里塞了太多无关信息模型跑偏有一段时间Agent总是答非所问。排查后发现是因为上下文里塞了太多工具返回的原始数据模型被这些数据干扰了。后来我在工具返回结果进入上下文之前先做了一层过滤和摘要只保留关键字段问题就消失了。6.4 没有监控出了问题不知道Agent上线后如果没有完善的监控出了问题只能靠用户反馈。我后来加了一套监控记录每次请求的输入、输出、工具调用链、token消耗、延迟这样出了问题能快速定位。7. 写在最后Agent开发没有银弹回到标题那个问题Agent网页接个api就万事大吉——显然不是。接API只是起点后面还有规划、记忆、工具调用、RAG、容错、监控一大堆事情要做。但我也不是说Agent开发有多难。这些事情每一件都有成熟的方案和工具关键是你要知道它们存在并且在合适的时机引入。我的建议是先用最小可行的方案把流程跑通然后根据实际遇到的问题逐步完善。不要一开始就追求大而全的架构那样很容易陷入过度设计。最后分享一个我自己的判断标准如果一个Agent项目你能清楚地回答它的状态存在哪、工具调用失败怎么办、上下文超了怎么处理、怎么知道它出问题了这四个问题那这个项目基本就靠谱了。如果答不上来那大概率还停留在接个API的阶段。