docs: add digital employee platform design document

Multi-tenant platform design with unified LLM provider abstraction,
RAG knowledge base, and tenant-isolated data storage. MVP uses SQLite +
ChromaDB, with planned migration to PostgreSQL + pgvector.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
root 2026-05-05 05:54:05 +08:00
parent 147104819b
commit 5c13f08c03
2 changed files with 641 additions and 0 deletions

View File

@ -0,0 +1,597 @@
# 数字员工平台设计文档
> 日期2026-05-05
> 状态:已批准
## 1. 背景与目标
### 1.1 背景
企业对 AI 数字员工的需求日益增长,但不同企业的业务场景、知识体系、合规要求各不相同。现有解决方案要么是通用聊天机器人(缺乏企业定制),要么是单点 SaaS 产品(数据隔离弱、模型选择受限)。需要一个多租户平台,让每家企业能配置专属数字员工,接入自选 LLM使用私有知识库。
### 1.2 目标
- 构建多租户数字员工平台,支持企业级数据隔离与独立计费
- 统一 LLM Provider 抽象层企业可自选模型提供商OpenAI / 通义千问 / 可扩展)
- RAG 知识库支持企业私有文档上传与检索增强生成
- 提供管理后台与对话前端,形成完整可演示链路
### 1.3 成功标准
| 指标 | MVP 目标 |
|------|----------|
| 租户隔离 | 企业间数据零泄露API Key 独立计费 |
| 对话延迟 | 首 token 响应 < 3s不含 LLM 调用开销 |
| RAG 准确性 | 知识库内问题 Top-3 召回率 > 80% |
| 可演示性 | 管理后台 + 对话界面端到端可用 |
| Provider 扩展 | 新增 Provider 实现工作量 < 1 |
## 2. 范围
### 2.1 MVP 范围P0
1. 企业租户管理CRUD + API Key 配置)
2. 数字员工人设配置(角色、语气、专业知识描述)
3. 对话接口实时聊天SSE 流式响应)
4. RAG 知识库(上传文档 → 分块嵌入 → 检索增强生成)
5. 对话历史存储与查询
### 2.2 MVP 基础版P1
6. 管理后台 UI企业管理、员工配置、对话监控
7. 对话前端 UI聊天界面
### 2.3 后续迭代P2
8. 用量统计 / 计费
9. 权限控制(企业管理员 vs 普通用户)
### 2.4 拓展功能P3按价值排序
1. **对话质量评估**:自动评估 RAG 回答的准确性与相关性
2. **数字员工模板市场**:预置客服/HR/销售等角色模板,一键启用
3. **多渠道接入**:微信/钉钉/飞书/Web 统一对话接口
4. **审批工作流**:敏感操作前需人类确认
5. **审计日志与合规**:完整对话审计链路
### 2.5 非目标
- 自训练/微调模型
- 实时语音对话
- 多模态输入(图片/视频)
- 移动端原生 App
## 3. 方案对比
### 3.1 方案 A轻量直连架构
```
FastAPI → Provider 抽象层 → OpenAI/通义千问 API
→ SQLite + ChromaDB嵌入式向量库
→ 文件存储(对话历史)
```
- 零外部依赖,`pip install` 即跑
- 开发周期 1-2 周
- 单机部署,不适合大规模
### 3.2 方案 BLangChain 编排架构
```
FastAPI → LangChain/LangGraph → 多 LLM Provider
→ PostgreSQL + pgvector
→ Redis缓存/会话)
```
- LangChain 500+ 集成LangGraph 支持多步 Agent
- 重依赖,升级频繁有 breaking change
- 生产维护成本高
### 3.3 方案 C自研编排 + PostgreSQL 全栈
```
FastAPI → 自研 Provider 抽象 + RAG Pipeline
→ PostgreSQL + pgvector统一存储
→ Redis会话/缓存)
```
- 完全可控,无重框架依赖
- PostgreSQL 统一关系数据 + 向量检索
- RAG pipeline 需自建,初始工作量较大
### 3.4 决策:方案 A 先行,演进到方案 C
| 阶段 | 存储 | 向量库 | 缓存 | 理由 |
|------|------|--------|------|------|
| MVP | SQLite | ChromaDB | 无 | 零外部依赖,快速验证 |
| V1 | PostgreSQL | pgvector | Redis | 生产级,统一存储 |
## 4. 推荐方案详细设计
### 4.1 系统架构总览
```
┌─────────────────────────────────────────────────────────┐
│ 前端层 (TypeScript) │
│ ┌──────────────┐ ┌──────────────┐ ┌───────────────┐ │
│ │ 管理后台 UI │ │ 对话前端 UI │ │ 模板市场 UI │ │
│ └──────┬───────┘ └──────┬───────┘ └───────┬───────┘ │
└─────────┼─────────────────┼──────────────────┼──────────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────┐
│ API 网关层 (FastAPI) │
│ ┌──────────┐ ┌───────────┐ ┌──────────┐ ┌───────────┐ │
│ │ 租户管理 │ │ 员工配置 │ │ 对话接口 │ │ 知识库管理 │ │
│ └──────────┘ └───────────┘ └──────────┘ └───────────┘ │
└─────────────────────┬───────────────────────────────────┘
┌───────────┴───────────┐
▼ ▼
┌──────────────────┐ ┌─────────────────────┐
│ 对话编排层 │ │ RAG Pipeline │
│ ┌─────────────┐ │ │ ┌─────────────────┐ │
│ │ 会话管理 │ │ │ │ 文档解析/分块 │ │
│ │ Prompt 构建 │ │ │ │ 嵌入生成 │ │
│ │ 流式响应 │ │ │ │ 向量检索 │ │
│ └─────────────┘ │ │ │ 上下文注入 │ │
│ ┌─────────────┐ │ │ └─────────────────┘ │
│ │ Provider │ │ └─────────────────────┘
│ │ 抽象层 │ │
│ │ ┌────────┐ │ │
│ │ │ OpenAI │ │ │
│ │ │ 通义 │ │ │
│ │ │ ... │ │ │
│ │ └────────┘ │ │
│ └─────────────┘ │
└──────────────────┘
┌─────────────────────────────────────────────────────────┐
│ 存储层 │
│ MVP: SQLite + ChromaDB + 文件存储 │
│ V1: PostgreSQL + pgvector + Redis │
└─────────────────────────────────────────────────────────┘
```
### 4.2 核心模块设计
#### 4.2.1 租户管理模块
**数据模型:**
```python
class Tenant:
id: UUID # 租户 ID
name: str # 企业名称
slug: str # URL 标识(唯一)
status: TenantStatus # active / suspended / deleted
created_at: datetime
updated_at: datetime
class TenantConfig:
id: UUID
tenant_id: UUID # 关联租户
llm_provider: str # openai / qwen / anthropic
llm_api_key: str # 加密存储的 API Key
llm_model: str # gpt-4o / qwen-max / ...
llm_base_url: str | None # 自定义 API 端点(可选)
max_tokens_per_month: int # 用量限制
created_at: datetime
updated_at: datetime
```
**API 端点:**
| 方法 | 路径 | 说明 |
|------|------|------|
| POST | `/api/v1/tenants` | 创建租户 |
| GET | `/api/v1/tenants/{id}` | 获取租户详情 |
| PUT | `/api/v1/tenants/{id}` | 更新租户 |
| DELETE | `/api/v1/tenants/{id}` | 删除租户(软删除) |
| PUT | `/api/v1/tenants/{id}/config` | 更新 LLM 配置 |
**安全约束:**
- API Key 使用 AES-256 加密存储,密钥从环境变量读取
- 租户间数据严格隔离,所有查询强制带 `tenant_id` 过滤
- 软删除策略,删除后 30 天可恢复
#### 4.2.2 数字员工配置模块
**数据模型:**
```python
class DigitalEmployee:
id: UUID
tenant_id: UUID # 所属租户
name: str # 员工名称(如"客服小助手"
role: str # 角色customer_service / hr / sales / ...
avatar_url: str | None # 头像
system_prompt: str # 人设系统提示词
greeting: str | None # 开场白
temperature: float # 生成温度 0.0-1.0
max_context_messages: int # 上下文窗口消息数
knowledge_base_ids: list[UUID] # 关联知识库
status: EmployeeStatus # active / inactive
created_at: datetime
updated_at: datetime
```
**API 端点:**
| 方法 | 路径 | 说明 |
|------|------|------|
| POST | `/api/v1/tenants/{tid}/employees` | 创建数字员工 |
| GET | `/api/v1/tenants/{tid}/employees` | 列出数字员工 |
| GET | `/api/v1/tenants/{tid}/employees/{eid}` | 获取详情 |
| PUT | `/api/v1/tenants/{tid}/employees/{eid}` | 更新配置 |
| DELETE | `/api/v1/tenants/{tid}/employees/{eid}` | 删除 |
#### 4.2.3 对话接口模块
**对话流程:**
```
用户消息
→ 会话加载(历史上下文)
→ RAG 检索(如果员工关联了知识库)
→ 查询向量化
→ ChromaDB/pgvector 相似度检索 Top-K
→ 上下文注入到 Prompt
→ Prompt 构建system + 知识上下文 + 历史消息 + 用户消息)
→ LLM Provider 调用(流式)
→ SSE 流式响应
→ 持久化对话记录
```
**数据模型:**
```python
class Conversation:
id: UUID
tenant_id: UUID
employee_id: UUID
user_id: str # 外部用户标识
title: str | None
created_at: datetime
updated_at: datetime
class Message:
id: UUID
conversation_id: UUID
role: MessageRole # user / assistant / system
content: str
token_count: int | None
sources: list[dict] | None # RAG 引用来源
created_at: datetime
```
**API 端点:**
| 方法 | 路径 | 说明 |
|------|------|------|
| POST | `/api/v1/tenants/{tid}/employees/{eid}/conversations` | 创建对话 |
| GET | `/api/v1/tenants/{tid}/conversations` | 列出对话 |
| GET | `/api/v1/tenants/{tid}/conversations/{cid}` | 获取对话详情(含消息) |
| POST | `/api/v1/tenants/{tid}/conversations/{cid}/messages` | 发送消息SSE 流式响应) |
| DELETE | `/api/v1/tenants/{tid}/conversations/{cid}` | 删除对话 |
**SSE 响应格式:**
```
event: message_start
data: {"conversation_id": "...", "message_id": "..."}
event: token
data: {"content": "你"}
event: token
data: {"content": "好"}
event: sources
data: {"documents": [{"title": "...", "snippet": "...", "score": 0.92}]}
event: message_end
data: {"token_count": 156}
event: error
data: {"code": "provider_error", "message": "..."}
```
#### 4.2.4 RAG 知识库模块
**处理流程:**
```
文档上传
→ 文件类型检测PDF / DOCX / TXT / MD
→ 文档解析(提取纯文本)
→ 文本分块RecursiveCharacterTextSplitter
→ chunk_size: 500, overlap: 50
→ 嵌入生成(调用 Embedding API
→ 向量存储ChromaDB按 tenant_id 隔离命名空间)
→ 元数据存储(文档标题、来源、分块偏移量)
```
**数据模型:**
```python
class KnowledgeBase:
id: UUID
tenant_id: UUID
name: str
description: str | None
embedding_model: str # text-embedding-3-small / ...
chunk_count: int
created_at: datetime
updated_at: datetime
class Document:
id: UUID
knowledge_base_id: UUID
tenant_id: UUID
filename: str
file_type: str # pdf / docx / txt / md
file_size: int
chunk_count: int
status: DocumentStatus # processing / ready / failed
error_message: str | None
created_at: datetime
```
**API 端点:**
| 方法 | 路径 | 说明 |
|------|------|------|
| POST | `/api/v1/tenants/{tid}/knowledge-bases` | 创建知识库 |
| POST | `/api/v1/tenants/{tid}/knowledge-bases/{kid}/documents` | 上传文档 |
| GET | `/api/v1/tenants/{tid}/knowledge-bases/{kid}/documents` | 列出文档 |
| DELETE | `/api/v1/tenants/{tid}/knowledge-bases/{kid}/documents/{did}` | 删除文档 |
| GET | `/api/v1/tenants/{tid}/knowledge-bases` | 列出知识库 |
| DELETE | `/api/v1/tenants/{tid}/knowledge-bases/{kid}` | 删除知识库 |
#### 4.2.5 LLM Provider 抽象层
**设计原则:**
- 统一接口Provider 可插拔
- 每个企业独立 API Key按租户路由
- 支持流式和非流式调用
- 统一错误处理与重试
```python
from abc import ABC, abstractmethod
from dataclasses import dataclass
@dataclass
class LLMMessage:
role: str # system / user / assistant
content: str
@dataclass
class LLMResponse:
content: str
token_usage: dict
model: str
finish_reason: str
class BaseLLMProvider(ABC):
"""LLM Provider 抽象基类"""
@abstractmethod
async def chat(
self,
messages: list[LLMMessage],
model: str,
temperature: float = 0.7,
max_tokens: int = 2048,
**kwargs,
) -> LLMResponse:
...
@abstractmethod
async def chat_stream(
self,
messages: list[LLMMessage],
model: str,
temperature: float = 0.7,
max_tokens: int = 2048,
**kwargs,
) -> AsyncIterator[str]:
...
@abstractmethod
async def embed(self, texts: list[str], model: str) -> list[list[float]]:
...
class OpenAIProvider(BaseLLMProvider):
"""OpenAI / 兼容 OpenAI 接口的 Provider"""
class QwenProvider(BaseLLMProvider):
"""通义千问 Provider兼容 OpenAI 接口格式)"""
# Provider 注册表
PROVIDERS: dict[str, type[BaseLLMProvider]] = {
"openai": OpenAIProvider,
"qwen": QwenProvider,
}
def get_provider(provider_name: str, api_key: str, base_url: str | None = None) -> BaseLLMProvider:
provider_cls = PROVIDERS.get(provider_name)
if not provider_cls:
raise ValueError(f"Unknown provider: {provider_name}")
return provider_cls(api_key=api_key, base_url=base_url)
```
**Provider 配置约定:**
| Provider | chat model | embedding model | 特殊说明 |
|----------|-----------|----------------|---------|
| openai | gpt-4o / gpt-4o-mini | text-embedding-3-small | 标准 OpenAI API |
| qwen | qwen-max / qwen-plus | text-embedding-v3 | 兼容 OpenAI SDK 格式 |
### 4.3 安全设计
#### 4.3.1 数据隔离
- 所有数据表包含 `tenant_id` 字段
- 所有查询强制 `WHERE tenant_id = :current_tenant`
- API 中间件自动注入 `tenant_id`,业务代码无法绕过
- ChromaDB 使用 tenant_id 作为 collection namespace 隔离向量数据
#### 4.3.2 API Key 安全
- LLM API Key 使用 AES-256-GCM 加密存储
- 加密密钥从环境变量 `ENCRYPTION_KEY` 读取,不入库不入日志
- 运行时解密仅用于发起 LLM 调用,不返回给前端
#### 4.3.3 输入校验
- 所有 API 入参使用 Pydantic 校验
- 文档上传限制:单文件 < 20MB仅允许 pdf/docx/txt/md
- 对话消息长度限制:单条 < 10000 字符
- 速率限制:每租户每分钟 60 次请求
### 4.4 技术栈
| 层 | MVP 技术选型 | V1 演进 |
|----|------------|---------|
| 后端框架 | FastAPI 0.115+ | FastAPI |
| 数据库 | SQLite (aiosqlite) | PostgreSQL 16 |
| 向量库 | ChromaDB 0.5+ | pgvector |
| 缓存 | 无 | Redis |
| ORM | SQLAlchemy 2.0+ (async) | SQLAlchemy 2.0+ |
| 嵌入/LLM | openai SDK | openai SDK |
| 文档解析 | PyPDF2 + python-docx | 同左 |
| 前端框架 | React + TypeScript + Vite | 同左 |
| 前端 UI | Ant Design | Ant Design |
| 对话前端 | 自研 Chat UI 组件 | 同左 |
### 4.5 项目结构
```
digital-employee-platform/
├── backend/
│ ├── app/
│ │ ├── __init__.py
│ │ ├── main.py # FastAPI 入口
│ │ ├── config.py # 配置管理
│ │ ├── database.py # 数据库连接
│ │ ├── models/ # SQLAlchemy 模型
│ │ │ ├── __init__.py
│ │ │ ├── tenant.py
│ │ │ ├── employee.py
│ │ │ ├── conversation.py
│ │ │ └── knowledge.py
│ │ ├── schemas/ # Pydantic 请求/响应模型
│ │ │ ├── __init__.py
│ │ │ ├── tenant.py
│ │ │ ├── employee.py
│ │ │ ├── conversation.py
│ │ │ └── knowledge.py
│ │ ├── api/ # API 路由
│ │ │ ├── __init__.py
│ │ │ ├── v1/
│ │ │ │ ├── __init__.py
│ │ │ │ ├── tenants.py
│ │ │ │ ├── employees.py
│ │ │ │ ├── conversations.py
│ │ │ │ └── knowledge.py
│ │ │ └── deps.py # 依赖注入
│ │ ├── services/ # 业务逻辑
│ │ │ ├── __init__.py
│ │ │ ├── tenant_service.py
│ │ │ ├── employee_service.py
│ │ │ ├── conversation_service.py
│ │ │ ├── knowledge_service.py
│ │ │ └── rag_service.py
│ │ ├── providers/ # LLM Provider 抽象层
│ │ │ ├── __init__.py
│ │ │ ├── base.py
│ │ │ ├── openai_provider.py
│ │ │ └── qwen_provider.py
│ │ └── middleware/ # 中间件
│ │ ├── __init__.py
│ │ └── tenant.py # 租户隔离中间件
│ ├── tests/ # 测试
│ │ ├── __init__.py
│ │ ├── conftest.py
│ │ ├── test_tenants.py
│ │ ├── test_employees.py
│ │ ├── test_conversations.py
│ │ ├── test_knowledge.py
│ │ └── test_providers.py
│ ├── alembic/ # 数据库迁移
│ │ └── ...
│ ├── pyproject.toml
│ └── .env.example
├── frontend/
│ ├── src/
│ │ ├── api/ # API 客户端
│ │ ├── components/ # 通用组件
│ │ ├── pages/
│ │ │ ├── admin/ # 管理后台页面
│ │ │ │ ├── Tenants.tsx
│ │ │ │ ├── Employees.tsx
│ │ │ │ └── Knowledge.tsx
│ │ │ └── chat/ # 对话前端页面
│ │ │ └── Chat.tsx
│ │ ├── App.tsx
│ │ └── main.tsx
│ ├── package.json
│ ├── tsconfig.json
│ └── vite.config.ts
└── docs/
└── plans/
```
## 5. 错误处理
| 错误类型 | 处理策略 | HTTP 状态码 |
|---------|---------|------------|
| LLM Provider 调用失败 | 指数退避重试 2 次,记录日志,返回降级提示 | 502 |
| LLM API Key 无效/过期 | 返回配置错误提示,不重试 | 401 |
| 租户 API 限流 | 返回 429附带 Retry-After 头 | 429 |
| 文档解析失败 | 标记文档状态为 failed记录错误信息 | 200异步 |
| RAG 无相关结果 | 正常返回不注入知识上下文LLM 按通用知识回答 | - |
| 向量库写入失败 | 重试 1 次,失败则文档标记 failed | 200异步 |
| 数据库连接失败 | 返回 503记录告警 | 503 |
## 6. 测试策略
### 6.1 单元测试
- Provider 抽象层mock LLM API 响应,验证接口一致性
- 服务层mock 数据库,验证业务逻辑
- RAG Pipelinemock embedding验证分块、检索逻辑
### 6.2 集成测试
- 端到端对话流:使用真实 LLM API测试 Key验证完整链路
- 租户隔离:创建两个租户,验证数据不互渗
- RAG 问答:上传文档后提问,验证回答包含文档内容
### 6.3 安全测试
- 越权访问:租户 A 尝试访问租户 B 资源,必须 403
- API Key 不出现在日志和 API 响应中
- 文档上传类型和大小限制
### 6.4 性能测试
- 对话接口p99 < 3s不含 LLM 调用
- 文档上传10MB PDF 解析 < 30s
- 并发:单租户 10 并发对话无异常
## 7. 演进路径
```
MVP (方案 A) V1 (方案 C)
───────────── ──────────────
SQLite + ChromaDB ──迁移──→ PostgreSQL + pgvector
文件存储对话历史 ──迁移──→ PostgreSQL JSONB
无缓存 ──新增──→ Redis 会话缓存
单实例部署 ──演进──→ Docker Compose 多服务
基础对话 ──新增──→ 对话质量评估
无模板 ──新增──→ 数字员工模板市场
Web 对话 ──新增──→ 多渠道接入
```

