Use when adding Langfuse MCP agent evals for a tool family of the Apify MCP server ("create evals for the storage tools"), when eval cases fail and you must dec
复制下面这句话,粘贴给 Claude Code、Codex、Cursor 等 AI 编程工具,它会读取安装说明并在你确认后完成安装。
请阅读 https://ai.atlankj.com/install/asset/gh-creating-mcp-agent-evals-b30ee596ba7f ,按照其中的说明把「creating-mcp-agent-evals」安装到你(当前 AI 工具)中。执行前先告诉我将运行的命令和写入的位置,等我确认。
查看 AI 将读取的安装说明正在读取 GitHub 原文…
内容来自 GitHub 原始文件,由原作者维护。在 GitHub 查看
Build a small, calibrated Langfuse eval suite for one tool family (tasks, storage, runs, …), then use its failures to fix the tools. Core principle: evals are designed from user intent, never from tool descriptions — the eval defines what should work; descriptions get fixed afterward to make naive agents pass it.
Commands, item shapes, probe patterns, and sweep queries: reference.md.
tsx script against the real API. Never write a case on an assumed contract — that's how you get input values the schema rejects.mcp-server-evals-pr (the --dataset default) holds the kind: "tool-call" items and gates PRs (PR open/reopen, or the validated label); mcp-server-evals-merge holds the kind: "agent" items and runs on push to master. Every item declares metadata.kind ("tool-call", single-turn, only the first tool call is asserted, no judge, nothing executes, or "agent", multi-turn, run to completion and scored by an LLM judge). A kind: "tool-call" case sets expectedTools (required) and, to pin arguments (not just the tool name), expectedArgs — a flat object, every listed key must deep-equal the captured call's same key, unlisted keys ignored; add mcpToolsOnly: true when a case must isolate MCP-vs-MCP tool choice from Claude Code's built-ins. A kind: "agent" case that provokes an error on purpose (a collision, a not-found, requirement discovery) sets metadata.expectedErrors to the tool name(s) allowed to fail on it — the zero-tool-error gate exempts only those, so it never masks an unrelated failure the way a blanket error-tolerant dataset would. Give the item id the dataset-prefixed shape — pr/<tool>/<slug> in the pr dataset, merge/<family>/<slug> in the merge one, where the middle segment is the tool or tool family (search-actors, tasks, web-fetch, …) and <slug> is the rest.| Suspect | Symptoms | Fix |
|---|---|---|
| The case | Query references context the agent can't obtain ("my usual setup"); input violates the actor's schema; the smart model's "wrong" behavior is actually defensible | Rewrite query self-contained; give round trips a purpose ("confirm it's live, then take it down") |
| The judge/reference | Agent did the right thing, reference demands the impossible (e.g. echo values the tool never returns) | Reword expectedOutput; it must only require what's observable (judge sees tool calls + args + final text, never tool results) |
| The product | The tool cannot satisfy a natural user request by design | Surface as a decision, don't silently adjust the case or the tool |
| The description/output | Naive model stalls to ask, guesses instead of using a discovery tool, hallucinates from an ambiguously named field | Output nudge first, description second; rename fields whose names invite misreading |
| The world | The live target page is down, changed, or empty (a 503 outage, a profile with zero posts) — the agent behaved correctly | Move content-bearing cases to stable hosts; where HTTP behavior IS the axis, make the reference outage-tolerant (a truthfully reported upstream error is a PASS path) |
| The model | Correct tool choice but a policy-shaped refusal (long verbatim reproduction, "placeholder domain"), or a bad habit that survives nudges at every layer you own | Refusal → scope the deliverable below the threshold (one section, public-domain text); reproducible habit after description + parameter fixes → keep the case, document the residual, stop tuning |
Always read the transcript before assigning blame. The judge's one-liner is a hint, not a diagnosis.
<tool> was called with <arg> and the final answer states <fact>. FAIL if …". Never "the agent should handle it well".metadata.expectedErrors instead; the gate is tool_errors == 0 over server (MCP) tool calls except the named ones (failed read-only probes still count: guessing a slug instead of searching is a failure; the agent's built-in tools are exempt — their stumbles are client noise, not ours).expectedTools is a list and the scorer passes on any member, so when a second tool legitimately serves the target (an Apify docs URL when fetch-apify-docs is loaded), name both rather than failing defensible behavior. Prefer targets where only the tool under test fits; where that is impossible, widen the list and skip expectedArgs, whose keys must hold for whichever tool the model picks.eval- prefixed resource names + a fixtures seed/cleanup script; each conversation self-contained (create → act → clean up); one permanent read-only fixture for pure "get" cases.agent-kind case that provokes an error on purpose has no metadata.expectedErrors → set it on that item; there is no run-wide error-tolerance flag any more, only the per-item, per-tool exemption.ftp.example.com, this-is-a-test.com) → models defensibly refuse "placeholder" targets; use a real host, and a nonexistent path on it when the fetch must fail.maxTurns for the recovery path, not the happy path.| Mistake | Consequence |
|---|---|
A case with no metadata.expectedErrors provokes an error on purpose | The zero-tool-error gate fails it; either it's a case bug, or expectedErrors is missing |
| Calibrating on the cheap model | Can't tell case bugs from description bugs; you'll "fix" descriptions against broken cases |
maxTurns too low on chain cases | Agent runs out of turns mid-flow and the judge sees an unfinished transcript |
| Fixed names without cleanup | Second run collides with the first run's leftovers; nondeterministic failures |
| Skipping the wave review | A systematic case-authoring flaw (e.g. unknowable context) replicates into every hard case |