265 lines
8.7 KiB
Markdown
265 lines
8.7 KiB
Markdown
---
|
||
created: 2026-03-29
|
||
type: project
|
||
status: 未开始
|
||
parent: "[[Smart Support]]"
|
||
phase: 4
|
||
timeline: 第 6-7 周
|
||
tags:
|
||
- phase-4
|
||
- analytics
|
||
- replay
|
||
- dashboard
|
||
- postgresql
|
||
- pagination
|
||
- data-visualization
|
||
- resolution-rate
|
||
- cost-tracking
|
||
---
|
||
|
||
# Phase 4:分析 + 回放
|
||
|
||
## 目标
|
||
|
||
让客户看到 AI 客服的 ROI。对话回放让客户信任系统(看到 AI 为什么做了某个决定),分析仪表盘用数据证明价值(自动解决了多少问题、省了多少成本)。这个阶段结束时,Smart Support 是一个完整可演示的产品。
|
||
|
||
## 前置条件
|
||
|
||
- [[Smart Support/Phase 1 - 核心框架]] 完成(PostgresSaver 已持久化所有 checkpoint 数据)
|
||
- [[Smart Support/Phase 3 - OpenAPI 自动发现]] 完成(有真实工具调用数据可分析)
|
||
- Token 用量统计回调已运行(Phase 1 实现)
|
||
|
||
## 阶段产出
|
||
|
||
- 对话回放页面:逐步展示 Agent 的决策过程
|
||
- 分析仪表盘:解决率、Agent 使用率、升级率、每对话成本
|
||
- 数据驱动的 ROI 证明能力
|
||
|
||
## 集成检查点
|
||
|
||
第 7 周末验证:
|
||
1. 完成几轮对话后,打开回放页面 → 看到完整决策时间线
|
||
2. 分析仪表盘显示正确的解决率和成本数据
|
||
3. 零数据状态(新部署)→ 仪表盘显示空状态引导
|
||
4. 200+ 轮对话的回放 → 分页正常,不卡顿
|
||
|
||
---
|
||
|
||
## 任务清单
|
||
|
||
### 1. 对话回放 API
|
||
|
||
- [ ] 端点 `GET /api/conversations` → 对话列表(分页)
|
||
- 返回:`thread_id`, 开始时间, 消息数, 最终状态(resolved/escalated/abandoned)
|
||
- 支持筛选:按状态、按日期范围、按 agent
|
||
- 分页参数:`page`, `page_size`(默认 20)
|
||
|
||
- [ ] 端点 `GET /api/replay/{thread_id}` → 单个对话的回放数据(分页)
|
||
- 查询 PostgresSaver checkpoint 表,按 checkpoint_id 排序
|
||
- 每个 checkpoint 解析为结构化时间线事件:
|
||
|
||
```json
|
||
{
|
||
"thread_id": "uuid",
|
||
"total_steps": 15,
|
||
"page": 1,
|
||
"page_size": 50,
|
||
"events": [
|
||
{
|
||
"step": 1,
|
||
"timestamp": "2026-04-10T14:30:00Z",
|
||
"type": "user_message",
|
||
"content": "查询订单 1042 的状态"
|
||
},
|
||
{
|
||
"step": 2,
|
||
"timestamp": "2026-04-10T14:30:01Z",
|
||
"type": "routing",
|
||
"agent": "order_lookup",
|
||
"reasoning": "用户请求查询订单状态"
|
||
},
|
||
{
|
||
"step": 3,
|
||
"timestamp": "2026-04-10T14:30:02Z",
|
||
"type": "tool_call",
|
||
"agent": "order_lookup",
|
||
"tool": "get_order_status",
|
||
"input": {"order_id": "1042"},
|
||
"output": {"status": "shipped", "tracking": "SF1234567"},
|
||
"duration_ms": 230
|
||
},
|
||
{
|
||
"step": 4,
|
||
"timestamp": "2026-04-10T14:30:03Z",
|
||
"type": "agent_response",
|
||
"agent": "order_lookup",
|
||
"content": "您的订单 1042 已发货,运单号 SF1234567",
|
||
"tokens": {"input": 450, "output": 35}
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
- 分页:`page` + `page_size` 控制每页 events 数量
|
||
- thread 不存在 → 404
|
||
|
||
- [ ] 端点 `GET /api/replay/{thread_id}/summary` → 对话摘要
|
||
- 总步骤数、涉及的 agents、工具调用次数、总 token 用量、总耗时、最终状态
|
||
|
||
### 2. 对话回放 UI
|
||
|
||
- [ ] 对话列表页:
|
||
- 表格显示所有对话(时间、消息数、状态、涉及 agent)
|
||
- 状态标签:🟢 已解决 / 🟡 已升级 / ⚫ 已放弃
|
||
- 点击进入回放详情
|
||
|
||
- [ ] 回放详情页:
|
||
- 左侧:原始聊天记录(用户消息 + AI 回复)
|
||
- 右侧:决策时间线(路由决策、工具调用、参数、返回值、耗时)
|
||
- 时间线高亮:
|
||
- 工具调用 → 蓝色
|
||
- interrupt 确认 → 黄色
|
||
- 错误/升级 → 红色
|
||
- 每个步骤可展开查看详细信息(工具输入输出、token 用量)
|
||
- 支持键盘导航(上/下箭头逐步浏览)
|
||
|
||
- [ ] 长对话分页加载(滚动加载或分页按钮)
|
||
|
||
### 3. 分析数据查询
|
||
|
||
- [ ] 数据来源:PostgresSaver checkpoint 表 + token 用量表
|
||
- [ ] 核心指标计算:
|
||
|
||
**解决率**
|
||
```sql
|
||
-- resolved = 至少一次成功工具调用 且 未触发升级
|
||
resolved_count / total_conversations * 100
|
||
```
|
||
|
||
**Agent 使用率**
|
||
```sql
|
||
-- 每个 agent 被路由到的次数占总路由次数的百分比
|
||
SELECT agent_name, COUNT(*) * 100.0 / total_routes AS usage_pct
|
||
```
|
||
|
||
**升级率**
|
||
```sql
|
||
-- 触发 webhook 升级的对话占总对话的百分比
|
||
escalated_count / total_conversations * 100
|
||
```
|
||
|
||
**每对话成本**
|
||
```sql
|
||
-- 基于 token 用量计算
|
||
SELECT thread_id,
|
||
SUM(input_tokens) * input_price + SUM(output_tokens) * output_price AS cost
|
||
```
|
||
|
||
**对话量趋势**
|
||
```sql
|
||
-- 按天/周/月聚合对话数量
|
||
SELECT DATE(created_at) AS date, COUNT(DISTINCT thread_id) AS conversations
|
||
GROUP BY date ORDER BY date
|
||
```
|
||
|
||
- [ ] 时间范围筛选:今天 / 7 天 / 30 天 / 自定义
|
||
- [ ] 所有查询加索引优化(checkpoint 表的 thread_id + timestamp)
|
||
|
||
### 4. 分析仪表盘 API
|
||
|
||
- [ ] 端点 `GET /api/analytics/overview` → 概览数据
|
||
|
||
```json
|
||
{
|
||
"period": "last_7_days",
|
||
"total_conversations": 142,
|
||
"resolution_rate": 73.2,
|
||
"escalation_rate": 12.7,
|
||
"avg_cost_per_conversation": 0.045,
|
||
"total_cost": 6.39,
|
||
"avg_messages_per_conversation": 4.2,
|
||
"avg_resolution_time_seconds": 45
|
||
}
|
||
```
|
||
|
||
- [ ] 端点 `GET /api/analytics/agents` → Agent 使用分布
|
||
|
||
```json
|
||
{
|
||
"agents": [
|
||
{"name": "order_lookup", "usage_pct": 45.3, "resolution_rate": 89.1},
|
||
{"name": "order_actions", "usage_pct": 30.2, "resolution_rate": 72.5},
|
||
{"name": "discount", "usage_pct": 15.8, "resolution_rate": 65.0},
|
||
{"name": "fallback", "usage_pct": 8.7, "resolution_rate": 20.0}
|
||
]
|
||
}
|
||
```
|
||
|
||
- [ ] 端点 `GET /api/analytics/trend` → 对话量趋势(按日)
|
||
- [ ] 端点 `GET /api/analytics/costs` → 成本趋势 + 按 agent 成本分布
|
||
- [ ] 所有端点支持 `period` 参数(`today`, `7d`, `30d`, `custom`)
|
||
|
||
### 5. 分析仪表盘 UI
|
||
|
||
- [ ] 概览卡片(顶部):
|
||
- 解决率(百分比 + 趋势箭头)
|
||
- 总对话数
|
||
- 升级率
|
||
- 平均成本/对话
|
||
- [ ] Agent 使用分布(饼图或条形图)
|
||
- [ ] 对话量趋势(折线图,按日)
|
||
- [ ] 成本趋势(折线图,按日)
|
||
- [ ] 零数据状态:
|
||
- 没有对话数据时,显示引导页面:「开始你的第一次对话,数据将在这里展示」
|
||
- 卡片显示 "—" 而非 0 或 NaN
|
||
|
||
### 6. 对话状态判定
|
||
|
||
- [ ] 实现对话最终状态判定逻辑:
|
||
- **resolved**:至少一次成功工具调用 + 未触发升级 webhook
|
||
- **escalated**:触发了升级 webhook
|
||
- **abandoned**:最后一条消息是用户发送的,且超过 30 分钟无后续(session TTL 过期)
|
||
- [ ] 状态写入 checkpoint metadata 或独立表
|
||
- [ ] 状态判定在对话结束时(WebSocket 断开 或 TTL 过期)异步执行
|
||
|
||
### 7. 测试
|
||
|
||
- [ ] **回放 API 测试:** 有效 thread_id → 返回结构化时间线
|
||
- [ ] **回放 API 测试:** 不存在的 thread_id → 404
|
||
- [ ] **回放 API 测试:** 大对话(200+ 步骤)→ 分页正常
|
||
- [ ] **回放 API 测试:** 时间线事件类型覆盖(user_message, routing, tool_call, agent_response, interrupt, error)
|
||
- [ ] **分析 API 测试:** overview 返回正确的解决率计算
|
||
- [ ] **分析 API 测试:** agent 使用分布百分比之和 = 100%
|
||
- [ ] **分析 API 测试:** 成本计算准确(基于 token 用量 × 价格)
|
||
- [ ] **分析 API 测试:** 时间范围筛选正确
|
||
- [ ] **零数据测试:** 无对话 → 所有指标返回合理默认值(非 NaN/null)
|
||
- [ ] **状态判定测试:** 成功工具调用 + 无升级 → resolved
|
||
- [ ] **状态判定测试:** 触发 webhook → escalated
|
||
- [ ] **状态判定测试:** 用户最后发言 + 超时 → abandoned
|
||
- [ ] **E2E 测试:** 完成对话 → 回放页面正确展示 → 仪表盘数据更新
|
||
|
||
## 技术要点
|
||
|
||
| 功能 | 实现方式 | 说明 |
|
||
|------|---------|------|
|
||
| 回放数据 | PostgresSaver checkpoint 表查询 | 按 thread_id + checkpoint_id 排序 |
|
||
| 分页 | OFFSET/LIMIT 或 cursor-based | 大数据量用 cursor |
|
||
| 图表 | Recharts 或 Chart.js | React 图表库 |
|
||
| 索引 | checkpoint 表加 thread_id + created_at 索引 | 保证查询性能 |
|
||
| 状态判定 | 异步任务 | WebSocket 断开或 TTL 到期时触发 |
|
||
|
||
## 风险与缓解
|
||
|
||
| 风险 | 影响 | 缓解措施 |
|
||
|------|------|---------|
|
||
| Checkpoint 数据格式变化 | 回放解析失败 | 版本化 checkpoint 格式,解析失败降级显示原始数据 |
|
||
| 大量对话数据查询慢 | 仪表盘加载慢 | 加索引 + 预聚合热门查询(物化视图) |
|
||
| 解决率定义不准确 | 指标误导 | 可配置定义,后续加入客户满意度信号 |
|
||
| Token 价格变化 | 成本计算不准 | 价格配置化,支持不同模型不同价格 |
|
||
|
||
## Related
|
||
|
||
- [[Smart Support/Phase 3 - OpenAPI 自动发现]]
|
||
- [[Smart Support/Phase 5 - 打磨 + 演示]]
|
||
- [[Smart Support]]
|