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

# Prompt 架构与接入规则

> 这份文档回答:"prompt 里应该写什么?哪些东西应该放 Zod / schema / common constants?怎么把 final output contract 给 AI?prompt 接入 production 前怎么 review?"
>
> 后端 pipeline 全景见 [2-backend.md](/architecture/2-backend.md)。本页只讲 prompt 架构。

***

## 1. 六层职责模型

一个 AI decision 不应该只靠一份 prompt 兜住。正确 mental model 是 6 层:

| 层                                    | 负责什么                                                                                                                        | 不负责什么                                             | 例子                                                                                                                     |
| ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| Taxonomy registry / common constants | 系统允许哪些 canonical business terms,以及这些词的官方定义                                                                                  | 不负责输出 JSON shape;不直接等于 prompt 文本                  | `@retaintive/common/taxonomy/task`, `@retaintive/common/taxonomy/contact`, `@retaintive/common/taxonomy/call-analysis` |
| Zod / JSON Schema                    | final output shape、required / optional / nullability、enum、discriminated union、字段短描述、array cap                               | 不负责复杂业务判断                                         | `ContactsAnalysisSchema`, `TaskDecision`                                                                               |
| Prompt                               | 业务判断规则、从 registry render 出来的 taxonomy definitions、证据优先级、hard boundary、examples / counterexamples、不要 hallucinate             | 不手写第二份 final output schema;不维护 registry 的第二份 copy | 什么时候 `create_open`,什么时候 `record_progress`,什么是 `intro_booking`                                                          |
| LLM call / assembly layer            | 把 system prompt、user input、Zod schema、model config 拼到一次或多次 call                                                             | 不直接执行业务写入                                         | `generateObject({ schema: zodSchema, system, prompt })`                                                                |
| Deterministic code / Orchestrator    | DNC、`taskId` 是否存在、tenant / store scope、duplicate open task、idempotency、DB transaction、`sourceCallId` 注入、priority derivation | 不靠 AI 自觉遵守安全边界                                    | Task Orchestrator / repository guard                                                                                   |
| Eval / Observability                 | 记录 prompt/schema/model/provider/version,统计 validation failure / retry,支持 golden eval 和 replay                               | 不代替 runtime guard;不直接改变 DB 写入                     | `ai_usage` logs、prompt version、schema version、golden fixtures                                                          |

核心规则:

- **Prompt file 是 business policy,不是 final schema source of truth**。
- **Final output contract 来自 Zod / common constants**。如果 prompt 里需要展示 output contract,也应该由同一份 schema / constants 生成,不要手写第二份。
- **Definition 的 source 在 registry,prompt 里出现的是 rendered taxonomy section**。AI 需要看到 enum / category 的业务含义,但这些 definition 不应该散落在 prompt 文件里手写。
- **Canonical enum definitions 跟 enum values 一起放 `@retaintive/common`**。如果一个 value 已经被 DB schema、domain policy、UI、prompt 共用,它的基础定义也应该在 common;Lambda prompt module 只负责 render 和补充 prompt-specific policy。
- **Section count 和 LLM call count 分开设计**。文本可以拆,call 不一定拆。
- **Draft prompt 是业务文案来源**。不能直接 replace production prompt;必须先过 schema audit。

最终标准:

```ts
const systemPrompt = [
  ROLE_AND_OBJECTIVE,
  renderTaxonomyDefinitions(TAXONOMY_REGISTRY),
  DECISION_RULES,
  EXAMPLES_AND_COUNTEREXAMPLES,
  OUTPUT_CONTRACT_REMINDER,
].join('\n\n');
```

也就是说:

- `@retaintive/common` registry 负责保存 canonical values + definitions。
- prompt builder 负责把 relevant definitions render 进 system prompt。
- Zod schema 负责 final output contract。
- LLM call 同时传 `systemPrompt` 和 `zodSchema`。
- Eval / observability 负责告诉我们 prompt/schema/model 改动后有没有变好或变坏。

### 1.1 Common Taxonomy Directory Organization

`@retaintive/common` 的 shared AI vocabulary 按 domain 拆成三条 focused taxonomy subpath。root barrel `@retaintive/common/taxonomy` 只做 compatibility / broad re-export；Lambda prompt builder 应优先 import focused subpath,避免 call-only 代码顺手拉入 task/db/UI 相关依赖。

