Task Pipeline 设计 Brief

Historical design brief(2026-07-23 校准):这是 2026-05 的设计任务书,不是当前 implementation specification。保留用于理解历史问题;当前 Task V2 parity 和 Task V2+ 路线见 工程审计与实施基线,Task V3 设计仍待评估。

这是什么: 给新 session 的设计任务。不是 session 总结,不是 bug 修复清单。 日期: 2026-05-30 前序工作: 2026-05-29 做了 task 生命周期调研(代码 + Neon 数据 + 业界对比),产出了 gap 分析文档和场景覆盖度。细节在材料里,这份 brief 只给方向。


你要做什么

设计 retaintive task pipeline 的架构:代码层和 prompt 层各自负责什么、怎么配合。

这是一个 system design 任务,不是修 bug 或补字段。你的角色:一个精通 AI 技术的 Principal Engineer / AI Engineer——选最贴合这个任务的角色来思考。


Expected Output

新 session 完成后应该交付这些:

  1. 代码 vs prompt 职责矩阵 — 每个决策点(触发/分类/关闭/没打通/playbook)标清楚谁负责 + 为什么
  2. 现状 vs 设计后 workflow 图 — 围绕职责划分画,不是围绕数据存储
  3. architecture recommendation — 基于上下游理解 + 业界校准,给出推荐的 pipeline 设计方案
  4. gap 分析文档更新 — 把职责划分设计写回 task-lifecycle-gap-analysis.md 最上面
  5. 需要改的代码/prompt 清单 — 具体到文件和改动方向(不是行号级,是设计级)
  6. API-first / AI-agent-readable 视角 — 反向从未来 API / CLI / OAuth / AI agent 调用方需要什么数据来验证 schema 和 workflow 设计,说明 task / progress / timeline 应该怎么被外部读取和写入

不是写代码。是设计 + Max review 后才执行。

呈现要求: 产出必须让不在这个 session 里的人(Vivian / Oliver / Peter)也能10分钟看懂核心结论。具体:每个交付物先用一句话说结论,再展开细节;用表格和图而不是长段落;技术细节不省略但要有层次(先 what + why,想看 how 再往下读)。不要 over-simplify(丢掉关键 nuance),也不要绕来绕去(读完不知道在说什么)。

Design Acceptance Criteria

设计合格的标准(不满足就不算完成):

  • 必须回答:task 到底只是待办清单(还没做的事),还是也兼做业绩记录(当场做成的事也要记),还是一个统一的事项对象(两者都能表达)。不能含糊
  • 每个"谁负责"的 recommendation 必须说明:为什么不是放在另一层做
  • 必须覆盖至少这些关键场景:lead no answer / intro booked / cancel saved / complaint resolved / DNC / inbound 当场成交 / SMS meaningful reply / 跨门店同号码
  • 必须区分Phase 1 必做future-compatible 设计(现在不做但架构要兼容的),不要混在一起

Non-goals (这次设计明确不做的)

  • ❌ 不设计完整 SMS pipeline — 只定义 task pipeline 预留给 SMS 的接口和触发点
  • ❌ 不重做 dashboard 指标体系 — 只定义 task lifecycle 对 metrics 的影响
  • ❌ 不设计 AI voice agent 产品 — 只确保 executorType / actor / confidence 等字段能兼容未来 AI 接管
  • ❌ 不做 production rollout 方案
  • ❌ 不改代码、不跑写入型 DB 操作、不 push、不 PR

必须显式回答的冲突问题

brief 里有几组方向天然有张力。不要默认调和,每个都逐一给出明确结论 + 理由:

  1. "每个当场办成的事都是 task" vs "业界通常 conversion funnel 不是 completed task" — 兼有可行吗?怎么兼有?
  2. "只提醒一次" vs "没打通还要回头再试" — 提醒一次是指"不重复建 task"还是"真的只打一次"?
  3. "AI 判断更灵活 / long term scale" vs "代码状态机必须 deterministic" — 哪些判断给 AI 哪些给代码,边界在哪?
  4. "SMS 不想触发 AI" vs "有意义 SMS 可能需要即时跟进" — 怎么定义"有意义"?
  5. "task 是待办" vs "task 是业绩记录" — 一个对象能同时承担两个语义吗?会不会污染其中一个?
  6. activity(打了电话) vs task progress(联系到了) vs business outcome(签约了) — 这三层是不是不同的概念,该不该压在同一个 task 对象上?

