提示词工程模式:写出稳定可靠的 AI 提示词
一份写出稳定、可预测的 AI 提示词的实用指南。
核心原则:降低不确定性
AI 模型每生成一个词,都在很多候选词中做选择。你的提示词结构直接决定了模型在关键节点是”犹豫”还是”确定”。
- 确定性高 → 行为稳定
- 确定性低 → 行为飘忽
下面所有技巧都在做同一件事:让模型在关键决策点更确定。
简单例子
你的提示词需要模型根据环境决定是否询问用户。
自然语言版本:
如果在 CI 环境中且没有参数,使用默认值。
如果在交互模式中有参数,直接运行。
如果在交互模式中没有参数,询问用户。
模型读完后,3 条规则同时争夺注意力。它需要回头扫描才能拼出答案。
决策树版本:
## CI 环境?
├─ 是
│ └─ 有参数?
│ ├─ 是 → 使用参数,执行
│ └─ 否 → 使用默认值,执行
└─ 否(交互模式)
└─ 有参数?
├─ 是 → 使用参数,执行
└─ 否 → 询问用户
模型判断 “CI = 是” 且 “参数 = 否” 后,注意力集中在这一行:
│ └─ 否 → 使用默认值,执行
↑ 注意力集中在这里
答案就在眼前,不需要回头看。确定性很高。
一句话总结
决策树让模型看几个附近的词就知道该做什么。自然语言让它扫一整段才能拼出答案。搜索范围越小,结果越确定。
模式 1:决策树替代自然语言
对有分支逻辑的指令,用可视化树结构替代文字描述。
不好:自然语言
如果在 CI 环境中且没有参数,使用默认值。如果在交互模式中有参数,
直接运行。如果在交互模式中没有参数,询问用户。
好:决策树
## $ARGUMENTS 非空?
├─ 是 → 解析参数,直接执行,不交互
└─ 否
## $CI 或 $CLAUDE_NONINTERACTIVE 已设置?
├─ 是 → 使用 <defaults> 的值,直接执行
└─ 否 → 询问用户缺少的参数,然后执行
为什么有效: 缩进编码了层级关系。模型在训练中见过大量缩进结构(代码、YAML、目录树),学会了”缩进越深 = 子条件”。自然语言没有这种空间编码。
模式 2:锚定(给起点)
给模型一个具体的起点,不让它凭空发挥。
不好:无锚定
生成一个部署脚本。
好:用模板锚定
基于这个模板生成部署脚本:
<template>
#!/bin/bash
set -euo pipefail
ENV="${1:?Usage: deploy.sh <env>}"
# ... 你的步骤
</template>
为什么有效: 模板的内容直接参与模型的注意力计算。模型的输出会被”拉向”模板的风格,而不是从”部署脚本”这个笼统概念中随机生成。
模式 3:认知卸载(把思考步骤写出来)
把模型本来需要隐式推理的步骤显式地写出来。
不好:隐式推理
分析这段代码的性能问题并修复。
好:显式步骤
<analysis_steps>
1. 找出所有循环和递归
2. 标注每个的时间复杂度
3. 标记 O(n²) 或更高的
4. 为每个标记的部分提出优化方案
</analysis_steps>
按顺序执行这些步骤。
为什么有效: LLM 没有真正的工作记忆。把中间步骤写出来等于给了”外部记忆”——每一步只需要看上一步的输出,不需要从头推导。
决策树 = 分支逻辑的认知卸载。 思维链 = 推理过程的认知卸载。 同一个原理,不同应用。
模式 4:注意力局部性(把相关的放在一起)
相关信息在文本中应该靠近。越近的词获得越强的注意力。
不好:规则离目标太远
<rules>永远不要删除生产数据库</rules>
...(中间隔了 500 个词)...
<task>清理过期数据</task>
好:规则紧挨目标
<task>
清理过期数据
<constraint>永远不要删除生产数据库</constraint>
</task>
为什么有效: Transformer 的注意力理论上是全局的,但实际上有位置偏好——近的词注意力更强。把约束放在它约束的动作旁边,不要放在远处的”通用规则”里。
模式 5:指令-动作绑定(一条指令一个动作)
每条指令应该尽可能直接对应一个可执行动作。
不好:一句话多个动作
检查代码风格问题并修复,然后运行测试确保通过。
好:一条指令 = 一个动作
1. 运行:`eslint --fix src/`
2. 运行:`npm test`
3. 如果测试失败 → 读错误输出,修复问题,回到步骤 2
为什么有效: 模型把一条清晰指令映射到一个工具调用的可靠性,远高于从一个长句中提取多个隐含动作。
模式 6:输出格式预设(给输出一个”形状”)
给模型一个输出的结构,它来填内容。
不好:开放式
分析这个 PR 的风险。
好:结构约束
<output_schema>
- risk_level: high | medium | low
- affected_files: [列表]
- rollback_plan: [字符串]
- requires_review: true | false
</output_schema>
为什么有效: 结构定义就像”铁轨”。生成每个字段值时,模型的注意力被字段名强力引导,大幅减少偏离。
模式 7:负空间(说”不要”的同时说”要”)
告诉模型不该做什么时,永远同时告诉它该做什么。
不好:只说不要
不要直接修改数据库。
不要跳过测试。
不要用 sudo。
好:不要 + 替代方案
<boundaries>
- 数据库变更 → 生成迁移文件,不要执行原始 SQL
- 需要验证 → 运行完整测试套件再继续,不要跳过
- 需要提权 → 请求用户确认,不要用 sudo
</boundaries>
为什么有效: “不要做 X” 只压制了某些输出,但没有推动任何替代方案。模型知道不往哪走,但不知道往哪走。同时给出替代方案就能同时压制错误路径并推动正确路径。
模式 8:XML 标签做语义分区
Claude 的训练数据中包含 XML 标签。用它们来划分提示词的不同部分。
推荐的提示词结构
<context>
模型需要了解的背景信息。
</context>
<parameters>
输入参数,包含类型、默认值、来源。
</parameters>
<decision_tree>
可视化的分支逻辑,每个叶子有明确动作。
</decision_tree>
<examples>
<example>
<input>...</input>
<thinking>模型应该遵循的逐步推理</thinking>
<output>...</output>
</example>
</examples>
<boundaries>
不要做什么 + 应该做什么。
</boundaries>
<output_schema>
期望的输出格式。
</output_schema>
为什么有效: XML 标签创建硬性的语义边界。模型把不同标签内的内容当作独立的区块,减少指令、示例、约束之间的互相干扰。
模式 9:带推理过程的示例
让模型看到怎么想,不只是输出什么。
不好:只有输入/输出
<example>
<input>deploy staging</input>
<output>已部署到 staging。</output>
</example>
好:输入 + 思考过程 + 输出
<example>
<input>deploy staging</input>
<thinking>
1. 提供了参数:"staging" → 非空 → 跳过用户交互
2. 环境 "staging" 有效(匹配 staging|production)
3. 未检测到 CI 变量 → 但有参数 → 静默执行
4. 执行部署到 staging
</thinking>
<output>已成功部署到 staging。</output>
</example>
为什么有效: 示例中的 <thinking> 模式会被泛化到模型自己的推理中。它学到的是推理方式,不只是输出格式。
各模式之间的关系
行为稳定性
↑
决策点的确定性高
↑
注意力分布集中
↑
提示词中的词语空间排列
↑
┌──────────┬──────────┬──────────┬──────────┐
│ 决策树 │ 注意力 │ 认知卸载 │ 输出格式 │
│ │ 局部性 │ │ 预设 │
├──────────┼──────────┼──────────┼──────────┤
│ 锚定 │ 指令-动作 │ 负空间 │ XML │
│ │ 绑定 │ │ 标签 │
├──────────┼──────────┼──────────┼──────────┤
│ 带推理的 │ │ │ │
│ 示例 │ │ │ │
└──────────┴──────────┴──────────┴──────────┘
所有技巧都在做同一件事:
改变生成时注意力在各个词上的分布。