```text
src/taxonomy/
├── index.ts                  # compatibility barrel; prefer focused subpaths
├── call-analysis/
│   ├── values.ts             # allowed call-analysis values / taxonomy shape
│   ├── definitions.ts        # AI-facing meanings for those values
│   └── index.ts              # @retaintive/common/taxonomy/call-analysis
├── contact/
│   ├── values.ts             # lifecycle / leadStatus / purchaseIntent values
│   ├── definitions.ts        # AI-facing meanings and mappings
│   └── index.ts              # @retaintive/common/taxonomy/contact
└── task/
    ├── values.ts             # task enum exports + AI-assignable subset
    ├── definitions.ts        # AI-facing meanings for task vocabulary
    └── index.ts              # @retaintive/common/taxonomy/task
```

File-level rule:

- **`values.ts`** answers "what values are allowed?" It owns value tuples, taxonomy topology, and constrained subsets such as `AI_ASSIGNABLE_TASK_TYPE_CATEGORIES`。
- **`definitions.ts`** answers "what do these values mean to AI / docs?" It explains values from `values.ts`; it should not invent new enum values。
- **`index.ts`** is the public export surface for that taxonomy domain。
- **UI copy is not AI taxonomy**。Frontend labels/descriptions such as dropdown text can live in UI metadata modules like `task-ui.ts`; prompt-facing definitions live in `taxonomy/<domain>/definitions.ts`。
- **Output shape is not taxonomy**。Final JSON shape remains in downstream Zod schemas such as `ContactsAnalysisSchema`, `TriageOutputSchema`, and `ClassifyOutputSchema`。

***

## 2. 当前 AI Output Contract Lines

现在的 prompt registry 不是只服务 task。代码里至少有三条 AI output contract line,它们要共享同一套 ownership model。

### 2.1 Call-Level AI: `ai-analysis-processor`

- **输出落点**: calls / call-analysis records。
- **Final schema**: `CallAnalysisSchema`。
- **Stage schemas**: `TriageOutputSchema`, `ClassifyOutputSchema`, `VerifyOutputSchema`, `CoachingOutputSchema`。
- **Shared taxonomy source**: `@retaintive/common/taxonomy/call-analysis`。
- **应该从 common render 进 prompt 的内容**: call state、customer type、primary category、34 个 subcategory leaves、outcome、follow-up reason、revenue priority 的 definitions。
- **Prompt 仍然负责**: 如何根据 transcript evidence 选择 category/subcategory/outcome,confusion-pair boundary,coaching judgment。

### 2.2 Contact-Level AI: `contacts-analyzer`

- **输出落点**: contacts 表。
- **Final schema**: `ContactsAnalysisSchema`。
- **关键 AI fields**: `customerSummary`, `actionNeeded`, `suggestedActions`, `leadStatus`, `purchaseIntent`, `goals`, `lifecycleStage`, `lifecycleState`, `doNotContact`, `hasOpenComplaint`, `customerFirstName`, `customerLastName`。
- **Shared taxonomy source**: `@retaintive/common/taxonomy/contact`。
- **应该从 common render 进 prompt 的内容**: contact lifecycle stage/state、lead status、lead-status-to-lifecycle-state mapping、purchase intent definitions。
- **Prompt 仍然负责**: lifecycle 判断规则、DNC interpretation、unknown/vendor/corporate boundary、summary writing quality、evidence priority。

### 2.3 Task-Level AI: `contacts-analyzer.taskDecisions[]`

- **输出落点**: AI proposes mutations; deterministic code writes tasks / task progress events。
- **Final schema**: `TaskDecision` discriminated union inside `ContactsAnalysisSchema`。
- **Shared taxonomy source**: `@retaintive/common/taxonomy/task`。Task DB enum values still originate in `@retaintive/common/db`; task taxonomy re-exports values and owns definitions / AI-assignable categories。
- **应该从 common render 进 prompt 的内容**: task `typeCategory`, `closeResult`, `progressType`, `channel`, AI-assignable task categories。
- **Prompt 仍然负责**: when to `create_open`, `close`, `update`, `record_progress`, evidence thresholds, suggested action writing rules。
- **Deterministic code 仍然负责**: DNC guard、tenant/store/contact scope、`taskId` existence、duplicate open task、idempotency、DB transaction。

