Prompt 评测与失败排查实战:LLM-as-judge + 回归测试 + Debug 模式
Prompt 上 production 后怎么做评测:LLM-as-judge 自动打分、回归测试集、失败 case 分类(幻觉 / 偏题 / 格式错误)、Debug 模式 + token / cost 可视化。
操作步骤
准备回归测试集
收集 50-200 个测试 case:30% happy path + 40% 边界 case + 30% 历史失败 case。JSONL 格式 git 版本化,每条含 input / expected_output / category。
配 LLM-as-judge
用 GPT-5.6 Sol 当 judge,写明确的 rubric prompt:『请基于以下维度评分(0-10):准确性 / 流畅度 / 风格 / 格式合规。给出每个维度分数 + 总体评分 + 1 句话理由。』
上线 Debug 日志
每次调用记录:input hash、完整 prompt、output、token usage、latency、模型版本、judge score。结构化 JSON 存 S3 / 数据库。
接成本监控
每天算每个 prompt 的 avg token × 调用次数 × 模型费率 = 月成本趋势。超阈值告警。
A/B 上线 + 灰度
新 prompt 走 A/B 流量 10% → 1-2 周 → 全量上线。每次上线必须跑回归集 + 看 judge score + 业务指标三重确认。
Prompt 写好只是开始——上 production 后你需要:LLM-as-judge 自动打分、回归测试集、失败 case 分类、Debug 日志、成本可视化。本文给一个完整的『Prompt 上线 + 持续监控』pipeline。
为什么需要评测?
一个 Prompt 上 production 后面临三个问题:
- 稳定性:模型版本更新 / prompt 微调可能导致输出漂移。
- 回归:改了 prompt 想让某个 case 变好,可能跑坏 5 个其他 case。
- 失败排查:用户报告『AI 答错了』——具体错在哪?怎么修?
评测不是『写完 prompt 就完事』,是产品日常。
1. LLM-as-judge 自动打分
让 GPT-5.6 当裁判给 prompt 输出打分。关键原则:judge 用更强的模型(Sol),选手用什么模型都行。
模式 A:score(0-10 打分)
import openai
client = openai.OpenAI()
JUDGE_PROMPT = """
你是 prompt 输出评测专家。给定 input、prompt 输出、参考 answer,按 0-10 分评分:
- 0-3:完全错误 / 跑题 / 幻觉
- 4-6:部分正确但有显著问题
- 7-9:基本正确,有小瑕疵
- 10:完全正确且符合 prompt 风格
输出 JSON:{"score": <int>, "reason": "<一句话>"}
Input: {input}
Output: {output}
Reference: {reference}
"""
def judge(input_text, output, reference):
response = client.responses.create(
model="gpt-5.6-sol", # 用 Sol 当 judge
input=[{
"role": "user",
"content": JUDGE_PROMPT.format(
input=input_text,
output=output,
reference=reference,
),
}],
text={
"format": {
"type": "json_schema",
"name": "judge_result",
"strict": True,
"schema": {
"type": "object",
"properties": {
"score": {"type": "integer", "minimum": 0, "maximum": 10},
"reason": {"type": "string"},
},
"required": ["score", "reason"],
"additionalProperties": False,
},
},
},
)
return json.loads(response.output_text)
# 用法
result = judge("什么是 GPT-5.6?", "GPT-5.6 是 OpenAI 2026-07-09 发布的旗舰模型家族。", "OpenAI 旗舰模型")
print(result["score"], result["reason"])
模式 B:pairwise(A vs B)
新 prompt 改版时常用——A vs B 哪个更好?
PAIRWISE_PROMPT = """
你是 prompt 输出评测专家。给定同一 input 的两个输出(A 和 B),判断哪个更好。
评估维度:准确性 / 流畅度 / 风格 / 格式合规。
胜者标记为 'A' / 'B' / 'tie'。
理由 1 句话。
Input: {input}
Output A: {output_a}
Output B: {output_b}
"""
def pairwise(input_text, output_a, output_b):
response = client.responses.create(
model="gpt-5.6-sol",
input=[{
"role": "user",
"content": PAIRWISE_PROMPT.format(
input=input_text,
output_a=output_a,
output_b=output_b,
),
}],
text={
"format": {
"type": "json_schema",
"name": "pairwise_result",
"strict": True,
"schema": {
"type": "object",
"properties": {
"winner": {"type": "enum", "values": ["A", "B", "tie"]},
"reason": {"type": "string"},
},
"required": ["winner", "reason"],
"additionalProperties": False,
},
},
},
)
return json.loads(response.output_text)
用法:跑 50+ case,新 prompt 在 pairwise 里赢 ≥ 60% 才考虑上线。
模式 C:rubric(多维度)
RUBRIC_PROMPT = """
你是 prompt 输出评测专家。给定 input、output,按以下 rubric 评分(每个 0-10):
1. 准确性(factual correctness):输出事实是否正确?
2. 流畅度(fluency):语言是否自然?
3. 风格匹配(style match):是否符合 prompt 要求的风格?
4. 格式合规(format compliance):是否符合 prompt 要求的格式?
每个维度给分 + 1 句话理由。最后给总体评分 = 加权平均(准确性 0.4 + 流畅度 0.2 + 风格 0.2 + 格式 0.2)。
输出 JSON 严格按 schema。
Input: {input}
Output: {output}
"""
用法:需要细分质量时用——比如客服 prompt 准确性最重要(40% 权重),其他维度均匀。
2. 回归测试集
每次改 prompt 之前必跑回归,避免跑坏老 case。
# tests/prompts/customer-support.jsonl
{"id": "happy-001", "input": "我的订单 12345 还没收到", "category": "happy", "expected": "查询订单状态后回复"}
{"id": "happy-002", "input": "怎么退订?", "category": "happy", "expected": "说明退订流程"}
{"id": "edge-001", "input": "我要投诉!", "category": "edge", "expected": "道歉 + 转接人工"}
{"id": "edge-002", "input": "1111111111111111 是订单号吗?", "category": "edge", "expected": "提示用户订单号格式错误"}
{"id": "failure-001", "input": "OpenAI 是哪家公司?", "category": "failure", "expected": "正确回答 OpenAI 公司信息"}
{"id": "failure-002", "input": "GPT-5.6 发布日期?", "category": "failure", "expected": "2026-07-09,不编造"}
配置:
- 数量:50-200 case
- 分布:30% happy path + 40% 边界 case + 30% 历史失败 case
- 格式:JSONL,每行一个 case,含 input / category / expected
- 存储:git 版本化(
tests/prompts/*.jsonl)
import json
def run_regression(prompt_template, test_file, judge_fn):
with open(test_file) as f:
cases = [json.loads(line) for line in f]
results = []
for case in cases:
output = run_prompt(prompt_template, case["input"])
score = judge(case["input"], output, case["expected"])
results.append({
"id": case["id"],
"category": case["category"],
"score": score["score"],
"reason": score["reason"],
})
avg_score = sum(r["score"] for r in results) / len(results)
failed = [r for r in results if r["score"] < 7]
print(f"Avg score: {avg_score:.2f}")
print(f"Failed cases: {len(failed)}/{len(results)}")
for r in failed:
print(f" {r['id']}: {r['reason']}")
return avg_score, failed
3. 失败 case 分类
每次失败 case 必须归类:
| 类别 | 现象 | 修法 |
|---|---|---|
| 幻觉 | 模型编造事实 | 加 grounding 上下文 + RAG |
| 偏题 | 答非所问 | prompt 加约束 + few-shot |
| 格式错误 | 输出不符合 schema | strict JSON Schema |
| 长度超限 | 输出过长 / 过短 | 设 max_tokens 或摘要 prompt |
| 语气不符 | 风格 / 语气不对 | prompt 明确语气 + few-shot 示例 |
| 超时 | latency > 阈值 | 换小模型 + streaming |
自动分类器:
FAILURE_CATEGORIES = ["幻觉", "偏题", "格式错误", "长度超限", "语气不符", "超时"]
def classify_failure(input_text, output, reference):
response = client.responses.create(
model="gpt-5.6-sol",
input=[{
"role": "user",
"content": f"""判断下面 prompt 输出属于哪种失败:
Input: {input_text}
Output: {output}
Reference: {reference}
失败类别:{FAILURE_CATEGORIES}
""",
}],
text={
"format": {
"type": "json_schema",
"name": "failure_classification",
"strict": True,
"schema": {
"type": "object",
"properties": {
"category": {"type": "enum", "values": FAILURE_CATEGORIES},
"confidence": {"type": "number", "minimum": 0, "maximum": 1},
},
"required": ["category", "confidence"],
"additionalProperties": False,
},
},
},
)
return json.loads(response.output_text)
# 用法:自动归档失败 case
result = classify_failure(input, output, reference)
# {"category": "幻觉", "confidence": 0.92}
4. Debug 模式
每次调用必 log 关键字段:
import hashlib
import json
import time
def run_prompt_with_debug(prompt_template, input_data, **kwargs):
# 计算 input hash(用于去重 + 关联回归集)
input_hash = hashlib.md5(json.dumps(input_data, sort_keys=True).encode()).hexdigest()
# 渲染 prompt
full_prompt = prompt_template.format(**input_data)
# 调用 + 计时
start = time.time()
response = client.responses.create(
model="gpt-5.6-terra",
input=[{"role": "user", "content": full_prompt}],
**kwargs,
)
latency_ms = (time.time() - start) * 1000
# Log 完整数据
log_entry = {
"timestamp": datetime.utcnow().isoformat(),
"input_hash": input_hash,
"input": input_data,
"full_prompt": full_prompt, # 完整 prompt,不要只 log diff
"output": response.output_text,
"token_usage": {
"input_tokens": response.usage.input_tokens,
"output_tokens": response.usage.output_tokens,
"cached_tokens": response.usage.input_tokens_details.cached_tokens,
},
"latency_ms": latency_ms,
"model": response.model,
"model_version": "gpt-5.6-terra-2026-08-08", # 锁定具体版本
}
# 自动跑 judge + 失败 case 归档
if "reference" in input_data:
judge_result = judge(input_data, response.output_text, input_data["reference"])
log_entry["judge_score"] = judge_result["score"]
if judge_result["score"] < 7:
# 失败 case 自动归档
archive_failure(log_entry)
save_log(log_entry)
return response.output_text
关键字段:
input_hash:去重 + 关联回归集full_prompt:完整 prompt(不要只 log diff,定位时需要)token_usage:input + cached + output 各自计数latency_ms:从调用开始到拿到 responsemodel_version:锁定具体版本(不是 alias)judge_score:自动打分
5. 成本可视化
每个 prompt 算月成本:
# 假设
prompt_id = "customer-support-v3"
monthly_calls = 100_000
avg_input_tokens = 800
avg_output_tokens = 200
cache_hit_rate = 0.4 # 40% 调用命中 cache
model = "gpt-5.6-terra"
# GPT-5.6 Terra: $2.50/$15 per MTok, cache 1/4
non_cached_input_cost = avg_input_tokens * (1 - cache_hit_rate) * 2.50 / 1_000_000
cached_input_cost = avg_input_tokens * cache_hit_rate * (2.50 / 4) / 1_000_000
output_cost = avg_output_tokens * 15 / 1_000_000
cost_per_call = non_cached_input_cost + cached_input_cost + output_cost
monthly_cost = cost_per_call * monthly_calls
print(f"Cost per call: ${cost_per_call:.4f}")
print(f"Monthly cost: ${monthly_cost:.2f}")
# 监控指标
# - 月成本趋势(升幅 > 30% 告警)
# - 单次成本 > 阈值告警(可能被滥用)
# - Cache hit rate 下降告警(prompt 可能变了)
6. A/B 上线 + 灰度
新 prompt 上线流程:
本地回归集 OK → A/B 10% 流量 1 周 → 灰度 50% 流量 1 周 → 全量上线
↑ judge score +0.5+ ↑ 业务指标对齐 ↑
def ab_test_prompts(input_data, old_prompt, new_prompt, traffic_split=0.5):
"""A/B test with traffic split"""
bucket = hash(input_data["user_id"]) % 100 # 0-99
if bucket < traffic_split * 100:
# A bucket
return run_prompt(old_prompt, input_data, log_extra={"variant": "A"})
else:
# B bucket
return run_prompt(new_prompt, input_data, log_extra={"variant": "B"})
A/B 期间必看指标:
- judge score(必须新 prompt ≥ 旧 +0.5)
- 业务指标(用户满意度、任务完成率、跳出率)
- 成本(不能涨 > 50%)
A/B 1-2 周新 prompt 在所有指标上不弱于旧,才能全量上线。
7. 完整 pipeline 示意
[Prompt 改版]
↓
[本地回归集跑一遍] ← tests/prompts/*.jsonl
↓
[judge score 全部 ≥ 7]? ─ 否 → 改 prompt 重试
↓ 是
[A/B 10% 流量]
↓
[1 周后看指标] ─ judge / 业务 / 成本 都对齐?─ 否 → 回滚
↓ 是
[灰度 50% 流量]
↓
[1 周后全量上线]
常见问题
1. LLM-as-judge 和人工评测哪个准?
两种方法都要用:(1) LLM-as-judge 跑量大、成本低、自动化——适合每日千+ 次评测;(2) 人工评测更准但贵——适合每月 50-200 个关键 case 做 calibration。最佳实践:LLM-as-judge 做日常 gate,人工评测每 2 周做一次『校准』——比较 judge score 与人工 score 的 correlation,目标 > 0.8。correlation < 0.7 说明 judge prompt 写得不对,需要重写。
2. 回归测试集放哪里?
三个位置:(1) 代码 repo 里 tests/prompts/<feature>.jsonl —— git 版本化 + CI 自动跑;(2) Prompt 管理平台(OpenAI 没有官方平台,但 Anthropic Prompt Manager / Humanloop / LangSmith 可以);(3) 数据库表——灵活但 git 难追。生产推荐 (1) + (2):repo 里存核心 happy path + 失败 case 快照,平台存完整历史 + 元数据。
3. 怎么判断 prompt 改版是好是坏?
三步:(1) 在回归测试集上跑新旧两版 prompt,比较 judge score(必须 score up +0.5+ 且不破老 case);(2) A/B 流量 10% 上线新 prompt,监控业务指标(用户满意度 / 任务完成率 / 跳出率);(3) 灰度 1-2 周后全量上线。注意:A/B 阶段必须新旧 prompt 同时服务同一群用户,否则用户分布偏差会掩盖效果差异。
4. 幻觉类失败 case 怎么排查?
三步:(1) 找到幻觉的具体事实——模型说了什么、事实是什么、官方源在哪;(2) 检查 prompt 里有没有 grounding 上下文(『请基于以下文档回答』+ 文档原文);(3) 加 RAG——让模型先去检索相关文档再回答。常见反模式:让模型凭记忆回答开放事实(『GPT-5.6 的发布日期是哪天』)——这种问题必须接 RAG 或 knowledge base。
5. 评测 prompt 的成本怎么算?
三层:(1) 评测本身成本——LLM-as-judge 调用 × 输入 token × judge 模型费率;(2) 被评测 prompt 的成本——运行成本;(3) 评测频率成本——每天跑回归集 × token。100 case × 500 input token × $2.50/MTok(GPT-5.6 Terra)= $0.125/day = $3.75/月。GPT-5.6 Sol 当 judge 会贵 2-3 倍。建议:日常回归用 Luna/Sol(便宜 + 准),critical gate 用 Sol。
下一步
- 想了解 prompt 核心模式?读 《Prompt Engineering 核心模式:8 个让 GPT 表现翻倍的模板》。
- 想了解 prompt 进阶?读 《Prompt Engineering 进阶:多轮上下文、结构化输出与 GPT-5.6 调优》。
- 想了解代码专用 prompt?读 《GPT-5.6 代码专用 Prompt 模式:让 Codex / Cursor 一次写对的 12 个模板》。
关键要点
- LLM-as-judge 三种模式:(1) score(0-10 打分)+ threshold;(2) pairwise(A vs B 谁更好)+ ELO 排名;(3) rubric(多维度评分如准确性 / 流畅度 / 风格)+ 加权汇总。GPT-5.6 Sol 当裁判与 GPT-5.6 Terra 当选手,judge 需要更强的 reasoning
- 回归测试集必须 50+ case,包含 happy path + 边界 case + 历史失败 case。每次 prompt 改完跑一次,确认新 prompt 没破老 case。建议用 JSONL 格式 + git 版本化
- 失败 case 四类:(1) 幻觉(模型编造事实)——加 grounding 上下文;(2) 偏题(答非所问)——prompt 加约束或 few-shot;(3) 格式错误(输出不符合 schema)——strict JSON Schema;(4) 长度超限——设 max_tokens 或摘要 prompt
- Debug 模式必 log 的字段:input hash、完整 prompt(不要只 log diff)、output、token usage(input / output / cached)、latency、模型版本、judge score。每次失败 case 自动归档到 regression set
- 成本可视化:每个 prompt 算 avg input / output token × 调用次数 × 模型费率 = 月成本。趋势监控:某 prompt 月成本 > 阈值 → 告警(可能被滥用或 prompt 变长)
常见问题
官方参考
相关文章
GPT-5.6 代码专用 Prompt 模式:让 Codex / Cursor 一次写对的 12 个模板
GPT-5.6 家族给代码场景优化的 12 个 prompt 模板:架构理解、增量实现、bug 定位、code review、测试生成、重构、依赖升级。配合 Codex CLI / Cursor / Aider 使用。
阅读全文Prompt Engineering 进阶:多轮上下文、结构化输出与 GPT-5.6 调优
Prompt Engineering 第二篇:多轮上下文管理、结构化输出(JSON Schema)、few-shot 模式、长上下文策略与 GPT-5.6 reasoning.effort 调优。
阅读全文Prompt Engineering 核心模式:8 个让 GPT 表现翻倍的模板
系统讲解 8 个高频 Prompt 模式:角色扮演、Few-shot、Chain-of-Thought、ReAct、Self-Consistency 等,每种配可复用模板。
阅读全文订阅 GPTMap Weekly
每周一封邮件,精选 OpenAI 重要更新、深度解读与最佳实践。无广告,可随时退订。