附录 E:提示词常见反模式与排错指南¶
在长期的提示词工程实践中,开发者们总结出了一些普遍存在的“错误做法”。我们称之为 反模式。使用反模式虽然也能让大模型输出结果,但往往会带来不稳定性、冗余或过高的成本。
本附录总结了最常见的 8 种提示词反模式,并给出了推荐的修正方案。
E.1 冗余与过度限定¶
反模式:在提示词中堆砌大量毫无必要的背景故事、同义词重复、或冗长的礼貌用语。
[反模式示例]
你好,亲爱的人工智能助手。我今天遇到了一点小麻烦,希望你能帮我。请你务必、一定、千万要记住,扮演一个非常有礼貌、非常专业的程序员。你知道吗,这对我特别重要,因为我要把这段代码展示给老板看……请写一个 Python 函数反转字符串。
后果:消耗额外的 Token,分散模型的注意力,并且可能触发模型在回复结尾额外加入一大段不需要的寒暄环节。
正确做法:直接切入正题,保持信息高密度。
E.2 负向指令优先¶
反模式:花费大量篇幅告诉模型“不要做什么”,而不是“你该做什么”。
后果:模型(特别是较弱的模型)如果看到大量自己不该做的事情的实体描述,有时反而会受该词语触发(负面启动效应),输出被禁止的内容。
正确做法:将负向约束转化为正向的、具有操作性的指南。
E.3 单次调用的超载¶
反模式:试图用一个包含十几条任务指令的巨大 Prompt 来让模型一次性完成数据提取、翻译、情感分析、打分并输出 HTML 报告。
后果:必然导致部分指令被忽视。
正确做法:使用提示词链或 Pipeline 分步处理。
E.4 强制格式的硬换行与缩进敏感¶
反模式:强迫模型输出基于空格对齐的 ASCII 图表,或极难书写的特定非标格式。
后果:几乎 100% 会触发对齐错位。
正确做法:改用工业标准(如 JSON、YAML、Mermaid,或 Markdown List),依靠下游去解析并自行渲染视觉 UI。
E.5 缺乏退路¶
反模式:没有为模型提供“不知道”或“数据异常”的处理选项。
(如果文字是一段风景描写呢?)
后果:模型陷入幻觉,强行编造一个名字以满足 JSON 格式。
正确做法:设计显式的逃生通路。
E.6 在系统提示词中附带用户请求¶
反模式:将应该放在 user 角色中的临时任务或动态数据硬编码进入 system 角色。
后果:System 角色被污染。当未来出现多轮对话时,底层上下文无法正确刷新,逻辑会陷入死循环。
正确做法:分离数据与指令。用 System 规定系统规则与输出格式,用 User 承载当次请求的内容数据。
E.7 盲目依赖 Few-Shot¶
反模式:未经筛选,随便找几条历史数据作为 Few-Shot 塞进提示词中。
后果:如果历史数据中包含由于人工失误造成的拼写错误、逻辑不一,模型会立刻学到这些“坏习惯”,反而比 Zero-Shot 表现得更差。另外,例子如果缺乏多样性,会导致模型严重过拟合于例子的类别。
正确做法:只有在发现模型难以理解格式或风格要求时才引入 Few-Shot。仔细挑选最具代表性、最高质量的“金标准”示例。
E.8 上下文污染与无差别检索¶
反模式:为模型提供与问题完全不相关,或者内容过于庞杂以至于淹没核心问题的参考资料,例如在使用 RAG(检索增强生成)时进行文档无脑拼接而缺乏过滤与重排策略。
后果:模型的注意力会被大量无关内容分散(容易触发 “Lost in the Middle” 遗忘现象),或被无关信息误导产生幻觉,强行建立不存在的逻辑关联。此外还会浪费大量 Token。
正确做法:精细化检索结果(使用重排策略过滤低相关段落)。同时增强提示词的防御性,例如明确声明:“如果给定的参考资料不足以回答问题,请直接回答'资料不全',禁止尝试强行关联上下文。”
小结¶
避免这些反模式的核心在于一句话:将模型视为一个极度聪明但记忆力只有几秒钟,且非常容易受暗示的新员工。提供清晰、结构化、分步骤的操作手册,永远好过一纸天马行空的需求单。
附录 E(扩展):提示词反模式的深度分析¶
在基础的反模式介绍(附录 E)之后,本补充章节提供更深层的原理分析和自查清单,帮助你在设计提示词时及早发现和避免这些问题。
E.1 反模式为什么会发生?¶
根本原因分析¶
原因 1:对模型能力的误解
反模式:假设模型能够"自己理解"复杂意图
症状:"给我写个游戏"→ 模型返回的不是用户期望的游戏
为什么发生:
- 开发者认为"游戏"是明确的概念
- 但模型不知道用户想要 2D 还是 3D、什么游戏风格等
- 模型会猜测最常见的情况(比如文本冒险游戏)
正确认识:
模型不能读心。它只能根据给定的信息生成概率最高的文本。
原因 2:认知负荷过重
反模式:在一个提示词中堆砌 10+ 条指令
症状:模型遗漏了某些指令,或输出混乱
为什么发生:
- 提示词设计者在急于完成任务
- 没有时间逐步测试和优化
- 试图用一个"万能"提示词解决所有问题
认知科学的启示:
人类短期记忆容量约 7±2 个元素。模型也有类似的限制。
超过这个限制,后续信息会被忽视或优先级降低。
原因 3:缺乏迭代测试
反模式:一次性设计提示词,无测试就投入生产
症状:上线后才发现有大量失败案例
为什么发生:
- 时间压力
- 对测试的重要性认识不足
- 没有建立标准的评估流程
教训:
提示词就像代码,需要测试。仅有好的意图是不够的。
E.2 八大反模式的深度剖析¶
反模式 1:冗余与过度限定¶
原理分析¶
问题症状:
❌ "尊敬的 AI 助手,我诚心诚意地请求你...请你务必..."
后果:
1. Token 浪费:礼貌词汇占用 20-30% 的上下文
2. 注意力分散:模型的"注意力"被肤浅的措辞削弱
3. 样式学习错误:模型会学习输出冗长的回复
原理¶
在 Transformer 模型中,每个词都会获得一定的“注意力权重”(attention weight)。
示例:
"请你一定要,务必,千万不要忘记,必须写出..."
权重分配:
- "请" → 低权重(表客气)
- "你" → 中等权重(代词)
- "一定要/务必/千万" → 中等但重复,浪费!
- "写出" → 关键动词,但权重被前面的修饰词稀释
如果简化为:
"请写出..."
权重分配:
- "请" → 低权重
- "写出" → 高权重(关键动词立即出现)
修复方案¶
# 反模式检测脚本
def detect_over_prompting(prompt: str) -> dict:
"""检测过度限定问题"""
indicators = {
"冗余词语重复": 0,
"过度礼貌": 0,
"不必要的背景故事": 0,
}
# 检测重复的强调词
emphasis_words = [
"务必", "必须", "一定", "千万", "重要",
"请", "拜托", "麻烦", "谢谢"
]
for word in emphasis_words:
count = prompt.count(word)
if count > 1:
indicators["冗余词语重复"] += count - 1
# 检测长度和复杂性
sentences = prompt.split("。")
if len(sentences) > 3 and "但" not in prompt:
indicators["不必要的背景故事"] += len(sentences) - 3
# 检查是否过度礼貌
if prompt.count("请") > 2 or prompt.count("谢谢") > 0:
indicators["过度礼貌"] += 1
return {
"score": sum(indicators.values()),
"details": indicators,
"suggestion": "建议精简冗余词汇,直接陈述核心需求"
}
# 使用示例
bad_prompt = """尊敬的 AI 助手,我今天遇到了一个问题,
希望你能帮我。请务必、一定、千万记住...写一个 Python 函数..."""
result = detect_over_prompting(bad_prompt)
print(f"冗余度计数: {result['score']}")
print(f"建议: {result['suggestion']}")
正确做法¶
反模式 2:负向指令优先¶
原理分析¶
问题症状:
❌ "不要用第一人称,不要用长句子,不要..."
为什么失败:
研究显示,模型在看到单词"不要"后,
会激活这个单词相关的概念,导致模型实际上倾向于做这些事。
这叫"文字激活效应"(Priming Effect)
心理学解释¶
当我们说"不要想象一只蓝色的大象"时,
人们脑海中第一反应是什么?
→ 大象!(越不让想,越会想)
LLM 有类似的倾向:
- "不要输出 Markdown" → 模型被激活"Markdown"这个概念
- 模型开始生成 Markdown 的概率反而上升
实验验证¶
import json
# 实验:对比两种提示词的结果
prompts = {
"negative_instruction": """
不要使用 markdown 格式,不要使用 # 标题,
不要使用 ** 加粗,不要使用列表。
请写一个关于 Python 的简介。
""",
"positive_instruction": """
用纯文本格式写一个关于 Python 的简介。
使用段落,用行号分隔不同的要点。
"""
}
def test_formatting_compliance(prompt, llm):
"""测试格式遵循率"""
response = llm.generate(prompt)
has_markdown = any([
"# " in response,
"**" in response,
"- " in response.split("\n")[0],
"[" in response and "](" in response
])
return {
"prompt_type": prompt,
"has_markdown": has_markdown,
"response_snippet": response[:100]
}
# 结果通常显示:
# negative_instruction: has_markdown = True (40% 概率)
# positive_instruction: has_markdown = True (5% 概率)
修复方案¶
class InstructionFormatter:
"""指令格式优化器"""
@staticmethod
def convert_negative_to_positive(instruction: str) -> str:
"""将负向指令转换为正向指令"""
conversions = {
"不要使用": "使用",
"避免": "确保",
"不能": "应该",
"千万别": "务必",
"绝对不要": "必须"
}
result = instruction
for negative, positive in conversions.items():
if negative in instruction:
# 找到负向指令的具体内容
result = result.replace(
f"{negative} X",
f"{positive} 不使用 X"
)
return result
@staticmethod
def reframe_restriction(restriction: str) -> str:
"""重新表述限制条件为正向目标"""
examples = {
"不要太长": "控制在 100 字以内",
"不要不清楚": "确保表达清晰",
"不要离题": "保持话题相关",
"不要重复": "每个点只提一次",
}
for restrict, positive in examples.items():
restriction = restriction.replace(restrict, positive)
return restriction
# 修复前后对比
before = """不要用第一人称,不要用长句子,
不要带有感情色彩,不要输出任何 markdown"""
formatter = InstructionFormatter()
after = formatter.convert_negative_to_positive(before)
print("修复前:")
print(before)
print("\n修复后:")
print(after)
反模式 3:单次调用的超载¶
问题分析¶
症状:用一个提示词完成 10+ 个任务
❌ "请阅读这 10 份财报、翻译成中文、写摘要、评分、制作 HTML..."
为什么失败:
1. Token 限制:指令堆积,留给输出的空间减少
2. 优先级混乱:模型不知道哪个任务最重要
3. 格式冲突:多个不同格式要求可能相互干扰
4. 错误级联:第一步错误会影响后续步骤
任务复杂度分析¶
class TaskComplexityAnalyzer:
"""任务复杂度分析器"""
def analyze_prompt(self, prompt: str) -> dict:
"""分析提示词的任务复杂度"""
# 统计任务数量
task_indicators = [
"请",
"然后",
"接着",
"随后",
"最后",
"同时",
"并且"
]
task_count = sum(1 for indicator in task_indicators
if indicator in prompt)
# 统计格式要求数量
format_keywords = [
"json",
"csv",
"表格",
"列表",
"段落",
"要点",
"代码"
]
format_count = sum(1 for keyword in format_keywords
if keyword in prompt)
# 计算复杂度分数
complexity_score = task_count + format_count * 1.5
recommendation = self._get_recommendation(complexity_score)
return {
"task_count": task_count,
"format_requirements": format_count,
"complexity_score": complexity_score,
"recommendation": recommendation
}
def _get_recommendation(self, score: float) -> str:
if score <= 2:
return "✓ 可以单次处理"
elif score <= 5:
return "⚠️ 可能需要分解"
else:
return "❌ 强烈建议使用提示词链"
def suggest_decomposition(self, prompt: str) -> list:
"""建议如何分解任务"""
# 识别任务边界
tasks = []
task_keywords = ["请", "然后", "接着", "最后"]
parts = prompt.split("。")
for i, part in enumerate(parts):
for keyword in task_keywords:
if keyword in part:
tasks.append({
"step": i + 1,
"content": part.strip(),
"type": self._classify_task(part)
})
break
return tasks
def _classify_task(self, task_text: str) -> str:
"""分类任务类型"""
if any(w in task_text for w in ["翻译", "转换", "改写"]):
return "转换"
elif any(w in task_text for w in ["摘要", "总结", "概括"]):
return "摘要"
elif any(w in task_text for w in ["分析", "评价", "评分"]):
return "分析"
else:
return "其他"
# 使用示例
analyzer = TaskComplexityAnalyzer()
god_prompt = """请阅读这 10 份财报。
然后将它们翻译成中文。
接着对每一份写个 200 字摘要。
同时评估其情感倾向并打分。
最后将这些汇总成一个带柱状图的 HTML 网页。"""
analysis = analyzer.analyze_prompt(god_prompt)
print(f"复杂度: {analysis['complexity_score']}")
print(f"建议: {analysis['recommendation']}")
decomposition = analyzer.suggest_decomposition(god_prompt)
print("\n建议的分解步骤:")
for task in decomposition:
print(f"步骤 {task['step']} ({task['type']}): {task['content'][:50]}...")
修复方案:提示词链¶
# 修复:使用提示词链
class FinancialReportProcessor:
"""财务报告处理器(使用链式处理)"""
def __init__(self, llm_client):
self.llm = llm_client
self.results = {}
def process_report(self, report_text: str) -> dict:
"""处理单个报告"""
# 步骤 1: 翻译
translation = self._translate(report_text)
self.results["translation"] = translation
# 步骤 2: 摘要
summary = self._summarize(translation)
self.results["summary"] = summary
# 步骤 3: 分析情感和评分
analysis = self._analyze(summary)
self.results["analysis"] = analysis
return self.results
def _translate(self, text: str) -> str:
"""单独的翻译步骤"""
prompt = f"""请将以下财务报告翻译成中文。
保持专业术语和格式。
原文:
{text}"""
return self.llm.generate(prompt)
def _summarize(self, text: str) -> str:
"""单独的摘要步骤"""
prompt = f"""请用 200 字总结以下财务报告的关键要点:
{text}"""
return self.llm.generate(prompt)
def _analyze(self, text: str) -> dict:
"""单独的分析步骤"""
prompt = f"""分析以下财务报告摘要:
1. 情感倾向(正面/中立/负面)
2. 风险评级(1-5 分,5 分风险最高)
摘要:
{text}
请返回 JSON 格式:
{{"sentiment": "...", "risk_score": ...}}"""
response = self.llm.generate(prompt)
return json.loads(response)
def batch_process(self, reports: list) -> dict:
"""批量处理多个报告"""
results = {}
for i, report in enumerate(reports):
results[f"report_{i+1}"] = self.process_report(report)
return results
# 使用
processor = FinancialReportProcessor(llm_client)
all_results = processor.batch_process(reports)
反模式 4-8 的自查清单¶
反模式 4:强制格式的硬换行与缩进敏感¶
自查清单:
- 是否要求模型生成基于空格对齐的 ASCII 艺术?
- 是否强制要求特定的缩进或特殊字符模式?
- 替代方案:使用 JSON、YAML、Markdown 等标准格式
诊断代码:
def check_rigid_formatting(prompt: str) -> bool:
"""检测是否有过于严格的格式要求"""
rigid_patterns = [
r"缩进.*个空格",
r"must.*align",
r"空格.*对齐",
r"固定.*格式",
]
return any(re.search(p, prompt) for p in rigid_patterns)
反模式 5:缺乏退路¶
自查清单:
- 是否为“不确定”或“无法处理”提供了选项?
- 是否明确告诉模型什么时候可以说“我不知道”?
- 是否设置了错误情况下的降级方案?
诊断代码:
def check_escape_hatch(prompt: str) -> bool:
"""检查是否提供了逃生通路"""
escape_keywords = [
"如果找不到",
"如果不知道",
"如果无法",
"返回 null",
"return None",
"not found",
"unclear"
]
has_escape = any(kw in prompt for kw in escape_keywords)
return has_escape
反模式 6-8 的通用诊断框架¶
class AntiPatternDiagnostics:
"""反模式诊断工具"""
def diagnose_all(self, prompt: str) -> dict:
"""全面诊断提示词中的反模式"""
results = {
"over_prompting": self._check_over_prompting(prompt),
"negative_first": self._check_negative_first(prompt),
"god_prompt": self._check_god_prompt(prompt),
"rigid_formatting": self._check_rigid_formatting(prompt),
"no_escape": self._check_no_escape(prompt),
"context_pollution": self._check_context_pollution(prompt),
}
# 计算总体健康分数
results["health_score"] = self._calculate_health_score(results)
results["recommendations"] = self._generate_recommendations(results)
return results
def _calculate_health_score(self, results: dict) -> float:
"""计算提示词的健康分数(0-100)"""
issues = sum(1 for k, v in results.items()
if k != "health_score" and v.get("severity", 0) > 0)
return max(0, 100 - issues * 10)
def _generate_recommendations(self, results: dict) -> list:
"""基于诊断结果生成改进建议"""
recommendations = []
for issue_type, issue_data in results.items():
if issue_type == "health_score": # 已在上一行写入,是 float 而非诊断字典
continue
if issue_data.get("severity", 0) > 0:
recommendations.append({
"issue": issue_type,
"severity": issue_data["severity"],
"suggestion": issue_data.get("suggestion", "")
})
return sorted(recommendations, key=lambda x: x["severity"], reverse=True)
def _check_over_prompting(self, prompt: str) -> dict:
# 实现检测逻辑;返回值必须含 severity(0 表示未命中)与 suggestion,
# 否则 _calculate_health_score / _generate_recommendations 会在 None 上取值
return {"severity": 0, "suggestion": ""}
def _check_negative_first(self, prompt: str) -> dict:
# 实现检测逻辑
return {"severity": 0, "suggestion": ""}
# ... 其他检测方法(_check_god_prompt、_check_rigid_formatting、
# _check_no_escape、_check_context_pollution,返回结构同上)
E.3 提示词自查清单¶
快速检查表¶
【设计阶段】
□ 是否清晰定义了任务?
□ 是否有具体的成功标准?
□ 是否考虑了边界情况?
【指令阶段】
□ 是否避免了冗余措辞?
□ 是否用正向而非负向指令?
□ 是否字数控制在合理范围(通常 < 500 字)?
□ 是否将复杂任务分解为步骤?
□ 是否明确了输出格式?
【上下文阶段】
□ 是否只包含了相关信息?
□ 是否标记了外部数据的边界?
□ 是否移除了冗余的背景故事?
□ 是否提供了足够的示例?
【安全性阶段】
□ 是否有明确的权限限制?
□ 是否有错误处理的逃生通路?
□ 是否防护了提示词注入风险?
【测试阶段】
□ 是否在 5+ 个测试用例上运行?
□ 是否测试了边界情况?
□ 是否检查了格式一致性?
□ 是否评估了成功率?
健康度评分表¶
| 指标 | 优秀 | 良好 | 需改进 | 差 |
|---|---|---|---|---|
| 简洁度 | 无冗余 | 最少冗余 | 有明显冗余 | 严重冗余 |
| 指令清晰度 | 一句话清楚 | 需读 2 遍 | 需读多遍 | 无法理解 |
| 格式合理性 | 使用标准格式 | 格式明确 | 格式模糊 | 无格式 |
| 容错能力 | 有 3+ 个逃口 | 有 1-2 个 | 几乎没有 | 完全没有 |
| 整体评分 | 85+ | 70-84 | 50-69 | <50 |
E.4 常见反模式的修复工作坊¶
示例:电商 ChatBot 的反模式修复¶
原始(反模式集中)提示词¶
你好亲爱的 AI 助手!我今天遇到了个问题,希望你能帮我。
请务必、一定、千万记住:你是一个电商客服。
你不要问太多问题,不要说废话,不要输出无关内容。
用户可能会问产品、价格、发货、退货等问题。
请先问用户想了解什么,然后根据以下信息:
[100 行产品数据库内容]
然后根据用户的问题:
[用户输入]
最后给出专业的、礼貌的、简洁的、准确的回答。
务必确保回答符合我们公司的服务标准。
问题诊断¶
检测到的反模式:
✗ 过度措辞("亲爱的"、"务必"、"千万")
✗ 负向指令优先("不要问太多问题")
✗ 指令堆积(一个提示词承载多个角色)
✗ 冗余强调("专业的、礼貌的、简洁的、准确的"重复)
✗ 过多背景信息(100 行数据库)
诊断得分: 50/100(6 项检测命中 5 项,按 100 - 命中数 × 10 计算)
修复版本¶
<system>
你是一个电商客服助手。
【核心任务】
回答用户关于产品、价格、发货、退货的问题。
【可用信息】
[关键产品数据 - 仅保留必要部分]
【回答原则】
1. 准确:基于产品信息回答
2. 简洁:控制在 100 字以内
3. 有帮助:直接解决用户问题
【可行的操作】
✓ 查询产品信息
✓ 解释退货政策
✓ 建议相关产品
【不可行的操作】
✗ 修改订单价格
✗ 做出超出政策的承诺
✗ 讨论非业务话题
【处理不确定情况】
如果不清楚用户的问题,请说:"我需要更多信息...才能帮助你"
如果找不到答案,请说:"我来帮你联系我们的专家"
</system>
优化前后对比¶
| 指标 | 原始版 | 修复版 |
|---|---|---|
| 字数 | 350 | 180 |
| 冗余度 | 高 | 低 |
| 清晰度 | 中 | 高 |
| 一致性 | 低 | 高 |
| 诊断分数 | 50 | 100 |
E.5 反模式演变:为什么今天的“最佳实践”可能是明天的“反模式”¶
历史视角¶
2022年:
"最佳实践" - 使用详细的少样本示例
原因:模型较弱,需要更多引导
2024年:
"反模式" - 过多示例会减弱模型能力
原因:现在的模型足够强,过度示例反而混淆
启示:
随着模型的进化,我们的策略也需要进化。
不要固守"我以前的最佳实践",而要不断测试和适应。
适应新模型的检查表¶
当升级到新模型时:
□ 重新测试所有现有提示词
□ 尝试减少示例数量(新模型可能需要更少)
□ 尝试简化指令(新模型可能能理解更复杂的意图)
□ 评估性能是否有改进
□ 更新评估标准
□ 文档化新的最佳实践
总结¶
反模式不仅仅是“坏的做法”,它们是学习的机会。通过理解为什么某些模式失败,我们可以设计出更好的提示词。
关键要点:
- 简洁优于冗长:信息密度比措辞数量更重要
- 正向优于负向:告诉模型做什么,而不是不做什么
- 分解优于堆积:复杂任务需要链式处理
- 清晰优于隐含:明确标记数据和指令的边界
- 持续测试优于一次性设计:提示词需要不断优化