***

## 3. Prompt 应该包含什么

Prompt 不是只能写 "business rules" 四个字。它应该包含 AI 做判断需要的业务语义,包括 enum / category 的 definition。区别在于:definition 的 source 应该在 registry,然后由 prompt builder render 进 prompt;不要散落在 6 份 prompt 里手抄。

应该放进 prompt 的内容:

1. **Role / objective** — 这次 AI 节点在业务上要完成什么。
2. **Input contract** — user message 会给哪些数据;哪些字段可信度高;哪些是 read-only context。
3. **Output ownership / hard boundary** — 这个 prompt 输出什么,绝不输出什么。
4. **Rendered taxonomy definitions** — 从 registry render 出来的 enum 业务含义,例如什么是 `intro_booking`,什么是 `lead_follow_up`,什么是 `record_progress`。
5. **Decision rules** — 在什么证据下选择哪个 category / action / closeResult。
6. **Evidence priority** — structured fields、transcript、SMS、lead records、existing task history 之间冲突时谁优先。
7. **Examples / counterexamples** — 尤其是容易混的边界:already booked vs intro booking,attempted close vs record progress,retention vs cancellation risk。
8. **Hallucination rules** — 不 invent prices、promotions、attendance、billing status、taskId、prior promises。
9. **Output reminder** — 提醒 "Return JSON matching the provided schema",可以附 generated concise contract,但不要手写完整 schema。

不应该放进 prompt 的内容:

- 手写完整 final JSON schema,尤其是 action shape / enum list / optional-nullable 规则。
- tenant / store / DNC / taskId safety guard 的最终判断。
- DB transaction、idempotency、source id 注入、priority derivation。
- 会被 common schema / registry 更新打破的复制粘贴 enum list 或 definition copy。
- code 已经能 deterministic 推导的字段。

***

## 4. Standard Prompt Template

不是每个 prompt 都必须机械套满所有标题;但接入 production 前,至少要能解释每一段落在下面哪个职责里。标题不需要写 `SECTION 1:` / `SECTION 2:`;编号会让 prompt 像表格模板,也会让后续插入新段落更笨重。推荐用表达职责的自然标题。

```text
# <Prompt Name>

## Role And Objective
- You are ...
- This prompt decides ...
- This prompt is used by ...

## Input Contract And Evidence Priority
- You will receive ...
- Treat structured fields as ...
- Treat transcript / SMS / voicemail as ...
- If signals conflict, prioritize ...

## Output Ownership And Hard Boundary
- This prompt outputs ...
- This prompt MUST NOT output ...
- Downstream code / another prompt owns ...

## Generated Taxonomy Definitions
- Render from registry; do not hand-write a second copy.
- <enum_value>: <business meaning>
- <enum_value>: <business meaning>
- Contrast cases:
  - Use X when ...
  - Do NOT use X when ...

## Decision Rules
- Create / classify / close / coach when ...
- Do not create / classify / close / coach when ...
- If existing state says ..., then ...

## Examples And Counterexamples
- Example: input signal -> expected decision -> reason
- Counterexample: similar-looking signal -> do NOT choose X -> reason

## Hallucination And Safety Rules
- Do not invent ...
- Only reference IDs shown in input ...
- If uncertain, ...

## Uncertainty And Fallback Rules
- If evidence is insufficient, choose the conservative no-mutation / omit-optional-field path.
- Do not fabricate missing IDs or missing facts to satisfy the schema.
- Runtime retry / reject behavior belongs to the AI helper and validator, not this prompt.

## Output Contract Reminder
- Return ONLY JSON matching the provided schema.
- Do not include markdown or commentary.
- Optional fields should be omitted unless evidence exists.
- Generated concise contract may be inserted here from Zod/common constants.
```

特殊 cases:

