TencentDB Agent Memory 的 OpenAPI:自称 28 个端点,代码 37 条

2026-08-16

如果你打算照着 MemoryKnowledge 的 OpenAPI 规格生成一份客户端,有一个数字值得先自己数一遍:规格描述里写的端点数,和代码里真正注册出来的路由数,不是同一个数。

先把前提摆清楚。本文讨论的是 TencentCloud/TencentDB-Agent-Memory 仓库中的 MemoryKnowledge/ 这一个模块,截至 2026-08-16 我们采集的快照是 97f9465,分支 feat/server_team——这个仓库的默认分支就是 feat/server_team,不是 main 也不是 master,所以下文所有文件路径都要放在这条分支上看。该模块 package.json 里的 version0.1.0MemoryKnowledge/package.json:2-3),包名 @tencentdb-agent-memory/knowledge-service,而整仓 CHANGELOG 最新条目是 2.0.1-beta.1。项目仍在 beta 阶段,接口与路径随版本变动,下面写到的每一条路由都请以仓库最新内容为准。

差异本身:两处位置,两个数

位置一:MemoryKnowledge/openapi.yaml:6 规格头部 info.description 的原文里有一句 Provides 28 endpoints。规格头还写明 openapi: 3.0.3info.title: Knowledge Service APIinfo.version: "1.0.0"servers[0].url: http://localhost:8421/v3,tags 只有 LLM-WikiCode-Graph 两个(MemoryKnowledge/openapi.yaml:1-46)。

我们用脚本数过 paths 下的路径条目,结果确实是 28 条,且全部只有 post 一个方法。规格里的注释把它们分成 LLM-Wiki (15 endpoints)MemoryKnowledge/openapi.yaml:50)与 Code-Graph 13 条。也就是说,规格自己说 28,规格自己的 paths 也是 28,这一层是自洽的。

位置二:MemoryKnowledge/src/server.ts:56-96 挂载出来的那棵路由树。 我们按 app.post / app.get 的字面量逐文件枚举,加上一处循环注册,得到的是 37 条。

来源文件条数说明
src/routes/wiki.ts16全部字面量 POST
src/routes/code-graph.ts6 + 86 条字面量 POST,另有 8 条按常量数组循环注册
src/routes/tools.ts2/list(194)、/call(247)
src/routes/llm-binding.ts3/set(40)、/status(95)、/list(103)
src/routes/auto-sync.ts2GET /auto-sync/status(25)、POST /auto-sync/trigger(38)

16 + (6 + 8) + 2 + 3 + 2 = 37。两处口径差 9 条。

这里只陈述差异,不推断哪一处「才是对的」,也不推断为什么两边没对上。以我们实读的仓库状态为准:规格里是 28,代码里是 37。

为什么按字面量数会数少:那 8 条是循环注册的

这是最容易在自己复核时翻车的一步。src/routes/code-graph.ts 里能直接搜到的 POST 只有 6 条——/create(182) /list(218) /get(232) /update-meta(244) /sync(265) /delete(285)。剩下 8 条查询类路由不是一条条写出来的,而是在 MemoryKnowledge/src/routes/code-graph.ts:322-323 用一个 for 循环,按常量 CODEGRAPH_QUERY_TOOL_NAMES 逐个注册的。

这个常量本身定义在 MemoryKnowledge/src/routes/tools.ts:385-387,共 8 个名字,不含 get_info。作为对照,同文件里的 CODE_GRAPH_TOOLS 是 9 个:get_info search explore callers callees impact node status filesMemoryKnowledge/src/routes/tools.ts:95-179)。WIKI_TOOLS 则是 7 个:get_info search list_pages read_page get_graph list_raw read_raw(同文件 49-93 行)。

所以你要是只用编辑器全局搜 app.post(/code-graph 这一组会少数 8 条,正好把 37 数成 29。这一条常量被注释标为「单一真相源」,另有一个 toCodeGraphToolName() 把外部短名映射成内部名 codegraph_<name>MemoryKnowledge/src/routes/tools.ts:393-395)。

差的九条:规格里查不到的部分

把两边对齐,规格里查不到、而代码里注册了的,正好是这九条:

