跳到主要内容

164 篇博文 含有标签「prompt-engineering」

查看所有标签

停不下来的 Agent:作为运行时故障模式的范围蔓延

· 阅读需 9 分钟
Tian Pan
Software Engineer

你让智能体修复一个不稳定的测试。第三分钟,测试通过了。第四分钟,智能体正在读取相邻文件。第九分钟,它“改进”了一个测试从未触及的辅助函数,为了清晰起见重命名了一个无关的参数,并开始对 fixture 构建器进行重构。最终提交的 diff 涉及 12 个文件和 400 行代码。原始 Bug 修复了,一些原本没坏的代码也顺便被“修复”了。

这不是模型感到困惑,而是模型完全按照指令留下的空间在行事。任务要求“修复 Bug”,但并没说“修复后就停止”。大多数智能体循环都有明确的起点和成功标准,但对第三个问题却含糊其辞:你什么时候结束?在聊天会话中,“结束”是由用户决定的。在自主循环中,“结束”是由停止条件决定的,如果你没写停止条件,那停止条件就是“模型失去了兴趣”。这不属于你可以调试的故障模式,而是一种你必须通过设计来消除的故障模式。

故障复盘:根本原因竟是一个无人负责的提示词

· 阅读需 10 分钟
Tian Pan
Software Engineer

故障复盘进行得非常顺利,直到遇到了一个没人能回答的问题。下午 2:14,结构化输出错误激增,某个收入工作流停滞了 90 分钟。时间线还原得很清晰:三周前,有人修改了系统提示词(system prompt),多加了几个关于“对话语气”的词,这在特定输入下悄悄导致模型偏离了 JSON 契约。修复方法很简单,只需一行代码回滚。但接下来的部分很难:有人问是谁做的改动,谁审核的,以及未来哪个团队负责维护这个提示词。房间里陷入了沉默。没有 Pull Request,没有审核人。改动是某个人在晚上 11 点通过厂商控制面板操作的,而那个人已经不记得这回事了。

那种沉默才是真正的事故。JSON 契约的失效只是症状。根因在于,系统中杠杆率最高的一处行为逻辑,竟然没有负责人,没有变更历史,也没有走任何管理其他生产环境变更的流程。模型没有出错。模型完全按照指令行事。失败之处在于,“指令”本身完全脱离了变更管理。

这是目前最常见的生产环境 AI 事故之一,而且几乎从未被正确命名。复盘报告在根因栏写下“提示词退化(prompt regression)”然后就此揭过。但“提示词退化”描述的是代码表现。真正的根因是组织架构图上的一个漏洞。

模型已到生命周期终点,并带走了你的提示词

· 阅读需 12 分钟
Tian Pan
Software Engineer

弃用通知看起来人畜无害。它以更新日志或邮件中一段平静的文字形式出现:该模型快照将在几个月后的某个日期从 API 中移除,这里是推荐的替代方案,感谢你与我们一起构建。其中暗含的工作量似乎只是一行代码的改动 —— 换掉模型字符串,重新部署,搞定。

这种设想是错误的,而且错得很昂贵。模型字符串是你损失的最小的东西。真正随着旧模型一起消失的,是你花了六个月调优的提示词(prompt) —— 每一个针对边缘案例的补丁、每一个重新排序的指令、每一个你因为那个特定模型会有特定烦人行为而添加的“仅以有效的 JSON 响应,不要用 Markdown 包装”。这些都不是可移植的。从统计学意义上讲,它是针对一个模型的行为进行拟合的。替代模型并不是“缺陷对缺陷”兼容的,因此这种拟合不再成立。

模型生命周期的结束是一个迁移项目。如果把它仅仅视为一次配置更改,你就会在生产环境中、在新模型上通过真实流量发现其中的差异。

每次事故后你的系统提示词都会增长 —— 而且没人会删掉任何一行

· 阅读需 10 分钟
Tian Pan
Software Engineer

打开任何一个已经在生产环境中运行了一年的智能体的系统提示词(system prompt)。滚动到底部。你会发现一层读起来像道歉一样的句子沉积层:“绝对不要伪造订单号。”“不要承诺无法确认的退款。”“如果用户在德国,不要提及旧版方案。”每一句都是一块化石。每一句都标志着生产环境中出现问题的确切时刻 —— 有人被传呼了,而当时能找到的最快修复方法就是增加一句话。

