Restore Ask workspace reads and output paging without granting write access, and let programming Subagents reuse their parent's browser page. Allocate browser resources only when used, keep Agent pages aligned with workbar tabs, recover released bindings, and remove unused automatic screenshot work. Preserve inherited Runtime selections during remote usage persistence and manual compression. Keep viable channel model fallbacks, display the actual scheduled-task mode and Harness model source, and avoid rediscovery delays when calling healthy MCP tools. Fix directory/history refresh, case-only renames, rename-aware commit diffs, and FastGPT probe success reporting. Add regression coverage and align feature documentation. The Agent-side connection timeout fix requires deploying an updated Agent; existing Ask read-only and Execute authorization boundaries remain unchanged. Final validation: 3839 tests passed, 66 skipped; typecheck, lint, development build, and diff checks passed. Isolated Electron UI/MCP workflows passed with a loopback model fixture. Current-source Linux x64 Host checks passed with three successful real model requests. Chromium loadURL rejection was not reproduced in the UI; released-binding recovery has automated coverage. Release note: 修复 Ask 读取项目文件、浏览器页面显示与恢复、文件管理及模型配置跟随中的不一致,并减少无用截图和 MCP 等待。定时任务显示实际工作模式,远程会话可正常保存继承 Runtime 的用量;远端连接超时修复需更新 Agent 后生效。
33 KiB
外部知识库技术设计
文档信息
| 项目 | 内容 |
|---|---|
| 状态 | 设计稿 |
| 版本 | 0.1 |
| 日期 | 2026-09-03 |
| 产品需求 | 外部知识库接入 PRD |
| 逻辑设计 | 外部知识库逻辑设计 |
| UI 设计 | 外部知识库 UI 设计 |
1. 设计约束
- 外部知识库扩展现有知识库领域,不建立独立检索工具、聊天范围或 Runtime 权限模型。
- 外部绑定使用远端检索,不落地远端文档、分块、向量和图谱。
- 所有网络、凭据、Provider 响应校验和结果标准化都在 Main 完成。
- Renderer 只能通过受限 IPC 管理实例、读取目录、保存绑定和发起测试。
- Dify、FastGPT、RAGFlow 使用独立 Adapter 和判别配置,不通过任意 JSON 请求模板实现。
- 首次实现只调用无内容修改语义的列表、详情和检索接口。
- Provider API 变化通过真实 fixture、Adapter 版本和能力快照处理,不通过猜测字段兼容。
2. 现有代码边界
当前实现中的主要扩展点:
| 边界 | 现有位置 | 需要的变化 |
|---|---|---|
| 共享知识契约 | src/shared/knowledge-contracts.ts、src/shared/contracts.ts |
增加实例、绑定、Provider 配置和外部引用判别联合 |
| IPC 名称 | src/shared/ipc-channels.ts |
增加实例和目录操作通道 |
| Preload | src/preload/index.ts |
暴露受限、类型化的外部知识库 API |
| Main IPC | src/main/ipc.ts |
校验输入、调用服务、投影脱敏结果 |
| 知识服务 | src/main/knowledge/knowledge-service.ts |
按知识库来源分派本地或外部检索 |
| 数据库 | src/main/knowledge/knowledge-database.ts |
增加实例、绑定和迁移 |
| 内部类型 | src/main/knowledge/types.ts |
增加 Provider、实例、绑定和标准化结果类型 |
| 知识页面 | src/renderer/src/KnowledgeWorkspace.tsx |
实例管理、创建向导类型和外部详情 |
| 检索测试 | src/renderer/src/KnowledgeRetrievalWorkbench.tsx |
支持本地与外部诊断判别联合 |
| 聊天预检索 | src/main/ipc.ts |
统一调用 Provider-aware 检索编排 |
| Agent 知识工具 | src/main/agent/knowledge-mcp-gateway.ts |
与预检索复用同一编排和引用标准化 |
外部 Provider 不是 KnowledgeSourceType。现有 file | directory | url 表示会进入本地
文档、分块和索引的资料来源;把远端绑定塞入该枚举会错误触发同步、分块和来源打开逻辑。
3. 模块设计
建议增加:
src/main/knowledge/external/
├─ external-knowledge-service.ts
├─ external-knowledge-store.ts
├─ external-knowledge-errors.ts
├─ external-knowledge-http.ts
├─ external-knowledge-registry.ts
├─ external-knowledge-normalizer.ts
└─ providers/
├─ dify-adapter.ts
├─ fastgpt-adapter.ts
└─ ragflow-adapter.ts
职责:
ExternalKnowledgeService:实例、目录、绑定、测试和检索编排。ExternalKnowledgeStore:实例和绑定持久化,凭据加解密。ExternalKnowledgeHttp:超时、取消、大小限制、地址和响应读取。ExternalKnowledgeRegistry:按 Provider 返回内置 Adapter,不接受运行时插件注册。ExternalKnowledgeNormalizer:统一结果边界、截断和引用。- Adapter:构造固定端点与请求,解析 Provider 响应,声明静态配置和能力条件。
KnowledgeService 继续作为聊天、检索测试和 MCP 网关的统一入口。它根据
KnowledgeBase.kind 调用现有本地检索或 ExternalKnowledgeService.retrieve。
4. Provider Adapter
type ExternalKnowledgeProvider = 'dify' | 'fastgpt' | 'ragflow'
interface ExternalKnowledgeAdapter<PersistedConfig, CapabilitySnapshot> {
readonly provider: ExternalKnowledgeProvider
readonly configVersion: number
normalizeBaseUrl(input: string): URL
testConnection(context: AdapterContext): Promise<ConnectionTestResult>
listKnowledgeBases(
context: AdapterContext,
input: CatalogPageInput
): Promise<CatalogPage>
getKnowledgeBase(
context: AdapterContext,
remoteKnowledgeBaseId: string
): Promise<RemoteKnowledgeBaseSummary>
probeRetrieval(
context: AdapterContext,
input: ProviderRetrieveInput<PersistedConfig>
): Promise<ProviderRetrieveResult>
retrieve(
context: AdapterContext,
input: ProviderRetrieveInput<PersistedConfig>
): Promise<ProviderRetrieveResult>
parseCapabilities(input: unknown): CapabilitySnapshot
validateConfig(
input: unknown,
capabilities: CapabilitySnapshot
): PersistedConfig
}
probeRetrieval 可以复用 retrieve,但必须使用用户在创建向导中明确输入的测试查询。
不得生成会泄露组织信息的默认问题,不得调用 Provider 的 App 或模型问答接口,也不得
修改远端知识内容。Provider 自身记录 API 审计或计算检索用量不属于内容修改,必须由界面
提前说明。
Adapter 返回数据对象,不返回 React 组件、HTML 或远端 Schema。Renderer 中的配置定义 由共享的 Provider 判别联合和本地字段描述生成。
5. 共享契约
5.1 实例
type CredentialMutation =
| { action: 'keep' }
| { action: 'replace'; value: string }
| { action: 'clear' }
interface ExternalKnowledgeInstanceSummary {
id: string
name: string
provider: 'dify' | 'fastgpt' | 'ragflow'
baseUrl: string
enabled: boolean
credentialStatus: 'configured' | 'missing' | 'unavailable'
probeStatus:
| 'untested'
| 'catalog-ready'
| 'healthy'
| 'list-restricted'
| 'auth-failed'
| 'unreachable'
| 'incompatible'
| 'failed'
detectedVersion?: string
bindingCount: number
lastTestedAt?: string
lastErrorCode?: string
}
Renderer 输入使用 CredentialMutation,因此新密钥会在输入控件和该次 IPC 中短暂存在。
Main 返回值永远没有 credential、apiKey、authorization 或加密 envelope。
5.2 绑定
interface ExternalKnowledgeBinding {
knowledgeBaseId: string
instanceId: string
remoteKnowledgeBaseId: string
remoteName: string
remoteDescription?: string
commonConfig: ExternalKnowledgeCommonConfig
providerConfig: DifyConfig | FastGptConfig | RagflowConfig
providerConfigVersion: number
adapterVersion: number
lastVerifiedAt?: string
}
providerConfig 必须带 provider 判别字段,且与实例 Provider 一致。remoteName 是用于
显示和变化检测的快照,不是授权标识。
5.3 标准化结果
现有 KnowledgeRetrievalResult 假定结果映射到本地 documentId/sourceId/chunkId。需要改为
引用定位的判别联合,同时保持现有调用方可按统一字段读取片段:
type KnowledgeReferenceLocator =
| {
kind: 'local'
documentId: string
sourceId: string
chunkId: string
parentChunkId?: string
}
| {
kind: 'external'
provider: ExternalKnowledgeProvider
instanceId: string
remoteKnowledgeBaseId: string
remoteDocumentId?: string
remoteChunkId?: string
providerScore?: number
location?: string
sourceUrl?: string
metadata?: Record<string, string | number | boolean | null>
}
interface UnifiedKnowledgeRetrievalResult {
knowledgeBaseId: string
documentTitle: string
sourceDisplayName: string
snippet: string
relevance?: number
rank: number
locator: KnowledgeReferenceLocator
}
remoteDocumentId 和 remoteChunkId 只保存 Provider 实际返回的标识,缺失时不得从标题、
序号或内容哈希推导。providerScore 保留原始值,但不改名为统一 relevance。只有经过
单独定义和验证的归一化算法才能填写跨 Provider relevance。初始跨库拼装按结果配额和
稳定 Provider 顺序工作,不按原始分数混排。
所有共享 Schema 使用严格对象并限制:
- 查询不超过 4,000 字符;同时遵守 Provider 更小限制,例如 Dify 当前公开接口的 250 字符限制,超出时在发送前明确失败,不静默截断查询。
- 单次目录页不超过 100 项,总目录最多 500 项。
- 标准化结果最多 20 条,单片段最多 8,000 字符。
- 标题、ID、定位、URL 和元数据键值均设独立上限。
- Provider 原始响应总字节数设固定上限,超限立即取消读取。
6. 持久化
6.1 数据库变化
保留现有 knowledge_bases 表,增加:
ALTER TABLE knowledge_bases
ADD COLUMN kind TEXT NOT NULL DEFAULT 'local'
CHECK (kind IN ('local', 'external'));
增加实例表:
CREATE TABLE external_knowledge_instances (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
provider TEXT NOT NULL CHECK (provider IN ('dify', 'fastgpt', 'ragflow')),
base_url TEXT NOT NULL,
enabled INTEGER NOT NULL CHECK (enabled IN (0, 1)),
credential_envelope_json TEXT,
probe_status TEXT NOT NULL,
detected_version TEXT,
capabilities_json TEXT NOT NULL,
transport_security TEXT NOT NULL,
transport_risk_accepted_url TEXT,
transport_risk_accepted_at TEXT,
last_tested_at TEXT,
last_error_code TEXT,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
);
增加绑定表:
CREATE TABLE external_knowledge_bindings (
knowledge_base_id TEXT PRIMARY KEY
REFERENCES knowledge_bases(id) ON DELETE CASCADE,
instance_id TEXT NOT NULL
REFERENCES external_knowledge_instances(id) ON DELETE RESTRICT,
remote_knowledge_base_id TEXT NOT NULL,
remote_name TEXT NOT NULL,
remote_description TEXT,
common_config_json TEXT NOT NULL,
provider_config_json TEXT NOT NULL,
provider_config_version INTEGER NOT NULL,
adapter_version INTEGER NOT NULL,
binding_status TEXT NOT NULL,
last_verified_at TEXT,
last_success_at TEXT,
last_error_code TEXT,
UNIQUE(instance_id, remote_knowledge_base_id)
);
已有知识库迁移为 kind = 'local'。外部知识库仍保留现有名称、描述和创建时间,但本地
storageMode、图谱、分块和本地检索设置不进入外部请求;后续可以在数据库重构时再移除
这些历史必填默认值,本功能不为此扩大迁移范围。
6.2 凭据
复用 SettingsCredentialCipher 和 Electron safeStorage:
replace:Main 加密新值后在一个事务中替换 envelope。keep:不读取、不重写现有 envelope。clear:确认后删除 envelope,并把实例凭据状态设为缺失。- 安全存储不可用时拒绝新增或替换,不降级为明文。
- 解密只发生在发起请求前;请求结束后不缓存明文。
实例导出、诊断和数据库普通 JSON 视图均排除 credential_envelope_json。
7. IPC 设计
建议增加独立通道:
knowledge:external-instances:list
knowledge:external-instances:test
knowledge:external-instances:save
knowledge:external-instances:set-enabled
knowledge:external-instances:delete
knowledge:external-catalog:list
knowledge:external-catalog:get
knowledge:external-bindings:create
knowledge:external-bindings:update
knowledge:external-bindings:remove
knowledge:external-retrieval:test
所有 Handler 必须:
assertTrustedSender。- 用共享 Zod Schema 解析严格输入。
- 根据实例 ID 在 Main 读取地址和凭据,不接受 Renderer 在检索请求中重复传入。
- 使用稳定错误码返回脱敏错误。
- 对网络操作支持 AbortSignal、总超时和响应大小限制。
目录和测试请求返回 requestId。Renderer 仍需校验当前类型、实例和目标与响应关联,避免
旧响应覆盖新表单。
8. HTTP 边界
8.1 服务地址
- 只接受
http:和https:。 - 拒绝用户名、密码、查询和片段。
- Adapter 负责规范化 Provider 所需 API 根路径,避免用户填写完整操作端点。
- 请求只能拼接 Adapter 内置相对路径,远端目录项或错误不能改变目标 URL。
- 重定向默认拒绝;若某 Provider 的受支持部署确需重定向,只允许同源且不得跨跳转发送 Authorization。
- 当前全局“内网兼容模式”决定是否允许 HTTP 和非标准 HTTPS 证书;操作开始后冻结该值。
- HTTP 或实际使用证书例外时,Main 返回
transportSecurity风险状态。用户必须针对规范化 后的当前地址明确确认,才能保存实例或发送 API Key;地址变化立即使旧确认失效。 - 不进行公共云回退,不把自部署地址替换成 Provider 官方地址。
用户明确配置内网地址属于产品用途,因此不能采用禁止私网地址的通用 SSRF 规则。安全边界 依靠显式实例配置、Main-only 请求、固定端点、无任意方法和无远端 URL 跟随。
8.2 请求限制
- 默认超时 15 秒,用户可在 1 至 60 秒内调整。
- 目录、详情和检索分别设置响应字节上限。
- JSON 解析后仍执行深度、数组数量、字符串长度和未知字段策略。
- 默认不自动重试。用户重试或上层下一次检索会产生新请求。
- 取消、应用关闭和实例删除立即终止相关请求。
- 日志只记录 Provider、实例 ID、操作、状态码、稳定错误码、耗时和字节数。
9. Provider 映射
本节记录 2026-09-03 核对的初始公开接口。实施时应把每个受支持版本的真实响应保存为 去敏 fixture,并以 fixture 和真实实例测试作为发布依据。
9.0 真实实例验证基线
2026-09-09 使用本机未入库的测试地址和 API Key 完成第一轮只读验证。验证只记录状态、 字段名、数量和长度,不记录 API Key、知识库名称或片段正文。
| Provider | 实例证据 | 目录实测 | 检索实测 | 当前结论 |
|---|---|---|---|---|
Dify 0.x |
响应头 x-version: 0.15.8 |
列表返回 200 和 3 项;详情 GET 返回 405 | 默认配置和显式当前配置均返回 200,结果为空 | 从目录项读取配置,手工 ID 通过检索验证;非空结果仍未验证 |
Dify 1.x |
响应头 x-version: 1.17.0 |
列表返回 200 和 1 项;详情 GET 返回 200 | 默认配置和显式当前配置均返回相同的 3 条非空结果 | 详情和 records[].segment/document 已验证;新增摘要索引、元数据、多模态和 Pipeline 能力字段 |
| FastGPT | 响应未提供版本,只能确认当前托管实例 | 基址包含 /api;列表和详情均返回 200,列表 data 直接为数组,本次 1 个 Dataset |
embedding 8 条、fullTextRecall 2 条、mixedRecall 7 条、mixedRecall + Rerank 9 条 | 三种检索模式和 Rerank 均已实测;当前结果包含 q,未包含 a |
| RAGFlow | 响应未提供产品版本,Server 为 nginx,不能据此推断版本 | GET /api/v1/datasets 返回 200,共 28 项;17 项配置 GraphRAG,15 项有完成证据 |
选定已完成图谱的库,基础检索 0 条,use_kg=true 返回 1 条,Knowledge Compilation 0 条 |
图谱检索已产生区别于基础检索的结果;当前没有库具备 Knowledge Compilation 配置证据 |
当前 Node 测试进程设置了 NODE_TLS_REJECT_UNAUTHORIZED=0,因此两个 HTTPS 实例的请求
使用了放宽的证书校验。这只能证明接口在当前测试环境可用,不能证明严格 TLS 校验通过。
产品实现不得读取该进程级设置作为隐式默认;实例测试和保存必须按 8.1 节处理传输风险。
9.1 Dify
| 操作 | 接口 |
|---|---|
| 列表 | GET /v1/datasets |
| 详情 | GET /v1/datasets/{dataset_id},0.15.8 不支持、1.17.0 支持 |
| 检索 | POST /v1/datasets/{dataset_id}/retrieve |
| 认证 | Authorization: Bearer <knowledge-api-key> |
Adapter 只接受 Knowledge Service API Key,不调用应用 /info、Chat 或 Workflow。默认不
发送 retrieval_model,沿用远端知识库配置。用户选择覆盖时,Adapter 必须一次收集并验证
当前接口要求的搜索方式、Top K、阈值、reranking_mode,以及相应的 Rerank Provider/模型
或关键词/向量权重与 Embedding Provider/模型;缺少任何必填标识时不构造请求。响应从
records[].segment、score、文档名称和元数据提取标准化引用。
Dify 当前文档限制查询不超过 250 字符。GoodBuddy 不静默截断;超出时检索测试和聊天 诊断返回 Provider 限制,并允许后续单独设计查询压缩策略。
两个实测版本共同返回 retrieval_model_dict,键包括搜索方式、Top K、阈值、Rerank 和
权重。显式原样复用该配置均返回 200,证明覆盖 envelope 可用,但 UI 编辑后的每种组合仍
需单独契约测试。
版本差异:
| 能力 | 0.15.8 |
1.17.0 |
Adapter 和 UI 规则 |
|---|---|---|---|
| Dataset 详情 | GET 返回 405 | GET 返回 200 | 能力探测后调用;旧版从目录项读取配置,不能把 405 视为实例故障 |
| 非空检索结构 | 本次未命中 | 默认和显式配置均返回 3 条 | 1.17 已验证 records[].segment.content、segment.document.id/name、位置和分数映射 |
| 元数据 | 无 doc_metadata |
字段存在,当前库定义数为 0 | 有实际字段定义时才显示受控元数据过滤器;不提供自由 JSON |
| 多模态与附件 | 未返回能力字段 | is_multimodal 和 files 字段可用,当前库非多模态且结果无附件 |
只显示远端状态;仅在结果实际带 files 时显示附件引用 |
| 父子分块 | 未验证 | 返回 child_chunks 数组,本次为空 |
仅在实际非空时显示子块证据,不补造父子关系 |
| 摘要索引 | 未返回能力字段 | 当前库配置了 summary_index_setting,本次结果 summary 为空 |
概览显示只读状态;仅在结果实际返回摘要时展示 |
| Knowledge Pipeline | 未返回能力字段 | pipeline_id/runtime_mode 存在,当前库未配置 Pipeline |
只读显示,不提供运行或编辑 Pipeline 的操作 |
Dify 1.x 官方 RetrievalModel 还声明 metadata_filtering_conditions,并支持
keyword_search/semantic_search/full_text_search/hybrid_search。当前实测库没有 Metadata
字段,未执行空条件或猜测字段探测;该配置保持禁用,直到所选库详情返回可用字段定义。
9.2 FastGPT
| 操作 | 接口 |
|---|---|
| 列表 | POST /api/core/dataset/list |
| 详情 | GET /api/core/dataset/detail?id=... |
| 检索 | POST /api/core/dataset/searchTest |
| 认证 | Authorization: Bearer <api-key> |
列表响应同时包含文件夹和知识库,只有 type = dataset 可以绑定。当前实测列表的
data 直接为数组,不是 data.list;Adapter 可以仅对已经实测的这两种明确 envelope
做版本化解析,不递归猜测任意嵌套。检索映射 datasetId、
text、Token limit、similarity、searchMode 和 usingReRank。初始版本不发送查询优化
字段,避免调用 FastGPT 配置的 LLM。
当前实测响应的 data 包含 list/duration/limit/searchMode/usingReRank/similarity;结果项
包含 q/id/datasetId/collectionId/sourceName/sourceId/chunkIndex/score,未返回 a。
Adapter 以 q 为必需片段,a 仅在远端实际返回时追加,不能要求 a 存在。
当前实例的 embedding、fullTextRecall、mixedRecall 和 mixedRecall + Rerank 均返回 200 和
非空结果,因此这四种界面组合可以启用。查询扩展会调用模型,仍不在初始界面和探测脚本中
启用。
FastGPT 4.15.0 起部署实例的 /apidoc/devapi 是接口事实来源,手工文档可能落后。支持矩阵
必须按真实版本测试;不能因为健康页可访问就假定列表和检索 Schema 相同。searchTest
可能记录 SEARCH_TEST 等远端审计并更新 API Key 用量;Embedding 和 Rerank 也可能产生
费用。GoodBuddy 将这些行为作为检索成本显示,不宣称该接口没有副作用。
9.3 RAGFlow
| 操作 | 接口 |
|---|---|
| 列表/详情 | GET /api/v1/datasets |
| 检索 | POST /api/v1/retrieval |
| 认证 | Authorization: Bearer <api-key> |
检索映射 question、dataset_ids、page_size、similarity_threshold、
vector_similarity_weight、knn_top_k、重排、use_kg 和
include_knowledge_compilation。不发送已弃用的 top_k。响应从 data.chunks 和
data.doc_aggs 提取片段、文档、位置和原始相似度。当前实测非空 chunk 使用
document_keyword 表示文档名,并包含 id/document_id/content/positions/similarity/
term_similarity/vector_similarity;初始 Adapter 应按该字段映射,不假定存在
document_name。
图谱规则:
parser_config.graphrag.use_graphrag = true只表示库配置了 GraphRAG;单独出现该配置不 表示图谱已经构建完成。graphrag_task_finish_at为有效非零时间才作为图谱完成证据,不写回。use_kg是检索时开关,只在已有图谱和受支持版本均确认后发送。- Knowledge Compilation 与旧 GraphRAG 分别建模。
include_knowledge_compilation使用本地保存的显式布尔值,初始默认 false;即使服务端 默认 true,也不依赖字段省略获得隐式行为。compilation_template_group_id或后续版本的等价受控字段作为 Knowledge Compilation 已 配置证据;仅仅请求返回 200 不能启用界面开关。- Provider 没有返回图节点或路径证据时,GoodBuddy 不生成图谱引用。
当前实例 28 个库中 17 个配置 GraphRAG、15 个存在完成证据。对一个已完成库使用同一查询,
基础检索返回 0 条,use_kg=true 返回 1 条且原始相似度为 1,说明图谱开关对实际结果有
影响。当前 28 个库均没有 Knowledge Compilation 配置证据;该请求虽返回 200 和零结果,
界面仍必须禁用开关并显示“当前知识库未配置 Knowledge Compilation”。
10. 检索编排
retrieveMany(knowledgeBaseIds, query, requestContext)
├─ load and authorize GoodBuddy knowledge bases
├─ partition local and external bindings
├─ local: existing retrieval path
├─ external: bounded concurrent adapter requests
├─ validate and normalize each response
├─ allocate deterministic context budget
└─ return evidence plus per-library diagnostics
预检索和 knowledge_search 工具必须调用同一个 retrieveMany。如果只修改聊天预检索而
未修改 KnowledgeMcpGateway,auto 和 always 会产生不同能力,这是阻断发布的问题。
10.1 上下文预算
- 每个知识库先保留不超过其
resultLimit的结果。 - 先给每个成功知识库一个最小有界配额,再按稳定顺序分配剩余字符。
- 不用不同 Provider 原始分数决定跨库优先级。
- 片段截断在 Main 完成并在引用中标记。
- 相同实例的多个绑定仍按绑定分别请求,除非 Provider 明确支持且 Adapter 实现等价的多 Dataset 请求;合并不得改变每个绑定的配置和诊断。
10.2 失败结果
返回结构包含每个知识库的:
interface KnowledgeRetrievalOutcome {
knowledgeBaseId: string
status: 'success' | 'empty' | 'failed' | 'cancelled'
durationMs: number
resultCount: number
errorCode?: ExternalKnowledgeErrorCode
truncated: boolean
}
至少一个 success 或 empty 表示检索编排完成;全部 failed/cancelled 时上层显示整体失败。
11. 引用与来源打开
外部结果不能进入依赖本地数据库的 referenceContext 和 openSource 路径。
- 引用详情直接使用请求时保存的标准化片段和定位。
- Main 可以按远端片段 ID 提供一次只读重新读取,但初始版本不要求。
- Provider 返回 URL 只作为不可信元数据保存。没有独立 URL 规则和真实实例验证前, Renderer 不显示打开链接操作。
- 活动和会话持久化保存标准化引用,其中包含实际用于回答的有界远端片段;这属于引用 留存,不是批量同步或本地索引。删除会话或对应活动时按现有生命周期删除该副本。
- 实例删除后,历史引用仍显示 Provider、知识库、文档名称和已保存片段,但标记连接已移除。
12. 支持矩阵与版本变化
每个 Adapter 维护明确的最低版本、已验证版本和 adapterVersion。连接测试优先读取可靠的
版本接口或响应头;无法识别版本时,只允许经真实请求验证过的基础列表和检索字段,高级字段
保持不可用。
Adapter 可以保存少量受控事实,例如“目录接口可用”“详情表明已构建图谱”,但不尝试从 远端拼出完整 capability manifest,也不计算 capability fingerprint。
adapterVersion相同且实例仍在支持矩阵内:解析已保存配置并执行。- Adapter 升级:使用明确的配置迁移或把绑定标记为
config-invalid,不猜测字段迁移。 - 实例版本离开支持矩阵:停止发送高级字段,并要求重新测试和确认。
- 新能力出现:保持默认关闭,用户主动配置后才发送。
- RAGFlow
use_kg还要求当前远端知识库存在已构建图谱的证据。
13. 安全与隐私
- API Key 在用户输入和保存 IPC 中短暂存在,随后使用系统安全存储加密;保存后不返回 Renderer,也不进入 Runtime、日志和普通元数据。
- 请求不附带完整会话、附件、本地知识库证据、系统提示、模型配置或其他 Provider 结果。
- Provider 结果使用与本地知识证据相同的不可信上下文标记。
- Adapter 拒绝响应中的原型污染键、过深对象、超长数组和非有限数值。
- 远端错误正文只用于 Main 内映射,日志与 UI 使用稳定错误码和短消息。
- 外部知识库不能扩大当前对话显式选择的 GoodBuddy 知识库 ID。
- Ask 与 Execute 对知识检索均为只读,Execute 不获得额外 Provider 权限。
- Provider 配置中的模型 ID、背景文本和 Metadata 条件按独立长度限制验证,不能携带凭据。
- HTTP 或证书例外需要按当前规范化地址确认凭据传输风险,地址变化后重新确认。
14. 测试
14.1 契约测试
- 每个 Provider 的列表、详情、检索成功和错误 fixture。
- 未知字段、缺字段、错误类型、超长内容、非有限分数和超大响应。
- Dify 查询长度、FastGPT 文件夹过滤、RAGFlow 图谱和 Knowledge Compilation 字段。
- Provider 配置判别联合拒绝类型错配和未知字段。
14.2 安全测试
- 保存完成后的 Renderer 快照、IPC 返回值、日志、错误、活动和导出中不存在明文 API Key;
replace输入只在当前表单和单次 IPC 请求中短暂存在。 keep/replace/clear凭据语义和安全存储不可用路径。- 地址中的凭据、查询、片段、危险 scheme、跨源重定向和远端 URL 注入被拒绝。
- 取消、超时、响应大小上限和应用关闭释放请求。
14.3 集成测试
- 实例保存、目录读取、手工 ID、绑定创建、编辑和本地移除。
- 同一远端目标重复绑定被拒绝。
- 删除实例的引用保护和级联本地移除确认。
- 本地与外部
retrieveMany部分成功、全部失败和确定性上下文预算。 - 聊天
always与 Agentknowledge_search使用同一 Provider-aware 编排。 - 历史引用在实例或绑定移除后仍可读。
14.4 UI 测试
- 类型切换、异步旧响应、目录搜索、刷新和手工模式。
- 两栏与窄窗口堆叠、键盘、焦点恢复和离开保护。
- Provider 字段显隐、失效配置、RAGFlow 图谱说明和恢复默认。
- 外部详情不出现导入、同步、分块和本地图谱操作。
- 错误、零结果、部分失败和 Provider 引用显示。
14.5 真实实例验收
每个 Provider 至少选择一个明确版本的自部署实例,记录:
- 版本、部署方式和认证范围。
- 列表与检索的请求/响应 fixture,移除凭据和业务正文。
- 默认与专属配置是否真实生效。
- 401、403、404、429、超时和取消行为。
- 查询、片段、引用和诊断的实际上限。
Mock 或公开文档通过不能代替真实实例验收。
2026-09-09 基线已完成 Dify 0.15.8/1.17.0 目录、详情差异和 1.17 非空检索结构,
FastGPT/RAGFlow 产品版本、严格 TLS、401/403/404/429、超时和取消尚未完成,因此不满足
本节完整验收条件。
14.6 可重复探测脚本
仓库提供 node scripts/external-knowledge-probe.mjs。默认从进程环境变量读取
GOODBUDDY_<PROVIDER>_BASE_URL/API_KEY,本地开发也兼容当前两行格式的 .env.dify、
.env.fastgpt 和 .env.ragflow;Dify 文件还支持多个 标签/URL/API Key 三行配置块,用于
同一次报告比较多个版本。输出不包含地址、凭据、远端 ID、名称、查询和正文。
node scripts/external-knowledge-probe.mjs
node scripts/external-knowledge-probe.mjs --provider=ragflow --extended
node scripts/external-knowledge-probe.mjs --extended --output=<report.json>
默认模式覆盖目录、详情和基础检索。--extended 额外执行 Dify 当前配置覆盖、FastGPT
Rerank、RAGFlow GraphRAG 和 Knowledge Compilation 检索。脚本只有固定 GET/POST 读取与
检索端点,不实现或调用远端创建、更新、上传和删除。
FastGPT 报告将请求成功与命中数量分开:HTTP 必须成功、业务 code 必须为 200,
且 data 或 data.list 必须是数组,才记录 success: true 和 count。成功的空数组
记录 count: 0;HTTP、业务、响应结构、JSON 解析或网络失败记录 success: false 与
固定失败类别,不用零命中代替失败。目录失败时不继续调用详情和检索。
features.searchModes 只包含基础检索实际成功的模式;rerankProbed 表示实际尝试,
rerankSucceeded 单独表示成功。历史基线保留原始证据,不追填未观测的成功字段。
tests/external-knowledge-probe-fastgpt.test.ts 使用内存 fetch fixture 运行真实 CLI,
覆盖错误、成功零命中和非空结果,不连接外部知识服务。
14.7 CRUD 验收边界
| 对象 | Create | Read | Update | Delete | 验收方式 |
|---|---|---|---|---|---|
| GoodBuddy 外部实例 | 是 | 是 | 是 | 是 | SQLite、凭据存储、IPC 和 Renderer 集成测试 |
| GoodBuddy 外部绑定 | 是 | 是 | 是 | 是 | SQLite、统一知识库列表、检索和删除确认测试 |
| Provider 远端知识库与内容 | 否 | 目录、详情、检索 | 否 | 否 | 探测脚本确认只有只读端点;代码审查确认无写端点 |
FastGPT 等 Provider 的公开 API 确实提供远端知识库、集合和数据 CRUD,但这不属于当前产品 接入。若未来要验证远端 CRUD,必须先修改 PRD,并使用可删除的专用测试实例或命名空间; 不能在本轮三个既有实例上执行破坏性测试。
15. 实施顺序
这里的顺序只用于控制代码依赖,不裁剪产品设计:
- 建立共享判别契约、数据库迁移和凭据存储。
- 实现 HTTP 边界、错误映射和 Adapter Registry。
- 逐个实现三种 Provider,并用 fixture 完成契约测试。
- 实现实例管理和目录 IPC。
- 扩展创建向导、统一列表和外部详情。
- 扩展检索测试、引用和
retrieveMany。 - 接入聊天预检索与
KnowledgeMcpGateway。 - 完成真实实例、安全、响应式和跨平台验收。
16. 发布条件
- 三种 Provider 的受支持版本和限制已在产品界面或发布说明中可查。
- 真实实例列表、绑定、检索和错误矩阵均通过。
- 没有写入远端知识内容的代码路径。
- API Key 泄漏测试、地址边界和响应大小测试通过。
- 本地知识库创建、同步、检索、图谱和引用回归测试通过。
auto、always、检索测试和 MCP 知识工具得到一致的外部知识能力。
17. 需求追踪
| 需求 | 技术落点 | 验证 |
|---|---|---|
EK-FR-01 至 EK-FR-03 |
实例契约、Store、实例 IPC、凭据和测试状态 | 实例集成测试、安全测试 |
EK-FR-04、EK-FR-05 |
Adapter 目录与详情接口、目录 IPC | Provider fixture、手工 ID 集成测试 |
EK-FR-06 至 EK-FR-09 |
Provider 判别联合、Adapter 配置版本、Renderer 本地字段定义 | 契约测试、UI 字段显隐测试 |
EK-FR-10、EK-FR-11 |
KnowledgeBase.kind、绑定表、统一 retrieveMany |
本地与外部混合检索测试 |
EK-FR-12、EK-FR-13 |
引用定位判别联合、结果标准化、检索测试 IPC | 引用持久化与 UI 测试 |
EK-FR-14 |
稳定错误码、逐库 Outcome、取消和超时 | 错误 fixture、部分失败测试 |
EK-FR-15 |
外键限制、绑定本地删除、无远端写接口 | 删除生命周期测试 |
EK-FR-16 |
Main-only HTTP、固定端点、传输风险确认 | 地址、证书和凭据泄漏测试 |