- **Read-only brain**(例如 Coaching Brain):不需要 output contract section,但必须标明 "read-only knowledge; does not output JSON"。
- **Task Decision**:必须有 action boundary、existing task handling、progress vs update vs close 的 contrast examples。
- **Contact Profile**:必须有 lifecycle taxonomy、leadStatus mapping、DNC / unknown / churned boundary。
- **Classification**:必须有 category / subcategory / topic\_type 的 compatibility rules,最好由 deterministic mapping 或 schema test 支撑。

渲染策略:

- **Small core taxonomy**:全部 render。比如 task type category、close result、progress type 这类核心 enum 数量少,放进 prompt 稳定且 cacheable。
- **Large playbook / tenant-specific rules**:按需 render subset。不要把几百条 playbook 或 tenant config 全塞进 every call。
- **Output contract**:只 render concise reminder 或 generated contract;full validation 仍由 Zod / JSON Schema 负责。

放置规则:

- **`@retaintive/common`**:canonical enum values、shared definitions、deterministic mappings、policy guard helpers。
- **Lambda prompt module**:把 common registry render 成 model-facing section,并放 prompt-specific examples / counterexamples / stage ownership。
- **Prompt text**:只接收 rendered result,不要维护 shared definition 的第二份 copy。

***

## 5. 极简例子:Staff Task 决策如何分层

假设只做一个极简任务:分析一通电话后,决定要不要创建 / 更新一个 staff task。这个例子不是 production 代码,而是说明 prompt / schema / code 的职责边界。

### 5.1 Taxonomy registry:统一 enum + definition

这部分不写在 prompt 里手动维护,而是代码 registry。真实系统里,DB/domain enum value 已经在 `@retaintive/common/db`,对应的 canonical definition 也应该放在 `@retaintive/common/taxonomy/<domain>`(例如 `@retaintive/common/taxonomy/task`),然后由各 Lambda prompt builder render 进 prompt。

```ts
const TASK_TYPE_CATEGORY = [
  'lead_follow_up',
  'retention',
] as const;

const TASK_TYPE_CATEGORY_DEFINITIONS = {
  lead_follow_up:
    'Lead is not booked yet and staff can still move them toward booking.',
  retention:
    'Member has unresolved complaint, service issue, or reliable retention risk.',
} as const;

const TASK_PROGRESS_TYPE = [
  'no_answer',
  'left_voicemail',
  'text_sent',
] as const;
```

含义:

- `TASK_TYPE_CATEGORY` / `TASK_PROGRESS_TYPE` 给 schema 和 code 用,限制合法值。
- `TASK_TYPE_CATEGORY_DEFINITIONS` 给 prompt 用,解释每个值什么时候该选。
- 以后 enum 或 definition 变了,改 registry,不要去 6 个 prompt 里搜字符串。

### 5.2 Zod schema:最终 output contract

这层定义 AI 最终必须输出什么。这里放机器能检查的东西:字段名、action 类型、enum、array cap、required / optional / nullability、字段短描述。

```ts
import { z } from 'zod';

const TaskDecisionSchema = z.discriminatedUnion('action', [
  z.object({
    action: z.literal('create_open'),
    typeCategory: z.enum(TASK_TYPE_CATEGORY),
    reason: z.string().describe('Why staff follow-up is needed'),
  }),

  z.object({
    action: z.literal('record_progress'),
    taskId: z.string(),
    progressType: z.enum(TASK_PROGRESS_TYPE),
    reason: z.string().describe('What happened during this attempt'),
  }),
]);

const OutputSchema = z.object({
  taskDecisions: z.array(TaskDecisionSchema).max(5).default([]),
});
```

Zod schema 会检查输出是否合法,但不会替 AI 完成业务判断。比如它知道 `lead_follow_up` 是合法值,但不知道 "already booked confirmation" 不应该创建 `lead_follow_up` task;这个判断要在 prompt policy 或 deterministic guard 里表达。

### 5.3 System prompt:固定业务判断 + rendered enum definition

`system` 是相对固定的工作手册。它告诉 AI:你是谁、负责什么、证据怎么排优先级、什么时候用哪个 action / category、哪些东西不能编造。它可以包含从 taxonomy registry render 出来的 definitions,但不要手写完整 final output schema。

```ts
const systemPrompt = `
You decide staff task mutations for a gym CRM.

Task type definitions:
${renderTaskTypeDefinitions(TASK_TYPE_CATEGORY_DEFINITIONS)}

