191 lines
17 KiB
Markdown
191 lines
17 KiB
Markdown
# 基于 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 文档同步时改为“已有元数据接线,完整共享网络待实现”。本轮不修改相邻仓库。
|