Prompt 架构与接入规则
这份文档回答:"prompt 里应该写什么?哪些东西应该放 Zod / schema / common constants?怎么把 final output contract 给 AI?prompt 接入 production 前怎么 review?"
后端 pipeline 全景见 2-backend.md。本页只讲 prompt 架构。
1. 六层职责模型
一个 AI decision 不应该只靠一份 prompt 兜住。正确 mental model 是 6 层:
核心规则:
- 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。
最终标准:
也就是说:
@retaintive/commonregistry 负责保存 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 相关依赖。
File-level rule:
values.tsanswers "what values are allowed?" It owns value tuples, taxonomy topology, and constrained subsets such asAI_ASSIGNABLE_TASK_TYPE_CATEGORIES。definitions.tsanswers "what do these values mean to AI / docs?" It explains values fromvalues.ts; it should not invent new enum values。index.tsis 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 intaxonomy/<domain>/definitions.ts。 - Output shape is not taxonomy。Final JSON shape remains in downstream Zod schemas such as
ContactsAnalysisSchema,TriageOutputSchema, andClassifyOutputSchema。
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:
TaskDecisiondiscriminated union insideContactsAnalysisSchema。 - 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、
taskIdexistence、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 的内容:
- Role / objective — 这次 AI 节点在业务上要完成什么。
- Input contract — user message 会给哪些数据;哪些字段可信度高;哪些是 read-only context。
- Output ownership / hard boundary — 这个 prompt 输出什么,绝不输出什么。
- Rendered taxonomy definitions — 从 registry render 出来的 enum 业务含义,例如什么是
intro_booking,什么是lead_follow_up,什么是record_progress。 - Decision rules — 在什么证据下选择哪个 category / action / closeResult。
- Evidence priority — structured fields、transcript、SMS、lead records、existing task history 之间冲突时谁优先。
- Examples / counterexamples — 尤其是容易混的边界:already booked vs intro booking,attempted close vs record progress,retention vs cancellation risk。
- Hallucination rules — 不 invent prices、promotions、attendance、billing status、taskId、prior promises。
- 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 像表格模板,也会让后续插入新段落更笨重。推荐用表达职责的自然标题。
特殊 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。
含义:
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、字段短描述。
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。
这里说的是“什么时候用哪个 action / category”,不是手写一份 50 行 output schema。renderTaskTypeDefinitions() 可以在内部决定这次 render 全部 core taxonomy,还是只 render relevant subset。
5.4 One LLM call: schema / system / prompt 的区别
在 Vercel AI SDK 的 generateObject() 里,这三个参数最容易混:
用 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 都会变差。
对应关系:
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)。
模型理想输出:
然后 Zod parse。parse 不过就 retry / fail,不能进 DB。
5.5 Deterministic code:最后真正执行
即使 AI 输出了合法 JSON,代码还要检查:
所以 AI 不是“直接写 DB”。AI 只是提案,code 决定能不能执行。
6. Current Structured Output Boundary
当前 shared AI helper 使用 Vercel AI SDK + OpenRouter:
这意味着:
- 当前档位是 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/
- OpenRouter Structured Outputs: https://openrouter.ai/docs/features/structured-outputs
- OpenRouter Provider Routing: https://openrouter.ai/docs/features/provider-routing
- 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 文件拆:
-
callytics-commonregistry 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。
-
callytics-infrastructureconsume 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。
-
retaintive/docsdocs 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/commonconstants / 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 产出数据架构。