怎么做

Step 1: 先理解整个系统的上下游

不要直接看 task。 先读 architecture 文档,理解:

  • 一通电话从进来到最终产生业务结果,整条链怎么走
  • 数据从 RingCentral → 转录 → AI 分析 → 写入各表 → 前端展示,每一步谁做的
  • task 在这条链里处于什么位置,它的上游(谁触发它)和下游(谁消费它)是什么
  • 环境区分: test 环境和 prod 环境不同。test 环境做了全面改造 (DynamoDB → Neon 等),prod 很多功能还没有。以 test 环境为准

所有代码都在本地 /Users/maxwsy/workspace/retaintive.code-workspace,先读代码再读文档。参考:

  • docs/architecture/0-system-overview.md — 系统全景
  • docs/architecture/2-backend.md — 后端数据管道(含通话分析)
  • docs/team-ops/repo-overview.md — 所有 repo 职责 + 技术栈
  • callytics-infrastructure/lambda/ai-analysis-processor/src/core/stages/pipeline.ts — per-call AI pipeline 编排(Pre-triage → Triage → Classify → Coaching)
  • callytics-infrastructure/lambda/contacts-analyzer/src/core/prompt-builder.ts — contact analysis prompt(1040 行,SECTION 4 是 task 决策逻辑)

Step 2: 从全局判断 task 的角色

理解了上下游之后,回答:

  • task 在这个系统里到底是什么?是”待办清单”还是”业绩记录”还是两者兼有?Max 的初步构思:两者兼有——既是待办清单,也能直接 mark 成完成(比如一通电话当场完成就直接标 closed)成为业绩记录。这个想法不一定对,建议 web search 看 competitors 怎么做,验证后再定。
  • 现在 task 的生成/关闭逻辑,放在系统的哪个环节是合理的?当前放置的位置对不对,还是应该重新设计?从正确性出发,不要因为现在是这样就继续这样走。 都在 test 环境,什么都可以改,有 AI 辅助改起来快。
  • prompt 和代码各自的能力边界在哪——哪些判断只有 AI 能做(需要理解通话内容),哪些是确定性的规则(代码就能做)?设计要 long term 能 scale:硬编码确定性规则以后改起来复杂。AI 时代要考虑 AI 的 capability(可以搜最新的),未来可能用 AI agent。design 要能 long term scale,不要设计成只适合当下。

Step 3: 设计代码 vs prompt 的职责划分

这是核心交付。要回答的具体问题:

决策该谁负责为什么现状怎么做的
要不要触发 task 流程?
建什么类型的 task?
当场完成建不建 task?
没打通怎么处理?
task 的 priority / suggestedActions?
什么时候关闭 task?
Playbook (员工执行指南)?

现状的问题:代码和 prompt 的职责混在一起。比如 close.ts:199 用代码硬编码了"没打通 → 关掉重建",但这个判断可能该由 AI 做;prompt 又硬规则禁止了"当场完成建 task",但这可能是产品规则该在代码层控制。这条线要重新划。

Step 4: 画 pipeline workflow 图

画出来的图应该围绕代码 vs prompt 的职责划分,不是围绕"数据存哪个表"。每个节点标清楚:这一步是代码控制还是 prompt 控制。

画两张:现状(代码和 prompt 混着来)vs 设计后(职责清晰)。

Step 5: 从 API / AI agent 视角反推数据模型

