
精读 `llm_as_a_judge.py` 89 行源码,拆解双 Agent 循环架构(`story_outline_generator` + `evaluator`)、`EvaluationFeedback` dataclass 三值评分设计、`to_input_list()` 全量上下文链 + `auto_mode` 双层安全阀,并与上期 Deterministic Flows 对比(迭代改进 vs 门控硬停),最后给出三条生产级落地建议:结构化输出是循环终止前提、while 必须有代码出口 + 语义出口双保险、Judge Prompt 校准流程。
examples/agent_patterns/ 里给了 89 行的完整实现。读完之后你会发现,真正的设计精髓不是「用 LLM 当裁判」这个 idea 本身,而是它背后的循环控制策略。agent_patterns/README.md 这样描述 LLM-as-a-Judge 的价值1:"LLMs can often improve the quality of their output if given feedback. A common pattern is to generate a response using a model, and then use a second model to provide feedback. You can even use a small model for the initial generation and a larger model for the feedback, to optimize cost."
llm_as_a_judge.py 源码4 只定义了两个 Agent:story_outline_generator = Agent(
name="story_outline_generator",
instructions=(
"Generate a story outline based on the user's input."
# 无 output_type,输出纯文本大纲
),
)
evaluator = Agent(
name="evaluator",
instructions=(
"Evaluate the story outline and provide feedback. "
"Never give it a pass on the first try. "
"After 5 attempts, you can give it a pass if the story outline "
"is good enough - do not go for perfection."
),
output_type=EvaluationFeedback, # 强制结构化输出
)story_outline_generator:内容生成者,给什么反馈就改什么,没有自我评判的职责evaluator:质量裁判,通过 output_type=EvaluationFeedback 约束只能输出结构化评分,不能说废话with trace("LLM as a judge"):
input_items: list[TResponseInputItem] = [{"content": user_msg, "role": "user"}]
while True:
# Step 1: 生成
story_outline_result = await Runner.run(
story_outline_generator,
input_items,
)
# Step 2: 评分
evaluator_result = await Runner.run(
evaluator,
story_outline_result.to_input_list(),
)
result: EvaluationFeedback = evaluator_result.final_output
# Step 3: 判断退出或继续
if result.score == "pass":
break
# Step 4: 把反馈追加进 input_items,下一轮 generator 看到
input_items = story_outline_result.to_input_list() + [
{"content": f"Feedback: {result.feedback}", "role": "user"}
]@dataclass
class EvaluationFeedback:
feedback: str
score: Literal["pass", "needs_improvement", "fail"]feedback:文本说明,给 generator 看的,解释「哪里不够好、怎么改」score:机器可读的三值评分,给代码逻辑看的,决定「继续还是停止」score 用 Literal["pass", "needs_improvement", "fail"] 而不是简单的 bool,保留了「不够好但也不算差」的中间状态。这与 evaluator instructions 里的「do not go for perfection」形成呼应——不要只有「完美」和「失败」两种结果。output_type=EvaluationFeedback 参数,评审 Agent 被强制只能输出符合这个 schema 的 JSON。代码层面直接解包:result: EvaluationFeedback = evaluator_result.final_outputfinal_output 的静态类型是 Any(因为 handoffs 可能改变最终运行的 agent),但配合 output_type 参数使用时,实际类型是可预期的。生产代码里可以加一行 assert isinstance(result, EvaluationFeedback) 做运行时保护。story_outline_result.to_input_list() 拿到完整的多轮对话历史4。这个默认的 preserve_all 模式会保留所有轮次的消息记录,不裁剪历史。deterministic.py 形成对比6:deterministic 模式直接把 final_output(一个字符串)传给下一步,干净但无历史。judge 模式需要 evaluator 看到「用户原始需求 + 所有历史大纲 + 所有历史反馈」,才能做出有上下文的评分判断,所以要保留完整链路。input_items = story_outline_result.to_input_list() + [
{"content": f"Feedback: {result.feedback}", "role": "user"}
]role="user" 的新消息追加,而不是修改 agent 的 instructions。这样每轮的历史不会被覆盖,generator 的系统提示词也保持稳定。# 检测环境变量
is_auto_mode = os.getenv("EXAMPLES_INTERACTIVE_MODE") == "auto"
max_rounds = 3 if is_auto_mode else None
rounds = 0
while True:
# ...
if result.score == "pass":
break
if max_rounds is not None:
rounds += 1
if rounds >= max_rounds:
breakEXAMPLES_INTERACTIVE_MODE=auto 时,最多跑 3 轮就强制退出。这个设计让同一份代码可以在「交互模式」(人工干预、不限轮次)和「CI/自动化」(有上限、可预期成本)下无缝切换。max_rounds 就是你的成本预算。评估一轮多少钱,乘以 max_rounds,上限就在那里。"Never give it a pass on the first try."
"After 5 attempts, you can give it a pass if the story outline is good enough - do not go for perfection."
max_rounds 更软,但更符合语义意图。两者组合,才是完整的退出条件设计。| 维度 | Judge 模式 | Deterministic 模式 |
|---|---|---|
| 流程形态 | while True 迭代循环 | 线性流水线,单次通过 |
| 不通过时 | 反馈注入,generator 重试 | exit(0) 硬停止 |
| 质量判断者 | LLM(evaluator agent) | LLM(输出 bool) |
| 上下文策略 | to_input_list() 全量历史 | final_output 字符串传递 |
| 典型场景 | 内容质量需要迭代改进的任务 | 门控检查——不符合条件就整流程终止 |
EvaluationFeedback 里的 score: Literal["pass", "needs_improvement", "fail"] 是整个循环可以用代码控制的基础。如果让 evaluator 输出自然语言「这个大纲写得还不错,有一些细节可以改进」,你就没有办法写出 if result.score == "pass": break。结构化输出不是锦上添花,是循环能终止的前提条件。auto_mode 里的 max_rounds=3 是一个好起点,生产环境根据成本预算调整。当前版本:本文基于 OpenAI Agents SDK v0.17.0(2026-05-08 发布)。
下期预告 #22:agent_patterns的下一个模式——Parallelization:用asyncio.gather同时启动多个 Agent,最后由 picker agent 从并行结果中择优。比对 judge 的深度优先,parallelization 是广度优先——两种截然不同的质量策略。
github.com
zhuanlan.zhihu.com
openai.github.io
github.com
openai.github.io
github.com
github.com
cn.linkedin.com
tianpan.co
163.com
This story was produced automatically by a channel. One sentence is all it takes for Neodrop to keep producing for you.