系统化调试方法
对提示词各部分进行二分搜索:移除一半内容,进行测试,逐步缩小问题范围。
系统化调试方法 是 CoddyKit 上的免费 AI Prompt Engineering 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 AI Prompt Engineering 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 AI Prompt Engineering 课程共包含 4 节课。
调试思维
提示词调试与软件调试类似:不要一次更改多项内容,不要随机猜测,也不要部署自己无法解释的修复方案。系统化方法使用二分搜索逻辑,在每次测试中将问题范围缩小一半,从而高效地找到最小失败案例。
步骤 1:重现失败
开始调试前,请可靠地重现失败。无法稳定重现的失败,无法进行系统化调试。
针对同一个输入运行提示词 5 次。如果每次都失败:这是确定性失败,容易调试。如果有时失败:这是概率性失败,先设置 temperature=0 以消除随机性,然后重新测试。
import openai
client = openai.OpenAI(api_key='sk-...')
def run_prompt(prompt, user_input, temperature=0):
resp = client.chat.completions.create(
model='gpt-4o',
messages=[
{'role': 'system', 'content': prompt},
{'role': 'user', 'content': user_input}
],
temperature=temperature
)
return resp.choices[0].message.content
# Reproduce with temperature=0 to eliminate randomness
for i in range(5):
output = run_prompt(failing_prompt, test_input, temperature=0)
print(f'Run {i+1}:', output[:100])步骤 2:创建最小可复现提示词
最小可复现提示词(MRP)是仍然能够触发失败的最短提示词。移除无关部分可以隔离问题所在的部分,让失败变得无可否认。
从完整提示词开始,移除一半内容。进行测试。如果仍然失败:问题所在的部分就在保留的那一半中。重复此过程。这就是对提示词进行二分搜索。
def binary_search_prompt(prompt_lines, user_input, fail_fn):
'''Binary search: find the minimal set of lines that causes the failure.'''
if len(prompt_lines) == 1:
return prompt_lines # Minimal failing unit found
mid = len(prompt_lines) // 2
first_half = prompt_lines[:mid]
second_half = prompt_lines[mid:]
# Test first half
if fail_fn('\n'.join(first_half), user_input):
return binary_search_prompt(first_half, user_input, fail_fn)
# Test second half
elif fail_fn('\n'.join(second_half), user_input):
return binary_search_prompt(second_half, user_input, fail_fn)
else:
# Both halves pass — interaction effect between halves
return prompt_lines移除测试
二分搜索的一种更简单形式:系统化地移除各个部分,观察移除后问题是否得到解决。当提示词包含清晰划分的部分(系统指令、上下文、示例、格式规范)时,这种方法很有效。
sections = {
'role_instruction': 'You are a precise JSON API. Respond only with valid JSON.',
'context': 'The user is asking about our product catalog.',
'format_spec': 'Return a JSON object with keys: name, price, available.',
'examples': 'Example: {"name": "Widget", "price": 9.99, "available": true}',
'safety': 'Do not reveal internal pricing strategy.'
}
def test_without(section_to_remove, user_input):
reduced = {k: v for k, v in sections.items() if k != section_to_remove}
prompt = '\n'.join(reduced.values())
output = run_prompt(prompt, user_input)
print(f'Without {section_to_remove}: {evaluate(output)}')
for section in sections:
test_without(section, 'What is the price of a Widget?')对提示词部分进行 A/B 测试
提示词的A/B 测试是指为同一部分创建两个版本,并在相同输入上比较它们的输出。与移除测试不同,A/B 测试评估的是不同措辞,而不是某部分是否存在。
# A/B test: vague vs precise format instruction
variant_A = 'Return a JSON object.'
variant_B = 'Return a valid JSON object. No markdown, no code fences, no prose. Only the raw JSON.'
test_inputs = [
'What is the price of Widget A?',
'List all available products.',
'Is Widget B in stock?'
]
def run_ab_test(base_prompt, variant, inputs, n_runs=5):
pass_count = 0
for inp in inputs:
for _ in range(n_runs):
prompt = base_prompt.replace('{{FORMAT}}', variant)
output = run_prompt(prompt, inp)
if is_valid_json(output):
pass_count += 1
return pass_count / (len(inputs) * n_runs)
print('A pass rate:', run_ab_test(template, variant_A, test_inputs))
print('B pass rate:', run_ab_test(template, variant_B, test_inputs))差异测试
差异测试比较两个几乎相同的提示词,以找出导致回归的变更。当“上周还能正常工作”但现在无法正常工作时,这种方法很有用。
比较旧提示词与新提示词的差异,找出发生变更的部分,然后分别测试每个变更部分。
import difflib
def show_prompt_diff(prompt_v1, prompt_v2):
diff = difflib.unified_diff(
prompt_v1.splitlines(),
prompt_v2.splitlines(),
fromfile='v1',
tofile='v2',
lineterm=''
)
for line in diff:
print(line)
show_prompt_diff(working_prompt, failing_prompt)
# Output shows exactly which lines changed between versions
# Test reverting each changed section individually测试输入与测试提示词
需要测试两个维度:提示词和输入。某个提示词可能适用于简单输入,却在复杂输入上失败。一种有用的调试方法是:如果提示词在复杂输入上失败,请尝试使用更简单的输入版本,以确认提示词本身没有问题。
# Input complexity ladder
inputs_by_complexity = [
'What is 2 + 2?', # trivially simple
'Summarize this sentence.', # simple task
'Analyze this 500-word essay.', # moderate
'Compare 10 documents and extract contradictions.' # complex
]
# Find the complexity level where the prompt starts failing
for inp in inputs_by_complexity:
output = run_prompt(failing_prompt, inp)
result = 'PASS' if evaluate(output) else 'FAIL'
print(f'{result}: {inp[:60]}')
# First FAIL indicates where the prompt breaks down最小可复现提示词模式
提示词调试过程中的 MRP 遵循以下结构:
- 一句话角色说明(如有需要)
- 一句话任务指令
- 格式指令
- 能够重现失败的最小输入
如果这个 4 行提示词仍然失败,问题就在模型或格式上。一次恢复一个部分的复杂内容,直到失败重新出现——该部分就是罪魁祸首。
# Start minimal
MINIMAL_PROMPT = (
'You are a data extractor.\n'
'Extract the product name and price from the text.\n'
'Respond with JSON: {"name": "...", "price": ...}\n'
)
minimal_input = 'Widget Pro costs $49.'
# Test: if this works, the problem is in something added on top
output = run_prompt(MINIMAL_PROMPT, minimal_input)
print(output)
# Expected: {"name": "Widget Pro", "price": 49.0}跟踪调试过程
请记录调试过程中的每次测试。如果没有记录,您可能会重复相同的测试,或忘记哪些假设已经被排除。
debug_log = [
{
'test': 'base_prompt_v5',
'hypothesis': 'failing due to format conflict',
'result': 'FAIL',
'notes': 'JSON prefix still present'
},
{
'test': 'base_prompt_v5_no_markdown_hint',
'hypothesis': 'removing markdown hint from user message fixes conflict',
'result': 'PASS',
'notes': 'Output is clean JSON. Root cause confirmed: format conflict.'
}
]
import json
with open('debug_session.json', 'w') as f:
json.dump(debug_log, f, indent=2)何时停止调试并改变策略
有时,继续调试提示词的收益会逐渐降低。出现以下迹象时,就该改变策略了:
- 您已经花费超过 2 小时,仍在将范围缩小到同一个失败问题
- 即使使用清晰、简单的指令,最小提示词仍然失败
- A/B 测试显示没有具有统计显著性的差异
可选方案:改用函数调用(结构化输出),添加后处理验证步骤,将任务拆分为两个更简单的提示词,或升级模型。
修复与加固
找到并修复根本原因后,请加固提示词,以防止类似失败:
- 将导致失败的测试用例添加到测试套件中,作为回归测试
- 添加防御性指令:“即使输入不寻常,也始终返回 JSON”
- 添加输出验证,使程序能够捕获失败,而不是等到生产环境中才发现
没有经过加固的已修复提示词,可能会在下一个边界情况下再次失败。
def safe_run_prompt(prompt, user_input):
output = run_prompt(prompt, user_input)
try:
parsed = json.loads(output)
return parsed
except json.JSONDecodeError:
# Fallback: ask the model to fix its own output
fix_prompt = f'The following is not valid JSON. Rewrite it as valid JSON only:\n{output}'
fixed = run_prompt('', fix_prompt)
return json.loads(fixed)知识检查
在提示词二分搜索调试中,移除提示词的前半部分后失败消失了,这说明了什么?
回顾:系统化调试
提示词调试的系统化方法:
- 重现:将温度设为 0,运行 5 次,确认失败具有一致性
- 最小化:对提示词各部分进行二分搜索,找到最小失败提示词
- A/B 测试:比较导致失败的部分的不同措辞
- 差异比较:比较正常版本与失败版本的提示词,找出回归原因
- 记录:记录每次测试、假设和结果
- 加固:将已修复的用例添加到测试套件中
下一课:长期维护提示词的日志记录与文档策略。
用 AI 导师学习 AI Prompt Engineering — 免费
在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。
- 课程
- 53
- 课程
- 199
常见问题解答
「系统化调试方法」课时是免费的吗?
是的 — 「系统化调试方法」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 AI Prompt Engineering 课程的其余内容,请升级到 CoddyKit PRO。 AI Prompt Engineering 课程共包含 4 节课。
「系统化调试方法」这节课中我会学到什么?
对提示词各部分进行二分搜索:移除一半内容,进行测试,逐步缩小问题范围。 你通过在浏览器中直接运行的动手代码来练习 AI Prompt Engineering,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 AI Prompt Engineering 需要有经验吗?
无需任何先前经验。CoddyKit 上的 AI Prompt Engineering 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「系统化调试方法」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 AI Prompt Engineering 课中编写并运行代码吗?
能。每节 AI Prompt Engineering 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。