七月 Prompt 工程复盘这一个月我们踩过的提示词十大坑一、七月的 Prompt 迭代记录像一份事故调查报告翻开七月的工作日志有关 Prompt 的修改记录占了 40%。修改 System Prompt 角色设定→测试 3 次→回滚、增加 2 个 Few-shot 示例→输出长度暴增→删除示例、添加输出格式约束→JSON 解析失败率 15%→切换为 Markdown 表格。这些问题单看都不大。但每个都浪费了至少半天时间。十个问题加起来七月有整整五个工作日消耗在了 Prompt 调试上。更深的痛点是同样的 Prompt 在 GPT-4 上效果很好换到 Qwen 上输出格式完全不同。多模型兼容的代价是 Prompt 复杂度指数级增长。见证奇迹的时刻不是 Prompt 突然变好了——是整理完这十个坑之后发现其中七个有通用的解决方案。这篇文章就是这份解决方案的总结。二、十大坑的根因分析十个坑按阶段分为三类设计阶段的 3 个、执行阶段的 4 个、评估阶段的 3 个。最严重的四个标红是角色设定模糊、JSON 格式失控、缺乏量化指标、版本管理缺失。见证奇迹的时刻当你意识到花在 Prompt 调试上的时间里80%消耗在不确定这个改动是变好了还是变坏了——缺乏量化评估是一切问题的放大器。三、十大坑的逐一拆解与解决方案坑1角色设定模糊症状System Prompt 写你是一个专业助手输出风格时准时飘忽。根因模糊的角色定义让 LLM 在自由发挥和遵循指令之间摇摆。# ❌ 模糊的角色设定 SYSTEM_PROMPT_BAD 你是一个专业的技术助手请帮助用户解决问题。 # ✅ 明确的角色设定含具体能力边界和行为规范 # 设计原因明确告知LLM能做什么和不能做什么 # 比单纯的角色标签更能约束行为边界 SYSTEM_PROMPT_GOOD 你是一个专注于Python后端开发的技术助手。 能力范围 - Python 3.10 语法和最佳实践 - FastAPI、Django框架使用 - PostgreSQL、Redis数据库操作 - Docker容器化部署 行为规范 - 代码示例必须可运行包含必要的import语句 - 不输出超过100行的代码块 - 对不确定的问题明确说我不确定 - 使用简体中文回复代码注释使用英文 禁止事项 - 不提供前端代码除非与后端API交互相关 - 不讨论非技术话题 - 不自称专家或资深 坑4JSON 格式失控症状让 LLM 输出 JSON结果包裹在 markdown 代码块里或者多了逗号、少了引号。根因LLM 不是 JSON 生成器它在理解内容和遵守格式之间的优先级取决于训练数据。def parse_llm_json_output(raw_output: str) - dict: 健壮的JSON解析器。 设计原因LLM输出的JSON有五种常见变异 每种都需要专门处理不能依赖单次json.loads。 import json import re # 策略1直接解析最理想的情况 try: return json.loads(raw_output) except json.JSONDecodeError: pass # 策略2提取markdown代码块中的JSON # 设计原因GPT-4等模型经常把JSON包裹在json中 json_block re.search(r(?:json)?\s*\n?(.*?)\n?, raw_output, re.DOTALL) if json_block: try: return json.loads(json_block.group(1)) except json.JSONDecodeError: pass # 策略3提取第一个{...}或[...] # 设计原因有时候JSON前后有解释文字 json_match re.search(r(\{.*\}|\[.*\]), raw_output, re.DOTALL) if json_match: try: return json.loads(json_match.group(1)) except json.JSONDecodeError: pass # 策略4修复常见JSON错误 # 设计原因LLM偶尔会生成尾部逗号、单引号等非标准JSON cleaned raw_output cleaned re.sub(r,\s*}, }, cleaned) # 移除尾部逗号 cleaned re.sub(r,\s*], ], cleaned) # 移除数组尾部逗号 cleaned cleaned.replace(, ) # 单引号转双引号(谨慎使用) try: return json.loads(cleaned) except json.JSONDecodeError: pass # 策略5提取所有键值对 # 设计原因最坏情况—从自由文本中提取字段 kv_pattern re.findall(r(\w)\s*:\s*([^]*), raw_output) if kv_pattern: return dict(kv_pattern) raise ValueError(f无法解析LLM输出为JSON: {raw_output[:200]})坑8缺乏量化指标from dataclasses import dataclass from typing import List dataclass class PromptEvalMetrics: Prompt评估指标。 设计原因将感觉好多了转化为可比较的数字 这是Prompt工程从艺术到工程的转变点。 format_compliance: float # 格式符合率 (0-1) hallucination_rate: float # 幻觉率 (0-1) avg_output_length: int # 平均输出长度 task_success_rate: float # 任务成功率 (0-1) json_parse_success: float # JSON解析成功率 (0-1) def compare_with(self, baseline: PromptEvalMetrics) - dict: 与基线对比量化改进幅度 return { format: self.format_compliance - baseline.format_compliance, hallucination: baseline.hallucination_rate - self.hallucination_rate, success: self.task_success_rate - baseline.task_success_rate, }坑10版本管理缺失Prompt 也需要版本管理。每次修改 Prompt 后记录修改了什么、为什么改、对哪个指标有什么影响。简单的 Git 提交信息就是最低成本的版本管理。四、Prompt 工程的边界权衡越长越好 vs 越精越好很多人认为 Prompt 越详细越好。但超过 500 字的 System Prompt 反而降低了关键指令的遵循度。长 Prompt 中LLM 的注意力被分散。核心约束放在开头和结尾中间放示例。Few-shot 数量0-shot 适合简单任务。1-3 shot 适合格式约束。5-shot 以上边际收益递减。见证奇迹的时刻当从 3-shot 增加到 5-shot 后格式符合率仅提升 2%但 token 消耗增加了 60%。通用 Prompt vs 场景特化一个 Prompt 覆盖所有场景是不可能的。务实的分层策略公共部分提取为基础模板场景特有约束作为叠加层。五、总结七月 Prompt 工程复盘揭示了十大常见问题按阶段分类为设计阶段 3 个角色定义模糊、指令冲突、Few-shot 质量低、执行阶段 4 个JSON 解析失败、Token 预算超支、跨模型兼容、温度参数不当、评估阶段 3 个缺乏量化指标、测试用例不足、版本管理缺失。核心解决方案包括角色定义需包含明确的能力边界和行为禁止项、JSON 输出需多策略容错解析、Prompt 评估必须引入量化指标替代主观判断、版本管理需至少保留修改记录和指标变化。Prompt 的长度的收益在 500 字附近达到最优Few-shot 数量超过 3-5 条后边际收益快速递减。