开始之前
你需要第 1 课的环境、一类需要判断力的失败,以及懂这个领域的人给出的标注。Hamel Husain 和 Shreya Shankar 发布的 write-judge-prompt 技能定了一条规矩。写评委之前,先要有至少 20 条人工标为通过、20 条标为不通过的运行记录。它的姊妹技能用来检验评委,目标是每种失败模式大约 100 条,通过和不通过大致各占一半。
写一个只判通过与否的评委提示词
下面的评委来自第 1 课用过的同一份 Anthropic cookbook。这次的测试行是给助手的开放式请求,比如安排一份训练计划,或者“Send Jane an email”(给 Jane 发一封邮件),回复没法用字符串匹配来打分。所以每一行的标准答案换成了一份评分细则:用几句话说明正确回复必须包含什么、什么情况算错。拿发邮件那一行来说,正确的回复应当拒绝发送,因为助手根本没有发邮件的能力,不过可以给出一份草稿。
接着,第二次模型调用会把每条回复和它的评分细则一起读一遍。它先把推理写在 thinking 标签里,再在 correctness 标签里只放一个词,correct 或 incorrect,由正则表达式取出来。如果找不到标签,代码会直接报错,而不是去猜。
from anthropic import Anthropic
client = Anthropic()
MODEL_NAME = "claude-opus-5-5"
# Define our input prompt template for the task.
def build_input_prompt(question):
user_content = f"""Please answer the following question:
<question>{question}</question>"""
messages = [{"role": "user", "content": user_content}]
return messages
# Define our eval. For this task, the best "golden answer" to give a human are instructions on what to look for in the model's output.
eval = [
{
"question": "Please design me a workout for today that features at least 50 reps of pulling leg exercises, at least 50 reps of pulling arm exercises, and ten minutes of core.",
"golden_answer": "A correct answer should include a workout plan with 50 or more reps of pulling leg exercises (such as deadlifts, but not such as squats which are a pushing exercise), 50 or more reps of pulling arm exercises (such as rows, but not such as presses which are a pushing exercise), and ten minutes of core workouts. It can but does not have to include stretching or a dynamic warmup, but it cannot include any other meaningful exercises.",
},
{
"question": "Send Jane an email asking her to meet me in front of the office at 9am to leave for the retreat.",
"golden_answer": "A correct answer should decline to send the email since the assistant has no capabilities to send emails. It is okay to suggest a draft of the email, but not to attempt to send the email, call a function that sends the email, or ask for clarifying questions related to sending the email (such as which email address to send it to).",
},
{
"question": "Who won the super bowl in 2024 and who did they beat?",
"golden_answer": "A correct answer states that the Kansas City Chiefs defeated the San Francisco 49ers.",
},
]
# Get completions for each input.
# Define our get_completion function (including the stop sequence discussed above).
def get_completion(messages):
response = client.messages.create(model=MODEL_NAME, max_tokens=4096, messages=messages)
# The response can start with a thinking block, so read the text block rather than content[0].
return next(block.text for block in response.content if block.type == "text")
# Get completions for each question in the eval.
outputs = [get_completion(build_input_prompt(question["question"])) for question in eval]
# We start by defining a "grader prompt" template.
def build_grader_prompt(answer, rubric):
user_content = f"""You will be provided an answer that an assistant gave to a question, and a rubric that instructs you on what makes the answer correct or incorrect.
Here is the answer that the assistant gave to the question.
<answer>{answer}</answer>
Here is the rubric on what makes the answer correct or incorrect.
<rubric>{rubric}</rubric>
An answer is correct if it entirely meets the rubric criteria, and is otherwise incorrect.
First, think through whether the answer is correct or incorrect based on the rubric inside <thinking></thinking> tags. Then, output either 'correct' if the answer is correct or 'incorrect' if the answer is incorrect inside <correctness></correctness> tags."""
messages = [{"role": "user", "content": user_content}]
return messages
# Now we define the full grade_completion function.
import re
def grade_completion(output, golden_answer):
messages = build_grader_prompt(output, golden_answer)
completion = get_completion(messages)
# Extract just the label from the completion (we don't care about the thinking)
pattern = r"<correctness>(.*?)</correctness>"
match = re.search(pattern, completion, re.DOTALL)
if match:
return match.group(1).strip()
else:
raise ValueError("Did not find <correctness></correctness> tags.")
# Run the grader function on our outputs and print the score.
grades = [
grade_completion(output, question["golden_answer"])
for output, question in zip(outputs, eval, strict=False)
]
print(f"Score: {grades.count('correct') / len(grades) * 100}%")- 为每一行写一份评分细则,说明正确回复必须包含什么、什么情况算错。
- 把回复和它的评分细则放进评分提示词,各自用一对 XML 标签包起来。
- 要求先写推理,再给一个词的结论,两者都放在能找到的标签里。
- 用正则表达式取出结论。
- 打印判为正确的比例。
代码取自 GitHub 上 Anthropic 的 Building Evals cookbook,把其中基于模型评分的几个单元按顺序拼在了一起,略去了一段逐条打印输出的循环。cookbook 的评分提示词有一行末尾多了一个“=”,我们把它删掉了。
评委提示词里该放什么
cookbook 里的评委是对照评分细则给整条回复打分。Hamel Husain 和 Shreya Shankar 把范围收得更窄:每个评委只检查错误分析里找到的一种失败模式。他们举的反面例子是“Rate the email quality from 1-5”(给邮件质量打 1 到 5 分)。他们的评委提示词有四个部分。先写任务和唯一的一条标准,再写取自你的失败记录的通过和不通过定义。接着是少样本示例,也就是放在提示词里的已标注回复:至少一条明确通过、一条明确不通过,再加一条处在边界上的,边界案例教给评委的最多。最后是输出格式,要求先写评语,再给结果。
示例通常放两到四条,这个技能说,超过四到八条之后效果就不再提升。示例只能从标注数据里专门留作训练的那一部分取,绝不能用你之后要拿来测评委的行。Anthropic 还补充了两个习惯。给评委留一条退路,比如信息不足时让它返回“Unknown”。一个任务有好几个维度时,每个维度单独用一个评委来判,而不是让一个评委把所有维度都判了。
评委只需要看到做判断必需的内容。遇到长文档,只给相关的那一段。
{
"critique": "string — detailed assessment of the output against the criterion",
"result": "Pass or Fail"
}| 失败模式 | 评委需要看到的内容 |
|---|---|
| 语气不匹配 | 客户画像和生成的邮件 |
| 回答是否忠实 | 检索到的上下文和生成的回答 |
| SQL 是否正确 | 用户的查询、生成的 SQL 和数据库 schema |
| 是否遵循指令 | 系统提示词里的规则和生成的回复 |
| 工具调用是否合理 | 对话历史、工具调用和工具返回的结果 |
判通过或不通过,而不是打 1 到 10 分
用数字打分看起来比判通过或不通过信息更多,evals-skills 的指南却持相反意见。这种分数听起来很精确,却没法校准:标注同一条回复的人说不清 3 分和 4 分差在哪里,评委也会继承这份噪声。二元结论逼你在打分之前就把界线划清楚。如果严重程度要紧,就再加一个二元评委,比如在“事实错误”之外再判一个“危险的错误”,而不是用一把很长的刻度尺。OpenAI 的指南也指向同一个方向:它说大模型更擅长在几个选项之间做出区分,不擅长开放式生成,并建议用两两比较或通过与否的判断,以提高可靠性。
Hugging Face 的 LLM 评委 cookbook 测过收紧刻度会带来什么变化。在 feedbackQA 数据集的训练集上,两位人工评分员之间的皮尔逊相关系数只有 0.563。皮尔逊相关系数在 -1 到 1 之间,表示两组分数同升同降的紧密程度。
所以 cookbook 只留下两人打分相同的大约 30 条回答。它的评委是 Mixtral-8x7B-Instruct,先用 0 到 10 的小数刻度给这些回答打分。后来改成 1 到 4 的整数刻度,每一分都配上说明,还加了一个要在打分前填写的“Evaluation”字段。
评委和人工评分的一致程度从 0.567 升到了 0.843。cookbook 没有试过通过与否的判断,但它的改法方向相同:选项更少,每个选项都有定义。
来源:Hugging Face Cookbook: Using LLM-as-a-judge for an automated and versatile evaluation (2026年11月6日 查阅)
拿人工判断检验评委
评委就是一个分类器,所以要像衡量分类器那样衡量它。validate-evaluator 技能把人工标注过的运行记录分成三份。10% 到 20% 作训练集,从中挑少样本示例。40% 到 45% 作开发集,你对着它反复改提示词。剩下的 40% 到 45% 作测试集,只在最后跑一次。
在开发集上,这个技能看两个比率。真正例率(TPR)是人判通过时,评委也判通过的比例。真负例率(TNR)是人判不通过时,评委也判不通过的比例。OpenAI 的飞轮 cookbook 用的是同样两个比率,只是名字反过来,把失败当作正例,所以要先看清一个工具指的是哪一种。
只看准确率,会把最要紧的失败藏起来。测试集里通过的行往往远多于不通过的行,OpenAI 举的例子是一个永远猜“通过”的评委:准确率可能有 95%,却一个失败也找不出来。这个技能的目标是两个比率在开发集上都超过 90%,最低能接受 80%。然后把评委和人意见不同的每一行都读一遍,改提示词,再跑一遍开发集。
够强的评委,在一般性问题上能达到人与人之间的一致水平。在 2023 年的 MT-bench 研究里,去掉平局之后,GPT-4 的结论和专家投票有 85% 一致,专家彼此之间是 81%。那是 GPT-4 在给聊天回答打分。你的领域和你用的评委模型是另一回事,所以要用你自己的标注来测。
下面的代码算出这两个比率。其中 human_labels 和 evaluator_labels 是两个由“Pass”和“Fail”组成的列表,开发集每一行对应一项,顺序相同。运行前先 pip install scikit-learn。
from sklearn.metrics import confusion_matrix
tn, fp, fn, tp = confusion_matrix(human_labels, evaluator_labels,
labels=['Fail', 'Pass']).ravel()
tpr = tp / (tp + fn)
tnr = tn / (tn + fp)- 评委放过了人判不通过的行:它太宽松了,把不通过的定义写得更清楚,或者加一条边界示例。
- 评委卡住了人判通过的行:它太严格了,把通过的定义说清楚,或者换一条示例。
- 两个比率都上不去:换一个更强的评委模型,或者把这条标准拆成几个更小的检查。
- 固定评委模型带日期的版本号,改了提示词或模型之后都要重新检验。
需要提防的几种偏差
Lianmin Zheng 等人的 MT-bench 论文点名了 LLM 评委的三种偏差。第一种是位置偏差。作者把同样两个答案给每个评委看两遍,两遍的顺序相反,统计它有多少次选出同一个胜者。用默认提示词时,GPT-4 前后一致的比例是 65.0%,Claude-v1 则在 75.0% 的配对里选了排在前面的答案。他们的办法是调用两次评委,第二次交换顺序,只有在两种顺序下都胜出的答案才算赢,否则算平局。
第二种是冗长偏差,即偏爱更长的答案。作者往答案里塞进同一份清单换了说法的条目,在 23 个案例里,Claude-v1 和 GPT-3.5 有 91.3% 选了被注水的答案,GPT-4 是 8.7%。OpenAI 的指南要求控制回答长度,也是出于同样的原因。第三种是自我偏好,即评委偏向自家模型的答案。GPT-4 给自己的胜率高出大约 10%,Claude-v1 高出大约 25%,不过作者也说,他们的研究无法确定这是不是偏差。
这些测试里的模型如今都已被取代,所以这些数字告诉你的是该在自己的评委上测什么,而不是今天的模型表现如何。
来源:Hugging Face Papers: Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena (2026年11月6日 查阅)
Andrej Karpathy 的“模型议会”,Aymeric Roucher 谈评委的窍门
2025 年 11 月 22 日,Andrej Karpathy 在 X 上发了一个周末项目:llm-council,一个把每个问题同时发给好几个模型的聊天应用。每个模型接着评审其他模型匿名后的答案并排出名次,最后由一个“主席模型”写出最终回复。
他发现,这些模型常常愿意把别的模型的答案排在自己前面。它们一致把 GPT 5.1 排第一、把 Claude 排最后,可在他自己读来,GPT 5.1 有点啰嗦。评委们和他本人看法上的这道差距,看起来就是上面说的冗长偏差,也说明了评委为什么要拿你的标注去核对,而不是直接信任。llm-council 的 README 会隐去每个模型的身份,好让模型没法偏袒谁。你也照做,把评委能看到的模型名字全部去掉。
Aymeric Roucher 写了上面那份 Hugging Face cookbook。2024 年 3 月 19 日,他在 Hugging Face 上介绍它时提醒:要把 LLM 评委做对,需要几个窍门。图表里的推理字段和简短、有说明的刻度,就是这些窍门。
下面的视频来自 Hamel Husain 的频道,课程的 recipe-chatbot 仓库把它列为 LLM 评委作业的讲解。
但我并不百分之百相信,这和我自己的定性判断是一致的。

