本来想聊点轻松的技术话题,但这篇得先把一个常见的坑说透。最近接连看了好几个团队的项目,大家在做Agent开发时,遇到效果不理想,第一反应都是"那我再改改提示词"。改完跑一跑,感觉好像好了一点,再让模型多试几次又翻车,于是接着改提示词。两个星期过去,Prompt写了一堆,Agent该崩还是崩,该乱还是乱。这种把Agent优化完全押注在提示词上的做法,本质上是在写玄学,不是在做工程。
我必须先说清楚,提示词在Agent项目里确实重要,但它只是整个系统的一层外衣。真正的Agent优化,核心在架构和系统层面:上下文怎么组织、任务怎么拆解、工具调用怎么校验、失败怎么兜底、效果怎么评估。如果你现在正在做Agent开发,发现自己每天都在纠结"这句提示词还能怎么改",那这篇文章就是写给你的。我会把我在实际项目中总结的Agent优化思路完整拆开,告诉你哪些问题值得花时间,哪些问题靠改提示词永远解决不了。
1. 调了一个礼拜提示词,Agent该崩还是崩
先说这种现象为什么这么普遍。刚接触Agent开发的团队,最容易陷入"提示词玄学循环",因为改提示词是成本最低的反馈调节方式:不需要改代码,不需要重新部署,甚至不需要查看更多上下文,找到对话窗口把Prompt改一版,再跑一次,立刻就能看到反应。这种即时反馈会让人产生一种错觉,好像真的在"优化"。
但问题在于,大多数时候你根本说不清楚刚才那次改动到底改变了什么。是措辞更清晰了,还是这次模型采样运气好?是例子选得更准了,还是刚好避开了之前触发错误的分支?因为没有归因机制,所有的"改善"都无法沉淀成可复用的结论,每次优化都只能从头再来。
1.1 为什么提示词优化容易变成"玄学"
我来还原一个很典型的场景。你写了一个文件处理Agent,调用一个内部工具读取Excel并生成统计报告。某天测试发现,当Excel里的某个Sheet为空时,Agent会编造一堆数据出来。你的第一反应是什么?大多数人的反应是,在提示词里加一句"注意:如果Sheet为空,请告知用户没有数据"。测一次,哎呀好了。再换一种结构的空文件,又错了,于是再加一句"注意:Sheet为空包括完全空白、只有表头等情况"。然后再换一种……你会发现,提示词越加越长,规则越写越细,但永远堵不住新变体。
这个例子暴露了玄学优化的三个特征。第一,问题被当作文本问题处理,但实际上它是一个数据校验问题。空Sheet的判断应该是工具层返回一个明确的"空数据"状态,而不是让模型去"理解"什么是空。第二,优化不具备泛化能力,每一条提示词补丁只针对测试中撞见的那一种错误,换个形式就失效。第三,你无法解释改动的原理,一旦解释不了原理,你就不敢删,也不敢重构,提示词最终变成一坨谁都不敢碰的"规则堆"。
1.2 一个典型的"玄学优化"实录
再举一个我实际排查过的例子。有个Agent要做多步操作:先搜索、再整理、再生成客户邮件。团队告诉我"效果不稳定,我们已经在提示词里加了很多约束,比如'务必先搜索再总结''不要遗漏关键信息',但还是会跳步骤"。后来我让他们把每次完整执行的日志拉出来,发现Agent实际执行的顺序是对的,搜索也确实做了,问题出在:搜索工具返回了十个结果,Agent只取前两个就开始写邮件了。
这根本不是"跳跃步骤"的问题,而是上下文窗口里的信息太多,模型在生成时"丢失"了后面几个搜索结果。你在提示词里写一百遍"请参考全部搜索结果"也没用,因为模型处理长文本时的注意力天然会偏向开头和结尾。正确的做法,是在系统层把搜索结果做一次摘要压缩,或者把结果数量限制在合理范围内,或者让Agent每处理一个结果就输出一条中间记录。这些都跟提示词无关,却实实在在决定了Agent的下限。
所以我的第一个建议很直白:当Agent出了问题,先不要问"提示词还能怎么改",先问"系统里哪一个环节在神化提示词的能力"。这也是我后面所有内容的基础。
2. Agent真正的瓶颈,通常藏在系统的三个位置
既然不要急着改提示词,那该看哪些地方?我做了不少Agent项目之后,把优化重点收敛到了三个位置。上下文管理、规划与控制、工具与数据接口。这三个位置你花力气去抠,每一分投入都能看到回报,而它们在大多数项目里恰恰是最容易被忽略的。
2.1 上下文管理:模型视野的"内存"设计
上下文是你的Agent做决策的全部依据。模型本身不记得任何历史,它每次能看到的只有当前请求里携带的上下文。所以上下文怎么来、怎么存、怎么更新,直接决定了Agent的"视野"质量。
我把上下文管理的优化动作分成四类:
- 裁剪与摘要:随着对话步数增加,历史消息会无限膨胀。常见做法是设定窗口阈值,超过后把早期消息做一次摘要,替代原文注入。这里的关键是摘要不能丢关键实体和数字,比如订单号、用户ID、金额。
- 检索注入:RAG类场景里,真正的技术含量不在"拼一段检索结果给模型",而在怎么判断哪些内容值得注入。很多Agent性能差,不是模型不行,而是把一堆不相关的内容塞进去,稀释了关键信息。
- 结构化存储:对话过程中产生的中间状态,比如已经查到的客户信息、已经确认过的条件,应该放到结构化的状态变量里,而不是全堆在对话历史中。
- 长度预算:给每一类内容分配上下文预算。系统指令占多少,历史摘要占多少,检索结果占多少,当前问题占多少。预先分配,避免单一内容挤爆窗口。
这四类优化里,前两类是"减负",后两类是"治理"。想想看,一个上下文里装了大量冗余信息的Agent,即使你的提示词写得再漂亮,它同样会迷失。这不是玄学,是可验证可测量的数据结构问题。
2.2 规划与控制:Agent的"控制流"到底谁说了算
Agent跟单轮Prompt服务最大的区别,就是它有规划能力。规划层决定了Agent先做什么、后做什么、出现问题怎么调整。这里最容易踩的坑是:把规划完全交给模型自由发挥,然后用提示词去约束它。
在我的项目里,我倾向于把"规划"分成两种。一种是宏观流程,即整个任务严格分几步,每步需要什么输入、产出什么结果;另一种是微观决策,即在一个步骤内部,模型需要做哪些判断。优化时我会把宏观流程尽量挪出模型控制,用代码去编排。整套流程是一张清晰的图,每个节点是明确的操作,模型只负责节点内部的具体决策。这样做的直接好处是:可追踪、可重试、不会因为模型状态不好而丢掉整个流程。
比如一个"资料收集-信息核对-生成报告"的Agent。如果宏观流程靠提示词约束:“请你先收集资料,然后核对,最后生成报告”,那么模型完全可能在某个回合跳过核对,或者提前生成报告。如果我把流程写成代码:第一步调用检索工具,拿到结果后入库;第二步把结果送入校验模块;校验通过后第三步才允许调用生成接口。这时候提示词只负责"在这个节点里把文章写好",它根本不可能跳过流程。用代码建立控制流,用提示词优化局部行为,两者的分工清楚了,优化才谈得上系统化。
2.3 工具与数据接口:Agent摸到的每一件工具都必须可靠
Agent的能力上限,其实是由它接的工具和数据决定的。你给模型一百个工具,每个工具的参数文档稀烂,返回结构不一致,错误信息含糊,那无论提示词怎么调,模型都会在工具调用上翻车。
我见过一个很典型的案例。团队的Agent经常"幻觉"出一些并不存在的数据,排查到最后发现,是因为工具返回的JSON里有一个字段时有时无,模型把缺失当成零处理。他们在提示词里反复强调"不要编造数据,不要臆测字段值",完全没用。后来我把工具接口改了,所有字段强制返回,缺失时统一用null填充,并在接口文档里写明"null表示无数据,不要尝试补全"。问题立刻消失。工具层的确定性,比提示词里的任何强调都可靠。
另外,给工具写描述时也要注意"面向模型编写"。工具描述的核心不是给人看的说明书,而是让模型知道"什么情况下该用我、注意我的哪些参数限制"。我在项目里会花专门时间打磨工具描述,但有一条原则:工具描述只描述功能和约束,不承担业务规则。业务规则放在代码里做校验,而不是靠模型自觉。
我把三个位置的核心问题总结成一张表,方便自查:
| 瓶颈位置 | 典型现象 | 验证方法 | 对应优化动作 |
|---|---|---|---|
| 上下文管理 | 步骤多了之后效果明显下降,越长的任务越不稳定 | 统计每次请求的token分布,检查上下文里的冗余占比 | 做历史摘要、限制检索注入数量、状态变量外置 |
| 规划与控制 | 任务流程经常跳步,或不按预期顺序执行 | 把完整执行链路打出来,看模型每一步的选择 | 用代码编排宏观流程,模型只做节点内部决策 |
| 工具与数据接口 | 工具调用频繁报错、返回解析失败、数据凭空出现 | 查看工具调用的失败率与错误类型分布 | 统一返回结构、明确错误码、把校验逻辑下沉到工具层 |
如果你现在正在为Agent效果不佳发愁,先对着这张表自检一遍,比打开对话窗口继续加Prompt有用得多。
3. 没有评估集的优化等于没优化
我见过太多项目在"优化"Agent时处于一种混沌状态。今天有人提了一句"感觉回答更专业了",明天又有另一个人说"好像变啰嗦了"。没有统一标准,没有量化数据,所谓的优化就沦为了个人主观感受。
在任何一个正经的Agent项目里,效果评估必须前置。如果你还没有一个固定的评估集,那你的所有优化动作,都是在没有标尺的情况下盲调。这跟做推荐系统不做AB测试、做数据管道不做数据校验是一样的荒谬。
3.1 先建基线,再谈优化
评估集的建立不需要特别复杂。第一步就是采集问题样本。把你过去一两个月里真实用户提问、测试人员构造的边界情况、线上翻车的案例全部捞出来,归好类。第二步是标注标准答案。注意,这里说的标准答案不一定是唯一正确的完整答案,而是一份"关键要素清单"。比如处理退款咨询的Agent,标准的回答至少要包含:是否支持退款、退款金额、到账时间、操作路径。只要这四个要素都在,就算通过;缺一个,就算失败。这种要素级标注比一句"回答得很好"要可执行得多。
3.2 三层评估架构:从单步到全链路
我自己的做法是把评估集拆成三层,每一层解决不同颗粒度的问题。
第一层是单步评估。针对Agent流程中的某一个动作做测试。比如"给定一段客户诉求,能否正确调用退款工具并填入正确的参数"。这一层专门抓工具调用和指令理解类问题。每次改完工具接口或者调整节点内的提示词,跑这一层,响应最直接。
第二层是流程评估。跑完整的多步任务,关注步骤是否缺失、顺序是否正确、中间状态是否被正确维护。它暴露的是编排层的缺陷。我前面说的"宏观流程到底该由代码控制还是提示词控制",这一层会给答案。
第三层是端到端评估。模拟真实用户,从输入一句自然语言开始,到拿到最终结果结束,只看最终的交付质量。这一层是最接近真实体验的,但问题定位最难。我的做法是:端到端失败,立刻回溯到第二层、第一层去复现,逐层收窄范围。
每次优化,至少要保证三层评估集整体不退化,你才敢说这次改动是正向的。如果连评估集都没有,那我建议你先放下手头所有的Prompt调优,花两三天把评估集搭起来。这绝对是Agent优化里性价比最高的一件事。
在指标选择上,我常用的核心指标有这几个:任务完成率、关键要素覆盖率、平均耗时、单次任务Token消耗、工具调用失败率、以及人为纠错次数。前两个衡量质量,后几个衡量成本和稳定性。优化Agent时,如果一项改动让完成率提高但Token消耗大幅上升,我会再权衡;如果让失败率下降但耗时翻倍,同样要掂量。指标之间是互相牵制的,只盯一个指标就容易走进新的玄学。
4. 可观测性,才是Agent优化真正的望远镜
做Agent开发和做传统后端开发的体验有一个很大的差别:传统后端出了问题,报错日志里能看到异常堆栈,能定位到具体代码行;而Agent的问题往往没有异常,它就是"结果怪怪的"。你的第一反应是"模型发癫了",但你完全看不到模型在每一层收到了什么、输出了什么、为什么做出这个选择。
如果没有可观测性,你连问题在哪一层发生的都不知道。你看到的是一个Agent最终给用户的回答质量很差,但你会怀疑是检索返回的内容不行,还是摘要步骤吞了关键信息,还是生成阶段写跑偏了。在这种情况下,改提示词就成了唯一的"可能性操作"——因为你只能碰到提示词。这完全是被逼出来的玄学。
4.1 记录什么以及为什么
要让Agent的优化从"猜"变成"看",必须做好日志记录。我常用的日志结构分四层。
模型调用日志是最基础的一层。记录每一次LLM请求的系统提示词、用户内容、温度参数、返回结果、Token数、耗时。不要怕日志量大,我见过太多项目因为"日志太多太占空间"而不记录完整的输入输出,最后优化时两眼一抹黑。实际上,在开发测试阶段,完整日志就是调试Agent的显微镜;到线上阶段,可以做采样率降级的策略,但开发期一定不能省。
工具调用日志是第二层。记录工具名、入参、出参、状态码、耗时。很多Agent"看似胡说八道",回溯后往往发现是工具返回了错误数据,模型基于错误数据一本正经地推理罢了。
流程链路日志是第三层。用统一的任务ID串联起整个流程的每一环。这样你可以从一次失败的端到端任务,直接展开成完整链路图,看到每一步花费的时长和结果。
人工标注日志是第四层,也是最容易被忽略的一层。把每一次人为纠错的记录都留下来。我有个习惯:每次从测试反馈中收到"这里Agent做错了",我都先去看这条纠错触发了哪条完整链路,而不是直接去改提示词。因为纠错本身就是最高价值的测试样本,比你自己拍脑袋构造的用例要真实得多。
4.2 用日志定位问题的实操思路
有了上面的日志结构,排查问题的过程就清晰了。比如端到端测试发现Agent最终生成的结论里出现了一个来源不明的报价数字。通过流程链路日志,我可以看到报价数字最初来自某次工具调用的返回值。再点开工具日志,才发现那是因为上游接口传参时漏了折扣字段。整个过程二十分钟能定位完成。如果在没有日志的环境下,我大概率又会在提示词里加一句"请注意报价要准确",然后祈祷它下次不犯。
再说一个判断要点:调提示词前,先看看这一步的模型输入里到底有没有足够的信息。有一次我发现Agent老是把A客户的数据混进B客户的报告里,团队讨论的结论是"模型对客户身份理解不够,得强化提示词里的身份约束"。我打开日志一看,工具返回的时候,数据条目上只带着客户ID的原始字符串,而模型在理解时经常混淆。根本不是提示词的问题,而是数据展示格式缺少了清晰的"当前数据属于哪个客户"的上下文锚点。加上锚点之后,问题直接消失。这就是可观测性的价值。
5. 提示词仍然重要,但它不是Agent系统的"内核"
说了这么多,千万不要把文章理解成"提示词不重要"或者"提示词无用论"。我真正的观点是:提示词在整个Agent系统中的定位,被严重错置了。很多团队把提示词当成控制Agent行为的核心工具,但实际上,提示词应该只承担系统的"表达层"功能。它就像一辆车的外形设计,决定了好不好看、顺不顺眼,但车的安全性、动力和底盘,靠的从来不是外形。
5.1 提示词该管什么
基于项目经验,我把提示词的职责收敛到三件事。第一,角色与行为边界:告诉模型它是什么、不能做什么、触碰边界时如何回应。第二,输出格式与风格:约定回答的结构、语气、长度、以及关键的格式要求。第三,局部决策的指导:在一个具体的节点里,怎么根据已有的结构化输入做出合理判断。
凡是超出这三条范畴的控制需求,都应该迁移到系统层。流程控制交给编排代码,数据校验交给接口层,状态管理交给变量存储,失败重试交给调用策略。提示词不该是容纳所有控制逻辑的地方。每次你在提示词里新增一条规则,都该先问自己:这条规则能不能用代码实现?能的话,就尽快挪出去。
5.2 提示词优化的可复现方法
如果有人确实需要优化提示词,我希望它至少是科学而不是玄学。我的做法是给提示词做版本管理,并把每次改动的目的和预期写清楚。改动模板长这样:
- 改动位置:系统提示词/用户提示词/工具描述
- 预期影响:提升格式遵守度/减少不必要的解释
- 评估验证:跑三层评估集中的哪几层
- 回滚条件:哪些指标出现退化就回滚
每一条改动都应该有明确的预期和验证手段。如果一条提示词改动说不清楚它到底影响了什么、为什么这样写,那这条改动大概率只是心理安慰。另外一个细节是,不要在完整的提示词里到处打补丁。很多项目的提示词被改得越来越长,像一篇不断追加注释的接口文档。一旦发现系统指令超过合理长度,我的建议是重写,把核心指令压缩,把边缘约束移到代码校验和格式规范里。
5.3 什么情况下才应该动提示词
我会在三种情况下主动调整提示词。第一,模型的角色定位或语气风格发生了变化,比如从客服助手调整为专业顾问。第二,出现了明确的输出格式问题,比如该输出JSON却输出了散文。第三,单节点内模型对结构化输入的判断不准确,且通过补充格式示例能改善。除此之外,当我遇到流程错乱、数据丢失、工具调用失败、上下文污染等问题时,我根本不会碰提示词,而是直接去查架构和日志。
这个习惯帮我省下了大量无效调试时间。同时也要提醒一下,很多Agent框架和现在市面上的Agent开发平台,给了用户很大的Prompt自由度,这容易让人误以为"Prompt是Agent项目的全部"。我个人的建议是,在正式项目中保持一个原则:系统提示词尽量精简,框架能力尽量下沉到代码。你越早相信系统而不是文字,Agent的稳定性会越早提升。
我在自己带的项目里,最终都是靠"评估集+完整日志+代码化流程控制"这三板斧把Agent从"感觉时灵时不灵"救出来的。回头再看,那些让人耗尽心力的"提示词玄学"问题,百分之八十在系统层就能被解决。提示词当然还要打磨,但它应该被放在整个工程体系里找到自己的位置,而不是把所有期待都压在几段文字上。希望看到这篇文章的朋友,能从下一次优化开始,先把日志打开,把评估集建起来,再决定要不要动你的Prompt。