给 AI Agent 装上"裁判眼":buddyMe Eval 系统从零到落地的完整实录

admin · 2026-05-15 · architecture · eval · verification · deep-dive · JSON · LLM-as-Judge

给 AI Agent 装上"裁判眼":buddyMe Eval 系统从零到落地

给 AI Agent 装上"裁判眼"

buddyMe Eval 系统从零到落地的完整实录——Schema 设计、真实执行验证、独立上下文注入和全链路测试

作者: admin 2026-05-15 buddyMe v0.2.1

01 起因:为什么 Agent 需要评估

如果 Agent 的表现只能靠主观感觉判断,那迭代就是盲人摸象。

OpenAI 在 Evals 方法论中明确提出:Agent 的可靠性不是靠一次 prompt 写好,而是靠持续评估和迭代。 可评估的指标包括任务完成率、工具调用准确率、幻觉率、错误恢复能力、平均完成轮数、成本与延迟。

buddyMe v0.2.1 在 task pipeline、tool system、memory management 上已有成熟实现,但缺少一个关键的闭环——对自身执行结果的评估。这次更新就是补上这个缺口。

02 三个核心设计问题

在动手写代码之前,需要回答三个关键问题:

Q1
谁来评估?
问题:评估 Agent 不能和主 Agent 共享 LLM 上下文,否则评估 prompt 会污染对话历史。
解法:独立的 LLM 客户端 — _eval_client = _create_client(model_name)
│
Q2
评估什么?
问题:评估不是打一个总分了事,需要多维度评判。
解法:六维度评估 Schema,每个维度有权重、有 rubric、有 evidence。
│
Q3
怎么保证输出是 JSON?
问题:LLM 可能输出 markdown、解释文本、甚至编造字段名。
解法:三层 JSON 提取 + 结构校验 + 服务端强制重算加权分。

参考框架对比

框架核心思路buddyMe 借鉴点
OpenAI EvalsTraces + Graders + Datasets全链路 Trace 采集
DeepEvalTask Completion + Tool Correctness维度拆分 + rubric 评分
BraintrustMulti-step reasoning testing多阶段执行路径追踪
AgentHallu幻觉归因分类truthfulness 维度的评分标准

03 架构设计

⚙️
AgentMain.invoke() — 主 Agent(独立 LLM 上下文)
Memory Prefetch → TaskRunner.run() → 结果合并 → 日志记录 → Memory Sync
│ 任务执行完成,全量轨迹数据交接
▼
📦
SessionState — 执行轨迹收集
task_plan(分解步骤) · sub_results(子任务结果) · used_tools(工具调用)
written_files(生成文件) · token_in/out(资源消耗) · agent_final_output
│
▼
🔍
TaskEvalAgent.evaluate() — 独立 LLM 客户端,隔离上下文
⑴ 读取文件内容 ⑵ 真实执行验证 ⑶ 构建 eval prompt ⑷ LLM 评估 (temp=0.0) ⑸ JSON 提取 + 校验 + 重算
四个关键设计决策
  1. 隔离性:_eval_client 独立于 _client 和 _sub_client,三个客户端互不干扰
  2. 防御性:不信任 LLM 的计算——加权总分由代码强制重算
  3. 可降级:LLM 不可用时回退到规则兜底报告
  4. 可验证:评估前先真实执行生成的代码,将运行结果纳入评估依据

04 六维度评估 Schema

维度权重评估什么评分标准
task_completion0.30是否完整解决了用户需求1.0=完全满足;0.6=部分满足;0.0=方向错误
truthfulness0.20输出是否基于真实数据,无幻觉1.0=全部真实;0.4=明显编造;0.0=完全捏造
tool_accuracy0.15工具选择是否合理、参数是否正确1.0=全部精准;0.6=1-2次不当;0.0=完全错误
output_quality0.15生成文件的可读性/完整性/可运行性1.0=可直接使用;0.6=需微调;0.0=完全无效
error_recovery0.10遇到错误时的恢复能力1.0=完美恢复;0.4=尝试但失败;0.0=连锁失败
efficiency0.10步骤是否精简,无冗余1.0=无冗余;0.4=可减少30%+;0.0=效率极低

权重总和 1.00,加权分映射到等级:A >= 0.9, B >= 0.8, C >= 0.7, D >= 0.6, F < 0.6

task_completion 权重最高(0.30)——任务做没做完是第一优先级。truthfulness 排第二(0.20)——幻觉是 Agent 最致命的问题。error_recovery 和 efficiency 是锦上添花,可以后续优化。

05 严格 JSON 输出的五重保障

LLM-as-a-Judge 技术最大的痛点是输出格式不可控。我们设计了五重保障:

1
System Prompt 强约束
"你必须且只能输出一个 JSON 对象"、"不要包裹在代码块中"——9 条绝对规则
│
2
temperature = 0.0
最大程度消除 LLM 输出的随机性
│
3
三层 JSON 提取(_extract_json)
尝试 1: 直接解析 → 失败 → 尝试 2: 去 markdown 代码块 → 失败 → 尝试 3: 括号配对
│
4
结构校验与修正(_validate_and_fix)
补全缺失维度(默认 0.5)、强制 score 为 float ∈ [0,1]、强制 evidence 为 str
│
5
服务端强制重算(_compute_overall)
核心原则:不信任 LLM 的计算,只信任它的判断。
LLM 负责打分和写证据,加权总分由代码根据权重强制计算。
# 不信任 LLM 的计算——加权总分由代码强制重算
weighted_score = 0.0
for dim_name, dim_info in EVAL_DIMENSIONS.items():
    score = report.get(dim_name, {}).get("score", 0.5)
    weighted_score += score * dim_info["weight"]  # 代码计算,非 LLM 输出
