1. 删架构之前的真实现场:一个Agent项目是怎么被拖垮的
做了一年多的Agent,这时间不算长,但足够把各种主流范式都试一遍。先直接说结论:这一年里让我最肉疼、但收益最大的一次改动,就是把一个团队搭了两个多月的“完整架构”删掉了。现在回头看,那不是我删掉的第几版方案,而是主动放弃了一种“看起来很专业”的建设方式。整个过程不是拍脑袋,是数据一步步逼出来的。
我当时接手的业务场景是智能客服Agent,负责售前咨询、订单查询、售后流转三类任务。听起来不复杂,但一接过来我就发现,代码库里的设计远比业务本身复杂。系统里跑着Planner(规划器)、Executor(执行器)、Verifier(验证器)三层,同时还挂着主管Agent、反思Agent,甚至还有一个专门用于“争议裁定”的Agent。记忆体系也分短期、长期、摘要、向量检索四套。工具层更不用提,统一网关、权限校验、重试策略、路由配置,应有尽有。
演示效果确实好。演示环境里,Agent回答连贯、逻辑清晰、能解释自己的步骤,看起来非常有“智能感”。但真实用户流量一进来,问题立刻暴露:一个普通的订单查询,用户在输入框敲了一句话,等回复要七八秒;稍微复杂一点的售后问题,Agent内部要来回调用好几轮LLM,中间偶尔还会出现反思Agent给出一个“貌似合理”的修改建议,主Agent采纳后,答案反而跑偏。
最折磨人的是排查。线上用户反馈“回答不对”,我打开日志,发现一条请求背后有五六次模型调用,分布在不同的Agent模块里,很难判断是哪一层出了问题。是规划错了?是反思改坏了?还是记忆摘要污染了?每条链路都有可能。我花在“猜”上的时间,比写新功能的时间还多。
那个阶段我经常跟同事说一句话:这个系统不是不聪明,是不稳定。它稳定地浪费着算力,稳定地变慢,稳定地在某些输入上翻车。而所有这些问题,都指向同一个根源——我们给一个本该轻量的问题,装了一副过于沉重的骨架。
后来我和团队坐下来复盘,问了一个很朴素的问题:这些架构组件,到底哪个在真实场景里产生了正收益?没人能给出量化答案。我们只有一堆流程图、概念图,和一些“理论上应该更好”的信心。那时候我就隐约意识到,这个方向大概率错了。真正动手去删,是在想清楚以下三个机制之后。
2. 重架构拖垮Agent的三个机制:Token、错误传播与无法定位
先说Token。很多人以为多几次LLM调用只是“慢一点”,但实际代价远比想象中大。我们当时给每个Agent都写了人设:规划Agent要有“战略思维”节奏,反思Agent要“批判性审视”,裁定Agent要“客观中立”。每个Agent的System Prompt动辄几千字,业务知识还要反复塞进上下文。一次用户请求,内部多次调用,每次调用都带着一大段冗余文本,输入Token很快破万。这不仅让单次请求的延迟暴涨,还直接把成本推高了一个量级。
更隐蔽的是上下文污染。某次反思Agent在分析用户问题时,随手生成了一段“用户可能对物流不满”的猜测,被写入记忆摘要。后续主Agent读取摘要后,完全跟着这个错误假设走,把原本简单的地址修改问题误判成物流投诉,来回兜圈子。这类问题在重架构里几乎无法根治,因为你不知道哪一次中间调用会往共享上下文里写脏数据。
再说错误传播。LLM本质是概率模型,任何一次调用都有失败概率。把多个概率模型串成一条流水线,整体成功率会相乘递减。假设主Agent的单步准确率是85%,反思Agent“正确修正”的概率是80%,验证器“正确判断结果可用”的概率是85%,三层叠加后的整体成功率只有58%左右。57.8%的成功率意味着,接近一半的用户请求得不到可用结果。而如果直接用单次模型调用,只要模型本身能力够,成功率就是那一次调用的水平,明显更高。
这也是“多Agent协作”最容易被高估的地方:理论上各司其职,实际上错误在层与层之间传递,而且每一层都在消耗时间和Token。很多人没有意识到,多Agent之间的对话并非免费的“智慧碰撞”,它们是在用真金白银和用户耐心做代价。
最后是无法定位。重架构下,一条请求会分裂成多条日志:Planner输出一个计划,Executor逐条执行,Verifier给出判定。如果最终结果错了,你必须同时检查计划是否合理、工具执行是否成功、反思是否把对的改成错的。这种排查成本在开发阶段还能忍,一旦线上用户量大起来,就完全不可接受。我统计过,当时排查一个中等复杂度问题平均要花二十分钟,其中大部分时间在“对照多个Agent的输出日志,猜是哪一步的锅”。
这三个机制叠加在一起,解释了我当时看到的全部现象:慢、贵、不稳、难查。而它们恰恰是架构复杂度带来的直接代价。所以当团队里有人提出“我们能不能不搞这么多层次”的时候,我没有像之前那样反驳,而是决定做一次严格对照实验,用数据来判断到底该删谁。
3. 动手删架构前,我先把“谁有用”做成了可以量化的对照实验
很多文章会教你直接删,但我想强调:盲删和盲堆一样危险。我当时做了一个为期两周的对照实验,思路很简单但有效。先把线上流量复制一份,维护A、B两条评估链路。A链路保持原架构不变;B链路则用我最想验证的极简方案:一个核心Agent + 原生工具调用 + 精简后的提示词,不搞多Agent,不搞状态机。两组用同一批测试集跑,测试集包含三百条真实用户问题,覆盖售前、售后、订单异常和多轮追问。
第一批结果就让我有点坐不住。B链路的任务完整解决率是87%,A链路只有74%。注意,B链路没有任何额外优化,只是删掉了架构,结果反而高了十三个点。我第一反应是测试集有偏差,于是人工抽检了三十条差异案例,发现A链路的大量失败来自“中间某个Agent把正确结果改错”或“验证器错误拦截了本来可用的回答”,而不是模型能力不足。这说明复杂编排确实在添乱。
更讽刺的是反思Agent。我单独做了一个剥离测试:把反思层关闭,只保留Planner+Executor。结果在简单任务上成功率不降反升,追问类任务基本持平。反思步骤在多数场景下根本没有“反思”到位,只是在消耗一次额外的模型调用和几秒钟延迟。真正有价值的反思极少——大概只有5%左右的复杂请求确实需要二次修正,而这部分完全可以用另一条策略处理,而不是全局无差别加一层。
实验做到这里,该删什么已经不言自明。我按顺序做了清理:先删掉主管Agent、反思Agent和裁定Agent,它们属于典型的“协作幻觉”;再删掉状态机和固化流程编排,改成轻量的关键字段判断;最后把四套记忆体系压缩成“最近5轮上下文 + 业务关键信息”的简单结构。向量检索暂时下线,因为业务场景里的知识召回需求远没有想象中频繁。
这次“删”不是一刀切。机制上保留了三个东西:工具封装层、输出校验、以及少量经过验证的few-shot示例和常见问题预案。工具封装是有实际价值的,因为真实业务必须对接订单系统、库存系统、售后工单系统,这些接口不能让模型自己裸调;输出校验能防止模型吐出不合法结构;预案代码则像一个兜底网,处理模型明显超出边界的情况。至于那些纯“架构感”的东西,一律不留。
4. 删除之后的形态:所谓“无架构”到底长什么样
删完之后,整个Agent的核心逻辑变得非常朴素,看起来甚至有点简陋。核心循环就一个:
import json from typing import List def run_agent(user_input: str, user_info: dict): messages = build_messages(user_input, user_info) tools = get_available_tools() for _ in range(MAX_TURNS): # 一般限制3轮 response = llm.chat(messages=messages, tools=tools) if response.tool_calls: messages.append(response.message) for call in response.tool_calls: result = execute_tool(call) messages.append({ "role": "tool", "tool_call_id": call.id, "content": json.dumps(result, ensure_ascii=False) }) continue return validate_response(response.text) return fallback_response()就这些。没有Planner,没有状态机,没有反思层。模型根据工具列表自己决定调用哪些工具、按什么顺序调用、什么时候给出最终答案。这个设计能跑起来,依赖的是当前模型已经具备的原生工具调用(function calling)能力——模型内部已经有“规划”的能力,代码层再包一层Planner,属于重复发明轮子。
但如果你以为这个方案什么都不用管,那就大错特错了。真正的工作量其实转移到了三个不那么显眼的地方。
第一是工具列表的精简。我特意把工具数量控制在八个以内,每个工具的docstring都写得极其详细:参数类型、单位、返回结构、可能的异常输出、典型失败场景。比如订单查询工具的docstring里会写明“当订单状态为PAY_PENDING时,用户的问题应该转向支付相关问题,不要尝试售后流程”。模型会认真读这些描述来做决策,工具描述写得越清晰,模型用得越准。
第二是提示词的结构。我放弃了长篇大论的任务说明,只保留四块:一句话身份、任务边界、动态工具说明、明确的兜底规则。其中兜底规则最重要,比如“如果查询接口返回空结果,必须向用户说明暂时无法获取信息,禁止编造订单状态”。这一类硬约束,是替代Verifier的关键。
第三是输出结构校验。模型返回的最终回答必须符合预定义的JSON结构,包含“回复文本”“是否需要人工介入”“命中的知识范围”三个字段。我会在代码里做一次校验,不合格就把整段回复丢弃,走兜底流程。这个校验不贵,却能拦住很多幻觉输出。
这套方案跑通后,我才真正理解了那句话:好的架构不是被“写”出来的,是“生长”出来的。极简并不等于不做工程化,而是把工程化用到刀刃上——代码管流程,模型管判断。在这个形态下,新增一个业务功能只需要加一个工具、改一段提示词,不需要再跑到调度层加节点。
5. 删除前后的量化对比:一次完整评估
删架构不是情怀,得有实打实的数字支撑。我整理了同一批测试集、同一时段线上日志的关键指标,这里列出来给大家参考。需要说明的是,这些数字来自我实际经手的某个特定业务场景,不保证普适,但趋势很有代表性。
| 指标 | 删除前 | 删除后 | 变化 |
|---|---|---|---|
| 任务完整解决率 | 74% | 92% | +18% |
| 平均响应时长(单次请求) | 6.8秒 | 2.4秒 | -65% |
| 单请求平均消耗Token | 约9.2k | 约4.1k | -55% |
| 无效工具调用占比 | 31% | 12% | -19% |
| 新增一个知识范围的平均开发周期 | 2.5天 | 0.5天 | -80% |
| 人工介入率 | 19% | 8% | -11% |
其中响应时长的变化最直观。删除前用户问完一句话,系统内部要对多个Agent进行串行调用;删除后大部分请求一次模型调用就能完成,最多再追加一两次工具调用。我做了一个小实验模拟用户感知:同样的问题,旧架构下等出答案的时间够我读完三行代码,新架构下基本是“刚点完发送就看到回复”。这种体验差异对留存的影响,比任何架构图都更有说服力。
Token成本的下降也不难解释。多Agent架构意味着同一个用户问题会被不同的角色模型重复阅读,每个角色都带着独立的长提示词。删掉这些冗余后,单请求Token输入量直接腰斩。我算过一笔账:如果一个月有十万次请求,新架构能省下约五倍的Token费用,这部分省下来的钱完全可以投入到更优质的模型选型上。
但我也要泼一盆冷水:这些数据不能简单归结为“删架构的功劳”。那一年模型本身也在快速变强,B链路使用的模型版本就比A链路晚了两代,功能调用能力、指令遵循能力都有明显提升。所以准确的说法是:模型能力变强是前提,删除冗余架构是放大器。如果你手里拿到的是当前最新一代模型,却还在跑两年前那套多Agent重型框架,那大概率是在给模型拖后腿。
另外,评估里最难量化但实际收益最大的一项是“调试时间”。删除前,定位一个线上问题需要十几分钟;删除后,因为整体链路只有一条,打开日志看工具调用序列和模型输出就能直接判断,通常一两分钟就能定位。对于小团队来说,这可太重要了。它直接决定了你一天能做多少事,也决定了团队敢不敢频繁迭代。
6. 架构删完之后踩的坑:没有架构不等于可以不设防
如果你以为删完架构就一马平川,那就太天真了。新方案上线后,我确实追了一段时间的问题,但踩出来的坑完全不一样了。第一波问题基本集中在“模型自由度过大”上。以前有Verifier兜着,模型就算想胡来,后面还有一个检查环节。现在没有这一层了,模型偶尔会胆子变大,最典型的就是用户问了一个不在业务范围内的问题,模型会尝试编造一个答案,而不是承认自己不知道。
我处理的办法是把“不得超出工具结果范围”写进提示词,并在代码里做强制校验:如果模型的回答引用了某个工具的结果,而这个工具实际没有被调用过,就判定为无效回答,走兜底话术。这相当于把验证从“事后检查内容质量”改成“事前卡住引用来源”,成本更低,效果也更直接。
第二个坑是工具门禁。删除向上编排后,工具执行层成了整个系统的命门。如果订单查询接口超时,模型会试图重试;如果连续重试都失败,它可能会编一个“系统繁忙”之外的模糊解释。我后来加了一个简单的规则:单轮最多允许模型调用同一个工具两次,超过就主动终止执行,返回预设话术并标记人工介入。这个规则很死板,但它把失败模式收敛成少数几种,方便我持续优化。
第三个坑更隐蔽,是工具本身的“吸引力”。新Agent架构下,模型是逐字阅读工具描述来决定行为的。如果某一天我加了一个功能强大但描述模糊的工具,模型会倾向于频繁使用它,哪怕这个工具跟用户问题根本不相关。我观察过一次离谱行为:知识检索工具描述里写着“支持查询常见问题”,结果用户问“退款多久到账”,模型不去查售后工具,反而去检索知识库,拿回一段泛泛而谈的说明。后来我把工具描述改得非常精确,强调“此工具用于查询政策文档,不包含用户订单和售后处理信息”,这种错配才明显减少。
所以我的体会是:删掉架构后,你要盯的指标不是“有没有架构文档”,而是“模型在哪些工具上浪费了次数”“哪句话术让用户重复追问”“哪个异常分支没有兜底”。工程化的工作量并没有消失,只是从编排层转移到了提示词、工具设计和异常处理上。换句话说,极简方案依然需要大量精细化工作,只不过它的重心更靠近模型和工具本身,远离了一堆空转的中间层。
7. 复盘:什么场景下“删架构”是蠢的,什么场景下它是必要的
写了这么多,我必须把边界条件讲清楚,否则这篇总结会误导不少人。这一个改动在我当时的业务里是正确的,但它并不具备普适性。至少有三类场景下,代码化编排和多Agent协作确实有用,删了反而是灾难。
第一类是强合规、强流程约束的场景。比如退款审批、理赔处理、工单派发,这类任务的子步骤有严格顺序,且每一步都需要留痕。如果一个Agent在理赔流程里“自由发挥”,先给用户放款再走风控,业务上绝对不可接受。这种场景必须用代码状态机把流程钉死,LLM只能充当某个节点上的判断器,不能拥有全局调度权。我后来在另一个偏风控的项目里就老老实实保留了大量代码化约束,绝不套用极简方案。
第二类是高并发下的任务分拆场景。当一个任务需要并行查询多个独立数据源,或者需要在多个子任务间做优先级调度时,一个简单的单循环就明显不够了。这时候需要队列、任务派发和合并层。你要是硬拿单Agent去扛,模型会变成瓶颈,而且工具并发也不好控制。这类场景的重点已经从“模型智能”变成了“并发工程”,删架构属于自残。
第三类是子步骤之间存在强依赖且错误代价极高的场景。虽然当前模型规划能力强了很多,但在某些专业领域,错误规划一次的成本可能是几十万。这时候用代码把依赖顺序固定下来,比让模型自由决定更稳妥。判断标准很简单:错误的代价越高,越应该用代码兜底,而不是信任模型临场发挥。
我个人的判断原则就一条:任何架构组件,从Planner到多Agent协作,从反思层到向量记忆,都必须能回答一个问题——它到底解决了哪个具体问题,去掉它之后哪个指标会变差。如果指标说不出来,这个组件大概率就是负资产。你不需要一步到位的全面极简,但最好每半年审视一次整个系统,把那些无法量化价值的层删掉,让架构保持与业务复杂度匹配的状态。
说真的,删掉那套架构之后,我做Agent最大的感受是:所谓智能,本来就应该尽量减少代码层面的“自以为聪明”。代码擅长的是流程、校验、并发、异常处理;而判断、规划、语言表达这些,应该更多地交给模型自己。把两者边界划清楚,比维护一个华丽的分层架构重要得多。