fischer-agentkit/docs/plans/2026-06-19-003-feat-enterpr...

19 KiB
Raw Blame History

title type status created completed origin deepened
feat: Enterprise Client-Server Architecture Evolution feat completed 2026-06-19 2026-06-19 docs/plans/2026-06-19-002-enterprise-client-server-architecture-plan.md false

feat: Enterprise Client-Server Architecture Evolution

Summary

将 Fischer AgentKit 从纯本地运行架构演进为企业级客户端+服务端架构。客户端Tauri 桌面端)作为 AI 工作台本地执行 Agent/终端/文件操作,服务端作为企业平台提供 LLM 网关(统一 Key 管理)、用户权限、审计日志、知识库共享能力。采用渐进式改造,每个阶段设立检查点验证核心假设。

Problem Frame

当前 AgentKit 是纯本地架构Tauri 启动本地 Python sidecarLLM API Key 存在本地 agentkit.yaml无用户系统、无权限管理、无服务端部署。企业场景需要统一管控 LLM Key 和成本、团队知识共享、权限与审计、多用户支持。

Scope Boundaries

In Scope

  • 服务端 LLM 网关(统一 Key + 用量统计 + 流式透传)
  • 用户认证JWT + API Key 双轨)
  • 三级 RBAC + 权限位
  • 双模式终端(本地 + 服务端)+ 三层白名单
  • 终端审计日志
  • 配置同步(轮询版)
  • 前端连接模式切换

Deferred to Follow-Up Work

  • Web 管理台V1 用 CLI 管理)
  • 技能市场 / 工作流模板中心YAML + Git 够用)
  • 生产系统集成(暴露 Webhook 即可)
  • SSO/OIDCV1 本地账号V2 预留接口)
  • 代码库语义索引
  • 多租户隔离(表预留 tenant_idV2 启用)
  • 多设备会话同步

Key Technical Decisions

KTD1: 终端保留在本地 Python sidecar非 Tauri Rust

决策:终端 PTY 逻辑保留在 Python sidecar 中,不迁移到 Tauri Rust 层。

理由:当前 terminal.py + PTYSession 已完整实现 PTY 管理、安全检测、确认流程。用 Rust 重写风险高、收益低。本地 sidecar 模式下终端逻辑不变,服务端终端新增独立端点。

KTD2: LLM 代理模式(非客户端直连)

决策:客户端通过服务端 LLM 网关间接调用 LLM不在本地存储 API Key。

