digital-employee-platform/docs/plans/2026-05-05-digital-employee-design.md
root 5c13f08c03 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>
2026-05-05 05:54:05 +08:00

22 KiB
Raw Blame History

数字员工平台设计文档

日期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

  1. 管理后台 UI企业管理、员工配置、对话监控
  2. 对话前端 UI聊天界面

2.3 后续迭代P2

  1. 用量统计 / 计费
  2. 权限控制(企业管理员 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 租户管理模块

数据模型:

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 数字员工配置模块

数据模型:

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 流式响应
  → 持久化对话记录

数据模型:

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 隔离命名空间)
  → 元数据存储(文档标题、来源、分块偏移量)

数据模型:

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按租户路由
  • 支持流式和非流式调用
  • 统一错误处理与重试
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 对话               ──新增──→   多渠道接入