Rules:
- Use create_open only when there is a new unresolved customer objective and no matching open task.
- Use record_progress when staff attempted contact but the objective is still unresolved.
- Do not create tasks for routine booking confirmation.
- Do not invent prices, promotions, attendance, billing status, or taskId.
- Return JSON matching the provided output schema.
`;
```

这里说的是“什么时候用哪个 action / category”,不是手写一份 50 行 output schema。`renderTaskTypeDefinitions()` 可以在内部决定这次 render 全部 core taxonomy,还是只 render relevant subset。

### 5.4 One LLM call: `schema` / `system` / `prompt` 的区别

在 Vercel AI SDK 的 `generateObject()` 里,这三个参数最容易混:

| 参数       | 一句话                | 变化频率                    | 类比             |
| -------- | ------------------ | ----------------------- | -------------- |
| `schema` | AI 最终必须交什么格式的 JSON | 相对固定,随代码发布变             | 标准表格           |
| `system` | AI 应该怎么判断、遵守哪些业务规则 | 相对固定,随 prompt version 变 | 员工工作手册         |
| `prompt` | 这一次要分析的具体事实和上下文    | 每次 call 都变              | 今天递给员工的工单 / 便签 |

用 contacts-analyzer 的 task decision 举例:

- `schema` 规定输出只能是 `create_open` / `record_progress` 等合法 action,字段名必须对,`progressType` 必须来自 enum。
- `system` 规定业务判断:已经有 matching open task 时不要重复创建;员工只是留了 voicemail 时应该 `record_progress`;不要编造 `taskId`、价格、促销、billing status。
- `prompt` 放动态数据:这家店叫什么、店电话是什么、这个客户是谁、当前有哪些 open tasks、最近一通电话或短信到底发生了什么。

所以你说的“店的电话号码、店名等等”属于 `prompt` 这一层,因为它们是每次调用变化的 input snapshot。它们不应该写进 `system`,否则 system prompt 会跟着每个 store/customer 变,cache 和 eval 都会变差。

```ts
const { object } = await generateObject({
  model: openrouter('deepseek/deepseek-v4-flash'),
  schema: OutputSchema,
  system: systemPrompt,
  prompt: `
STORE:
- storeId: 7d4a...
- storeName: West Loop Fitness
- storePhone: +1-312-555-0100

CONTACT:
- contactPhone: +1-312-555-0199
- lifecycleStage: lead
- lifecycleState: active

OPEN TASKS:
- ref: T1
- typeCategory: lead_follow_up
- status: open
- reason: Lead booked an intro but has not purchased membership.

LATEST CALL:
Staff called the lead from +1-312-555-0100. The lead did not answer.
Staff left a voicemail asking them to call back about their intro booking.
`,
});
```

对应关系:

- `schema: OutputSchema` = final output contract。机器用它 validate AI 输出;它回答“最终 JSON 长什么样?”。
- `system: systemPrompt` = stable business policy + taxonomy definitions + examples。它回答“AI 应该怎么判断?”。
- `prompt: ...` = per-call dynamic data。它回答“这一次发生了什么?这家店 / 这个客户 / 这些 open tasks 是什么?”。
- `TASK_TYPE_CATEGORY` / `TASK_TYPE_CATEGORY_DEFINITIONS` = taxonomy registry,通常在 call 前被用来生成 `OutputSchema` 和 `systemPrompt`。

在上面的例子里,AI 理想上不应该创建新 task,因为 `prompt` 已经告诉它有一个 matching open task `T1`。它应该输出 `record_progress`,把“本次电话留了 voicemail”记录到已有 task。

> open task 在 `prompt` 里渲染为顺序**短引用**(`T1`、`T2`...),模型只回引用,代码验证后翻译回真实 UUID —— 模型从不接触/回写 UUID(机制见 §10)。

模型理想输出:

```json
{
  "taskDecisions": [
    {
      "action": "record_progress",
      "taskRef": "T1",
      "progressType": "left_voicemail",
      "reason": "Staff attempted follow-up and left a voicemail; the lead objective is still unresolved."
    }
  ]
}
```

然后 Zod parse。parse 不过就 retry / fail,不能进 DB。