方法 + 路径代码位置
POST /wiki/update-metaMemoryKnowledge/src/routes/wiki.ts:132
POST /code-graph/update-metaMemoryKnowledge/src/routes/code-graph.ts:244
POST /tools/listMemoryKnowledge/src/routes/tools.ts:194
POST /tools/callMemoryKnowledge/src/routes/tools.ts:247
POST /internal/llm-binding/setMemoryKnowledge/src/routes/llm-binding.ts:40
POST /internal/llm-binding/statusMemoryKnowledge/src/routes/llm-binding.ts:95
POST /internal/llm-binding/listMemoryKnowledge/src/routes/llm-binding.ts:103
GET /auto-sync/statusMemoryKnowledge/src/routes/auto-sync.ts:25
POST /auto-sync/triggerMemoryKnowledge/src/routes/auto-sync.ts:38

有意思的是 tools 这一组。README 自述的四类能力里就明确列了 POST /v3/tools/list/v3/tools/callMemoryKnowledge/README.md:10-16),而这两条在 openapi.yaml 的 paths 里找不到。

另外,/internal/llm-binding 这一组的源码注释写得很直白:这些是内部端点,「KS trusts the internal network like its other routes; no extra auth layer is added here」(MemoryKnowledge/src/routes/llm-binding.ts:15-17)——即这组路由没有额外鉴权层。这句是源码原文,照实记下来;至于部署时怎么处置,属于你自己环境里的事。

复核动作:三步,都能自己跑

第一步,数规格。在 MemoryKnowledge/ 目录下:

python -c "
import re
y=open('openapi.yaml',encoding='utf-8').read()
print(len(re.findall(r'^  (/[\w/-]+):', y, re.M)))
"

我们跑出来是 28。

第二步,确认那九条真的不在规格里。最省事的是直接判存在性——我们用 'update-meta' in openapi.yaml 复核,结果是 Falsetoolsllm-bindingauto-sync 同理各搜一遍即可。

第三步,数代码。用正则扫 src/routes/ 下的 app.post / app.get 字面量,得到 wiki 16、code-graph 6、tools 2、llm-binding 3、auto-sync 2 共 29 条;然后必须手工把 code-graph.ts:322-323 那个循环注册的 8 条加回去,才是 37。

别把这三条也算进 37

/v3 是前缀,不是全部。src/server.ts 的挂载顺序是:accessLog() 全局中间件 → onError(errorHandler)/health无前缀)→ 新建一个 api 实例挂 /wiki/code-graph/tools/internal/llm-binding 与 auto-sync 的根路由 → 最后 app.route(config.apiPrefix, api) 统一加前缀(MemoryKnowledge/src/server.ts:56-96)。

前缀之外还有三条:GET /healthMemoryKnowledge/src/routes/health.ts:10,返回 { status: "ok", timestamp })、Swagger UI 的 /docs、以及 /openapi.jsonMemoryKnowledge/src/server.ts:100-111)。数 37 的时候这三条不在其中。

顺带记一笔:/openapi.json 这个 handler 返回的 Content-Type 写的是 application/yamlMemoryKnowledge/src/server.ts:105)——路径后缀与响应头声明的类型不一致,只陈述这一点。

还有一层要注意:/v3 本身是可配的。API_PREFIX 的默认值是 /v3MemoryKnowledge/src/config.ts:154),README 也写「默认端口 8421,API 前缀 /v3」(MemoryKnowledge/README.md:6),两处一致。但 MCP 那侧的 HTTP 客户端拼 URL 的写法是 ${baseUrl}/v3${endpoint}——/v3写死的字符串MemoryKnowledge/src/mcp/http-client.ts:36)。同一个文件里,请求头只设了 Content-Type,有 token 时加 Authorization: Bearer(37-38 行),我们在其中没有找到设置 x-tdai-service-id 的代码;而被调用的那些路由在缺该头时会返回 400(例如 MemoryKnowledge/src/routes/wiki.ts:470)。

还有一处规格与代码的错位

如果你正在用这份 spec 生成客户端,ServiceIdHeader 这一处也值得一起看。

MemoryKnowledge/openapi.yaml:716-725 定义了 components.parameters.ServiceIdHeader,且标了 required: true。但全文 ServiceIdHeader 只出现 2 次:一次是定义处,另一次是 IdFields 描述里的一句「See the ServiceIdHeader parameter」(754-755 行)。全文 parameters: 也只出现 1 次,就是 components 里那次——28 个操作没有任何一个写 parameters: - $ref: '#/components/parameters/ServiceIdHeader'