除了给前端页面用,task pipeline 最终也要能被外部系统和 AI agent 可靠调用。设计时要从 API contract 反向验证数据模型:

  • 未来可能会有 OAuth API、CLI、第三方集成、AI agent(Codex / Claude Code / customer-owned agent)读取或操作 task。
  • 不要只问"数据库怎么存",还要问"外部调用方怎么一眼读懂这个 task 现在是什么状态、尝试过几次、下一步该做什么、最终结果是什么"。
  • 需要明确 tasks / task progress / contact_timeline 各自的职责:
    • tasks: 当前业务事项对象和最终 outcome
    • task progress / attempt: 每次执行进展(no answer / voicemail / text sent / callback requested 等)
    • contact_timeline: contact 维度统一时间线和审计
  • 如果建议新增 task_progress_events 或类似结构,必须说明它和 contact_timeline 的关系:谁是 source of truth,谁是 projection / audit feed,发生一次 progress update 时两边怎么写。
  • 需要草拟 high-level API shape,例如:
    • GET /tasks/:taskId 返回 task snapshot
    • GET /tasks/:taskId/progress 返回 task progress history
    • POST /tasks/:taskId/progress 记录 no-answer / voicemail / text-sent / callback 等进展
    • POST /tasks/:taskId/close 只记录 business outcome
    • GET /contacts/:contactId/timeline 返回跨实体时间线
    • GET /contacts/:contactId/work-objects 给 AI agent 一次性读取 open/closed objectives + recent progress + next action context
  • 对比竞品 API / object model 时,要查官方 API 文档或产品文档,看 HubSpot / Salesforce / Salesloft / Outreach / Mindbody / ABC 等怎么表达 task、activity、call disposition、timeline、outcome。
  • 竞品只是校准,不是答案。很多旧 CRM/API 设计来自 AI 不成熟、人工录入、LLM 成本高的时代。要识别他们的历史包袱,再决定 retaintive 在 2026 AI-native 场景下应该怎么做得更清晰。

Step 6: 更新 gap 分析文档

把设计结论写回 docs/product-design/v2/tasks-feature/task-lifecycle-gap-analysis.md。这份文档已有 schema 对照、场景覆盖度、业界对比——需要在最上面加上"代码 vs prompt 职责"这个维度的设计。


思考方式

像一个懂 AI 的 principal engineer 那样思考。 不是在修一个现有系统的 bug,是在设计一个 AI + 代码混合的架构。要考虑:

  • AI 和代码各自擅长什么:AI 擅长理解语义/判断意图/处理模糊情况;代码擅长执行确定性规则/保证幂等/控制状态机。把对的事交给对的层。
  • 上下游协调:改了 task pipeline 的某个环节,对上游(per-call AI / lead-tracking)和下游(前端展示 / dashboard 指标 / 未来 AI 化)有什么影响?
  • 成本:每次调 AI 有 LLM 成本。什么时候值得花钱调 AI 判断,什么时候用代码规则就够了?
  • 未来 AI 化:现在前台手动做的事(打电话/选 close result/写 note),以后可能 AI voice agent 来做。现在的架构要给这个过渡留空间,不要设计成只有人能用。
  • API-first / agent-readable:未来不只是前端读这些数据,第三方系统、CLI、OAuth API、AI agent 也会读写 task。schema 和 workflow 要能被 API 稳定表达,而不是只适合当前页面或某个 prompt。
  • 场景 robust:不是技术上的健壮,是符合真实前台使用场景的健壮——系统行为要对得上前台脑子里"我手头有几件事、办完了没"的心智模型。

已知的核心问题(前序调研发现的)

不展开,只列要点。细节在材料里。不要逐个解决这些小问题——做好顶层设计,这些问题会同时被解决。以面破题,不以点破题。

  1. 当场完成 = 零 task: prompt 禁止当场建 task,但产品需要每个办成的事都记为 task
  2. 没打通 = 关掉重建: 代码硬编码的,前台心智不对齐,task 数虚增
  3. disposition 和 outcome 混在一个字段: close_result 18 值混了"打通没"和"办成没",业界全部分开。disposition 其实已经在 calls.callState 里有了
  4. 前端 close dropdown 缺 2 个值: booked/cancelled schema 有但 UI 没有,Neon 里 AI 已写入 29 条
  5. Core Productivity metric 有 bug: denominator 让 rate 恒≈100%

Max 在前序 session 表达的方向

