ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Apify MCP Server Agent Evals 实战:基于 Langfuse 的 MCP 工具族评测套件设计与故障诊断指南

Apify MCP Server Agent Evals 实战:基于 Langfuse 的 MCP 工具族评测套件设计与故障诊断指南 【免费下载链接】apify-mcp-serverThe Apify MCP server enables your AI agents to extract data from social media, search engines, maps, e-commerce sites, or any other website using thousands of ready-made scrapers, crawlers, and automation tools available on the Apify Store.项目地址https://gitcode.com/gh_mirrors/ac/apify-mcp-server点击查看免费下载本文介绍 Apify MCP Server 团队沉淀的 Langfuse Agent Eval 方法论如何为一个 MCP 工具族tasks、storage、runs、web-fetch 等构建一套小型、经过校准的评测套件并用它的失败来反哺修复工具本身。读完本文你将掌握从用户意图出发设计用例、双数据集 CI 门禁编排、模型阶梯校准、Langfuse CLI 实操以及一套失败时按顺序归因的诊断框架。核心原则评测从用户意图出发而非从工具描述出发这套方法论的第一条原则也是贯穿全文的哲学是evals are designed from user intent, never from tool descriptions——评测定义的是应该能正常工作的事而工具描述是事后为了让朴素的 Agent 能通过评测才去修复的东西。这个顺序非常重要。如果写用例时盯着工具描述抄你测的是 Agent 的鹦鹉学舌能力parroting而不是它对自然语言用户请求的理解与工具选择能力。描述是被测对象绝不能被当成出题依据。完整的命令、条目形态、探测模式与清扫查询sweep queries详见配套参考手册 reference.md。整体流程七步走1. 盘点工具Inventory the tools每个工具、每个参数组至少要有一个用例——最终由覆盖率矩阵coverage matrix来证明而不是口头声明。2. 先探测平台Probe the platform first在编写任何依赖 API 行为的用例必填字段、唯一性规则、限制、错误消息之前先用一个一次性的tsx脚本对着真实 API验证。绝不要基于假设的契约写用例——否则你会得到一堆被 schema 拒绝的输入值。3. 两个数据集每个 CI 门禁一个Two datasets, one per CI gate数据集默认条目 kind门禁时机mcp-server-evals-pr--dataset默认值kind: tool-call门禁 PRPR 打开/重开或打上validated标签mcp-server-evals-merge需显式--dataset指定kind: agentpush 到 master 时运行每个条目必须在metadata.kind中声明自己的类型tool-call单轮只断言第一次工具调用无 judge什么都不执行agent多轮运行到完成由 LLM judge 打分。一个tool-call用例通过expectedTools必填固定工具名通过expectedArgs可选固定参数——它是一个扁平对象列出的每个 key 都必须与捕获到的调用中同名 key 深度相等未列出的 key 忽略。需要把 MCP 与 MCP 之间的工具选择与 Claude Code 内置工具隔离开时加mcpToolsOnly: true。一个故意触发错误的agent用例撞名、not-found、需求探索必须设置metadata.expectedErrors列出允许在该条目上失败的工具名——零工具错误门禁只豁免这些具名工具因此它永远不会像整库宽泛容错那样掩盖无关的失败。条目 id 必须是数据集前缀形态pr 数据集中是pr/tool/slugmerge 数据集中是merge/family/slug中间段是工具或工具族search-actors、tasks、web-fetch等slug是其余部分。4. 分波次写用例Write cases in waves2–3 个简单用例单工具、输入明确→ 1–2 个中等用例跨工具链、运行选项→ 2–3 个困难用例含糊的用户语言、错误恢复、碰撞。每一波写完先运行并评审再写下一波——否则一个系统性的用例编写缺陷比如不可知的上下文会复制进每一个困难用例里。5. 先用最强模型校准Calibrate on the strongest model first先用 Opus 校准。在最强模型上的失败必然是用例缺陷或产品缺口绝不可能是描述问题。只有一套校准过的套件强模型 100% 通过才能把弱模型上的失败归因于描述问题。6. 逐级下调模型Ladder downSonnet → Haiku。Opus 通过而 Haiku 失败 工具描述或输出没能承载一个朴素 Agent 的理解。这才是你构建这套评测想要捕获的信号。7. 先修输出再修描述Fix tools via outputs before descriptions工具响应的 summary/nextStep 里的一句引导语每次调用都会到达每个 Agent而描述文本往往只是被 skim 一眼。原始构建中修复 Haiku 失败的两个输出修正output nudge都是响应文本的改动而非描述改动。数据集条目形态Langfuse item shape一个agent用例的完整 JSON 形态如下见 reference.md{ datasetName: mcp-server-evals-merge, id: merge/family/tool-difficulty-1, input: { query: 用户语言提示词不得出现工具名 }, expectedOutput: PASS only if tool was called with args and the final answer states fact. FAIL if 具体错误行为., metadata: { category: tool-or-chain, kind: agent, maxTurns: 10, tools: [family, actors] } }关键约束datasetName二选一kind: agent条目用mcp-server-evals-mergekind: tool-call条目用mcp-server-evals-pr。metadata是严格校验的实现见 langfuse/dataset.ts未知 key 会在任何 LLM 花费之前就让本次运行失败。可用旋钮category、kind、expectedTools、expectedArgs、expectedErrors、maxTurns、tools、failTools、mcpToolsOnly。category 被测工具--category过滤的依据难度写在 id 的slug半段。kind: agent必须有expectedOutput多轮、judge 打分expectedErrors/failTools/maxTurns生效kind: tool-call必须有非空expectedTools并拒绝expectedOutput、expectedErrors、failTools、maxTurns轮数固定为 2。expectedArgs可选仅tool-call只在expectedTools只列出一个工具、或列出的每个工具都共享相同 key 与期望值时使用——扁平对象无法对不同工具施加不同期望。示例pr/call-actor/rag-web-browserapify/rag-web-browser既可以解析到通用call-actor工具{actor, input}也可以解析到直接工具apify--rag-web-browser{query, maxResults, ...}两种参数形态互不兼容所以该条目把两个工具都列进expectedTools且不带expectedArgs。maxTurns参考单工具 6–8创建验证 10链式 12–18。要为 reference 允许的最长路径探索→拒绝→回退留预算而不是为快乐路径Actor 运行类用例要为轮询周期留出余量run 可能超过等待上限。条目按idupsert。id 在项目内永久唯一即使归档/在其他数据集删除重建也不会释放。退休用例 upsertstatus: ARCHIVED。failTools仅agentharness 在到达服务器前强制失败的工具列表如[call-actor]消息携带真实的report-problem引导语——用于确定性地产出可触发 nudge 的失败这是真实服务器 API 无法按需复现的场景。运行评测命令行实操基本命令# 默认数据集 mcp-server-evals-pr门禁是聚合通过率 DEFAULT_PASS_THRESHOLD (0.9 # 依据见 runner/run.ts)。--pass-threshold 1.0 恢复严格的全通过门禁。 # 裸跑 快速 PR 门禁集即 kind: tool-call 的条目。 pnpm run evals:mcp-agent --agent-model claude-haiku-4-5 --subscription # merge 集kind: agent 条目push 到 master 时运行 pnpm run evals:mcp-agent --dataset mcp-server-evals-merge --agent-model m --subscription # 按 id 前缀只跑一个族 pnpm run evals:mcp-agent --dataset mcp-server-evals-merge --id ^merge/family/ --agent-model m --subscription # 进一步收窄--category name--concurrency N--tool-timeout secs--iterations N (passk/pass^k)命令在 package.json 中定义为pnpm run build tsx evals/runner/run.ts会先自动构建 MCP server另有evals:mcp-agent:export-dataset、evals:mcp-agent:tasks-fixtures、evals:mcp-agent:schedules-fixtures三个配套脚本。关键 flag 详解实现见 evals/runner/run.ts--subscription从进程环境删除ANTHROPIC_API_KEY让 Agent SDK 的 Claude Code 子进程使用本地登录凭据不加则按 API key 计费。注意当--subscription未开启时该变量属于必填项缺失会直接process.exit(1)。--claude-judge让 judge 也跑在 Agent SDK 上此时--judge-model接受 Anthropic 模型 id默认claude-sonnet-5配合--subscription --claude-judge一次运行只需APIFY_TOKEN Langfuse 三个 key无需 OpenRouter key。注意Claude judge 评 Claude agent 可能自我宽容self-lenient——要可比数字优先用 OpenRouter judge。m模型阶梯claude-opus-5校准→claude-sonnet-5→claude-haiku-4-5CLI 默认也是最敏感的探针。默认配置见 evals/config.tsagent 默认claude-haiku-4-5judge 默认deepseek/deepseek-v4-flash。--pass-threshold默认0.9依据在 evals/runner/run.tspr 数据集里有两个 tool-call 条目被保留但 Haiku 大约每三次运行漏一次失败本身就是信号而非用例缺陷--pass-threshold 1.0要求每个 trial 都过。--concurrency默认 8映射到 SDK 的maxConcurrency是顺序批次执行而非滚动窗口——一个慢测试会拖住同批其他测试。--tool-timeout默认 60 秒DEFAULT_TOOL_TIMEOUT_SECONDS跑长时 Actor 时用--tool-timeout 600加大。退出码0 聚合通过率passed trials / requested trials达到--pass-threshold1 未达标或 setup 失败。链式 shell 命令的退出码是最后一个run 的——读每个日志的行而不是看整条链的状态。已知 flakes Never completed (task threw)harness/SDK 进程问题先单条目重试一次再诊断远程/沙箱环境下 Agent 读到 MCP servers still connecting 而回退到内置工具本地不重现——单条目重试一次本地机器上重复失败才是真的。有状态族的 fixtures 脚本创建命名资源的套件在两次运行之间要先跑 fixtures 脚本pnpm run evals:mcp-agent:tasks-fixtures按族适配删除遗留的eval-*资源并重新播种永久 fixture。纯 Web 目标族如web-fetch、web-selection不创建命名状态无需 fixtures 脚本——在 README 里说明即可。Langfuse 环境与 CLI 操作环境变量LANGFUSE_PUBLIC_KEYpk-lf-... # 项目设置 → API keys LANGFUSE_SECRET_KEYsk-lf-... LANGFUSE_BASE_URLhttps://langfuse.apify.dev这些放在仓库根目录的.env中harness 通过 dotenv 加载并在任何客户端构造前先做值清洗sanitizeProcessEnv()见 evals/runner/run.ts。Git worktree 不共享.env——先从主 checkout 复制一份cp main-checkout/.env .env。CLI 读的是LANGFUSE_HOST而非LANGFUSE_BASE_URL所以两个都要导出。Langfuse CLI 使用npx在仓库内会被拒绝运行pnpm 固定的devEngines——从任意其他目录运行。CLI 调用前的标准 preamblecd /tmp export $(grep -E ^LANGFUSE repo/.env | xargs) export LANGFUSE_HOST$LANGFUSE_BASE_URLnpx -y langfuse-cli api datasets list --json # 两个数据集已存在无需创建 jq -c .[0] items.json | npx -y langfuse-cli api dataset-items create --body-file - # create 按 id UPSERT重发同 id 即可迭代用例 npx -y langfuse-cli api dataset-items get id npx -y langfuse-cli api dataset-items delete id # 不可逆且不释放 idid 已烧掉——用归档代替status: ARCHIVED每个用例的编辑循环upsert 条目 → 用--id substring-regex只重跑该条目 → 读 transcript。读取失败 transcriptjudge 理由 每轮工具调用。--from-start-time必填条目的output字段是 JSON字符串——需要fromjson管道npx -y langfuse-cli api experiment-items list \ --experiment-name runName from console --from-start-time ISO --fields core,io --all --json \ | jq -r .body.data[] | (.output | fromjson) as $o | $o.id $o.judgeResult.verdict \n ([$o.transcript[] | to_entries[] | .key : (.value | tostring | .[0:300])] | join(\n))运行后清扫意外错误。只读kind: agent条目没有expectedErrors条目的 agent 运行必须贡献零行 ERROR但每个通过的kind: tool-calltrial 都会按设计产生一个 ERROR spandeny-all hook 拒绝了它正在测量的那次调用而 tool-call 条目不能声明expectedErrors。npx -y langfuse-cli api observations list --level ERROR \ --from-start-time run start ISO --fields core,basic,io --limit 100API 探测模式写平台依赖用例之前在evals/scripts/probe_*_tmp.ts放一个一次性脚本用pnpm exec tsx运行用完删除。用真实的apify-client精确探测用例将依赖的行为必填字段、唯一性错误、发布要求、长度限制、密钥处理。捕获精确的错误消息和typeslug——reference 可以要求 Agent 对其作出反应工具错误包含(API error type: slug)。import dotenv/config; import { ApifyClient } from apify-client; const client new ApifyClient({ token: process.env.APIFY_TOKEN }); // create the thing the case assumes, read it back, print the error/shape, delete it对于实时 Web 用例探测精确的目标 URL验证抓取到的内容支持前提状态、body、答案需要的事实——并优先选稳定主机rfc-editor.org、example.com而非易挂的主机httpbin.org 经常 503凡是内容本身就是交付物的地方。覆盖率矩阵数据集的完成定义对每个工具至少一个专属用例加上每个参数组在某个用例中被覆盖create: input/name/configget: found not-foundupdate: 每个可独立更新的组生命周期工具一个干净的快乐路径用例 一个带expectedErrors的需求发现用例。一个工具仅作为其他用例的尾巴被练习如 unpublish也是可接受的只要专属用例会与已有用例重复——报告覆盖率时要明确说明这一点。诊断失败用例——按这个顺序归因嫌疑症状修复用例Query 引用了 Agent 拿不到的上下文my usual setup输入违反 actor 的 schema强模型错误行为实际上站得住脚把 query 改写为自包含给往返操作一个目的确认它是活的然后把它关掉judge/referenceAgent 做对了reference 要求了不可能的事例如要求回显工具从不返回的值改写expectedOutput它只能要求可观测的东西judge 只能看到工具调用 参数 最终文本永远看不到工具结果产品该工具按设计就无法满足一个自然用户请求作为决策浮出水面不要偷偷调整用例或工具描述/输出朴素模型卡住去问、猜而不是用发现类工具、被命名含糊的字段误导而产生幻觉先输出引导语再改描述重命名那些诱发误读的字段世界实时目标页面挂了、变了、或空了503 故障、零帖子的 profile——Agent 行为正确把内容承载型用例移到稳定主机HTTP 行为本身就是评测轴的地方让 reference 容忍故障如实上报上游错误就是一个 PASS 路径模型工具选对了但出现策略性拒绝超长逐字复述、placeholder domain或在你能控制的每一层 nudge 之后仍存活的不良习惯拒绝 → 把交付物缩小到阈值以下一个 section、公有领域文本nudge 参数修复后可复现的习惯 → 保留用例、记录残余、停止调优归因前永远先读 transcript。Judge 的一句话只是线索不是诊断。防止返工的规则Reference 必须是 judge 可检查的契约PASS only iftoolwas called withargand the final answer statesfact。FAIL if …。绝不写the agent should handle it well。Query 用用户语言。点名工具的 query 测的是鹦鹉学舌而不是描述困难用例绝不能点名工具。Telemetry 要真实。绝不为隐藏预期错误而降级 span 级别——那会掩盖真实错误。改为在条目的metadata.expectedErrors中具名预期失败门禁是tool_errors 0统计服务器MCP工具调用中除具名者之外的所有失败失败的只读探测仍然算猜 slug 而不是 search 就是失败Agent 的内置工具豁免——它们的磕绊是客户端噪音不是我们的。写 judge 盲区条款。Judge 看不到工具结果所以 reference 必须预防误读Agent 叙述怪癖count 读出来是 0 但 items 在那里不是承认失败通过明确归属的回退交付的内容是检索到了而不是编造了绝不要求叙述一个合法替代路径完全跳过的事件一个 block、一个 error。惩罚虚假声称而非惩罚沉默的成功。结果和诚实是两个轴礼节宣布切换工具、为绕路道歉是加分项绝不是 PASS 条件。tool-call 用例必须接受每个站得住脚的答案。expectedTools是列表scorer 命中任一成员即通过——当第二个工具也合法地服务目标时如fetch-apify-docs已加载时一个 Apify 文档 URL把两个都列上而不是让合法行为失败。优先选择只有被测工具适配的目标做不到就放宽列表并跳过expectedArgs其 key 必须对模型选中的任一工具都成立。探测目标而不只是机制。实时 Web 用例要在编写时抓取精确 URL检查内容支持前提一个探测过可工作的 scraper 对一个后来发现是零帖子的 profile 依然返回了空。状态是账号全局的。固定的eval-前缀资源名 fixtures seed/cleanup 脚本每个对话自包含创建 → 动作 → 清理纯 get 用例用一个永久只读 fixture。数据集条目 id 永久项目唯一——不能在数据集间搬移归档后也不能复用。搬动一个用例 新 id 归档旧的。红线——停下来重新思考盯着工具描述写用例 → 你在测鹦鹉学舌。关掉文件。一个故意触发错误的agent用例没有metadata.expectedErrors→ 在该条目上设置它不再有运行级容错 flag只有按条目、按工具的豁免。一次重跑修复了你没诊断的失败 → 已知 harness flaketask threw, never completed可以重试一次judge 判 FAIL 永远不是 flake读 transcript。因为一个模型失败了一次就改工具 → 先复现或诊断单次运行是随机的。Query 里出现明显假 URLftp.example.com、this-is-a-test.com→ 模型会合理地拒绝占位符目标用真实主机需要抓取失败时用该主机上不存在的路径。交付物要求逐字复述几百字以上 → 某些模型会在零工具调用的情况下以复述为由拒绝无论许可如何用例测的会变成拒绝阈值而非工具选择。用例的支线任务不是被测轴超大 payload 引诱文件交付或字节级校验→ 让用户要求在聊天内交付并预先授权截断为maxTurns预算恢复路径而非快乐路径。常见错误错误后果一个没有metadata.expectedErrors的用例故意触发错误零工具错误门禁判它失败要么是用例 bug要么是缺expectedErrors用便宜模型校准分不清用例 bug 和描述 bug你会对着坏用例去修描述链式用例maxTurns设太低Agent 中途耗尽轮数judge 看到未完成的 transcript固定名字无清理第二次运行与第一次的残留碰撞非确定性失败跳过波次评审一个系统性的用例编写缺陷如不可知的上下文复制进每个困难用例从发现修复工具优先级排序响应 summary/nextStep 文本——例如stored values are never returned…、to re-check publication state, use get-actor-task。每次调用都会到达每个 Agent。Summary 绝不能陈述平台还无法背书结论未验证的零计数应写成reads 0, can lag而不是no items found——Agent 会引用 summary 并据此放弃。参数 schema 约束 describe()——把 API 限制编码进去.max(60)让非法调用在触达 API 之前就在客户端失败。参数描述在写参数时被读取所以约束说明放那里比放描述尾部更有效——但它也有极限一个弱模型在两者都修好后仍把 ftp:// 静默改写为 https://修完你拥有的每一层后记录残余。字段重命名 / 形态对齐——字段名诱发误读或偏离 API 契约时与 API 对象对齐structuredContent改动必须为内部仓库的契约套件标记。描述 USAGE 行——偏置-行动 nudgeresolve loose Actor references with search-actors instead of asking条件依赖hasTool()。任何工具改动后pnpm run build会随evals:mcp-agent自动执行先只重跑受影响的模型/用例对最后再跑完整阶梯。底层机制速览源码级补充为帮助你理解命令与规则背后的实现几个关键源码位置两条评测模式的分工tool-call模式由 agent/claude_agent.ts 里的 deny-allPreToolUsehook 拒绝每次调用拒绝措辞TOOL_CALL_DENY_REASON与固定轮数TOOL_CALL_MAX_TURNS 2定义在 runner/tool_call_mode.tsAgent 在报告本会调用什么后停止评分函数resolveFirstToolMatch会跳过 Claude Code 的路由元工具ToolSearch只测量第一个非 ToolSearch 调用实现名字在expectedTools内 列出的expectedArgskey 深度相等的匹配逻辑见 runner/tool_call_mode.ts。Judge 的输入边界judge 看到工具调用与参数、Agent 回复但看不到原始工具结果judge/judge.ts 的JUDGE_PROMPT_TEMPLATE明确写明 Tool results are not shown (only tool calls and agent responses)这就是为什么 reference 只能要求可观测事实。条目的严格校验metadata用z.strictObject校验evals/langfuse/dataset.ts未知 key 直接让 run 在 LLM 花费前失败kind专属字段的交叉约束expectedOutput/expectedErrors/failTools/maxTurns仅限agentexpectedTools/expectedArgs仅限tool-call在superRefine中强制evals/langfuse/dataset.ts。通过率门禁pass_rate passedTrials / requestedTrialsrequestedIds.length * iterations所以被丢弃的 trial 会拉低比率而不是从统计中消失evals/runner/experiment.ts默认阈值0.9及背后的理由记录在 evals/runner/run.ts。数据集即真理之源运行只读数据集、从不写入用例在 Langfuse UI 编辑evals:mcp-agent:export-datasetscripts/export_dataset.ts只是导出快照供离线阅读运行时不读快照——完整的架构决策进程隔离、Claude Agent SDK、judge 客户端共享等记录在 evals/README.md。更完整的评测系统背景两个数据集的既有族、CI 门禁阈值、工具描述编写准则、常见问题排查可进一步阅读 evals/README.md 与技能参考手册 reference.md。赞分享【免费下载链接】apify-mcp-serverThe Apify MCP server enables your AI agents to extract data from social media, search engines, maps, e-commerce sites, or any other website using thousands of ready-made scrapers, crawlers, and automation tools available on the Apify Store.项目地址https://gitcode.com/gh_mirrors/ac/apify-mcp-server点击查看免费下载相关推荐Fluent UI React v9 SSR 下 Menu/Popover 使用 defaultOpen 出现水合错误怎么排查Fluent UI React v9 SSR 下 Menu/Popover 使用 defaultOpen 出现水合错误怎么排查 在 Fluent UI ReacApify MCP Server 前端设计系统实战指南基于 theme.* Design Tokens 与 apify/ui-library 的 Widget 开发规范Apify MCP Server 前端设计系统实战指南基于 theme. Design Tokens 与 apify/ui library 的 WidgetChrome MCP Server 安装与连接故障排查完全指南mcp-chrome-bridge doctor 诊断与 Native Messaging Host 排障实战Chrome MCP Server 安装与连接故障排查完全指南mcp chrome bridge doctor 诊断与 Native Messaging HoMCP 服务AI Agent浏览器控制GUI 自动化工具调用人工智能AI 应用上一篇大麦自动抢票脚本部署指南从双端配置到开票实战下一篇Apache Arrow 格式规范解读Tensor 与 Sparse Tensor 数据结构的 IPC 序列化与内存布局创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表