代码那边则是每个 handler 各自读 header 并在缺失时返回 400(例如 MemoryKnowledge/src/routes/wiki.ts:61)。常量名是 SERVICE_ID_HEADER = "x-tdai-service-id"MemoryKnowledge/src/api-helpers.ts:12),白名单正则 ^[A-Za-z0-9_-]+$、最长 200(同文件 20-21 行),注释写明这是为了防路径穿越——因为这个 id 会被拼进 data/{service_id}/{team_id}/{resource_id}/ 的目录路径里(14-19 行)。规格描述里也写了这条要求:每个端点都要在 x-tdai-service-id 请求头里带租户身份,缺失或格式错返回 400(MemoryKnowledge/openapi.yaml:11-16)。

也就是说,这个约束在规格的散文描述里有、在代码里有,但没有落到规格的结构化字段上。从生成器的角度看,读散文和读 parameters 不是一回事。同样,只陈述差异,到此为止。

同一个模块里,「有多少个能力」有三套数

再多说一层,免得你在别处看到别的数字时以为自己数错了。这个模块对外暴露能力的口径不止 HTTP 路由这一套,至少有三套彼此独立的计数,各有各的定义处:

  • HTTP 路由/v3 前缀下 37 条,前缀外 /health/docs/openapi.json 三条。定义处是 src/routes/ 下各文件加 src/server.ts:56-96 的挂载。
  • Tools 自发现清单WIKI_TOOLS 7 个、CODE_GRAPH_TOOLS 9 个,都定义在 MemoryKnowledge/src/routes/tools.ts:49-9395-179。它们是通过 POST /v3/tools/list/v3/tools/call 这两条路由对外的,传入未知工具名会返回 403(MemoryKnowledge/src/routes/tools.ts:270-271,282-283)。
  • MCP 工具清单MCP_TOOLS 12 个——code_search code_explore code_callers code_callees code_impact code_node code_status code_files wiki_search wiki_read wiki_list wiki_graphMemoryKnowledge/src/mcp/tools.ts:25-220)。这一套走 StdioServerTransport,MCP server 自报的身份是 { name: "knowledge-mcp", version: "0.1.0" }MemoryKnowledge/src/mcp/server.ts:34),实现上是把工具调用转成 HTTP 请求打回来(同文件 63 行),转发地址取 KNOWLEDGE_API_URL,默认 http://localhost:8421(94-95 行)。

三套数字互不相等,各自的定义处也不在一处:一套在 src/routes/src/server.ts 的挂载,一套在 src/routes/tools.ts 的两个常量数组,一套在 src/mcp/tools.ts。这里只记录这三套计数分别是多少、写在哪儿,不去推断它们之间该是什么关系。要紧的是你在文档、issue、对接单里写数字时,把「哪一套」说明白。

顺手记住的另外两个数字口径

同一模块里还有两处数字在不同层不一致,排查时容易撞上:

一是端口。模块内四处都是 8421——MemoryKnowledge/README.md:6src/config.ts:150Dockerfile:78docker-compose.yml:19;而仓库根 INSTALL.md:58 的端口表写的是 8424INSTALL.md:91 给的 Swagger 地址是 http://localhost:8424/docs

二是「4 张表」。MemoryKnowledge/src/db/schema.ts:2-8 的头注释写「4 SQLite tables」,src/db/client.ts:46 的注释写「for all 4 tables + indexes」,.env.example:13 也写 4 张;而 schema 里在 131 行还定义了第五张 llm_bindingclient.ts 的函数体里建的也是 5 张。

这两条和端点数是同一类东西:文档层、配置层、代码层各写各的,取数之前先确认自己读的是哪一层。 这也是本模块里最实用的一条经验——凡是要把某个数字写进代码或写进工单,先问一句它来自哪个文件的第几行。

延伸阅读


本文依据 TencentDB Agent Memory 官方仓库(github.com/TencentCloud/TencentDB-Agent-Memoryfeat/server_team 分支上的 README、INSTALL、CHANGELOG、ROADMAP 与四个模块的源码整理, 核对日 2026-08-16,对应仓库快照 97f9465。该仓库的默认分支即为 feat/server_team。 本文内容为仓库源码与文档口径,我们没有部署、也没有运行过该项目的任何一个模块, 因此不涉及运行效果、检索质量与性能的任何描述。 该项目主模块处于 beta 阶段、其余模块版本号仍为 0.1.0,参数与接口随版本变动,请以仓库最新内容为准。 该项目会采集并存储团队的对话、文档与代码,属于敏感数据,是否使用请结合自身合规要求评估。 安全与合规相关做法请结合自身环境评估,本文不构成安全方案建议。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。