这些是他的想法和倾向,不是 finalized spec:

  • 每个当场办成的事都是一个 task(签约/book intro/cancel save/resolve/reschedule)
  • 一个任务只提醒一次,不要关掉重建
  • 只管打电话 + SMS,不管走进店里的。SMS 还没想好
  • 没打通要分情况:lead 更重要
  • 店长战绩 = 完成多少 task (superset) → 其中多少签约/挽留 (subset)
  • 未来要 AI 化:人做的操作以后 AI 做
  • 代码和 prompt 的职责要想清楚再动手
  • 整个 flow 对比应该围绕"代码 vs prompt 职责划分"画,不是围绕"数据存哪"
  • 要先从 high level 理解整个系统上下游,再看 task 这一块怎么设计

材料清单

只有代码是 source of truth。其余都是不同人在不同时间的想法,不一定对。

A. 代码 (✅ Source of Truth)

文件看什么
callytics-common/src/db/schema/tasks.tstask 表 27 字段 + close_result 18 值 + CHECK 约束
callytics-common/src/db/schema/task-ui.tsCLOSE_RESULT_OPTIONS 16 项 + TYPE_CATEGORY_OPTIONS 9 项
callytics-common/src/db/schema/calls.tscallState (disposition) + primaryOutcomeResult + followUpNeeded
callytics-common/src/db/schema/contacts.tslifecycleStage / leadStatus / doNotContact / actionNeeded
callytics-common/src/db/schema/contact-timeline.ts16 种事件,多态 actor,AI forensic 字段
callytics-common/src/db/schema/playbook-feedback.tshelpful / not_relevant
callytics-infrastructure/.../prompt-builder.tscontact analysis prompt (1040 行) — SECTION 4 是 task 决策逻辑
callytics-infrastructure/.../models.ts:155-184AI 决策 Zod: create / close / update (无 create-as-closed)
callytics-infrastructure/.../neon-repository.ts:702create 硬编码 status='pending'
callytics-infrastructure/.../stages/pipeline.tsper-call AI pipeline 编排
callytics-infrastructure/.../stages/prompts.tsper-call 3 个 system prompt
lead-tracking/src/neon-repository.ts:180-204lead_outreach 建 task 逻辑
studio-website-monorepo/.../tasks/close.ts:199-218员工关闭 + no_answer/left_voicemail 自动重建
studio-website-monorepo/.../dashboard-staff.ts:113-172Core Productivity SQL + denominator bug

B. 架构文档 (读了再开始设计)

文件看什么
docs/architecture/0-system-overview.md系统全景
docs/architecture/2-backend.md后端数据管道(含通话分析上下游)
docs/team-ops/repo-overview.md所有 repo 职责

C. V1 Task Feature 设计文档 (⚠️ 初版设计,不一定错但不够全,现在要改进)

V1 是最初怎么设计 task feature 的思路。不一定错,可能只是不够完整,现在要做更全面的改进。 读它可以理解最初的设计意图。

文件看什么路径
Tasks Overview功能总览 + 定位docs/product-design/v1/tasks-feature/tasks-overview.md
Tasks Spec完整规格docs/product-design/v1/tasks-feature/tasks-spec.md
Task 字段设计字段定义 + 设计决策docs/product-design/v1/tasks-feature/tasks-field-design.md
Task 生命周期生成/更新/关闭机制docs/product-design/v1/tasks-feature/task-lifecycle.md
Task 生命周期 (Prompt 视角)prompt 怎么控制 taskdocs/product-design/v1/tasks-feature/prompt-task-lifecycle.md
Task 与营收归因close_result → revenue 映射docs/product-design/v1/tasks-feature/revenue-attribution.md

D. V2 Task Feature 设计文档 (⚠️ 现版本,schema 对齐后的)

文件看什么路径
Task 字段字典27 字段定义 (对齐 schema)docs/product-design/v2/tasks-feature/tasks-fields.md
Task 枚举清单close_result 18 值 / typeCategory 9 值 等docs/product-design/v2/tasks-feature/task-enums.md
Task 业务规则SLA / 优先级窗口 / 营收归因docs/product-design/v2/tasks-feature/task-business-rules.md
Task 计算配置状态计算 / dueAt 公式 / playbook 数据源docs/product-design/v2/tasks-feature/tasks-calculations.md
Task 页面展示前端 UI 设计 + schema 支持状态docs/product-design/v2/tasks-feature/tasks-display.md

