EP02. "Prompt 评估工作流:从拍脑袋到用数据说话"
🔒 登录后可标记已读- Prompt 写完只测一次就上线,上生产环境「大概率会出事」——用户会用你完全没想到的方式提问,靠感觉测几次不够
- Prompt Engineering(怎么写好一个 prompt)跟 Prompt Evaluation(怎么客观量测一个 prompt 好不好)是两件不同的事,这篇笔记讲后者
- 一套完整评估流程是:草拟 prompt → 准备测试数据集 → 跑一遍 Claude → 打分 → 照分数改进 prompt → 再跑一次比较分数,全程可以用代码自动化
- 打分(grading)分三种方式:写代码硬检查格式、找另一个模型当裁判、找真人看——这篇笔记后半段示范用 Claude 自己当裁判
- 前置知识:读过 [EP01](./EP01_claude-api基础入门.md),会用
client.messages.create()、assistant prefill + stop sequence 这套基本功
重点内容
为什么不能只测一次就上线
写完一个 prompt,一般有三条路:
| 做法 | 问题 |
|---|---|
| 测一次就觉得行了 | 上生产环境后「翻车风险很高」 |
| 针对几个想到的边界情况多测几次 | 「用户实际会用的方式,往往比想象中更出人意料」——照样有漏网之鱼 |
| 搭一套评估流程(eval pipeline),跑分、再照客观指标迭代 | 前期要多花时间搭基础设施,但能在上线前抓出弱点、客观比较不同版本、靠数据而不是直觉去迭代 |
📌 一句话总结这篇笔记的立场:"当你把 prompt 部署到生产环境,用户跟它互动的方式,一定会超出你的预料。"
一套典型评估流程的五步
第一步:草拟 prompt
prompt = f"""
Please answer the user's question:
{question}
"""
第二步:准备评估数据集
收集能代表真实使用场景的样本问题。示范用的极简数据集只有三条:「2+2 等于多少」「怎么煮燕麦粥」「月球有多远」。真实项目的数据集可能有几十、几百甚至几千条。
第三步:整批跑过 Claude
把数据集里每一条问题套进 prompt 模板,发给 Claude,收集回答。
第四步:交给评分员打分
用 1-10 分制评估回答质量。示范三条分别拿到 10 分、4 分、9 分,平均 7.66 分。
第五步:照分数改 prompt,重新跑一次
针对拿低分的地方调整 prompt。示范只是加了一句「Answer the question with ample detail」,平均分从 7.66 涨到 8.7。
💡 这套流程的价值在于「拿到客观的数字」——不同版本的 prompt 可以直接拿分数比较,不用靠感觉猜哪个写得更好。
搭一套真正能跑的评估管线
以「帮用户写 AWS 相关代码(Python / JSON / Regex 三选一格式)」这个 prompt 为例,拆成三个函数:
run_prompt:把测试用例套进 prompt 模板、发给 Claude
def run_prompt(test_case):
"""Merges the prompt and test case input, then returns the result"""
prompt = f"""
Please solve the following task:
{test_case["task"]}
"""
messages = []
add_user_message(messages, prompt)
output = chat(messages)
return output
📌 这个示范版本的 prompt 刻意写得很简单(没加任何格式要求),所以输出会偏啰嗦——这是为了后面几节示范怎么一步步改进格式约束。
run_test_case:跑一条用例 + 打分(先用占位分数)
def run_test_case(test_case):
"""Calls run_prompt, then grades the result"""
output = run_prompt(test_case)
# TODO - Grading
score = 10
return {
"output": output,
"test_case": test_case,
"score": score
}
run_eval:把整个数据集都跑一遍
def run_eval(dataset):
"""Loads the dataset and calls run_test_case with each case"""
results = []
for test_case in dataset:
result = run_test_case(test_case)
results.append(result)
return results
执行:
with open("dataset.json", "r") as f:
dataset = json.load(f)
results = run_eval(dataset)
每条结果包含三样:Claude 的输出、原始测试用例、评分。这就是大多数 AI 评估系统的骨架——接下来只需要把占位的 score = 10 换成真正的打分逻辑。
用 Claude 自己生成测试数据集
数据集不一定要手写,可以让 Claude(建议用 Haiku 这类速度快的模型,不用动用旗舰模型)批量生成。
- 测试用例统一存成 JSON 对象,带
"task"字段 generate_dataset()函数的做法:叫 Claude"Generate an evaluation dataset for a prompt evaluation",针对 Python / JSON / Regex 三种 AWS 相关任务各生成几条- 拿到结果照样用 assistant prefill(
`json)+stop_sequences=["`"]这招解析出干净 JSON(跟 [EP01](./EP01_claude-api基础入门.md) 的 Structured Data 技巧完全一样) - 生成完存成
dataset.json,供后面步骤反复复用:
json.dump(dataset, f)
打分的三种方式
| 方式 | 怎么做 | 适合检查什么 |
|---|---|---|
| Code Grader | 写代码硬性检查 | 输出长度、有没有出现关键词、语法能不能 parse 成功(JSON/Python/Regex)、可读性 |
| Model Grader | 另外呼叫一次 Claude 当裁判 | 回答品质、有没有照指令做、完整度、有没有用、安不安全 |
| Human Grader | 真人看 | 整体品质、全面性、深度、简洁度、相关性 |
Model Grader 实作
def grade_by_model(test_case, output):
eval_prompt = """
You are an expert code reviewer. Evaluate this AI-generated solution.
Task: {task}
Solution: {solution}
Provide your evaluation as a structured JSON object with:
- "strengths": An array of 1-3 key strengths
- "weaknesses": An array of 1-3 key areas for improvement
- "reasoning": A concise explanation of your assessment
- "score": A number between 1-10
"""
messages = []
add_user_message(messages, eval_prompt)
add_assistant_message(messages, "```json")
eval_text = chat(messages, stop_sequences=["```"])
return json.loads(eval_text)
接进 run_test_case:
def run_test_case(test_case):
output = run_prompt(test_case)
model_grade = grade_by_model(test_case, output)
score = model_grade["score"]
reasoning = model_grade["reasoning"]
return {
"output": output,
"test_case": test_case,
"score": score,
"reasoning": reasoning
}
算整体平均分:
from statistics import mean
def run_eval(dataset):
results = []
for test_case in dataset:
result = run_test_case(test_case)
results.append(result)
average_score = mean([result["score"] for result in results])
print(f"Average score: {average_score}")
return results
💡 让裁判模型同时给 strengths(优点)、weaknesses(缺点)、reasoning(评分理由),不是只要一个数字——这样能避免模型偷懒,什么都打个不功不过的 6 分,逼它给出有区分度的评分。
Code Grader:检查格式跟语法
Code Grader 检查的是「格式对不对」跟「语法能不能 parse」,这两样纯属客观对错,不需要另一个模型判断:
- 格式:回答应该只有要求的代码本身(Python / JSON / Regex),不该夹带解释文字
- 语法:生成的内容要真的能被对应语言 parse 出来
def validate_json(text):
try:
json.loads(text.strip())
return 10
except json.JSONDecodeError:
return 0
def validate_python(text):
try:
ast.parse(text.strip())
return 10
except SyntaxError:
return 0
def validate_regex(text):
try:
re.compile(text.strip())
return 10
except re.error:
return 0
每个函数:能 parse 成功给 10 分,失败给 0 分。
测试用例要多带一个 "format" 字段,告诉评分函数该用哪个 validator:
{
"task": "Create a Python function to validate an AWS IAM username",
"format": "python"
}
让 prompt 配合评分标准
要拿到干净的代码输出,prompt 本身也要改得更明确:直接要求「Respond only with Python, JSON, or a plain Regex」,不要解释文字;再搭配 assistant prefill(比如 `code )引导 Claude 直接开始写代码,不写废话。
综合 Model Score 跟 Syntax Score
最终分数可以把两种评分取平均:
(model_score + syntax_score) / 2
📌 两者的权重不是固定的——比如格式正确性对你的应用更重要,就把 syntax score 权重调高,反之亦然。
常见错误
- ❌ Prompt 只手动测一两次就直接上线——用户实际输入的多样性,几乎一定会超出手测能覆盖的范围
- ❌ 只给裁判模型一个「打几分」的空格——不要求给 strengths/weaknesses/reasoning,裁判很容易懒得区分、全部打差不多的中间分数
- ❌ 生成测试数据集用了跟正式评估一样贵的旗舰模型——生成数据这种量大但不需要顶尖品质的任务,用 Haiku 这类快模型更划算
- ❌ 只做 Model Grader、不做 Code Grader(或反过来)——像「格式对不对」「语法能不能 parse」这种有绝对对错的项目,交给代码检查比交给模型判断更准、更省成本
Sources
官方文档:
- Building with the Claude API(Claude Academy 课程)— https://academy.claude.com/courses/building-with-the-claude-api