19 KiB
Copilot 配置中心实施计划
日期:2026-07-12 状态:已实施并验证(平台 Provider、账户模型/行为、Embedding 重建) 菜单名称:
Copilot 配置目标:为 GoChat 自托管部署提供可安全管理、可测试、可运行时生效的 Copilot/LLM 配置入口,并让页面选择的模型真正作用于 LLM 请求。
1. 已确认的产品决策
- 设置菜单统一命名为 Copilot 配置,不在用户界面继续使用“Captain AI 配置”作为供应商配置名称。
Captain仍保留为 AI 助手、知识库、场景、工具等业务模块的内部领域名称,不做全仓重命名。- LLM Provider、Base URL、API Key 属于平台级配置,对整套 GoChat 安装生效。
- 功能开关、功能模型、回复风格属于账户级配置,只影响当前 Account。
- Assistant 的提示词、Guardrails、Response Guidelines、知识文档和 Inbox 绑定继续在 Assistant 页面管理,不塞入 Copilot 配置页。
- API Key 以明文写入
installation_configs.value;接口只返回配置状态和掩码,日志禁止记录 Key 或 Authorization Header,页面不提供查看明文能力。 - Copilot 在系统中全局永久启用,不提供总开关,也不允许通过环境变量、配置文件或页面关闭。
- Copilot Provider 参数只从数据库读取,不定义任何 Copilot/Captain 环境变量。
- 除 Embedding 维度变化外,配置保存后应运行时生效,不要求重启服务。
2. 实施前缺口
实施前仓库已经有 Captain/Copilot 页面、API 和 LLM Provider,但还不是一个可用的配置闭环:
- 设置侧栏中的 Captain AI 入口被注释。
- 旧设置页仅允许 Cloud/Enterprise 安装类型访问,自托管 Community 配置为不可访问。
- 旧设置页只能保存
captain_models和captain_features,没有 Provider、Base URL、API Key。 - Provider 在
bootstrap.go启动时一次性创建,页面配置无法替换运行中的 Provider。 - 旧启动配置工厂接收
provider参数,但实际固定创建 OpenAI-compatible Eino ChatModel;该入口现已移除。 - 多个 Service 仍使用硬编码模型或 Provider 默认模型,账户保存的模型选择没有完整进入请求链路。
installation_configs已有平台级 CRUD,但目前是无类型字符串存储,不能直接安全暴露 LLM 密钥。
因此本任务不能只解开旧菜单;需要同时补齐配置存储、权限、运行时 Provider 和模型解析。
3. 页面入口与权限
3.1 菜单与路由
- 菜单位置:
设置 → Copilot 配置 - 页面路由:
/app/accounts/:accountId/settings/copilot - 前端路由名:
copilot_settings_index - 移除旧路由的 Cloud/Enterprise 安装类型限制。
- 不使用
captain_integrationFeature Flag 或其他开关控制配置页和 Copilot 总体可用性。 - Provider 尚未配置时页面展示“配置不完整”,而不是“未启用”。
3.2 权限分层
| 用户角色 | 平台 Provider 配置 | 账户功能配置 | 连接测试 | API Key 状态 |
|---|---|---|---|---|
| SuperAdmin | 可读写 | 可读写 | 可执行 | 仅显示是否已配置和掩码 |
| Account Administrator | 只读状态 | 可读写 | 不可执行平台密钥测试 | 仅显示“已配置/未配置” |
| Agent | 不可访问 | 不可访问 | 不可访问 | 不可访问 |
平台配置的写接口必须使用 SuperAdmin 中间件保护,不能仅依赖前端隐藏。
4. 页面信息架构
页面分为五个区块:
- 运行状态:当前 Provider、连接状态和配置完整性。Copilot 始终启用,不提供总开关。
- 对话模型:Provider、Base URL、API Key、默认 Chat Model。
- Embedding 模型:Embedding Provider、Key、Endpoint、Model、Dimensions。
- 生成与可靠性:Temperature、Max Tokens、Timeout、Retry。
- 当前账户功能:Editor、Copilot、Assistant、标签建议、知识库语义搜索的开关和模型。
“保存配置”和“测试连接”必须是两个独立动作:测试候选参数不落库;保存前后端均需再次校验。
5. 平台级参数规划
5.1 基础状态
| 字段 | 配置键 | 类型/默认值 | 页面规则 | 生效方式 |
|---|---|---|---|---|
| 配置状态 | configured |
derived boolean | 根据页面保存的 Provider、Model、Base URL 与 API Key 判断 | 只读 |
不定义 enabled 字段。Copilot 路由、菜单和服务始终注册;账户级功能开关只控制具体能力,不等价于关闭系统 Copilot。
5.2 对话模型
| 字段 | 配置键 | 类型/默认值 | 校验与交互 |
|---|---|---|---|
| Provider | chat.provider |
enum:openai / anthropic / openai_compatible;默认 openai |
必填;决定请求协议,不再把所有 Provider 当 OpenAI 协议处理 |
| Base URL | chat.base_url |
URL | openai/anthropic 自动提供官方默认值;openai_compatible 必填;禁止非 HTTP(S) URL |
| API Key | chat.api_key |
secret | 写入时允许空值表示“不修改”;清除必须单独确认;GET 永不返回明文 |
| 默认模型 | chat.model |
string,默认 gpt-4o-mini |
必填;支持手工输入,不能只依赖前端静态模型列表 |
Provider 预设只负责填充默认 Endpoint,不锁死模型:
| Provider | 默认 Base URL | 协议实现 |
|---|---|---|
| OpenAI | https://api.openai.com/v1 |
llm.OpenAIProvider,OpenAI Chat Completions API |
| Anthropic | https://api.anthropic.com |
llm.AnthropicProvider,Anthropic Messages API |
| OpenAI Compatible | 用户填写 | llm.OpenAIProvider + 自定义 Base URL;适用于 DeepSeek、通义千问、豆包及自建网关 |
EinoProvider 适配器仍保留给显式构造的 Eino ChatModel/Embedder 使用;数据库驱动的
ProviderManager 运行时配置链路不经过该适配器,而是按协议直接创建上述 Provider。
首期不单独增加 DeepSeek/Qwen/Doubao 枚举,避免把供应商宣传名称与真实协议实现绑死。
5.3 Embedding 模型
| 字段 | 配置键 | 类型/默认值 | 校验与交互 |
|---|---|---|---|
| Embedding 模式 | embedding.mode |
enum:reuse_chat_credentials / separate;默认 reuse_chat_credentials |
Chat Provider 为 Anthropic 时必须使用 separate |
| Provider | embedding.provider |
enum:openai / openai_compatible |
仅在 separate 模式展示 |
| Base URL | embedding.base_url |
URL | 自定义兼容 Provider 必填 |
| API Key | embedding.api_key |
secret | 与 Chat Key 分开存储;允许复用但不能在响应中回显 |
| 模型 | embedding.model |
string,默认 text-embedding-3-small |
必填;连接测试必须实际调用 embeddings API |
| 向量维度 | embedding.dimensions |
integer,默认 1536 |
范围 1-4096;修改时二次确认,并通过重建接口迁移现有文章向量 |
Embedding 配置不能隐式依赖 Anthropic,因为 Anthropic 当前没有 Embeddings API。
5.4 生成与可靠性
| 字段 | 配置键 | 类型/默认值 | 校验 | 生效方式 |
|---|---|---|---|---|
| Temperature | generation.temperature |
number,默认 0.7 |
0-2 | 热生效 |
| 最大输出 Tokens | generation.max_tokens |
integer,默认 1024 |
64-32768 | 热生效 |
| 请求超时 | request.timeout_seconds |
integer,默认 60 |
5-300 秒 | 热生效 |
| 最大重试次数 | request.max_retries |
integer,默认 3 |
0-5;只重试网络错误、429 和 5xx | 热生效 |
首期不开放以下高风险或不稳定参数:关闭 TLS 校验、任意代理地址、任意请求 Header、完整请求/响应日志。
6. 账户级参数规划
账户配置继续存入 Account 的 captain_models、captain_features 和 captain_preferences,但 UI 名称统一为 Copilot。
6.1 功能开关和模型
| 功能 | Feature Key | Model Key | 默认状态 | 说明 |
|---|---|---|---|---|
| 编辑器改写 | editor |
editor |
开启 | 润色、改写、语气调整 |
| Copilot 对话 | copilot |
copilot |
开启 | 客服侧边栏问答与回复建议 |
| AI Assistant | assistant |
assistant |
关闭 | Assistant Playground、自动辅助能力 |
| 标签建议 | label_suggestion |
label_suggestion |
关闭 | 仅建议;自动应用由账户策略决定 |
| 知识库语义搜索 | help_center_search |
使用平台 Embedding 模型 | 关闭 | 开启前必须通过 Embedding 测试并完成索引 |
首期暂不在页面开放 audio_transcription,直到后端具有独立的语音转写 Provider 和真实调用链。
模型下拉选项应由后端根据当前 Provider 返回,且始终提供“手工填写模型 ID”。不可再返回无法由当前 Provider 调用的静态模型列表。
6.2 回复行为
| 字段 | 现有字段 | 默认值 | 说明 |
|---|---|---|---|
| 回复语气 | tone |
professional |
professional / friendly / casual / formal |
| 回复语言 | language |
auto |
auto 表示跟随客户消息;同时允许明确语言代码 |
| 最大回复长度 | max_response_length |
500 |
范围 50-5000 字符 |
| 附加指令 | custom_prompt_suffix |
空 | 最大 1000 字;页面提示其作用范围 |
| 自动应用标签 | auto_label_enabled |
false | 与“标签建议”功能分开控制 |
| 自动创建跟进 | auto_follow_up_enabled |
false | 默认关闭 |
| 自动回复客户 | auto_reply_enabled |
false | 高风险开关,需二次确认并提示绑定 Assistant/Inbox |
Assistant 自身的 Temperature、Guardrails、Response Guidelines 优先级高于账户默认值。
7. 配置来源
- Copilot 始终启用,不存在部署级启用开关。
- Provider、Base URL、API Key 与默认模型仅允许通过页面和对应 API 配置。
- 不定义或读取任何 Captain/Copilot 环境变量,也不读取
config*.yaml中的 Provider、模型或启用配置。 - 数据库没有完整配置时,业务 API 返回“Provider 未配置”,不会使用空 Key 请求外部服务。
- 页面、菜单、接口响应文案使用“Copilot”;内部 Captain 领域名保持不变。
8. 存储与密钥呈现
8.1 存储方案
复用 installation_configs,但通过专用 CopilotConfigService 管理以下固定键,不允许前端直接操作通用键值 CRUD:
| InstallationConfig Name | 内容 |
|---|---|
COPILOT_PROVIDER_CONFIG |
不含密钥的 JSON 配置 |
COPILOT_CHAT_API_KEY |
Chat Provider API Key 明文 |
COPILOT_EMBEDDING_API_KEY |
独立 Embedding Provider API Key 明文;复用 Chat 凭据时为空 |
8.2 API Key 处理要求
- Copilot API Key 直接以明文写入
installation_configs.value,不做 AES-256-GCM 或其他应用层加密。 - 数据库、备份和运维访问权限承担密钥保护责任;密钥不得进入普通配置导出、日志或错误响应。
- API 响应只返回:
configured: true/false、masked_value: "sk-****abcd"。 - 更新请求中省略
api_key表示保留原值;clear_api_key: true才允许清除。 - 错误日志、审计日志、连接测试响应均不得包含 Key、Authorization Header 或完整请求体。
9. 后端 API 规划
9.1 平台级接口(SuperAdmin)
| 方法 | 路径 | 用途 |
|---|---|---|
| GET | /platform/api/v1/copilot/config |
获取平台配置、掩码和状态 |
| PUT | /platform/api/v1/copilot/config |
校验并保存平台配置 |
| POST | /platform/api/v1/copilot/config/test |
用候选配置测试 Chat 和 Embedding,不保存 |
| GET | /platform/api/v1/copilot/embeddings/reindex |
获取文章 Embedding 重建进度 |
| POST | /platform/api/v1/copilot/embeddings/reindex |
后台启动文章 Embedding 重建 |
连接测试返回:
{
"chat": { "ok": true, "latency_ms": 320, "model": "gpt-4o-mini" },
"embedding": { "ok": true, "latency_ms": 180, "model": "text-embedding-3-small", "dimensions": 1536 }
}
失败响应仅返回归一化错误:认证失败、Endpoint 不可达、模型不存在、限流、超时、响应格式不兼容、Embedding 维度不匹配。
9.2 账户级接口(Administrator/SuperAdmin)
| 方法 | 路径 | 用途 |
|---|---|---|
| GET | /api/v1/accounts/:account_id/copilot/config |
返回平台只读状态 + 当前账户配置 |
| PUT | /api/v1/accounts/:account_id/copilot/config |
更新账户功能、模型和回复行为 |
旧 /captain/preferences 接口保留兼容,但新页面只调用 /copilot/config 聚合接口。
10. 运行时 Provider 设计
使用 llm.ProviderManager 替代 bootstrap 中固定注入单个 llm.Provider:
CopilotConfigService
→ 解析有效平台配置
→ 构造候选 Chat Provider + Embedding Provider
→ 执行轻量健康校验
→ 原子替换 Provider Snapshot
→ 新请求使用新 Snapshot,进行中的请求继续完成
核心约束:
- 保存失败或 Provider 初始化失败时,不替换当前可用配置。
- Service 依赖
ProviderResolver,每次任务开始时获取不可变 Snapshot。 - Snapshot 包含 Chat Provider、Embedding Provider、默认模型和生成参数。
- 账户模型解析顺序:
账户 feature model → 平台 chat.model → provider default。 - 所有硬编码
gpt-4、静态模型和直接读取启动配置的调用都必须迁移到 resolver。 - Provider 配置不完整时返回明确业务错误,不向外部服务发请求。
Embedding 维度由迁移 000056_make_article_embedding_dimension_dynamic 改为动态 pgvector
列;保存维度变更后由 SuperAdmin 通过重建接口重新生成全部文章向量,页面展示进度和失败状态。
11. 前端交互要求
- 菜单展示名称固定为“Copilot 配置”。
- 页面顶部显示状态徽标:配置完整、配置不完整、连接正常、连接异常。
- API Key 输入框默认空白并显示“已配置”;不把掩码当作真实值回传。
- Provider 改变时自动填充推荐 Base URL,但不覆盖用户已经编辑的值。
- Anthropic + 复用 Chat Embedding 凭证属于无效组合,前端即时提示,后端再次拒绝。
- “测试连接”分别展示 Chat 与 Embedding 结果。
- 保存成功后展示实际生效的 Provider、模型和时间。
- 修改 Embedding Dimensions 时展示阻断式警告,不允许无确认保存。
- Account Administrator 看到平台配置状态但不能看到 Endpoint 之外的敏感信息,也不能编辑平台配置。
12. 实施阶段
阶段 1:配置闭环(P0)
- 新增 Copilot typed config DTO、Service 和平台/账户 API。
- 接入 InstallationConfig 明文密钥存储、API 掩码和不回显规则。
- 实现 Provider 工厂的 OpenAI、Anthropic、OpenAI-compatible 分支。
- 实现
CopilotProviderManager和热切换。 - 新建“Copilot 配置”页面和菜单,移除安装类型限制。
- 接通 Chat/Embedding 连接测试。
阶段 2:运行链路统一(P0)
- 清理 Service 中硬编码模型。
- 将账户 feature model 接入所有对应 LLM 请求。
- 统一 Temperature、Max Tokens、Timeout、Retry 的解析。
- Provider 未配置时返回统一错误码和前端提示。
阶段 3:账户策略与质量(P1)
- 聚合现有 CaptainPreference 回复行为配置。
- 增加配置变更审计事件,但不记录密钥。
- 增加 Provider 健康状态和最近测试时间。
- 提供知识库 Embedding 重建入口和进度状态。
阶段 4:后续能力(P2)
- Provider 动态模型列表发现与缓存。
- 独立语音转写 Provider。
- Token 用量、成本和账户配额。
- Langfuse/OpenTelemetry AI 调用观测。
- 多 Provider fallback;首期不自动跨供应商降级,避免数据和成本不可控。
13. 验证结果
后端自动化
GOCHAT_TEST_DB=sqlite go test ./internal/... ./pkg/... ./cmd/...通过。go test ./...通过。- 覆盖明文存储、掩码/不回显、保留/替换/清除、候选测试不落库、Provider 热切换、 OpenAI/OpenAI-compatible/Anthropic、超时/重试、统一安全错误、动态 Embedding 维度和重建状态。
- Service →
ProviderManager→ Fake HTTP Provider 集成测试证明 editor、copilot、assistant、 label suggestion 分别使用账户配置的功能模型,未配置时由 Manager 回退平台默认模型。 - Assistant 显式配置的 Temperature(包括
0)优先于平台默认值;未显式配置时继续使用平台值。 - OpenAI-compatible 的错误响应与 malformed SSE chunk 不进入日志或健康检查响应;对外只返回稳定错误类别。
- SuperAdmin 平台权限、Administrator 账户权限和 Agent 禁止访问均有 Handler/Middleware 回归测试。
- 配置变更写入
audits,只记录 Provider、模型、维度、配置状态和是否变更 Key,不记录 Key 或掩码。
前端自动化
- Vitest 覆盖菜单/路由、Pinia 平台与账户请求、SuperAdmin 识别、Provider 条件字段、 API Key 不回填/清除确认、清除 Key 时允许保存但禁止连接测试、Anthropic 非法组合、 维度确认、回复行为和自动回复确认。
pnpm build通过。
真实运行验证
- Playwright 在
http://127.0.0.1:3036/app/accounts/1/settings/copilot验证页面名称、路由、 SuperAdmin 可编辑态、无框架错误覆盖,以及 1440×1000 和 390×844 布局。 - 本地 Fake LLM Server 验证候选连接测试同时调用 Chat 与 Embedding;请求使用页面填写的
gpt-4o-mini、text-embedding-3-small、Bearer Key 和dimensions: 1536。 - 候选测试前数据库无 Copilot Key;保存后
COPILOT_CHAT_API_KEY明文为测试 Key;刷新页面后 输入框为空,仅显示掩码,再次测试使用已保存 Key 成功。 - PostgreSQL 审计记录包含 Account、SuperAdmin、Provider/模型/维度和 Key 变更布尔值, 不包含 API Key 或掩码。
14. 验收标准
- ✅ 自托管 Community 安装可以进入“设置 → Copilot 配置”。
- ✅ 只有 SuperAdmin 可以修改平台 Provider 和 API Key。
- ✅ API Key 明文落库,所有读取接口只返回掩码/状态且日志不记录密钥。
- ✅ 页面可以独立测试 Chat 与 Embedding 连接。
- ✅ 保存有效配置后不重启即可让新 LLM 请求使用新 Provider。
- ✅ editor/copilot/assistant/label suggestion 使用账户模型,未指定时回退平台默认模型。
- ✅ Anthropic Chat 可以搭配独立 OpenAI-compatible Embedding 配置。
- ✅ Provider 不可用或未配置时返回稳定错误码,不使用空 Key 请求外部服务。
- ✅ 候选测试和失败配置不会替换当前正在工作的 Provider。
- ✅ 相关后端测试、前端测试/构建和浏览器端到端验证通过。
15. 本次明确不做
- 不将所有
Captain代码、表名和 API 全量改名为Copilot。 - 不允许普通 Agent 或任意 Account Administrator 修改平台 API Key。
- 不提供 Copilot 总开关、环境变量配置或 YAML Provider 配置。
- 不在首期支持任意 Header、关闭 TLS 校验或输出完整 LLM 请求日志。
- 不展示或提供复制已保存 API Key 明文的能力。
- 不在首期实现自动跨 Provider fallback。
- 不把 Assistant 的知识库、工具、Guardrails 和 Inbox 绑定搬入 Copilot 配置页。