Selected work

Making model quality measurable

Evaluation infrastructure for an internal LLM assistant at Apple: the framework, the benchmark behind it, the gates it feeds, and the agent tooling underneath.

Evaluation · Apple

An eval framework for an order-operations assistant

I own the evaluation framework for an internal assistant that answers natural-language questions about orders — payment method, fulfillment status, failure cause, SAP transmission contents — instead of support and QE manually querying four backend services. Built in Python with pytest, asyncio, and pydantic, it scores six dimensions: tool selection, factual accuracy, groundedness, completeness, hallucination, and refusal correctness.

Five of the six are deterministic rather than judge-based. Tool selection is precision, recall, and F1 against the expected tools in the logged call trace. Accuracy runs through typed normalizers — currency, storefront-local dates, order numbers, addresses, enums — then exact compare, which removed a large class of false failures caused by formatting rather than incorrectness. Hallucination is entity and numeric containment against the retrieved service payloads. Only the free-text explanation needs an LLM judge, and that judge is calibrated against the deterministic scorers on items with known ground truth, reported alongside its own agreement rate, and never allowed to gate a build alone.

PythonpytestasynciopydanticLLM-as-a-judgeAnthropic Messages API
Benchmark design

600 items whose answers don't rot

The benchmark covers 600 items over 200 seed orders spanning six storefronts, order types, and payment methods. Golden answers are derived from known order parameters rather than hand-labeled, which makes ground truth reproducible instead of an ongoing annotation cost.

Staleness was the harder problem. Every field is classified immutable or volatile; volatile expected values are re-derived from the services before each run, while a change to an immutable field is surfaced as a data defect rather than quietly absorbed as eval drift. Non-determinism is handled with n=5 sampling and pass-rate scoring instead of pass/fail, plus a tracked consistency metric that isolates unstable items — so eval flakiness never gets reported as a model regression.

Derived golden answersDataset versioningStratified samplingn=5 pass-rateConsistency tracking
CI/CD & quality gates

Gates the team trusts

Evaluation runs inside the pipeline: a stratified 120-item run on every pull request that touches prompts, tool definitions, or model version, and the full 600-item suite nightly. Per-dimension deltas get posted to the PR on pass and fail alike, so the numbers are visible even when nothing is broken.

Gating is tiered — hard failure on hallucination rate, tool-selection F1, and accuracy; warnings on completeness and consistency — after an all-or-nothing gate trained the team to re-run until green. That structure caught a model-version regression where overall accuracy improved while tool-selection F1 fell on multi-tool questions, causing stale data to be reported confidently. The fix was clarifying tool staleness semantics in the tool definitions.

Tiered gatesStratified PR runsNightly suitesRegression detectionGitHub Actions
Agentic & backend surfaces

MCP tooling and the services beneath it

I develop and maintain MCP server integrations for agent tooling, testing tool registration, call routing, malformed-argument handling, error states, and timeout propagation as a suite that runs independently of agent reasoning — because a tool layer that misbehaves should fail its own tests, not show up as a mysterious quality drop upstream.

Underneath that, backend validation is automated across 30+ service clients over gRPC and REST with OpenAPI and YAML-driven specs, covering contract, negative, edge-case, and error-code paths including XML/JSON verification and authentication flows.

MCPMulti-turn tool callinggRPCRESTOpenAPIContract testing

Have something to build?

Open to new challenges and collaborations grounded in real human needs.