Add chat file/image upload UX, attachment proxying, vision thumbnails, and per-turn image scoping so agents only use the current upload. Extend MindSpace asset context, billing token state, OA/scenario verify scripts, and related runtime config. Co-authored-by: Cursor <cursoragent@cursor.com>
19 KiB
TKMind Search Capability 插拔式接入架构与开发计划
日期: 2026-07-10
状态: 设计评估完成,等待用户明确指令后再开始开发
0. 文档目的
本文定义如何在现有 Memind Portal + Goose Runtime 架构中,以插拔方式增加以下四项外部信息能力:
search.web: 公共网页搜索。search.news: 新闻和时效信息搜索。search.code: GitHub 等公共代码与开源项目搜索。search.read: 根据 URL 读取并清洗网页正文。
本文只描述架构、边界、协议和后续开发计划。本阶段不修改业务代码、不启动新服务、不调用生产 Provider、不改变生产配置,也不执行发布。
第一阶段不考虑 Skill Store、第三方开发者发布、商业化、Credit 扣费、收益分成和第三方代码托管。
1. 结论
现有项目已经具备适合 Search Capability 的扩展入口,不需要重构聊天和会话主链路。
推荐目标:
H5 / Web / WeChat
|
v
现有 Agent Run Gateway
|
v
现有 tkmind-proxy
|
v
Goose
|
| 仅在功能开关和用户能力同时允许时注册
v
tkmind-search MCP Extension
|
v
Search Hub
- request validation
- fixed provider routing
- result normalization
- citation construction
- URL safety
- timeout / limits
|
+--> SearXNG: web / news
+--> GitHub API: code
+--> Reader Adapter: read
+--> optional commercial provider adapters
核心决策:
- 不替换现有 Goose
platform/web扩展。 - 不覆盖现有
webSkill。 - 不覆盖现有本地代码搜索
searchSkill。 - 新增独立扩展名
tkmind-search,默认关闭。 - Search Hub 不进入 Portal HTTP 主请求链路。
- Search 失败只能影响当前工具调用,不能导致会话、SSE 或 Agent Run 基础设施失效。
- 第一阶段使用固定 Provider 路由,不引入 LLM Router 和动态评分。
2. 现有项目基础
2.1 已有能力注入机制
capabilities.mjs 已经通过 buildAgentExtensionPolicy() 生成 Goose extension_overrides。
当前 web capability 会注入:
{
"type": "platform",
"name": "web",
"available_tools": ["web_search", "fetch_url"]
}
这证明现有架构已经把“用户能力授权”和“Goose 实际工具集合”连接起来。新 Search 不应另建一条绕过该策略的入口。
2.2 已有禁用和会话对账机制
policies.mjs 会在 network_egress=deny 时移除联网能力。
session-reconcile.mjs 会在恢复会话时:
- 获取当前会话扩展。
- 移除不再允许的扩展。
- 添加缺失的扩展。
- 在扩展集合变化时重启 Goose session runtime。
因此,新 Search Capability 可以复用当前权限和会话对账体系,形成可验证的关闭语义。
2.3 已有搜索相关 Skill
当前仓库中两个名称必须保留原义:
skills/web: Goose 内置web_search和fetch_url的使用说明。skills/search: 使用 ripgrep 搜索当前工作区代码和文件,不是公网代码搜索。
为避免命名冲突,新能力内部使用:
- Goose extension:
tkmind-search - Capability grant:
search_external - Search protocol capability:
search.web/search.news/search.code/search.read - 可选用户 Skill 文档名:
search-external
2.4 现有路由基础
当前 chat-intent-router.mjs 已将实时新闻、天气、行情等需要联网查询的请求判定为 agent_orchestration。
第一阶段不扩大自动路由范围。测试和灰度优先通过显式选择 Search Skill 或专用测试账号进入 Agent,避免普通问答被误路由。
3. 硬性隔离边界
3.1 保持不变的模块
第一阶段禁止因 Search 接入而改变以下模块的职责或协议:
- H5 发送消息和订阅事件的顺序。
POST /agent/runs的请求语义。- Agent Run 状态机。
tkmind-proxy作为 Portal 到 goosed 的唯一适配器边界。- Session Broker ownership 和 goosed target mapping。
- Session SSE 和 Run SSE 协议。
chat-finish-sync的消息 merge 行为。- Memory V2 的读取、写入和压缩行为。
- MindSpace 页面、文件和发布链路。
- UserDataSpace 数据访问。
- MySQL 用户、会话、订单和计费表。
- 现有
platform/web和本地searchSkill。
3.2 Search Hub 允许做的事情
Search Hub 只负责:
- 校验搜索或读取请求。
- 根据 capability 使用固定规则选择 Provider。
- 调用公共搜索、GitHub 或 Reader Provider。
- 标准化结果。
- 去除明显重复 URL。
- 构建来源和引用对象。
- 执行超时、响应大小和 URL 安全限制。
- 返回结构化结果或统一错误。
3.3 Search Hub 禁止做的事情
Search Hub 不得:
- 创建、恢复或修改 Goose session。
- 写入 Agent Run 状态。
- 直接写 Memory V2。
- 直接写 MindSpace 页面或文件。
- 读写 UserDataSpace。
- 读取完整聊天记录。
- 直接访问用户业务 MySQL 表。
- 接管 Goose 最终回答。
- 把搜索结果自动保存为长期资产。
- 因 Provider 故障修改 Portal 或 Goose 服务状态。
4. 运行形态
4.1 第一阶段: 独立 stdio MCP
第一阶段建议增加一个独立进程运行的 MCP Extension:
Goose session
-> stdio MCP: tkmind-search
-> Search Hub modules
-> outbound HTTPS
优点:
- 复用仓库已经验证过的 stdio MCP 接入方式。
- Search 代码不进入 Portal 进程请求处理路径。
- MCP 进程异常不会直接终止 Portal。
- 关闭扩展后 Goose 不启动对应进程。
- 不新增公网监听端口。
限制:
- 每个运行实例的缓存和健康状态不天然共享。
- 多会话下可能产生多个 MCP 子进程。
- Provider 限流第一阶段只能依赖 Provider 和轻量本地限制。
这些限制可以接受,因为第一阶段目标是安全验证四项能力,而不是建设大规模 Search 平台。
4.2 后续可选: 内部 Search Sidecar
当调用量需要共享缓存、全局限流和统一 Provider 熔断时,可以演进为:
Goose
-> tkmind-search MCP bridge
-> private Search Hub sidecar
-> Providers
Sidecar 只能监听内部地址,并且不属于第一阶段范围。
5. Goose 工具设计
推荐使用一个扩展、两个工具,而不是四个独立插件。
5.1 tkmind_search
负责:
search.websearch.newssearch.code
请求示例:
{
"capability": "search.web",
"query": "Goose Agent latest release",
"language": "zh-CN",
"region": "CN",
"freshness": {
"type": "days",
"value": 30
},
"limit": 10
}
5.2 tkmind_read
负责:
search.read
请求示例:
{
"url": "https://example.com/article",
"max_chars": 30000,
"include_metadata": true
}
search.read 不与搜索请求共用 query 字段。Reader 的输入、SSRF 风险和响应上限与搜索不同,应保持独立工具 Schema。
6. 统一返回协议
搜索结果最小结构:
{
"request_id": "srch_example",
"status": "success",
"capability": "search.web",
"provider": "searxng",
"query": "Goose Agent latest release",
"results": [
{
"id": "result_001",
"type": "webpage",
"title": "Example title",
"url": "https://example.com/article",
"snippet": "Example snippet",
"published_at": null,
"retrieved_at": "2026-07-10T00:00:00Z",
"source_name": "Example",
"language": "en",
"provider_rank": 1,
"metadata": {}
}
],
"citations": [
{
"citation_id": "cite_001",
"result_id": "result_001",
"url": "https://example.com/article",
"title": "Example title"
}
],
"timing": {
"duration_ms": 800
}
}
Reader 结果最小结构:
{
"request_id": "read_example",
"status": "success",
"capability": "search.read",
"url": "https://example.com/article",
"final_url": "https://example.com/article",
"title": "Example title",
"content": "Cleaned article text",
"content_type": "text/html",
"content_hash": "sha256:...",
"retrieved_at": "2026-07-10T00:00:00Z",
"trust_level": "untrusted_external_content",
"truncated": false
}
Provider 自带摘要只能作为结果字段,不能直接作为 TKMind 最终答案。最终回答继续由 Goose 生成。
7. Provider 方案
7.1 第一阶段推荐
| Capability | 默认 Provider | 说明 |
|---|---|---|
search.web |
SearXNG | 自建、固定配置、返回标准化网页结果 |
search.news |
SearXNG news category | 第一阶段复用同一搜索服务 |
search.code |
GitHub Search API | 搜索 repository、code、issue、release 等 |
search.read |
Readability Adapter 或受控 Reader | 读取 URL 并输出正文和元数据 |
SearXNG 的生产部署和对外服务方式需要在实施前完成许可证合规确认。
7.2 可选 Provider
Brave、Tavily、Jina Reader 可以后续作为 Provider Adapter 接入,但不应成为第一阶段启动条件。
第一阶段不做多 Provider 并行聚合,不做质量动态评分,也不做自动商业 Provider 降级。
8. 功能开关和授权
8.1 建议开关
TKMIND_SEARCH_ENABLED=false
TKMIND_SEARCH_PROVIDER_SEARXNG_ENABLED=false
TKMIND_SEARCH_PROVIDER_GITHUB_ENABLED=false
TKMIND_SEARCH_READER_ENABLED=false
8.2 生效条件
普通用户只有同时满足以下条件才能获得新扩展:
TKMIND_SEARCH_ENABLED = true
AND user capability search_external = true
AND network_egress = allow
任意条件不满足时,不得把 tkmind-search 加入 extension_overrides。
8.3 关闭语义
当 TKMIND_SEARCH_ENABLED=false 时:
- 不注册
tkmind-searchExtension。 - 不启动 Search MCP 子进程。
- 不读取 Provider Secret。
- 不产生 Search 外部网络请求。
- 不改变现有
platform/web。 - 不影响现有 Skill、MCP、会话、SSE、Memory、MindSpace 和 UserDataSpace。
- 老会话恢复时,由现有 session reconcile 移除
tkmind-search。
8.4 灰度原则
第一阶段只允许专用测试账号开启 search_external。
禁止一开始修改默认用户能力,也禁止对所有用户替换现有 web capability。
9. 安全要求
9.1 URL 和 SSRF
Reader 必须拒绝:
localhost和回环地址。- RFC1918 私网地址。
- Link-local 和云元数据地址。
- Docker、Colima、Kubernetes 和宿主机内部域名。
- 非 HTTP/HTTPS 协议。
- 解析后落入受限地址的域名。
每次重定向都必须重新执行 URL 和解析后 IP 校验。还需要限制:
- 最大重定向次数。
- 最大响应体积。
- 请求总超时。
- 允许的 MIME 类型。
- 压缩后解包体积。
9.2 Prompt Injection
所有 Reader 正文必须标记:
{
"trust_level": "untrusted_external_content"
}
网页内容只能作为资料,不得改变系统指令、请求其他工具、读取用户数据或执行命令。
9.3 数据最小化
Provider 请求不得包含:
- 真实
user_id。 tenant_id。- 手机号、邮箱或用户名。
- 完整会话内容。
- Memory V2 内容。
- MindSpace 私有文件。
- UserDataSpace 数据。
Provider 只接收搜索参数、随机 request ID 和必要的 Provider 鉴权信息。
9.4 Secret
Provider Key 只能从运行环境或 Secret 引用读取,禁止写入仓库、Skill 文档、日志和 Goose 对话上下文。
10. 超时和错误隔离
第一阶段建议:
| 操作 | 超时上限 |
|---|---|
| Web/News Search | 10 秒 |
| Code Search | 10 秒 |
| Reader 单页 | 10 秒 |
| MCP 工具总调用 | 12 秒 |
统一错误示例:
{
"status": "error",
"error": {
"code": "PROVIDER_TIMEOUT",
"message": "Search provider timed out",
"retryable": true
}
}
Search MCP 不得主动重启 Portal 或 goosed,不得修改 Agent Run 数据。Provider 失败应作为普通工具错误返回,由 Goose 决定是否解释、重试一次或继续回答。
11. 可观测性
第一阶段只记录技术指标,不接用户扣费:
- request ID。
- capability。
- Provider 名称。
- 成功或错误码。
- 响应耗时。
- 结果数量。
- 是否触发 Reader。
- 是否截断。
默认不记录完整搜索词。调试环境需要查询内容时,应显式开启并做脱敏处理。
Search 日志应与 Portal 会话日志分离,避免 Provider 波动污染现有服务健康判断。
12. 对现有项目的预期影响
12.1 功能关闭时
预期影响为零:
- Goose 工具列表不变化。
- Portal 请求链路不变化。
- 会话和 SSE 不变化。
- 不新增网络请求。
- 不新增运行进程。
12.2 测试账号开启时
只影响该账号的 Goose 工具集合:
- Goose 可以调用新 Search MCP。
- 搜索轮次可能增加 1 到 12 秒延迟。
- 结构化结果会占用一定会话上下文 Token。
- Provider 故障只影响当前搜索工具调用。
12.3 需要避免的间接影响
- 不要扩大聊天 Router 规则导致普通问答大量进入 Agent。
- 不要让前端只根据 Skill grant 显示搜索入口,而忽略有效 capability 和
network_egress。 - 不要让新旧搜索工具使用相同名称。
- 不要把 Search Provider 健康状态加入 Portal 总体存活条件。
- 不要在 Search 稳定前关闭现有
platform/web。
13. 开发计划
所有开发阶段均等待用户后续明确指令。每个 Patch 必须可以单独测试和停止,不自动进入下一阶段。
Patch 0: 基线确认
目标:
- 记录开发前分支和工作区状态。
- 确认现有 capability、session reconcile、Agent Run 和 SSE 测试基线。
- 确认当前 goosed 对自定义 stdio MCP 配置字段的实际兼容性。
产物:
- 基线测试结果。
- 不改业务行为的接入点确认。
停止条件:
- 现有关键测试未通过。
- goosed 当前版本无法可靠加载独立 stdio MCP。
Patch 1: 协议和纯函数
目标:
- 定义 Search、Read、Result 和 Error Schema。
- 实现请求校验、URL canonicalization、结果标准化和错误映射纯函数。
- 不连接任何 Provider。
建议新增范围:
search-capability/
schemas/
search-errors.mjs
request-validator.mjs
result-normalizer.mjs
citation-builder.mjs
验收:
- Schema 正反例单测。
- Provider 原始结果不能穿透到 Goose。
- 所有成功结果必须包含来源 URL。
Patch 2: Search MCP 空运行时
目标:
- 新增独立
tkmind-searchstdio MCP。 - 暴露
tkmind_search和tkmind_read。 - Provider 未启用时返回
CAPABILITY_DISABLED。 - 默认不开启、不注入任何用户会话。
验收:
- MCP initialize、tools/list、tools/call 单测。
- MCP 子进程异常不影响 Portal 测试。
- 功能关闭时 extension policy 与开发前完全一致。
Patch 3: SearXNG Web/News Adapter
目标:
- 接入
search.web和search.news。 - 使用固定 Provider 路由。
- 完成超时、结果上限和标准化。
验收:
- 使用本地 mock Provider 完成确定性测试。
- Provider 超时、空结果、无效 JSON 和 5xx 均返回统一错误。
- 新闻结果保留发布时间;未知发布时间不得伪造。
Patch 4: GitHub Code Adapter
目标:
- 接入
search.code。 - 与现有本地
searchSkill 保持名称和行为隔离。
验收:
- Repository、Issue 和 Code 等结果映射为统一结构。
- API 限流返回可重试错误。
- 不把 GitHub Token 返回到日志或工具结果。
Patch 5: Reader 和 URL Safety
目标:
- 接入
search.read。 - 实现 URL Safety Validator。
- 增加重定向、MIME、体积和正文长度限制。
验收:
- 回环、私网、metadata、IPv6 特殊地址和重定向到私网均被拒绝。
- 非 HTML/允许类型被拒绝或明确标记。
- 正文统一标记为不可信外部内容。
- 超大页面被截断且返回
truncated=true。
Patch 6: Capability 和功能开关接入
目标:
- 增加默认关闭的
search_externalcapability。 - 增加全局和 Provider 功能开关。
- 在
buildAgentExtensionPolicy()中条件化注入tkmind-search。 - 复用
network_egress和 session reconcile。
验收:
- 默认用户 extension policy 不变化。
- 只有三层条件全部满足时才注入扩展。
- 开关关闭后,恢复会话会移除扩展。
- 现有
web和searchSkill 测试不变化。
Patch 7: 测试账号本地端到端验证
目标:
- 只为专用测试账号开启能力。
- 验证 Search 工具调用、结果引用和失败隔离。
- 不改变默认用户能力。
验收场景:
- 普通聊天不调用 Search。
- Web 搜索返回来源。
- News 搜索保留时间信息。
- Code 搜索不调用本地 ripgrep Skill。
- Reader 拒绝私网 URL。
- Provider 超时后会话仍可继续。
- Search 关闭后同一账号恢复为原工具集合。
- Run SSE 和 Session SSE 的终态行为不变。
Patch 8: 可选 UI 和窄范围路由
只有后端本地验证稳定后才评估:
- 是否增加独立“联网搜索”入口。
- 前端是否按有效 capability 而不是单纯 Skill grant 展示。
- 是否增加窄范围、可关闭的自动 Search 意图规则。
第一阶段可以完全不改 UI,通过显式测试请求验证后端能力。
14. 测试与回归范围
实际开发时至少需要覆盖:
- Search Schema 和 Adapter 单测。
- MCP 协议单测。
- Capability policy 单测。
- Session reconcile 增删扩展单测。
tkmind-proxy会话启动和恢复测试。- Agent Run Gateway 回归测试。
- SSE taxonomy 和 Finish sync 回归测试。
- 现有
web、本地search和 chat skill 路由测试。 - URL Safety 专项测试。
如果任何改动触及 MindSpace 回归守卫路径,必须按照仓库 AGENTS.md 执行对应 verify;本方案原则上不要求触及这些路径。
15. 回退方案
本地或后续灰度发现问题时,按以下顺序回退:
- 设置
TKMIND_SEARCH_ENABLED=false。 - 确认新会话不再包含
tkmind-search。 - 恢复测试账号会话,确认 reconcile 移除扩展。
- 保留现有
platform/web,继续提供原搜索能力。 - Search MCP 和 Provider 不进入 Portal 健康检查,不需要重启现有服务完成逻辑回退。
代码回退不得使用脏工作区或直接修改生产文件,仍须遵守仓库开发和发布规范。
16. 第一阶段明确不做
- Skill Store。
- 第三方开发者接入。
- 用户支付和 Search Credit。
- 开发者收益结算。
- Tavily Deep Research 编排。
- 多 Provider 并行聚合。
- AI Provider Router。
- LLM 全量重排。
- Platform Hosted 第三方代码。
- 企业私有搜索。
- 搜索结果自动写 Memory 或 MindSpace。
- 替换或删除现有 Goose
platform/web。 - 修改现有 Run SSE 和 Session SSE 协议。
17. 开发启动闸门
开始任何代码开发前,必须再次获得用户明确指令。
开发指令不自动授权:
git push。- 合并
main。 - 构建或发布
103runtime/artifact。 - 修改生产配置。
- 启动生产 Provider。
- 执行任何生产动作。
开发完成后必须先完成对应本地测试和 verify,再由用户决定下一步。