fischer-agentkit/docs/plans/2026-06-19-002-enterprise-c...

1027 lines
39 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 企业级 AI 客户端平台 — 架构方案文档
> 文档编号2026-06-19-002
> 创建日期2026-06-19
> 状态:方案评审中(含独立批判性分析)
---
## 目录
1. [背景与动机](#1-背景与动机)
2. [产品定位](#2-产品定位)
3. [架构总览](#3-架构总览)
4. [客户端设计](#4-客户端设计)
5. [服务端设计](#5-服务端设计)
6. [权限模型](#6-权限模型)
7. [终端安全](#7-终端安全)
8. [LLM 调用链路](#8-llm-调用链路)
9. [数据同步](#9-数据同步)
10. [认证体系](#10-认证体系)
11. [数据库设计](#11-数据库设计)
12. [安全模型](#12-安全模型)
13. [实施路线图](#13-实施路线图)
14. [独立批判性分析](#14-独立批判性分析)
15. [方案优化与补全](#15-方案优化与补全)
16. [待决策问题](#16-待决策问题)
---
## 1. 背景与动机
### 1.1 当前架构
Fischer AgentKit 当前是纯本地运行架构:
- **CLI/Tauri 桌面端**:启动本地 Python sidecar`127.0.0.1:{随机端口}`),前端通过 Tauri IPC 获取端口后连接本地 sidecar
- **LLM 配置**API Key 存储在本地 `agentkit.yaml` + `.env`
- **认证**:仅全局 API Key + `clients.yaml` 多客户端 key无用户系统
- **数据**:会话存储在本地 SQLite情景记忆在 PostgreSQL可选
- **终端**PTY 在本地 sidecar 中执行
### 1.2 改造动机
- **企业统一管理 LLM Key 和成本**:当前 Key 散落在各客户端,无法统一管控
- **团队知识共享**:企业代码规范、最佳实践需要集中管理、团队共享
- **权限与审计**:企业需要控制谁能使用终端等高危功能,需要审计操作记录
- **多用户支持**:当前无用户概念,无法区分不同用户的会话和操作
### 1.3 对标产品
| 产品 | 客户端 | 服务端 | 差异 |
|------|--------|--------|------|
| Trae | 桌面 IDE + AI Agent | 云端模型 | 个人工具 |
| Cursor | VS Code Fork + AI | 云端模型 + Team | 团队工具 |
| Codex CLI | 终端 CLI | 云端模型 | 命令行助手 |
| **AgentKit 目标** | **桌面客户端 + AI Agent** | **企业平台(权限/KB/审计)** | **企业级 AI 开发平台** |
**核心差异化**:代码不离开客户端 + Agent 本地执行 + 企业级治理
---
## 2. 产品定位
### 2.1 定位声明
> 企业级 AI 开发客户端平台:客户端是开发者的 AI 工作台(类似 Trae服务端是企业共享资源与治理中心。
### 2.2 双买家模型
| 维度 | 开发者视角 | 企业 IT 视角 |
|------|----------|------------|
| 核心价值 | AI 辅助编程、本地执行 | 统一 Key 管理、成本管控、审计合规 |
| 部署模式 | 本地优先 | 集中部署 |
| 成功指标 | 任务完成率、响应延迟 | 合规率、成本可控 |
### 2.3 差异化竞争力
1. **代码不离开客户端**真差异化Cursor/Trae 的 codebase indexing 在云端AgentKit 的代码上下文完全本地
2. **专家团/董事会模式**(已有优势):当前代码库已有的多 Agent 协作模式Cursor/Trae 完全没有
3. **企业级治理**(目标差异化):统一 LLM Key、成本管控、权限审计
---
## 3. 架构总览
### 3.1 双进程模型
```
┌─────────────────────────────────────────────────────────────┐
│ 企业服务端(云端/内网) │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ LLM 网关 │ │ 用户权限 │ │ 审计日志 │ │ 知识库 │ │
│ │ (统一Key) │ │ 中心 │ │ 中心 │ │ 中心 │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ PostgreSQL + pgvector │ Redis │ MinIO(可选) │
└───────────────────────┬─────────────────────────────────────┘
│ HTTPS API + WSS
│ (认证: JWT + API Key)
┌─────────────┼─────────────┐
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────┐ ┌──────────────┐
│ Tauri 桌面 │ │ Tauri │ │ Web 管理台 │
│ 客户端 │ │ 客户端 │ │ (浏览器) │
│ │ │ │ │ │
│ ┌──────────┐ │ └──────────┘ │ 用户管理 │
│ │本地Sidecar│ │ │ 审计查看 │
│ │(Python) │ │ │ 配置管理 │
│ │├Agent引擎│ │ └──────────────┘
│ │├终端 │ │
│ │├文件操作 │ │
│ │├会话存储 │ │
│ │└LLM代理 │ │
│ └──────────┘ │
│ ┌──────────┐ │
│ │前端(Vue3)│ │
│ └──────────┘ │
└──────────────┘
```
### 3.2 核心设计原则
| 原则 | 说明 | 价值定位 |
|------|------|---------|
| LLM Key 不下发客户端 | 客户端通过服务端 LLM 网关间接调用 | **成本管控 + 审计**(非安全边界) |
| 代码不离开客户端 | Agent 在客户端本地执行,文件操作在本地 | **安全 + 隐私**(真差异化) |
| 终端在客户端本地执行 | 服务端不提供终端功能 | **安全**(服务端无 RCE 风险) |
| 离线降级 | 服务端不可用时客户端部分可用 | **可用性** |
### 3.3 关键架构决策
| 决策点 | 选择 | 理由 |
|--------|------|------|
| 终端位置 | 本地 Python sidecar非 Tauri Rust | 避免用 Rust 重写 PTY + 命令分类逻辑 |
| LLM 调用模式 | 服务端代理(非客户端直连) | 统一 Key 管理 + 用量审计 + 成本管控 |
| 配置同步 | 轮询 + ETag非 WebSocket 推送) | 配置变更频率低(周/月级),轮询足够 |
| 会话历史 | 本地 SQLite不上传服务端 | 隐私保护 + 减少网络传输 |
| 服务端部署 | 支持内网私有化部署 | 跨地域公网延迟不可接受 |
---
## 4. 客户端设计
### 4.1 客户端分层
```
Tauri 桌面客户端
├── UI 层Vue 3 + Ant Design Vue
│ ├── 对话界面Chat
│ ├── 工作台界面Workspace
│ ├── 终端界面Terminal
│ ├── 知识库浏览KB Browser
│ ├── 工作流管理Workflow
│ └── 设置中心Settings
├── 本地服务层Python Sidecar - FastAPI
│ ├── /local/agent — 本地 Agent 执行引擎
│ ├── /local/terminal — 本地终端PTY
│ ├── /local/files — 本地文件操作
│ ├── /local/session — 本地会话存储SQLite
│ ├── /local/cache — 本地 LLM 语义缓存
│ └── /local/llm-proxy — LLM 代理(转发到服务端网关)
├── 远程通信层
│ ├── /api/auth/* — 认证(登录/JWT
│ ├── /api/llm/chat — LLM 代理(通过服务端网关)
│ ├── /api/kb/* — 知识库查询
│ ├── /api/config/* — 配置同步
│ └── /api/audit/* — 审计日志上报
└── 本地存储
├── SQLite会话、缓存、配置快照
├── 文件系统(代码、项目)
└── 内存Agent 运行时状态)
```
### 4.2 客户端保留的模块
| 当前模块 | 客户端角色 | 改造 |
|---------|----------|------|
| `core/` Agent 引擎 | 本地执行 | LLM 改为 RemoteLLMProvider |
| `tools/` 工具 | 本地执行 | 不变 |
| `chat/` 会话 | 本地 SQLite | 增加 owner_id |
| `routes/terminal.py` | 本地终端 | 增加权限检查 + 审计上报 |
| `llm/gateway.py` | 改为代理模式 | 新增 RemoteLLMProvider |
| `skills/` | 本地 + 远程同步 | 增加从服务端同步 |
| `experts/` | 本地 + 远程配置 | 增加从服务端同步 |
### 4.3 客户端启动流程
```
1. Tauri 启动 → 启动本地 Python Sidecar127.0.0.1:{随机端口}
2. 前端加载 → 检查本地是否有登录凭证JWT
├─ 有且有效 → 直接进入主界面
├─ 有但过期 → 尝试 refresh → 成功则进入,失败则跳转登录
└─ 无 → 跳转登录页
3. 登录成功后:
a. 从服务端拉取用户信息 + 权限
b. 从服务端同步配置(技能/Agent/工作流,带 ETag 增量)
c. 初始化本地 Agent 引擎(使用 RemoteLLMProvider
4. 进入主界面,用户开始工作
```
### 4.4 离线降级策略
| 功能 | 服务端可用 | 服务端不可用 |
|------|----------|------------|
| 对话 | 通过服务端 LLM 网关 | 用户自填 Key 直连 LLM降级模式 |
| 终端 | 本地执行 + 审计上报 | 本地执行 + 审计暂存本地 |
| 文件操作 | 本地执行 | 本地执行 |
| 知识库 | 实时查询服务端 | 使用本地缓存的 KB 元数据 + 已缓存文档 |
| 工作流模板 | 实时拉取 | 使用本地缓存版本 |
| 配置同步 | 轮询更新 | 使用本地缓存 |
---
## 5. 服务端设计
### 5.1 服务端模块(按必要性排序)
| 优先级 | 模块 | 职责 | V1 是否必须 |
|--------|------|------|------------|
| P0 | LLM 网关 | 统一 Key、用量统计、成本管控、语义缓存、限流 | ✅ 必须 |
| P0 | 用户认证 | JWT 签发/验证、用户 CRUD | ✅ 必须 |
| P1 | 审计日志 | LLM 调用审计 + 危险命令审计 | ✅ 应该 |
| P1 | 知识库 | pgvector 语义搜索、团队隔离 | ✅ 应该 |
| P2 | 配置同步 API | 技能/Agent/工作流配置分发 | 可延后 |
| P3 | Web 管理台 | 用户管理、审计查看、配置管理 | 可延后 |
| P3 | 技能市场 | 技能发布与分发 | 可延后 |
| P3 | 工作流模板中心 | 工作流 CRUD、版本控制 | 可延后 |
| P4 | 生产系统集成 | CI/CD Webhook | 暴露 Webhook 即可 |
### 5.2 服务端 API
```
认证 API
POST /api/v1/auth/login — 登录
POST /api/v1/auth/refresh — 刷新 token
POST /api/v1/auth/logout — 登出
GET /api/v1/auth/me — 当前用户信息
LLM 网关 API
POST /api/v1/llm/chat — LLM 对话(非流式)
POST /api/v1/llm/chat/stream — LLM 流式对话SSE
知识库 API
GET /api/v1/kb/search — 知识库搜索
GET /api/v1/kb/documents/{id} — 获取文档
配置同步 API
GET /api/v1/config/version — 配置版本号
GET /api/v1/config/skills — 技能配置
GET /api/v1/config/agents — Agent 配置
GET /api/v1/config/workflows — 工作流模板
审计 API
POST /api/v1/audit/terminal — 终端审计上报
GET /api/v1/usage/me — 我的用量
管理 API需 admin 权限):
GET /api/v1/admin/users — 用户管理
POST /api/v1/admin/users — 创建用户
GET /api/v1/admin/audit/terminal — 终端审计日志
GET /api/v1/admin/usage — 全局用量统计
```
---
## 6. 权限模型
### 6.1 三级角色 + 权限位
```
角色:
member — 普通用户(对话 + 只读 KB + 工作流执行)
operator — 高级用户(+ 终端 + KB 写入)
admin — 管理员(+ 用户管理 + 系统配置)
```
### 6.2 权限位定义
```python
class Permission(str, Enum):
CHAT = "chat" # 对话
KB_QUERY = "kb.query" # 知识库查询
KB_WRITE = "kb.write" # 知识库写入
WORKFLOW_EXECUTE = "workflow.execute" # 工作流执行
TERMINAL_LOCAL_USE = "terminal.local.use" # 本地终端使用
TERMINAL_SERVER_USE = "terminal.server.use" # 服务端终端使用
TERMINAL_WHITELIST_MANAGE = "terminal.whitelist.manage" # 白名单管理
USER_MANAGE = "user.manage" # 用户管理
SYSTEM_CONFIG = "system.config" # 系统配置
ROLE_PERMISSIONS: dict[str, set[Permission]] = {
"member": {Permission.CHAT, Permission.KB_QUERY, Permission.WORKFLOW_EXECUTE},
"operator": {
Permission.CHAT, Permission.KB_QUERY, Permission.KB_WRITE,
Permission.WORKFLOW_EXECUTE, Permission.TERMINAL_LOCAL_USE,
},
"admin": set(Permission), # 含 TERMINAL_SERVER_USE + TERMINAL_WHITELIST_MANAGE
}
```
### 6.3 终端授权
终端分为**本地终端**和**服务端终端**两种模式,授权要求不同:
| 终端模式 | 执行位置 | 所需权限 | 额外要求 | 审计策略 |
|---------|---------|---------|---------|---------|
| 本地终端 | 客户端本地 sidecar | `TERMINAL_LOCAL_USE` | `is_terminal_authorized=True` | 仅危险命令上报 |
| 服务端终端 | 服务端 PTY | `TERMINAL_SERVER_USE` | `is_server_terminal_authorized=True` | **全量命令记录** |
**授权流程**
1. `operator` 角色默认有本地终端权限admin 可单独授予 `is_terminal_authorized`
2. 服务端终端权限仅 `admin` 角色默认拥有,或 admin 单独授予 `is_server_terminal_authorized`
3. 两种终端权限独立控制,互不影响
---
## 7. 终端安全
### 7.1 三层防护
```
第一层:角色门禁
→ 用户必须有 TERMINAL_USE 权限 + is_terminal_authorized=True
→ member 角色看不到终端入口
第二层:命令分类
→ 安全命令ls, cat, pwd...):有权限即可执行
→ 危险命令rm, sudo, chmod...):每次必须人工确认
→ 未知命令:默认视为危险
第三层:人工确认(每次)
→ 危险命令每次执行都弹出确认对话框
→ 不提供"加入白名单"选项(危险命令不持久化白名单)
→ 必须勾选"我已了解风险"才能确认
```
### 7.2 终端审计
| 审计内容 | 上报策略 |
|---------|---------|
| 危险命令 + 确认结果 | 实时上报服务端 |
| 普通命令流水 | **不上报**(隐私保护,全量监控是 MDM/EDR 的职责) |
| 命令输出内容 | **不上报**(可能含敏感信息) |
| 审计元数据 | 命令文本、风险等级、是否确认、exit_code、时间戳 |
### 7.3 BYOD 模式
- 支持纯本地模式(不接入企业服务端),此时无审计上报
- 企业配发设备接入服务端时,审计上报自动启用
---
## 8. LLM 调用链路
### 8.1 调用流程
```
客户端 Agent → 本地 LLM Proxy → 服务端 LLM 网关 → LLM Provider API
JWT 认证
用量统计
成本管控
语义缓存(共享)
限流/熔断
```
### 8.2 RemoteLLMProvider
```python
class RemoteLLMProvider(LLMProvider):
"""通过服务端 LLM 网关调用 LLM不在本地存储 API Key"""
def __init__(self, server_url: str, auth_token_provider: Callable[[], str]):
self._server_url = server_url
self._auth_token_provider = auth_token_provider
async def chat(self, request: LLMRequest) -> LLMResponse:
response = await httpx.post(
f"{self._server_url}/api/v1/llm/chat",
json=request.model_dump(),
headers={"Authorization": f"Bearer {self._auth_token_provider()}"},
)
return LLMResponse(**response.json())
async def chat_stream(self, request: LLMRequest):
async with httpx.AsyncClient() as client:
async with client.stream(
"POST",
f"{self._server_url}/api/v1/llm/chat/stream",
json=request.model_dump(),
headers={"Authorization": f"Bearer {self._auth_token_provider()}"},
) as response:
async for line in response.aiter_lines():
if line.startswith("data: "):
yield StreamChunk(**json.loads(line[6:]))
```
### 8.3 流式 fallback 语义
**已知风险**:当前 `gateway.py` 的"首 chunk 前失败则 fallback"在单进程内简单,跨网络后客户端可能已收到部分 chunkfallback 会导致内容跳变。
**处理方案**
- 服务端网关在首 chunk 前完成 fallback当前逻辑不变
- 首 chunk 后不再 fallback直接返回错误
- 客户端收到错误后自行决定是否重试
### 8.4 延迟分析
| 部署拓扑 | RTT | 50 次 LLM 调用额外延迟 | 可接受性 |
|---------|-----|---------------------|---------|
| 同内网 | 5ms | +0.5s | ✅ 完全可接受 |
| 跨城内网 | 30ms | +3s | ✅ 可接受 |
| 跨地域公网 | 150ms | +15s | ⚠️ 开始难受 |
| 跨国公网 | 300ms | +30s | ❌ 不可接受 |
**结论**:服务端必须支持**内网私有化部署**。跨地域公网部署需要客户端支持直连降级。
### 8.5 内网 LLM 支持
服务端 LLM 网关支持接入内网 LLM 服务:
- vLLMOpenAI 兼容 API
- OllamaOpenAI 兼容 API
- 当前 `ProviderConfig` 已是 OpenAI 兼容格式,只需配置 `base_url` 指向内网地址
---
## 9. 数据同步
### 9.1 同步策略(简化版)
| 数据类型 | 方向 | 策略 |
|---------|------|------|
| 用户信息/权限 | 服务端 → 客户端 | 登录时拉取 + JWT 续期时刷新 |
| 技能/Agent/工作流配置 | 服务端 → 客户端 | 启动时全量拉取 + 每 5 分钟轮询版本号 |
| 知识库 | 服务端 → 客户端 | 实时查询 + 元数据本地缓存 + LRU 文档缓存 |
| 会话历史 | 纯本地 | 不上传服务端 |
| 终端审计 | 客户端 → 服务端 | 危险命令实时上报 + 离线暂存 |
| LLM 用量 | 服务端记录 | 通过 LLM 网关自动记录 |
### 9.2 配置同步实现(轮询版)
```python
# 客户端配置同步引擎
class ConfigSync:
async def sync(self):
# 1. 检查版本号
remote_version = await api.get("/api/v1/config/version")
if remote_version == local_version:
return # 无变更
# 2. 全量拉取(配置数据量小,无需增量)
skills = await api.get("/api/v1/config/skills")
agents = await api.get("/api/v1/config/agents")
workflows = await api.get("/api/v1/config/workflows")
# 3. 更新本地缓存
await update_local_cache(skills, agents, workflows)
local_version = remote_version
async def start_polling(self):
while True:
await asyncio.sleep(300) # 5 分钟
try:
await self.sync()
except Exception:
pass # 离线时静默失败
```
### 9.3 知识库缓存策略
| 层级 | 缓存内容 | 大小 | 策略 |
|------|---------|------|------|
| L1 | KB 文档列表 + 标题 + 摘要 | ~100KB | 启动时全量拉取 |
| L2 | 最近使用的 N 篇文档全文 | ~10MB | LRU 缓存,按需拉取 |
| L3 | 实时查询 | - | L1/L2 miss 时请求服务端 |
---
## 10. 认证体系
### 10.1 双轨认证
```
请求进入
├─ 有 Authorization: Bearer <jwt> ?
│ └─ 是 → 验证 JWT → 提取 user_id → request.state.current_user = User
├─ 有 X-API-Key: <key> ?
│ └─ 是 → 查 user_api_keys 表 → 识别 user_id → request.state.current_user = User
│ (兼容旧 clients.yaml → 识别为 system client
└─ 无凭证
├─ dev mode → 放行
└─ 生产 → 401
```
### 10.2 JWT 流程
```
登录POST /api/v1/auth/login {username, password}
→ 验证密码 (bcrypt)
→ 生成 access_token (15min) + refresh_token (7d)
→ 返回 {access_token, refresh_token, user}
刷新POST /api/v1/auth/refresh {refresh_token}
→ 生成新 access_token
登出POST /api/v1/auth/logout
→ 撤销 refresh_token
```
### 10.3 SSO/OIDCV2 规划)
V1 支持本地账号认证。V2 预留 OIDC 接口,支持:
- Azure AD / Microsoft Entra ID
- Google Workspace
- 企业自建 OIDC Provider
---
## 11. 数据库设计
### 11.1 服务端 PostgreSQL
```sql
-- 用户表
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
username VARCHAR(64) UNIQUE NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
role VARCHAR(32) NOT NULL DEFAULT 'member',
is_active BOOLEAN NOT NULL DEFAULT TRUE,
is_terminal_authorized BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
last_login_at TIMESTAMPTZ,
created_by UUID REFERENCES users(id),
tenant_id UUID, -- 多租户预留
metadata JSONB DEFAULT '{}'
);
-- 用户 API Key 表
CREATE TABLE user_api_keys (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
key_hash VARCHAR(255) UNIQUE NOT NULL,
key_prefix VARCHAR(16) NOT NULL,
name VARCHAR(64),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
last_used_at TIMESTAMPTZ,
expires_at TIMESTAMPTZ,
is_revoked BOOLEAN NOT NULL DEFAULT FALSE
);
-- 终端审计日志
CREATE TABLE terminal_audit_logs (
id BIGSERIAL PRIMARY KEY,
user_id UUID NOT NULL REFERENCES users(id),
session_id VARCHAR(64) NOT NULL,
command TEXT NOT NULL,
command_hash VARCHAR(64) NOT NULL,
risk_level VARCHAR(16) NOT NULL,
was_confirmed BOOLEAN NOT NULL DEFAULT FALSE,
was_approved BOOLEAN NOT NULL DEFAULT FALSE,
executed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
exit_code INTEGER,
client_ip INET,
metadata JSONB DEFAULT '{}'
);
-- LLM 用量记录
CREATE TABLE llm_usage_records (
id BIGSERIAL PRIMARY KEY,
user_id UUID NOT NULL REFERENCES users(id),
provider VARCHAR(64) NOT NULL,
model VARCHAR(128) NOT NULL,
input_tokens INTEGER NOT NULL,
output_tokens INTEGER NOT NULL,
cost_cents INTEGER NOT NULL DEFAULT 0,
latency_ms INTEGER,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
metadata JSONB DEFAULT '{}'
);
-- 用户会话JWT refresh token
CREATE TABLE user_sessions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
refresh_token_hash VARCHAR(255) UNIQUE NOT NULL,
device_info JSONB DEFAULT '{}',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
expires_at TIMESTAMPTZ NOT NULL,
revoked_at TIMESTAMPTZ
);
```
### 11.2 客户端 SQLite现有 + 改造)
```sql
-- conversations 表增加 owner_id
ALTER TABLE conversations ADD COLUMN owner_id TEXT;
CREATE INDEX idx_conversations_owner ON conversations(owner_id);
```
### 11.3 多租户预留
所有服务端表预留 `tenant_id` 字段V1 默认为 NULL单租户V2 启用多租户隔离。
---
## 12. 安全模型
### 12.1 分层安全
```
Layer 1: 网络安全
├─ 客户端 ↔ 服务端HTTPS + WSS
├─ 服务端 ↔ LLMHTTPS
└─ 服务端内部VPC 隔离
Layer 2: 认证安全
├─ 用户登录:用户名+密码bcrypt, rounds=12→ JWT
├─ 客户端认证JWTaccess 15min + refresh 7d
├─ 系统集成API KeySHA256 hash 存储)
└─ 登录限流5次/分钟
Layer 3: 权限安全
├─ RBAC 三级角色 + 权限位
├─ 路由级权限检查
├─ 数据级隔离owner_id / tenant_id
└─ 终端双重授权
Layer 4: 操作安全
├─ 终端命令三层防护
├─ 危险命令不持久化白名单
├─ 审计日志(只追加,不可篡改)
└─ 敏感操作二次确认
Layer 5: 数据安全
├─ LLM API Key 不下发客户端
├─ 代码文件不离开客户端
├─ 会话历史不上传服务端
└─ 审计日志脱敏
```
### 12.2 LLM 成本配额
```python
# 按 user/tenant 设月度 token 配额
class UsageQuota:
monthly_token_limit: int # 月度 token 上限
monthly_cost_limit_cents: int # 月度费用上限(分)
current_tokens: int # 当月已用
current_cost_cents: int # 当月已花费
# 服务端 LLM 网关检查
async def check_quota(user: User) -> bool:
quota = await get_user_quota(user.id)
if quota.current_tokens >= quota.monthly_token_limit:
raise HTTPException(429, "Monthly token quota exceeded")
if quota.current_cost_cents >= quota.monthly_cost_limit_cents:
raise HTTPException(429, "Monthly cost quota exceeded")
return True
```
---
## 13. 实施路线图
### 13.1 修订后的路线图(含 Phase 0
| 阶段 | 内容 | 周期 | 交付物 |
|------|------|------|--------|
| **Phase 0** | 包拆分 + 双进程骨架 | 3 周 | `agentkit_core` / `agentkit_client` / `agentkit_server` 三包分离,双进程能跑 |
| **Phase 1** | LLM 网关 + 基础认证 | 3 周 | RemoteLLMProvider + 服务端 LLM 网关 + JWT 登录 |
| **Phase 2** | 权限 + 审计 + 配置同步 | 3 周 | 3 级 RBAC + 审计日志 + 配置轮询同步 |
| **Phase 3** | KB 共享 + 离线降级 | 3 周 | 团队 KB + KB 缓存 + 离线降级 |
| **Phase 4+** | Web 管理台 / SSO / 代码索引 | 延后 | 按需推进 |
### 13.2 Phase 0包拆分前置必做
当前 `server/` 包是单体,没有客户端/服务端边界。Phase 0 需要拆分为:
```
agentkit/
├── core/ — Agent 引擎(客户端服务端共用)
│ ├── base.py
│ ├── react.py
│ ├── rewoo.py
│ └── ...
├── llm/ — LLM 抽象层(共用)
│ ├── protocol.py
│ ├── gateway.py
│ ├── config.py
│ └── remote_provider.py — 新增
├── tools/ — 工具(共用)
├── client/ — 客户端特有
│ ├── sidecar.py — 本地 sidecar 入口
│ ├── terminal.py — 终端(从 server/routes/ 迁移)
│ ├── files.py — 文件操作
│ ├── session.py — 本地会话存储
│ ├── sync.py — 配置同步引擎
│ └── audit.py — 审计上报
├── server/ — 服务端特有
│ ├── app.py — 服务端 FastAPI app
│ ├── auth/ — 认证授权
│ ├── llm_gateway/— LLM 网关
│ ├── kb/ — 知识库
│ ├── audit/ — 审计
│ └── admin/ — 管理 API
└── shared/ — 共享模型/配置
├── models.py
└── config.py
```
### 13.3 Phase 1 验证目标
Phase 1 结束时验证核心价值:
- 企业统一管 LLM Key
- 审计 LLM 用量
- 客户端通过服务端代理调用 LLM
**如果 Phase 1 后企业不买单,停止后续投入。**
### 13.4 替代方案最小验证4 周)
如果不确定企业是否买单,可先做最小方案:
- 服务端只做 LLM Key 代理 + 用量统计
- 用户认证用 API Key沿用现有 `clients.yaml`
- 无 RBAC、无 KB 共享
- 4 周可交付,用最小代价验证企业需求
---
## 14. 独立批判性分析
> 以下为独立架构师以全新视角对方案的批判性分析,未经修改。
### 14.1 需求目标分析
#### 14.1.1 产品定位不清晰
方案把两个**买家不同、成功指标不同、部署模式不同**的产品缝在一起:
| 维度 | 开发者生产力工具 | 企业治理平台 |
|------|----------------|------------|
| 买家 | 开发者个人 | IT/安全/采购 |
| 核心指标 | 任务完成率、延迟 | 合规率、成本可控 |
| 部署 | 本地优先 | 集中部署 |
方案同时声称要"类似 Trae/Cursor"又要"企业级平台",但**没有回答:先卖给谁?谁拍板?谁付钱?**
#### 14.1.2 差异化竞争力
真正的差异化只有一条半:
- **"代码不离开客户端"**真差异化Cursor/Trae 的 codebase indexing 在云端)
- **"Agent 本地执行"**半个差异化Cursor 的 Agent 也是本地跑的)
方案漏掉了真正能拉开差距的能力:当前代码库已有的**专家团/董事会模式**,这是 Cursor/Trae 完全没有的。
#### 14.1.3 遗漏的核心场景
1. **代码库语义索引**Cursor 的核心竞争力,方案完全没提
2. **IDE 集成**:开发者活在 VS Code/JetBrains 里,纯桌面端推广阻力大
3. **离线/内网 LLM**:很多企业不能用云端 LLM
4. **多设备会话**:方案内部矛盾(会话纯本地 vs 多设备)
5. **模型评估/回归**:企业上线 Agent 前要评估
### 14.2 必要性分析
#### 14.2.1 服务端模块必要性
| 模块 | 必要性 | 理由 |
|------|--------|------|
| LLM 网关 | 必须 | "企业级"唯一不可替代的价值 |
| 用户认证 | 必须 | 但 V1 只需 3 级 |
| 审计日志 | 应该 | 范围要收窄(只审计 LLM 调用 + 危险命令) |
| 知识库 | 应该 | 可用现有 KB + pgvector 先跑 |
| 工作流模板 | 可延后 | YAML + Git 够用 |
| 技能市场 | 可延后 | 分发不是瓶颈 |
| 生产系统集成 | 不要做 | 暴露 Webhook 够用 |
| Web 管理台 | 可延后 | V1 用 CLI 管理 |
**结论**V1 服务端只需要 3 个模块——LLM 网关 + 用户认证 + 审计日志。
#### 14.2.2 LLM 代理模式利弊
代理模式的真实成本(被低估):
- ReAct/专家团循环是**多轮串行 LLM 调用**,一个复杂任务可能 20-50 次
- 跨地域公网RTT 150ms+)会明显劣化体验
代理模式的真实收益(被高估):
- "Key 不下发"保护的是**企业的 LLM 预算和用量审计**,不是真正的安全边界
- Tauri 桌面端跑在用户机器上,用户能 dump 内存、抓包
**建议**:代理模式保留,但明确其价值是成本管控 + 审计,不是安全。服务端必须支持内网部署。
#### 14.2.3 四级 RBAC 过度设计
- `viewer`:谁会用 AI 编程工具只看不操作?想象出来的角色
- `user vs power`:终端和 KB 管理是两个不相关的权限,不该绑成一个等级
企业真实需求是**权限点**,不是角色等级。建议 3 级 + 权限位。
#### 14.2.4 终端审计隐私
| 场景 | 审计合理性 |
|------|-----------|
| 企业配发电脑 | 合理 |
| BYOD | 不合理 |
| 危险命令确认记录 | 合理 |
| 全量命令流水 | 过度(是监控不是审计) |
建议:只上报危险命令 + 确认结果,不上报普通命令流水。
### 14.3 架构设计合理性
#### 14.3.1 配置同步 WebSocket 过度设计
配置变更频率是**周/月级**,用 WebSocket 推送是杀鸡用牛刀。更简单的方案:启动时全量拉取 + 每 5 分钟轮询版本号 + 手动刷新。
#### 14.3.2 会话历史纯本地 vs 企业审计矛盾
如果企业要审计"员工用 AI 做了什么",会话历史是最核心的审计对象。纯本地意味着审计员看不到。
**建议**:拆成三层:
1. 完整对话内容:本地(默认)
2. 操作摘要:上报服务端(脱敏后)
3. LLM 调用元数据:服务端网关天然就有
#### 14.3.3 知识库不缓存导致离线断裂
KB 完全不缓存意味着离线时 Agent 无法引用任何团队知识,与"离线降级"原则矛盾。
**建议**:元数据缓存 + LRU 文档缓存 + 离线时只用已缓存文档。
#### 14.3.4 当前代码库适配性
FastAPI + Vue3 + Tauri 技术栈没问题,但当前 `server/` 包是单体,没有客户端/服务端边界。需要一次彻底的包结构重组Phase 0
### 14.4 改造方案可行性
#### 14.4.1 最大技术风险:终端的位置
当前 `terminal.py` 的 PTY 跑在 Python sidecar 里。改造后:
- 路线 A移到 Tauri Rust风险太高用 Rust 重写 PTY + 命令分类
- 路线 B保留本地 Python sidecar**唯一现实路线**,终端逻辑不动
#### 14.4.2 RemoteLLMProvider 改造
`LLMProvider` 是干净的 ABCRemoteLLMProvider 本身 2-3 天。难点在服务端流式透传 + 取消传播 + fallback 语义1-2 周。
#### 14.4.3 路线图评估
"每阶段 2-3 周,共 8-12 周"——**不现实**,因为:
1. Phase 0包拆分没算进去
2. 用户系统从零开始
3. 终端位置决策未明确
4. 双进程调试环境搭建
**现实评估**12 周4 阶段 × 3 周),假设 1-2 个全职开发。
#### 14.4.4 "看似简单实则困难"的改造点
1. 流式 fallback 语义跨网络后的重新定义
2. `_verify_api_key` 的全局替换(十几个路由文件)
3. `clients.yaml` 兼容(两套认证并存)
4. Tauri sidecar 的远程地址注入
5. 专家团/董事会的 LLM 调用放大延迟
### 14.5 改进建议汇总
#### 架构简化
1. 砍掉 WebSocket 配置同步,用轮询 + ETag
2. 砍掉 viewer 角色RBAC 改 3 级 + 权限位
3. 砍掉"生产系统集成"模块,暴露 Webhook
4. 砍掉"技能市场"和"工作流模板中心"YAML + Git 够用
5. 明确双进程模型
#### 遗漏的考虑
| 遗漏项 | 重要性 | 建议 |
|--------|--------|------|
| 多租户隔离 | 高 | 所有表预留 tenant_id |
| SSO/OIDC | 高 | V2 支持V1 预留接口 |
| 数据备份/DR | 高 | PG 备份 + Redis 持久化 |
| 客户端升级 | 中 | Tauri updater 机制 |
| LLM 成本配额 | 中 | 按 user/tenant 设月度限额 |
| 代码库语义索引 | 高 | "类 Cursor"的必修课 |
| API 版本化 | 低 | 客户端和服务端独立发版后需要 |
#### 替代方案
**替代方案 B推荐起步服务端只做 LLM 代理**
- 砍掉 KB/工作流/技能市场/用户系统
- 服务端只做 LLM Key 代理 + 用量统计
- 用户认证用 API Key沿用 clients.yaml
- 4 周可交付,用最小代价验证企业需求
---
## 15. 方案优化与补全
基于独立分析,对原方案进行以下优化:
### 15.1 已采纳的优化
| 原方案 | 优化后 | 依据 |
|--------|--------|------|
| 四级 RBAC (viewer/user/power/admin) | 三级 + 权限位 (member/operator/admin) | §14.2.3 |
| WebSocket 配置同步 | 轮询 + ETag | §14.3.1 |
| 9 个服务端模块并列 | V1 只做 3 个LLM 网关 + 认证 + 审计) | §14.2.1 |
| 终端全量审计上报 | 只上报危险命令 | §14.2.4 |
| 知识库不缓存 | 元数据 + LRU 文档缓存 | §14.3.3 |
| 8-12 周路线图 | 12 周(含 Phase 0 包拆分) | §14.4.3 |
| 会话历史纯本地 | 三层拆分(内容本地 + 摘要上报 + 元数据服务端) | §14.3.2 |
### 15.2 新增补全
| 补全项 | 说明 |
|--------|------|
| Phase 0 包拆分 | 前置必做3 周 |
| 多租户预留 | 所有表预留 tenant_id |
| SSO/OIDC 接口预留 | V1 本地账号V2 OIDC |
| LLM 成本配额 | 按 user/tenant 月度限额 |
| 内网 LLM 支持 | vLLM/Ollama 接入 |
| 客户端直连降级 | 服务端不可用时用户自填 Key 直连 LLM |
| 代码库语义索引 | 列入 Phase 4+ 规划 |
| 数据备份策略 | PG 备份 + Redis 持久化 |
### 15.3 替代方案:最小验证路径
如果不确定企业是否买单,建议先走 4 周最小方案:
```
Week 1-2: 服务端 LLM Key 代理 + 用量统计
Week 3: 客户端 RemoteLLMProvider
Week 4: 联调 + 企业试用
```
验证核心假设:**企业是否真需要统一管 LLM Key 和成本**。
验证通过后,再按 Phase 0 → Phase 3 推进完整方案。
---
## 16. 待决策问题
以下问题需要明确后才能进入实施:
### 16.1 必须先回答的三个问题
| # | 问题 | 影响 |
|---|------|------|
| 1 | **卖给谁?** 开发者个人还是企业 IT | 决定优先级和功能取舍 |
| 2 | **服务端部署在哪?** 内网还是公网? | 决定代理模式是否可接受 |
| 3 | **终端跑在哪?** Tauri Rust 还是本地 sidecar | 决定 Phase 0 工作量 |
### 16.2 架构决策
| # | 问题 | 选项 | 建议 |
|---|------|------|------|
| 4 | 先做完整方案还是最小验证? | 完整 12 周 vs 最小 4 周 | 先做最小验证 |
| 5 | 是否支持 BYOD | 支持/不支持 | 支持(纯本地模式) |
| 6 | 会话内容是否上传? | 纯本地/摘要上报/全量上传 | 摘要上报 |
| 7 | V1 是否支持 SSO | 支持/不支持/预留接口 | 预留接口 |
| 8 | 代码库语义索引何时做? | Phase 3/Phase 4+/不做 | Phase 4+ |
---
## 附录 A当前代码库关键文件索引
| 模块 | 文件 | 改造角色 |
|------|------|---------|
| LLM 协议 | `src/agentkit/llm/protocol.py` | 共用,新增 RemoteLLMProvider |
| LLM 网关 | `src/agentkit/llm/gateway.py` | 服务端保留,客户端改代理 |
| LLM 配置 | `src/agentkit/llm/config.py` | 服务端 |
| Agent 引擎 | `src/agentkit/core/` | 客户端本地执行 |
| 工具 | `src/agentkit/tools/` | 客户端本地执行 |
| 终端 | `src/agentkit/server/routes/terminal.py` | 迁移到 `client/terminal.py` |
| 会话存储 | `src/agentkit/chat/sqlite_conversation_store.py` | 客户端,增加 owner_id |
| 鉴权中间件 | `src/agentkit/server/middleware.py` | 服务端,改造为 JWT + API Key 双轨 |
| 客户端配置 | `src/agentkit/server/client_config.py` | 服务端,迁移到 DB |
| 服务端配置 | `src/agentkit/server/config.py` | 服务端,增加 auth 配置 |
| 专家团 | `src/agentkit/experts/` | 客户端,配置从服务端同步 |
| 知识库 | `src/agentkit/memory/knowledge_base.py` | 服务端 |
| 情景记忆 | `src/agentkit/memory/episodic.py` | 服务端,增加 user_id |
| Tauri sidecar | `src-tauri/src/sidecar.rs` | 客户端,增加远程地址注入 |
| Tauri 配置 | `src-tauri/tauri.conf.json` | 客户端,放宽 CSP |
| 前端 API | `src/agentkit/server/frontend/src/api/base.ts` | 客户端,支持双目标 |
| 前端 Chat | `src/agentkit/server/frontend/src/stores/chat.ts` | 客户端WS 附加 token |
## 附录 B术语表
| 术语 | 定义 |
|------|------|
| Sidecar | Tauri 启动的本地 Python 进程,提供本地 API |
| LLM 网关 | 服务端统一管理 LLM API Key 和用量的代理服务 |
| RemoteLLMProvider | 客户端通过服务端 LLM 网关调用 LLM 的 Provider 实现 |
| RBAC | 基于角色的访问控制 |
| 权限位 | 独立于角色的细粒度权限(如 terminal.local.use |
| BYOD | Bring Your Own Device自带设备 |
| 离线降级 | 服务端不可用时客户端部分功能仍可使用 |
| 本地终端 | 在客户端本地机器上执行命令的终端模式 |
| 服务端终端 | 在服务端机器上执行命令的终端模式,需 admin 授权 |
| 危险命令 | 可能影响系统安全的终端命令rm/sudo/chmod 等) |
| 内置白名单 | 系统级不可修改的安全命令列表_SAFE_COMMAND_PREFIXES |
| 全局白名单 | admin 管理的命令白名单,仅服务端终端适用 |
| 用户白名单 | 用户自管的命令白名单,仅本地终端适用 |
| 会话白名单 | 临时白名单,当前会话有效,会话结束清除 |
| 黑名单 | admin 管理的禁止命令列表,所有终端模式生效,优先级最高 |
| 终端审批 | 服务端终端中非白名单危险命令需 admin 实时批准的机制 |
| 审计日志 | 记录用户操作的不可篡改日志 |
| 租户 | 多租户架构中的隔离单位(企业/团队) |
---
*文档结束。待决策问题明确后进入实施阶段。*