跳到主要内容

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

查看所有标签

你的 PRD 只是一个未经测试的 Prompt —— 直到你对其进行评测

· 阅读需 10 分钟
Tian Pan
Software Engineer

打开过去六个月内发布的任何 AI 功能的系统提示词(System Prompt),将其与授权该功能的 PRD 并排阅读。你会发现这两个文档在互相争吵。PRD 写道:“助手应该是提供帮助且专业的,避免胡编乱造,如果无法回答则体面地拒绝。”系统提示词则写道:“你是一个 AI 助手。保持简洁。如果不确定,说‘我不知道’。绝不捏造事实。”PRD 占了一整页。提示词只有九行。它们之间的鸿沟就是你本季度发布的所有行为 Bug 的所在地。

这种便利的虚构说法认为,提示词只是 PRD 的“实现细节”。实际关系恰恰相反。提示词是模型执行的契约;而 PRD 是由一个从未编译过它的作者用模型听不懂的语言编写的契约草案。每一个 AI 功能的 PRD 都是一个未经测试的提示词。那些承认这一点并在签字确认前通过评估(Eval)运行 PRD 的团队,发布的功能会少一个上线后产生意外的根源。

AI 功能依赖图:当提示词修改成为静默破坏性变更时

· 阅读需 12 分钟
Tian Pan
Software Engineer

一个团队负责摘要生成器。另一个团队负责摄取这些摘要的搜索排序器。第三个团队负责一个路由,根据排序器的置信度分数在不同的智能体人格之间进行选择。这些团队都没有共同的值班轮换,也没有人参加同一个站会,他们之间唯一的契约就是“上一个功能的输出是下一个功能的输入”。周二,摘要团队收紧了一个提示词,以修复销售演示中反馈的幻觉问题。六小时后,搜索排序器的质量骤降。到周三早上,路由开始将任务交给错误的智能体人格。复盘报告会将原因记录为“提示词变更”,但实际原因是团队的 AI 功能已经悄然组成了一个没人绘制过的有向图。

这是最常见的 AI 故障形式,它不会触发你为 AI 故障构建的任何警报。模型没有宕机。被修改功能的评估套件显示为绿色。Token 成本曲线很平稳。真正断裂的是两个功能之间的接口,你的依赖工具将其视为纯文本,因为在 API 边界它确实只是纯文本——并且将其视为惰性的,因为纯文本不携带版本、Schema 或弃用策略。

当你的禁止列表变成秘籍:提示词中负面示例的隐性成本

· 阅读需 11 分钟
Tian Pan
Software Engineer

打开一个成熟的生产系统提示词(system prompt)并搜索“not”这个词。在一个已经发布了三个季度并经历过几次事故的功能中,你几乎总能发现一个看起来像“遗憾清单”的章节——“不要提供医疗建议,不要生成匹配这些模式的代码,不要使用这个正则表达式生成内容,不要冒充这些竞争对手,不要使用这些短语。”每一行都可以追溯到一起特定的事故。每一行都是由一位满怀信心地说“这能解决问题”的工程师添加的。而这个列表,每一个季度都像博物馆增加展品一样不断增长。

极少数团队会公开承认的是,这个列表——提示词中最具防御性、经过最仔细审查的部分——对于错误的读者来说,也是整个功能中最有用的产物。一个决意提取系统提示词的用户,现在拥有一份经过策划、组织良好且模型可读的清单,其中包含了团队所担心的所有行为。禁止列表就是一份食谱。而团队亲手编写了这本烹饪书。

每个租户的提示词编译:当你的系统提示词变成构建产物时

· 阅读需 12 分钟
Tian Pan
Software Engineer

当一个多租户 SaaS 团队在其系统提示词(system prompt)中添加第三个 if tenant_industry == "healthcare" 分支时,那一刻他们其实已经在不经意间为自己聘请了一位编译器工程师。没有人申请过这个人头(headcount),也没有人事先规划过这项工作。团队以为自己在交付一个功能,实际上交付的是一套构建系统,而这套系统仅靠 f-strings 勉强维系。

任何试图将 AI 功能推广到具有哪怕轻微差异的客户群体的团队,最终都会撞上同一堵墙。租户 A 属于医疗行业,需要符合 HIPAA 标准的回答框架。租户 B 属于法律行业,需要严格的引用规范。租户 C 是购买了自定义安全准则的大型企业。租户 D 是免费层级用户,使用默认设置。最直觉的做法是用运行时条件语句(runtime conditionals)处理差异,这些条件不断嵌套,直到除了作者之外没人能读懂这个提示词。第二种直觉——也是大多数团队在撞墙后得出的方案——是提示词编译(prompt compilation):规范的“提示词”不再是一个字符串,而是一个源码产物(source artifact),最终触达模型的则是编译后的输出。

提示词组合:管理一组提示词,而非单一的最佳提示词

