TencentDB Agent Memory 三处都写 4 张表,实际建了 5 张
如果你打算读懂 TencentDB Agent Memory 里 MemoryKnowledge 这个模块的数据层,最省事的入口通常是 src/db/schema.ts 的头注释——它会直接告诉你有几张表、分别干什么。这一次这条捷径会把你带偏一点点:注释写的是 4 张,文件里定义的是 5 张。
下面的内容全部基于该仓库 feat/server_team 分支上的快照(这个仓库的默认分支就是 feat/server_team,不是 main 也不是 master,贴路径、贴 raw 链接时要注意这一点)。MemoryKnowledge/package.json 里这个模块的包名是 @tencentdb-agent-memory/knowledge-service,版本还是 0.1.0,整仓处于 beta 阶段,下面提到的字段名与默认值随版本变动。
三处「4 张表」分别在哪一行
先把三处位置摆出来,方便你自己去仓库里对:
| 位置 | 原文口径 |
|---|---|
MemoryKnowledge/src/db/schema.ts:2-8 | 头注释写 4 SQLite tables for knowledge metadata,并逐条列出四张 |
MemoryKnowledge/src/db/client.ts:46 | migrate() 上方注释写 for all 4 tables + indexes |
MemoryKnowledge/.env.example:13 | 写「SQLite 数据库路径(4 张表:knowledge_wiki / knowledge_code_graph / *_audit)」 |
注释里列的那四张分别是:knowledge_code_graph(代码仓索引的元数据与状态)、knowledge_wiki(wiki 知识库的元数据与状态)、knowledge_wiki_audit(wiki 状态变更的追加式审计日志)、knowledge_code_graph_audit(code-graph 侧的同款审计日志)。这四张确实存在,头注释对它们的描述也和后面的定义对得上。
顺便记一处很容易被当成笔误的设计:这两张业务表的 status 默认值不一样。knowledge_code_graph.status 默认是 pending,knowledge_wiki.status 默认是 draft。源码注释解释了这个差异——draft 表示「壳建好了但还没加工」,只在 create 的那一次出现;而 code-graph 是 create 即开始建图,所以直接进 pending(MemoryKnowledge/src/db/schema.ts:69-70)。状态枚举本身也分两套:SyncStatus 是 pending | processing | ready | failed,WikiStatus 则是 SyncStatus 再加一个 draft(MemoryKnowledge/src/store/types.ts:18,26)。两张表看着对称,默认值不对称是有注释交代的。
问题出在同一个文件继续往下读:MemoryKnowledge/src/db/schema.ts:131-139 又定义了第五张表 llm_binding。client.ts 那边同样如此——注释说「4 tables」,而 migrate() 的函数体里一共有 5 条 CREATE TABLE IF NOT EXISTS,第五条就是 llm_binding(MemoryKnowledge/src/db/client.ts:143-152)。
按写「不一致」的规矩,这里只陈述差异:注释与 .env.example 写的是 4,schema 定义与运行时建表 SQL 是 5,以我们实读的仓库状态为准。为什么没同步、哪个才是「本意」,我们不推断,也不用它去评价这个项目。
你可以怎么自己核一遍
这类差异最怕的是转述一遍变成新的传言,所以给两个可执行的判定动作,不需要装任何东西、不需要跑服务:
- 打开
MemoryKnowledge/src/db/schema.ts,按行号把表定义逐段数下来:knowledge_code_graph在 18-51 行、knowledge_wiki在 55-88 行、knowledge_wiki_audit在 92-106 行、knowledge_code_graph_audit在 110-124 行,第五段llm_binding在 131-139 行。而位于文件最上方的那段头注释在 2-8 行,它列出来的只有前四段。顺便往下翻到 149-151 行,那里还有两个被注释标为「保留字段」的常量CODE_DATA_VERSION与WIKI_DATA_VERSION,值都是 0。 - 打开
MemoryKnowledge/src/db/client.ts,migrate()的函数体是 50-153 行那一整段手写 SQL,数一数里面的CREATE TABLE IF NOT EXISTS:建llm_binding的那一条在 143-152 行,正好落在 46 行注释所说的「4 tables」之外。
两处都数完,你就不必依赖任何人的转述了。顺带确认一下自己看的是哪个库文件:这个服务级 SQLite 的路径由 KNOWLEDGE_DB_PATH 决定,代码里的默认值是 ./data/knowledge.db(MemoryKnowledge/src/config.ts:152),drizzle.config.ts:4-9 里 dbCredentials.url 读的也是同一个环境变量、同一个回退值。建库时会设 journal_mode = WAL 与 busy_timeout = 5000(MemoryKnowledge/src/db/client.ts:32-34),这些都是代码里写死的默认值,不代表运行起来会是什么表现。
第五张表 llm_binding 是什么
它不是知识资产本身,而是这个服务实例(按 service_id 维度)该把 LLM 请求发到哪儿的路由记录。Drizzle 侧的字段是这些(MemoryKnowledge/src/db/schema.ts:131-139):
| 字段 | 类型 | 约束 / 默认 |
|---|---|---|
service_id | text | primary key |
mode | text | not null,默认 proxy |
proxy_base_url | text | 可空 |
api_key | text | 可空 |
base_url | text | 可空 |
enabled | integer | not null,默认 1 |
updated_at | text | not null |
MemoryKnowledge/src/db/schema.ts:126-129 的注释解释了两种 mode 的含义:mode='proxy' 时调 context_proxy,并带一个专用的 knowledge-service user_key;mode='byo' 时调用户自带的 OpenAI 兼容端点。
顺带说一处措辞:模块自身的全局配置里,LLM_MODE 默认值是 proxy,且只认 custom 这一个值来切换(MemoryKnowledge/src/config.ts:159);而上面那段表注释里写的另一种模式叫 byo。两处位置、两个词,摆在这里,你读代码时别把它们当成同一个字符串去比较。
这张表和请求路径的关系在 MemoryKnowledge/src/store/llm-binding-store.ts:146-185 的 resolveLlmConfig() 里:没有可用 binding 且全局是 custom 时,原样返回全局配置;没有可用 binding 而全局是 proxy 时,返回一份把 baseUrl 与 apiKey 清空的配置,让上层 createLlmClient 直接抛错——同一处注释写的是 no silent direct fallback(151-157 行)。proxy 模式下最终的 baseUrl 拼法是 {proxy_base_url}/proxy/{service_id}/v1(167 行)。
对外操作这张表的是三个内部端点 /set、/status、/list(MemoryKnowledge/src/routes/llm-binding.ts:40,95,103),挂载点是 /v3/internal/llm-binding(MemoryKnowledge/src/server.ts:86)。同文件 15-17 行的注释明写这组路由没有加额外的鉴权层,理由原文是它像该服务的其它路由一样信任内部网络。这张表里有 api_key 列,两件事放在一起,是你在评估部署方式时要自己掂量的部分。
同一张表,字段在两层也对不上
既然已经翻到这儿,再记一处:llm_binding 在 Drizzle schema 里没有 model 列(字段就是上表那七个),而 MemoryKnowledge/src/db/client.ts:143-152 的运行时建表 SQL 里,第 148 行写着 model TEXT。与此同时,MemoryKnowledge/src/store/llm-binding-store.ts:16-17 的注释写的是:model 不按实例存储,它总是来自全局的 LLM_MODEL 环境变量。
三处位置说完,就停在这里。
为什么这条值得单独记一笔:这个模块的表结构存在两条并行的来源。MemoryKnowledge/drizzle.config.ts 指定了 schema: "./src/db/schema.ts"、out: "./src/db/migrations",package.json:18-19 也有 db:generate / db:migrate 两个脚本走 drizzle-kit;但运行时建表并不走 drizzle-kit,走的是 client.ts:50-153 那段手写的原生 SQL,之后再用 addColumnIfMissing() 按 PRAGMA table_info 补列(157-163 行,补的是 knowledge_code_graph 与 knowledge_wiki 的 service_url / summary,以及两张 audit 表的 service_id)。另外,drizzle.config.ts 里 out 指向的 ./src/db/migrations 目录在我们采集的这份快照里并不存在——MemoryKnowledge/src/db/ 下只有 client.ts 和 schema.ts 两个文件。
所以当你看到某个字段「schema 里有 / 没有」时,先确认自己看的是哪一条来源。
什么情况说明你遇到的不是这件事
- 你数出来的四张表叫
wiki_fts/page_meta/graph_edge/source:那是另一套。这个模块还有一层「每个 wiki 一个独立 SQLite 文件index.db」的设计,与正文.md同目录同生命周期,承载的正是这四张表(MemoryKnowledge/src/engines/wiki/index-db.ts:3-9,建表在 72-119 行)。那一层的「四张」是对得上的,别和服务级库的表数混在一起。 - 你在看的是别的模块:本文只覆盖
MemoryKnowledge/。同仓的MemoryCore/MemoryPanel/MemoryProxy各有各的数据层,我们这次没有核,不做任何延伸。 - 你手上的库是历史数据:
migrate()用的是CREATE TABLE IF NOT EXISTS加按需补列,一个更早建出来的库文件里有几张表、有没有model列,取决于它当初是被哪个版本建的。这属于你自己那份文件的状态,不是文档口径问题。
最后一句用来收住:这类「注释里的数字」和「代码里的定义」对不上的地方,在这个仓库里不止一处(端点数、端口、默认模型名都有类似情况)。读这种还在快速变动的项目,把注释当索引、把定义当事实,比争论哪个是对的更省时间。
延伸阅读
- 从头读起:TencentDB Agent Memory 是什么:团队级 Agent 记忆中枢怎么读
- 本专题共 40 篇,完整分组目录见专题页
- TencentDB Agent Memory 的 OpenAPI:自称 28 个端点,代码 37 条
- TencentDB Agent Memory 的 llm_binding 表:schema 与建表 SQL 两套
本文依据 TencentDB Agent Memory 官方仓库(github.com/TencentCloud/TencentDB-Agent-Memory)
feat/server_team 分支上的 README、INSTALL、CHANGELOG、ROADMAP 与四个模块的源码整理,
核对日 2026-08-16,对应仓库快照 97f9465。该仓库的默认分支即为 feat/server_team。
本文内容为仓库源码与文档口径,我们没有部署、也没有运行过该项目的任何一个模块,
因此不涉及运行效果、检索质量与性能的任何描述。
该项目主模块处于 beta 阶段、其余模块版本号仍为 0.1.0,参数与接口随版本变动,请以仓库最新内容为准。
该项目会采集并存储团队的对话、文档与代码,属于敏感数据,是否使用请结合自身合规要求评估。
安全与合规相关做法请结合自身环境评估,本文不构成安全方案建议。