理由:核心价值是成本管控 + 用量审计(非安全边界)。服务端必须支持内网部署以避免跨地域延迟。客户端保留直连降级能力(服务端不可用时用户自填 Key

KTD3: 配置同步用轮询(非 WebSocket 推送)

决策:启动时全量拉取 + 每 5 分钟轮询版本号 + 手动刷新。

理由:配置变更频率是周/月级WebSocket 推送是杀鸡用牛刀。轮询实现量是 WebSocket 的 1/10覆盖 99% 场景。

KTD4: 三级 RBAC + 权限位(非四级角色)

决策member / operator / admin 三级角色 + 独立权限位。

理由:四级中的 viewer 是想象出来的角色。企业真实需求是权限点(能否用终端、能否管理 KB不是角色等级。权限位比固定等级更灵活。

KTD5: 双模式终端 + 三层白名单

决策:支持本地终端(客户端 sidecar PTY和服务端终端服务端 PTY均配三层白名单内置/全局/用户)+ 黑名单。

理由:本地终端满足开发者本地操作需求,服务端终端满足 DevOps 管理服务器需求。白名单机制平衡安全与效率。

High-Level Technical Design

Phase 1: LLM Gateway + Auth          Phase 2: RBAC + Audit + Terminal
┌──────────────┐                    ┌──────────────┐
│  Client      │                    │  Client      │
│  RemoteLLM   │──JWT──►            │  Terminal    │──JWT──►
│  Provider    │                    │  (Local)     │
└──────┬───────┘                    └──────┬───────┘
       │ SSE                              │ WS
       ▼                                  ▼
┌──────────────┐                    ┌──────────────┐
│  Server      │                    │  Server      │
│  LLM Gateway │                    │  Auth+RBAC   │
│  + JWT Auth  │                    │  + Audit     │
│  + Usage     │                    │  + Whitelist │
└──────────────┘                    └──────────────┘

Phase 3: Server Terminal + KB
┌──────────────┐
│  Client      │
│  Terminal    │──JWT──►
│  (Server)    │
└──────┬───────┘
       │ WSS
       ▼
┌──────────────┐
│  Server      │
│  Server PTY  │
│  + Approval  │
│  + KB Search │
└──────────────┘

Implementation Units

U1. 服务端 LLM 网关 API

Goal: 在服务端新增 LLM 代理端点,接收客户端请求并转发到 LLM Provider记录用量。

Dependencies: 无(首个单元)

Files:

  • src/agentkit/server/routes/llm_gateway.py(新建)
  • src/agentkit/server/app.py(注册路由)
  • tests/unit/test_llm_gateway.py(新建)

Approach:

  • 新增 POST /api/v1/llm/chat(非流式)和 POST /api/v1/llm/chat/streamSSE 流式)
  • 复用现有 LLMGateway.chat()chat_stream()
  • 流式端点将 StreamChunk 序列化为 SSE 格式(data: {json}\n\n
  • 记录每次调用的 user_id、model、tokens、cost 到 llm_usage_records
  • JWT 认证U2 完成前临时用 API Key

Test scenarios:

  • 非流式 chat 请求返回正确的 LLMResponse JSON
  • 流式 chat 请求返回 SSE 格式,每个 chunk 是 data: {json}\n\n
  • 无效 model 返回 404
  • LLM Provider 失败时返回 502
  • 用量记录正确写入数据库model, tokens, cost
  • 无认证时返回 401

Checkpoint CP1: 服务端 LLM 网关可独立运行,通过 curl 验证流式和非流式调用。


U2. JWT 认证模块

Goal: 实现用户注册/登录/JWT 签发验证,替换当前纯 API Key 认证。

Dependencies: U1

Files:

  • src/agentkit/server/auth/__init__.py(新建)
  • src/agentkit/server/auth/models.py新建UserModel + UserApiKeyModel
  • src/agentkit/server/auth/jwt_utils.py新建JWT 签发/验证)
  • src/agentkit/server/auth/password.py新建bcrypt 哈希)
  • src/agentkit/server/auth/middleware.py新建AuthMiddleware
  • src/agentkit/server/auth/dependencies.py新建require_permission 依赖)
  • src/agentkit/server/routes/auth.py新建login/refresh/logout/me
  • src/agentkit/server/app.py(注册路由 + 中间件替换)
  • tests/unit/test_auth.py(新建)

Approach:

  • UserModel: id, username, email, password_hash, role, is_active, is_terminal_authorized, is_server_terminal_authorized
  • UserApiKeyModel: user_id, key_hash(SHA256), key_prefix, name, expires_at, is_revoked
  • JWT: access_token(15min) + refresh_token(7d)HS256 签名
  • AuthMiddleware: JWT 优先 → API Key → 兼容 clients.yaml → dev mode 放行
  • require_permission(*perms): FastAPI 依赖注入,检查 request.state.current_user 的角色权限
  • 初始 admin 引导: 首次启动时从 AGENTKIT_ADMIN_USERNAME/PASSWORD 创建 admin 用户
  • 数据库: V1 用 SQLite复用 aiosqlite后续切换 PostgreSQL

Test scenarios:

  • 注册/登录返回 access_token + refresh_token
  • refresh_token 可刷新 access_token
  • 错误密码返回 401
  • JWT 过期后返回 401refresh 后可用
  • API Key 认证识别用户身份
  • 无认证 dev mode 放行
  • 无认证生产 mode 返回 401
  • require_permission 正确拒绝/放行
  • 初始 admin 创建成功

Checkpoint CP2: 可通过登录 API 获取 JWT使用 JWT 访问 LLM 网关。


U3. RemoteLLMProvider客户端 LLM 代理)