· 阅读需 12 分钟
Tian Pan
Software Engineer

大多数生产环境中的 AI 团队谈论提示词(prompt)的方式就像初级交易员谈论股票一样:总觉得存在一个“最好的”,而工作就是把它找出来。于是他们不断迭代——一个 Slack 线程,几行评估数据,产生一个新的赢家,推送到主分支,如此循环。其结果是一个承载了产品全部意图解析覆盖面的单一制品(artifact),针对一个固化的评估集进行了优化,而它距离 P1 级事故往往只差一次令人遗憾的修改。

错误在于“单一”这个词。提示词不是一种证券,而是一种配置(allocation)。同一个用户意图可以由几个变体很好地服务,每个变体都有自己的置信区间、各细分领域的性能以及对模型和语料库偏移的敏感度。正确的心理模型不是“找到最好的提示词”,而是“管理一篮子提示词,其构成本身就是产品”。量化金融在五十年前就弄明白了这一点,而其运营机制几乎可以直接无缝迁移。

Prompt 回滚不像代码:为什么 git revert 是错误的原子操作

· 阅读需 10 分钟
Tian Pan
Software Engineer

一位资深工程师将 Prompt 的更改通过 10% 的灰度发布(canary)推送到生产环境。到了第二天早上,灰度组的有用性评分(helpfulness score)下降了四个点,值班人员发现了这一点,团队做了每个团队都会做的事情——撤回提交(revert commit)并重新部署。仪表板没有恢复。第二天也没有恢复。三天后,一份复盘报告显示,看到糟糕 Prompt 的那一组用户仍然在看到退化的输出,因为他们的对话历史中现在包含了由已撤回的 Prompt 生成的助手回复,而模型正基于这些回复进行预测。提交已经消失了,但损害仍在。

这是 LLMOps 中“像对待代码一样对待 Prompt”这一建议悄悄跳过的部分。代码回滚是文本替换,用于恢复确定性的过去状态。Prompt 回滚必须处理一系列副作用——缓存、历史记录、评估基准、实验分组、下游契约——这些都是糟糕的 Prompt 已经印刻在生产环境中的。git revert 翻转了文本,但它没有翻转后果。

少样本示例造成的租户泄露:当你的提示词库变成跨客户数据存储库

· 阅读需 13 分钟
Tian Pan
Software Engineer

打开一个日益成熟的 AI 产品的生产环境系统提示词(system prompt),向下滑过角色描述,你几乎总能看到一个标有 # Examples## Few-shot demonstrations 的部分。这些示例非常出色——它们很具体,具有领域针对性,且精准地匹配了上季度评估集(eval set)中表现不佳的失败模式。但在仔细观察后,你发现它们其实也是真实的客户数据。来自真实账户的真实工单 ID。从支持会话中原封不动摘录的措辞模式。某个租户使用的内部产品代码,而其他客户群从未听说过。

把这些示例放进去的团队并不是粗心大意。这些示例进入提示词的方式与好示例一贯进入提示词的方式相同:有人从生产环境的追踪(traces)中挖掘出模型处理不佳的案例,挑选出最干净的现成示例,将其粘贴到系统消息中,看着评估分数上升,然后发布。这条从生产环境追踪到系统提示词的流水线,是现代 LLM 工程中最可靠的提示词改进闭环。但这也是团队在不知不觉中构建的一个结构性跨租户数据泄露渠道,而系统提示词已悄然变成了一个数据处理协议(DPA)从未涵盖的多租户数据存储库。

LLM 提示词中 “现在” 的五种定义

· 阅读需 13 分钟
Tian Pan
Software Engineer

一名客服代理告诉用户“根据我们截至今天的最新定价”,并引用了上季度的价格表。系统提示词正确地注入了 today is {current_date}。检索层提取了具有最高时效性评分(freshness score)的文档。模型回答得信心十足。每个组件都严格执行了其规定的任务,但用户得到了一个错误的答案,而值班工程师却无法复现这个问题,因为当他们在晚上 9 点回溯追踪记录(trace)时,“今天”已经变成了不同的一天。

这并不是一个罕见的 Bug。这是一种几乎存在于每一个生产级 LLM 流水线中的失效模式,因为“现在”隐式地存在于提示词的五个不同层级中,而这些层级是由不同的人在不同时间、针对不同的“现在”定义编写的。只要请求是从前端用户会话同步运行的,这些层级通常能达成一致。一旦请求被重放用于调试、在夜间进行批处理、在固定于 3 月的评估框架(eval harness)中运行,或者被排队并在一个小时后消费,各层级就开始产生分歧——模型产生了一个在提示词内部逻辑自洽但在外部环境中错误的答案。

Prompt 卧推:对“快乐路径”之外的提示词进行压力测试

· 阅读需 11 分钟
Tian Pan
Software Engineer

