> For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt.

# 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](/product-design/v3/tasks-feature/task-domain-lifecycle.md) 为产品基准。

这份文档是给 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 Smoke | `contacts-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 Rehearsal     | revenue / retention / safety objective 从 transcript facts 到 task proposal 是否可审查、可复现         | `callytics-infrastructure/scripts/revenue-rehearsal/*`                                      |

## 1. 怎么选要跑哪一套

| 你改了什么 / 想验证什么                                                                                  | 应该跑什么                    | 原因                                                               |
| ---------------------------------------------------------------------------------------------- | ------------------------ | ---------------------------------------------------------------- |
| `contacts-analyzer` prompt、`ContactsAnalysisSchema`、task decision policy、model config、taxonomy | Task Golden Eval         | 真实模型 + production prompt + production Zod schema，验证 decision 没变坏 |
| writer、`applyTaskAction()`、Policy Guard、DB constraint、task persistence                         | DB 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 objective                                           | Revenue Rehearsal        | 用 transcript-style scenario 产出 reviewer-readable report          |
| 想从 transcript 往后跑真实 staging path                                                               | Revenue Staging Injector | dry-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 Eval      |   61 | `lambda/contacts-analyzer/scripts/golden-eval/cases.ts`             | `create_open` 11、`create_closed` 8、`close` 13、`record_progress` 9、`update` 8、`negative_noop` 5、`safety` 7 |
| Demo candidates       |   10 | 同上，`demoCandidate` metadata                                         | demo 前只从稳定通过且非 `knownGap` 的 case 里挑                                                                       |
| Known gaps            |    1 | 同上，`knownGap` marker                                                | runner 照跑照报，但不计入 exit code                                                                                |
| DB Replay             |   13 | `test/integration/contacts-analyzer-db-replay.integration.test.ts`  | representative writer / Policy Guard / DB constraints cases                                               |
| Call Input Smoke      |    9 | `lambda/ai-analysis-processor/scripts/call-accuracy-smoke/cases.ts` | 8 个 `classify` model cases，1 个 `prompt_only` case                                                         |
| Contact Context Smoke |   10 | `lambda/contacts-analyzer/scripts/contact-context-smoke/cases.ts`   | contacts / messages / leads / tasks / progress context                                                    |
| Revenue Rehearsal     |   12 | `scripts/revenue-rehearsal/cases.ts`                                | 14 个 expected task decisions，覆盖 intro、upgrade、referral、cancel、payment、DNC                                 |

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

```bash
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。

本地跑：

```bash
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`：

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

场景评审文档目前在 [Baseline v1 Scenario Review](/ai/product/task-accuracy/baseline-v1-scenario-review.md)。如果 `cases.ts` 变了，先重新生成 review Markdown，让产品确认 `existingState / newEvidence / expected / notExpected / rationaleZh`，再跑真实模型。

## 4. DB Replay 怎么跑

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

```bash
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：

```bash
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：

```bash
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：

```bash
npm run eval:input-smoke
```

对应解释文档：

- [Call Input Smoke](/ai/product/call-accuracy/input-smoke.md)
- [Contact Context Smoke](/ai/product/contact-accuracy/input-smoke.md)

## 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 行为。

```bash
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，不写库：

```bash
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：

```bash
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=prod`、`environment=production` 或 SSM param 含 `/prod/` 时，injector 必须拒绝运行。

更完整的背景见 [Revenue Rehearsal Playbook](/ai/product/task-accuracy/revenue-rehearsal-playbook.md)。

## 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；如果指定 `bucket` 或 `case`，只跑选中的范围。workflow artifact 会上传 `eval-results.json` / `eval-output.txt` 或 `smoke-results.json` / `smoke-output.txt`。Lark card 由 `scripts/lark-notify.ts` 消费 JSON result 生成。

## 8. Peter review 时看什么

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

1. 先看 [Baseline v1 Design](/ai/product/task-accuracy/baseline-v1-design.md)：确认我们为什么把 eval 拆成 Golden Eval、DB Replay、Input Smoke。
2. 再看 [Baseline v1 Scenario Review](/ai/product/task-accuracy/baseline-v1-scenario-review.md)：确认每个 Task Golden Eval case 的业务期望是否对。
3. 对 revenue demo 看 [Revenue Rehearsal Playbook](/ai/product/task-accuracy/revenue-rehearsal-playbook.md)：确认 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 是否连续稳定通过，而不是单次运气好。
