🧠AI Prompt 与上下文
Prompt调试与迭代
难度:⭐ | 高频指数:🔥🔥🔥 | 应用岗相关度:★★★
面试回答
常见问法
- “Prompt 不好使的时候你怎么调?”
- “你有没有系统化的 Prompt 调试方法?”
- “怎么做 Prompt 的版本管理和 A/B 测试?“
回答
Prompt 调试不是瞎试,而是有系统方法的。核心思路是:先诊断问题类型,再针对性调整,最后用评测验证效果。
# Prompt调试系统化框架
class PromptDebugger:
"""
Prompt调试四步法:
1. 诊断问题类型
2. 定位原因
3. 针对性修改
4. 评测验证
"""
def __init__(self, llm_client, eval_dataset):
self.llm = llm_client
self.eval_dataset = eval_dataset
self.prompt_versions = []
def diagnose(self, prompt, bad_outputs):
"""
诊断Prompt问题类型
常见问题分类:
- 输出不稳定:同一输入多次输出差异大
- 格式不对:不按要求的格式输出
- 幻觉:编造不存在的信息
- 拒绝回答:该回答的不回答
- 答非所问:回答和问题不相关
- 信息遗漏:回答不完整
"""
issues = []
for output in bad_outputs:
# 检查格式问题
if not self.check_format(output):
issues.append({
'type': 'format_error',
'description': '输出格式不符合要求',
'example': output[:200]
})
# 检查幻觉
if self.detect_hallucination(output):
issues.append({
'type': 'hallucination',
'description': '包含编造的信息',
'example': output[:200]
})
# 检查拒绝回答
if self.detect_refusal(output):
issues.append({
'type': 'refusal',
'description': '不必要的拒绝回答',
'example': output[:200]
})
# 检查答非所问
if self.detect_irrelevant(output):
issues.append({
'type': 'irrelevant',
'description': '回答与问题不相关',
'example': output[:200]
})
return {
'issues': issues,
'primary_issue': self.identify_primary_issue(issues),
'suggested_fixes': self.suggest_fixes(issues)
}
def suggest_fixes(self, issues):
"""根据问题类型建议修复方案"""
fixes = {
'format_error': [
"添加明确的输出格式示例",
"使用 JSON schema 约束",
"在 prompt 末尾重复格式要求",
],
'hallucination': [
"添加'如果不确定请说不知道'的约束",
"要求标注信息来源",
"降低 temperature 参数",
],
'refusal': [
"放宽安全约束的措辞",
"明确说明这是合法的使用场景",
"调整 system prompt 的角色定义",
],
'irrelevant': [
"在 prompt 开头强调任务目标",
"添加 CoT(思维链)引导",
"拆分复杂 prompt 为多步",
],
'unstable': [
"降低 temperature(0.1-0.3)",
"添加更多约束条件",
"使用 few-shot 示例固定输出模式",
],
'incomplete': [
"明确列出需要包含的要素",
"使用 checklist 格式要求",
"添加'请确保覆盖以下方面'的提示",
]
}
suggested = []
for issue in issues:
issue_type = issue['type']
if issue_type in fixes:
suggested.extend(fixes[issue_type])
return list(set(suggested)) # 去重
# 常见问题的调试技巧
class PromptFixStrategies:
"""针对不同问题的修复策略"""
def fix_unstable_output(self, original_prompt):
"""修复输出不稳定"""
fixes = [
# 1. 降低温度
{"param": "temperature", "value": 0.1},
# 2. 添加格式约束
{"action": "append", "content": "\n\n请严格按照以下格式输出,不要添加额外内容:"},
# 3. 添加 few-shot
{"action": "add_examples", "count": 3},
]
return fixes
def fix_format_error(self, original_prompt):
"""修复格式问题"""
# 策略:在prompt末尾重复格式要求 + 给出正反例
improved = original_prompt + """
## 输出格式(重要!)
必须输出合法的JSON,格式如下:
```json
{
"field1": "value1",
"field2": "value2"
}
错误示例(不要这样输出):
-
不要在JSON前后加解释文字
-
不要使用markdown代码块以外的格式
-
不要省略必需字段 """ return improved
def fix_hallucination(self, original_prompt): """修复幻觉问题""" # 策略:添加约束 + 要求引用 constraint = """
重要约束
-
只基于提供的资料回答,不要编造信息
-
如果资料中没有相关信息,请明确说”根据提供的资料无法回答”
-
每个事实陈述都要标注来源编号
-
不确定的信息用”可能”、“大约”等词修饰 """ return original_prompt + constraint
def fix_with_cot(self, original_prompt): """添加思维链(CoT)""" cot_instruction = """
请按以下步骤思考:
- 首先理解问题的核心是什么
- 然后从提供的信息中找到相关内容
- 最后组织答案
让我们一步步来: """ return original_prompt + cot_instruction
def split_complex_prompt(self, complex_prompt):
"""拆分复杂Prompt为多步"""
# 复杂任务拆成多个简单步骤
steps = [
{
'step': 1,
'prompt': "从以下文本中提取所有关键实体(人名、地名、组织名)",
'output_format': "JSON列表"
},
{
'step': 2,
'prompt': "基于提取的实体,分析它们之间的关系",
'input': "上一步的输出",
'output_format': "关系三元组"
},
{
'step': 3,
'prompt': "基于实体和关系,生成结构化摘要",
'input': "前两步的输出",
'output_format': "结构化报告"
}
]
return steps
### 追问
**怎么做 Prompt 的 A/B 测试?**
```python
class PromptABTest:
"""Prompt A/B测试框架"""
def __init__(self, eval_dataset, metrics):
self.eval_dataset = eval_dataset
self.metrics = metrics
def run_ab_test(self, prompt_a, prompt_b, sample_size=50):
"""
A/B测试两个Prompt版本
1. 在相同数据集上运行两个版本
2. 计算各维度指标
3. 统计显著性检验
4. 给出结论
"""
results_a = []
results_b = []
# 随机选择测试样本
test_samples = random.sample(self.eval_dataset, sample_size)
for sample in test_samples:
# 版本A
output_a = self.run_prompt(prompt_a, sample['input'])
score_a = self.evaluate(output_a, sample['expected'])
results_a.append(score_a)
# 版本B
output_b = self.run_prompt(prompt_b, sample['input'])
score_b = self.evaluate(output_b, sample['expected'])
results_b.append(score_b)
# 统计分析
comparison = self.compare_results(results_a, results_b)
return {
'prompt_a_avg': sum(results_a) / len(results_a),
'prompt_b_avg': sum(results_b) / len(results_b),
'winner': 'A' if comparison['a_better'] else 'B',
'confidence': comparison['confidence'],
'significant': comparison['confidence'] > 0.95,
'details': comparison
}
def compare_results(self, results_a, results_b):
"""统计比较"""
import numpy as np
a_mean = np.mean(results_a)
b_mean = np.mean(results_b)
# 简单的t检验
from scipy import stats
t_stat, p_value = stats.ttest_ind(results_a, results_b)
return {
'a_better': a_mean > b_mean,
'difference': abs(a_mean - b_mean),
'confidence': 1 - p_value,
'a_mean': a_mean,
'b_mean': b_mean
}
原理展开
Prompt 版本管理
class PromptVersionManager:
"""
Prompt版本管理
记录每个版本的:
- Prompt内容
- 修改原因
- 评测结果
- 适用场景
"""
def __init__(self, storage_path):
self.storage_path = storage_path
self.versions = []
def save_version(self, prompt_content, metadata):
"""保存新版本"""
version = {
'version': f"v{len(self.versions) + 1}",
'content': prompt_content,
'created_at': time.time(),
'author': metadata.get('author', 'unknown'),
'change_reason': metadata.get('reason', ''),
'eval_results': metadata.get('eval_results', {}),
'notes': metadata.get('notes', ''),
'status': 'draft' # draft / active / deprecated
}
self.versions.append(version)
return version['version']
def compare_versions(self, version_a, version_b):
"""对比两个版本"""
va = self.get_version(version_a)
vb = self.get_version(version_b)
return {
'content_diff': self.diff_content(va['content'], vb['content']),
'eval_comparison': self.compare_evals(
va['eval_results'], vb['eval_results']
),
'recommendation': self.recommend(va, vb)
}
def get_changelog(self):
"""获取变更日志"""
changelog = []
for v in self.versions:
changelog.append({
'version': v['version'],
'date': v['created_at'],
'reason': v['change_reason'],
'accuracy': v['eval_results'].get('accuracy', 'N/A'),
'status': v['status']
})
return changelog
# 实际案例:一个Prompt从v1到v5的迭代过程
PROMPT_ITERATION_EXAMPLE = """
=== 任务:从用户反馈中提取情感和关键问题 ===
--- v1(初版,问题:输出不稳定,格式混乱)---
"分析以下用户反馈,提取情感和问题。"
问题诊断:太模糊,没有格式约束
--- v2(加格式约束,问题:有时还是不输出JSON)---
"分析以下用户反馈,提取情感和问题。输出JSON格式。"
问题诊断:格式要求不够具体
--- v3(加schema和示例,问题:幻觉,编造不存在的问题)---
"分析以下用户反馈,提取情感和关键问题。
输出格式:
{
"sentiment": "positive/negative/neutral",
"issues": ["问题1", "问题2"],
"severity": "high/medium/low"
}
示例:
输入:'这个产品太难用了,按钮找不到'
输出:{"sentiment": "negative", "issues": ["界面不友好", "按钮难找"], "severity": "medium"}"
问题诊断:模型会编造反馈中没提到的问题
--- v4(加约束防幻觉,问题:部分边界case处理不好)---
"分析以下用户反馈,提取情感和关键问题。
重要:只提取反馈中明确提到的问题,不要推测或编造。
如果反馈内容不清晰,issues字段返回空数组。
输出格式:
{
"sentiment": "positive/negative/neutral",
"issues": ["只写反馈中明确提到的问题"],
"severity": "high/medium/low"
}
示例:..."
问题诊断:空反馈和多语言混合时处理不好
--- v5(最终版,加边界处理)---
"你是一个用户反馈分析助手。
任务:从用户反馈中提取情感倾向和具体问题。
规则:
1. sentiment只能是 positive/negative/neutral 之一
2. issues只写反馈中明确提到的问题,不推测
3. 如果反馈为空或无法理解,返回 {"sentiment": "neutral", "issues": [], "severity": "low"}
4. 如果反馈包含多个问题,按严重程度排序
输出格式:
{
"sentiment": "positive/negative/neutral",
"issues": ["问题1", "问题2"],
"severity": "high/medium/low"
}
示例1(负面):
输入:'登录总是失败,试了三次都不行'
输出:{"sentiment": "negative", "issues": ["登录失败"], "severity": "high"}
示例2(正面):
输入:'新版本速度快了很多,赞'
输出:{"sentiment": "positive", "issues": [], "severity": "low"}
示例3(模糊):
输入:'还行吧'
输出:{"sentiment": "neutral", "issues": [], "severity": "low"}
现在分析以下反馈:
{user_feedback}"
评测结果:准确率从v1的62%提升到v5的91%
"""
调试流程总结
# 系统化调试流程
DEBUG_WORKFLOW = {
"step1_reproduce": {
"description": "复现问题",
"actions": [
"收集bad case(至少5-10个)",
"分类问题类型",
"确认是Prompt问题还是其他环节问题"
]
},
"step2_diagnose": {
"description": "诊断根因",
"actions": [
"是格式问题?→ 加格式约束和示例",
"是幻觉?→ 加事实约束和引用要求",
"是不稳定?→ 降温度、加few-shot",
"是答非所问?→ 加CoT、拆分prompt",
"是拒绝回答?→ 调整角色定义和约束措辞"
]
},
"step3_fix": {
"description": "针对性修改",
"actions": [
"每次只改一个变量",
"保留旧版本做对比",
"先在bad case上验证"
]
},
"step4_validate": {
"description": "评测验证",
"actions": [
"在完整评测集上跑",
"确认bad case修复了",
"确认没有引入新问题(回归)",
"记录版本和结果"
]
}
}
易错点
- 没有系统方法,靠直觉瞎改 Prompt
- 每次改多个变量,无法判断哪个改动有效
- 只在 bad case 上验证,不做全量回归
- 不记录版本,改来改去回不到之前的好版本
- 把所有问题都归结为 Prompt 问题(可能是检索或数据问题)
记忆技巧
记住 Prompt 调试的”四步法 + 五类问题”:
四步法: 复现 → 诊断 → 修改 → 验证
五类常见问题及对策:
- 输出不稳定 → 降温度 + few-shot
- 格式不对 → 加 schema + 正反例
- 幻觉 → 加约束 + 要求引用
- 答非所问 → 加 CoT + 拆分
- 拒绝回答 → 调角色定义
面试速答版
- Prompt 调试不是瞎试,系统方法是:复现问题 → 诊断类型 → 针对性修改 → 评测验证
- 五类常见问题:不稳定(降温度)、格式错(加schema)、幻觉(加约束)、答非所问(加CoT)、拒绝(调角色)
- 关键原则:每次只改一个变量,保留旧版本做对比,在完整评测集上回归
- A/B 测试方法:相同数据集跑两个版本,统计显著性检验后再决定上线
- 版本管理:记录每个版本的内容、修改原因、评测结果,能随时回滚
- 常见坑:靠直觉改、改多个变量、只看 bad case 不做回归、不记录版本
- 一句话最佳实践:先确认是不是 Prompt 的问题,再系统化调试,用数据说话
Related · Prompt 与上下文