一个在你的评估集(eval set)上得分 92%,但在真实生产流量中得分 60% 的提示词(prompt),并不是一个有 bug 的提示词。它是一个评估集在结构上无法发现 bug 的提示词。这种差距并非噪声,而是针对那些与提示词设计意图共享语域(register)、长度分布、语言和礼貌程度的示例进行优化的结果——而这些示例正是由编写评估案例的同一个意图所创作的。

真实用户不会配合你的设计意图。他们会发送三个词的片段、十二个段落的文章、作为问题粘贴的代码块、省略冠词的非正式语域、添加敬语的正式语域,以及你的 few-shot 示例从未涉及的语言查询。这些都不是攻击性的,这只是输入分布(input distribution)。如果你的评估集是由编写提示词的同一个人策划的,那么它几乎肯定与这种分布毫无相似之处。

缩小这一差距的学科不是“更多评估”,而是一种不同类型的评估——一个压力矩阵(stress matrix),它刻意改变你策划的集合中保持不变的维度,并对退化曲线(degradation curves)进行评分,而不是单一的准确率数字。称之为提示词卧推(prompt bench press):你不是在测试提示词能否完成工作,而是在测试随着输入变得更难,它是如何失败的。

采样漂移:当 Temperature 和 Top-P 变成团队内部的“口头传说”

· 阅读需 10 分钟
Tian Pan
Software Engineer

打开任何上线超过一年的 AI 功能的生产环境配置,你会发现一个考古挖掘现场。temperature: 0.7 是因为有人想让演示看起来不那么机械。top_p: 0.85 是因为一个客户抱怨输出太普通。frequency_penalty: 0.4 是因为 2024 年有那么糟糕的一周,一个现在已经退役的模型一直在重复自己。这些决定都没有记录。它们都没有针对当前的基座模型进行重新测试。它们在每一次请求、每一次评估、每一次 A/B 测试中运行,塑造着自原始工单关闭以来再也没有人会有意识选择的行为。

这就是采样漂移(Sampling Drift)。它是由于权宜之计而进行的采样器微调的缓慢积累,这些微调最初的理由已经消失,而其效果却在不断叠加。你配置中的数值并不是经过“调优”的——它们是过去事故的化石记录,被缩放到了你当前的流量规模。

它之所以不可见,是结构性原因造成的。你运行的每一次评估都是针对当前的采样配置进行评分的,所以头条数据看起来总是没问题。当 Temperature 值比基座模型落后两个版本时,不会触发报警。也没有日历邀请会提醒你“在本季度重新网格化采样参数”。这种衰减是无声的,直到有人运行了一个干净的实验,发现一个质量提升、Token 减少,或者两者兼而有之的机会,就摆在眼前,且不需要任何工程成本。

规范翻译税:当规范、提示词和评估发生漂移时

· 阅读需 12 分钟
Tian Pan
Software Engineer

一名 PM 用英文写了一份功能规范 (feature spec)。一名工程师将其翻译成带有惯用 LLM 模式的系统提示词 (system prompt) —— 思维链 (CoT) 脚手架、输出格式强制,以及一些涵盖规范中从未提到的失败模式的避险条款。一位评估 (eval) 作者打开同一份规范,冷读一遍,并根据自己的理解编写 JSON 测试用例。三周后,这三个产物各不相同,没人能说清楚一个回归到底是提示词的 bug、规范与实现的差异,还是从第一天就写错的评估。

这就是规范翻译税 (specification translation tax)。传统软件也有这种问题 —— PRD 与代码之间、代码与测试之间的差距 —— 但编译器和类型系统缩小了这种差距。AI 功能没有这种兜底保障。提示词是系统实际阅读的文档。评估是没人签署的合同。规范是没人执行的意图描述。每一项都是将同一意图翻译成不同的媒介,如果没有双向的一致性,行为就会通过那个最容易编辑的产物泄露进来。

入职缺口:为什么新工程师需要三个月才能上手 AI 技术栈

· 阅读需 10 分钟
Tian Pan
Software Engineer

一个拥有八年经验的后端工程师加入了你的团队。在一般的代码库中,到第三周他们就能开始交付功能了。但在 AI 层面,他们仍然在私信里问问题,而且你能预测出他们在问哪两位资深工程师。入职三个月后,他们终于被信任可以修改系统提示词(system prompt)了 —— 这并不是因为提示词有多难,而是因为没有人能告诉他们,哪些评估(evals)能捕捉到退化(regression),而哪些会直接放行错误的输出。

这在通常意义上并不是招聘问题或文档问题。AI 代码库带有一种隐藏的领域知识税(domain-knowledge tax),这种税不会出现在代码审查中,不会出现在 README 中,静态分析器也无法察觉。这笔税体现在入职时间、对同一批人的重复提问,以及最终团队悄悄分化为“能动它的人”和“其他所有人”。