产品闭环分析:从信息孤岛到数据闭环¶
分析日期:2026-02-13 分析范围:lead-tracking、callytics-infrastructure、studio-api 三大模块 分析目标:识别产品闭环缺失点,制定改进路线
1. 核心结论¶
1.1 一句话总结¶
你的系统是一个极其优秀的「通话分析器」,但不是一个「销售闭环系统」。 三个 agent 一致认为:数据采集能力强,但数据之间是孤岛,老板看到的是 "发生了什么",而不是 "我该做什么"。
1.2 问题本质¶
系统是三个各自优秀但互不对话的子系统。Lead-tracking 做好了采集,callytics 做好了 AI 分析(prompt 写得非常棒),studio-api 做好了展示。但它们之间的连接线——phone 匹配、history 注入、outcome 回写、事件触发——全部缺失或只在运行时临时计算。
打通这些连接线不需要重写任何系统,只需要 把已有的点连成线。
2. 当前架构(三个信息孤岛)¶
2.1 整体数据流¶
graph LR
subgraph "Island 1: Lead Tracking"
E[Lark Suite 邮箱] -->|IMAP 每5分钟| P[IMAP Poller Lambda]
P -->|解析邮件| LT[(LeadTracking-v2<br/>DynamoDB)]
end
subgraph "Island 2: Call Analysis"
RC[RingCentral 通话] -->|Webhook| SQS[SQS Queue]
SQS --> DL[Download Lambda]
DL -->|录音| S3[(S3 Bucket)]
S3 --> TR[Deepgram 语音转文字]
TR -->|文本| AI[Bedrock AI 分析]
AI -->|结构化数据| CA[(call-analysis<br/>DynamoDB)]
end
subgraph "Island 3: Studio API"
API[studio-api]
API -->|读取| LT
API -->|读取| CA
API -->|运行时 phone 匹配| API
WEB[studio-web] -->|展示| BOSS[老板看到数据]
end
LT -.-|无持久链接| CA
2.2 各模块存储的数据¶
erDiagram
LeadTracking_v2["LeadTracking-v2"] {
string id PK "leadEmail + receivedAt"
string leadEmail
string phone "10-digit format"
string firstName
string lastName
string bookedDate
string bookedTime
string leadType "Web Lead or Online Intro"
string receivedAt
string outcome "INTRO_BOOKED etc (手动或AI自动)"
string outcomeUpdatedAt
string outcomeUpdatedBy
string outcomeHistory "array"
}
call_analysis["call-analysis"] {
string telephonySessionId PK
string callStartTime
string fromPhoneNumber "E.164 format"
string toPhoneNumber "E.164 format"
string callDirection
number callDuration
string staff_name "AI-detected"
string customer_type "AI-classified"
string primary_category "AI-classified"
string primary_subcategory "AI-classified"
string primary_outcome "AI-classified"
string follow_up_needed "AI-determined"
string executive_summary "AI-generated"
}
LeadTracking_v2 ||--o{ call_analysis : "no direct FK"
核心问题:两个表之间没有 Foreign Key
- Lead 的 phone 存为 10 位(
7328561597) - Call 的 phone 存为 E.164(
+17328561597) - 每次展示都靠 studio-api 在运行时做 phone 匹配
- 结果不持久化,无法追溯
3. 8 个关键断裂点¶
3.1 断裂点总览¶
graph TD
G1["GAP 1: Phone 格式不一致<br/>Lead=10位 vs Call=E.164"]
G2["GAP 2: 无 Call→Lead 持久关联<br/>每次运行时重新匹配"]
G3["GAP 3: CUSTOMER_HISTORY 未注入<br/>Prompt 有占位符但代码没实现"]
G4["GAP 4: AI Outcome 不写回 Lead<br/>AI说intro_booking但Lead.outcome=null"]
G5["GAP 5: Outcome 变更无事件<br/>无 SNS/EventBridge 触发"]
G6["GAP 6: AI vs 手动 Outcome 无校验<br/>可能冲突无人发现"]
G7["GAP 7: 同一人多条 Lead<br/>无 phone 去重机制"]
G8["GAP 8: 通话无生命周期标签<br/>不知道是首次还是跟进"]
G1 -->|阻塞| G2
G2 -->|阻塞| G3
G2 -->|阻塞| G4
G4 -->|导致| G5
G4 -->|导致| G6
G7 -->|恶化| G2
G8 -->|影响| G4
style G1 fill:#ff6b6b,color:#fff
style G2 fill:#ff6b6b,color:#fff
style G3 fill:#ff6b6b,color:#fff
style G4 fill:#ffa94d,color:#fff
style G5 fill:#ffa94d,color:#fff
style G6 fill:#ffd43b,color:#333
style G7 fill:#ffd43b,color:#333
style G8 fill:#ffd43b,color:#333
3.2 详细说明¶
| # | 断裂点 | 严重度 | 代码位置 | 具体问题 |
|---|---|---|---|---|
| 1 | Phone 格式不一致 | CRITICAL | lead-tracking/poller.ts:65 |
normalizePhone() 存 10 位,call-analysis 存 E.164 |
| 2 | 无 Call→Lead 持久关联 | CRITICAL | call-history.ts:142-156 |
运行时 phone 匹配,不存 leadId |
| 3 | CUSTOMER_HISTORY 未注入 | CRITICAL | prompt-builder.ts:35-61 |
有 {CUSTOMER_HISTORY_WILL_BE_INJECTED_HERE} 但代码没实现 |
| 4 | AI Outcome 不写回 Lead | HIGH | list.ts:78-84 |
AI 分析的 customer_type/outcome 不存回 LeadTracking |
| 5 | Outcome 变更无事件 | HIGH | update-outcome.ts:130-141 |
只写 DynamoDB,无 SNS/EventBridge |
| 6 | AI vs 手动 Outcome 无校验 | MEDIUM | types.ts:51-56 |
AI 说 follow_up_needed=true 但 Lead 标记 CLOSED |
| 7 | 同一人多条 Lead | MEDIUM | poller.ts:159 |
id = email#timestamp 无法防止同一 phone 重复创建 Lead |
| 8 | 通话无生命周期标签 | MEDIUM | call-history.ts:174-196 |
分了 before/after 但不标注 stage |
3.3 GAP 3 详解:最大的已有但未实现的功能¶
sequenceDiagram
participant RC as RingCentral
participant Lambda as AI Analysis Lambda
participant Prompt as standard-v1.0.0.txt
participant Bedrock as Amazon Bedrock
RC->>Lambda: 通话录音 + 转录文本
Lambda->>Lambda: buildAnalysisPrompt()
Note right of Lambda: ✅ 注入了 STAFF_LIST
Note right of Lambda: ❌ 没有注入 CUSTOMER_HISTORY
Lambda->>Prompt: 替换占位符
Note over Prompt: {CUSTOMER_HISTORY_WILL_BE_INJECTED_HERE}<br/>← 这行原样保留在 prompt 里!
Lambda->>Bedrock: 发送 prompt + transcript
Bedrock-->>Lambda: AI 分析结果
Note over Lambda: AI 无法看到此客户的历史通话<br/>无法识别回访客户<br/>无法检测升级模式
prompt-builder.ts 第 35-61 行的代码:
- ✅ 检查了
{STAFF_LIST_WILL_BE_INJECTED_HERE}并替换 - ❌ 完全没有处理
{CUSTOMER_HISTORY_WILL_BE_INJECTED_HERE} - 占位符文本原样发送给 Bedrock
4. 文档愿景 vs 实际实现对比¶
4.1 7 种 Call Type 的实现状况¶
graph LR
subgraph "文档定义的 7 种 Call Type"
LC[Lead Call]
FC[Follow-up Call]
SC[Service Call]
RFC[Referral Call]
WBC[Win-back Call]
RMC[Reminder Call]
RTC[Retention Call]
end
subgraph "Prompt 中的实现"
IB[intro_booking]
MPR[membership_purchase]
SVC[service 子类]
RP[reactivation_purchase]
BC[booking_confirmation]
REF[referral_program]
end
LC -->|50%| IB
LC -->|50%| MPR
FC -.->|0% 缺失| NONE1[❌ 无对应]
SC -->|60%| SVC
RFC -.->|20% 降级| REF
WBC -->|80%| RP
RMC -.->|30% 混淆| BC
RTC -.->|0% 缺失| NONE2[❌ 无对应]
style NONE1 fill:#ff6b6b,color:#fff
style NONE2 fill:#ff6b6b,color:#fff
style REF fill:#ffa94d,color:#fff
style BC fill:#ffd43b,color:#333
4.2 客户分级的缺失¶
| 文档的 A/B/C/D 分级 | Prompt 的 customer_type | 差距 |
|---|---|---|
| A 级(高意愿+高匹配) | prospective_client |
Prompt 无法区分 A 和 C,都叫 prospective |
| B 级(有意愿+有顾虑) | prospective_client |
无顾虑类型标注,无 objection 分类 |
| C 级(低意愿+可激活) | prospective_client |
无激活时机评估 |
| D 级(不匹配) | prospective_client |
无"建议放弃"信号 |
影响
文档强调 "80% 的精力放在 A/B 级客户上",但 AI 无法区分客户等级,老板不知道该把资源集中在谁身上。
5. 理想状态:详细工作流¶
5.1 完整 Lead 生命周期¶
关于自动分配
下图中 Lead 分配给 Staff 的步骤暂不自动化。当前由 Staff 在 Dashboard 上自行查看新 Lead 并手动拨打。未来可考虑自动分配。
graph TD
%% ==================== STEP 1: Lead 到达 ====================
subgraph "STEP 1: Lead 到达"
EMAIL[Lead 通知邮件<br/>from Lark Suite]
POLL[IMAP Poller Lambda<br/>每 5 分钟]
PARSE[解析邮件内容]
DEDUP{phone 去重检查}
NEW_LEAD[创建新 Lead<br/>stage = new]
MERGE[合并到已有 Lead<br/>更新 receivedAt]
EMAIL --> POLL
POLL --> PARSE
PARSE --> DEDUP
DEDUP -->|新 phone| NEW_LEAD
DEDUP -->|已存在| MERGE
end
%% ==================== STEP 2: Staff 看到 Lead ====================
subgraph "STEP 2: Staff 看到并拨打"
DASH[Dashboard 显示新 Lead<br/>带 Hot/Warm/Cold 标签]
SLA[Response Time SLA 倒计时<br/>目标: 5分钟内首次拨打]
CALL[Staff 拨打电话]
NEW_LEAD --> DASH
MERGE --> DASH
DASH --> SLA
SLA --> CALL
end
%% ==================== STEP 3: 通话录制 ====================
subgraph "STEP 3: 通话发生"
RC_CALL[RingCentral 录制通话]
WEBHOOK[Webhook 事件]
SQS_Q[SQS Queue]
CALL --> RC_CALL
RC_CALL --> WEBHOOK
WEBHOOK --> SQS_Q
end
%% ==================== STEP 4: AI 分析(增强版)====================
subgraph "STEP 4: AI 分析(含历史注入)"
DOWNLOAD[下载录音 to S3]
TRANSCRIBE[Deepgram 语音转文字]
LOOKUP["🆕 查询 LeadTracking<br/>by phone number"]
HISTORY["🆕 获取该 phone 最近 3 通电话"]
BUILD["🆕 构建 prompt<br/>注入 STAFF_LIST<br/>注入 CUSTOMER_HISTORY"]
BEDROCK[Amazon Bedrock AI 分析]
SAVE_CALL[保存到 call-analysis<br/>含 customer_type, outcome,<br/>coaching, follow_up 等]
SAVE_LINK["🆕 保存 leadId 关联"]
SQS_Q --> DOWNLOAD
DOWNLOAD --> TRANSCRIBE
TRANSCRIBE --> LOOKUP
LOOKUP --> HISTORY
HISTORY --> BUILD
BUILD --> BEDROCK
BEDROCK --> SAVE_CALL
SAVE_CALL --> SAVE_LINK
end
%% ==================== STEP 5: Outcome 自动回写 ====================
subgraph "STEP 5: Outcome 自动回写"
STREAM["🆕 DynamoDB Streams<br/>on call-analysis"]
INFER["🆕 Outcome Inference Lambda"]
MAP{"🆕 AI outcome<br/>→ Lead outcome 映射"}
UPDATE_LEAD["🆕 更新 LeadTracking:<br/>outcome, stage,<br/>lastContactTime, callRef"]
SAVE_LINK --> STREAM
STREAM --> INFER
INFER --> MAP
MAP -->|intro_booking| UPDATE_LEAD
MAP -->|membership_purchase| UPDATE_LEAD
MAP -->|no match| SKIP[不更新]
end
%% ==================== STEP 6: 老板看完整漏斗 ====================
subgraph "STEP 6: 老板看到完整漏斗"
TODAY["今日概要<br/>12通话 / 3 booking / 2待跟进"]
FUNNEL["完整漏斗<br/>47 Leads → 43 Calls → 18 Booked"]
PERF["Staff 绩效卡<br/>Sarah: 33% 转化率"]
FOLLOWUP["Follow-up 任务队列<br/>带 SLA 倒计时"]
COACHING["Coaching 趋势<br/>本周弱点: 异议处理"]
UPDATE_LEAD --> TODAY
UPDATE_LEAD --> FUNNEL
UPDATE_LEAD --> PERF
UPDATE_LEAD --> FOLLOWUP
UPDATE_LEAD --> COACHING
end
%% ==================== 未来: 行动触发 ====================
subgraph "FUTURE: 自动行动触发"
EVENT["🆕 EventBridge Rule<br/>on outcome change"]
SMS[发送确认 SMS]
TASK[创建 Follow-up 任务]
ALERT[通知 Staff]
UPDATE_LEAD -.->|未来| EVENT
EVENT -.-> SMS
EVENT -.-> TASK
EVENT -.-> ALERT
end
5.2 AI 分析增强:CUSTOMER_HISTORY 注入流程¶
sequenceDiagram
participant SQS as SQS Queue
participant Lambda as AI Analysis Lambda
participant LT as LeadTracking-v2
participant CA as call-analysis
participant Bedrock as Amazon Bedrock
SQS->>Lambda: 新通话事件
Lambda->>Lambda: 下载录音, 转录
rect rgb(200, 255, 200)
Note over Lambda,CA: 🆕 新增: 查询历史
Lambda->>CA: 查询 fromPhoneNumber 最近 3 通电话
CA-->>Lambda: [{callStartTime, category, outcome, summary}]
Lambda->>LT: 查询 phone 对应的 Lead 信息
LT-->>Lambda: {firstName, receivedAt, bookedDate, outcome}
end
rect rgb(200, 220, 255)
Note over Lambda,Bedrock: 🆕 增强: 构建完整 prompt
Lambda->>Lambda: 替换 {STAFF_LIST_WILL_BE_INJECTED_HERE}
Lambda->>Lambda: 🆕 替换 {CUSTOMER_HISTORY_WILL_BE_INJECTED_HERE}
Note right of Lambda: "最近 3 通电话:<br/>- 2/11: intro call, booked<br/>- 2/8: price inquiry, no book<br/>Lead info: Jane Smith, 2/7到达"
Lambda->>Bedrock: 完整 prompt + transcript
end
Bedrock-->>Lambda: AI 分析结果
rect rgb(255, 220, 200)
Note over Lambda,LT: 🆕 新增: 回写 Lead
Lambda->>CA: 保存 call-analysis (含 leadId)
Lambda->>LT: 更新 Lead: outcome, stage, lastContactTime
end
为什么 CUSTOMER_HISTORY 不包含 SMS/Text 数据
Dashboard "All" 视图中同时展示了通话记录和 SMS 记录,但 CUSTOMER_HISTORY 注入只查询了通话数据。原因:
- SMS 没有持久化 — studio-api 每次加载 Lead 列表时实时调 RingCentral Message Store API 获取 SMS 数据,只提取
firstMessageTime(最早的 outbound 短信时间),内容不存储到任何 DynamoDB 表 - AI Lambda 没有 RingCentral OAuth token — 只有 studio-api 通过用户建立的 connection 才能访问 RingCentral API,AI 分析 Lambda 无法直接调用
- SMS 没有 transcript — 短信是纯文本,不经过 Transcribe,注入 prompt 的价值远低于通话分析摘要
如果未来需要将 SMS 纳入客户历史,前提是先实现 SMS 持久化(将 RingCentral SMS 数据定期同步到 DynamoDB),这可以作为 Phase 2+ 的考量。
5.3 Outcome 映射规则¶
graph LR
subgraph "AI 分析输出(Prompt Taxonomy)"
AI_IB["intro_booking<br/>+ outcome.result = success"]
AI_MP["membership_purchase_related<br/>+ outcome.result = success"]
AI_OTHER["所有其他 subcategory<br/>或 result ≠ success"]
end
subgraph "Lead Outcome(studio-api 定义)"
L_BOOKED[INTRO_BOOKED]
L_SKIP[不更新 — 保持当前状态]
end
AI_IB --> L_BOOKED
AI_MP --> L_BOOKED
AI_OTHER --> L_SKIP
当前映射范围有限
Phase 1 只实现了最高优先级的一条映射规则。LeadOutcomeValue 类型定义了 5 种值(INTRO_BOOKED | SELF_BOOKED | INVALID_LEAD | NO_CALL_LIST | CLOSED),但其中 SELF_BOOKED 需要 CRM 集成,INVALID_LEAD / NO_CALL_LIST / CLOSED 是手动设置的终态。
映射保护规则(shouldUpdateLeadOutcome)
- 只在 Lead outcome 为 null / undefined(尚未设置)时才自动写入
- 手动终态
CLOSED、INVALID_LEAD、NO_CALL_LIST不会被自动覆盖 - 已有相同值时不重复写入
- 每次自动更新记录
updatedBy: "system"以区分手动/自动
6. 老板视角:Before vs After¶
6.1 Before(当前)¶
graph TD
BOSS[老板登录 Dashboard]
BOSS --> L_LIST[Lead 列表<br/>姓名/电话/来源/时间]
BOSS --> C_LIST[通话列表<br/>日期/时长/员工/分类]
BOSS --> METRICS[指标: 通话数/Booking数/取消数]
L_LIST -.->|"需要手动关联"| C_LIST
L_LIST -.->|"需要手动更新 Outcome"| L_LIST
style BOSS fill:#4a90d9,color:#fff
style L_LIST fill:#e9e9e9,color:#333
style C_LIST fill:#e9e9e9,color:#333
style METRICS fill:#e9e9e9,color:#333
老板的 "So What?" 反应:
| 系统展示的数据 | 老板的反应 | 缺失的关键 |
|---|---|---|
| "今天有 12 通 intro call,3 个 booking" | "那 3 个人来了吗?买了吗?" | 到店 + 成交追踪 |
| "Lead Jane Smith 3 天前打来" | "为什么没人回她电话?她是热的还是冷的?" | 响应时间 + 温度标签 |
| "Sarah 今天接了 8 通电话" | "她产生了多少收入?" | 收入归因 |
| "有 2 个 cancellation" | "为什么取消?能挽回吗?" | (这个 prompt 其实做得不错!) |
| "Coaching: Sarah 应该这样说..." | "她有在改进吗?" | 时间维度的技能追踪 |
核心结论
系统告诉老板 "What happened",但老板需要 "What should I do next"。
6.2 After(理想)¶
graph TD
BOSS[老板登录 Dashboard]
BOSS --> TODAY["📊 今日概要<br/>12通话 | 3 booking | 2待跟进<br/>明星员工: Sarah (33%转化)"]
BOSS --> FUNNEL["📈 完整漏斗<br/>47 Leads → 43 Calls → 18 Booked<br/>→ 12 到店 → 8 成交 = $4,800"]
BOSS --> TASKS["✅ Follow-up 队列<br/>5个待跟进 | 2个即将超时<br/>Jane Smith: CC未采集, 剩余4h"]
BOSS --> LEADS["🔥 Lead 列表<br/>🟢 Hot 3 | 🟡 Warm 8 | 🔴 Cold 5<br/>响应时间: 平均 34 分钟"]
BOSS --> PERF["👤 Staff 绩效<br/>Sarah: 12通话→4 booking (33%)<br/>弱点: 异议处理 | 趋势: ↑ 改善中"]
BOSS --> JOURNEY["🛤️ Lead 旅程<br/>Jane: 2/7到达 → 2/8首次联系(27min)<br/>→ 2/9预约 → 2/12到店 → 2/12成交"]
style BOSS fill:#4a90d9,color:#fff
style TODAY fill:#d4edda,color:#333
style FUNNEL fill:#d4edda,color:#333
style TASKS fill:#fff3cd,color:#333
style LEADS fill:#d4edda,color:#333
style PERF fill:#d4edda,color:#333
style JOURNEY fill:#d4edda,color:#333
7. Prompt 升级建议¶
7.1 需要新增的 Call Type¶
| 新增 | 分类 | 理由 |
|---|---|---|
| followupcall | revenue_impacting | 区分首次接触 vs 后续跟进,独立衡量跟进效果 |
| retention_call | revenue_impacting | 主动关怀不活跃会员,而不是等他们取消 |
| referral_call | revenue_impacting (从 other 升级) | 直接影响 Leads 数量,是低成本获客渠道 |
| appointment_reminder | service (独立于 booking_confirmation) | pre-event 确认 ≠ online booking follow-up |
7.2 需要新增的输出字段¶
| 字段 | 类型 | 说明 |
|---|---|---|
intent_level |
high / medium / low |
客户转化意向评估 |
call_sequence |
first_contact / follow_up / retention |
通话在 Lead 生命周期中的阶段 |
objection_type |
price / time / trust / none |
客户主要异议类型 |
recommended_next_action |
string | AI 建议的下一步行动 |
8. 实施路线图¶
详细的每个 Phase Before/After 描述和实施清单,请参阅 分阶段路线图。
9. Debate 记录¶
9.1 共识区(三个 Agent 全部同意)¶
- 必须打通 Lead → Call 的数据链路 — 这是最高优先级,没有这个其他都白搭
- 必须实现 CUSTOMER_HISTORY 注入 — prompt 占位符已经写好了,但代码没实现,这是巨大浪费
- Follow-up Call 必须作为独立类型存在 — 不能把首次接触和后续跟进混为一谈
- Call outcome 应该自动写回 Lead — 手动更新 outcome 是不可持续的
9.2 争议区(Agent 们有不同观点)¶
9.2.1 争议 1:A/B/C/D 分级要不要加到 Prompt 里?¶
- Agent 2(强烈支持): "这是 80/20 法则的体现,直接告诉销售'这个人值不值得花 20 分钟'"
- Agent 3(谨慎支持): "先做一个简单的 Hot/Warm/Cold 三级标签就够了,A/B/C/D 太复杂,老板看不懂"
- Agent 1(中立): "现在连 Lead 和 Call 都没打通,先做基础数据链路,分级是第二步"
判断: Agent 1 说得对——先打通数据,再做分级。但 Agent 3 的 Hot/Warm/Cold 简化方案比 Agent 2 的 A/B/C/D 更实用。
9.2.2 争议 2:模块化架构值不值得做?¶
- Agent 2: "文档描述了完美的模块化,但现在客户只有 OrangeTheory,做模块化是过早优化"
- Agent 3: "模块化是销售策略,不是技术架构。先把功能做出来,卖的时候再包装成套餐"
判断: 同意 Agent 3——模块化是 pricing 策略,不是当前的技术需求。先把功能做好,package 是商业层面的事。
9.2.3 争议 3:实时通话辅助值不值得做?¶
- Agent 3(提出): "Real-time call assist 是终极差异化——销售接电话时,AI 实时提示话术"
- Agent 2: "这是 12+ 周的工作量,且需要 live transcription,技术复杂度远超当前能力"
判断: 现阶段不值得做。投入产出比太低,而且现有的 post-call coaching 已经很强了,先把闭环做好。
9.2.4 争议 4:Referral Call 要不要从 "other" 升级到 "revenue_impacting"?¶
- Agent 2(强烈支持): "文档说 referral 是'低成本获客高效渠道',放在 other 类别是对 referral 价值的贬低"
- Agent 1(中立): "取决于 OrangeTheory 是否真的有 referral program"
- Agent 3: "如果老板看到 referral call 数量为零,他会问'我们没在做 referral 吗?'——这本身就是有价值的 insight"
判断: 应该升级。Referral 影响 Leads 数量,直接关联收入公式
新客收入 = Leads × 转化率 × 客单价。
9.3 通过的想法¶
| 想法 | 结论 | 理由 |
|---|---|---|
| CUSTOMER_HISTORY 注入 | ✅ 立即做 | Prompt 已设计好,代码缺实现,ROI 最高 |
| Phone 格式统一 | ✅ 立即做 | 基础数据一致性,阻塞其他改进 |
| AI Outcome 自动回写 | ✅ 立即做 | 消除手动更新瓶颈 |
| Follow-up Call 类型 | ✅ Phase 3 | 无法区分首次和跟进是重大分析盲区 |
| Retention Call 类型 | ✅ Phase 3 | 系统完全被动,需要主动干预能力 |
| Hot/Warm/Cold 标签 | ✅ Phase 2 | 比 A/B/C/D 简单,老板更容易理解 |
| Referral 升级到 revenue | ✅ Phase 3 | 直接影响 Leads 数量,不该在 other 类别 |
9.4 保留/推迟的想法¶
| 想法 | 结论 | 理由 |
|---|---|---|
| Lead 自动分配给 Staff | ⏸️ 推迟 | 当前团队小,手动可行,自动化收益不大 |
| A/B/C/D 完整分级 | ⏸️ 简化为 Hot/Warm/Cold | 4 级太复杂,3 级更实用 |
| 模块化架构 | ⏸️ 推迟 | 当前只有 1 个客户,是 pricing 策略不是技术需求 |
| ML 预测 Lead 转化率 | ⏸️ 数据不足 | 需要 200+ 标注数据集,目前没有 |
9.5 否定的想法¶
| 想法 | 结论 | 理由 | 谁否定的 |
|---|---|---|---|
| 实时通话辅助 | ❌ 不做 | 12+ 周工作量,需 live transcription,技术复杂度远超收益 | Agent 2 + 综合判断 |
| ML 预测 Lead 转化率 | ❌ 数据不足 | 需要 200+ 标注数据集,目前没有 | Agent 3(自己提出也自己承认太早) |
| 完整 CRM 对接 | ❌ 风险高 | OTF 有自己的系统,API 不明确 | Agent 1 |
| 5 层模块化架构 | ❌ 过早优化 | 文档理想态,当前只有 1 个客户 | Agent 2 + Agent 3 |
| Staff Development Learning Paths | ❌ 太远 | 需 UX + 内容 + ML,10+ 周 | 所有 Agent 同意太远期 |
10. Agent 1 关键代码级发现¶
10.1 发现 1:CUSTOMER_HISTORY 是最大的已有但未实现的功能¶
prompt-builder.ts:35-61 — 处理了 {STAFF_LIST_WILL_BE_INJECTED_HERE},完全没有处理 {CUSTOMER_HISTORY_WILL_BE_INJECTED_HERE}。
AI 已经被设计为能理解客户历史(prompt 里写了怎么用),但 Lambda 代码从来没有注入这些数据。这是一个 "花了 80% 的钱但漏了最后 20%" 的问题。
10.2 发现 2:studio-api 已有 Lead-Call 匹配,但只在运行时¶
call-history.ts:142-156 的 phone 匹配逻辑:
- 前端每次请求 Lead 列表时,API 实时查 call-analysis 表
- 用 phone number 匹配
fromPhoneNumber或toPhoneNumber - 但结果不持久化——下次请求还要重新匹配
10.3 发现 3:Lead Outcome 已有 5 种状态但全靠手动¶
// studio-api/apps/api/src/routes/leads/types.ts
type LeadOutcomeValue =
'INTRO_BOOKED' | 'SELF_BOOKED' | 'INVALID_LEAD' | 'NO_CALL_LIST' | 'CLOSED'
有 outcome history 追踪(谁在什么时候改的),但:
- 没有从 AI 分析自动推断
- 没有 outcome 变更事件触发
- 没有与 AI 的
primary_outcome交叉验证
10.4 发现 4:前端有 Lead 分组逻辑但很原始¶
lead-grouping.ts 按 phone + 3 天窗口分组,能检测 pre-contact calls,但没有生命周期阶段标签。
11. 核心 Metrics(改进后可追踪的指标)¶
| 指标 | 当前状态 | 改进后 | 意义 |
|---|---|---|---|
| Response Time | 无法追踪 | Lead 到达 → 首次通话 | 影响转化率的第一要素 |
| Lead Contact Rate | 无法追踪 | 有通话的 Lead / 总 Lead | 员工执行力 |
| Booking Rate | 手动计算 | AI 自动统计 intro_booking | 通话转预约效率 |
| Follow-up Effectiveness | 无法区分 | 跟进电话的独立转化率 | 持续跟进的价值 |
| Staff Conversion Rate | 无 | 每个员工的 Lead → Booking 率 | 绩效差异化管理 |
| Coaching Trend | 无 | 团队弱点趋势 + 改善速度 | 培训 ROI |
| Lead Temperature Accuracy | 无 | Hot/Warm/Cold 预测 vs 实际转化 | AI 分级准确性 |
12. 附录 A:关键文件索引¶
| 组件 | 文件路径 | 关键行数 | 用途 |
|---|---|---|---|
| Lead 采集 | lead-tracking/src/poller.ts |
112-190 | 邮件解析和存储 |
| Lead Schema | lead-tracking/lib/leadtracking-stack.ts |
17-50 | DynamoDB 表和 GSI |
| AI Prompt 构建 | callytics-infra/lambda/ai-analysis-processor/src/core/prompt-builder.ts |
35-61 | Prompt 占位符替换 |
| AI 字段映射 | callytics-infra/config/schemas/orangeTheory/ai-mappings/ai-mapping-v1.0.0.json |
全文件 | AI 输出 → DynamoDB 字段 |
| Standard Prompt | callytics-infra/config/schemas/orangeTheory/prompts/standard-v1.0.0.txt |
全文件 | 1248 行 AI 分析指令 |
| Lead 列表 API | studio-api/apps/api/src/routes/leads/list.ts |
88-259 | Lead + Call 查询和匹配 |
| Call 匹配逻辑 | studio-api/apps/api/src/routes/leads/call-history.ts |
102-164 | Phone-based call 分发 |
| Outcome 更新 | studio-api/apps/api/src/routes/leads/update-outcome.ts |
44-164 | 手动 outcome 更新 |
| Lead 类型定义 | studio-api/apps/api/src/routes/leads/types.ts |
1-70 | 响应格式定义 |
| 前端 Lead 分组 | studio-web/src/pages/lead-tracker-old/data/lead-grouping.ts |
1-137 | 前端分组逻辑 |
13. 附录 B:Lead Outcome 定义(实际代码)¶
代码中没有 stage 字段。Lead 状态通过 outcome: LeadOutcomeValue 单一字段跟踪,定义在 studio-api/apps/api/src/routes/leads/types.ts:
type LeadOutcomeValue = 'INTRO_BOOKED' | 'SELF_BOOKED' | 'INVALID_LEAD' | 'NO_CALL_LIST' | 'CLOSED';
| Outcome | 含义 | 设置方式 |
|---|---|---|
| (null/undefined) | 新 Lead,尚未处理 | 默认状态 |
INTRO_BOOKED |
已预约体验课 | 自动:AI 判断 intro_booking + success 或 membership_purchase_related + success |
SELF_BOOKED |
客户自行在线预约 | 手动:Dashboard 用户标记 |
INVALID_LEAD |
无效 Lead(空号/非目标) | 手动:Dashboard 用户标记(终态,不可被自动覆盖) |
NO_CALL_LIST |
不可联系 | 手动:Dashboard 用户标记(终态,不可被自动覆盖) |
CLOSED |
已关闭/已转化 | 手动:Dashboard 用户标记(终态,不可被自动覆盖) |