跳到主要内容

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

查看所有标签

你在无意中为 Prompt 构建了一个功能开关系统 —— 但却缺少治理

· 阅读需 12 分钟
Tian Pan
Software Engineer

打开你团队用来发布提示词(prompt)变更的配置仓库。看看最近的 30 个 commit。其中有多少个经过了代码审查(code review)?有多少个在 CI 中设置了评估门禁(eval gate)?有多少个你能——肯定地——归因为对看到它们的用户的生产环境行为产生了可衡量的变化?如果你的答案是“绝大多数”,那你是个例外。对于其他人来说,这些 commit 此刻正在生产环境中运行,而读取它们的系统所做的事情与特性标志(feature-flag)服务完全一致:热加载一个值,分发给用户,改变产品行为。区别在于,你的特性标志服务拥有审计日志、曝光追踪、熔断开关(kill switches)以及针对特定分群的定向投放。而你的提示词发布流水线只有 git push

这并非隐喻。这是对你团队正在运行的生产系统的准确描述。提示词配置仓库、你的 worker 轮询的 S3 存储桶、数据库中的 “prompts” 集合、你的应用在启动时获取的 LangSmith/PromptLayer/Braintrust 资产——这些全都是特性标志服务。它们具有相同的运行时形态:一个存在于二进制文件之外的值,二进制文件在热路径(hot path)上读取它,更改该值即可在无需部署的情况下改变真实用户的行为。唯一缺少的,是你的 SRE 团队在批准“真正的”特性标志服务之前所要求的所有控制措施。

你的 Prompt 时钟是正确性边界,而非日志字段

· 阅读需 11 分钟
Tian Pan
Software Engineer

一个调度代理将客户的入职电话订在了周二,而不是周三。调查花费了两天时间。Prompt 没问题。模型没问题。日历工具也没问题。错误在于系统 Prompt 携带了一个早一小时的 current_time 字段,当时请求正通过一个在 UTC 午夜前刚刚构建的缓存前缀(cached prefix)进行路由。当代理解析出“明天上午 10 点”并调用预订工具时,“明天”所指的日期对于东京的用户来说已经是“今天”了。

代理根本无法察觉。它没有任何感知手段。LLM 没有时钟。它们只有你在 Prompt 中提供给它们的字符串,并且它们会像对待用户问题一样权威地对待这个字符串——也就是说,完全信任,不加怀疑,也没有第二个来源可以进行交叉比对。

大多数团队在抽象层面都知道这一点,但仍然将注入的时间戳视为日志字段:某种有则更好、渲染到系统 Prompt 中提供上下文、不属于任何人的明确责任、不属于任何人的正确性边界的内容。这种构想是错误的。时间戳是一个正确性边界。每一个依赖于“现在”的代理行为——调度、过期、重试窗口、“最近”、“明天”、“五分钟内”、检索文档的新鲜度检查——都运行在你生成的时间管道之上,并继承了该管道所拥有的每一个 Bug。

对话历史是你的提示词从未承认的负担

· 阅读需 12 分钟
Tian Pan
Software Engineer

下次当用户抱怨“AI 今天变笨了”时,去看看你产品的分析数据。筛选出对话轮次超过 20 轮的会话。你会发现每次都是同样的 U 型曲线:前几轮表现良好,中间几轮表现也不错,而到了后期轮次,质量却直线下跌。提示词没变,模型也没变。变化的是,后期每一轮对话都背负着沉重的载荷:用户的拼写错误、话说到一半的废话、模型的模棱两可、后来被撤销的更正、没人重读的工具输出,以及用户在第四轮就放弃了的目标残余。你的提示词模板把这些“沉积物”当成了信号,模型也是如此。但这不应该。

对话历史并非免费的上下文。它是一种你每一轮都在付费重新发送的负债;它变得越混乱,就越会损害你向用户收费提供的答案。“聊天”这个隐喻是混乱的根源。聊天界面让用户和工程师习惯于将记录视为神圣不可侵犯的 —— 可滚动的、仅限追加的、从不重置。这种习惯被原封不动地引入了 LLM 应用中,尽管在模型处理上下文的物理机制上并没有这种依据。模型是无状态的。对话记录只是你选择不断拉长的一段字符串。你可以缩减它,而且通常你应该这样做。

演示循环偏见:你的开发流程如何悄然演变为针对“有魅力的失败”进行优化

· 阅读需 12 分钟
Tian Pan
Software Engineer

每个 AI 产品团队都会有一种特定的会议,通常发生在周四。有人共享屏幕,在 notebook 里输入一个 prompt,然后运行三四个例子。房间里的人反应热烈。大家惊叹“哇”。有人截图发到 Slack。决策就这样做出了——上线、更换模型、调整 temperature。没有人记录失败率,因为根本没人去衡量它。