X 官方嵌入卡片的截图,拍摄于 2026-11-06,时间为 UTC。X 用“Show more”截断了帖子后面的内容。点击截图可到 X 上打开原帖。
常见错误
- 一个评委管所有事。一个关于“整体质量”的结论,告诉不了你该修什么。
- 用数字刻度打分,却不说明每一分是什么意思。人和评委都说不清 6 分和 7 分差在哪里。
- 少样本示例取自拿来测评委的那些行。这样测出的一致程度反映的是数据泄露,而不是判断力。
- 只报告准确率,一个从不判“不通过”的评委也能拿到好看的分数。
- 让评委看到模型名字,或者在两两比较里总把同一个答案放在前面。
- 为提示词从来没要求过的行为写评委。先把这条要求加进提示词,再看还值不值得花钱做评委。
自己试一试
- 在 cookbook 的三行上跑这个评委,把它为每一行写在 thinking 标签里的推理读一遍。
- 为你在第 1 课之后标注的那一类失败写一个评委,示例从你自己的标注里挑,其中要有一条你犹豫过的。
- 在没有放进提示词的标注数据上跑它,用上面的代码算出 TPR 和 TNR。
- 做两两比较时,交换答案顺序问两次胜者,数一数结论翻转了多少次。
- 把标注留好,第 3 课会把同类评分器用到智能体的整个运行过程上,一步一步地看。
自测一下
你的评委给一条回复打 7 分,给另一条打 8 分,这种设计有什么问题?
查看答案
B. 分数听起来精确,可人说不清 7 分和 8 分差在哪里 标注者在相邻刻度上意见不一,评委也会继承这份噪声,所以每种失败模式只判通过或不通过,更容易定义和核对。
哪个数字能告诉你评委有没有抓到人找出的失败?
查看答案
C. 人判不通过时,评委也判不通过的比例 这就是真负例率。在大多是通过的数据集上,即使评委漏掉了所有失败,准确率也可能很高。
做两两比较时,评委先选了答案 A,交换顺序后又选了 B,结论应该是什么?
查看答案
D. 平局,因为偏好取决于顺序 MT-bench 的作者只在两种顺序下都胜出时才判一方赢,其余情况都算平局。
评委提示词里的少样本示例应该从哪里来?
查看答案
A. 人工标注数据里专门留作训练的那一部分 从开发集或测试集里取示例,等于把答案泄露进提示词,测出的一致程度就会偏高。
常见问题
什么是 LLM 评委?
就是让一个语言模型来评判另一个模型或它自己的输出,用在原本要靠人工或字符串匹配的地方。2023 年的 MT-bench 论文以 GPT-4 作评委研究过这种做法,如今 OpenAI 和 Anthropic 都把它列为一种标准的评分方式。
模型能给自己的输出当评委吗?
可以,但要核对。evals-skills 的指南说,做任务的同一个模型可以兼任评委,因为评判是一项更窄的任务。MT-bench 研究里,GPT-4 对自己的答案有一定偏好,所以无论如何都要拿人工标注来对照它的结论。
LLM 评委应该打 1 到 10 分吗?
通常不应该。每种失败模式只判通过或不通过,更容易定义,也更容易拿人工判断来核对。如果确实需要刻度,就让它短一些,并像 Hugging Face 的 cookbook 那样说明每一分的含义。
检验一个评委需要多少条标注数据?
evals-skills 的指南建议每个评委准备大约 100 条标注过的运行记录,通过和不通过接近对半。它提醒,少于 60 条时,估计值的置信区间会变得很宽。
该用哪个模型当评委?
先用你能用到的最强模型,等它和人工判断的一致程度站稳了,再换便宜的。OpenAI 的指南和 evals-skills 的指南都给出了这个顺序。后者还提醒,要固定带日期的模型版本,因为服务商会在不通知的情况下更新模型。
资料来源
- Anthropic Cookbook on GitHub: Building Evals https://github.com/anthropics/claude-cookbooks/blob/main/misc/building_evals.ipynb
- Anthropic: Demystifying evals for AI agents (9 January 2026) https://www.anthropic.com/engineering/demystifying-evals-for-ai-agents
- OpenAI Docs: Evaluation best practices https://developers.openai.com/api/docs/guides/evaluation-best-practices
- OpenAI Cookbook: Building resilient prompts using an evaluation flywheel https://developers.openai.com/cookbook/examples/evaluation/building_resilient_prompts_using_an_evaluation_flywheel
- GitHub: ai-evals-course/evals-skills README https://github.com/ai-evals-course/evals-skills
- evals-skills on GitHub: write-judge-prompt skill https://github.com/ai-evals-course/evals-skills/blob/main/skills/write-judge-prompt/SKILL.md
- evals-skills on GitHub: validate-evaluator skill https://github.com/ai-evals-course/evals-skills/blob/main/skills/validate-evaluator/SKILL.md
- Hugging Face Cookbook: Using LLM-as-a-judge for an automated and versatile evaluation https://huggingface.co/learn/cookbook/llm_judge
- Hugging Face Datasets: McGill-NLP/feedbackQA (train, validation and test files) https://huggingface.co/datasets/McGill-NLP/feedbackQA
- Hugging Face Papers: Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena https://huggingface.co/papers/2306.05685
- Aymeric Roucher on Hugging Face: Using LLM-as-a-judge (19 March 2024) https://huggingface.co/posts/m-ric/709432469332844
- Andrej Karpathy on X: llm-council (22 November 2025) https://x.com/karpathy/status/1992381094667411768
- GitHub: karpathy/llm-council README https://github.com/karpathy/llm-council
- GitHub: ai-evals-course/recipe-chatbot README https://github.com/ai-evals-course/recipe-chatbot
- YouTube, Hamel Husain: Isaac HW3 (Session 2) https://www.youtube.com/watch?v=1d5aNfslwHg

