为什么反模式比最佳实践更值得学
网上有大量"Prompt Engineering最佳实践"文章,但很少有人系统梳理什么不该做。实际上,理解反模式往往比记忆最佳实践更有效——因为反模式描述的是你在压力下自然会犯的错误,而最佳实践描述的是理想状态。
本文整理了在大量生产LLM应用中反复出现的Prompt反模式,每个模式都附有真实的坏例子和改进方案。
反模式一:角色扮演滥用(Role Bloat)
问题描述
过度依赖角色定义,用大量篇幅描述AI"是什么",而不是"应该做什么":
❌ 坏的系统提示:
你是一个拥有20年经验的资深软件工程师,同时也是人工智能领域的专家,
你对各种编程语言都有深入了解,包括Python、Java、JavaScript、Go、Rust等,
你曾在多家顶级科技公司工作,包括Google、Apple、Microsoft等,
你擅长系统设计、代码优化、Bug调试……(200字角色描述)
请帮我写一个Python函数,读取CSV文件。
问题:LLM不需要"相信"自己是某个角色才能表现好。200字的角色描述对实际输出贡献极小,却占用了宝贵的上下文窗口。
✅ 好的系统提示:
请用Python编写函数,功能:读取CSV文件并返回字典列表。
要求:
- 处理编码错误(默认utf-8,自动fallback到gbk)
- 跳过空行
- 返回类型:List[Dict[str, Any]]
原则:角色定义应该服务于约束行为,而不是营造氛围。最多一两句话,直接描述期望的行为特征。
反模式二:隐式假设(Implicit Context)
问题描述
假设LLM知道你的业务上下文,没有在Prompt中明确提供:
❌ 用户问题:
"这个用户的权限够吗?"
❌ Agent的工具调用 + 问LLM:
工具返回了:{"user_id": "123", "role": "viewer"}
然后问LLM:这个权限够吗?
问题:LLM不知道"够"是指什么操作的权限。它会随机猜测,或者给出通用性回答。
✅ 好的做法:
上下文:用户(user_id=123, role=viewer)正在尝试执行操作:
操作类型:export_user_data(批量导出用户数据)
权限要求:需要 admin 或 data_manager 角色
用户当前角色:viewer
问题:此用户是否有权限执行该操作?请返回JSON格式的判断结果。
原则:把LLM需要做出判断所需的全部信息都放在Prompt里。不要假设它记得你上次说的话,不要假设它了解你的系统。
反模式三:过度约束(Over-specification)
问题描述
用大量规则约束输出,结果反而降低了质量:
❌ 坏的约束:
请写一篇关于机器学习的文章,要求:
1. 第一段必须是定义
2. 第二段必须讲历史
3. 第三段必须讲应用
4. 第四段必须讲挑战
5. 第五段必须是总结
6. 每段必须恰好100字
7. 不能使用"此外"这个词
8. 不能使用被动句
9. 每段必须有一个比喻
10. 文章必须包含3个例子
...(20条规则)
问题:过多的机械性规则会让LLM分心——它把注意力放在"是否满足规则"上,而不是"内容是否高质量"上。这就像让作家一边写作一边数每句话的字数,结果必然文思枯涩。
✅ 好的约束:
请写一篇面向技术初学者的机器学习入门文章(1500字左右)。
目标读者:有编程基础但没接触过ML的开发者
期望效果:读完后能理解ML是什么,并想尝试写第一个模型
风格:像朋友解释,不像教科书
原则:约束要描述目标,而不是路径。说明你想要什么效果,让LLM自己找最好的实现方式。
反模式四:Chain of Thought过度依赖
问题描述
把所有问题都加"一步步思考",以为这样总是更好:
❌ 不适合的场景:
用户:今天几月几日?
系统提示:在回答前,请一步步思考,确认你的推理过程。
LLM:让我一步步分析:
首先,我需要确定当前是什么年份……
其次,我需要考虑时区问题……
(500字推理后)
所以今天可能是2026年4月30日。
问题:CoT(Chain of Thought)对推理题有效,但对简单查询反而引入冗余和延迟。
适合CoT的场景:数学计算、逻辑推理、多步骤规划 不适合CoT的场景:信息查询、格式转换、简单判断
# 动态判断是否需要CoT
def build_prompt(task_type: str, question: str) -> str:
cot_tasks = ["math", "logic", "planning", "analysis"]
if task_type in cot_tasks:
cot_instruction = "请一步步分析,展示你的推理过程。"
else:
cot_instruction = "" # 简单任务不加CoT
return f"{cot_instruction}\n\n{question}"
反模式五:否定指令陷阱(Negative Instructions)
问题描述
大量使用"不要做X"的指令:
❌ 充满否定的Prompt:
你是客服助手,请注意:
- 不要使用攻击性语言
- 不要提供法律建议
- 不要谈论竞争对手
- 不要做出任何承诺
- 不要透露内部系统信息
- 不要讨论敏感话题
...(10条"不要")
问题一:否定指令在LLM中比正向指令效果差——你告诉它"不要想大象",它满脑子都是大象。
问题二:否定列表会暗示LLM"这些是可能的操作路径",反而增加了它做这些事的概率。
✅ 转化为正向约束:
你的职责:
- 协助用户解决产品使用问题
- 提供产品功能的准确信息
- 在无法解决时,引导用户联系人工客服(电话:400-xxx-xxxx)
- 保持友好、专业的语气
超出以上范围的请求(如法律、医疗建议),请回答:"这超出了我的服务范围,建议您咨询专业人士。"
原则:把"不要做X"改写为"应该做Y"。如果必须用否定,不超过3条,且配合正向替代方案。
反模式六:格式指令不一致
问题描述
在Prompt中混用多种格式要求,或者指令本身的格式和要求输出的格式矛盾:
❌ 格式混乱:
请用JSON格式返回结果。字段包括:姓名、年龄、职业。
另外,如果用户是学生,请在回答前加上"[学生用户]"的标注。
如果信息不完整,用---分隔线标注缺失部分。
确保输出是可解析的JSON。
问题:这段指令要求JSON,又要求在前面加文本标注,又要求用分隔线——这些相互矛盾。LLM会随机选择一种理解,或者产生混合格式。
✅ 清晰的格式指令:
请返回如下JSON格式(严格JSON,无其他文本):
{
"name": "姓名 或 null",
"age": "年龄数字 或 null",
"occupation": "职业 或 null",
"is_student": true/false,
"completeness": "complete" 或 "partial",
"missing_fields": ["缺失字段列表"]
}
原则:格式要求要自洽,不要在一个Prompt里混用多种输出格式。
反模式七:动态信息写死(Static Injection)
问题描述
把会变化的信息硬编码在System Prompt里:
❌ 错误示例:
SYSTEM_PROMPT = """
你是2026年3月15日更新的AI助手,当前产品版本是v2.3.1,
当前正在进行春节促销活动,折扣为8折,
今天的值班人员是张三(分机:123)……
"""
问题:这些信息会过期,但System Prompt可能被缓存。用户在4月份问促销活动,得到3月份的错误信息。
✅ 动态注入当前状态:
def build_system_prompt():
dynamic_context = {
"date": datetime.now().strftime("%Y-%m-%d"),
"product_version": config.get("product_version"),
"active_promotions": promotions_service.get_active(),
"on_call_staff": staff_service.get_today_oncall(),
}
return f"""你是AI助手。
当前状态(实时信息):
- 今日日期:{dynamic_context['date']}
- 产品版本:{dynamic_context['product_version']}
- 当前促销:{json.dumps(dynamic_context['active_promotions'], ensure_ascii=False)}
- 今日值班:{dynamic_context['on_call_staff']}
"""
反模式八:单一版本Prompt(No Version Control)
问题描述
所有业务场景共用一个Prompt,修改时没有版本控制:
❌ 危险的做法:
# config.py
SYSTEM_PROMPT = "你是..." # 直接修改,没有版本记录
# 某个周五下午
SYSTEM_PROMPT = "你是...(改了一个词)" # 没有测试,直接上线
# 结果:周末大量用户反馈AI行为异常
# 工程师:我改了啥?
✅ Prompt版本管理:
# prompts/v1.2.0.py
SYSTEM_PROMPT_V120 = """...(稳定生产版本)..."""
# prompts/v1.3.0-beta.py
SYSTEM_PROMPT_V130_BETA = """...(测试中)..."""
# 通过配置控制使用哪个版本
def get_system_prompt(user_group="stable"):
if user_group == "beta":
return SYSTEM_PROMPT_V130_BETA
return SYSTEM_PROMPT_V120
# 或者用git管理,配合PR review
一份快速自检清单
在发布Prompt前,过一遍这些问题:
- 角色定义是否简洁(不超过2句话)?
- LLM需要的所有上下文是否都已提供?
- 是否有超过5条的约束规则(考虑合并/精简)?
- CoT指令是否只用在需要推理的任务上?
- 否定指令是否已转化为正向描述?
- 格式要求是否自洽、无矛盾?
- 动态信息是否通过代码注入而非硬编码?
- Prompt是否有版本控制,修改是否有记录?
结语
好的Prompt工程不是记住越多技巧越好,而是清楚理解LLM的局限性,避免给它制造混乱的信号。
很多时候,删掉一半Prompt内容,效果反而更好。精简、明确、一致——这三个词,比任何高级技巧都更有用。
把这份反模式清单贴在桌边,每次写Prompt时扫一遍。