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

# Voice Agent 可行性

作者: Max + AI (Claude Opus 4.7) + Codex
日期: 2026-05-25
状态: 调研报告 — 非 implementation plan, 不给时间表
读者: retaintive 团队 (含 non-technical 成员)

> 这份提到 "tenant-scoped tool API" / "capability token" / "control plane" 等架构概念。如果不熟悉 layered vs hexagonal 分层 / ports & adapters / Dependency Inversion / SOLID, 先看 [Backend 架构 Pattern](/system-design/backend-patterns.md)。

***

## 这份文档要回答什么

Max 看到 Chowbus / Toast 在做 AI 接电话, 想知道:

1. 市面上 AI 接打电话产品是怎么做的, 自研还是接第三方
2. retaintive 未来从 "AI 帮员工建任务" 演进到 "AI 自己打 / 接电话", 难度多大
3. 多店运营时怎么保证数据不串
4. 现有 backend 够不够, 缺什么
5. 晚上下班场景具体怎么跑

***

## 一句话结论

有条件推荐做, 但不是马上做。

retaintive 起步比绝大多数 SaaS 容易。多租户隔离 / Deepgram + LLM pipeline / 21 张 Neon 表 / 权威 phone→store 映射这些底子已经跑生产, 同档对手是 Chowbus (cloud-native + 数据 pipeline 完备, $209M Series E), 不是 ABCPOS 那种 legacy POS。

工程上中等不难 — 接 Vapi 或 Retell + 暴露 tenant-scoped tool API + 加一张 session 表 + 改 calling hours 引擎。不需要重写 backend, 不需要造新 pipeline。

合规上真的难。TCPA (FCC 2024 把 AI 合成语音明确纳入监管) + FTC click-cancel rule + 两方录音同意州法。这部分不能跳, 不能事后补, 必须从一开始进架构设计。

产品上风险中等。第一次上线 AI 接电话, 店主对品牌第一接触点的信任度容易被一次翻车毁掉。必须 1 店试点 + 老板能开关 + 通话可 review。

什么时候做: 前端展示阶段做完后再启动。现在不动代码。

定位接受重新 framing — 第一阶段不做 booking / sales / outbound, 只做 AI 接电话 + 留信息 + 合规路由。当成 "替员工值夜班接电话留信息", 不是 "AI receptionist 自主决策"。

***

## 市场全景

### 按层分谁在做这件事

底层 voice 基础设施 — Twilio, LiveKit, Deepgram, ElevenLabs, Cartesia, OpenAI Realtime API

中层通用 platform (帮你把底层拼起来, 给开发者用) — Vapi, Bland AI, Retell AI, Synthflow, Pipecat

上层垂直 app —

- 餐厅: Loman, Bite Buddy, Slang.ai, NeverClosed, SoundHound (drive-thru), PolyAI (enterprise)
- 健身房: CallSphere, Dograh, Whippy, JustCall, Capture Client
- POS 巨头自带: Toast IQ (Toast POS), Chowbus AI Digital Worker

### 几乎没人自研底层

自己造一个生产级 voice agent 要 $800K-2M, 12-24 个月。接第三方 platform 是 $0.05-0.20/min, 数天上线。2024 年 42% 的企业 AI 项目放弃 (2023 是 17%), 主因低估自研复杂度。

垂直 SaaS (餐厅 / 健身房 / 医疗) 100% 站在中层 platform 之上, 只控制行业 prompt + 集成 + workflow。retaintive 没理由例外。

### Retell 不是最强

标价 $0.07/min 是钓鱼, 全套配齐实际 $0.25-0.33/min。没有 visual builder, 改流程要工程师。没有 RBAC / audit trail / ISO 27001。非企业用户只有 Discord / email 支持。

按 retaintive 场景选不同 trade-off:

- 最快上线试水选 Vapi (最 dev-friendly, free tier 够 POC)
- 跑量 outbound 选 Bland AI (per-minute 价格便宜 30-50%)
- 低延迟做预约选 Retell (600ms latency 行业最低)
- no-code 让运营改选 Synthflow

***

## 典型技术栈

绝大多数 2026 垂直 AI voice 产品的组合:

```
Telephony            STT              LLM                   TTS                  Orchestration
─────────           ───────          ──────                ──────────           ──────────────
Twilio          →   Deepgram     →   GPT-5 / Claude   →   ElevenLabs       →   Vapi
ConversationRelay   Nova-3           OpenAI Realtime      Cartesia Sonic-3      或 Retell
                                                          OpenAI TTS            或 LiveKit Agents
                                                                                或 Pipecat
```