### 5.5 Deterministic code:最后真正执行

即使 AI 输出了合法 JSON,代码还要检查:

```ts
for (const decision of output.taskDecisions) {
  assertNotDnc(contactPhone);

  if (decision.action === 'record_progress') {
    assertTaskBelongsToContact(decision.taskId);
    assertTaskIsOpen(decision.taskId);
    assertSameStore(decision.taskId, storeId);
  }

  if (decision.action === 'create_open') {
    assertNoMatchingOpenTask(decision.typeCategory, contactId);
  }

  applyTaskAction(decision);
}
```

所以 AI 不是“直接写 DB”。AI 只是提案,code 决定能不能执行。

***

## 6. Current Structured Output Boundary

当前 shared AI helper 使用 Vercel AI SDK + OpenRouter:

```ts
generateObject({
  schema: zodSchema,
  mode: 'json',
  system: opts.systemPrompt,
  prompt: opts.userMessage,
});
```

这意味着:

- 当前档位是 JSON mode + Zod validation。它能把 schema 信息给模型,并在客户端做 parse / validation。
- 这不是 strict JSON Schema constrained decoding。严格 `json_schema` 模式要另行评估 provider support 和 `oneOf` / discriminated union 限制。
- `deepseek/deepseek-v4-flash` 可以继续用于当前档位;OpenRouter Models API 显示这个模型整体支持 `response_format` / `structured_outputs`,但具体 endpoint 支持不完全一致,所以 production 仍然必须保留 Zod validation / retry。

原则:

- **JSON mode + Zod validation + retry 是当前 DeepSeek / OpenRouter 路径的 mandatory reliability floor,不是可选 cleanup。**
- 不要直接押宝 strict schema。先保持 `generateObject + Zod parse`,把 prompt 里的手写 output schema 改成“从 Zod / common constants 生成的简短 contract”。这样 drift 最少,也最符合当前代码。
- AI SDK 6 已支持 `generateText` + `Output.object` 形式的 structured output,也支持 multi-step tool loop 末尾生成 structured output。当前代码仍使用 `generateObject`;未来如果 contacts/task flow 变成 agentic flow,可以评估迁移,但不要把这当成当前事实。

参考:

