From 5c13f08c0394404f40b35391adc26986937a9575 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 5 May 2026 05:54:05 +0800 Subject: [PATCH] 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 --- .../2026-05-05-digital-employee-design.md | 597 ++++++++++++++++++ memory/2026-05-05.md | 44 ++ 2 files changed, 641 insertions(+) create mode 100644 docs/plans/2026-05-05-digital-employee-design.md create mode 100644 memory/2026-05-05.md diff --git a/docs/plans/2026-05-05-digital-employee-design.md b/docs/plans/2026-05-05-digital-employee-design.md new file mode 100644 index 0000000..5e9af2a --- /dev/null +++ b/docs/plans/2026-05-05-digital-employee-design.md @@ -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 方案 B:LangChain 编排架构 + +``` +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 Pipeline:mock 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 对话 ──新增──→ 多渠道接入 +``` diff --git a/memory/2026-05-05.md b/memory/2026-05-05.md new file mode 100644 index 0000000..504bc0e --- /dev/null +++ b/memory/2026-05-05.md @@ -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:对话质量评估、模板市场、多渠道接入、审批工作流、审计日志 + +## 问题与修复 + +(暂无)