资讯动态

Agno Eval Suite 评测套件实战指南:多 Case 聚合、标签筛选、JSON 报告与 CI 退出码

发布时间:2026/9/10 1:57:42 来源:尧图企业网站定制
Agno Eval Suite 评测套件实战指南多 Case 聚合、标签筛选、JSON 报告与 CI 退出码【免费下载链接】agnoBuild, run, and manage agent platforms.项目地址: https://gitcode.com/GitHub_Trending/ag/agno本篇技术指南以 Agno 官方 Cookbook 中的 Eval Suite Cookbooks 为核心系统讲解如何将多个评测用例Case聚合为一个评测套件Suite运行。你将掌握通过内置cli()一键跑全量或按标签/名称筛选的评测、为每个 Case 配置独立超时与 Tag、输出结构化 JSON 报告并读取 CI 退出码以及面向 CI 工作流和嵌入式场景的程序化调用方式run_cases/arun_casesSuiteResult.to_dict()并深入理解其底层实现。一、什么是 Eval Suite在 Agno 的评测体系中单个Case描述一个输入喂给一个 Agent 或 Team加上若干可选的检查项。Eval Suite 则是把这些 Case 组织起来作为一次聚合的评测套件统一运行并提供四个关键能力Tag 选择按标签如smoke筛选要运行的 Case 子集每 Case 超时为每个 Case 独立设置超时上限防止单个用例无限期挂起拖垮整条流水线JSON 报告将汇总结果与逐 Case 明细导出为机器可读的 JSONCI 退出码通过进程退出码区分全部通过 / 存在失败 / 未选中任何用例可直接对接 CI 门禁。该目录位于 cookbook/09_evals/suite属于 Agno Evals Cookbook 的组成部分与accuracy准确性、agent_as_judgeLLM 裁判、reliability工具调用可靠性、performance性能基准等目录并列参见 cookbook/09_evals/README.md。套件运行器的核心实现位于 libs/agno/agno/eval/suite.py是本文所有行为描述的事实依据。二、目录文件总览该目录包含两个可直接运行的示例脚本文件说明suite_basic.py两个 Casejudge 判定 reliability 可靠性检查通过内置的cli()运行被测试对象是单个 Agentsuite_team_scoring.py一个 Team 通过套件运行leader 委派给 calculator 成员和 writer 成员reliability 检查能看到成员的真实工具调用每个答案由 1-10 数值型 judge 打分两者都从agno.eval导入Case与cli其余导入分别对应 Agent 与 Team 场景suite_basic.pyfrom agno.eval import Case, clisuite_team_scoring.pyfrom agno.eval import Case, JudgeMode, cli三、标准用法内置 CLI两个示例脚本的if __name__ __main__分支都以sys.exit(cli(CASES))结束即把命令行解析、运行、渲染与退出码全部交给内置 CLI。以下命令可直接从仓库根目录执行python cookbook/09_evals/suite/suite_basic.py # 运行全部 cases python cookbook/09_evals/suite/suite_basic.py --list # 仅列出 cases不运行 python cookbook/09_evals/suite/suite_basic.py --tag smoke # 只运行带 smoke 标签的子集 python cookbook/09_evals/suite/suite_basic.py --name factorial_uses_calculator # 只运行指定名称的 case python cookbook/09_evals/suite/suite_basic.py --json-output tmp/evals.json # 导出 JSON 报告 python cookbook/09_evals/suite/suite_basic.py -v # 每个 case 渲染完整运行面板命令行的完整参数由 suite.py 中的argparse定义参数默认值作用--nameNone只运行指定名称的 Case--tagNone只运行带该标签的 Case--timeout套件默认default_timeout120 秒默认的每 Case 超时秒Case 自身设置了timeout_seconds时以 Case 为准--json-outputNone将机器可读的 JSON 结果写入指定路径--listFalse只列出被选中的 Case不运行-v/--verboseFalse每个 Case 结束后渲染完整运行面板Message、Tool Calls、Response3.1 退出码约定CI 门禁依据cli()返回的退出码由 suite.py 决定是 CI 判断的关键契约0所有选中的 Case 全部通过1存在任何失败包括--json-output写入失败2没有 Case 匹配选择器例如标签拼写错误、名称不存在。特别注意一个防御性设计空套件也算失败。在 SuiteResult.status 的实现中status在没有结果时直接返回FAIL——原因在于 CI 门禁通常比较 PASS一个拼错标签的空套件绝不能什么都没运行却绿灯放行。这也正是--tag打错时进程以 2 退出的原因CLI 会打印no cases selected并列出所有可用 Case 名称。四、示例一suite_basic.py单 Agent 双检查suite_basic.py 是套件的最小完整示例展示了两种检查类型的组合import sys from agno.agent import Agent from agno.eval import Case, cli from agno.models.openai import OpenAIResponses from agno.tools.calculator import CalculatorTools # 1. 创建被测 Agent agent Agent( idmath-tutor, modelOpenAIResponses(idgpt-5.5), tools[CalculatorTools()], instructionsUse the calculator tools for any arithmetic., ) # 2. 声明 Cases CASES ( Case( namefactorial_uses_calculator, agentagent, inputWhat is 10! (ten factorial)?, tags(smoke,), criteriaStates that 10! equals 3628800., expected_tool_calls(factorial,), ), Case( nameexplains_compound_interest, agentagent, inputExplain compound interest in one short paragraph., criteriaExplains that interest is earned on both the principal and previously earned interest., ), ) # 3. 运行套件 if __name__ __main__: sys.exit(cli(CASES))两个 Case 各侧重一种检查factorial_uses_calculator同时启用judge 检查criteria判定回答内容是否正确陈述 10! 3628800与reliability 检查expected_tool_calls(factorial,)要求运行期间真实调用过factorial工具并打了smoke标签explains_compound_interest仅启用 judge 检查criteria要求解释利息同时基于本金和已赚利息产生无标签。五、示例二suite_team_scoring.pyTeam 数值裁判suite_team_scoring.py 将套件能力延伸到 Team 场景并引入JudgeMode.NUMERIC数值评分import sys from agno.agent import Agent from agno.eval import Case, JudgeMode, cli from agno.models.openai import OpenAIResponses from agno.team.team import Team from agno.tools.calculator import CalculatorTools # 1. 创建 Team 及其成员 calculator Agent( idcalculator, modelOpenAIResponses(idgpt-5.5), tools[CalculatorTools()], instructionsUse the calculator tools for every arithmetic operation. Never compute arithmetic yourself., ) writer Agent( idwriter, modelOpenAIResponses(idgpt-5.5), instructionsAnswer in one clear paragraph., ) assistant_team Team( idassistant-team, modelOpenAIResponses(idgpt-5.5), members[calculator, writer], instructionsDelegate arithmetic to the calculator member and writing to the writer member, then report the members result., ) # 2. 声明 Cases——均针对 Team CASES ( Case( nameteam_uses_calculator, teamassistant_team, inputWhat is 4891 multiplied by 7238?, tags(smoke,), criteriaStates that the product is 35,401,058., judge_modeJudgeMode.NUMERIC, judge_threshold7, expected_tool_calls(multiply,), ), Case( nameteam_explains_clearly, teamassistant_team, inputExplain compound interest in one paragraph., criteriaExplains that interest is earned on both the principal and previously earned interest., judge_modeJudgeMode.NUMERIC, judge_threshold7, ), ) # 3. 运行套件 if __name__ __main__: sys.exit(cli(CASES))该示例与示例一的关键差异被测对象是 Team 而非 AgentCase(teamassistant_team, ...)传入的是Team实例leader 会把算术任务委派给 calculator 成员、把写作任务委派给 writer 成员reliability 检查深入到成员层级expected_tool_calls(multiply,)校验的是成员真正执行的multiply工具调用而不是 leader 的delegate_task_to_member委派调用每个回答都由数值裁判打分judge_modeJudgeMode.NUMERIC让裁判输出 1-10 的分数judge_threshold7为及格线分数 ≥ 7 判 PASS。5.1 JudgeMode 与阈值语义JudgeMode定义在 suite.py是一个 str 枚举JudgeMode.BINARY默认裁判给出 pass/fail 二元判定JudgeMode.NUMERIC裁判给出 1-10 分数judge_threshold默认 7作为及格线分数达到阈值才判 PASS。需要说明的是Case 中的judge_threshold会被透传给AgentAsJudgeEval的threshold字段见 suite.py最终由 agent_as_judge.py 中的数值评分指令执行——分数 1-2 为完全不符、5-6 为部分成功但有明显问题、9-10 为完全符合或超出标准。Case 构造时会校验judge_threshold必须在 1-10 之间见 suite.py越界直接抛ValueError。六、Case 字段与构造校验Case是一个frozen dataclass见 suite.py完整字段如下字段默认值含义name必填Case 名称用于--name筛选与报告标识input必填喂给 Agent/Team 的输入文本agent/teamNone被测对象二选一必填tags()标签元组用于--tag筛选timeout_secondsNone每 Case 独立超时秒未设置时回退到套件级default_timeout120 秒criteriaNone设置后启用 judge 检查AgentAsJudgeEvaljudge_modelNone每 Case 的裁判模型覆盖未设置时回退到套件级judge_model再回退到AgentAsJudgeEval默认模型judge_modeBINARY裁判评分模式judge_threshold7数值模式及格线1-10仅在NUMERIC模式下生效expected_tool_callsNone设置后启用 reliability 检查ReliabilityEvalallow_additional_tool_callsTrue宽松模式允许出现预期之外的工具调用子集匹配setup/teardownNone生命周期钩子setup在运行前执行超时计时之外其返回值作为context传给teardownteardown在 setup 完成后无论通过/失败/出错/超时都会执行并接收(context, result)以便检查result.error/result.timed_outscorer/expectedNone进程内 scorer 检查agno.scorer 协议运行在 Case 超时之内仅对可评分的运行执行Case在构造时__post_init__会做三类校验见 suite.pyagent/team 互斥两者都不传或都传都会抛ValueError必须存在至少一种检查criteria、expected_tool_calls、scorer三者全空时抛错。这里用的是真值判断而非is None因此criteria或expected_tool_calls()这类空检查也会被拒绝——防止构造出绿色通过但什么都没验证的假 CI 门禁judge_mode 合法性未知模式直接抛错NUMERIC模式下judge_threshold超出 1-10 抛错。七、程序化调用run_cases / arun_cases除命令行外套件运行器还暴露了两个面向程序化调用的 APICI 工作流、嵌入式场景关键特性是runner 本身不做任何控制台 I/O——所有展示都通过on_case_start/on_run_event/on_case_end三个钩子完成见 suite.pycli()本身也只是这些公开 API 的一个消费者。from agno.eval import run_cases, arun_cases # 同步版本 suite run_cases(CASES) # 整个套件运行在单个事件循环上 payload suite.to_dict() # 机器可读结果CI 直接消费 # 异步版本用于已运行事件循环的场景 suite await arun_cases(CASES)run_cases/arun_cases的完整签名见 suite.py支持与 CLI 对齐的筛选与定制参数默认值含义cases必填待筛选的 Case 序列tag/nameNone按标签/名称筛选default_timeout120每 Case 默认超时秒Case.timeout_seconds优先judge_modelNone套件级默认裁判模型Case.judge_model优先dbNone透传给AgentAsJudgeEval/ReliabilityEval用于把评测结果写入存储on_case_start/on_case_end/on_run_eventNone展示钩子分别在每个 Case 运行前、结束后以及每个流式运行事件时回调钩子还有两条实现细节值得注意展示钩子必须是同步可调用对象直接在事件循环上内联执行传入异步钩子会被检测并以TypeError拒绝见 suite.py。而setup/teardown则相反同步可调用对象通过asyncio.to_thread执行、异步可调用对象被直接await套件运行被取消如服务端 cancel、或 agno 将 KeyboardInterrupt 转换成的取消时会中止后续 Case未运行的 Case 以skippedTrue和errorskipped: suite aborted after cancelled run的形式补进结果列表见 suite.py保证报告与to_dict()的 Case 数量始终一致。7.1 SuiteResult 与 to_dict() 载荷SuiteResult聚合了每个 Case 的结果其to_dict()输出是一个对 CI 消费者稳定的契约见 suite.py顶层结构为{ summary: { total: 2, passed: 2, failed: 0, status: PASS }, cases: [ { name: factorial_uses_calculator, agent_id: math-tutor, team_id: null, tags: [smoke], session_id: eval-factorial_uses_calculator-1a2b3c4d, duration_seconds: 4.213, judge_passed: true, judge_reason: The output states that 10! equals 3628800., judge_score: null, reliability_passed: true, output: 10! is 3628800., tools_called: [factorial], timed_out: false, skipped: false, passed: true, error: null, score_value: null, score_passed: null, score_reason: null } ] }各字段语义CaseResult定义见 suite.pyagent_id / team_id拆分记录被测对象——Agent Case 记agent_id、Team Case 记team_id另一个保持null这也是为什么 TEST_LOG 中 team 用例的载荷是team_id: assistant-team、agent_id: nullsession_id每个 Case 独享的评测会话格式eval-{case_name}-{8位随机hex}设置db时用它把 Case 关联到存储的会话/轨迹被跳过的 Case 为空字符串judge_passed / judge_reason / judge_score裁判结论。judge_score仅在数值模式下有值1-10二元模式下为null——保留原始分数是为了在纯 pass/fail 之外还能追踪质量漂移reliability_passedreliability 检查结论未配置时为nulltools_called运行期间按顺序触发的工具名Team 场景会深入一层收集成员的调用见下文timed_out / skipped / error超时、被跳过标记与错误信息运行错误、裁判错误、清理错误以;拼接score_value / score_passed / score_reason进程内 scorer 的结论未配置 scorer 时三者均为null自 2.8.0 起追加纯增量字段不破坏既有 CI 消费者。注意原始运行输出对象RunOutput/TeamRunOutput存放在CaseResult.response中不包含在to_dict()里以便程序化调用方通过result.response获取完整的内容、工具调用与指标。八、源码级原理Case 的执行流水线理解套件行为的关键在于_arun_case与_run_case_body见 suite.py组成的执行流水线结果初始化为每个 Case 生成专属session_id并用time.perf_counter()开始计时避免评测流量污染 Agent/Team 自身的会话历史setup 钩子在超时计时之外执行asyncio.wait_for包裹的是_run_case_body而非 setup失败时该 Case 直接记录错误流式运行通过runner.arun(input..., streamTrue, stream_eventsTrue, yield_run_outputTrue)消费事件流。RunOutput/TeamRunOutput在流中捕获并立即提交响应与证据字段——即使流在最终输出后卡住如持久化或用户清理挂起超时也不会丢弃已经产出的结果运行错误则通过错误事件记录而不是抛出异常见 suite.py可评分性判定只有无组件错误、存在响应、且RunStatus.completed的运行才进入评分。暂停/取消的运行携带占位内容如 HITL 样板不能作为真实答案参与评分见 suite.pyjudge 检查设置criteria时构造AgentAsJudgeEvalshow_spinnerFalse、telemetryFalse保持套件静默把judge_mode直接透传为scoring_strategy见 suite.pyreliability 检查设置expected_tool_calls时构造ReliabilityEval。Agent Case 传agent_responseTeam Case 传team_response——这一点至关重要如果 Team 场景错误地走agent_responsereliability 只会看到 leader 的顶层消息即delegate_task_to_member委派调用而看不到成员的真正工具调用见 suite.pyscorer 检查设置scorer时在同一超时窗口内执行scorer.ascore(response, case.expected)Team Case 的response是TeamRunOutput因此针对 Agent 内容编写的 scorer 看到的是 leader 的综合结果见 suite.pyteardown 钩子在finally中执行超时/出错也照常运行——超时前可能已有变更落盘清理失败必须在载荷中可见而非只在控制台出现见 suite.py汇总CaseResult.passed为所有已配置检查judge、reliability、scorer的与运算见 suite.py有 error 直接判失败SuiteResult.status仅在全部通过时为PASS。8.1 Team 场景的可靠性检查如何看到成员调用这是 Team 评测中最容易踩坑的机制。在 reliability.py 的_evaluate中Team 场景通过_collect_member_evidence见 reliability.py递归收集所有嵌套层级的成员响应包括每个成员的tools执行记录与消息。这样expected_tool_calls(multiply,)才能命中 calculator 成员真正执行的multiply调用而不是 leader 的委派调用。TEST_LOG 的实测载荷印证了这一点tools_called: [delegate_task_to_member, multiply]——reliability 同时看到了委派动作和成员的真实工具。另外reliability 判定以执行记录executions而非请求记录为准一个期望的工具只有在存在干净执行无tool_call_error、非is_paused时才计入通过被拒绝/出错/参数非法的调用会以requested but refused/errored的形式出现在missing_tool_calls中并标注原因保证红色的 CI 门禁能一眼看出是评测错了还是 Agent 错了见 reliability.py。九、验证结果与已知行为TEST_LOG仓库附带的 cookbook/09_evals/suite/TEST_LOG.md 记录了这两个示例的实测验证结果可作为行为预期的参考suite_basic.pyPASS。两个 Casejudge reliability 组合、纯 judge全部通过退出码 0--list、全量运行加--json-output均验证通过JSON 载荷形状符合预期tools_called: [factorial]、status: PASS未知--tag以退出码 2 结束并列出了可用 Case 名称suite_team_scoring.pyPASS。两个针对 Team 的 Case 全部通过退出码 0--list、--list --json-output、--tag smoke、--name、全量加--json-output以及程序化run_cases/arun_cases入口均被覆盖验证载荷中team_id: assistant-team、agent_id: null算术 Case 的tools_called包含delegate_task_to_member与multiply两个 Case 的judge_score均为 10。十、实践建议结合源码与示例这里给出几个落地建议把套件写成一个独立入口文件参考两个示例的写法在__main__中sys.exit(cli(CASES))让 Python 退出码直接成为 CI 结果若你的流程里已有一个运行中的事件循环服务端、notebook改用await acli(CASES)避免嵌套asyncio.run为冒烟/全量分流打 Tag把核心快速用例打上smoke标签日常 CI 跑--tag smoke夜间或发版前跑全量--list可先确认筛选结果给 Case 设置合理超时通过Case.timeout_seconds为昂贵用例单独设限套件级--timeout兜底避免单个用例拖垮整条流水线Team 场景务必传team字段既保证agent_id/team_id在报告中的正确归属也保证 reliability 能通过team_response收集到成员层级的真实工具调用数值裁判适合质量追踪JudgeMode.NUMERICjudge_threshold不仅给出 pass/fail还能通过judge_score观察质量随迭代的漂移空检查是陷阱criteria或expected_tool_calls()会在构造期被拒绝撰写 Case 时确保每个检查都有实质内容否则会出现绿色但无意义的假门禁。至此你可以基于 suite_basic.py 与 suite_team_scoring.py 两个模板结合 suite.py 的实现细节为自己的 Agent / Team 搭建可筛选、可超时、可出报告、可接 CI 的聚合评测套件。【免费下载链接】agnoBuild, run, and manage agent platforms.项目地址: https://gitcode.com/GitHub_Trending/ag/agno创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价