- DeepSeek JSON Output: [https://api-docs.deepseek.com/guides/json\_mode/](https://api-docs.deepseek.com/guides/json_mode/)
- OpenRouter Structured Outputs: [https://openrouter.ai/docs/features/structured-outputs](https://openrouter.ai/docs/features/structured-outputs)
- OpenRouter Provider Routing: [https://openrouter.ai/docs/features/provider-routing](https://openrouter.ai/docs/features/provider-routing)
- AI SDK 6: [https://vercel.com/blog/ai-sdk-6](https://vercel.com/blog/ai-sdk-6)

***

## 7. Eval And Observability

Prompt 架构不只看 prompt 文本能不能读懂,还要能回答:"这次 prompt / schema / model 改动后,质量有没有变好?"

每个 production AI call 应尽量记录:

- prompt identity: prompt name、prompt version / hash、rendered taxonomy version。
- schema identity: Zod schema name、schema version / common package version。
- model identity: model id、provider、provider routing result。
- reliability signals: JSON parse failure、Zod validation failure、retry count、repair count、finish reason、latency、token usage。
- replay keys: input snapshot reference、output object、validation error summary、downstream mutation result。

每次改 prompt / taxonomy / output schema 前后,至少跑:

- **Golden eval set**:典型输入固定 expected output,用于保护正常业务路径。
- **Safety counterexamples**:DNC、wrong `taskId`、tenant / store mismatch、already booked no task、routine confirmation no task 等边界样本。
- **Drift tests**:generated taxonomy 和 registry 一致;stale terms absent;read-only section 不输出 mutation fields。

***

## 8. Current Rollout Plan

当前落地顺序应该按 source-of-truth 边界拆,不是按单个 prompt 文件拆:

1. **`callytics-common` registry foundation**
   - 添加 task/contact/call shared definitions。
   - 添加 focused exports: `@retaintive/common/taxonomy/task`, `@retaintive/common/taxonomy/contact`, `@retaintive/common/taxonomy/call-analysis`。
   - 添加 drift tests:每个 enum value 都有 definition,没有 stale keys。
   - 不改 prompt,不改 LLM behavior。

2. **`callytics-infrastructure` consume generated sections**
   - contacts prompt consume common task/contact taxonomy sections from focused taxonomy subpaths。
   - ai-analysis classify prompt consume common call taxonomy section from `@retaintive/common/taxonomy/call-analysis`。
   - triage/classify/verify/coaching/contact analyzer 都追加 generated output contract reminder。
   - 不接入 6 个 draft prompt,不改变 LLM call count。

3. **`retaintive/docs` docs sync**
   - public docs 和 infra spec 同步记录 ownership model。

下一轮才适合做 **Prompt Content Quality Mega PR**:逐个迁移 / 改写 6 个 draft prompt,并针对 prompt open issues 做业务判断和 examples/counterexamples。

***

## 9. 接入前 Schema Audit Checklist

每份 prompt draft wire 进 production 前,至少检查:

- **Input**: prompt 声明的 input section 名和 code 实际 user message 一致。
- **Output schema**: prompt 输出字段落在对应 Zod schema 内;optional / nullable 语义一致。
- **Enum vocabulary**: prompt 里的 enum values 和 canonical definitions 来自 `@retaintive/common` constants / registry 或其 generated taxonomy;没有 stale copy。
- **Action boundary**: create / close / update / record\_progress / reopen 等 action 名和 live schema 一致。
- **Responsibility boundary**: prompt 不承担 DNC final guard、tenant/store guard、taskId existence、duplicate guard、idempotency。
- **Examples**: 每个高风险边界至少一个 positive example 和一个 counterexample。
- **Drift tests**: enum present、stale terms absent、generated taxonomy matches registry、read-only section 不输出 mutation fields。
- **Golden eval set**: 典型输入固定 expected output,覆盖最常见 create / update / close / no-op 路径。
- **Safety counterexamples**: DNC、wrong `taskId`、tenant / store mismatch、already booked no task、routine confirmation no task 等高风险边界。

***

## 10. 落地状态与决策追加(2026-06-10)

本文档的架构在 2026-06 已基本落地,以下是状态快照与本文未覆盖的新决策(执行细节以 callytics-infrastructure 的 roadmap spec 为准):

- **Prompt 物理文件化已 ship**:两个 Lambda 的 prompt 文本拆为独立 section 文件(domain folders:contact/ + task/),组装顺序只活在 surface manifest;**组装后的完整 prompt 以 golden snapshot 形式 checked-in** — 任何内容 PR 的 review diff 直接显示模型可见的变化。这是本文 §4 模板的物理载体,也是未来外置存储(S3 / DB)的迁移单元。
- **taskId 短引用机制**:模型不再接触/回写真实 UUID — open tasks 渲染为顺序短引用(T1、T2...),模型只回引用,代码验证后翻译回真 id;UUID 输出即编造,schema 层硬拒。§5.4 示例已采用该写法(`ref: T1` 输入、`taskRef: "T1"` 输出)。实测根除了 UUID 抄串(eval 6 轮零坏引用)。
- **referral 语义闭环**:taxonomy definitions 收窄为纯推荐语义(去掉 event/corporate/promotion 杂烩),close result 定义为 task 级完成态(拿到推荐联系人 / 被推荐人到访 / 权益处理完成),非 revenue attribution。
- **已确认的模型行为弱点(修复方向已定)**:决策保守性 no-op — 该 close / record\_progress 时输出空数组(LLM "不愿破例"的已知现象)。修法不是逐句补丁:因果化指令(解释不行动的业务后果)+ 每个高风险边界正/反例对照(§9 checklist 的 Examples 项)。
- **场景化指导注入(新决策)**:按确定性预选信号(open task 类别 / lead 状态 / 最近通话子类)把相关 playbook 片段注入 **user message**(system prompt 保持字节稳定,cache 不碎);品牌专属内容短期 hardcode map,长期归 per-tenant pack。
- **数据层闭环**:AI 产出的存储架构(append-only / 反应层 / 修正对 / provenance)见 [AI 产出数据架构](/system-design/ai-output-data-architecture.md)。
