TencentDB Agent Memory 的构建产物名:三处写法不一致

2026-08-16

翻一个陌生仓库的时候,最容易被忽略也最容易卡住的,往往不是那些写在 README 首屏的能力表,而是「这个服务到底是用哪条命令、跑哪个文件起来的」。TencentDB Agent Memory 的 MemoryKnowledge 模块就有这么一处:同一个服务的启动入口,在仓库里被写成了两种文件名,dist/server.jsdist/server.mjs,而且不是随口一提,是分别落在包描述、bin 脚本、容器入口脚本这三种会被真正执行到的地方。

这篇只做一件事:把这几处原文、文件路径和行号摆出来,再给出你自己去核的动作。不推断哪一处是对的,也不推断为什么会这样。

先把坐标对齐

先交代清楚我们在看哪一份东西,不然行号对不上。

我们采集的时间锚点是 2026-08-16,对应仓库快照 97f9465。要特别注意的是,这个仓库的默认分支是 feat/server_team,不是 main 也不是 master——本文所有路径与行号都指这个分支上的状态。

MemoryKnowledge/ 这个目录对应的包名是 @tencentdb-agent-memory/knowledge-servicepackage.json 里的 version0.1.0MemoryKnowledge/package.json:2-3)。它自述是 monorepo 内的 Knowledge Service,也就是用户侧的 Wiki + Code-Graph 引擎,管控面在 ../MemoryPanelMemoryKnowledge/README.md:3-4)。整个项目处于 beta 阶段,主模块版本是 2.0.0-beta.1,本模块与另外两个模块还是 0.1.0;换句话说,下面提到的这些文件名、脚本、字段随版本变动是完全可能的,以你手上仓库的最新内容为准

四处口径,逐处摆出来

#位置原文写的是
1MemoryKnowledge/package.json:6"main": "./dist/server.js"
2MemoryKnowledge/bin/server.mjs:2import "../dist/server.js";
3MemoryKnowledge/docker/entrypoint.sh:238exec node dist/server.mjs
4deploy/panel-knowledge-combined/start-combined.sh:101node "$(test -f dist/server.js && echo dist/server.js || echo dist/server.mjs)"

第 1、2 处是一致的,都是 .jspackage.jsontype 字段是 modulemain 指向 ./dist/server.js;同时它声明了两个 bin,knowledge-server./bin/server.mjsknowledge-mcp./bin/mcp.mjsMemoryKnowledge/package.json:5-10)。而 bin/server.mjs 这个文件本身只有两行,第二行就是 import "../dist/server.js";。注意这里有个容易看花眼的地方:bin 脚本自己叫 .mjs,它 import 的目标却是 .js,这两个扩展名指的不是一回事,一个是仓库里手写的壳,一个是构建产物。

第 3 处是容器路径。MemoryKnowledge/docker/entrypoint.sh 全文 241 行,作用是把命令行 flag 映射成环境变量(例如 --public-url--llm-mode--llm-key),最后一句执行的是 exec node dist/server.mjs。而镜像的 ENTRYPOINT 正是 ["/usr/bin/tini","--","/usr/local/bin/docker-entrypoint.sh"]CMD["start"]MemoryKnowledge/Dockerfile:88-89)。也就是说,容器方式起服务时走的是这一行,不是 package.jsonmain,也不是 bin 脚本。

第 4 处是同仓另一个部署目录里的合并镜像启动脚本,它没有二选一,而是两种都试:先 test -f dist/server.js,存在就用它,否则退回 dist/server.mjs。紧挨着它的上一行还把端口换了个变量名传进去——PORT="${KNOWLEDGE_PORT}"deploy/panel-knowledge-combined/start-combined.sh:100)。

以上四处就是全部差异。我们只陈述这四处写法不同,不判断哪一处与实际产物一致

产物到底叫什么,看构建配置那一行

想知道 dist/ 下最终生成的文件叫什么,得看构建配置。MemoryKnowledge/tsdown.config.ts 全文 30 行,关键字段是:

entry: ["./src/server.ts", "./src/mcp/server.ts"],
outDir: "./dist",
format: "esm",
platform: "node",
clean: true,
fixedExtension: true,
dts: false,
sourcemap: false,

其中第 18 行是 fixedExtension: true,配合 format: "esm"。这两个字段合起来会产出什么扩展名,属于 tsdown 这个构建工具自己的语义,我们没有构建过这个模块,也不替它下结论,请以 tsdown 官方文档和你本地构建后 dist/ 的实际内容为准。这里只记录一个事实:仓库里同时存在指向 .js 与指向 .mjs 的启动写法,而构建配置显式开了 fixedExtension