grade = "A" if weighted_score >= 0.9 else ...

06 真实执行验证

评估不能只看代码"写了什么",还要看"跑起来是什么"。这是 buddyMe Eval 区别于纯 LLM-as-Judge 的核心特性。

入口文件检测(五阶段优先级)

检测入口文件 — 五阶段优先级 阶段 1: Agent 输出中提到的文件名(最可靠) ↓ 无匹配 阶段 2: 标准入口名 — main.py, app.py, run.py, start.py, manage.py... ↓ 无匹配 阶段 3: 扫描 Python 文件,检测 if __name__ == "__main__" ↓ 无匹配 阶段 4: HTML 文件 — 进入结构验证流程 ↓ 无匹配 阶段 5: Shell 脚本 — .sh 文件

执行引擎

Python
python "{path}"
捕获 stdout/stderr/exit_code
HTML
结构验证:DOCTYPE/HTML/HEAD/BODY/闭合标签
5 项检查
Shell
bash "{path}"
捕获 stdout/stderr/exit_code

所有执行都有超时保护(30 秒),超时自动 kill。验证结果被标记为"最高优先级证据",放在 eval prompt 的最前面。

07 完整执行流程图

👤
用户: "5月17日北京游览导览,生成html格式"
│
▼
⚙️
AgentMain.invoke() — 主 Agent
① Memory Prefetch ② plan_task() → 分解为 6 步 ③ 子任务执行循环 ④ 结果合并 + 日志 ⑤ Memory Sync
│ state.task_plan / sub_results / used_tools / written_files 全量交接
▼
🔍
TaskEvalAgent.evaluate() — 独立 _eval_client
⑴ _read_written_files() ⑵ _run_verification()
_detect_entry_points() — 五阶段优先级检测入口文件
_execute_file() / _validate_html() — 真实执行或结构验证
⑶ _build_eval_prompt()
Schema + rubric + ★真实执行结果(最高优先级)★ + 轨迹 + 文件内容 + 资源消耗
⑷ LLM 评估 (temp=0.0, 最多 3 次) ⑸ JSON 提取 + 校验 + 重算 ⑹ 输出报告

08 真实测试:北京游览导览

项目值
查询5月17日北京游览导览,生成html格式给我
模型deepseek (deepseek-v4-pro)
子任务模型glm-4.7 (sub_agent_code_plan)
评估模型deepseek (独立客户端)
总耗时~26 分钟

任务分解(6 步)

research 搜索天气
research 搜索景点
build HTML 骨架
build 填充内容
build 交互+响应式
verify 最终检查

工具调用统计

baidu_search × 13, write_file × 3, edit_file × 5, read_file × 4, glob × 1, invoke_skill × 3 (frontend-design)

生成文件:beijing_guide_20260517.html — 28,768 bytes / 1,041 行,故宫朱红 × 现代杂志 editorial 美学。

EvalAgent 评估报告

综合评分: 0.82 / 1.00
等级: B
任务完成度高,输出质量优秀,但执行效率因冗余步骤而降低
task_completion  ;█████████░ 0.9 — 核心需求全部满足
tool_accuracy    ;███████░░░ 0.7 — 多次重复搜索
truthfulness    ;█████████░ 0.9 — 基于真实数据
error_recovery  ;████████░░ 0.8 — 验证阶段成功恢复
efficiency      ;█████░░░░░ 0.5 — 冗余搜索、重写文件
output_quality  ;█████████░ 0.9 — 结构完整、交互齐全
真实执行验证: PASS
HTML结构验证(5/5): DOCTYPE=Y HTML=Y HEAD=Y BODY=Y 闭合=Y
改进建议:
1. 减少重复搜索,首次搜索后直接使用结果
2. 避免编辑阶段重写整个文件,应使用增量编辑

09 代码改动清单

文件改动说明
agent_moudle/verify.py新建 ~975 行评估引擎(Schema + 真实执行验证 + JSON 提取 + 格式化)
session/state.py+4 行新增 task_plan、sub_results 字段
agent_moudle/task_runner.py+2 行写入 state.task_plan 和 state.sub_results
agent_moudle/agent.py+28 行新增 _eval_client + _evaluator,invoke() 中集成评估
initspace/brain/AGENT.md+45 行新增第 7 节「任务交付与评估」

10 踩坑记录

坑 1 — 上下文污染
最初复用 _sub_client 做评估,发现评估 prompt 影响子任务后续调用。
解法:_eval_client = _create_client(model_name),完全独立的客户端实例。
坑 2 — 执行轨迹断层
plans 和 sub_results 是 TaskRunner.run() 的局部变量,invoke() 拿不到。
解法:在 SessionState 新增 task_plan 和 sub_results 字段。
坑 3 — LLM 不按格式输出
即使 System Prompt 要求"只输出 JSON",LLM 仍可能包裹 markdown。
解法:三层提取——直接解析 → markdown 去包 → 括号配对。成功率从 ~60% → ~95%。
坑 4 — LLM 计算错误
LLM 在计算加权总分时经常算错(连乘连加)。
解法:完全不让 LLM 算。_compute_overall() 由代码强制计算。

11 后续规划

短期
Baseline 追踪(同一批样本对比分数变化)
失败案例转 instruction(guardrails)
HTML 截图验证(无头浏览器)
中期
Constrained decoding(token 层面保证 JSON)
多模型交叉评估(减少单模型偏见)
人工介入率追踪
长期
自动 prompt 优化(评估反馈闭环)
回归测试集(持续评估)
A/B 测试框架(策略/模型对比)
一句话引用:从三个核心设计问题出发,设计六维度评估 Schema、五重 JSON 输出保障、真实执行验证引擎。以树状流程图展示完整数据流,并以真实测试(北京游览导览 HTML 生成)验证全链路评估效果。