对比传统 SDLC,指出 LLM 应用中验证必须从开发初期就融入系统,因为 LLM 的随机性不同于传统软件的可重复性。
在传统的 SDLC 中,验证是别人的工作,而且通常要到后期才会进行。QA 团队负责检查软件是否完成了预期功能。由于软件行为可以重复复现,你最终可以将这些检查自动化,然后继续推进后续工作。
所以在构建 Slooster 时,我先完成了那些困难的部分:
构建 prompt、反复调优,并为参数和输出定义 schema。
构建一套系统,为每个 prompt 选择 provider、model、temperature 以及其他调优配置。
一切在本地都运行得很好,于是我告诉自己,验证层可以晚点再做。
遗憾的是,一旦 LLM 进入系统,传统的 SDLC 模式就失效了。别忘了,LLM 是根据上下文进行猜测来生成输出的。毫无疑问,它们越来越擅长这件事,但本质上仍然是在猜测。即使什么都没变,同一个 prompt 下一次也可能给出不同的答案,甚至是错误答案。因此,验证必须成为软件本身的一部分。
当 model 参与工作流程时,你必须从第一天起就构建一套能够从容消化这种不可预测性的系统。
将 Slooster Guide 部署到 staging 环境后,我在给联合创始人演示之前快速检查了一遍。
此前连续几周都能返回真实且符合条件的供应商的完全相同的 prompt——model 和配置也完全相同——这次却返回了看起来像占位数据的内容,甚至真的输出了 Vendor A、Vendor B、Vendor C。点击重新生成后,结果里又多出了 Vendor D。
一个在本地连续数周都能提供干净输出的 model,在真实调用中仍然可能给你一堆垃圾,而且无论事先做多少测试,都无法彻底避免这种情况。这正是为什么必须对每一次实际输出进行内联验证,而不是只在发布前验证一次。
我加入了验证层,并内置了重试机制:捕获不合格的输出,然后重新发起调用。但重试需要时间,而用户等待时,应用还必须保持响应。
因此,验证并不是没有成本的,也不存在一套适用于所有场景的方案。验证在哪里运行、重试力度有多大,以及结果是否需要由人查看,都取决于具体用例。
首先执行确定性检查:schema validator 会拒绝任何在结构上不符合规范的内容。但像「Vendor A」这样的占位内容在结构上完全有效。它能通过 schema 检查,却依然不是有效输出。这属于语义错误,而不是结构错误,你需要另一种检查来识别它。
因此,最后一道关卡是让一个 model 检查另一个 model:通过验证 prompt,根据第一个 prompt 收到的相同标准来评判其输出。
一个 AI gate prompt 大致如下:
You are checking another model's answer before a user sees it.
The task it was given: [the original request and selection criteria].
Its answer: [the response to check].
Reply as JSON: 'pass' (true/false), 'reason' (one line), 'confidence' (0 to 1).
Fail it if the answer has placeholder names, generic filler, items that don't meet the stated criteria, or anything that reads like example data instead of a real result.
这个 gate 可以运行在生成答案的同一个 model 上,也可以使用完全不同的 provider 和 model,提供独立的第二意见。把它设计成一个配置项,这样调优时就不需要修改代码。
三个重要结论:
并非每个响应都值得承担重试成本,但也不能默认默默相信每一个响应。
把你对答案的 confidence 展示出来,让用户能够看到。
根据具体场景,在展示输出的同时,为用户提供清晰的质疑方式,并将这些反馈直接送回系统,让下一次尝试知道自己此前没有达到什么标准。
model 不应该对自己的输出拥有最终决定权。让人参与到流程中是一项功能,而不是一个以后需要弥补的缺口。
model 在下一次调用时不会给出完全相同的响应,这会让简单粗暴的缓存变成陷阱,而完全不使用缓存又代价高昂。
答案是采用智能缓存:
在合适的情况下复用优质结果。
为用户提供明确的重新生成控制权,让他们可以按需刷新结果。
智能缓存也能抵消一部分验证成本。合理组织 prompt,让其中稳定的部分可以被缓存,能够抵消验证层带来的相当一部分额外开销。
如果用相同方式对待所有 prompt,最终只会增加成本,同时得到不尽如人意的性能。
相反,应当为不同类型的 prompt 匹配合适的 provider 和 model:
简单调用使用便宜、快速的 model。
真正重要的答案使用能力更强的 model。
为验证 gate 选择合适的 model。
按 prompt 进行选择并不是过早优化。这是在验证关键环节的同时,让整个系统保持快速响应的必要方式。
我原本计划在 MVP 完成后再加入验证。但 staging 环境中的这次意外让我大幅提前了它的优先级,我很庆幸自己这么做了,否则我很可能根本不会考虑响应中出现占位数据的情况。
验证层与 transformer、schema 和 spec 一样,都是系统不可或缺的一部分。如果要构建下一个系统,我会从验证层开始。
当 model 承担实际工作时,验证不能只是一个可以选择添加的附加层。它必须成为整个系统赖以构建的基石。
再强调一次,这里不存在一套适用于所有场景的解决方案。AI 通过承担大量工作为你提供了杠杆,但掌控权仍然必须在你手中,而且预先梳理清楚思路比以往任何时候都更加重要。
如果你正在构建以 AI 工作流作为解决方案一部分的软件,也在应对同样的不可预测性,我很乐意分享自己的经验,也希望了解你的经历。
你还可以考虑屏蔽此人和/或举报滥用行为。