E. 调研产出 (⚠️ AI 产出,Max review 中)

文件看什么
docs/product-design/v2/tasks-feature/task-lifecycle-gap-analysis.md现状 vs ideal 对比 + schema 对照 + 16 场景覆盖度 + 业界对比

F. 参考材料 (⚠️ 不一定对,当参考不当结论)

文件来源说明
~/Downloads/retaintive-contact-task-workflow.html来源未确认(可能是 AI 或队友)task workflow 设计图,9 section。Max 明确说这是别人写的,不一定对
~/Downloads/05-task-playbook-system-prompt.txtOliver V1 草稿第 5 个 prompt,13 scenario。初稿,需和最终设计对齐
~/Downloads/retaintive-mvp-v31-prototype.htmlOliverUI 原型,讨论用
~/Downloads/ui-prototype-mvp-v3(1).htmlVivian旧版原型
prompt-eval/expected_results.json团队测试13 TC,全无 taskDecisions 预期
飞书会议纪要 linkMax+Vivian+Oliver+Peter2026-05-27/28 两场会议共识,不是 spec

G. Neon Test 环境 (✅ 可查真实数据)

  • Project: callytics-test (restless-boat-70724564, us-west-2)
  • 用 Neon MCP 跑 SELECT 验证假设,不写入

H. AWS (✅ 已登录)

  • Account: 237206024479, AdminAccess role
  • 可看 Lambda / CloudWatch,用于验证 prompt 实际输出

I. 前序调研成果 — 分三类: Facts / Hypotheses / Calibration

前一个 session 做了大量调研。这些是校准用的,不是替代你自己思考的答案。 按可信度分成三类:

Facts (已用代码/数据验证,可直接信)

事实验证方式
task 创建只能产 status='pending',没有 create-as-closed 路径neon-repository.ts:702 + models.ts:180
close_result 18 值里混了 3 个 disposition (no_answer/left_voicemail/callback_later)tasks.ts:38-54
disposition 已经在 calls.callState 里有了 (human_conversation/voicemail/no_answer/busy_signal)calls.ts:154
CLOSE_RESULT_OPTIONS (UI) 只有 16 项,缺 booked/cancelledtask-ui.ts:20-37
Neon test: booked 已写入 25 条、cancelled 4 条,AI 在用但前端选不到Neon SELECT
Neon test: 616 closed task 全是 auto_closed, manual_closed=0, closedByStaffName 全是 "system"Neon SELECT
prompt-eval 13 TC 全不包含 taskDecisions 预期——task AI 行为尚无测试覆盖expected_results.json
close.ts:199 硬编码 no_answer → 关旧 task + INSERT 新 task (due 1天后)close.ts:199-218
dashboard-staff.ts:121WHERE closed_by_staff_name IS NOT NULL 吞掉所有 pending task → rate 恒≈100%读代码 + Neon 验证
lead-tracking 建 task: 固定 pending/high/5min SLA, onConflictDoNothing 幂等lead-tracking/neon-repository.ts:180-204

Hypotheses (前序 session 的推断,需要你验证后才能采纳)

假设来源需要验证什么
task 表只需新增 3 个字段 (attemptCount / executorType / closeResultReason)AI 调研结论新 system design 可能发现需要更多或更少
close_result 应移出 3 个 disposition,加 rescheduledAI 调研 + Max 倾向取决于职责划分设计——如果 prompt 管 disposition,可能不需要改 close_result
closeType 应加 create_closed,models.ts 应加 create-as-closed 决策类型AI 调研结论取决于"当场完成"的设计——可能有更好的方案
没打通应改成"同 task + attempt 计数",不关闭业界对比推断取决于代码 vs prompt 职责划分——也许 prompt 判断比代码规则更灵活

Calibration (业界校准,不是答案,是参考坐标系)