这就是演示循环(demo loop),它带有一种几乎没有团队意识到的结构性偏见:它筛选的不是最佳输出,而是最“易读”的输出。几周或几个月下来,你的 prompt 不断演进,最终生成的是那些能“在会议中镇住场面”的答案——自信、流利、格式整齐、切中主题。至于它们是否正确,则是另一个变量,而你的流程并没有衡量这个变量。

其结果就是我所说的“有魅力的失败”(charismatic failure):输出结果在某些方面是错误的,但由于选择压力,你的演示循环已经被训练得会自动忽略这些错误。

“以后再加评估”的陷阱:测量债务如何产生复利效应

· 阅读需 10 分钟
Tian Pan
Software Engineer

每个在没有评估(evals)的情况下发布 AI 功能的团队都会对自己讲同样的故事:我们会以后再添加衡量标准,等到找到产品与市场契合点(PMF)之后,等到提示词(prompt)稳定之后,等到下一次发布之后。六个月后,提示词已经被四位工程师和两名产品经理修改过,其行为支撑着三个客户集成,团队发现“以后添加评估”意味着要从从未为此目的结构化过的生产日志中重建意图。本应开发新功能的季度变成了考古季度。

这不是规划错误。而是一个复利错误。为了更快发布而跳过评估的团队,正是那个将花费十二周时间从不完整的追踪(traces)中重建评估基础设施、为二月份所谓的“正确”含义争论不休、并悄悄移除没人能证明依然有效的功能的团队。追赶的成本超过了内置的成本——不是一点点,而是随着每一次未经回归检查就发布的提示词修改而倍增。

面试模式与任务模式:你的智能体不断打破的无形契约

· 阅读需 12 分钟
Tian Pan
Software Engineer

打开任何智能体 (Agent) 的用户反馈渠道,你都会发现两类抱怨,它们声音宏大、普遍存在,且都被归咎于模型。第一种听起来像是:“它在干活前问的问题太多了。”第二种听起来像是:“它不跟我确认就自顾自地跑去乱做一气。”产品团队将这两者视为截然相反的问题,并发布了相反的修复方案——收紧系统提示词以减少提问,然后在下一季度因另一种抱怨声变大而再次放开。这两种改变都无法长久奏效,因为这两类抱怨的核心并不在于提问或行动本身,而在于用户默默选定了一份契约,而智能体未能履行。

与智能体的每一次对话都运行在两种隐性模式之一中。访谈模式 (Interview mode) 是一种契约,用户期望智能体在采取任何实质性行动之前先提取需求——澄清性提问是受欢迎的,过早执行则是失败。任务模式 (Task mode) 则是另一种契约,用户已经完成了思考,心中已有具体计划,并期望智能体根据现有上下文直接执行,仅在真正受阻时才提问——提问是阻力,半生不熟的执行则是失败。

用户不会宣布他们处于哪种模式。他们期望智能体能从消息、对话历史和情境中读懂模式,并在智能体搞错时给予严厉的抨击。针对“问题太多”和“问得不够”的修复方案是同一个:将“模式”作为一个一等公民的概念引入你的智能体,从你可以实际观察到的信号中检测它,并在不确定时向用户明示。

Markdown 优于 JSON:你正在支付却未察觉的输出格式税

· 阅读需 12 分钟
Tian Pan
Software Engineer

大多数团队在上线当天开启 JSON 模式,却从未衡量这背后的代价。这种假设合情合理:结构化输出能保证正确性,为什么不选它呢?答案是,严格的 JSON 模式约束解码通常会使数学、符号和多步分析任务的推理准确度降低 5–15%,而由于评估是在开启格式标志之前运行的,或者评估衡量的是可解析性而非质量,因此没人注意到这一点。

输出格式是一种解码时的约束,正如所有约束一样,它会扭曲模型的概率分布。当你查看日志时,这种扭曲是不可见的:JSON 有效,Schema 匹配,字段类型也对得上。你在日志中看不到的是模型本可以用散文形式产出的推理过程,但由于无法塞进你给定的语法中而消失了。“格式税”是真实存在的,在文献中已有详尽记录,但在生产环境中几乎普遍未被衡量。

这篇文章将探讨何时该支付这笔费用,如何在不必支付时及时止损,以及对于既想要结构化输出又想要准确性的工程师来说,格式选择的决策树究竟是什么样的。

模式匹配失败:当你的 LLM 流利地解决了错误的问题时

· 阅读需 12 分钟
Tian Pan
Software Engineer

用户将一份冗长且复杂的错误报告粘贴到你的 AI 助手。它看起来像是一个经典的空指针问题,其措辞和代码布局与数以千计的 Stack Overflow 帖子如出一辙。模型自信地做出了响应,引用了常用的修复方案,听起来非常权威。用户向它表示感谢。然而,错误依然存在。这份报告实际上关于的是竞态条件 (race condition);空指针的表述只是用户描述症状时的偶然方式。

