Task Prompt Architecture And Agent Evolution
Current legacy prompt architecture(2026-07-15):本文的 push/pull context、schema/writer 分层和 self-check 方法仍可参考;Objective-first、
create_closed lead_follow_up、Category Matrix 与 globalcloseResult不是 Target。现行 Task/AI runtime contract 见 Task System Design V3。
0. 一句话
retaintive 是一台 把客户那边发生的任何事,翻译成该达成的目标、该做的事 的机器。
- 发生的事 = call、SMS、voicemail、lead form;以后还会有 Salesforce、Slack、email、web form。
- 翻出来的 = 今天主要是
taskDecisions[]/task;产品上正在演进成更稳定的objective。 - 中间那层翻译 = AI 做判断,但 AI 只提出 proposal,不拥有最终写入权。
所以所有 AI/task 设计争议,本质都是同一个问题:这台翻译机该信什么、谁说了算。
本文记录两件事:
- 今天怎么系统性改
contacts-analyzerprompt,不再盲改。 - 未来怎么从
pushcontext 走向pullcontext / self-check agent,但不在底座没稳时上 agent。
1. 当前现实:一个 call,内部分层
当前 contacts-analyzer 还没有拆成两个 AI call。runtime 仍然是一个 combined prompt,一次输出:
- contact profile fields
taskDecisions[]
但是 prompt 内部必须按职责分层:
当前 combined system prompt 应该按这个顺序组织:
在 code 里对应:
2. System prompt / user prompt / schema / writer 分工
关键规则:
- prompt 说
MUST不够;如果字段是最终写入必需,schema、fallback、writer 必须合起来保证它不会以坏状态落库。 - schema 不是永远越严越好。对模型常见但可确定修复的半成品输出,例如 fieldless
update,schema 可以先放行,让 deterministic fallback 有机会修成record_progress/close/ validupdate。 - schema 通过不代表业务正确;writer / Policy Guard 仍然要二次校验。
- user prompt 只是事实输入,不应该塞长期 policy。
- stale contact snapshot 是 context,不是 fresh task intent 的硬 gate。
3. Contact 和 Task 的边界
Contact 回答:
Task 回答:
Shared / Evidence Authority 回答:
重要边界:
例子:
booked = terminal是 lead first-booking lifecycle 的 contact 规则。- 但如果最新 interaction 里 new lead 当场 booked,且没有 open task,task 层仍应
create_closed lead_follow_up/booked记 ledger。 - 如果已经有 open
lead_follow_up,则close T1 booked,不是create_closed。
4. Prompt 里必须有什么
每次改 contacts-analyzer prompt,都检查这些 section 是否存在且职责清楚:
5. Taxonomy 使用原则
taxonomy 的 source of truth 是 code/common,不是 prompt 手写文本。
在 callytics-infrastructure 里:
- Task taxonomy 从
@retaintive/common/db和@retaintive/common/taxonomy/task动态注入。 - Contact taxonomy 从
@retaintive/common/taxonomy/contact动态注入。 - Prompt 只应该写“怎么用 taxonomy 做判断”,不要复制第二份 enum/definition。
如果发现 taxonomy definition 本身太薄,例如:
referral不够说明 guest pass / friend details / referral credit 边界。renewal不够说明 payment recovery vs freeze expiry。retention不够说明 complaint / billing dispute / service issue。
正确动作:
不要只在 prompt 里 patch 一句,因为那会让别的 consumer 继续吃旧 taxonomy。
6. 怎么避免信息重复
目标不是“同一个词永远不能出现两次”,而是每层不抢职责。
合理重复:
这是 contract chain,不是重复。
不合理重复:
- contact section 讲完整 task state machine。
- task section 重写 full lifecycle profile policy。
- user prompt 注入长期 business policy。
- prompt 手写复制 common taxonomy。
- examples 试图覆盖所有 enum 全排列。
7. Prompt accuracy 修改流程
Phase 1:还原现状,不改东西
先回答“AI 到底看到了什么”:
- 拼出当前 assembled
system prompt。 - 找出
userMessage实际包含哪些字段。 - 确认
Zod schema对输出有什么 admission rule 和硬约束。 - 看 deterministic fallback 和 writer / Policy Guard 怎么消费 output。
- 画出当前链路。
常看代码:
Phase 2:按层拆问题
每个问题都要归因到一层:
Phase 3:先写结构,再写文字
不要直接 patch 一句。先说明要改哪个 section:
Phase 4:用 eval failures 验证结构
每个失败 case 用这个模板:
重点看这些模式:
create_closed被输出成[]。- referral 边界弱。
record_progressvsupdate混。update选对了但缺suggestedActions。- stale contact snapshot 静默压掉 fresh task intent。
Phase 5:改 runtime prompt / schema
改动顺序:
- 修改 section text。
- 区分 model-facing output contract 和 schema admission policy:最终合法输出要清楚,但 schema 不要过早挡住 fallback 可修复的模型输出。
- 如果 required/optional 或 schema admission 变了,同步改
models.ts。 - 同步 generated output contract。
- bump prompt version。
- regenerate assembled prompt snapshot。
- 跑 unit tests。
- 跑 real-model eval。
常用命令:
8. 未来方向:从 push context 到 pull context
一句话:
把 task 系统从「push,一次性把所有信息塞满 prompt」演进成「pull,AI 按需调 read tools 自取上下文」,并加一个独立自检 agent 评估 task 生成得对不对。
状态:
- 方向已定。
- 技术可行性已确认到平台层。
- 不在当前 mega PR scope。
- 必须等
2026-06-21-task-system-redesign-plan.md的门禁 + 模型 B +task_sources底座落地后启动。
硬约束:
起因
现在 contacts-analyzer 生成任务时,把 contact profile、open tasks、policy、call facts、history 一起塞进 prompt。Max 的真实怀疑是:
想要的是:
- 给 AI 一组只读接口 / tools,例如 read contact、read task history、read call facts、read messages。
- AI 自己决定需要什么 context 就调什么 tool。
- 另起一个只读 self-check agent,评估 task 是否生成正确,把人工 track 的工作自动化。
术语对照:
9. 技术可行性和 caveat
平台层可行:
重要 nuance:
generateObject+ giant context 是 push。generateText/ tool loop + read tools 是 pull。- 迁移不是改一个参数,而是换调用模式、加 loop、定义 tool schemas、加 cost/timeout/trace。
- 不需要从零造 agent runtime;用现有 Lambda + Vercel AI SDK loop + OpenRouter 即可试水。
- 不需要引入 MCP。MCP 是给外部 AI client 接入;这是产品内 AI,function-calling 足够。
启动前必须做一个 staging smoke:
原因:官方文档说明机制支持 tool calling,不等于我们选定的模型 / provider / output schema 组合在多轮 loop 上稳定。
参考:
- Vercel AI SDK
generateText: https://ai-sdk.dev/docs/reference/ai-sdk-core/generate-text - Vercel AI SDK tools: https://ai-sdk.dev/docs/ai-sdk-core/tools-and-tool-calling
- OpenRouter tool calling: https://openrouter.ai/docs/guides/features/tool-calling
- OpenRouter AI SDK provider: https://github.com/OpenRouterTeam/ai-sdk-provider
- DeepSeek tool calls: https://api-docs.deepseek.com/guides/tool_calls
10. Self-check and pull-context agents
Self-Check Agent(独立自检 agent):先做
做什么:
为什么先做它:
- 只读,不碰生产写库路径。
- 直接解决当前痛点:人工逐条看 task 是否对。
- 用低风险场景验证 tool-calling loop、trace、cost、timeout。
- 它属于 Eval / Replay / Observability 层,不改核心生成管道。
输出不应该直接改 task。它应该输出:
Pull-Context Generation Agent(生成时自取上下文):后做
做什么:
为什么后做:
- 它动核心生成管道。
- 它解决“怎么取上下文”,不解决“判断逻辑对不对”。
- 如果门禁和 state machine 还错,pull context 只会让错误更难 debug。
- 先用 self-check agent 验证 loop,再上核心生成路径。
11. 顺序
CTO 判断:
- 门禁是地基。地基错时上 agent,会把不稳定放大。
- self-check agent 是低风险 tool-calling 试水点。
- generation agent 动核心管道,等底座稳定再上。
12. 启动时再细化的设计
13. Recipe label mapping
recipeLabel 不是构想。traceplane 里已经有基础实现,可以作为未来 eval/agent recipe versioning 的参考。
当前行为:
recipes存具体版本,主键是project_id + target + version。recipe_labels存 label 映射,主键是project_id + target + label,值是version。- 运行时解析优先级:如果请求传
recipeVersion,直接按版本取;否则按recipeLabel ?? "prod"查 label。 - 保存 recipe 时:
POST /v1/recipes?label=prod会保存版本,并写入 label -> version 映射。
代码位置:
还没产品化的部分:
- candidate -> prod 的发布 / 晋级 workflow。
- rollback。
- audit UI。
- approval policy。
- cost / usage view。
14. 不做什么
明确排除:
- 当前底座 mega PR 不含 agent / tool-calling 代码。
- 不从零造 agent runtime。
- 不引入 MCP 作为产品内 AI 的第一实现。
- 不在门禁修复前上 Pull-Context Generation Agent。
- 不让 self-check agent 写 production DB。
- 不让 prompt 手写复制 taxonomy。
15. 给未来 AI agent 的执行口令
当未来 agent 被要求“提高 task prompt 准确率”时,必须先做:
If the agent cannot explain what the model sees and which layer owns the rule, it is not allowed to patch prompt text.