web search 是校准用的,不替代系统设计结论。最终判断必须回到 retaintive 的前台心智、数据模型和 pipeline 成本。

校准点业界怎么做来源
disposition vs outcomeSalesforce / Salesloft 分成两个独立字段PhoneIQ · Salesloft
没打通怎么处理呼叫中心用 Task ID 更新原 task,不关闭重建Sprinklr · Outreach
当场成交怎么计计入 conversion funnel,不是 completed task (但 retaintive 想兼有,需要验证可行性)Convoso · Mariana Tek
短通话省 AI 成本Gong 的 minimum duration gateGong
AI + 代码混合架构Temporal 状态机 + LangGraph agentic workflow + human-in-the-loop 模式arXiv · Google Cloud
健身房 CRM 怎么做Mindbody / ABC / Glofox / PushPress 的 task/follow-up 定义各官网

| SMS 触发 AI 的成本控制 | 业界三层 gate: content gate (regex) → batch gate (debounce) → token-tier gate (小 classifier)。但注意:业界 2024 年的做法基于当时 LLM 贵 + 慢的限制,2026 年成本降了 10-50x、小模型 classifier 成熟了(NVIDIA LLM Router 1.75B)。限制变了,解法可能也该变。 设计时要重新思考:SMS 中什么样的内容值得触发分析,而不是照搬"SMS 一律不触发" | Twilio CI · NVIDIA LLM Router · MindStudio | | SMS vs Call 合流分析 | 业界写到同一条 contact record,但触发时机不同。同样要考虑:这个做法可能只是当时技术限制下的妥协,不是最优解。 设计时问:如果成本不是问题,理想的 SMS 分析策略是什么?然后再把成本约束加回来做 trade-off | Twilio · Aloware · RingCentral | | SMS debounce | AWS 原生 MaximumBatchingWindowInSeconds (最长 300 秒),SQS 上设就行 | AWS Lambda batching · n8n |

详细内容在 gap 分析文档的"业界怎么做"段。


前序 session 发现的关键事实(设计时要知道的)

这些不是"要修的 bug 清单",而是你做 system design 时的输入事实——你需要知道系统实际上怎么运作的,才能设计对。

现有 prompt pipeline 怎么触发 task:

  • per-call AI (Layer 1) 分析每通电话,产出 fu=yes/no (follow-up needed) + out=success/attempted/... (outcome)
  • contact analysis (Layer 2, daily batch) 消费 Layer 1 的输出,做跨通话的 contact 级别分析,产出 taskDecisions[] (create/close/update)
  • fu=no + out=success 的组合在当前 prompt 里 = 不建 task (prompt-builder.ts:812, 611-617)
  • 这个 fu= 信号是 AI 对 AI 的传递——Layer 1 的 AI 告诉 Layer 2 的 AI "要不要跟进"

2026-05-31 note: 这里的 Layer 1 / Layer 2 是旧 task 讨论里对 AI signal chain 的叫法,不等同于 Unified Pipeline Architecture 设计 Brief 里的 Layer 1 Shared Mutation / Layer 2 Processing Capability。

task 创建只有 3 条路径:

  1. lead-tracking 直接建 (lead_outreach, 不经 AI)
  2. contact analysis AI 建 (taskDecisions[].create)
  3. 员工手动建 (studio-api)
  • 所有路径都只产 status='pending'。没有"一步建成 closed"的路径

task 关闭有 2 条路径:

  1. AI auto-close (contact analysis 的 taskDecisions[].close,必须引用已有 taskId)
  2. 员工 manual-close (studio-api close.ts)
  • 但 Neon 实测: manual-close 在 test 环境从未被使用过 (0 条)

没打通的硬编码逻辑 (close.ts:199-218):

  • 这段代码不在 prompt 里,是纯代码逻辑
  • 员工在前端选 no_answer → 代码关掉旧 task + 自动 INSERT 一个新 pending task (due 明天)
  • left_voicemail → 同上,due 2 天后
  • 用了 ON CONFLICT DO NOTHING 防重复

