Files
memind/docs/tkmind-search-capability-architecture-plan.md
john 32fb2cdeaf feat: chat uploads, vision turn isolation, and MindSpace agent improvements
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>
2026-07-11 00:23:01 +08:00

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

核心决策:

  1. 不替换现有 Goose platform/web 扩展。
  2. 不覆盖现有 web Skill。
  3. 不覆盖现有本地代码搜索 search Skill。
  4. 新增独立扩展名 tkmind-search,默认关闭。
  5. Search Hub 不进入 Portal HTTP 主请求链路。
  6. Search 失败只能影响当前工具调用,不能导致会话、SSE 或 Agent Run 基础设施失效。
  7. 第一阶段使用固定 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_searchfetch_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 和本地 search Skill。

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 工具设计

推荐使用一个扩展、两个工具,而不是四个独立插件。

负责:

  • search.web
  • search.news
  • search.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-search Extension。
  • 不启动 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-search stdio MCP。
  • 暴露 tkmind_searchtkmind_read
  • Provider 未启用时返回 CAPABILITY_DISABLED
  • 默认不开启、不注入任何用户会话。

验收:

  • MCP initialize、tools/list、tools/call 单测。
  • MCP 子进程异常不影响 Portal 测试。
  • 功能关闭时 extension policy 与开发前完全一致。

Patch 3: SearXNG Web/News Adapter

目标:

  • 接入 search.websearch.news
  • 使用固定 Provider 路由。
  • 完成超时、结果上限和标准化。

验收:

  • 使用本地 mock Provider 完成确定性测试。
  • Provider 超时、空结果、无效 JSON 和 5xx 均返回统一错误。
  • 新闻结果保留发布时间;未知发布时间不得伪造。

Patch 4: GitHub Code Adapter

目标:

  • 接入 search.code
  • 与现有本地 search Skill 保持名称和行为隔离。

验收:

  • 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_external capability。
  • 增加全局和 Provider 功能开关。
  • buildAgentExtensionPolicy() 中条件化注入 tkmind-search
  • 复用 network_egress 和 session reconcile。

验收:

  • 默认用户 extension policy 不变化。
  • 只有三层条件全部满足时才注入扩展。
  • 开关关闭后,恢复会话会移除扩展。
  • 现有 websearch Skill 测试不变化。

Patch 7: 测试账号本地端到端验证

目标:

  • 只为专用测试账号开启能力。
  • 验证 Search 工具调用、结果引用和失败隔离。
  • 不改变默认用户能力。

验收场景:

  1. 普通聊天不调用 Search。
  2. Web 搜索返回来源。
  3. News 搜索保留时间信息。
  4. Code 搜索不调用本地 ripgrep Skill。
  5. Reader 拒绝私网 URL。
  6. Provider 超时后会话仍可继续。
  7. Search 关闭后同一账号恢复为原工具集合。
  8. 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. 回退方案

本地或后续灰度发现问题时,按以下顺序回退:

  1. 设置 TKMIND_SEARCH_ENABLED=false
  2. 确认新会话不再包含 tkmind-search
  3. 恢复测试账号会话,确认 reconcile 移除扩展。
  4. 保留现有 platform/web,继续提供原搜索能力。
  5. 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
  • 构建或发布 103 runtime/artifact。
  • 修改生产配置。
  • 启动生产 Provider。
  • 执行任何生产动作。

开发完成后必须先完成对应本地测试和 verify,再由用户决定下一步。