配置里另外两点顺带记一下:clean: true 表示构建会清目录;deps.neverBundle 把所有 node: 内建以及 package.json 里声明的依赖全部排除出 bundle(MemoryKnowledge/tsdown.config.ts:12-29)。

你自己怎么核这一处

这一段是可执行的判定动作,不需要任何推断:

  1. 先确认你走的是哪条启动路径。pnpm/npm 的 bin(knowledge-server)起,走的是第 2 处;用官方 Dockerfile 起,走的是第 3 处;用 deploy/panel-knowledge-combined/ 那套合并镜像起,走的是第 4 处。三条路径读的是不同的文件,不要混着看。
  2. 构建完直接列目录。MemoryKnowledge/ 下执行构建后,看 dist/ 里到底是 server.js 还是 server.mjs(顺带看 dist/mcp/ 下那个)。这是唯一能一锤定音的动作,比读任何一处文档都直接。
  3. 比对上面那张表的四行原文。 打开这四个文件的对应行号,确认在你手上的版本里它们是否仍然不同——版本在变,差异可能已经不在了。
  4. 注意镜像里没有宿主机的 dist。 MemoryKnowledge/.dockerignore 的 1-11 行把 *.mddocs__tests__*.test.tsdistcoverage 等排除在构建上下文之外,按 .dockerignore 的语义,你本地已有的 dist/ 不会被带进镜像。所以在容器里核产物名,要在容器内部核,不能拿宿主机的结果去推。

顺带一提:MCP 那个入口是同一个模型

这个模块有两个可执行入口。除了 HTTP 服务,还有一个走 stdio 的 MCP 进程:bin/mcp.mjs 同样只有两行,第二行是 import "../dist/mcp/server.js";。而 tsdown.config.tsentry 数组里的第二项正是 ./src/mcp/server.ts。也就是说,两个入口共用同一份构建配置,产物扩展名这件事对它们是同一件事——你核 dist/server.* 的时候,顺手把 dist/mcp/server.* 一起核了,成本是零。

MCP 进程还有个独立的配置面:转发地址 KNOWLEDGE_API_URL 默认 http://localhost:8421,可选 KNOWLEDGE_API_TOKENMemoryKnowledge/src/mcp/server.ts:94-95)。这跟启动文件名没关系,只是提醒你别把两套环境变量搞混。

什么情况说明你碰到的不是这件事

排查文章最该写清楚的是边界。以下这些现象,不是由构建产物文件名引起的,别往这条线上排:

  • 服务起来了但端口不对。 这个模块自己的默认端口是 8421——MemoryKnowledge/README.md:6src/config.ts:150Dockerfile:78docker-compose.yml:19 都是 8421;而仓库根 INSTALL.md:58 的端口表写的是 8424,deploy/global-images/.env.example:50 里的变量是 KNOWLEDGE_PORT=8424。这是另一处口径差异,与文件名无关。
  • 依赖装不上或原生模块编译失败。 MemoryKnowledge/start.sh 那 80 行里有手工编译 better-sqlite3 的步骤,还写死了若干本机路径;这属于依赖构建,不是入口文件名。
  • 接口返回 400。 每个 handler 都要求请求头带 x-tdai-service-idMemoryKnowledge/src/api-helpers.ts:12),缺了就 400。服务本身是起着的。
  • 调 LLM 报错说缺 key 或 baseUrl。 ingest-v2/llm.ts:51-53 明确写了缺 apiKeybaseUrl 直接抛错、不再兜底读 process.env。这也是运行期的事。

反过来,如果你看到的是「node 报找不到模块 / 找不到文件」,而且报的那个路径正好是 dist/server.jsdist/server.mjs 其中之一,那才落在本文说的这条线上——此时按上面第 2 步列一次 dist/ 就能对上。

这类差异该怎么读

最后说个方法论,不是对这个项目的评价。

在一个还在 beta、默认分支是 feat/server_team 这种功能分支的仓库里,同一件事在不同层写法不同是能遇到的:这个模块里还有端点数(规格自称 28 条,代码在 /v3 下注册了 37 条)、默认模型名(Memory-Modelgpt-4o-mini 等多处不同)、LLM_MAX_TOKENS 默认值(src/config.ts:165 是 32768,ingest-v2/llm.ts:45 是 8192)几处同类差异。这些我们另有篇目专门讲。

对读者来说,可迁移的只有一条:文档里写的、配置里写的、和你机器上真实存在的文件,是三件事。 遇到对不上的时候,别急着挑一个信,去做那个能一锤定音的动作——列目录、看进程实际执行的命令行、在容器内部核。这一步做完,四处写法谁对谁错就不用猜了。

延伸阅读


本文依据 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?报名体系课或加入会员,照着学、照着用。