前台实际怎么看 task:

  • tasks 页面 3 段式 flow: Why (为什么有这个 task) → Playbook (怎么做) → Action (Update / Close)
  • Update (no answer / voicemail / text sent) 和 Close (converted / not interested / ...) 在 UI 上想分开,但当前后端没有真正的 "status update" 动作——只有 close
  • playbook-panel.vue (223 行) 前端已有,但后端 playbook prompt 没接入

disposition 数据已经在 calls 表里:

  • calls.callState = human_conversation / voicemail / no_answer / busy_signal / system_error
  • calls.result = Accepted / Missed / No Answer / Busy / Voicemail (RingCentral 原始值)
  • calls.primaryOutcomeResult = success / attempted / retained / pending_follow_up / cancelled / na
  • calls.followUpNeeded + calls.followUpReasons = AI 判断的 follow-up 信号
  • 这些都是 per-call 的,已经有了,不需要在 task 表重复存

contact_timeline 的设计:

  • 16 种事件类型,覆盖 task 全生命周期 (task.created / task.status_changed / task.updated / task.due_at_changed / task.note_updated)
  • 多态 actor (system / call_analysis / contact_analysis / staff / lead_webhook)
  • AI forensic 字段 (aiRunId / aiModelUsed / aiConfidence) — 可追溯 AI 为什么做了这个决策
  • 有 entityType + entityId 索引,查某个 task 的事件历史很快

补充维度(设计时别漏)

多门店 / store 级隔离

task 的幂等约束 uq_tasks_pending_contact_category(contactPhone, storeId, typeCategory) 做——同一个客人在不同门店可以有独立的 pending task。contacts 表主键也是 (phone, storeId)。设计 pipeline 时必须考虑:同一个电话号码跨门店的 task 是独立的,不能共享。

前台一天的实际操作流程(场景 robust 的基础)

设计必须对得上前台真实的工作方式,不能只看代码:

  1. 早上开工: 打开系统看待办清单——"今天有哪些客人要跟进"(新 lead 要联系、有人要取消会籍要挽留、有人试课完没签约要追)。每件事有紧迫度(dueAt)。
  2. 白天逐个处理: 挑一件 → 打电话/发短信 → 几种结果:
    • 打通了,当场办成了(签约/约到试课/挽留住/解决了投诉)→ 一件事了结
    • 打通了,没当场办成(客人要考虑/要改时间再打)→ 还没完,记下进展回头来
    • 没打通(没人接/留语音信箱)→ 也没完,回头再试
    • 客人说别再打了(DNC)→ 结束(但不是办成)
  3. 当场来的: 客户直接打进来或走进店里,当场就把事办了(当场签约)——这没经过"待办清单"但是实打实的业绩
  4. 一天结束 / 店长视角: 想知道"今天战绩如何"——完成了几件事、其中几个签约/挽留(superset/subset)

未来 AI agent 的操作流程(设计要兼容)

现在人做的操作以后 AI voice agent 来做。设计时要考虑:

  • AI agent 自动外呼 → 自动判断对话结果 → 自动关闭/更新 task
  • 需要区分"人做的"和"AI 做的"(executorType)
  • 低置信度的 AI 决策需要人工复核(human-in-the-loop)
  • 现在人选的 close_result / 写的 note 是未来训练 AI 的 ground truth

SMS 处理方式

现状: message-processor Lambda 只做存储(RC webhook → Neon),不触发 AI 分析。SMS 消息存入后,等 contacts-analyzer 的下一次 batch run(daily cron 06:00 UTC 或 per-call 触发)才被读到(作为 RECENT MESSAGES 注入 prompt)。

Max 的顾虑: 不想让 SMS 不停 trigger AI scan——一条 "thanks" 不值得花 LLM 成本分析。当前设计通过"不直接触发"解决了成本问题,但引入了 delay(SMS 到了要等 batch run 才分析)。

设计时要思考:

  • 当前"被动等 batch"的方式够不够?还是需要"有意义的 SMS 才触发即时分析"?
  • 如果要即时分析:怎么区分"有意义"(客户回复了有实质内容)vs"无价值"(thanks / ok / emoji / 自动回复)?
  • 有没有 debounce 机制(5 分钟内多条合并)?
  • 业界 2026 怎么做?small model 做前置过滤?

