8.7 KiB
8.7 KiB
created, type, status, parent, phase, timeline, tags
| created | type | status | parent | phase | timeline | tags | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2026-03-29 | project | 未开始 | Smart Support | 4 | 第 6-7 周 |
|
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 周末验证:
- 完成几轮对话后,打开回放页面 → 看到完整决策时间线
- 分析仪表盘显示正确的解决率和成本数据
- 零数据状态(新部署)→ 仪表盘显示空状态引导
- 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 解析为结构化时间线事件:
{
"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 用量表
- 核心指标计算:
解决率
-- resolved = 至少一次成功工具调用 且 未触发升级
resolved_count / total_conversations * 100
Agent 使用率
-- 每个 agent 被路由到的次数占总路由次数的百分比
SELECT agent_name, COUNT(*) * 100.0 / total_routes AS usage_pct
升级率
-- 触发 webhook 升级的对话占总对话的百分比
escalated_count / total_conversations * 100
每对话成本
-- 基于 token 用量计算
SELECT thread_id,
SUM(input_tokens) * input_price + SUM(output_tokens) * output_price AS cost
对话量趋势
-- 按天/周/月聚合对话数量
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→ 概览数据
{
"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 使用分布
{
"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 价格变化 | 成本计算不准 | 价格配置化,支持不同模型不同价格 |