上周我发现了一件有点尴尬的事。
我的AI播客管道里有一个精心编写的系统提示词——"对话指南"——我花了好几天才写出来的。它告诉两位主持人(两个AI足球评论员)该如何互相对话。不要重复同样的开场。不同段落要有不同的结构。口头禅要克制使用。绝对不要编造统计数据。
LLM逐字阅读了。然后几乎全部无视。
越南主持人一集说了13次"Trời ơi"(天哪)。日本主持人每个段落的开头都是"いやー、健一さん!"(哎呀,健一先生!)。英语主持人信心满满地引用了xG 0.35和65%控球率——这些数字在我的数据库里根本不存在。
提示词被礼貌地接收了。然后被无视了。
这是我在提示工程中学到的最有用的一件事:LLM有两种读取模式,而且它们对待这两种模式的方式截然不同。
两种读取模式的问题
这是我最初的对话指南的样子。因为结构完全相同,我把越南语版本翻译成英文来展示:
STYLE GUIDELINES:
HOST INTERACTION PATTERN: Emotional Host + Analytical Host.
STRICT RULES FOR EVERY SEGMENT:
0. NEVER REPEAT THE SAME OPENING. Vary which host initiates,
which match moment they react to first.
1. EMOTIONAL START (mandatory): Every segment begins with
the emotional host's pure reaction.
2. DATA-GROUNDING RULE (mandatory): Every claim must cite
specific numbers. Not "they dominated" but "61% possession,
3.17 xG to 0.65."
3. CATCHPHRASES:
Emotional host: "You see that?!" "Wait wait wait..."
Analytical host: "There's a deeper reason..." "Let me tell you."
看起来很周全吧?我真的以为我做到位了。
但当我读到实际生成的脚本时,情况是这样的:
| 规则 | 指南写的内容 | LLM实际做的 |
|---|---|---|
| 规则0(禁止重复) | 变化开场方式 | 每个段落都以情绪化主持人的口头禅开场 |
| 规则2(数据) | 引用具体数字 | 引用了完全捏造的数字,语气还极其笃定 |
| 规则3(口头禅) | 标志性短语列表 | 每条短语每集使用了5到13次 |
规则就在那里。LLM读过了。但这些规则的效力相当于建议,而非要求。
这时我意识到:LLM把我的规则当作"风格背景信息"——而不是"可执行的约束条件"。
模式:上下文 vs. 命令
想想你阅读不同类型文本的方式。如果我给你一张餐厅菜单,你会把它当作行动信息来读。如果我给你一篇关于意大利面历史的维基百科文章,你会把它当作背景知识来读。
LLM对提示词的处理类似。当规则出现在标记为"STYLE GUIDELINES"、"HOST INTERACTION PATTERN"或"RULES FOR SEGMENTS"的段落中时,模型会将其视为环境信息——为回答提供色彩的背景,但不构成约束。
当规则出现在标记为"CRITICAL IMPROVEMENTS REQUIRED"或"SPECIFIC PHRASE LIMITS"的段落中时,模型会将其视为可执行的命令——必须验证和纠正的事项。
这个洞察的关键不是"CRITICAL"或"REQUIRED"这些词。关键在于规则在管道的哪个位置。
修复方案:让审查步骤强制执行生成步骤忽略的东西
我的管道有两个LLM调用:
- 生成步骤 —— 以对话指南为背景,逐段撰写脚本
- 审查步骤 —— 通读完整的脚本并加以改进
最初,所有规则都在生成步骤里。审查步骤只有通用的反重复规则("不要说两次'That's fascinating'"),完全以英语为中心,对我的主持人特有的口头禅或结构要求一无所知。
修复是结构性的,不是词汇性的。我把执行权转移到了审查步骤——因为那里能同时看到完整脚本。
改变如下:
Before:规则在生成提示词中(被无视)
STYLE GUIDELINES:
0. NEVER REPEAT THE SAME OPENING...
1. EMOTIONAL START...
2. DATA-GROUNDING...
3. CATCHPHRASES: "You see that?!" ...
After:规则被提取并注入审查提示词(强制执行)
CRITICAL IMPROVEMENTS REQUIRED ACROSS THE ENTIRE SCRIPT:
2a. ENFORCE STYLE GUIDELINES' STRUCTURAL RULES:
The STYLE GUIDELINES above contain specific requirements
about segment structure. These are REQUIREMENTS, not suggestions.
- If the guidelines say "X of Y segments must vary," CHANGE
segments that violate this.
- Check how EACH segment opens. If 4+ out of 5 open identically,
VARY at least 2.
3b. LOCALE-SPECIFIC PHRASE LIMITS (extracted from host profiles —
MAXIMUM 2 TIMES each across entire script):
- "Trời ơi" / "Trời má" — max 4x combined
- "Có một lý do sâu hơn" — max 2x
- "Mày thấy chưa?!" — max 2x
...
这里发生了两件事:
-
结构规则从上下文升级为命令——被重新表述为"强制执行"和"修改违反此规则的段落",而不是"这是推荐模式"
-
口头禅从主持人配置中提取出来,以明确的限制而非建议列表的形式呈现。"Catchphrases: here are some"变成了"These phrases: MAXIMUM 2 TIMES each。"
两处修改都在审查提示词中,而非生成提示词中。这是关键的架构决策。生成步骤将风格指南作为上下文接收——它需要个性色彩。审查步骤将规则作为执行命令接收——它需要合规权限。
提取细节(为什么这在7种语言中都有效)
我不想手工维护每种语言的短语列表。每次调整主持人配置,我都得同时更新审查提示词。这种不一致足以毁掉一个独立开发者的产品。
于是我写了一个小的提取函数,在审查时解析主持人配置。每种语言的配置都有一个带标准标签的口头禅部分:
- 越南语:
Câu cửa miệng: - 日语:
口癖: - 西班牙语:
Latiguillos: - 法语:
Phrases fétiches: - 韩语:
입버릇: - 中文:
口头禅:
函数找到对应的标签,提取其后所有的引用字符串,并格式化为可执行的限制:
@staticmethod
def _extract_catchphrase_limits(host_profiles: str) -> str:
patterns = [
(r'Câu cửa miệng:?', r'"([^"]+)"'), # Vietnamese
(r'口癖:?', r'「([^」]+)」'), # Japanese
(r'Latiguillos:?', r'"([^"]+)"'), # Spanish
# ... etc for all 7 languages
]
limits = []
for marker_pattern, quote_pattern in patterns:
match = re.search(marker_pattern, host_profiles)
if match:
phrases = re.findall(quote_pattern, host_profiles[match.end():])
for phrase in phrases:
limits.append(f' - "{phrase}" — max 2x')
return "\n".join(limits)
现在,当我编辑主持人配置、修改他们的口头禅时,审查提示词会自动更新。没有不一致。没有遗漏的语言。
实际修复了哪些问题(用数据说话)
以下是修复前和修复后生成的剧集之间的变化:
| 指标 | 修复前 | 修复后 |
|---|---|---|
| "Trời ơi"次数(配额:最多4次) | 13次 | 越南语尚未测试,但日语中所有4个口头禅均在配额内 |
| "Có một lý do sâu hơn"(配额:最多2次) | 5次 | 在对应的日语测试中在配额内 |
| 捏造统计数据(xG、控球率、阵型宽度) | 4个编造的数字 | 零个编造的数字 |
| 相同模式的段落开头 | 6/6完全相同 | 日语中仍是5/5——见下文 |
| 越南/日本关联保留 | 1/4存活(审查删除了3个) | 11/11存活 |
| 主持人口吻交叉污染 | 双方互相使用对方的短语 | 清晰分离 |
口头禅配额、反捏造规则和本地化保留都已奏效。主持人配置现在能足够清晰地表达每位主持人的个性,LLM不再混淆谁该说什么。
还有哪些问题
有一条规则仍然失败:结构多样性。对话指南说"5个段落中至少有2个必须使用不同的结构入口。"修复后,日语剧集仍然以完全相同的方式打开每一个段落:"いやー、健一さん!"——一集里出现了五次。
这不是提示词强制执行的问题。这是架构的问题。
生成步骤独立生成每个段落。段落3不知道段落1和2是以情绪化主持人的口头禅开头的。每个段落都用同一个对话指南独立生成,所以每个段落都做出同样的"用情绪化主持人开场"的决定。
审查步骤本应能发现这一点——它能同时看到完整脚本。我也加了明确的强制执行语言,要求它变化开场方式。但运行审查的Gemini 3.5 Flash显然觉得重构段落开场比削减口头禅或弱化捏造声明更困难。开场的多样性需要重新生成部分内容,而不仅仅是修剪或删除。这对模型来说是更重的任务。
我仍在处理这个问题——可能需要更强的审查模型,或者重新设计管道结构,让段落之间共享开场状态。更广泛的启示是:**提示词强制执行无法修复架构问题。**如果管道结构本身使规则无法被遵守,在提示词里写再多"CRITICAL"或"MANDATORY"也救不了你。
框架:每条规则问自己三个问题
经过这次经历,我现在对每一个系统提示词都用三个问题进行审计:
1. 这条规则放在哪里——生成还是审查? 关于个性和语气的规则放在生成环节。关于合规、一致性和结构的规则放在审查环节。如果一条规则同时涉及两者(比如口头禅——它是个性的体现但需要限制),就两边都放。
2. 这条规则的措辞是上下文还是命令? "这些是口头禅"是上下文。"每条最多2次"是命令。同一条规则需要两种形式——生成步骤需要知道口头禅是什么,审查步骤需要强制执行它们出现的频率。
3. 管道真的能执行这条规则吗? 逐段生成无法强制执行跨段落的多样性。任何提示词都无法解决这个问题。你需要把规则移到审查步骤(能看到完整脚本),或者重新设计管道,让段落之间共享状态。
这个框架不仅适用于播客生成。它适用于任何多步骤LLM管道——内容生成、代码审查、文档摘要,任何有单独的生成和质量控制阶段的场景。
我还在持续迭代中,但如果你正在构建你的第一个多步骤LLM管道:至少分成两个步骤。第一步带着个性和自由度生成——给它上下文、示例、语调指导。第二步带着精确性和执行力审查——给它明确的限制、合规性检查和修改的权限。
生成步骤应该像给创意合作者做简报。审查步骤应该像把检查清单交给编辑。
当你在两者都做了之后,规则仍然被无视,先问架构的问题。是提示词的问题,还是管道的问题?
常见问题
这对单一提示词设置(无管道)适用吗?
适用,但作用有限。在单一提示词中,你要求同一个模型同时具有创造性和合规性——两者冲突时,创造性永远战胜合规性。即使在单一提示词中,把指令分成"上下文"部分和明确的"约束"部分也有帮助。但天花板是存在的。两个带着不同指令的独立调用几乎总是优于一次。
你为什么不直接把生成提示词里的规则写得更强硬?
我试过。我加了"MANDATORY"、"CRITICAL"、"NEVER",全大写写满了。生成步骤有太多相互竞争的需求——它要同时做到引人入胜、听起来自然、多样化、有本地真实感,还要合规。当模型必须在"听起来像一个兴奋的越南足球迷"和"只说两次'Trời ơi'"之间做选择时,个性永远赢。审查步骤没有这种冲突——它唯一的任务就是强制执行。
审查步骤用的是什么模型?
Gemini 3.5 Flash(出于成本考虑——审查在7种语言的所有剧集上运行)。它能很好地处理简单的强制执行(削减口头禅、弱化捏造统计数据)。但它在需要内容重新生成的任务上吃力,比如重构段落开场。更强的模型会有帮助,但我还没能证明成本的合理性。
我利用晚上和周末独自开发DIALØGUE(对话)——一个AI播客平台。口头禅提取和审查提示词修改的代码是开源的——你可以在我的播客引擎仓库中阅读完整的系统提示词和强制执行逻辑。我在这里记录一路上的所学。
如果你遇到过类似的问题——规则被读取但没被执行——我很好奇:那条规则是什么,它在你的管道中的哪个位置?
就这些了。
祝好,Chandler