- API versioning: all REST endpoints prefixed with /api/v1/ - Structured logging: replaced stdlib logging with structlog (console/JSON modes) - Alembic migrations: versioned DB schema with initial migration - Error standardization: global exception handlers for consistent envelope format - Interrupt cleanup: asyncio background task for expired interrupt removal - Integration tests: +30 tests (analytics, replay, openapi, error, session APIs) - Frontend tests: +57 tests (all components, pages, useWebSocket hook) - Backend: 557 tests, 89.75% coverage | Frontend: 80 tests, 16 test files
1264 lines
37 KiB
Markdown
1264 lines
37 KiB
Markdown
# Smart Support -- 系统架构文档
|
|
|
|
> 版本: 1.0 | 日期: 2026-03-29 | 状态: APPROVED (CEO + ENG CLEARED)
|
|
>
|
|
> **配套文档:** 分阶段任务清单、检查点标准、风险登记册详见 [DEVELOPMENT-PLAN.md](DEVELOPMENT-PLAN.md)
|
|
|
|
---
|
|
|
|
## 目录
|
|
|
|
1. [系统概览](#1-系统概览)
|
|
2. [组件职责分解](#2-组件职责分解)
|
|
3. [数据流图](#3-数据流图)
|
|
4. [技术栈决策](#4-技术栈决策)
|
|
5. [数据库设计](#5-数据库设计)
|
|
6. [API 设计](#6-api-设计)
|
|
7. [Agent 系统架构](#7-agent-系统架构)
|
|
8. [MCP 集成层](#8-mcp-集成层)
|
|
9. [安全架构](#9-安全架构)
|
|
10. [部署架构](#10-部署架构)
|
|
11. [架构决策记录 (ADR)](#11-架构决策记录-adr)
|
|
12. [非功能性需求](#12-非功能性需求)
|
|
|
|
---
|
|
|
|
## 1. 系统概览
|
|
|
|
### 1.1 定位
|
|
|
|
Smart Support 是一个 AI 客服**行动层框架**。它不替代 Zendesk/Intercom 等现有客服平台,
|
|
而是补全这些平台缺失的能力 -- 让 AI 能直接调用内部系统完成操作(查订单、取消订单、发优惠券等)。
|
|
|
|
现有客服工具的自动化率卡在 20-30%,原因是它们只能回答问题,无法执行操作。
|
|
Smart Support 通过 MCP 协议连接内部系统,将自动化率提升到 60%+。
|
|
|
|
### 1.2 核心价值
|
|
|
|
"粘贴你的 API,获得一个能执行真实操作的智能客服。"
|
|
|
|
### 1.3 目标用户
|
|
|
|
中型电商公司(日均 500-5000 订单,5-20 名客服)的客户体验负责人。
|
|
|
|
### 1.4 高层架构图
|
|
|
|
```
|
|
+------------------+
|
|
| React Chat UI | (前端: 聊天 / 回放 / 分析仪表盘)
|
|
+--------+---------+
|
|
| WebSocket (双向, 流式)
|
|
v
|
|
+--------+---------+
|
|
| FastAPI Server | (HTTP + WebSocket 入口)
|
|
| main.py |
|
|
+--------+---------+
|
|
|
|
|
v
|
|
+--------+---------+
|
|
| Context Manager |<--- PostgresSaver (会话状态持久化)
|
|
| (LangGraph State)| langgraph-checkpoint-postgres
|
|
+--------+---------+
|
|
|
|
|
v
|
|
+--------+--------------------+
|
|
| LangGraph Supervisor | (Agent 编排 + 意图路由)
|
|
| langgraph-supervisor 0.0.30+|
|
|
+--------+--------------------+
|
|
|
|
|
+----+----+----+----+
|
|
| | | | |
|
|
v v v v v
|
|
Agent Agent Agent Agent Fallback
|
|
A B C D Agent
|
|
| | | |
|
|
v v v v
|
|
MCP MCP @tool CLI
|
|
Tools Tools Wrapper
|
|
| | | |
|
|
v v v v
|
|
+-------------------------------+
|
|
| 客户内部系统 |
|
|
| (Shopify, REST API, gRPC 等) |
|
|
+-------------------------------+
|
|
|
|
横切关注点:
|
|
+-------------------------------------------+
|
|
| interrupt() -- 写操作人工确认 (HITL) |
|
|
| callbacks.py -- Token 用量 / 成本统计 |
|
|
| analytics/ -- 解决率 / Agent 使用率 |
|
|
| replay/ -- 对话回放 API |
|
|
| openapi/ -- OpenAPI 自动发现 + SSRF 防护 |
|
|
+-------------------------------------------+
|
|
```
|
|
|
|
### 1.5 项目结构
|
|
|
|
```
|
|
smart-support/
|
|
├── backend/
|
|
│ ├── app/
|
|
│ │ ├── main.py # FastAPI + WebSocket 入口
|
|
│ │ ├── graph.py # LangGraph Supervisor 构建
|
|
│ │ ├── graph_context.py # GraphContext: 图 + 分类器 + 注册表的类型化封装
|
|
│ │ ├── ws_handler.py # WebSocket 消息分发 + 速率限制
|
|
│ │ ├── ws_context.py # WebSocketContext: WS 依赖包
|
|
│ │ ├── auth.py # API Key 认证中间件
|
|
│ │ ├── api_utils.py # 共享 API 响应工具 (envelope)
|
|
│ │ ├── agents/ # Agent 定义 + 工具绑定
|
|
│ │ ├── registry.py # YAML Agent 注册表加载器
|
|
│ │ ├── openapi/ # OpenAPI 解析 + MCP 服务器生成
|
|
│ │ │ ├── parser.py # OpenAPI 3.0 规范解析
|
|
│ │ │ ├── ssrf.py # SSRF 防护 (独立工具)
|
|
│ │ │ ├── classifier.py # LLM 端点分类
|
|
│ │ │ └── generator.py # MCP 服务器代码生成
|
|
│ │ ├── replay/ # 对话回放 API
|
|
│ │ ├── analytics/ # 数据分析查询 + API
|
|
│ │ └── callbacks.py # Token 用量统计 Callback
|
|
│ ├── agents.yaml # Agent 注册表配置
|
|
│ ├── templates/ # 垂直行业模板
|
|
│ │ ├── e-commerce.yaml
|
|
│ │ ├── saas.yaml
|
|
│ │ └── fintech.yaml
|
|
│ └── tests/
|
|
├── frontend/ # React 聊天 UI + 回放 + 仪表盘
|
|
├── docker-compose.yml # PostgreSQL + 应用
|
|
└── pyproject.toml
|
|
```
|
|
|
|
---
|
|
|
|
## 2. 组件职责分解
|
|
|
|
### 2.1 前端层 (React)
|
|
|
|
| 组件 | 职责 |
|
|
|------|------|
|
|
| Chat UI | 多轮对话界面, 流式 token 显示, interrupt 确认/拒绝交互 |
|
|
| Replay UI | 分步时间线回放 Agent 决策过程、工具调用和返回结果 |
|
|
| Analytics Dashboard | 解决率、Agent 使用率、升级率、对话成本等指标可视化 |
|
|
| OpenAPI Import UI | 粘贴 URL, 查看导入进度, 审核 LLM 分类结果 |
|
|
|
|
### 2.2 API 层 (FastAPI)
|
|
|
|
| 模块 | 职责 |
|
|
|------|------|
|
|
| main.py | 应用入口, WebSocket 端点, 静态文件服务 |
|
|
| auth.py | API Key 认证: 管理端点通过 `X-API-Key` header, WebSocket 通过 `?token=` query param |
|
|
| ws_handler.py | 双向通信: 接收用户消息, 流式返回 token, 处理 interrupt 响应 |
|
|
| graph_context.py | 类型化封装: 将编译后的图与分类器、注册表绑定, 替代猴子补丁 |
|
|
| ws_context.py | 依赖包: 将 WebSocket 处理所需的 9 个依赖打包为单一不可变对象 |
|
|
| api_utils.py | 共享响应格式: 统一的 `envelope()` 函数 |
|
|
|
|
### 2.3 Agent 编排层 (LangGraph)
|
|
|
|
| 模块 | 职责 |
|
|
|------|------|
|
|
| graph.py | 初始化 LangGraph Supervisor, 绑定 Agent + 工具 + Checkpointer |
|
|
| registry.py | 从 YAML 文件加载 Agent 定义, 验证配置合法性 |
|
|
| agents/ | Agent 定义: 每个 Agent 拥有独立的 system prompt, 工具集, 权限边界 |
|
|
|
|
### 2.4 工具集成层
|
|
|
|
| 模块 | 职责 |
|
|
|------|------|
|
|
| MCP Tools | 通过 `langchain-mcp-adapters` (MultiServerMCPClient) 连接 MCP 服务器 |
|
|
| @tool 装饰器 | 直接 REST/GraphQL HTTP 调用, 无 MCP 开销 |
|
|
| CLI Wrappers | 包装现有 CLI 工具 (Shopify CLI, AWS CLI 等), 解析 stdout/stderr |
|
|
|
|
### 2.5 持久化层
|
|
|
|
| 模块 | 职责 |
|
|
|------|------|
|
|
| PostgresSaver | LangGraph checkpoint 持久化, 支持回放和分析查询 |
|
|
| PostgreSQL | 存储会话状态、对话历史、分析数据 |
|
|
|
|
### 2.6 横切模块
|
|
|
|
| 模块 | 职责 |
|
|
|------|------|
|
|
| callbacks.py | LangChain callback, 统计每次对话的 token 用量和成本 |
|
|
| openapi/ | OpenAPI 规范解析 + SSRF 防护 + LLM 端点分类 + MCP 服务器生成 |
|
|
| replay/ | 自定义分页 API, 查询 checkpointer 状态历史 |
|
|
| analytics/ | 聚合查询: 解决率、Agent 使用率、升级率、成本 |
|
|
|
|
---
|
|
|
|
## 3. 数据流图
|
|
|
|
### 3.1 消息处理流程
|
|
|
|
```
|
|
用户输入消息
|
|
|
|
|
v
|
|
[1] WebSocket 接收消息
|
|
|
|
|
v
|
|
[2] 构造 LangGraph input (thread_id + message)
|
|
|
|
|
v
|
|
[3] Supervisor 收到消息
|
|
|
|
|
+---> [3a] 意图分类 (LLM structured output)
|
|
|
|
|
v
|
|
[4] 路由到目标 Agent (基于 Agent 描述匹配)
|
|
|
|
|
+---> [4a] 无匹配 -> Fallback Agent -> 通用回复或澄清提问
|
|
|
|
|
v
|
|
[5] Agent 执行
|
|
|
|
|
+---> [5a] 读操作: 直接调用 MCP Tool -> 返回结果
|
|
|
|
|
+---> [5b] 写操作: 触发 interrupt() -> 进入中断流程 (见 3.2)
|
|
|
|
|
v
|
|
[6] Agent 生成回复
|
|
|
|
|
v
|
|
[7] astream_events() 流式推送 token
|
|
|
|
|
v
|
|
[8] WebSocket 发送给客户端
|
|
|
|
|
v
|
|
[9] PostgresSaver 自动保存 checkpoint
|
|
```
|
|
|
|
### 3.2 中断 (Interrupt) 流程
|
|
|
|
```
|
|
Agent 调用写操作工具
|
|
|
|
|
v
|
|
[1] interrupt() 暂停图执行
|
|
|
|
|
v
|
|
[2] 服务端通过 WebSocket 发送确认提示
|
|
{type: "interrupt", action: "cancel_order", params: {...}}
|
|
|
|
|
v
|
|
[3] 客户端显示确认对话框
|
|
|
|
|
+---> [3a] 用户批准
|
|
| |
|
|
| v
|
|
| [4a] Command(resume=True) 恢复图执行
|
|
| |
|
|
| v
|
|
| [5a] 工具执行操作 -> 返回结果 -> 流式回复
|
|
|
|
|
+---> [3b] 用户拒绝
|
|
| |
|
|
| v
|
|
| [4b] Command(resume=False) 恢复图执行
|
|
| |
|
|
| v
|
|
| [5b] Agent 确认未执行 -> 流式回复
|
|
|
|
|
+---> [3c] 30 分钟无响应 (TTL 超时)
|
|
|
|
|
v
|
|
[4c] 自动取消 + 重新评估当前状态
|
|
|
|
|
v
|
|
[5c] 向用户发送过期通知 + 提供重试选项
|
|
|
|
会话 TTL 规则 (来源: design-doc.md):
|
|
- 会话采用 30 分钟滑动窗口 TTL, 每次用户消息重置计时器
|
|
- 待审批的 interrupt 延长会话 TTL, 直到用户响应或 interrupt 超时
|
|
- interrupt 自身有独立的 30 分钟固定 TTL (超时自动取消)
|
|
- WebSocket 断线重连时, 服务端重新发送未完成的 interrupt 提示
|
|
```
|
|
|
|
### 3.3 OpenAPI 导入流程
|
|
|
|
```
|
|
运维人员粘贴 OpenAPI 规范 URL
|
|
|
|
|
v
|
|
[1] SSRF 防护检查
|
|
|
|
|
+---> 私有 IP / DNS 重绑定 -> 拒绝并返回错误
|
|
|
|
|
v
|
|
[2] 获取 OpenAPI 规范文件
|
|
|
|
|
v
|
|
[3] openapi-spec-validator 验证规范格式
|
|
|
|
|
+---> 格式错误 -> 返回清晰的错误信息
|
|
|
|
|
v
|
|
[4] 解析所有端点 (路径 + 方法 + 参数 + Schema)
|
|
|
|
|
v
|
|
[5] LLM 自动分类 (异步后台任务)
|
|
| - 读/写分类
|
|
| - 客户参数识别
|
|
| - Agent 分组建议
|
|
| (通过 WebSocket 推送进度)
|
|
|
|
|
v
|
|
[6] 运维人员审核分类结果
|
|
| - 修正错误分类
|
|
| - 调整 Agent 分组
|
|
|
|
|
v
|
|
[7] 生成 MCP 服务器 + Agent YAML 配置
|
|
|
|
|
v
|
|
[8] 新工具注册到 Agent Registry
|
|
|
|
|
v
|
|
[9] 立即可在聊天中使用
|
|
```
|
|
|
|
---
|
|
|
|
## 4. 技术栈决策
|
|
|
|
| 组件 | 选型 | 理由 |
|
|
|------|------|------|
|
|
| 语言 | Python 3.11+ | LangGraph/LangChain 生态首选语言, Agent 开发最成熟 |
|
|
| Web 框架 | FastAPI | 原生 async, WebSocket 支持, 性能优秀 |
|
|
| Agent 编排 | LangGraph 1.x + langgraph-supervisor | 内置 supervisor 模式, 中间件支持, 不重复造轮子 |
|
|
| MCP 集成 | langchain-mcp-adapters | MultiServerMCPClient 管理多 MCP 连接 |
|
|
| 本地工具 | LangChain @tool 装饰器 | 简单 Python 函数即工具, 无 MCP 开销 |
|
|
| 状态持久化 | PostgresSaver (langgraph-checkpoint-postgres v3.0.5) | 从第一天起用 PostgreSQL, 支持回放/分析查询 |
|
|
| 数据库 | PostgreSQL 16 | 成熟稳定, jsonb 支持, checkpoint 兼容 |
|
|
| LLM | Claude Sonnet 4.6 (默认) | 通过 LangChain BaseChatModel 抽象, 支持切换 OpenAI/Google |
|
|
| 流式输出 | FastAPI WebSocket + astream_events() | 双向通信, 内置流式支持 |
|
|
| 前端 | React | 组件化, 生态成熟, 满足 Chat/Replay/Dashboard 三个 UI 面 |
|
|
| 部署 | Docker Compose | 单命令启动, PostgreSQL + 应用 |
|
|
| OpenAPI 验证 | openapi-spec-validator | 成熟的 Python OpenAPI 规范验证库 |
|
|
| 测试 | pytest + FastAPI TestClient | Python 测试标准, 支持 async |
|
|
|
|
### LLM 提供商抽象
|
|
|
|
```
|
|
环境变量:
|
|
LLM_PROVIDER=anthropic # anthropic | openai | google
|
|
LLM_MODEL=claude-sonnet-4-6-20250514
|
|
|
|
代码路径:
|
|
LangChain BaseChatModel -> ChatAnthropic / ChatOpenAI / ChatGoogleGenerativeAI
|
|
```
|
|
|
|
不构建自定义 wrapper。使用 LangChain 内置的提供商抽象。
|
|
|
|
---
|
|
|
|
## 5. 数据库设计
|
|
|
|
### 5.1 设计原则
|
|
|
|
- Phase 1 锁定 schema, 确保 Phase 4 分析/回放无需迁移
|
|
- PostgresSaver 管理 checkpoint 表 (由 langgraph-checkpoint-postgres 自动创建)
|
|
- 分析数据通过查询 checkpoint 表 + 自定义表聚合
|
|
|
|
### 5.2 表结构
|
|
|
|
#### checkpoints (由 PostgresSaver 自动管理)
|
|
|
|
```sql
|
|
-- langgraph-checkpoint-postgres 自动创建的表
|
|
-- 存储 LangGraph 图的每一步状态快照
|
|
CREATE TABLE checkpoints (
|
|
thread_id TEXT NOT NULL,
|
|
checkpoint_ns TEXT NOT NULL DEFAULT '',
|
|
checkpoint_id TEXT NOT NULL,
|
|
parent_checkpoint_id TEXT,
|
|
type TEXT,
|
|
checkpoint JSONB NOT NULL, -- 图状态快照
|
|
metadata JSONB DEFAULT '{}', -- 包含 step, source, writes 等
|
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
PRIMARY KEY (thread_id, checkpoint_ns, checkpoint_id)
|
|
);
|
|
|
|
-- checkpoint 写入记录
|
|
CREATE TABLE checkpoint_writes (
|
|
thread_id TEXT NOT NULL,
|
|
checkpoint_ns TEXT NOT NULL DEFAULT '',
|
|
checkpoint_id TEXT NOT NULL,
|
|
task_id TEXT NOT NULL,
|
|
idx INTEGER NOT NULL,
|
|
channel TEXT NOT NULL,
|
|
type TEXT,
|
|
blob BYTEA NOT NULL,
|
|
PRIMARY KEY (thread_id, checkpoint_ns, checkpoint_id, task_id, idx)
|
|
);
|
|
```
|
|
|
|
#### conversations (自定义 - 对话元数据)
|
|
|
|
```sql
|
|
CREATE TABLE conversations (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
thread_id TEXT UNIQUE NOT NULL, -- 关联 checkpoints.thread_id
|
|
customer_id TEXT, -- 客户标识 (可选)
|
|
status TEXT NOT NULL DEFAULT 'active', -- active | resolved | escalated
|
|
resolution_type TEXT, -- auto | human | escalated
|
|
started_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
ended_at TIMESTAMPTZ,
|
|
turn_count INTEGER DEFAULT 0,
|
|
agents_used TEXT[] DEFAULT '{}', -- 使用过的 Agent 名称
|
|
total_tokens INTEGER DEFAULT 0,
|
|
total_cost_usd NUMERIC(10,6) DEFAULT 0,
|
|
escalation_url TEXT, -- Webhook 升级目标 URL
|
|
metadata JSONB DEFAULT '{}'
|
|
);
|
|
|
|
CREATE INDEX idx_conversations_status ON conversations(status);
|
|
CREATE INDEX idx_conversations_started_at ON conversations(started_at);
|
|
```
|
|
|
|
#### interrupts (自定义 - 中断审批记录)
|
|
|
|
```sql
|
|
CREATE TABLE interrupts (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
thread_id TEXT NOT NULL REFERENCES conversations(thread_id),
|
|
agent_name TEXT NOT NULL,
|
|
action TEXT NOT NULL, -- cancel_order, apply_discount 等
|
|
parameters JSONB NOT NULL,
|
|
status TEXT NOT NULL DEFAULT 'pending', -- pending | approved | rejected | expired
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
resolved_at TIMESTAMPTZ,
|
|
resolved_by TEXT, -- customer | operator | system(ttl)
|
|
ttl_expires_at TIMESTAMPTZ NOT NULL -- created_at + 30 min
|
|
);
|
|
|
|
CREATE INDEX idx_interrupts_status ON interrupts(status);
|
|
CREATE INDEX idx_interrupts_ttl ON interrupts(ttl_expires_at)
|
|
WHERE status = 'pending';
|
|
```
|
|
|
|
#### sessions (自定义 - 会话状态持久化)
|
|
|
|
```sql
|
|
-- 用于多 worker 部署的 PostgreSQL 会话状态管理
|
|
-- PgSessionManager 使用此表替代内存中的 dict
|
|
CREATE TABLE sessions (
|
|
thread_id TEXT PRIMARY KEY,
|
|
last_activity TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
has_pending_interrupt BOOLEAN NOT NULL DEFAULT FALSE,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
```
|
|
|
|
#### analytics_events (自定义 - 分析事件流)
|
|
|
|
```sql
|
|
CREATE TABLE analytics_events (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
thread_id TEXT NOT NULL,
|
|
event_type TEXT NOT NULL, -- message | tool_call | interrupt | escalation | resolution
|
|
agent_name TEXT,
|
|
tool_name TEXT,
|
|
tokens_used INTEGER DEFAULT 0,
|
|
cost_usd NUMERIC(10,6) DEFAULT 0,
|
|
duration_ms INTEGER,
|
|
success BOOLEAN,
|
|
error_message TEXT,
|
|
metadata JSONB DEFAULT '{}',
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX idx_analytics_thread ON analytics_events(thread_id);
|
|
CREATE INDEX idx_analytics_type ON analytics_events(event_type);
|
|
CREATE INDEX idx_analytics_created ON analytics_events(created_at);
|
|
```
|
|
|
|
### 5.3 分析查询示例
|
|
|
|
```sql
|
|
-- 解决率 (成功工具调用 + 无升级)
|
|
SELECT
|
|
COUNT(*) FILTER (WHERE resolution_type = 'auto') * 100.0 / COUNT(*) AS resolution_rate
|
|
FROM conversations
|
|
WHERE started_at >= NOW() - INTERVAL '7 days';
|
|
|
|
-- Agent 使用率
|
|
SELECT unnest(agents_used) AS agent, COUNT(*) AS usage_count
|
|
FROM conversations
|
|
WHERE started_at >= NOW() - INTERVAL '7 days'
|
|
GROUP BY agent ORDER BY usage_count DESC;
|
|
|
|
-- 成本/对话
|
|
SELECT AVG(total_cost_usd) AS avg_cost
|
|
FROM conversations
|
|
WHERE ended_at IS NOT NULL AND started_at >= NOW() - INTERVAL '7 days';
|
|
```
|
|
|
|
---
|
|
|
|
## 6. API 设计
|
|
|
|
### 6.1 WebSocket 协议
|
|
|
|
**端点:** `ws://host:8000/ws`
|
|
|
|
#### 客户端 -> 服务端
|
|
|
|
```json
|
|
// 发送消息
|
|
{
|
|
"type": "message",
|
|
"thread_id": "conv-abc-123",
|
|
"content": "取消订单 #1042"
|
|
}
|
|
|
|
// 中断响应 (批准)
|
|
{
|
|
"type": "interrupt_response",
|
|
"thread_id": "conv-abc-123",
|
|
"interrupt_id": "int-xyz-789",
|
|
"approved": true
|
|
}
|
|
|
|
// 中断响应 (拒绝)
|
|
{
|
|
"type": "interrupt_response",
|
|
"thread_id": "conv-abc-123",
|
|
"interrupt_id": "int-xyz-789",
|
|
"approved": false
|
|
}
|
|
```
|
|
|
|
#### 服务端 -> 客户端
|
|
|
|
```json
|
|
// 流式 token
|
|
{
|
|
"type": "token",
|
|
"thread_id": "conv-abc-123",
|
|
"content": "正在"
|
|
}
|
|
|
|
// 中断提示 (需要人工确认)
|
|
{
|
|
"type": "interrupt",
|
|
"thread_id": "conv-abc-123",
|
|
"interrupt_id": "int-xyz-789",
|
|
"agent": "order_actions",
|
|
"action": "cancel_order",
|
|
"params": {"order_id": "1042"},
|
|
"description": "取消订单 #1042",
|
|
"ttl_seconds": 1800
|
|
}
|
|
|
|
// 工具调用通知 (UI 展示用)
|
|
{
|
|
"type": "tool_call",
|
|
"thread_id": "conv-abc-123",
|
|
"agent": "order_lookup",
|
|
"tool": "get_order_status",
|
|
"params": {"order_id": "1042"}
|
|
}
|
|
|
|
// 工具结果
|
|
{
|
|
"type": "tool_result",
|
|
"thread_id": "conv-abc-123",
|
|
"tool": "get_order_status",
|
|
"result": {"status": "shipped", "tracking": "SF1234567"}
|
|
}
|
|
|
|
// 消息完成
|
|
{
|
|
"type": "message_complete",
|
|
"thread_id": "conv-abc-123"
|
|
}
|
|
|
|
// 错误
|
|
{
|
|
"type": "error",
|
|
"thread_id": "conv-abc-123",
|
|
"message": "LLM 服务暂时不可用,请稍后重试"
|
|
}
|
|
|
|
// OpenAPI 导入进度
|
|
{
|
|
"type": "import_progress",
|
|
"task_id": "imp-456",
|
|
"stage": "classifying",
|
|
"progress": 0.6,
|
|
"message": "正在分类端点 (18/30)..."
|
|
}
|
|
```
|
|
|
|
#### 重连机制
|
|
|
|
WebSocket 断线后客户端重连:
|
|
1. 客户端使用相同 `thread_id` 重新连接
|
|
2. 服务端从 PostgresSaver 恢复会话状态
|
|
3. 如有未完成的 interrupt, 重新发送 interrupt 提示
|
|
|
|
### 6.2 REST 端点
|
|
|
|
| 方法 | 路径 | 描述 |
|
|
|------|------|------|
|
|
| GET | `/` | 聊天 UI 静态页面 |
|
|
| GET | `/api/replay/{thread_id}` | 对话回放 (分页) |
|
|
| GET | `/api/replay/{thread_id}?page=2&per_page=20` | 回放分页参数 |
|
|
| GET | `/api/analytics` | 分析仪表盘数据 |
|
|
| GET | `/api/analytics?range=7d` | 指定时间范围 |
|
|
| POST | `/api/openapi/import` | 提交 OpenAPI 规范 URL |
|
|
| GET | `/api/openapi/import/{task_id}` | 查询导入任务状态 |
|
|
| POST | `/api/openapi/import/{task_id}/review` | 提交分类审核结果 |
|
|
|
|
### 6.3 回放 API 响应格式
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"thread_id": "conv-abc-123",
|
|
"total_steps": 42,
|
|
"page": 1,
|
|
"per_page": 20,
|
|
"steps": [
|
|
{
|
|
"step": 1,
|
|
"type": "user_message",
|
|
"content": "查一下订单 1042 的状态",
|
|
"timestamp": "2026-03-29T10:00:00Z"
|
|
},
|
|
{
|
|
"step": 2,
|
|
"type": "supervisor_routing",
|
|
"target_agent": "order_lookup",
|
|
"reasoning": "用户询问订单状态,路由到 order_lookup agent",
|
|
"timestamp": "2026-03-29T10:00:01Z"
|
|
},
|
|
{
|
|
"step": 3,
|
|
"type": "tool_call",
|
|
"agent": "order_lookup",
|
|
"tool": "get_order_status",
|
|
"params": {"order_id": "1042"},
|
|
"result": {"status": "shipped"},
|
|
"duration_ms": 230,
|
|
"timestamp": "2026-03-29T10:00:02Z"
|
|
},
|
|
{
|
|
"step": 4,
|
|
"type": "agent_response",
|
|
"agent": "order_lookup",
|
|
"content": "订单 #1042 已发货...",
|
|
"tokens": 87,
|
|
"timestamp": "2026-03-29T10:00:03Z"
|
|
}
|
|
]
|
|
},
|
|
"error": null
|
|
}
|
|
```
|
|
|
|
### 6.4 分析 API 响应格式
|
|
|
|
```json
|
|
{
|
|
"success": true,
|
|
"data": {
|
|
"range": "7d",
|
|
"total_conversations": 342,
|
|
"resolution_rate": 0.62,
|
|
"escalation_rate": 0.15,
|
|
"avg_turns_per_conversation": 4.2,
|
|
"avg_cost_per_conversation_usd": 0.034,
|
|
"agent_usage": [
|
|
{"agent": "order_lookup", "count": 198, "percentage": 0.42},
|
|
{"agent": "order_actions", "count": 89, "percentage": 0.19},
|
|
{"agent": "discount", "count": 55, "percentage": 0.12}
|
|
],
|
|
"interrupt_stats": {
|
|
"total": 89,
|
|
"approved": 71,
|
|
"rejected": 12,
|
|
"expired": 6
|
|
}
|
|
},
|
|
"error": null
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 7. Agent 系统架构
|
|
|
|
### 7.1 Agent 注册表 (YAML 驱动)
|
|
|
|
所有 Agent 通过 `agents.yaml` 声明式配置:
|
|
|
|
```yaml
|
|
agents:
|
|
- name: order_lookup
|
|
description: "查询订单状态、物流信息、订单详情"
|
|
permission: read # read 操作不触发 interrupt
|
|
personality:
|
|
tone: professional
|
|
greeting: "您好,我来帮您查询订单信息。"
|
|
escalation_message: "这个问题需要人工客服介入,我来帮您转接。"
|
|
tools:
|
|
- get_order_status
|
|
- get_tracking_info
|
|
- get_order_details
|
|
|
|
- name: order_actions
|
|
description: "取消订单、修改订单、变更收货地址"
|
|
permission: write # write 操作触发 interrupt
|
|
personality:
|
|
tone: careful
|
|
greeting: "我可以帮您处理订单变更,所有操作都会先经过您的确认。"
|
|
tools:
|
|
- cancel_order
|
|
- modify_order
|
|
- update_shipping_address
|
|
|
|
- name: discount
|
|
description: "发放优惠券、应用折扣码、退款处理"
|
|
permission: write
|
|
personality:
|
|
tone: friendly
|
|
tools:
|
|
- apply_discount
|
|
- generate_coupon
|
|
- process_refund
|
|
```
|
|
|
|
### 7.2 注册表加载 (registry.py)
|
|
|
|
```
|
|
启动时:
|
|
[1] 读取 agents.yaml
|
|
[2] 验证配置合法性 (名称唯一, 工具存在, 权限合法)
|
|
- 失败: 清晰的错误信息 (文件名 + 行号)
|
|
[3] 为每个 Agent 构建 LangGraph node:
|
|
- 绑定 system prompt (含 personality 配置)
|
|
- 绑定工具集
|
|
- 设置权限边界
|
|
[4] 注册到 Supervisor
|
|
```
|
|
|
|
### 7.3 Supervisor 路由
|
|
|
|
```
|
|
+---> order_lookup (读)
|
|
|
|
|
用户消息 --> Supervisor --> order_actions (写 + interrupt)
|
|
(意图分类) |
|
|
+---> discount (写 + interrupt)
|
|
|
|
|
+---> fallback_agent (兜底)
|
|
```
|
|
|
|
路由机制:
|
|
- Supervisor 使用 LLM structured output 进行意图分类
|
|
- 基于 Agent 的 `description` 字段选择最佳匹配
|
|
- 多意图请求 (如 "取消订单并给我优惠券") 由 Supervisor 顺序编排
|
|
- 歧义意图 -> 澄清提问
|
|
- 无匹配 -> Fallback Agent 处理
|
|
|
|
### 7.4 Fallback Agent
|
|
|
|
专门处理路由失败的通用 Agent:
|
|
- 捕获所有未匹配的意图
|
|
- 提供通用帮助信息
|
|
- 引导用户更清晰地表述需求
|
|
- 记录未匹配事件供后续分析路由准确率
|
|
|
|
### 7.5 垂直行业模板
|
|
|
|
预置 YAML 模板, 新客户 5 分钟内上手:
|
|
|
|
| 模板 | 包含的 Agent | 典型工具 |
|
|
|------|-------------|---------|
|
|
| e-commerce.yaml | order_lookup, order_actions, discount, shipping | 订单查询, 取消, 退款, 物流追踪 |
|
|
| saas.yaml | account, billing, support | 账户管理, 订阅变更, 工单创建 |
|
|
| fintech.yaml | account_inquiry, transaction, dispute | 余额查询, 交易记录, 争议处理 |
|
|
|
|
---
|
|
|
|
## 8. MCP 集成层
|
|
|
|
### 8.1 三层工具架构
|
|
|
|
```
|
|
LangChain Tool Interface (统一 Python 函数)
|
|
|
|
|
+--- [1] MCP Tools (langchain-mcp-adapters)
|
|
| 用于复杂/有状态的集成
|
|
| 通过 MCP 协议 (stdio/SSE) 连接
|
|
|
|
|
+--- [2] Direct API Tools (@tool 装饰器)
|
|
| 简单 REST/GraphQL 调用
|
|
| 无 MCP 开销
|
|
|
|
|
+--- [3] CLI Wrappers (@tool 装饰器)
|
|
包装 CLI 工具 (Shopify CLI, AWS CLI)
|
|
解析 stdout/stderr
|
|
```
|
|
|
|
关键设计: LangChain 工具就是 Python 函数加描述 -- 后端实现细节对 Agent 透明。
|
|
不构建自定义工具基类。
|
|
|
|
### 8.2 MCP 连接管理
|
|
|
|
```python
|
|
# 使用 langchain-mcp-adapters 的 MultiServerMCPClient
|
|
# 每个 MCP 服务器独立连接
|
|
mcp_config = {
|
|
"shopify": {
|
|
"command": "python",
|
|
"args": ["mcp_servers/shopify_server.py"],
|
|
"transport": "stdio"
|
|
},
|
|
"internal_api": {
|
|
"url": "http://mcp-server:3000/sse",
|
|
"transport": "sse"
|
|
}
|
|
}
|
|
```
|
|
|
|
### 8.3 OpenAPI 自动生成 MCP 服务器
|
|
|
|
Phase 3 核心功能:
|
|
|
|
```
|
|
OpenAPI 3.0 规范
|
|
|
|
|
v
|
|
[解析] 提取端点 + 参数 + Schema
|
|
|
|
|
v
|
|
[分类] LLM 自动分类:
|
|
- read / write
|
|
- 客户参数 (order_id, customer_id 等)
|
|
- Agent 分组建议
|
|
|
|
|
v
|
|
[审核] 运维人员修正分类结果
|
|
|
|
|
v
|
|
[生成] 输出:
|
|
- MCP 服务器代码 (包装每个端点)
|
|
- agents.yaml 配置 (Agent 定义 + 工具绑定)
|
|
|
|
|
v
|
|
[注册] 热加载到 Agent Registry
|
|
```
|
|
|
|
### 8.4 工具故障处理
|
|
|
|
| 故障类型 | 处理策略 |
|
|
|---------|---------|
|
|
| 瞬时错误 (超时/限流) | 指数退避重试 (最多 3 次) |
|
|
| 认证失败 | 立即升级到人工, 不重试 |
|
|
| API 不可用 | 向用户显示错误 + 升级 |
|
|
| 响应格式异常 | 记录日志 + 返回友好错误消息 |
|
|
|
|
---
|
|
|
|
## 9. 安全架构
|
|
|
|
### 9.1 安全层次
|
|
|
|
```
|
|
+---------------------------------------+
|
|
| [L1] 输入验证 |
|
|
| - WebSocket 消息格式校验 |
|
|
| - 消息长度限制 |
|
|
| - Agent YAML 配置验证 |
|
|
+---------------------------------------+
|
|
| [L2] SSRF 防护 (openapi/ssrf.py) |
|
|
| - 屏蔽私有 IP (10.x, 172.16-31.x, |
|
|
| 192.168.x, 127.x, 169.254.x) |
|
|
| - DNS 重绑定攻击防护 |
|
|
| - URL 白名单 (可选) |
|
|
+---------------------------------------+
|
|
| [L3] HITL 人工确认 |
|
|
| - 所有写操作需要人工批准 |
|
|
| - 30 分钟 TTL, 过期自动取消 |
|
|
| - 重新评估当前状态后才允许重试 |
|
|
+---------------------------------------+
|
|
| [L4] 权限隔离 |
|
|
| - 每个 Agent 只能访问配置的工具集 |
|
|
| - read Agent 无法调用 write 工具 |
|
|
| - 工具级别的参数校验 |
|
|
+---------------------------------------+
|
|
| [L5] 操作审计 |
|
|
| - 每个操作记录: Agent, 参数, 结果, |
|
|
| 时间戳, 操作 ID |
|
|
| - 全量存入 PostgreSQL |
|
|
| - 支持回放和事后审查 |
|
|
+---------------------------------------+
|
|
```
|
|
|
|
### 9.2 SSRF 防护详细设计
|
|
|
|
`openapi/ssrf.py` 作为独立工具模块:
|
|
|
|
```
|
|
URL 输入
|
|
|
|
|
v
|
|
[1] 解析 URL -> 提取 hostname
|
|
|
|
|
v
|
|
[2] DNS 解析 hostname -> IP 地址
|
|
|
|
|
v
|
|
[3] 检查 IP 是否为私有地址:
|
|
- 10.0.0.0/8
|
|
- 172.16.0.0/12
|
|
- 192.168.0.0/16
|
|
- 127.0.0.0/8
|
|
- 169.254.0.0/16
|
|
- ::1, fe80::/10
|
|
- 0.0.0.0
|
|
|
|
|
+---> 私有 IP -> 拒绝, 返回明确错误
|
|
|
|
|
v
|
|
[4] 发起 HTTP 请求
|
|
|
|
|
v
|
|
[5] 二次检查: 验证实际连接的 IP (防 DNS 重绑定)
|
|
|
|
|
+---> 重绑定到私有 IP -> 中断连接, 返回错误
|
|
|
|
|
v
|
|
[6] 返回响应内容
|
|
```
|
|
|
|
### 9.3 未来安全增强 (NOT in scope, 记录于 TODOS.md)
|
|
|
|
- API Key 认证 (WebSocket 连接)
|
|
- Session-based 认证 (Dashboard/Replay/Import)
|
|
- 全端点限流
|
|
- 多租户隔离
|
|
|
|
---
|
|
|
|
## 10. 部署架构
|
|
|
|
### 10.1 Docker Compose
|
|
|
|
```
|
|
+-------------------------------------------+
|
|
| Docker Compose |
|
|
| |
|
|
| +----------------+ +------------------+ |
|
|
| | smart-support | | PostgreSQL 16 | |
|
|
| | (Python App) | | | |
|
|
| | | | - checkpoints | |
|
|
| | FastAPI :8000 +--> - conversations | |
|
|
| | React (static) | | - interrupts | |
|
|
| | | | - analytics | |
|
|
| +----------------+ +------------------+ |
|
|
| |
|
|
+-------------------------------------------+
|
|
```
|
|
|
|
```yaml
|
|
# docker-compose.yml (概念)
|
|
version: "3.9"
|
|
services:
|
|
app:
|
|
build: .
|
|
ports:
|
|
- "8000:8000"
|
|
environment:
|
|
- DATABASE_URL=postgresql://user:pass@db:5432/smartsupport
|
|
- LLM_PROVIDER=anthropic
|
|
- LLM_MODEL=claude-sonnet-4-6-20250514
|
|
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
|
|
depends_on:
|
|
- db
|
|
|
|
db:
|
|
image: postgres:16
|
|
environment:
|
|
- POSTGRES_DB=smartsupport
|
|
- POSTGRES_USER=user
|
|
- POSTGRES_PASSWORD=pass
|
|
volumes:
|
|
- pgdata:/var/lib/postgresql/data
|
|
ports:
|
|
- "5432:5432"
|
|
|
|
volumes:
|
|
pgdata:
|
|
```
|
|
|
|
### 10.2 环境变量
|
|
|
|
| 变量 | 用途 | 默认值 |
|
|
|------|------|--------|
|
|
| DATABASE_URL | PostgreSQL 连接串 | (必填) |
|
|
| LLM_PROVIDER | LLM 提供商 | anthropic |
|
|
| LLM_MODEL | 模型名称 | claude-sonnet-4-6-20250514 |
|
|
| ANTHROPIC_API_KEY | Anthropic API Key | (必填) |
|
|
| OPENAI_API_KEY | OpenAI API Key | (可选) |
|
|
| INTERRUPT_TTL_MINUTES | 中断超时时间 | 30 |
|
|
| WEBHOOK_RETRY_MAX | Webhook 最大重试次数 | 3 |
|
|
|
|
### 10.3 单命令启动
|
|
|
|
```bash
|
|
# 设置 API Key
|
|
export ANTHROPIC_API_KEY=sk-xxx
|
|
|
|
# 启动
|
|
docker compose up
|
|
|
|
# 访问
|
|
open http://localhost:8000
|
|
```
|
|
|
|
---
|
|
|
|
## 11. 架构决策记录 (ADR)
|
|
|
|
### ADR-001: 使用 LangGraph Supervisor 进行多 Agent 编排
|
|
|
|
**背景:** 需要将不同类型的客服请求路由到不同的专业 Agent。
|
|
|
|
**决策:** 使用 `langgraph-supervisor` v1.1 内置的 supervisor 模式。
|
|
|
|
**正面影响:**
|
|
- 不同 Agent 拥有独立的权限边界和工具集
|
|
- 不同操作有不同的失败模式和安全检查
|
|
- 框架内置, 无需自建编排逻辑
|
|
- 支持中间件扩展
|
|
|
|
**负面影响:**
|
|
- 每次请求增加一轮 LLM 调用 (supervisor 路由), 延迟 8-15 秒
|
|
- 原型阶段可能过度工程化 (Cross-Model Review 的质疑)
|
|
|
|
**缓解措施:** 全程流式输出 token, 降低用户感知延迟。
|
|
|
|
**替代方案:**
|
|
- 单 Agent + 工具路由: 更简单, 但权限隔离困难
|
|
- 关键词路由: 无 LLM 开销, 但准确率低
|
|
|
|
**状态:** ACCEPTED (创始人明确选择, 理由: 不同操作需要不同权限边界)
|
|
|
|
---
|
|
|
|
### ADR-002: 从第一天使用 PostgresSaver 而非 InMemorySaver
|
|
|
|
**背景:** LangGraph 提供多种 checkpointer 实现。InMemorySaver 更简单, PostgresSaver 需要数据库。
|
|
|
|
**决策:** 从 Phase 1 起使用 PostgresSaver + Docker Compose。
|
|
|
|
**正面影响:**
|
|
- Phase 4 的回放和分析功能可直接查询, 无需迁移
|
|
- 进程重启不丢失会话状态
|
|
- 数据 schema 从第一天锁定
|
|
|
|
**负面影响:**
|
|
- 开发环境需要运行 PostgreSQL (通过 Docker Compose 缓解)
|
|
- 比 InMemorySaver 配置更复杂
|
|
|
|
**替代方案:**
|
|
- InMemorySaver: 更简单但重启丢数据, 迁移到 PostgresSaver 并非简单配置切换
|
|
- SQLiteSaver: 中间方案, 但最终仍需迁移
|
|
|
|
**状态:** ACCEPTED
|
|
|
|
---
|
|
|
|
### ADR-003: WebSocket 双向通信而非 HTTP 轮询
|
|
|
|
**背景:** 需要支持流式 token 输出 + interrupt 交互。
|
|
|
|
**决策:** FastAPI WebSocket + LangGraph astream_events()。
|
|
|
|
**正面影响:**
|
|
- 真正的双向通信: 服务端推送 token, 客户端发送 interrupt 响应
|
|
- 延迟低, 无轮询开销
|
|
- LangGraph 原生支持 astream_events()
|
|
|
|
**负面影响:**
|
|
- WebSocket 连接管理复杂 (断线重连, 状态恢复)
|
|
- 不如 REST 易于调试
|
|
|
|
**替代方案:**
|
|
- SSE + REST: 服务端推送用 SSE, 客户端操作用 REST。更简单但需两个通道。
|
|
- HTTP 轮询: 最简单但延迟高, 不适合流式场景。
|
|
|
|
**状态:** ACCEPTED
|
|
|
|
---
|
|
|
|
### ADR-004: YAML 声明式 Agent 注册表
|
|
|
|
**背景:** 需要让客户和运维人员能配置 Agent, 而不需要修改代码。
|
|
|
|
**决策:** Agent 定义通过 YAML 文件配置, 启动时加载验证。
|
|
|
|
**正面影响:**
|
|
- 非开发人员可配置 Agent
|
|
- 新增 Agent = 新增配置条目 + 连接工具
|
|
- 支持垂直行业模板 (预置 YAML)
|
|
- 配置可版本控制
|
|
|
|
**负面影响:**
|
|
- YAML 配置错误的调试体验不如代码
|
|
- 需要构建配置验证逻辑
|
|
|
|
**缓解措施:** 启动时严格验证, 错误信息包含文件名和行号。
|
|
|
|
**状态:** ACCEPTED
|
|
|
|
---
|
|
|
|
### ADR-005: LangGraph interrupt() 实现 HITL 而非自定义审批系统
|
|
|
|
**背景:** 写操作需要人工确认。
|
|
|
|
**决策:** 使用 LangGraph 内置的 `interrupt()` 函数暂停图执行, 等待用户响应。
|
|
|
|
**正面影响:**
|
|
- 框架内置, 无需自建状态机
|
|
- 与 checkpointer 深度集成, 中断状态自动持久化
|
|
- 使用 `Command(resume=value)` 恢复, API 简洁
|
|
|
|
**负面影响:**
|
|
- 需要自建 TTL 超时逻辑 (30 分钟)
|
|
- 需要处理 WebSocket 断线后重发 interrupt
|
|
|
|
**状态:** ACCEPTED
|
|
|
|
---
|
|
|
|
### ADR-006: OpenAPI 规范解析 + LLM 分类 + 人工审核三步流程
|
|
|
|
**背景:** 核心卖点 "粘贴 API, 获得客服" 需要自动理解 API 端点。
|
|
|
|
**决策:** 三步流程: 解析规范 -> LLM 自动分类 -> 人工审核修正。
|
|
|
|
**正面影响:**
|
|
- 自动化程度高: LLM 处理大部分分类工作
|
|
- 人工审核兜底: 防止 LLM 错误分类导致安全问题 (将读操作误分为写)
|
|
- 异步执行 + WebSocket 进度推送, 不阻塞聊天
|
|
|
|
**负面影响:**
|
|
- LLM 分类成本 (大型 API 可能有 100+ 端点)
|
|
- 分类准确率取决于 API 文档质量
|
|
|
|
**替代方案:**
|
|
- 纯手动配置: 安全但耗时
|
|
- 纯 LLM 自动化: 快但有安全风险
|
|
|
|
**状态:** ACCEPTED
|
|
|
|
---
|
|
|
|
### ADR-007: SSRF 防护作为独立工具模块
|
|
|
|
**背景:** OpenAPI URL 导入功能允许用户提供任意 URL, 存在 SSRF 风险。
|
|
|
|
**决策:** 构建独立的 `openapi/ssrf.py` 工具, 屏蔽私有 IP + DNS 重绑定。
|
|
|
|
**正面影响:**
|
|
- 独立模块, 可在 Phase 3 前并行开发
|
|
- 可复用于其他需要外部 URL 访问的场景
|
|
- 双重检查 (DNS 解析前 + 实际连接后)
|
|
|
|
**状态:** ACCEPTED
|
|
|
|
---
|
|
|
|
## 12. 非功能性需求
|
|
|
|
### 12.1 性能
|
|
|
|
| 指标 | 目标 | 备注 |
|
|
|------|------|------|
|
|
| 首 token 延迟 | < 2 秒 | Supervisor 路由 + Agent 启动 |
|
|
| 端到端响应时间 | 8-15 秒 | 含 LLM 调用, 通过流式输出缓解感知延迟 |
|
|
| MCP 工具调用 | < 5 秒 | 取决于下游 API |
|
|
| 回放 API | < 500ms | 分页查询, 每页 20 步 |
|
|
| 分析查询 | < 2 秒 | PostgreSQL 聚合查询 + 索引 |
|
|
| WebSocket 消息 | < 100ms | 本地处理延迟 |
|
|
|
|
### 12.2 可扩展性
|
|
|
|
**当前阶段 (原型):**
|
|
- 单实例部署, Docker Compose
|
|
- 单租户架构
|
|
- 预期负载: 并发 10-50 个对话
|
|
|
|
**扩展路线图:**
|
|
|
|
| 阶段 | 用户规模 | 架构变更 |
|
|
|------|---------|---------|
|
|
| 原型 | 1-10 并发 | 单实例 Docker Compose |
|
|
| 首个客户 | 10-50 并发 | 增加连接池, 优化查询 |
|
|
| 多客户 | 50-200 并发 | 多租户隔离, 水平扩展应用层 |
|
|
| 规模化 | 200+ 并发 | Redis 缓存层, 读写分离, CDN 静态资源 |
|
|
|
|
### 12.3 可靠性
|
|
|
|
| 故障场景 | 处理策略 |
|
|
|---------|---------|
|
|
| LLM API 超时/限流 | 向用户返回错误消息, 建议重试 |
|
|
| MCP 工具调用失败 | 升级到人工 + 显示错误消息 |
|
|
| PostgreSQL 连接断开 | try/except 包裹图调用, 返回用户友好错误 |
|
|
| WebSocket 断线 | 客户端自动重连, 服务端恢复状态 |
|
|
| 中断 TTL 过期 | 自动取消 + 提供重试选项 |
|
|
| Webhook 目标不可达 | 指数退避重试 (最多 3 次) + 记录日志 |
|
|
| 无效 YAML 配置 | 启动时检查, 清晰报错 (文件+行号) |
|
|
|
|
### 12.4 可测试性
|
|
|
|
| 测试类型 | 覆盖范围 | 工具 |
|
|
|---------|---------|------|
|
|
| 单元测试 | Agent 逻辑, SSRF 防护, YAML 解析 | pytest |
|
|
| 集成测试 | WebSocket 消息流, 图调用, Checkpoint | pytest + FastAPI TestClient |
|
|
| E2E 测试 | 6 个关键流程 (见下) | pytest |
|
|
|
|
**6 个 E2E 关键流程:**
|
|
1. 快乐路径: 查询订单状态 -> 获得答案
|
|
2. 取消+批准: 取消订单 -> interrupt -> 批准 -> 确认取消
|
|
3. 取消+拒绝: 取消订单 -> interrupt -> 拒绝 -> 未执行
|
|
4. 多轮上下文: "查订单1042" -> "取消那个" -> 正确解析指代
|
|
5. OpenAPI 导入: 粘贴规范 URL -> 工具生成 -> 聊天中使用新工具
|
|
6. 对话回放: 选择已完成对话 -> 分步回放正确渲染
|
|
|
|
**覆盖率目标:** 80%+
|
|
|
|
### 12.5 成本控制
|
|
|
|
| 措施 | 说明 |
|
|
|------|------|
|
|
| Prompt 缓存 | 从第一天启用 (Phase 1 任务 1.4.5), 减少重复 system prompt 的 LLM 成本。来源: TODOS.md 设计变更 |
|
|
| Token 用量统计 | LangChain callback 记录每次对话的 token 消耗 |
|
|
| 成本/对话指标 | 在分析仪表盘展示, 支持优化决策 |
|
|
| LLM 提供商可切换 | 可根据成本/性能在 Claude/GPT/Gemini 间切换 |
|
|
|
|
### 12.6 NOT in Scope
|
|
|
|
> 完整的范围外事项清单见 [DEVELOPMENT-PLAN.md 范围外事项](DEVELOPMENT-PLAN.md#范围外事项-来自工程评审)。
|
|
> 关键排除项: 认证/授权、多租户、CI/CD、限流、Zendesk/Intercom 集成、移动端、i18n、计费。
|
|
|
|
---
|
|
|
|
## 附录: 关键参考文档
|
|
|
|
| 文档 | 路径 | 内容 |
|
|
|------|------|------|
|
|
| **开发计划** | [`docs/DEVELOPMENT-PLAN.md`](DEVELOPMENT-PLAN.md) | 分阶段任务清单、检查点标准、风险登记册、并行化策略 |
|
|
| 项目概览 | `README.md` | 技术栈, 项目结构, 快速开始 |
|
|
| CEO 计划 | `ceo-plan.md` | 产品愿景, 范围决策, 6 项扩展 |
|
|
| 设计文档 | `design-doc.md` | 问题定义, 约束, 方案选择 |
|
|
| 工程评审 | `eng-review-plan.md` | 架构决策, 测试策略, 失败模式 |
|
|
| 测试计划 | `eng-review-test-plan.md` | 测试路径, 边界情况, E2E 流程 |
|
|
| 待办事项 | `TODOS.md` | 延迟项, 设计变更记录 |
|