Files

191 lines
17 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.
# 基于 GoodBuddy 的后端基础设计
状态:B1 已实现、验收部分完成,2026-10-05;B2 至 B6 待实现。原始设计日期为 2026-10-04。
本文是[技术设计](./technical-design.md)的基础服务实施分册,维护客户端适配依据、接口和实施顺序。
产品范围由 [PRD](./prd.md)维护,业务状态由[功能逻辑](./logic-design.md)维护,已验证事实见[实施进度](./progress.md)。
## 1. 设计结论
GoodBuddy 承担模型选择、对话、工具执行、知识检索入口和文档日常操作。ShareServer 独立运行,
负责模型请求转发、组织身份与授权、共享目录和服务端文档存储。ONLYOFFICE 是独立编辑服务。
不把 Electron、客户端 SQLite、Agent Runtime 或客户端源码引入服务端构建。
基础功能优先利用客户端已有调用路径:先完成正常的模型网关接入,再增加组织与设备身份,
随后实现组织模型导入和真实资源发布。知识检索、文档编辑各自按实际用户动作验收。
完整组织服务仍以 PostgreSQL 为目标;本地网关阶段继续单进程文件存储,不先建设消息系统、联邦或通用任务平台。
## 2. 客户端依据与差距
下表链接指向相邻 `goodbuddy` 仓库,要求两个仓库位于同一级目录。只引用契约,不建立源码依赖。
| 客户端实现 | 已核对行为 | 后端设计影响 |
| --- | --- | --- |
| [模型配置 schema](../../../../goodbuddy/src/shared/contracts.ts) | profile 含 `baseUrl`、`modelName`、显式 `protocol`、认证方式及能力设置;模型 ID 最长 128 字符 | 开放模型 ID 按客户端限制保存;目录携带协议,不能只返回显示名称 |
| [OpenAI 地址拼接](../../../../goodbuddy/src/main/agent/openai-endpoint.ts) | 在 Base URL 后追加 `chat/completions` 或 `responses`;不自动增加 `/v1` | 接入信息必须给出包含 `/v1` 的完整 Base URL |
| [模型 Runtime](../../../../goodbuddy/src/main/agent/model-runtime.ts) | 连接测试发非流式生成请求;对话走 SSE,包含工具、工具结果和用量字段 | 获取模型成功不能代替连接测试;必须验收 JSON、SSE 与工具往返 |
| [配置存储](../../../../goodbuddy/src/main/runtime-settings-store.ts)、[凭据加密](../../../../goodbuddy/src/main/settings-credential-cipher.ts) | Main 保管模型 Key,Renderer 只看到是否已配置 | Desktop 保存网关访问 Key,上游 Key 留在 ShareServer |
| [模型选择](../../../../goodbuddy/src/shared/runtime-selection-contracts.ts) | 会话、项目、全局逐层解析模型 profile | 导入组织模型不覆盖个人模型,也不自动更换已有会话选择 |
| [设备共享服务](../../../../goodbuddy/src/main/device-sharing-service.ts) | 单服务 URL,稳定设备 ID,HTTP 注册、列表、发布和撤销;没有认证或心跳 | 现有 ID 不能当作用户身份;注册记录不能标为在线 |
| [发布契约](../../../../goodbuddy/src/shared/device-sharing-contracts.ts) | 仅名称、描述、类型、来源模式和权限声明,没有实际资源 ID | 不能从目录记录直接派发执行或检索请求 |
| [能力目录](../../../../goodbuddy/src/main/capabilities/capability-service.ts) | 可枚举本机 Skill、MCP 等配置 | 后续发布选择器可复用枚举;枚举结果不自动授权共享 |
| [知识服务](../../../../goodbuddy/src/main/knowledge/knowledge-service.ts) | `retrieve`、`retrieveMany` 是现有检索入口 | 提供端经授权后直接调用知识服务,不用 Agent 提示词代替检索协议 |
| [外部知识契约](../../../../goodbuddy/src/shared/external-knowledge-contracts.ts) | 当前提供者是 Dify、FastGPT、RAGFlow | ShareServer 共享知识需要新增适配,不能假设现有外部连接已支持 |
| [Office 功能文档](../../../../goodbuddy/docs/features/office-document-editing/README.md) | Office 编辑尚在设计;文件解析与外部打开已有实现 | 服务端 callback 和客户端文档 Tab 都要实现,不能把解析当作编辑 |
GoodBuddy 目前没有自动获取网关模型并创建 profile 的通用流程。现有设备共享页面也不会自动
启用模型连接。设备共享应用仍默认关闭,名称保留“设备共享(技术预览)”。
模型协议分别验收:本期只支持 `openai-chat-completions`。Responses、Anthropic、图像生成和
Embedding 均不因为上游声称“OpenAI 兼容”而自动支持。现有网关也没有这些转发端点。
远程 Agent 使用模型时,发请求的 Host 必须能访问网关;桌面本机的 `127.0.0.1` 地址不能直接用于该场景。
## 3. 服务划分与存储
| 服务 | 第一项可用行为 | 数据归属 |
| --- | --- | --- |
| 模型网关 | 保存上游、开放模型、验证访问 Key、转发并记录调用 | 上游配置及凭据、映射、访问 Key 摘要、调用元数据 |
| 身份与组织 | 管理员初始化、成员登录、加入组织 | 用户、组织、成员关系、会话 |
| 设备与目录 | 认证设备登记、撤销、发布者和资源绑定 | 设备归属、发布记录、动作授权;设备连接状态单独管理 |
| 客户端配置 | 显式获取并导入组织模型,回报应用结果 | 组织配置版本与每设备接收/应用结果 |
| 知识共享 | 对指定发布条目检索并返回引用 | 服务端保存发布元数据;远程模式的正文仍在提供设备 |
| 文档服务 | 上传、读取、编辑后保存、按归属删除或转交 | 主文档、归属、版本、回收记录;编辑会话单独保存 |
继续沿用 Hono 路由、业务 Store 和根 `shared/` DTO。业务增长后按上述职责拆文件,不预先建立
空模块树或通用插件框架。HTTP 边界校验输入与输出投影,控制台只使用 API,不直接访问存储。
现有 `sharing.json` 与 `gateway.json` 保留。网关新增秘密使用服务端加密密文,组织阶段再将
用户、组织、设备和授权纳入 PostgreSQL 事务。迁移要保留现有 ID 和撤销事实;没有身份的旧目录
只能作为未绑定记录,不能按设备名称自动认领。迁移命令、备份和重复执行行为随数据库实现交付。
## 4. B1:正常模型网关接入
这一实施单元完成本地可用路径,不依赖组织数据库。支持一个 ShareServer 实例、多个上游和
多个模型映射;使用本机管理入口,GoodBuddy 可手工配置网关。组织分组、费用结算、自动切换上游另行实现。
### 4.1 上游与凭据
新建上游输入 `name`、`baseUrl`、`protocol=openai-chat-completions`、`authentication=api-key|none`、
`enabled`。使用 API Key 时输入真实密钥。更新通过 `credentialAction=keep|replace|clear` 区分
保留、替换和清除,空输入不解释为清除。响应只返回 `credentialConfigured`,不返回密钥或密文。
使用 Node 标准加密实现 AES-256-GCM;主密钥来自部署配置或数据目录外的秘密文件,首次配置
命令为 `npm run gateway:init-key -- <文件路径>`,父目录须已存在,拒绝覆盖已有文件。
通过 `SHARESERVER_MASTER_KEY_FILE` 指定文件,或用 `SHARESERVER_MASTER_KEY` 提供 64 位十六进制值,不能同时设置。
密文带随机 nonce 与认证标签,以稳定上游 ID 为 AAD,随上游记录原子保存,避免独立文件半提交。
缺少或错误的主密钥应报告凭据不可用,不能生成新密钥覆盖既有密文。备份说明要求单独保管主密钥。
主密钥不进入 Web、普通数据备份和日志;HTTP 请求正文不记录密钥。
现有环境变量引用是已持久化的数据,需要继续可读、可调用;编辑时可以显式替换为托管凭据。
移除产品界面的前缀导入和变量名输入,环境文件加载仅保留为开发测试方式,不自动扫描 GoodBuddy 配置。
Base URL 接受 HTTP/HTTPS,保留合法服务路径,拒绝内嵌凭据、query 和 fragment,去掉尾斜杠。
可信内网 HTTP 上游已属于支持范围。访问 Key 经非加密 HTTP
传输的部署限制在接入说明中说明,对外部署使用 HTTPS;不为此加入额外网络发现流程。
### 4.2 模型与转发
发现模型调用上游 `/models`,发现失败不删除已保存配置,也不阻止手动填写模型 ID。
用户选择模型并指定对外 ID 后才创建映射。新对外 ID 最长 128 字符,首字符为 ASCII 字母或数字,
其余允许字母、数字、下划线、点、冒号、斜杠、连字符;显示名称单独保存。现有更长别名保留调用,
在导入 GoodBuddy 前要求管理员显式改名,不静默截断已有标识。
每个对外 ID 明确绑定一个上游和远端模型。转发只替换模型名与上游认证,不执行工具,不自动重试
有可能已经执行的请求。工具参数、工具结果和用量按 Chat Completions 协议传递;取消传播至上游。
保留现有超时、输出大小边界和终态审计。上游缺失用量记录为未知,不显示为零消耗。
### 4.3 网关访问与管理边界
客户端访问 Key 与上游 API Key 分开。服务端生成随机访问 Key,只在创建成功时返回完整值,
持久化 SHA-256 摘要、ID、名称、创建/撤销时间和允许的模型记录 UUID;别名改名不改变授权,列表不返回原值。可撤销后重新创建,
不提供读取旧 Key。初期 Key 代表一个调用配置,审计可关联 Key ID,但不能把备注名解释为已认证用户。
`/v1/models` 与 `/v1/chat/completions` 使用 Bearer Key;未知或撤销的 Key 返回 401,
无权调用该模型返回 403。列表只返回该 Key 允许且可用的模型。停用或撤销阻止后续请求,
已开始的流按原请求结束或由调用方取消;本期不承诺撤销自动追回已输出内容。
本机管理接口不能仅依靠 Origin 检查授权。B1 默认管理请求限直连回环来源,校验实际连接地址,
拒绝携带 `Forwarded`、`X-Forwarded-*` 或 `X-Real-IP` 的管理请求,并检查 Origin。
Vite 在代理 `/api` 前也检查原始 socket,只允许回环。除健康和就绪 GET 外,非回环 API 请求
仅能访问已带 Key 的推理接口;无认证旧目录 API 也保持
本机访问。容器/反向代理管理需要 B2 登录接入,不能将代理地址当作管理员。Web 网关测试仍通过
网关转发逻辑,由本机管理入口调用,不在浏览器长期保存管理秘密或把豁免开放给推理接口。
### 4.4 已实现接口
下表记录 B1 已实现接口,字段、错误及资源限制以技术设计第 4.2 节为准。前缀导入接口已移除,旧环境引用仅保留存储兼容。
| 路径 | 已实现行为 |
| --- | --- |
| `GET /api/v1/gateway/config` | 上游与模型公开投影、调用元数据、部署指定 `gatewayBaseUrl`;不携带任何密文或完整 Key |
| `POST /api/v1/gateway/upstreams`、`PUT /api/v1/gateway/upstreams/:id` | 接收地址、协议、认证方式和凭据操作,替代新表单的 `apiKeyEnv` |
| `POST /api/v1/gateway/upstreams/:id/discover` | 真实模型发现,保留手工映射入口 |
| `POST /api/v1/gateway/models`、`PUT /api/v1/gateway/models/:id` | 保存对外 ID、显示名、远端模型和启停 |
| `GET/POST /api/v1/gateway/access-keys` | 列表或创建模型访问 Key |
| `POST /api/v1/gateway/access-keys/:id/revoke` | 撤销 Key,重复撤销返回同一撤销事实 |
| `POST /api/v1/gateway/test` | 本机管理端非流式测试;复用真实转发及审计,不接受自定义上游 URL |
| `GET /api/v1/gateway/v1/models` | Bearer 认证后的 OpenAI 模型列表 |
| `POST /api/v1/gateway/v1/chat/completions` | Bearer 认证、模型授权、JSON/SSE 转发 |
Key 无效返回 401,其余错误沿用 `{error:{code,message},requestId}`,请求 ID 与调用
审计关联。不能把上游含密钥的错误正文原样返回;保留可定位的上游状态和错误类别。
### 4.5 GoodBuddy 使用与验收
管理员保存上游并开放模型后,在网关接入区取得 Base URL、协议和对外模型 ID,创建访问 Key。
GoodBuddy 在现有模型连接页面手动新增配置:
```text
Base URL: http://127.0.0.1:8787/api/v1/gateway/v1
Protocol: openai-chat-completions
Model: 管理员开放的模型 ID
API Key: ShareServer 签发的访问 Key
```
该操作不依赖设备共享开关,不读取供应商 Key,不修改个人已有 profile。异机调用用客户端可达
的 ShareServer 地址;界面显示配置的公开地址,不能把 Vite 端口或请求中的任意 Host 当作权威地址。
以下为完整验收清单,尚未全部通过。2026-10-05 已完成自动化检查和部分真实 API 验证,
包括发现、JSON/SSE、工具选择及本地执行、重启持久化与撤销拒绝;工具结果未回传上游,
未验证 GoodBuddy Desktop;浏览器仅核对页面快照,交互与视觉验收未完成。详细证据和剩余项目见[实施进度](./progress.md)。
验收依次检查:
1. 从空目录经 Web 保存真实上游,发现或手动添加模型;刷新、重启仍保留配置,密钥不回显。
2. GoodBuddy 现有模型连接测试成功,真实会话收到流式回答,审计可以关联模型和访问 Key。
3. 用无副作用工具完成一次真实工具调用与结果回传;停止生成时上游请求被取消。
4. 错误 Key、撤销 Key、未授权模型和停用上游均拒绝新调用,错误不伪装成空成功响应。
5. 上游超时、SSE 中断、凭据缺失、主密钥错误均给出准确状态;检查持久化及日志不含明文秘密或对话正文。
6. 验证 HTTP 内网上游及管理接口来源限制。单元测试不能替代上述桌面与真实服务验证。
这组验证只覆盖本机模型 Runtime。OpenCode、Continue、Harness 和远程 Agent 另行记录结果,
不从同一个 profile 推断全部 Runtime 可用。真实模型验证记录调用次数,不将配置下发标记为已实现。
## 5. 后续基础服务实施顺序
| 单元 | 交付内容 | 前置条件与完成标准 |
| --- | --- | --- |
| B2 身份与组织 | PostgreSQL 迁移、首个管理员、登录退出、单组织成员、设备绑定与撤销;Web 使用会话,Desktop 凭据在 Main 保存 | 从可信本机管理扩展到组织部署;两个不同成员不能改动对方设备或私人资源;退出或撤销后新请求被拒 |
| B3 组织模型导入 | 认证目录、用户显式导入、组织模型来源标记、配置版本与应用回报 | 依赖 B2;客户端创建独立 profile,保留个人配置;离线为待接收,收到后保存成功才为已应用 |
| B4 真实资源发布 | 从本机能力/知识库选择资源,登记稳定来源 ID、所有者、提供设备及独立动作权限 | 依赖 B2;客户端增加资源绑定和提供端通道;无心跳不显示在线,旧手工目录不自动成为可调用资源 |
| B5 共享知识检索 | 消费者选共享库,服务端授权并路由,提供端调用 `retrieveMany`,返回有界引用 | 依赖 B4;两台 GoodBuddy 真实检索,撤销及提供端离线有准确失败;正文读取、下载各自另验收 |
| B6 服务端文档 | 主文档上传、读取、个人删除、转交组织、回收;再接 ONLYOFFICE 编辑保存与 GoodBuddy 文档入口 | 归属功能依赖 B2;保存后重开及重启可见,转交后个人删除权失效,管理员元数据可见不赋予正文权限 |
Office 私有 DOCX 试验仍可按技术设计第 10.1 节独立验证部署与保存。该试验没有用户归属,
不能替代 B6。后续服务端主存文档保存不要求 Desktop 回写确认;显式本地/SSH 来源模式另走既有源文件契约。
B3 先实现主动获取和显式导入,不以推送、离线队列或回滚系统为第一步。组织配置关联服务端稳定
模型 ID,个人 profile 不由组织配置覆盖。组织撤销后网关直接拒绝访问,客户端缓存不能维持授权。
B4 的提供端连接必须单独实现。已有 Agent 执行通道没有发布身份、共享授权和知识正文协议,不能
直接暴露为共享 API。远程知识模式不上传整个库;服务器副本模式须实际完成文件与索引写入才可标为可检索。
## 6. 文档与实施记录
2026-10-04 设计轮只完成设计与源码核对,不更改两仓运行代码、不读取 `.env*`、不调用上游模型。
现有模拟接口仍留在服务端源码但已退出控制台路由,后续清理应单独验证调用方,不作为基础服务使用。
2026-10-05 按 B1 代码同步技术设计第 4.2 节、逻辑规则、UI 设计、运行文档和实施进度,
将实现状态与部分验收结果分开记录。B2 至 B6 和 B1 剩余验收继续按上述顺序推进。
跨产品网络与 Office 契约继续引用 GoodBuddy 原文;其总体架构仍有“没有真实 Desktop 集成”的旧描述,
应在后续 GoodBuddy 文档同步时改为“已有元数据接线,完整共享网络待实现”。本轮不修改相邻仓库。