vault backup: 2026-04-06 16:23:54

This commit is contained in:
Yaojia Wang
2026-04-06 16:23:54 +02:00
parent e4cee2f21d
commit 7ab3575374
10 changed files with 507 additions and 635 deletions

View File

@@ -1,7 +1,8 @@
---
created: 2026-03-29
updated: 2026-04-06
type: project
status: 未开始
status: COMPLETED (2026-03-31)
parent: "[[Smart Support]]"
phase: 4
timeline: 第 6-7 周
@@ -19,243 +20,57 @@ tags:
# Phase 4分析 + 回放
> Status: COMPLETED (2026-03-31)
## 目标
让客户看到 AI 客服的 ROI。对话回放让客户信任系统(看到 AI 为什么做了某个决定分析仪表盘用数据证明价值自动解决了多少问题、省了多少成本。这个阶段结束时Smart Support 是一个完整可演示的产品
## 前置条件
- [[Smart Support/Phase 1 - 核心框架]] 完成PostgresSaver 已持久化所有 checkpoint 数据)
- [[Smart Support/Phase 3 - OpenAPI 自动发现]] 完成(有真实工具调用数据可分析)
- Token 用量统计回调已运行Phase 1 实现)
让客户看到 AI 客服的 ROI。对话回放让客户信任系统,分析仪表盘用数据证明价值
## 阶段产出
- 对话回放页面:逐步展示 Agent 的决策过程
- 分析仪表盘解决率、Agent 使用率、升级率、每对话成本
- 数据驱动的 ROI 证明能力
- 回放数据模型StepType 枚举、ReplayStep、ReplayPage冻结数据类
- 检查点转换器PostgresSaver JSONB -> 结构化 ReplayStep 时间线
- 回放 APIGET /api/conversations分页列表、GET /api/replay/{thread_id}(分页时间线)
- 分析数据模型AgentUsage、InterruptStats、AnalyticsResult
- 分析事件记录器Protocol 接口 + PostgresAnalyticsRecorder + NoOpAnalyticsRecorder
- 分析查询resolution_rate、agent_usage、escalation_rate、cost_per_conversation、interrupt_stats
- 分析 APIGET /api/analytics?range=Xd
- DB 迁移analytics_events 表 + conversations 列扩展
## 集成检查点
## 新增文件
第 7 周末验证:
1. 完成几轮对话后,打开回放页面 → 看到完整决策时间线
2. 分析仪表盘显示正确的解决率和成本数据
3. 零数据状态(新部署)→ 仪表盘显示空状态引导
4. 200+ 对话的回放 → 分页正常,不卡顿
| 文件 | 用途 |
|------|------|
| `app/replay/models.py` | StepType, ReplayStep, ReplayPage |
| `app/replay/transformer.py` | Checkpoint JSONB -> ReplayStep[] |
| `app/replay/api.py` | 回放 + 对话列表 API |
| `app/analytics/models.py` | AgentUsage, InterruptStats, AnalyticsResult |
| `app/analytics/event_recorder.py` | 记录器 Protocol + 实现 |
| `app/analytics/queries.py` | SQL 查询 + get_analytics 聚合 |
| `app/analytics/api.py` | 分析 API 路由 |
---
## 分析指标
## 任务清单
| 指标 | 计算方式 |
|------|---------|
| 解决率 | 成功工具调用 + 未升级 / 总对话数 |
| Agent 使用率 | 每 Agent 路由次数占比 |
| 升级率 | 触发 Webhook 对话占比 |
| 每对话成本 | Token 用量 x 价格 |
| 中断统计 | approved/rejected/expired 分布 |
### 1. 对话回放 API
## 测试覆盖
- [ ] 端点 `GET /api/conversations` → 对话列表(分页)
- 返回:`thread_id`, 开始时间, 消息数, 最终状态resolved/escalated/abandoned
- 支持筛选:按状态、按日期范围、按 agent
- 分页参数:`page`, `page_size`(默认 20
- 新增测试74 个
- 总测试399
- 覆盖率92.87%
- 所有新模块覆盖率 81-100%
- [ ] 端点 `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 价格变化 | 成本计算不准 | 价格配置化,支持不同模型不同价格 |
- 前端页面推迟到 Phase 5
- ws_handler 事件记录推迟(注册 NoOpAnalyticsRecorder
- conversations.agents_used 列未填充
## Related