这是在生产环境 LLM 系统中捕捉难度最高的一类 Bug。模型没有拒绝回答,没有推诿。它没有幻觉出一个虚假的 API。它只是极其流畅地解决了错误的问题,而下游的所有环节——包括用户、你的评估流水线、你的护栏 (guardrails)——都看到了一个看似合理且切中要害的回答,然后继续下一步。我将此称为模式匹配失败 (pattern-matching failures):模型锁定了查询的表面特征,并针对与实际提出的问题相邻的问题给出了一个自信的答案。

提示词所有权问题:当康威定律盯上你的 Prompt 时

· 阅读需 13 分钟
Tian Pan
Software Engineer

每个复杂的 AI 产品最终都会产生一个谁也不敢碰的 prompt。它包含三个条件分支,两个在处理客户报告的事故时临时粘贴进去的内联示例,以及一个以 “IMPORTANT:” 开头的句子,后面跟着一段没人记得是谁写的语气指令。这个 prompt 长达 1,400 个 token。最后一次修改它的 PR 是由一名早已转岗的工程师审核的。当新模型发布时,没人敢保证这个 prompt 依然有效。当评估(evals)结果下降时,没人确定是 prompt、模型、检索流水线还是下游工具导致的。这个字符串被四个服务共享。每个团队都有自己的本地覆盖(override),而且这些覆盖都没有文档记录。

这就是 Prompt 所有权问题,它是多团队 AI 工程中讨论最少却最普遍的失效模式。这不只是一个技术问题,而是康威定律(Conway's Law)在 token 层面的体现。一个组织的 prompt 最终会反映出它的组织架构、RACI 缺口和协作成本——而模型并不关心你的 Jira 层级,它只会为同样不在乎这些的终端用户产生不连贯的行为。

你的提示词正在与模型已有的认知竞争

· 阅读需 12 分钟
Tian Pan
Software Engineer

你刚接入的前沿模型对你的竞争对手早有定见。对于你产品旨在反驳的那些难题,它有一套默认答案。它对你所在的领域有一套“最佳实践”,而这些实践往往源于训练语料库中占据主导地位的内容;对于你在设计文档中反复纠结的每一个争议性决策,它都暗自偏向于传统做法。这些都不会出现在你的系统提示词(system prompt)中,也不是你写的。在涉及到你产品核心差异化的查询上,模型会先倾向于那些默认设定,而不是你告诉它的内容。

大多数团队在发布产品时,都把模型当成了一张可以任意配置的白纸。写好角色设定(persona),列出规则,粘贴品牌语气指南,运行几个能产生正确回答形式的 QA 提示词,然后就大功告成了。通过审核的提示词往往是处理简单查询的——在这些查询中,模型的先验认知(prior)恰好与你的预期相符。而那些真正有趣的查询,即如果产生通用回答就会让你的产品惨败的查询,几乎从未进入提示词迭代循环。在这些查询中,先验认知正在悄无声息地取胜。

右缘准确率下降:为什么上下文窗口的最后 20% 是个陷阱

· 阅读需 12 分钟
Tian Pan
Software Engineer

200K token 的上下文窗口并不是真正的 200K token 窗口。将其填满,你刚刚付费使用的模型就会悄然变成一个更糟糕的版本——这种退化并非发生在“迷失在中间(lost in the middle)”所预言的中间位置,而是在右侧边缘,也就是近因偏差(recency bias)本应拯救你的地方。包装盒上的标签卖给你的是余量;而硅片卖给你的却是悬崖。

这是一种大多数团队尚未内化的不同失效模式。“迷失在中间”训练了一代提示词工程师(prompt engineers),让他们习惯于将关键指令放在开头,将关键问题放在结尾,坚信首因效应(primacy)和近因效应(recency)能确保信号得以传递。然而,当利用率接近宣称的窗口极限时,这种启发式方法会悄然失效。这种下降并非逐渐的、线性的,也与模型在半满状态下的表现不对称。一旦超过某个随模型而异的利用率阈值,你就进入了一个不同的运行机制,在 30K 时有效的提示词结构在 180K 时会彻底失败。

经济上的诱惑让情况变得更糟。如果你刚刚为百万 token 的窗口付费,那么使用它的压力是巨大的——你会倾倒整个代码库,喂入每一张支持工单,交给它季度财报,并让它找出重点。结果就是,你会得到一个看似推导严密、实则自信错误的答案,而在审计时它会瞬间瓦解。

Prompt 的语义差异分析:为什么 Git Diff 在提示词变更的影响上会误导你

· 阅读需 12 分钟
Tian Pan
Software Engineer

一位队友提交了一个 PR,将你 Agent 的系统提示词(System Prompt)从 420 行重写为 380 行。Diff 是一片红绿交错的“惨状”:删除了段落、移动了章节、精简了语言。你批准了它,因为这些清理看起来很合理。一周后,退款请求的准确率下降了 8 个百分点,却没人能说出到底是哪一行导致的。

另一位队友在一条指令中添加了“简洁”(concise)这个词。Diff 只有三个字符。没人仔细审查它,因为几乎没有什么可看的。但这次修改导致 22% 的查询在工具调用(Tool-call)行为上发生了变化。