AI Evaluation Playbook

Current legacy eval operations(2026-07-15):本文说明旧 taskDecisions[] suites 的运行与定位方式;其中 case counts、paths 和 expected vocabulary 都必须以 live test code 复核,不能作为 V3 domain contract。V3 acceptance/eval 以 Task System Design V3 为产品基准。

这份文档是给 Peter 的总入口:我们现在不是只靠人工 spot check,也不是只跑 unit tests。当前 eval 分成几层,每层回答一个不同问题。

回答的问题主要位置
Call Input Smoke单次 call analysis 的 structured facts 有没有喂歪callytics-infrastructure/lambda/ai-analysis-processor/scripts/call-accuracy-smoke/*
Contact Context Smokecontacts-analyzer 看到的 contact-level context 是否完整callytics-infrastructure/lambda/contacts-analyzer/scripts/contact-context-smoke/*
Task Golden Eval真实模型能不能把 context 稳定转成正确的 taskDecisions[]callytics-infrastructure/lambda/contacts-analyzer/scripts/golden-eval/*
DB Replay如果 expected taskDecisions[] 到了 writer,Policy Guard / DB constraints / persisted rows 是否正确callytics-infrastructure/test/integration/contacts-analyzer-db-replay.integration.test.ts
Revenue Rehearsalrevenue / retention / safety objective 从 transcript facts 到 task proposal 是否可审查、可复现callytics-infrastructure/scripts/revenue-rehearsal/*

1. 怎么选要跑哪一套

你改了什么 / 想验证什么应该跑什么原因
contacts-analyzer prompt、ContactsAnalysisSchema、task decision policy、model config、taxonomyTask Golden Eval真实模型 + production prompt + production Zod schema,验证 decision 没变坏
writer、applyTaskAction()、Policy Guard、DB constraint、task persistenceDB Replay不测模型,直接注入 expected taskDecisions[],验证写库安全和落库结果
task 错了,但怀疑是 call analysis 上游 facts 错Call Input Smoke先确认 calls row 和 RECENT CALLS context 没喂错
task 错了,但怀疑 contact snapshot / messages / leads / open tasks context 缺事实Contact Context Smoke先确认 contacts-analyzer user message 看到完整 contact context
demo 或 review revenue / retention / safety objectiveRevenue Rehearsal用 transcript-style scenario 产出 reviewer-readable report
想从 transcript 往后跑真实 staging pathRevenue Staging Injectordry-run 默认,只在显式 --write 且 staging/test Neon SSM param 下写库

核心边界:Golden Eval 测模型判断,DB Replay 测写库安全,Input Smoke 测上游 context,Revenue Rehearsal 测业务 objective 这一层。不要把所有问题都塞进同一个 eval。

2. Cases 在哪里

当前 case inventory 以源码为准。下面数字在 2026-06-22 用 Bun 从对应 cases.ts 直接 import 重新计算。

Suite当前数量Case source主要维度
Task Golden Eval61lambda/contacts-analyzer/scripts/golden-eval/cases.tscreate_open 11、create_closed 8、close 13、record_progress 9、update 8、negative_noop 5、safety 7
Demo candidates10同上,demoCandidate metadatademo 前只从稳定通过且非 knownGap 的 case 里挑
Known gaps1同上,knownGap markerrunner 照跑照报,但不计入 exit code
DB Replay13test/integration/contacts-analyzer-db-replay.integration.test.tsrepresentative writer / Policy Guard / DB constraints cases
Call Input Smoke9lambda/ai-analysis-processor/scripts/call-accuracy-smoke/cases.ts8 个 classify model cases,1 个 prompt_only case
Contact Context Smoke10lambda/contacts-analyzer/scripts/contact-context-smoke/cases.tscontacts / messages / leads / tasks / progress context
Revenue Rehearsal12scripts/revenue-rehearsal/cases.ts14 个 expected task decisions,覆盖 intro、upgrade、referral、cancel、payment、DNC

重新核对 case 数量可以在 callytics-infrastructure 里跑:

bun -e "import { GOLDEN_CASES } from './lambda/contacts-analyzer/scripts/golden-eval/cases.ts'; const by={}; for (const c of GOLDEN_CASES) by[c.review.bucket]=(by[c.review.bucket]||0)+1; console.log({ total: GOLDEN_CASES.length, by });"

bun -e "import { CALL_SMOKE_CASES } from './lambda/ai-analysis-processor/scripts/call-accuracy-smoke/cases.ts'; console.log(CALL_SMOKE_CASES.length);"

bun -e "import { CONTACT_CONTEXT_SMOKE_CASES } from './lambda/contacts-analyzer/scripts/contact-context-smoke/cases.ts'; console.log(CONTACT_CONTEXT_SMOKE_CASES.length);"

bun -e "import { REVENUE_REHEARSAL_CASES } from './scripts/revenue-rehearsal/cases.ts'; console.log(REVENUE_REHEARSAL_CASES.length);"

3. Task Golden Eval 怎么跑

Task Golden Eval 是主要的 model behavior safety net。它用真实模型、真实 production prompt、真实 Zod schema 跑 synthetic cases。它不比对自由文本,只检查结构化字段,例如 action、enum、数组长度、task ref。

本地跑:

cd callytics-infrastructure

# 真实模型运行需要 OPENROUTER_API_KEY。
# 可以从 test env SSM 取,profile 以本机 aws configure list-profiles 为准。
export OPENROUTER_API_KEY=$(AWS_PROFILE=<profile> aws ssm get-parameter \
  --name /callytics/openrouter-api-key --with-decryption \
  --region us-west-2 --query 'Parameter.Value' --output text)

# 快速冒烟:每题 1 次
npm run eval:golden

# Pre-merge 标准:每题 3 次,多数票判定
npm run eval:golden -- --runs 3

# 只跑 demo candidates
npm run eval:golden -- --suite demo --runs 5

# 只跑某个 bucket
npm run eval:golden -- --suite full --bucket close --runs 5

# 只跑某一题
npm run eval:golden -- --case C30-voicemail-records-progress --runs 5

# 输出 machine-readable result,供 Lark card / artifact / debugging 使用
npm run eval:golden -- --suite demo --runs 5 --json eval-results.json

只导出产品评审 Markdown,不调用模型、不需要 OPENROUTER_API_KEY

npm run eval:golden -- --review-md ./tmp/task-accuracy-scenarios.md

场景评审文档目前在 Baseline v1 Scenario Review。如果 cases.ts 变了,先重新生成 review Markdown,让产品确认 existingState / newEvidence / expected / notExpected / rationaleZh,再跑真实模型。

4. DB Replay 怎么跑

DB Replay 不回答“模型会不会自己答对”。它回答的是:如果 expected taskDecisions[] 已经产生,production handler / writer / Policy Guard / Neon 会不会正确处理。

cd callytics-infrastructure

# 需要 NEON_API_KEY / NEON_PROJECT_ID_TEST。
# 测试会使用 synthetic DB rows,不调用模型。
npm run eval:db-replay

适合触发 DB Replay 的改动:

  • applyTaskAction() 或 task orchestrator 行为变化。
  • Policy Guard allowlist / duplicate / DNC / store-match 规则变化。
  • writer 落库、timeline、suggestions、playbooks、progress event 行为变化。
  • DB schema / constraint / index 变化。

5. Input Smoke 怎么跑

Input Smoke 用来把问题分层。task 错的时候,先判断是模型 decision 错,还是上游 facts/context 已经喂错。

Call Input Smoke:

cd callytics-infrastructure

# 默认跑 classify model cases,需要 OPENROUTER_API_KEY。
npm run eval:call-smoke

# 只验证 prompt/context,不调用模型。
npm run eval:call-smoke -- --no-model

# 只跑一题,输出 JSON。
npm run eval:call-smoke -- --case CALL-04 --json call-smoke-results.json

# 导出产品评审 Markdown。
npm run eval:call-smoke -- --review-md ./tmp/call-input-smoke.md

Contact Context Smoke:

cd callytics-infrastructure

# 默认验证 context builder;可加 --model 跑真实模型。
npm run eval:contact-smoke

npm run eval:contact-smoke -- --case CONTACT-08 --json contact-smoke-results.json

npm run eval:contact-smoke -- --model --case CONTACT-08

npm run eval:contact-smoke -- --review-md ./tmp/contact-context-smoke.md

组合跑上游 input smoke:

npm run eval:input-smoke

对应解释文档:

6. Revenue Rehearsal 怎么跑

Revenue Rehearsal 是业务 objective 层的 executable pack。它把 transcript-style scenario、Call AI facts、Contacts Analyzer output、objective policy、task decision、report artifact 串起来,适合 demo 前 review revenue / retention / safety 行为。

cd callytics-infrastructure

# 不调用模型:验证 fixtures/context/report shape。
npm run eval:revenue-rehearsal -- \
  --no-model \
  --json artifacts/revenue-rehearsal/report.json \
  --markdown artifacts/revenue-rehearsal/report.md

# 真实模型模式:验证 prompt + model + fallback 当前表现。
npm run eval:revenue-rehearsal -- \
  --runs 3 \
  --json artifacts/revenue-rehearsal/report.json \
  --markdown artifacts/revenue-rehearsal/report.md

# 只跑一个 case。
npm run eval:revenue-rehearsal -- --case REV-01 --runs 3

Staging transcript injector 从 transcript 往后跑 staging path。默认 dry-run,不写库:

npm run eval:revenue-staging-inject -- \
  --environment staging \
  --store-id <store-id> \
  --store-phone <store-phone> \
  --account-id <account-id> \
  --phone <customer-phone> \
  --transcript-file ./tmp/transcript.txt \
  --json artifacts/revenue-rehearsal/inject.json \
  --markdown artifacts/revenue-rehearsal/inject.md

写 staging/test DB 必须显式 --write,并且传 staging/test Neon SSM param:

npm run eval:revenue-staging-inject -- \
  --environment staging \
  --neon-ssm-param "$NEON_DATABASE_URL_PARAM" \
  --write \
  --store-id <store-id> \
  --store-phone <store-phone> \
  --account-id <account-id> \
  --phone <customer-phone> \
  --transcript-file ./tmp/transcript.txt

安全边界:environment=prodenvironment=production 或 SSM param 含 /prod/ 时,injector 必须拒绝运行。

更完整的背景见 Revenue Rehearsal Playbook

7. GitHub Actions 怎么跑

callytics-infrastructure/.github/workflows/golden-eval-nightly.yml 是线上入口。

Scheduled runs:

  • 每天 13:00 UTC 跑 task-demo demo sentinel:--suite demo --runs 5
  • 同一个 schedule 也跑 full regression bucket matrix:create_open / create_closed / close / record_progress / update / negative_noop / safety,每个 bucket --runs 5

Manual dispatch 支持:

  • task-demo
  • task-full
  • known-gaps
  • call-smoke
  • contact-smoke

手动跑 task-full 时,如果 bucket=all 且没有指定 case,workflow 会走 bucket matrix;如果指定 bucketcase,只跑选中的范围。workflow artifact 会上传 eval-results.json / eval-output.txtsmoke-results.json / smoke-output.txt。Lark card 由 scripts/lark-notify.ts 消费 JSON result 生成。

8. Peter review 时看什么

Peter 不需要先读全部源码。建议按这个顺序 review:

  1. 先看 Baseline v1 Design:确认我们为什么把 eval 拆成 Golden Eval、DB Replay、Input Smoke。
  2. 再看 Baseline v1 Scenario Review:确认每个 Task Golden Eval case 的业务期望是否对。
  3. 对 revenue demo 看 Revenue Rehearsal Playbook:确认 objective、expected behavior、not expected behavior 和 report 是否可审。
  4. 需要追源码时,看本页上面的 code paths 和 runner commands。

重点不是“模型输出看起来合理吗”,而是:

  • facts 有没有进入 prompt。
  • expected decision 是否符合业务 workflow。
  • not expected behavior 是否明确。
  • assertions 是否检查结构化 contract,而不是比对自由文本。
  • high-risk mutation 是否会被 Policy Guard / DB constraints 挡住。
  • demo case 是否连续稳定通过,而不是单次运气好。