Goal: 在客户端新增 RemoteLLMProvider,通过服务端 LLM 网关调用 LLM。

Dependencies: U1, U2

Files:

  • src/agentkit/llm/remote_provider.py(新建)
  • src/agentkit/llm/gateway.py(增加 RemoteLLMProvider 注册支持)
  • tests/unit/test_remote_provider.py(新建)

Approach:

  • RemoteLLMProvider(LLMProvider): 实现 chat()chat_stream()
  • chat(): POST /api/v1/llm/chat,带 Authorization: Bearer {jwt}
  • chat_stream(): POST /api/v1/llm/chat/stream,解析 SSE 流为 StreamChunk
  • 构造函数接收 server_url + auth_token_providercallable返回当前 JWT
  • 错误处理: 401 触发 token 刷新重试502 抛 LLMProviderError
  • 客户端 LLMGateway 配置为使用 RemoteLLMProvider 时,不加载本地 Provider 配置

Test scenarios:

  • chat() 正确发送请求并解析 LLMResponse
  • chat_stream() 正确解析 SSE 流为 StreamChunk 序列
  • 401 响应触发 token 刷新重试
  • 502 响应抛出 LLMProviderError
  • 网络超时抛出异常
  • is_final=True 的 chunk 正确标记

Checkpoint CP3: 客户端 Agent 通过 RemoteLLMProvider → 服务端网关 → LLM Provider 完成对话。


U4. 前端认证 + 连接模式切换

Goal: 前端实现登录页、JWT 管理、API Client 附加 JWT、连接模式切换。

Dependencies: U2, U3