没人删除这些句子。不是因为它们还在发挥作用,而是因为删除一句话意味着需要证明一个否定命题 —— 证明模型不会在一个可能已经在三个模型版本前修复的 Bug 上发生回退。没人能证明这一点,所以那行字留了下来。系统提示词变成了一个关于过去事故的“只增不减”(append-only)日志,它让你在每一次调用中都永远支付着 token 费用。

这是 AI 系统中最隐蔽的一种技术债,因为它看起来不像债。它看起来像是在尽职尽责。

AI 工程师的前 90 天:一份在六周文档失效期内依然有效的入职指南

· 阅读需 13 分钟
Tian Pan
Software Engineer

新员工打开入职文档。文档指向了十一个月前的一个服务架构图、一个最后更新于十月的名为 “我们的 LLM 技术栈” 的 Confluence 页面,以及一个 “我们使用的模型供应商” Notion 表格。这些文档都没有告诉他们哪个提示词是针对哪种失败模式优化的,哪些评估案例是在哪次事故后添加的,当模型从 4.5 升级到 4.6 时哪个评判模型被重新校准了,或者为什么支持代理的系统提示词有一段谁都不敢动的奇怪的三行前导内容。入职两周后,他们提交了一个 “小的提示词清理” PR,删除了这段前导内容。评估套件通过了。不到一天,生产环境的准确率下降了四个百分点。

标准的新员工入职指南 —— 阅读架构文档、配置电脑、在第二周前完成第一个 PR —— 是为加入服务端的工程师设计的。AI 工程师加入的是一种不同的制品。他们要编辑的不是某个主任工程师写的 5000 行 Go 服务;而是一个经历了 11 次事故和 17 次评估驱动重写的 30 行提示词,而这 30 行代码的意义只存在于团队中两个人的脑子里。你的入职文档无法捕捉到这些,而尝试写一份更长的文档是错误的修复方案。

按客户定制的提示词分支:为什么你的下一次模型迁移是 47 次迁移

· 阅读需 13 分钟
Tian Pan
Software Engineer

我上个月交流过的一位 AI 初创公司 CTO 打开她的笔记本电脑,给我看了一个数字:47。那是目前在生产环境中运行的独立系统提示词(System Prompt)的数量,每个企业客户或每个逻辑分组各占一个。基础提示词在第四个月为一家需要更温和拒绝态度的医疗客户派生(Fork)了一次。然后为一家需要引用的法律客户又派生了一次。接着是为一家金融服务客户派生的,因为他们的合规团队有一份违禁词清单。当时,这些看起来都不是什么大事。每一个都是独立批准的小需求,让大客户经理团队能够顺利签下订单。

两年后,模型提供商宣布了她那些针对旧版本调优的提示词的切换截止日期。她的工程团队直觉反应是对新模型运行评估套件(Eval Suite)。评估套件仅针对基础提示词。基础提示词仍在为 0 号客户提供服务,该客户没有任何覆盖配置,且约占收入的 9%。

Prompt 的 Pre-Commit Hooks:LLM 团队一直缺失的内环工具链

· 阅读需 11 分钟
Tian Pan
Software Engineer

打开任何生产环境中的 LLM 代码库里的提示词文件,你会发现评审者的目光变得呆滞。这个 diff 是 15 行自然语言,其中包含一个微调过的 few-shot 示例,一条重新表述的指令,以及编辑器留下的一个多余的尾部空格。没有针对它的语法检查,没有 Linter 抱怨相互矛盾的指令,没有扫描器注意到 few-shot 示例包含上周二支持日志中真实客户的电子邮件地址,也没有冒烟评估(smoke eval)来确认这一更改不会导致系统实际提供的提示词延迟飙升。评审者凭感觉批准——就像 2008 年团队批准 HTML 模板的 diff 一样——然后在 6 小时后,生产遥测系统捕获到了回归。

围绕代码的内环工具(inner-loop tooling)已经成熟了 20 年。围绕提示词的内环工具则介于“我们在 git 中有一个 .md 文件”和“我们在入职后运行过一次 promptfoo”之间。这种差距正在扩大,因为在许多系统中,提示词现在是杠杆率更高的修改:一个 30 行的系统提示词更改比 1000 行的服务重写更能改变行为,而它的评审过程却像处理一份 Word 文档。

Prompt 即文档:当系统 Prompt 成为唯一可信的交付物时

· 阅读需 11 分钟
Tian Pan
Software Engineer

一位产品经理在 Slack 上私聊你,询问当客户要求助手取消订阅时会发生什么。你开始凭记忆输入答案,然后又自我怀疑,于是打开系统提示词读了 30 秒。你粘贴回一份摘要。他们向你道谢后继续忙别的了。三小时后,支持团队问了同样的问题。到了周四,合作伙伴负责人把提示词的截图贴进了交易审查中。

