跳到主要内容

接手 AI 系统审计:如何掌控一个非你亲手构建的 LLM 功能

· 阅读需 12 分钟
Tian Pan
Software Engineer

有人离职了。入职文档上写着“去问 Sarah”,但 Sarah 现在已经在另一家公司了。你正盯着一个 900 行的系统提示词(system prompt),里面有些章节标题写着类似 ## DO NOT REMOVE THIS SECTION 的字样,而你完全不知道如果删掉会发生什么。

这就是“继承的 AI 系统”问题,它与继承常规代码不同。对于遗留代码,意志坚定的工程师可以追踪执行路径、阅读测试,并从行为中重构意图。但对于继承的 LLM 功能,提示词就是逻辑——但它是用自然语言编写的,其失败模式是概率性的,而且作者的意图被困在他们的脑海里。没有堆栈跟踪会告诉你哪个护栏(guardrail)触发了以及为什么触发。

以下是如何审计一个非你构建的 LLM 功能的方法——且不会触发那些前任开发者在暗中防止的回归问题。

从失败存档开始,而不是代码

在任何继承的 AI 系统中,最有价值的资产不是提示词,而是“哪里坏过”的历史。在你阅读系统提示词的任何一行之前,先去查看追踪事故的地方——Slack、Linear、Jira 或共享文档——并搜索该功能导致用户可见问题的每一次记录。

你正在构建的是一个失败目录(failure catalog):一个从症状到系统响应的映射。系统提示词中每一个不寻常的章节都是为了防止某些特定情况而写的。## Never discuss competitors 条款之所以存在,是因为曾有人抱怨助手推荐了竞争对手的产品。底部的 few-shot 示例之所以存在,是因为如果没有它们,模型在某些边缘情况下会返回错误的 JSON schema,而这些情况曾耗费了三周时间才诊断出来。

如果没有事故历史,请采访即将离职的工程师或产品经理(PM)。即使是 30 分钟的“最常出故障的地方是什么,你是如何修复的?”也比一周的探索性提示词调试更有价值。你追求的是因果链:事故 → 行为 → 提示词更改 → 解决。这条链条上的每一个环节都解释了系统提示词中的某一段落。

结构化拆解提示词

一旦你有了失败目录,就将其映射到提示词上。逐节查看并询问:这一节防止了什么失败?

Useful heuristics by section type:

  • 角色定义和人格条款:防止行为漂移——模型滑入一个与产品语气或范围不符的默认助手人格。
  • 约束和限制章节(“绝不”、“不要”、“始终拒绝”):防止特定的用户可见的失败。语言越具体,导致该段落的事故就越具体。
  • Few-shot 示例:编码了隐式的行为契约。一个在你看来冗余的示例,很可能是为了解决模型在生产环境中反复出错的歧义。在不了解它解决了哪种歧义的情况下将其删除,就是你引入回归(regression)的方式。
  • 输出格式指令:之所以存在是因为下游代码期望特定的 schema。在未审计该输出的每一个消费者之前更改它们,就是你悄无声息地破坏集成的方式。
  • 上下文注入模式:包含哪些信息、顺序如何、排除哪些信息——反映了关于哪些上下文有助于模型、哪些会误导模型的血泪教训。精简的上下文往往优于全面的上下文;排除的内容和包含的内容一样都是经过深思熟虑的。

对于每一节,写一行注释:“本节防止 [失败类型]。证据:[事故或假设]。”如果你写不出这行注释——如果你真的不知道它防止了什么失败——那么这一节在动它之前需要进行受控实验。

区分硬约束与软约束

并非所有护栏都具有相同的风险配置。在开始重构之前,你需要建立一个心理模型,明确哪些约束是承重的,哪些是装饰性的。

硬约束(Hard constraints)是系统绝不能违反的行为属性。在医疗助手中,绝不提供诊断。在金融工具中,绝不生成投资建议。在任何涉及 PII(个人身份信息)的系统中,绝不通过不受控的输出路径回传个人信息。这些约束通常由于法律或合规原因而存在,而这些原因并未写在提示词本身中。违反它们一次——即使是在测试环境中——也可能产生责任风险。在触碰任何相关内容之前,先了解这些约束存在于何处(基于提示词、基础设施层面,或两者兼有)。

软约束(Soft constraints)是风格或行为偏好,如果整体方向正确,可以容忍暂时的违反。语气指令、格式偏好、关于回答详简程度的启发式方法。这些是可以安全实验的,因为违反它们是可恢复且可见的。

这种区分很重要,因为继承的 AI 系统经常将两者混为一谈。你会发现安全关键的限制与“回复字数在 200 字以内”被埋在同一章节。将它们拆开。硬约束属于一份单独的文档,由有权更改它们的人负责,并配有证明约束成立的测试用例。

在着手任何改动前,先构建特征测试套件

当你继承一项 LLM 功能时,你写的首行代码不应该是新功能,而应该是特征测试(Characterization tests)——这是一组输入与当前系统生成的输出配对,在你进行任何改动之前,将当前行为锁定。

这借鉴了传统软件工程的经验,但 LLM 版本有一个特殊之处:模型的输出是非确定性的。你不是在测试字符串是否精确匹配,而是在测试行为属性:输出是否保持在预期的主题范围内?它是否遵循了格式要求?它是否拒绝了本该拒绝的输入?

使用 LLM 作为裁判 (LLM-as-judge) 模式来评估这些属性:将模型的输出发送到第二次调用中,附带一份评分量表,并让它针对每个约束条件进行评分。针对当前系统运行你的特征测试,记录评分分布,并将该分布视为你的回归基准(Regression baseline)。任何降低该分布得分的重构都应被视为潜在的回归,而非改进。

加载中…
References:Let's stay in touch and Follow me for more thoughts and updates