-
Notifications
You must be signed in to change notification settings - Fork 132
@W-23558172: Enable coding-agent eval harness in main + admin tool-coverage cases #623
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Alon-ST-DATA
wants to merge
16
commits into
main
Choose a base branch
from
asimantov/eval-admin-tools
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
af614a2
robust test harness for evluating tmcp + claude code with the califor…
joeconstantino 399beb0
version bump
joeconstantino d5915c1
docs update
joeconstantino 7d59f1f
linting fixes
joeconstantino a9894ee
case run fixes
joeconstantino 28a250b
make runner and grader coding agent agnostic
joeconstantino a54665a
addtl sample questions
joeconstantino 01724d9
Add admin-tool eval cases onto the eval harness
Alon-ST-DATA a2c2ba4
Fix CI lint: realign package-lock with main (eslint 9.39.4)
Alon-ST-DATA ada05e1
Self-review fixes for eval admin-tools harness
Alon-ST-DATA 4394573
Address Akash review nits on eval graders
Alon-ST-DATA a673059
Bump version to 3.7.0
Alon-ST-DATA 96d6d25
docs(evals): note free-tier LangSmith key suffices for local eval runs
Alon-ST-DATA 412d4bc
chore: realign package-lock after rebase onto main (uuid dep)
Alon-ST-DATA 081b078
Merge origin/main into asimantov/eval-admin-tools
Alon-ST-DATA d919b7b
Remove DEFERRED eval design specs per review (jarhun88)
Alon-ST-DATA File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| { | ||
| "label": "Evaluation", | ||
| "position": 8, | ||
| "link": { | ||
| "type": "generated-index", | ||
| "description": "Tools and benchmarks for evaluating the accuracy of Claude Code against the Tableau MCP server." | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,214 @@ | ||
| --- | ||
| sidebar_position: 1 | ||
| --- | ||
|
|
||
| # Claude Code Eval Harness | ||
|
|
||
| The Tableau MCP eval harness runs [Claude Code](https://docs.anthropic.com/en/docs/claude-code/overview) as a live agent against the Tableau MCP server and grades its responses against known-correct answers. It is designed to measure query accuracy — not simulated tool calls, with real API round-trips to a live Tableau Cloud or Server site. | ||
|
|
||
| The primary benchmark is 30 questions from the [BIRD Mini-Dev](https://bird-bench.github.io/) dataset scoped to the California Schools database. | ||
|
|
||
| --- | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| ### Required | ||
|
|
||
| - **Claude Code** installed and available on your `PATH` (`claude --version` should work) | ||
| - **A published California Schools datasource** on your Tableau Cloud or Server site. This is a single published datasource that joins the three California Schools source tables (`schools`, `frpm`, `satscores`). You will need its LUID. A .tdsx for this data source ships in the BIRD Mini-Dev snapshot (see the eval [README](https://github.com/tableau/tableau-mcp/blob/main/evals/README.md#regenerating-expected-answers) for how to obtain it) at `evals/bird_mini/data/tableau_datasources/california_schools`; note `evals/bird_mini/` is gitignored and not committed. | ||
| - **Tableau credentials** — any supported auth method (PAT, OAuth, direct trust). See [Authentication](/docs/configuration/mcp-config/authentication) for setup. | ||
|
|
||
| ### Optional | ||
|
|
||
| - **LangSmith account** — required for grading. Grading is sourced entirely from the LangSmith trace (there is no local-artifact grading path), so without a posted trace `grade.ts`/`grade-bird.ts` return `grading_error`. See [LangSmith Integration](#langsmith-integration). | ||
| - **A grader harness** — for semantic grading (LLM judge). The judge runs headless through a coding-agent harness (`GRADER_HARNESS`, default `claude-code`), NOT the OpenAI API. Without a usable harness, the verdict falls back to numeric-only grading. | ||
|
|
||
| --- | ||
|
|
||
| ## Environment Variables | ||
|
|
||
| Copy `env.example.list` to `.env` at the repo root and fill in the values below. | ||
|
|
||
| ### Required | ||
|
|
||
| | Variable | Description | | ||
| |---|---| | ||
| | `SERVER` | Your Tableau Cloud or Server URL (e.g. `https://10ax.online.tableau.com`) | | ||
| | `SITE_NAME` | Your Tableau site name | | ||
| | `PAT_NAME` | Personal Access Token name | | ||
| | `PAT_VALUE` | Personal Access Token secret | | ||
| | `EVAL_DATASOURCE_LUID` | LUID of the published California Schools datasource. Find it in Tableau by opening the datasource and copying the ID from the URL. | | ||
|
|
||
| ### Optional — LangSmith | ||
|
|
||
| | Variable | Default | Description | | ||
| |---|---|---| | ||
| | `LANGSMITH_API_KEY` | — | Your LangSmith API key. Get one at [smith.langchain.com](https://smith.langchain.com) → Settings → API Keys. If not set, traces are not posted. | | ||
| | `LANGSMITH_PROJECT` | `tableau-mcp-evals` | LangSmith project to post traces to. | | ||
|
|
||
| ### Optional — Grading | ||
|
|
||
| | Variable | Default | Description | | ||
| |---|---|---| | ||
| | `GRADER_HARNESS` | `claude-code` | Coding-agent harness that runs the semantic-match LLM judge headless. One of `claude-code`, `cursor`, `codex`. If no usable harness is available, `semantic_match` is skipped and the verdict is based on `numeric_match` only. | | ||
| | `GRADER_MODEL` | harness default | Model the judge harness uses (e.g. `claude-sonnet-4-5`). Leave unset to use the harness's own default. | | ||
|
|
||
| --- | ||
|
|
||
| ## Running the Harness | ||
|
|
||
| ### Run the full BIRD suite (30 questions) | ||
|
|
||
| ```bash | ||
| npm run eval:suite | ||
| ``` | ||
|
|
||
| ### Run a filtered subset | ||
|
|
||
| ```bash | ||
| npm run eval:suite -- --difficulty simple # only the 8 "simple" questions | ||
| npm run eval:suite -- --difficulty moderate # only "moderate" questions | ||
| npm run eval:suite -- --ids 5,11,12 # specific question IDs | ||
| ``` | ||
|
|
||
| Difficulty levels map to the BIRD benchmark's own classifications: `simple`, `moderate`, and `challenging`. | ||
|
|
||
| ### Run a single question by ID | ||
|
|
||
| ```bash | ||
| npm run eval:suite -- --ids 5 | ||
| ``` | ||
|
|
||
| ### Run an ad hoc custom question | ||
|
|
||
| Pass any natural language prompt directly, without a suite file: | ||
|
|
||
| ```bash | ||
| npm run eval:claude -- input "How many schools have an average SAT math score above 400?" | ||
| ``` | ||
|
|
||
| Ad hoc runs use the same Claude Code + Tableau MCP setup as suite runs and produce the same local artifacts. They are graded by `grade.ts` (tool coverage only), not `grade-bird.ts`, because there is no precomputed expected answer to compare against. | ||
|
|
||
| --- | ||
|
|
||
| ## Grading | ||
|
|
||
| ### Grade a full suite run | ||
|
|
||
| After `eval:suite` completes, grade every case at once: | ||
|
|
||
| ```bash | ||
| npm run eval:grade:suite # auto-discovers most recent | ||
| npm run eval:grade:suite -- evals/suite-runs/YYYY-MM-DD/<suite-run-id> # explicit path | ||
| ``` | ||
|
|
||
| This writes a single `suite-grade.json` to `evals/grades/YYYY-MM-DD/<suite-run-id>/`. | ||
|
|
||
| ### Grade a single run | ||
|
|
||
| ```bash | ||
| npm run eval:grade:bird -- evals/runs/YYYY-MM-DD/<run-id> | ||
| ``` | ||
|
|
||
| Output goes to `evals/grades/YYYY-MM-DD/<run-id>/bird-result.json`. | ||
|
|
||
| --- | ||
|
|
||
| ## Grading Signals and Metrics | ||
|
|
||
| Each run is evaluated on four signals. The **verdict** is determined by the two outcome signals only. The structural signals are recorded for debugging purposes and do not affect the verdict. | ||
|
|
||
| ### Outcome signals (drive the verdict) | ||
|
|
||
| | Signal | Method | Description | | ||
| |---|---|---| | ||
| | `numeric_match` | Code | The expected numeric value or row count appears in Claude's final message. Integer matches are exact; float matches allow ±1% tolerance. String answers (e.g. school names) use case-insensitive substring matching. | | ||
| | `semantic_match` | LLM judge | A headless coding-agent judge (`GRADER_HARNESS`/`GRADER_MODEL`) scores Claude's final message against the gold answer summary on a 0–1 scale. A score ≥ 0.8 passes. Skipped if no grader harness is available. | | ||
|
|
||
| ### Structural signals (informational) | ||
|
|
||
| | Signal | Method | Description | | ||
| |---|---|---| | ||
| | `columns_match` | Tool call inspection | The expected VizQL field captions are present in the `query-datasource` call. Extra columns are allowed; only missing required columns count against this signal. | | ||
| | `filters_match` | Tool call inspection | The expected filter field captions are present in the `query-datasource` call. Same subset-matching logic as `columns_match`. | | ||
|
|
||
| ### Verdicts | ||
|
|
||
| | Verdict | Meaning | | ||
| |---|---| | ||
| | `pass` | Both `numeric_match` and `semantic_match` passed | | ||
| | `partial` | One of the two outcome signals passed (or one was unavailable) | | ||
| | `fail` | Both outcome signals failed | | ||
| | `error` | Claude Code exited with a non-zero code | | ||
| | `skip` | Both outcome signals were unavailable (e.g. no grader harness and no numeric result to match) | | ||
|
|
||
| --- | ||
|
|
||
| ## Metrics Captured Per Run | ||
|
|
||
| Each case run records the following, available in `bird-result.json` (individual) or `suite-grade.json` (aggregated). All metrics are sourced from the LangSmith trace (the single source of truth for grading); the local `agent-output.jsonl` stream is kept for human debugging only. | ||
|
|
||
| | Metric | Source | Notes | | ||
| |---|---|---| | ||
| | `wall_s` | Trace | Wall time of the run, from the trace's root span | | ||
| | `tool_calls` | Trace | Total number of tool calls made | | ||
| | `tools_used` | Trace | Deduplicated list of tool names called | | ||
| | `model` | Trace | Model name reported in the trace | | ||
| | `tokens.input_tokens` | Trace | Summed across all LLM runs | | ||
| | `tokens.output_tokens` | Trace | Summed across all LLM runs | | ||
| | `tokens.cache_creation_tokens` | Trace | Prompt cache write tokens | | ||
| | `tokens.cache_read_tokens` | Trace | Prompt cache read tokens | | ||
| | `tokens.total_tokens` | Trace | Total tokens across all LLM runs | | ||
|
|
||
| --- | ||
|
|
||
| ## Output Directories | ||
|
|
||
| All output is written locally and gitignored. Directories are organized by date. | ||
|
|
||
| ``` | ||
| evals/ | ||
| runs/ | ||
| YYYY-MM-DD/ | ||
| <run-id>/ one folder per case run | ||
| run.json metadata, timing, exit code | ||
| agent-output.jsonl full agent stream (human debugging only — never a grading input) | ||
| mcp-config.json MCP server config handed to the agent | ||
| logs/ MCP server logs | ||
|
|
||
| suite-runs/ | ||
| YYYY-MM-DD/ | ||
| <suite-run-id>/ | ||
| suite-summary.json aggregate timing and token counts for all cases in the run | ||
|
|
||
| grades/ | ||
| YYYY-MM-DD/ | ||
| <run-id>/ | ||
| bird-result.json per-case grading output | ||
| <suite-run-id>/ | ||
| suite-grade.json aggregate grading output for a full suite run | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## LangSmith Integration | ||
|
|
||
| Grading reads tool coverage, metrics, and the agent's final message **from the LangSmith trace** — it is the single source of truth. If no trace is posted for a run, `grade.ts`/`grade-bird.ts` return `grading_error`, so a working LangSmith setup is required to grade. | ||
|
|
||
| The trace is posted by the coding-agent's LangSmith tracing plugin, not by this harness directly. For Claude Code, install the [langsmith-tracing plugin](https://github.com/langchain-ai/langsmith-claude-code-plugins); the adapter sets the `LANGSMITH_*`/`CC_LANGSMITH_*` environment for the agent subprocess, but the plugin must be installed for a trace to actually be posted. Setting `LANGSMITH_API_KEY` alone is not sufficient. | ||
|
|
||
| Traces are posted to the project set by `LANGSMITH_PROJECT` (default: `tableau-mcp-evals`). Each run is matched to its trace by `eval_run_id`. | ||
|
|
||
| --- | ||
|
|
||
| ## About the BIRD Dataset | ||
|
|
||
| The BIRD (BIg Bench for laRge-scale Database Grounded Text-to-SQL Evaluation) Mini-Dev benchmark is a standard text-to-SQL evaluation dataset. The 30 California Schools questions used here were selected because the underlying database can be represented as a single Tableau published datasource that joins three source tables. | ||
|
|
||
| The suite file at `evals/suites/bird-california-schools.json` ships with precomputed expected answers (row counts, scalar values, and gold answer summaries) so no database access is required to run grading. To regenerate it from the raw BIRD SQLite snapshot: | ||
|
|
||
| ```bash | ||
| python3 evals/scripts/precompute-bird-answers.py | ||
| ``` | ||
|
|
||
| This requires the California Schools SQLite file at `evals/bird_mini/data/dev_databases/california_schools/california_schools.sqlite`. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is the bird benchmark do we know? im trying to google around for it but im not sure im looking at the right thing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A Big Bench for Large-Scale Database Grounded Text-to-SQLs
A benchmark dataset for evaluating how well LLMs can convert natural language questions into SQL queries.