Files:

  • src/agentkit/server/frontend/src/stores/auth.ts(新建)
  • src/agentkit/server/frontend/src/api/base.ts(改造,附加 JWT
  • src/agentkit/server/frontend/src/views/LoginView.vue(新建)
  • src/agentkit/server/frontend/src/router/index.ts(路由守卫)
  • src/agentkit/server/frontend/src/api/auth.ts(新建)
  • src/agentkit/server/frontend/src/App.vue(启动时初始化认证)

Approach:

  • auth store: user, accessToken, refreshToken, permissions, hasPermission(), canAccessTerminal()
  • BaseApiClient.request(): 自动附加 Authorization: Bearer {token}401 时自动刷新
  • BaseApiClient.createWebSocket(): 附加 ?token={jwt} 查询参数
  • 登录页: 用户名 + 密码 → 调用 /api/v1/auth/login → 存储 JWT → 跳转主页
  • 路由守卫: 未登录跳转 /login,权限检查
  • initApiBaseURL(): Tauri 模式检查 localStorage 中的远程服务器配置

Test scenarios:

  • 登录成功后 JWT 存入 localStorage跳转主页
  • 登录失败显示错误提示
  • API 请求自动附加 JWT
  • 401 响应自动触发 token 刷新
  • token 刷新失败跳转登录页
  • WebSocket 连接附加 token 参数
  • 路由守卫正确拦截未登录用户

Checkpoint CP4: 前端登录 → JWT 认证 → 通过服务端 LLM 网关对话,全链路打通。


U5. 权限模型 + RBAC 中间件

Goal: 实现三级 RBAC + 权限位,集成到所有路由。

Dependencies: U2

Files:

  • src/agentkit/server/auth/permissions.py新建Permission enum + ROLE_PERMISSIONS
  • src/agentkit/server/auth/dependencies.py(完善 require_permission
  • src/agentkit/server/routes/portal.py(增加权限检查)
  • src/agentkit/server/routes/terminal.py(增加权限检查)
  • src/agentkit/server/routes/settings.py(增加权限检查)
  • src/agentkit/server/routes/kb_management.py(增加权限检查)
  • tests/unit/test_permissions.py(新建)

Approach:

  • Permission enum: CHAT, KB_QUERY, KB_WRITE, WORKFLOW_EXECUTE, TERMINAL_LOCAL_USE, TERMINAL_SERVER_USE, TERMINAL_WHITELIST_MANAGE, USER_MANAGE, SYSTEM_CONFIG
  • ROLE_PERMISSIONS: member / operator / admin 权限映射
  • require_permission(*perms): 检查 request.state.current_user 的角色权限
  • 现有路由增加 Depends(require_permission(Permission.XXX))
  • dev mode无用户: 终端等高危功能仍需认证,其他放行

Test scenarios:

  • member 角色可对话但不可访问终端
  • operator 角色可使用本地终端但不可管理用户
  • admin 角色可访问所有功能
  • 未认证用户在 dev mode 可对话但不可用终端
  • 权限不足返回 403

Checkpoint CP5: 不同角色用户访问不同功能,权限检查生效。


U6. 本地终端白名单 + 审计上报

Goal: 本地终端增加三层白名单机制 + 危险命令审计上报。

Dependencies: U5

Files:

  • src/agentkit/server/routes/terminal.py(改造白名单逻辑)
  • src/agentkit/server/auth/models.py(增加白名单表模型)
  • src/agentkit/server/routes/terminal_whitelist.py(新建,白名单管理 API
  • src/agentkit/server/app.py(注册白名单路由)
  • tests/unit/test_terminal_whitelist.py(新建)

Approach:

  • 白名单匹配优先级: 黑名单 → 内置安全白名单 → 用户白名单 → 会话白名单 → 危险检测
  • 用户白名单存储在服务端 DBterminal_whitelist_user 表),客户端缓存
  • 黑名单存储在服务端 DBterminal_blocklistadmin 管理
  • 危险命令确认后可选加入会话白名单(不持久化到用户白名单)
  • 危险命令执行后上报审计日志到服务端(terminal_audit_logs 表)
  • 白名单管理 API: GET/POST/DELETE /api/v1/terminal/whitelist/user

Test scenarios:

  • 内置安全白名单命令直接执行
  • 用户白名单命令直接执行
  • 会话白名单命令直接执行
  • 黑名单命令被拒绝
  • 危险命令弹出确认,确认后执行
  • 危险命令拒绝后不执行
  • 危险命令审计日志正确上报
  • 白名单 CRUD API 正常工作

Checkpoint CP6: 本地终端白名单生效,危险命令需确认且审计上报。


U7. 配置同步引擎

Goal: 客户端从服务端同步技能/Agent/工作流配置。

Dependencies: U2

Files:

  • src/agentkit/server/routes/config_sync.py(新建,配置同步 API
  • src/agentkit/server/app.py(注册路由)
  • src/agentkit/client/sync.py(新建,客户端同步引擎)
  • tests/unit/test_config_sync.py(新建)

Approach:

  • 服务端 API: GET /api/v1/config/version(返回版本号)+ GET /api/v1/config/skills|agents|workflows(返回配置列表)
  • 客户端 ConfigSync: 启动时全量拉取 → 每 5 分钟轮询版本号 → 版本变化时全量拉取
  • 配置缓存在本地 SQLiteconfig_cache 表)
  • 离线时使用本地缓存

Test scenarios:

  • 启动时全量拉取配置
  • 版本号未变化时不拉取
  • 版本号变化时全量拉取
  • 离线时使用本地缓存
  • 配置正确更新到本地

Checkpoint CP7: 客户端启动后自动同步服务端配置,离线时使用缓存。


U8. 服务端终端 + 审批机制

Goal: 新增服务端终端模式,非白名单危险命令需 admin 审批。

Dependencies: U5, U6

Files:

  • src/agentkit/server/routes/terminal_server.py(新建,服务端终端 WebSocket
  • src/agentkit/server/auth/models.py(增加审批表模型)
  • src/agentkit/server/routes/terminal_whitelist.py(增加全局白名单 + 审批 API
  • src/agentkit/server/app.py(注册路由)
  • tests/unit/test_terminal_server.py(新建)

Approach:

  • WS /api/v1/terminal/server/ws: 服务端 PTY WebSocket
  • 权限检查: TERMINAL_SERVER_USE + is_server_terminal_authorized
  • 命令执行流程: 黑名单 → 内置白名单 → 全局白名单 → 会话白名单 → 非白名单需 admin 审批
  • 审批机制: 创建 terminal_approvals 记录 → WebSocket 推送 admin → admin 批准/拒绝 → 执行/取消
  • 审批超时: 5 分钟自动拒绝
  • 全量审计: 所有命令(含执行/拒绝/审批)记录到 terminal_audit_logs
  • 会话隔离: 每个用户独立 PTY 会话,工作目录隔离
  • 资源限制: 最大并发会话数、会话超时

Test scenarios:

  • 有权限用户可连接服务端终端
  • 无权限用户被拒绝
  • 全局白名单命令直接执行
  • 非白名单危险命令创建审批请求
  • admin 批准后命令执行
  • admin 拒绝后命令取消
  • 审批超时自动拒绝
  • 所有命令审计日志记录
  • 会话隔离正确

Checkpoint CP8: 服务端终端可用,非白名单命令需 admin 审批,全量审计。


U9. 前端终端双模式 UI + 白名单管理

Goal: 前端终端支持本地/服务端模式切换,白名单管理页面。

Dependencies: U6, U8

Files:

  • src/agentkit/server/frontend/src/components/terminal/TerminalPanel.vue(改造,模式切换)
  • src/agentkit/server/frontend/src/components/terminal/WhitelistManager.vue(新建)
  • src/agentkit/server/frontend/src/api/terminal.ts(改造,支持双模式)
  • src/agentkit/server/frontend/src/stores/auth.ts(增加 canUseServerTerminal

Approach:

  • 终端面板顶部: [本地终端] [服务端终端] Tab 切换
  • 本地终端: 连接本地 sidecar WebSocket
  • 服务端终端: 连接服务端 WebSocket带 JWT
  • 非白名单命令: 本地终端用户确认 / 服务端终端显示"等待审批"
  • 白名单管理页: Tab我的白名单 / 全局白名单 / 黑名单)

Test scenarios:

  • 本地终端模式正常执行命令
  • 服务端终端模式正常执行命令
  • 模式切换正确切换 WebSocket 连接
  • 无权限用户看不到服务端终端 Tab
  • 白名单管理 CRUD 正常工作
  • 危险命令确认对话框正确显示

Checkpoint CP9: 前端双模式终端可用,白名单管理页面正常。


Checkpoint Summary

检查点 验证内容 通过标准
CP1 服务端 LLM 网关 curl 验证流式和非流式调用
CP2 JWT 认证 登录获取 JWT使用 JWT 访问 API
CP3 客户端 LLM 代理 客户端 Agent 通过服务端网关完成对话
CP4 全链路打通 前端登录 → JWT → 服务端 LLM → 对话
CP5 权限模型 不同角色访问不同功能,权限检查生效
CP6 本地终端白名单 危险命令需确认且审计上报
CP7 配置同步 客户端自动同步服务端配置
CP8 服务端终端 非白名单命令需 admin 审批
CP9 前端双模式终端 双模式切换 + 白名单管理

Risks & Dependencies

风险 影响 缓解
流式 fallback 跨网络语义变化 客户端可能看到内容跳变 服务端首 chunk 前完成 fallback首 chunk 后不 fallback
_verify_api_key 全局替换遗漏 部分路由无权限检查 代码审查 + 测试覆盖
clients.yaml 兼容 两套认证并存增加复杂度 V1 保留兼容V2 废弃
Tauri sidecar 远程地址注入 前端 API 调用目标变化 base.ts 支持双目标
专家团 LLM 调用放大延迟 多 expert 串行 × RTT 服务端网关连接复用

Verification Strategy

每个检查点CP必须通过以下验证才能进入下一阶段

  1. 单元测试: 新增代码的单元测试全部通过
  2. 集成测试: 关键链路的集成测试通过
  3. 手动验证: 按检查点描述的手动验证步骤通过
  4. 回归测试: pytest tests/unit/ -x -q 不新增失败(已知 test_rewoo_agent_yaml_loads 除外)
  5. 前端类型检查: npx vue-tsc --noEmit 通过
  6. 代码规范: ruff check 改动文件无新增错误