44
memory/2026-05-05.md Normal file
View File

@ -0,0 +1,44 @@
# 2026-05-05
## 纪要
- 数字员工平台项目启动,完成设计文档
## 决策
### 综合型数字员工平台 - 架构决策
- **结论**:采用方案 A轻量直连先行 MVP演进到方案 C自研编排 + PostgreSQL 全栈)
- **理由**
- MVP 用 SQLite + ChromaDB 零外部依赖1-2 周可交付
- 避免 LangChain 重依赖和频繁 breaking change
- 自研 Provider 抽象层保持轻量可控
- 生产级方案用 PostgreSQL + pgvector 统一存储
- **影响**
- 项目结构按模块化设计,存储层可替换
- Provider 抽象层接口需稳定,后续新增 Provider 不改业务代码
### 技术选型
- **后端**Python FastAPI + SQLAlchemy 2.0 async
- **前端**React + TypeScript + Vite + Ant Design
- **存储 MVP**SQLite + ChromaDB
- **存储 V1**PostgreSQL + pgvector + Redis
- **LLM MVP**OpenAI + 通义千问(兼容 OpenAI SDK 格式)
### 多租户隔离策略
- 共享服务实例 + API Key 隔离 + 独立知识库ChromaDB namespace 隔离)
- 所有数据表强制 tenant_id 过滤
- LLM API Key AES-256 加密存储
### MVP 范围
- P0租户管理、员工配置、对话接口、RAG 知识库、对话历史
- P1管理后台 UI、对话前端 UI
- P2用量统计/计费、权限控制
- P3对话质量评估、模板市场、多渠道接入、审批工作流、审计日志
## 问题与修复
(暂无)