更深层的设计问题: 当前 SMS 和 Call 都汇入同一个 contact analysis(Layer 2)再统一决定 task。这个"先合流再决策"的模式对不对?Call 和 SMS 的信号密度完全不同(一通 5 分钟的电话 vs 一条 "thanks"),但现在走同一个 1040 行的 prompt + 同样的 LLM 成本。是不是应该 call 和 SMS 各自有不同的判断路径/不同的触发条件?competitors 怎么处理多渠道合流?

注意: SMS 还没有完全想清楚,先 focus 电话。但 pipeline 设计要给 SMS 留位置,不能设计成只支持电话。

API / CLI / AI agent 可读性

这次设计还必须考虑未来对外或内部 API 的形状。Retaintive 以后可能让第三方系统、CLI、客户自己的 AI agent、或 Codex / Claude Code 这样的 agent 通过 OAuth/API 读取和操作 task。

设计时要显式回答:

  • 一个外部调用方如何区分:
    • task 当前生命周期状态(pending / closed)
    • task 执行进展(no_answer / left_voicemail / text_sent / callback_requested)
    • 最终业务结果(converted / booked / cancel_saved / issue_resolved / do_not_contact)
  • 如果有 task progress / attempt 事件,它们和 contact_timeline 怎么同步:
    • 是否需要独立 source-of-truth 表(如 task_progress_events)
    • contact_timeline 是否作为 projection / audit feed
    • 同一次 progress update 是否应在一个 transaction 里同时写 progress event、timeline event、task snapshot
  • API 返回应该是给机器可读的结构化对象,而不是要求调用方解析 timeline JSONB 或 prompt 文本。
  • 竞品 API 的做法只能作为校准:旧 CRM 常把 activity/task/call disposition 混在一起,那可能是历史限制,不一定是 AI-native 系统的最佳设计。

设计时要考虑到(high-level,不需要写具体实现)

  • AI 判断失败时的 fallback 策略 — prompt 返回无法解析的结果 / Lambda timeout / Zod 校验不过,代码怎么兜底?这是代码层的核心职责之一
  • contacts-analyzer 有 6 个触发路径 — EventBridge cron / on-demand / P1 followUp / Task close / T5 showed / T6 trialed。设计 pipeline 时要覆盖所有入口,不能只改一条路径
  • 业界做法是参考不是圣经 — 2026 年的技术限制和 2024 年不同(LLM 成本降 10-50x、小模型 classifier 成熟、边缘推理变快)。不要因为"Twilio 这么做"就照搬,要思考他们当时的限制是什么、现在还在不在、有没有更好的方式
  • 并发 / 幂等 / race condition — 这个系统有多条触发路径同时跑:daily batch 和 per-call 可能同时分析同一个 contact;lead-tracking 建 task 的同时 AI 也想建;员工在前端 close 的同时 AI batch 也在 auto-close。设计要说明这些并发场景怎么处理
  • API contract / data access pattern — 设计要说明核心读写路径:task list 怎么快读当前状态、task detail 怎么读 progress history、contact detail 怎么读 timeline、manager metrics 怎么聚合 attempts vs completed objectives、external API/AI agent 怎么读懂同一个事项。
  • 设计边界:如果需要改,什么都可以改 — per-call pipeline / contact analysis / schema / prompt / 前端,都在 scope 内。这是 test 环境,没有"不能碰"的东西

约束

  • 先理解全局再看局部 — 不要直接钻进 task 字段,先把系统上下游走通
  • 先设计再写代码 — 画图、确认逻辑、Max review 之后才动手
  • Code as source of truth — 每个结论先读代码验证,不信文档 narrative
  • 不自动 push/PR — 改完先给 Max review
  • 不要以点破题,以面破题 — 不要逐个修小问题,要做好顶层设计让问题自然消解
  • 从正确性出发 — 不要因为现在是这样就继续这样走,test 环境什么都可以改
  • 保持 high-level — 这是 system design,不是 code review。提"要考虑 error handling / logging",不写具体加在哪行