恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
基于MCP协议自动合成智能体评测用例:从工具Schema到可执行测试
首页
资讯中心
/
基于MCP协议自动合成智能体评测用例:从工具Schema到可执行测试
基于MCP协议自动合成智能体评测用例:从工具Schema到可执行测试
发布时间:2026/9/2 6:12:32
智能体评测一直是个容易被低估的问题。功能 demo 可以手工编写几条 Prompt 验证但当智能体需要调用几十个外部工具时评测集的质量会直接决定迭代方向是否正确。Agent Seer 提出的思路是借助 MCPModel Context Protocol模型上下文协议中已经结构化的工具描述、输入输出 Schema自动合成智能体评测任务而不是靠人工一条一条写题。一旦把工具能力变成可解析的契约评测样本的生成、断言逻辑和覆盖率统计就可以从“写题”变成“程序化生产”。下面的内容会从 MCP 规范可评测量入手拆解一条从工具 Schema 到评测用例的合成链路并给出一个能跑通的最小生成器。读完后你可以把同一套思路应用到自己项目的工具评测、Agent 回归测试和接口能力验证中。1. 为什么智能体评测不能只靠手工写题传统大模型评测集通常由标注人员编写问题、标准答案再用准确率或相似度打分。到了智能体场景执行动作、工具调用、结果解析、多轮上下文全部成为评测对象评测的复杂度从“一题一答案”变成“一题一条执行链路”。如果还靠人工手工写题很快会遇到三方面问题。1.1 手工评测集的三个问题第一个问题是覆盖面受限。人工最容易写正常路径而边界情况比如参数缺省、日期格式非法、多个相似工具竞争、工具调用顺序颠倒往往只有线上出问题后才想起来补题。等想起来补的时候原始 Prompt 和上下文可能已经很难还原。第二个问题是维护成本高。一个 MCP 工具升级了inputSchema新增一个必填参数原有的评测题就可能失效。如果没有自动同步机制评测集就会慢慢变成“能跑但测不准”的存量资产。工具越多这种失效越隐蔽。第三个问题是结果主观。智能体回答“北京今天天气不错”和调用工具返回温度再整理出的答案在语义上可能相似但评测目标完全不同。如果标准答案里没有写明预期工具、预期参数、返回结构约束评分就容易被模型话术带偏。这三个问题叠加在一起会让评测集变成团队里最不敢改、又最需要改的部分。工具升级后旧题还在跑老流程新能力没有样例覆盖最后只能靠线上反馈倒逼补题。1.2 MCP 规范为什么适合做评测生成依据MCP 的价值在于把工具能力变成了机器可读的契约。MCP Server 暴露工具时会携带工具名、描述、inputSchema、outputSchema等元数据。这些元数据原本用于让模型知道“有哪些工具、怎么调用”但同样的信息也可以反过来用于“生成评测任务、判断调用是否符合预期”。举个例子。假设工具get_weather的描述是“根据城市和日期查询天气”inputSchema明确city是 string、date是 string且两个字段都必填。根据这段描述生成器可以自动构造用户任务“北京在 2025-04-01 的天气怎么样”同时生成一条预期智能体应该调用get_weather参数city北京、date2025-04-01。这个过程不需要人工写题只需要人工审核生成结果。可以说MCP 让评测合成从“基于语义猜测”变成了“基于契约推导”。只要 Schema 足够规范评测生成器就能稳定产出可校验的用例。2. MCP 规范里的可评测要素开始搭建生成器之前先要把 MCP 规范中可以作为评测信号的字段梳理清楚。这里不展开完整规范只把和智能体评测直接相关的部分整理出来。2.1 tool、resource、prompt 分别能提供什么MCP Server 主要暴露tools、resources、prompts三类能力。tools是可执行动作resources是被读取的数据访问入口prompts是预设任务模板。对评测来说三类信息各有价值。MCP 元素可评测的意义示例评测信号tool.name工具唯一标识断言智能体是否调用了正确工具tool.description功能语义说明生成用户问题、判断工具选择是否合理inputSchema参数名、类型、必填、枚举、格式构造合法输入、非法输入、边界输入outputSchema返回结构约束判断 Agent 是否正确解析返回结果resources数据访问入口生成需要先读取数据再回答的任务prompts预设任务模板把模板直接改写成评测任务annotations只读性、破坏性提示设计权限、敏感操作类安全评测如果只做最小版本优先关注tool.name、tool.description、inputSchema、outputSchema就够了。其他信息可以作为后续扩展。2.2 inputSchema 和 outputSchema 是生成器的核心输入inputSchema告诉生成器参数结构、必填项、类型、枚举值、格式约束。有了它才能生成合法输入和非法输入。outputSchema告诉评测器返回结构应该满足什么约束比如必须有condition字段、temperature必须是 number。有了它才能判断 Agent 是否真的按协议消费了返回结果而不是只生成了一段看起来合理的文字。下面是一个 MCP 工具定义的简化示例。{ name: get_weather, description: 根据城市和日期查询天气信息, inputSchema: { type: object, properties: { city: { type: string, description: 城市名称例如北京 }, date: { type: string, format: date, description: 查询日期格式 YYYY-MM-DD } }, required: [city, date] }, outputSchema: { type: object, properties: { temperature: { type: number }, condition: { type: string } }, required: [condition] } }这里最关键的是required数组和properties里的type。生成器必须先读required保证必填参数一定出现再根据type生成对应类型的值。否则很容易出现“任务生成成功但 Agent 调用工具时参数通不过校验”的情况。注意不同 MCP SDK 版本里的字段命名可能不同有的实现会把inputSchema写成schema或parameters。落地前先确认当前使用的 SDK 和规范版本不要假定所有 MCP Server 都返回同一种结构。3. Agent Seer 的评测合成链路设计有了 MCP Schema 之后怎么把它变成可执行的评测建议把流程拆成一条清晰链路每一个环节只负责一件事。3.1 整体链路合成链路可以分成七步解析 MCP Schema把工具列表统一成内部ToolSpec结构。规范化工具描述补全缺失的语义信息。根据工具描述和参数结构生成用户任务模板。根据inputSchema构造合法输入样例和非法输入样例。生成预期行为约束包括预期工具、预期参数、禁止调用工具。生成评测脚本或 JSON 评测用例。运行智能体收集轨迹执行断言并产出报告。这七步可以全部自动化但每步都需要人工审核入口。尤其是第 3 步生成的任务描述和第 5 步生成的预期行为直接影响评测质量。3.2 核心模块与数据流在 Agent Seer 的设计中核心模块可以拆成五个部分。模块输入输出关键点SchemaParserMCP Server 返回的 JSON Schema 列表统一格式的 ToolSpec 列表兼容 $ref、anyOf、allOf、oneOfTaskGeneratorToolSpec、业务域规则TaskTemplate 列表从 description 提取用户意图CaseBuilderTaskTemplate、输入样例策略TestCase 列表组合必填、可选、非法参数Verifier智能体轨迹、预期约束通过、失败、警告规则断言优先LLM 辅助RunnerTestCase、工具 Mock评测报告隔离外部依赖保证可重复这里最容易出错的是 SchemaParser。真实 MCP Server 返回的 Schema 不一定都是简单对象可能包含$ref引用、anyOf联合类型、嵌套对象、正则pattern。如果解析器没有做规范化后续生成的值就会偏离约束。3.3 从工具描述到评测用例的映射示例下面是一条从工具描述到评测用例的映射过程。工具是get_weather内部结构如下{ toolSpec: { name: get_weather, description: 根据城市和日期查询天气 }, taskTemplate: 查询{city}在{date}的天气, inputSamples: [ { city: 北京, date: 2025-04-01 }, { city: 上海, date: 2025-04-01 } ], expected: { tool: get_weather, params: { city: 北京, date: 2025-04-01 } }, testCase: { id: get_weather-001, userTask: 北京4月1日天气怎么样, assertions: [ agent_should_call_tool, agent_should_not_call_irrelevant_tool, agent_should_return_parseable_result ] } }用户任务可以由模板生成也可以由大模型基于工具描述改写。预期参数必须和输入样例严格对齐否则评测会测出“模型调了工具但参数和用户意图无关”这类问题。4. 最小实现从 MCP 描述自动生成评测任务下面用一个最小示例说明完整链路。目标不是做一个生产级评测平台而是把“Schema 解析 - 参数生成 - 任务生成 - 用例输出”跑通。4.1 准备一份可解析的 MCP 工具清单建议目录结构如下agent-seer-demo/ ├── mcp_tools.json └── generate_cases.pymcp_tools.json模拟 MCP Server 导出结果。如果你已经连接了真实 MCP Server可以通过客户端获取工具列表后导出成类似 JSON也可以先手工整理。{ servers: [ { name: weather_server, tools: [ { name: get_weather, description: 根据城市和日期查询天气信息, inputSchema: { type: object, properties: { city: { type: string, description: 城市名称例如北京 }, date: { type: string, format: date, description: 查询日期格式 YYYY-MM-DD } }, required: [city, date] } } ] } ] }这个示例只覆盖最基础的场景。真实项目里还需要处理enum、pattern、minimum、maximum、$ref等 JSON Schema 关键字否则生成出的参数可能过不了校验。4.2 生成器代码使用 Python 标准库即可不需要引入第三方依赖。下面代码会解析工具清单为每个工具生成limit条评测用例并输出到 JSONL 文件。import argparse import json import random from pathlib import Path from typing import Any, Dict, List CITY_SAMPLES [北京, 上海, 广州, 深圳, 杭州] DATE_SAMPLES [2025-04-01, 2025-05-06, 2025-06-15] def generate_value(prop: Dict[str, Any], required: bool) - Any: if not required and random.random() 0.3: return None if enum in prop: return random.choice(prop[enum]) prop_type prop.get(type) if prop_type string: if prop.get(format) date: return random.choice(DATE_SAMPLES) examples prop.get(examples) if examples: return random.choice(examples) return random.choice(CITY_SAMPLES) if prop_type integer: return random.randint(1, 100) if prop_type number: return random.randint(1, 100) 0.5 if prop_type boolean: return random.choice([True, False]) if prop_type array: return [] if prop_type object: return {} return None def build_input(tool: Dict[str, Any]) - Dict[str, Any]: schema tool.get(inputSchema, {}) properties schema.get(properties, {}) required set(schema.get(required, [])) result {} for name, prop in properties.items(): value generate_value(prop, name in required) if value is not None: result[name] value for name in required: if name not in result: result[name] None return result def build_task(tool: Dict[str, Any], params: Dict[str, Any]) - str: name tool.get(name, ).replace(_, ) desc tool.get(description, ) param_text .join([f{k}{v} for k, v in params.items()]) return f请调用 {name} 工具{desc}。参数{param_text}。请先说明你的计划再执行。 def build_case(tool: Dict[str, Any], idx: int) - Dict[str, Any]: params build_input(tool) return { id: f{tool.get(name)}-{idx:03d}, tool: tool.get(name), userTask: build_task(tool, params), expected: { tool: tool.get(name), params: params, }, assertions: [ agent_should_call_tool, agent_should_not_call_irrelevant_tool, agent_should_return_parseable_result, ], } def load_tools(path: Path) - List[Dict[str, Any]]: data json.loads(path.read_text(encodingutf-8)) tools [] for server in data.get(servers, []): tools.extend(server.get(tools, [])) return tools def main() - None: parser argparse.ArgumentParser() parser.add_argument(--input, requiredTrue, helpMCP 工具清单 JSON 文件) parser.add_argument(--output, requiredTrue, help输出 JSONL 文件路径) parser.add_argument(--limit, typeint, default5, help每个工具生成多少条用例) args parser.parse_args() random.seed(42) tools load_tools(Path(args.input)) cases [] for tool in tools: for idx in range(1, args.limit 1): cases.append(build_case(tool, idx)) Path(args.output).write_text( \n.join(json.dumps(case, ensure_asciiFalse) for case in cases), encodingutf-8, ) print(fgenerated {len(cases)} cases - {args.output}) if __name__ __main__: main()代码里有两个关键点。第一build_input会读取required数组保证必填参数一定出现同时给可选参数一定概率填充None。这是为了后续扩展“缺参”场景但真实生产环境建议用 JSON Schema validator 再次校验。第二build_task把工具名和参数拼进用户任务。这种模板在最小示例里够用但生成出的任务会比较机械。真正要让评测集自然可以改用大模型基于tool.description做改写或者准备更丰富的任务模板池。4.3 运行命令与输出在目录下执行python generate_cases.py --input mcp_tools.json --output cases.jsonl --limit 5预期输出是 5 条 JSONL。每条结构类似{id: get_weather-001, tool: get_weather, userTask: 请调用 get weather 工具根据城市和日期查询天气信息。参数city北京date2025-05-06。请先说明你的计划再执行。, expected: {tool: get_weather, params: {city: 北京, date: 2025-05-06}}, assertions: [agent_should_call_tool, agent_should_not_call_irrelevant_tool, agent_should_return_parseable_result]}到这里一条最基础的“从 MCP Schema 到评测用例”链路就跑通了。接下来需要处理的是如何让用例更逼近真实用户场景。5. 关键细节与参数设计自动生成评测用例难点不在生成而在生成出来的用例是否有区分度。下面几个设计点会直接影响评测质量。5.1 合成输入样例的常见策略生成输入值时不能只用一个固定样例否则评测集只会测到“工具调用链路通不通”测不到参数组合和边界行为。常见策略如下。参数类型合法生成示例非法示例评测意图string北京空字符串、超长字符串、错误城市名校验必填、格式、语义理解integer1-1、0、超过范围值校验范围约束number36.5非数字、NaN、负数校验数值边界booleantrueyes、1校验类型转换array[2025-04-01]非数组、空数组校验数组结构和长度object{lat: 39.9, lon: 116.4}缺少必填字段校验嵌套结构date2025-04-0104/01/2025、带时间字符串校验 format实际项目里非法用例不一定要全部作为“必失败”用例。有些非法输入应该被模型识别并拒绝调用工具而不是硬调用后报错。这取决于评测目标。5.2 预期行为约束怎么设计评测用例不能只有userTask还要有明确的预期行为。建议用结构化断言表达而不是写一大段自然语言描述。下面是一个示例。{ assertions: [ { type: tool_call, expect: { tool: get_weather, params: { city: 北京, date: 2025-04-01 } }, severity: blocker }, { type: not_call, tool: send_email, severity: warning }, { type: output_schema, schema: { required: [condition] }, severity: blocker } ] }tool_call断言智能体是否调用了指定工具参数是否匹配。not_call断言是否出现了不该调用的工具适合用来测“相似工具竞争”和“敏感操作误触发”。output_schema断言返回结果是否符合结构要求。建议把断言分为blocker和warning两级。blocker不通过代表任务失败warning不通过只记录不阻断避免因为一句话表达差异导致评测全部失败。5.3 评测运行参数建议运行 Agent 评测时参数设置会显著影响结果稳定性。下面的参数值只是起点具体要根据自己的模型和工具规模调整。参数建议值影响temperature0 或很低降低随机性提升可复现性max_tokens1024 到 2048避免长任务输出被截断timeout_seconds30 到 60避免工具调用卡死num_runs每个用例至少 3 次衡量模型随机性concurrency1 到 5避免外部接口限流llm_judge_temperature0保证评分结果稳定如果评测目标是衡量真实对话质量num_runs可以提高到 5 次以上最终结果取通过率或多数投票结果而不是只看单次输出。6. 运行验证与结果分析生成评测用例之后还要验证评测集本身是否可用。不能只看生成器能跑还要看生成结果是否符合预期。6.1 验证生成结果先运行一遍生成器并检查输出文件python generate_cases.py --input mcp_tools.json --output cases.jsonl --limit 3 cat cases.jsonl预期能看到 3 条用例。接着用 Python 做一次基础校验比如检查每条用例是否包含id、userTask、expected、assertions。python -c import json; linesopen(cases.jsonl).readlines(); print(count, len(lines)); [print(json.loads(l)[id]) for l in lines]如果输出数量不对优先检查mcp_tools.json里 tools 是否被正确解析。6.2 人工抽检与质量指标自动生成必须配人工抽检。至少要从生成结果里随机抽 20 到 50 条逐条确认以下几点用户任务是否自然是否像真实用户会说的话。预期工具是否唯一是否存在多个工具都能完成任务的情况。参数值是否符合inputSchema约束是否真的能通过 JSON Schema 校验。非法用例是否真的非法还是只是“语义上不常见”。为了让抽检有量化依据可以统计以下指标。指标计算方式建议目标可执行率能完成评测运行的用例数 / 总数初期高于 90%断言命中率智能体调用符合预期的用例数 / 总数稳定后高于 70%模板重复率使用相同任务模板的用例占比每个工具低于 30%误报率人工判定为错误的失败数 / 失败总数低于 10%如果模板重复率过高说明生成器只在改参数没有真正覆盖不同的用户表达方式。这时候需要引入任务模板池或大模型改写。6.3 从一条用例到一份评估报告运行完成后Agent Seer 会把每条用例的执行轨迹、工具调用序列、最终答案、断言结果合并成 JSON 报告。报告结构可以这样设计{ caseId: get_weather-001, status: pass, trajectory: [ { type: thought, content: 用户需要查询天气我应该调用 get_weather }, { type: tool_call, tool: get_weather, params: { city: 北京, date: 2025-04-01 } }, { type: tool_result, content: { temperature: 18, condition: 晴 } } ], assertions: [ { type: tool_call, passed: true }, { type: not_call, passed: true }, { type: output_schema, passed: true } ] }有了这种报告定位问题时就只需要看trajectory和assertions不需要重新跑一遍 Agent 去找日志。7. 常见问题与排查路径自动合成评测在落地过程中会遇到不少问题。下面整理几个高频场景和排查建议。7.1 现象、原因与处理方案问题现象常见原因检查方式处理建议生成的用户任务像模板拼接语义不自然description 写得太简略模板词太固定打印生成的任务人工朗读一遍补充 description 场景词或引入大模型改写预期工具调用选错多个工具 description 相似对比候选工具的 description 和 inputSchema加入工具选择约束人工审核更多样例参数值不符合 Schema没有处理 enum、pattern、$ref 等关键字用 JSON Schema validator 校验生成参数扩展解析器支持组合 Schema同一工具生成大量重复用例随机样本池太小或固定种子导致值重复统计生成的参数分布扩大样本池或按业务域分组生成LLM Judge 结果不稳定temperature 过高指标定义模糊固定 temperature对比多次结果规则断言优先LLM 只做辅助调用真实 MCP Server 时超时或受限外部服务不稳定权限不足查看超时日志和状态码引入 mock server隔离外部依赖7.2 排查顺序遇到评测用例失败时建议按以下顺序排查而不是一上来就怀疑模型能力。先检查输入 Schema 是否完整必填项是否都正确解析。再确认生成的参数能否通过 JSON Schema 校验。然后确认用户任务在自然语言上是否可理解是否有多义。接着检查 Agent 是否真的按预期调用工具还是调了别的工具。最后检查断言逻辑是否正确比如参数比较是否忽略了类型差异。如果前面几步都正常才应该把问题归因于模型能力不足或工具服务质量不稳定。8. 从学习环境到生产环境的安全与工程化最小示例跑通后距离生产使用还有一段距离。生产环境里工具调用涉及外部系统、权限、数据、成本评测平台本身也需要工程化。8.1 学习环境与生产环境的差异维度学习环境生产环境数据来源手工整理 JSON从 MCP Server 动态拉取或从配置中心同步工具依赖允许真实调用默认 Mock有控制放行外部服务随意调用需要配额、鉴权、审计用例存储本地 JSONL数据库、版本管理评估执行单机串行分布式任务队列或 CI 流水线日志print结构化日志、trace id安全无敏感数据脱敏、审计、权限隔离最典型的变化是工具调用隔离。生产评测不应该每次都在真实外部服务上执行否则会污染业务数据也会被外部限流影响评测结果。建议用 mock server 返回固定样例只有在专门的安全冒烟测试里才放行真实调用。8.2 生产化需要补齐的能力以下是上线前建议检查的清单配置外置MCP Server 地址、模型名称、超时时间不要写在代码里。幂等生成同一版本 Schema 反复生成结果应该一致方便回归对比。数据脱敏输入样例和用户任务不要包含真实个人信息。失败隔离单个工具或单条用例失败不影响整个评测任务。结果归档每次评测的用例版本、模型版本、工具版本都要记录。权限审计谁触发了评测、评测了哪些工具、是否调用真实服务都要留痕。版本标签MCP Schema 变化时要给评测集打版本号方便追溯。如果团队还没有评测平台可以先从“生成器 JSONL 本地报告”开始等数据积累到一定程度再做任务调度和结果可视化。9. 最佳实践与扩展方向Agent Seer