这就是“提示词即文档”(prompt-as-documentation)反模式。当你第一次意识到这种情况发生时,感觉会很棒。你花了六个星期调优的制品,现在成了产品功能的权威真理来源。产品经理在读它,支持团队在读它,销售团队在读它,甚至某个角落的设计师也在读它。你的工作成了支柱,这在以前的服务层代码中从未有过。你可以通过计算有多少不相干的人能凭记忆调出这个文件来证明这一点。

Prompt 作者身份问题:三个角色同时编辑同一个文件

· 阅读需 14 分钟
Tian Pan
Software Engineer

翻开任何一个运行了一年的生产系统提示词(system prompt)的 git blame,你都会发现一些工程团队不愿承认的事实:这个文件有三个作者,而他们对“变更”的定义各不相同。上个月重构指令块的工程师将提交记录标为“无功能变更,仅为了清晰起见重新排序”。每季度读一次该文件的产品经理会这样描述同样的差异:“你改写了语气——客户会察觉到的”。运行回归测试套件的 ML 工程师会说:“你搞坏了第三个少样本示例(few-shot example),从那以后评估结果(eval)就一直变红了”。

这三者都是正确的。提示词同时具备代码、规范和超参数的属性。任何长期交付 AI 功能的团队都会发现,该文件的提交历史是一场缓慢进行的三方署名权争议,CODEOWNERS 无法捕捉到这一点,diff 查看器也无法体现出来。

Agent 内部的提示词图谱:无人绘制的跨提示词回归链

· 阅读需 13 分钟
Tian Pan
Software Engineer

一位资深工程师向 planner 提示词(prompt)提交了一个只有四个单词的修改——“if uncertain, ask first”(如果不确定,先询问)。Planner 自身的评估集(用于评分计划是否合理)提升了 0.5 分。他们合并了代码。两周后,verifier 的评估显示通过率出现了 3 个百分点的回归,且没人能复现。根本原因在于:planner 现在会提出更多澄清性问题,executor 在第二轮收到的任务描述变短了,而 verifier 的评分准则(rubric)是针对之前 executor 较长的输出进行隐式调优的。一个没人标记为高风险的修改,一次性改变了下游的三个分布。

当你把智能体(agent)内部的提示词看作一个扁平的文件文件夹,而不是一个带有“边”(edges)的图(graph)时,就会发生这种情况。提示词有负责人,但它们之间的“边”却无人看管。

过时的 Few-Shot 示例以及你的提示词仓库所忽略的半衰期

· 阅读需 11 分钟
Tian Pan
Software Engineer

打开任何已经上线超过九个月的 AI 功能的系统 Prompt。向下滚动,越过角色描述,越过格式规则,越过安全护栏。停在标题为 <examples>## Examples 的块,或者是你的团队在某人把前三个好用的 Slack 线程复制到代码块的那天给它起的任何名字。读一读它们。有 60% 的可能性,其中至少有一个引用了已经更名的功能、一个已不存在的按钮,或者产品经理在两个季度前悄悄砍掉的工作流。

这种衰退从评测(eval)仪表盘上是看不出来的。评测得分是绿色的。它们已经绿了好几个月了。它们之所以是绿色的,是因为评测集是针对 Few-shot 示例所引用的同一个产品界面编写的,两者已经同步老化。模型正在完美地模仿去年的产品,而在一个以此标准打分的测试集上,它是合格的,然而真实用户在与今年的产品互动,并默默忍受由此产生的幻觉(confabulations)。这就是没有人写进 LLMOps 路线图的半衰期。

工具 Schema 演进陷阱:当一个可选参数改变了你 Planner 的先验分布

· 阅读需 11 分钟
Tian Pan
Software Engineer

在某个周二,一个全新的可选参数被添加到了工具描述中。这个改动很小——在 diff 中只有六行代码,没有破坏性的签名变更,没有更新调用者,也没有触及任何评估用例。PR 描述写着“为现有搜索工具添加了可选的 language 过滤器支持”。两名评审员批准了,随后上线。

一周后,成本仪表板显示,搜索工具的调用频率比之前的基准线增加了 18%。受影响的 agent 延迟也以大致相同的比例攀升。没人能指出哪一个评估用例失败了。新参数在使用时表现正常;在不使用时,也无关紧要。然而,planner 显然改变了它对何时使用该工具的看法——而评估套件(用于衡量工具的“正确性”)对于工具“频率”的变化却无话可说。