latency 标杆:

- 700ms 以下 — 听感对话流畅
- 700-900ms — 用户察觉延迟
- 900ms 以上 — 用户挂电话

retaintive 走外呼必须打到 700ms 以内。

***

## retaintive 现有代码现状

### 系统架构 (现在长这样)

```
RingCentral → ringcentralSubscriptionService (webhook receiver)
            → SQS (telephony + message queue)
            → callytics-infrastructure (Lambda factory)
                ├── transcribe-processor → Deepgram nova-2-phonecall + Whisper batch
                ├── ai-analysis-processor → LLM (triage / classify / coaching)
                ├── contacts-analyzer → contact-level aggregation
                ├── neon-sync → DynamoDB → Neon
                └── lead-processor / message-processor
            → DynamoDB (call-analysis, call-events, MessageStore, LeadTracking-v2)
            → Neon PostgreSQL (21 张表)
            → studio-website-monorepo (Hono API + Vue 3 frontend)
            → Cloudflare Pages (studio.retaintive.ai)
```

### Store-level 隔离已落地

来源: `docs/system-design/store-level-isolation.md` (2026-04-14 定稿, PR #277 2026-04-28 切换完成, \~99.7% 填充率)

| 概念             | 值                      | 角色                               |
| -------------- | ---------------------- | -------------------------------- |
| `store_id`     | UUID, retaintive 生成    | 唯一隔离键, 所有查询 `WHERE store_id = ?` |
| `account_id`   | RC OAuth ownerId       | 性能分区 + 安全网, 不做隔离                 |
| `franchise_id` | 硬编码 (`"orangeTheory"`) | 品牌标识, 无隔离价值                      |
| `store_phone`  | E.164 phone            | 审计字段, 不做隔离                       |

加了 `store_id NOT NULL` 的表: calls / contacts / leads / tasks / phone\_numbers / operating\_schedules / messages / staff / contact\_timeline。

`rc_store_phones` 是 phone → store\_id 的权威映射。Prod 数据 2026-05-25 query 结果: 78 phone / 78 distinct / 13 store / 0 dup。每个 phone 唯一映射一个 store。

### 现有数据可以直接喂给 voice agent

读完 schema 后, voice agent 需要的 "店内 context" retaintive 几乎都有现成:

| Voice agent 要回答 | 数据已在哪                                                                            |
| --------------- | -------------------------------------------------------------------------------- |
| 会员价多少           | `store_config.pricing` (JSONB, 支持 intro offers / class packs / membership tiers) |
| 营业时间            | `operating_schedules.schedule` (per-day open/close + effective\_date)            |
| 明天 10am 有空吗     | `operating_schedules` + `blackout_periods` (节假日 / 特殊关店)                          |
| 你们是哪家店          | `rc_stores.name` + `store_config.alias`                                          |
| 我之前打过电话吗        | `contacts` 表 (`WHERE phone AND store_id`)                                        |
| 我是 lead 吗       | `leads` 表                                                                        |
| 我有过失约吗          | `tasks` 表                                                                        |

voice agent 主要工作不是写新业务逻辑, 而是: 拼一个 store context bundle endpoint 聚合上面 6-7 个数据源 + 把 system prompt 模板化 + 暴露 3-5 个 tool 给 voice 平台调。

### studio-api 已有 multi-tenant 基础

`apps/api/src/utils/store-authorization-neon.ts` 的 `getAuthorizedStoreNeon(userId, storeId)` 用一个 SQL 验证用户对 store 的权限。21 个 route 模块全部按 store scope 设计。JWT auth + tracing + error-handler 三层 middleware 就位。

voice agent 拿 storeId 调 studio-api 现有 endpoint = 0 重构。但当前 endpoint 都是 JWT-scoped 给前端用, voice partner 不能直接用 — 见 §endpoint 现状。

retaintive 的 CI 数据是真正护城河。voice agent 拿到的不是 "通用健身房 prompt", 是 "Devon 店今晚营业到 10pm + intro offer $49 + 这个号码上周打过电话问过价 + Sarah 是 manager + 明早 9-11am 空" 这种 store-specific live context。CallSphere / Dograh / Whippy 这些通用 voice 平台拿不到这层。

***

## 多租户隔离设计

Max 最关心的问题。retaintive 已有 store\_id 隔离是基础, voice agent 加一层。

### Inbound 解析链路

```
客户拨 +16104403480 (Devon 店的号码)
  ↓
RC 接通 + 录音 + webhook 到 ringcentralSubscriptionService
  ↓
voice agent gateway 接到 inbound call (RC SIP forward 或 Twilio bridge)
  ↓
voice agent 启动前调 retaintive API:
  POST /v3/voice-agent/inbound-context
  body: { calledNumber: "+16104403480", callerNumber: "+12125559999" }
  ↓
retaintive API 执行:
  1. resolvePhoneIdentity → 查 rc_store_phones 拿 storeId
  2. 查 store_config (timezone / business hours / pricing)
  3. 查 callerNumber 是不是已知 lead/contact (WHERE store_id = ?)
  4. 返回 tenant-scoped context bundle
  ↓
voice agent 用 context 开始对话, 后续所有 tool call 必须带 storeId
  ↓
通话结束 → 录音 + 转录 → 进入现有 call-analytics-pipeline
```

### Outbound 链路

```
触发: lead 表新增一行 (store_id NOT NULL 已填好)
  ↓
触发器 (EventBridge): 5min 后员工没接 → 触发 AI 外呼
  ↓
retaintive 调 voice 平台 API:
  POST https://api.vapi.ai/call/phone
  body:
    phoneNumberId: <Devon 店的 vapi phone resource>
    customer: { number: "+12125559999" }
    assistant:
      systemPrompt: <retaintive 拼好, 注入 store 信息>
      tools:
        - checkSchedule  → studio-api /v3/voice-agent/schedule
        - bookAppointment → studio-api /v3/voice-agent/book
        - escalateToHuman → studio-api /v3/voice-agent/escalate
      metadata: { storeId, leadId }
  ↓
voice agent 拨号 → AI 用 store-scoped prompt 对话
  ↓
每次 tool call 打到 retaintive API:
  - 验证 capability token (绑 storeId / leadId / allowed tools / expiry / nonce)
  - 强制 WHERE store_id = $tenant
  - 跨 store 查询直接 403
  ↓
通话结束 → webhook 回到 retaintive → 进入现有 pipeline
```

### 数据串店的三层防护

**Phone routing 层**

Devon 客户拨错号到 White Plains: rc\_store\_phones 查到 storeId = WP, AI 自报 "Hi this is White Plains", 客户自己挂电话。

两店共用号码: schema 当前允许但 prod 没出现 (见 §schema 加固)。

号码移店 (Devon → WP): UI 改 phone-store-assignment 之后, 新通话 routing 到 WP, 旧数据留 Devon (TCPA 合规要求)。

**API 调用层 (voice agent 调 retaintive)**

每个 tool endpoint 五道关:

1. 验证 capability token (server-side 发的 session token, 不信任 header 中的 storeId)
2. storeId 从 token 解出, 不允许 caller 自己 declare
3. SQL 层强制 `WHERE store_id = $tenant`
4. Tool response schema 校验
5. Audit log (storeId / tool / input / output 全记)

token 设计借鉴 OAuth2 capability pattern: `voice_agent_session_id` → 一次性服务端 token, 绑 storeId / leadId / allowed tools / expiry / nonce / call vendor id。token 失效后 voice agent 调用直接 403。

**Voice 平台层**

| 平台                        | 多租户方式                                                  | retaintive 怎么用                                       |
| ------------------------- | ------------------------------------------------------ | ---------------------------------------------------- |
| Vapi                      | per-tenant phoneNumberId + per-call assistant override | 一个 vapi phone resource = 一个 store, dynamic prompt 注入 |
| Retell                    | weighted agent lists + dynamic variables               | 类似                                                   |
| Twilio Programmable Voice | 完全自管                                                   | 每个 store 一个 phone, callbackUrl 带 storeId             |

POC 选 Vapi (dev-friendly + per-call dynamic prompt + 便宜)。但 vendor 拥有 call state / latency path / prompt runtime / recordings / phone resources / failure modes / pricing — voice 平台是 disposable POC 工具, 不该成为 system of record。retaintive 长期边界应该是: 自有 policy engine / session ledger / consent-DNC / prompt-script versions / audit / outcome scoring, 只 buy media + orchestration。

### Schema 加固

`rc_store_phones` 的 unique index 是 `(store_id, phone_number)` 组合, phone\_number 单独不 unique:

```typescript
// callytics-common/src/db/schema/rc-stores.ts
uniqueIndex('uq_rc_store_phones_store_phone').on(table.storeId, table.phoneNumber),
index('idx_rc_store_phones_number').on(table.phoneNumber),  // NOT UNIQUE
```

意味着 schema 允许同一个号码出现在多个 store 行。`resolvePhoneIdentity` 用 `WHERE phone_number = $1 LIMIT 1`, 如果真出现 dup, routing 是 nondeterministic。

Prod query 2026-05-25 验证: 78 phone / 0 dup, 不是 active bug, 是 latent risk。仍要加 unique 约束兜底 — voice agent 上线后 outbound 是新 write path, dup 风险概率上升。

修法: schema 加 `UNIQUE(phone_number)` (或 partial unique on active rows) + 写入前 application-level invariant check + CloudWatch alarm 监控 dup count 持续为 0。voice agent 之前要做, 不阻塞 voice agent 启动。

### 隔离的非数据维度 (容易漏)

数据库层 store\_id WHERE 不够, 还有几个 boundary 也要 store-scoped:

- Voice 平台 vendor logs / recordings / debug payload (per-store DPA + retention 配置)
- Vendor 端 webhook payload 验证 (不能信任 vendor 发来的 metadata.storeId, 用本地 session\_id 双向校验)
- Human escalation 链路: 转接号码 / staff assignment / SMS 通知 / task owner / manager mobile phone 全部 store-scoped
- 复用现有 call-analytics-pipeline 时, contacts 表 phone-only dedupe 可能把多 store caller 的历史串起来 — 要 verify

`voice_agent_sessions` 新表的 store\_id 字段必须 `uuid` 类型 (跟 `rc_stores.id` 一致), 别在新表降级为 `text`。

***

## 晚上下班场景具体怎么跑

第一阶段定位接受重新 framing: AI 不直接 booking, 不直接报 cancellation outcome, 不报 approved snippets 之外的 pricing。

### Inbound (客户主动打来)

```
22:00 客户拨 Devon 店主线 +16104403480
  ↓
RC 转 voice agent gateway (RC SIP forward)
  ↓
Voice agent 接起 (3 秒内):
  "Hi, this is Devon OrangeTheory. We're closed for the night
   but I'm here to help. Are you looking to try a class,
   ask about pricing, or something else?"
  ↓
分支 A: "I want to try a class"
   → AI 留 name + phone + 建 task "Lead inquiry from after-hours"
   → 发 SMS "Got it! Our team will call you tomorrow before 11am."

分支 B: "Pricing?"
   → AI 报价 (从 store_config.pricing 拉 approved snippet)
   → 建 task 跟进

分支 C: "I want to cancel my membership"
   → 必须立刻 acknowledge + 时间戳锁死 + 创建合规可追溯的 cancellation event
   → 不能 "tomorrow team will follow up" (FTC 2025-08 已起诉 LA Fitness cancellation friction)
   → AI 仅 capture, 实际 cancellation 处理走员工 SOP

分支 D: 沉默 / 挂电话
   → AI 留 voicemail 记录, 建 missed_lead task
  ↓
所有路径 → 现有 call-analytics-pipeline → 老板早上看 dashboard
```

### Outbound (新 lead 凌晨提交表单)

```
01:00 AM 有人填了 Devon 店的体验课表单
        → lead-tracking poller 写入 lead 表 (store_id = Devon)
  ↓
EventBridge rule 看 lead.calling_hours_window:
  TCPA 8am-9pm 是 called party local time (不是 store 时区!)
  推 called party 时区的策略:
    1. 优先用 lead capture 时收集的辅助信号 (IP geo / zip code) — 最准
    2. fallback 用电话区号推时区 — 不可靠 (携号转网 / 跨州迁移)
    3. 保守策略: 区号时区 ∩ store 时区, 两个时区都在 8am-9pm 才拨
       (e.g. lead 是 NYC 区号但实际在 CA, ET 8am 拨 = PT 5am = 违规)
  → defer 到下一个安全窗口
  ↓
执行时间到, 还要 re-check:
  - consent 还有效?
  - phone 在 DNC list?
  - phone 在 FCC reassigned number database?
  - lead 还属于这个 store?
  - 现在是 called party 的 8am-9pm?
  ↓
全过 → voice agent 拨过去:
  "Hi <name>, this is Sarah from Devon OrangeTheory.
   You inquired about a free class. Did I catch you at a good time?
   Takes 1 minute."
  ↓
分支 A: "yes" → 资格初筛 → 约时间 → 建 task confirm
分支 B: "not now" → "When's a good time today?" → 改 task dueAt
分支 C: "wrong number" → mark lead invalid + DNC list 加号
分支 D: 没接 → leave voicemail (注意: voicemail 不是 TCPA loophole) + SMS follow-up
分支 E: "stop calling" / "remove me" → 立刻停, 写 DNC + 取消所有 queued retries/SMS
  ↓
全部 → pipeline
```

### Risk

| 维度   | 做了会怎样                                                                                          | 不做会怎样                               |
| ---- | ---------------------------------------------------------------------------------------------- | ----------------------------------- |
| 客户体验 | gym 行业 first-call-no-answer 流失 40-60%, AI 接住转化率显著高                                             | 晚上 lead 第二天员工才看到, 转化掉 60%           |
| 数据隔离 | 三层防护 + capability token + audit log 兜底                                                         | n/a (现在没 outbound)                  |
| 合规   | TCPA + FCC AI voice + FTC click-cancel 必须做对                                                    | 联邦 / 集体诉讼风险 (单条 $500-1500, 集体诉讼上千万) |
| 成本   | Vapi 标价 $0.10-0.20/min, all-in 实际 2-3x markup (含 STT/LLM/TTS/recording/SMS/retries/monitoring) | 员工漏接 lead 机会成本                      |
| 店主信任 | 1 店试点 + 老板能开关 + 通话可 review                                                                     | 直接全店上线翻车 = 失去信任                     |

### AI 能说什么 — approved claim library

AI 能说什么不应该由 prompt 自由发挥, 而是由 retaintive 拥有的 approved claim library 控制:

| 话题                                       | 第一阶段边界                                                                |
| ---------------------------------------- | --------------------------------------------------------------------- |
| Pricing                                  | 只说 `store_config.pricing` 中批准过的 snippet。不做临时折扣, 不承诺特殊价格               |
| Booking                                  | 收集偏好时间, 创建 task。除非接真实 availability + writeback, 否则不说 "you are booked" |
| Cancellation                             | 立刻记录 request, 不给用户增加阻力, 不承诺法律结论                                       |
| Health / injury / pregnancy / disability | 少问、少存、必要时转人工                                                          |
| Minors                                   | 保守转人工                                                                 |
| Angry customer / refund                  | 转人工, 保留 transcript                                                    |
| Wrong number                             | 立即停止, 标记 suppression                                                  |

### 真实成本由这些组成

不要用 platform 标价 `$0.10-0.20/min` 直接做财务承诺。真实成本:

| 成本项               | 说明                                      |
| ----------------- | --------------------------------------- |
| telephony minutes | inbound / outbound / transfer 都可能计费     |
| STT               | streaming 比 batch 更贵, 计费方式也不同           |
| LLM               | latency 和 model 选择影响成本                  |
| TTS               | ElevenLabs / Cartesia / OpenAI TTS 成本不同 |
| recording storage | 录音存储 + retention policy                 |
| SMS               | follow-up / confirmation / handoff      |
| failed calls      | 未接 / 重试 / 超时也可能产生成本                     |
| monitoring        | Sentry / Datadog / logs                 |
| vendor margin     | Vapi / Retell 打包后的加价                    |
| human review      | 店主和内部 review workflow 的人力成本             |

POC 阶段按真实账单算每通 after-hours call 的 cost, 再对比 missed lead 的机会成本。

***

## Build vs Buy

Max 原问: 我们对接另外一个像 Deepgram 这样的东西, 把 prompt 给他们吗? 还是它能访问我们的数据库?

都不是。是 **tool-based integration**:

| 层                                   | 谁负责                         | retaintive 怎么接入                |
| ----------------------------------- | --------------------------- | ------------------------------ |
| Telephony (打电话本身)                   | Twilio 或 Vapi 内嵌            | API call                       |
| STT (语音转文字)                         | Deepgram (已用) 升级到 streaming | API key, 已熟                    |
| LLM (理解 + 回答)                       | Claude (已用) / GPT           | 通过 voice 平台配置                  |
| TTS (文字转语音)                         | ElevenLabs / Cartesia       | voice 平台配置                     |
| Orchestration                       | Vapi 或 Retell, 不自研          | API + webhook                  |
| 业务逻辑 (查 lead / 排 schedule / 建 task) | retaintive 自己               | 暴露 HTTP tools, voice 平台调       |
| Storage                             | retaintive Neon             | voice 平台不直连, 通过 retaintive API |

不只把 prompt 给他们 — 还要把 retaintive API 当 tool 给 voice 平台调用。绝对不给 DB access — 必须经 retaintive API, 才能强制 tenant scoping。

判定 Buy vs Build 三问 (ABCPOS framework):

1. 行业有成熟 partner SaaS? 有 → buy
2. retaintive 拥有独特数据? 有 → build
3. ROI break-even 在 12 个月以内? 超过 → buy

应用到 voice agent: 行业有 Vapi/Retell/Slang.ai → buy 底层。retaintive 独特数据是 CI + lead funnel + tasks → build prompt + tool API 接入。ROI: 自建 $800K-2M / 12-24 个月, 接 Vapi 数天上线 → 明确 buy。

结论: voice 底层 buy partner, 业务逻辑 + tenant-scoped tool API + consent ledger build 自己。

### 长期 vendor lock-in 边界

POC 用 Vapi 可以快速验证, 但 Vapi / Retell 不是 durable architecture。Vendor 拥有 call state / latency path / prompt runtime / recordings / phone resources / failure modes / pricing。长期 retaintive 必须自有什么 / 可以买什么:

| retaintive 必须拥有            | 可以先买                     |
| -------------------------- | ------------------------ |
| policy engine              | media transport          |
| session ledger             | orchestration runtime    |
| consent / DNC ledger       | STT / TTS                |
| prompt and script versions | telephony routing        |
| approved claim library     | vendor dashboard         |
| audit logs                 | low-level latency tuning |
| outcome scoring            | voice model selection    |

volume 上来后再评估是否从 Vapi / Retell 迁到 LiveKit Agents / Pipecat / Twilio 自管。POC 阶段不要为未来迁移提前造完整平台, 但 API 边界要干净。

***

## 上线前必须当 test cases 处理的 edge cases

这些不是边角料, 全部要在 POC 阶段就跑过:

| Edge case                                                            | 需要的处理                                                                                          |
| -------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| consent 是 phone + person + store/seller + channel + purpose + source | 不把 per-lead 当成万能 consent                                                                       |
| outbound 排队后状态变化                                                     | 执行时 re-check consent / DNC / phone assignment / lead ownership / store config / calling window |
| Lead 从 Devon 移到 White Plains                                         | 取消旧 session, 按新 store policy 重新创建                                                              |
| 客户换号码                                                                | 旧 consent 不自动跟新号                                                                               |
| reassigned number                                                    | 老 lead 外呼前查 FCC reassigned number database 或采用保守策略                                             |
| 推 called party 时区                                                    | 区号不可靠, 优先用 lead capture 时收的 IP/zip; fallback 用区号时区 ∩ store 时区双交集 (任一在 8am-9pm 外就 defer)        |
| mid-call revocation ("stop calling" / "don't call me")               | 立即停止, 不能继续问 "one more question"                                                                |
| duplicate triggers (form submit + IMAP lead + CRM import)            | 需要 idempotency key                                                                             |
| voicemail                                                            | 仍受 TCPA 监管, 不是 loophole                                                                        |
| call recording disclosure                                            | 按州处理 two-party consent, 不能全美一个模板                                                               |
| tool timeout                                                         | 不让 AI 编答案, 转人工或安全结束                                                                            |
| vendor webhook retry                                                 | webhook receiver 必须幂等, 双向校验不信 vendor metadata                                                  |
| phone mapping duplicate                                              | schema unique + monitoring                                                                     |
| prompt hallucinated offer                                            | approved claim library + adversarial evals                                                     |
| Devon 客户拨错号到 White Plains                                            | rc\_store\_phones 解析为 WP, AI 自报 "Hi this is White Plains", 客户挂电话                               |

***

## Endpoint 现状 + 缺什么

### AI partner 接入必须经公开 API + OAuth

ABCPOS 调研报告 (Max 引用) 核心架构判断: AI partner 不能直连数据库, 必须经公开 read-only API + OAuth。理由对 retaintive 一样成立:

- 安全 / 性能 / 抽象 / 多租户隔离, 全靠 API 层兜底
- 每个 partner 单独定制 endpoint 不可扩展, 第二个 partner 接进来工程量翻倍
- partner 是独立公司, 不应该共享 retaintive 工程师的内部 secret, 必须 OAuth (或同级别 capability token)

### 7 个 voice agent tool 的 endpoint 现状

| Voice agent tool                              | 干啥                                    | 现状                                                           |
| --------------------------------------------- | ------------------------------------- | ------------------------------------------------------------ |
| `getStore(storeId)`                           | 店名 / timezone / 营业状态                  | 已有 `GET /v3/setup` + `GET /v3/stores`                        |
| `getStoreContext(storeId)`                    | pricing / intro offers / lead\_emails | 已有 `GET /v3/setup` (返 store\_config.pricing JSONB)           |
| `getOperatingHours(storeId, date)`            | 那天营业? 几点空?                            | 表数据在 (operating\_schedules + blackouts), 没现成语义 endpoint, 要新建 |
| `lookupContact(storeId, phone)`               | 这号码是谁 / 历史通话 / lead status            | 已有 `GET /v3/contacts` + `GET /v3/conversations`              |
| `lookupLead(storeId, leadId)`                 | lead 来源 / 状态 / 之前问过啥                  | 已有 `GET /v3/leads` + `GET /v3/leads/pipeline`                |
| `createTask(storeId, contactPhone, body)`     | 建 task 给店长                            | 有 `POST /tasks/*`, voice 触发的 task 创建要新建                      |
| `escalateToHuman(storeId, sessionId, reason)` | 转人工 / voicemail / 通知店长                | 完全没有                                                         |

新建 3 个 endpoint: `GET /v3/operating-hours/effective`, `POST /v3/voice/create-task`, `POST /v3/voice/escalate`。

4 个可复用 endpoint 必须加内部 token 或 OAuth scope — 现在的 v3 路由都是 JWT-scoped 给前端用, voice partner 不是用户。

### 缺什么完整清单

后端工作:

1. 修复 `rc_store_phones` schema (加 unique 索引兜底)
2. 公开 API + OAuth 改造 — AI partner 接入硬前提
3. 3 个新 endpoint
4. 4 个现有 endpoint 加内部 token / OAuth scope
5. Voice control plane: session ledger / capability token / kill switches / policy engine
6. `voice_agent_sessions` Neon 表 + Drizzle migration (store\_id 必须 uuid 类型)
7. Outbound trigger Lambda: EventBridge + 执行时 re-check consent / DNC / calling-hours
8. TCPA consent ledger (维度: phone + person + store + channel + purpose + source, 不是 per-lead)
9. DNC list + FCC reassigned number database 检查
10. Calling hours engine — per called-party timezone, 不复用 operating\_schedules
11. Voice 平台 webhook receiver (Vapi end-of-call event, 幂等 + 双向校验, 不信任 vendor metadata)
12. Observability 改造 — Sentry + Datadog APM (AI 出错 1 分钟内要看到, 不然单一事故损害品牌信任)
13. 复用现有 call-analytics-pipeline 分析 AI 通话录音 (0 工作量)

Voice 平台层:

- Vapi 账号 + per-store phone resource provision (RC SIP forward 或 Twilio bridge)
- system prompt 设计 + call replay evals + adversarial tests + per-brand approval
- Fallback / 异常处理 (AI 卡住转人工)

前端:

- 老板看 voice agent 通话记录 (复用 calls 列表 UI, 加 source filter)
- 老板开关 voice agent (per-store)
- AI 出错通话 review + flagging + redaction + 退款 / 投诉处理 workflow
- Outbound consent 管理 UI

合规 + 法律 (独立工作流, 早期介入, 不是 launch checklist):

- TCPA — AI voice 属 artificial/prerecorded voice, telemarketing 需要 prior express written consent (FCC 2024 ruling)
- FCC AI voice ruling 强化 AI 合成语音监管
- FCC reassigned number database lookup
- FTC click-cancel rule — recurring membership 取消必须跟 signup 一样容易
- FTC v. LA Fitness (2025-08) — phone cancellation friction 已有判例
- State-level robocall (CA AB 1132 / FL FDUTPA / 各州差异)
- Two-party consent recording (12 个州, CA / FL / IL / NY 等)
- HIPAA 一般不直接适用, 但 injuries / pregnancy / disability / health goals / minors / biometric 触发 state privacy + discrimination 风险

工程量我猜不准, 不给周数。可以确定的复杂度量级:

- 改 schema + 加 unique 约束: 小
- 公开 API + OAuth 改造: 中等偏大, 是硬前提
- voice control plane + session ledger + tool endpoints: 中等
- TCPA consent + DNC + calling hours engine: 中等偏大 (含合规咨询)
- Observability + 前端 review UI: 中等

ABCPOS framework 关键洞察对 retaintive 也成立: 不要 "先 foundation 再 AI" 顺序执行, 而是用具体 AI feature 反向倒逼基础设施改造。voice agent 这件事本身就是反向倒逼公开 API + observability + idempotent write + consent ledger 的最好契机。这是 Shopify 当年走过的 vertical SaaS 升级套路。

### 失败 scenario (不能让它发生)

ABCPOS 调研报告 §4.3 列了 4 个失败模式, 翻译到健身房直接成立:

1. AI 接电话, 客户说 "I want two memberships", STT 把 "two" 听成 "twenty", 系统下了 20 个 Stripe charge, 次日客户发现, 18 个退款
2. 缺少 Sentry, 工程团队不知道哪些电话失败, 半个月后才发现这是系统性 bug
3. Outbound trigger API 不幂等, 网络抖动触发 retry, 同一个 lead 拨两次, 双倍 SMS, 触发 TCPA 投诉
4. 健身房老板在小红书 / Reddit 发声 "retaintive 的 AI is BS", 行业社区病毒传播

恢复成本 $50 万 + 6 个月, 远超 partner Vapi 总成本。这是 Observability 必须在 ship 前做扎实的原因。

***

## 需要决定的事

不给时间表, 不猜。下面是要决定的内容:

立刻 (这周内):

- Neon query 验证 `rc_store_phones` (已跑 2026-05-25, prod 0 dup)
- schema 加 unique 索引这件事独立 PR, 不等 voice agent
- 这份 spec 给 Peter / 陈栋 / non-tech 成员 review, 看读不读得懂

前端展示阶段做完后, 决定 voice agent 启动时:

- 试点店选哪个 (建议 Devon, 数据量大)
- Voice 平台先 POC 哪个 (推荐 Vapi)
- 公开 API + OAuth 改造怎么做: 走独立工作流 (AI 之前必修) 还是借 voice agent 反向倒逼
- TCPA consent 怎么收集: 现有 lead form 加 checkbox, IMAP 来的 lead 怎么办
- AI 出错 / 卡壳怎么 escalate: 转店长手机 / 留 voicemail / SMS
- 商业模式: 现有 seat-based 加 AI minute 包 / per-call surcharge (留到看真实数据再定)

不应该现在决定 (防被动 commit):

- 不承诺具体开发周数
- 不承诺全店 rollout 时间
- 不承诺 autonomous outbound 做不做
- 不承诺 booking 或 closed-loop sales
- 不承诺把 Vapi / Retell 当作长期最终架构

***

## 来源

retaintive 内部代码 (verified):

- `callytics-common/src/phone-identity/phone-identity.ts`
- `callytics-common/src/db/schema/rc-stores.ts`
- `callytics-common/src/db/schema/operating-schedules.ts`
- `callytics-common/src/db/schema/store-config.ts`
- `studio-website-monorepo/apps/api/src/utils/store-authorization-neon.ts`
- `studio-website-monorepo/apps/api/src/routes/v3/` 全部 route 文件
- `docs/system-design/store-level-isolation.md`
- `docs/architecture/0-system-overview.md`

Neon prod query (2026-05-25 via Neon MCP):

- callytics-prod project (`red-math-38447173`) — rc\_store\_phones isolation 验证

市场调研:

- [Chowbus $81M Series E AI Digital Worker](https://restauranttechnologynews.com/2026/03/chowbus-raises-81-million-to-expand-its-ai-powered-platform-for-independent-restaurants/)
- [Retell AI G2 reviews](https://www.g2.com/products/retell-ai/reviews)
- [Lindy 18 voice agents tested 2026](https://www.lindy.ai/blog/ai-voice-agents)
- [Lumay Build vs Buy Guide](https://www.lumay.ai/blogs/best-build-vs-buy-ai-voice-agent-guide)
- [Vapi outbound docs](https://docs.vapi.ai/calls/outbound-calling)
- [Twilio + LiveKit production pattern](https://medium.com/@wasifullahdev/from-call-flows-to-autonomous-agents-building-real-time-voice-ai-with-twilio-livekit-c2dd22834db6)

合规 (FCC + FTC 官方源):

- [FCC 2024 AI voice TCPA declaratory ruling](https://docs.fcc.gov/public/attachments/FCC-24-17A1.pdf)
- [FCC revocation strengthening order (2025)](https://docs.fcc.gov/public/attachments/DA-25-312A1_Rcd.pdf)
- [FTC v. LA Fitness cancellation friction (2025-08)](https://www.ftc.gov/news-events/news/press-releases/2025/08/ftc-sues-la-fitness-making-it-difficult-consumers-cancel-gym-memberships)
- [FTC click-cancel Negative Option Rule (2024-10)](https://www.ftc.gov/business-guidance/blog/2024/10/click-cancel-ftcs-amended-negative-option-rule-what-it-means-your-business)

外部调研对照:

- ABCPOS PDF "AI 战略评估与十二个月路线建议" (Max 引用, 微信文档)
- Codex adversarial review (2026-05-25 跑, 跑了 FCC + FTC docs 校准, 完整 output session-archived)
