摘要
1795条、近千万字的AI知识库没上向量库,只有SQLite+FTS5。本文复盘一晚连修四个治理真问题:字段零填充、共识不落库、90天一刀切自否、Navicat三连抓包,附入库闸门代码与六条可抄清单。

10 月 11 号晚上,我和军师本来只是闲聊。军师是我的 AI 总架构师,基于 Kimi Code,给我那支数字员工团队出主意、定规矩、盯执行。聊着聊着,话题收敛到一个判断:配置体系、知识库、记忆体系,表面是三件事,实际上是同一件事,AI 的记忆问题。
我的知识库 kb 是自研的,SQLite 文件库加 FTS5 全文检索,1795 条、近 995 万字,没有向量检索。这一晚没聊出什么新架构,倒是连查出四个真问题,当场全修了。
不上向量库,不是省钱,是判断
不上向量库的理由一句话:1795 条、近千万字的库里,SQLite 加 FTS5 毫秒级返回,离极限差着两个数量级,向量检索没有要解决的问题。
当时我们的家底是这样的:
| 指标 | 数值 |
|---|---|
| 条目数 | 1795 条 |
| 总字数 | 近 995 万字 |
| 库文件 | 87.9 MB |
| 检索引擎 | SQLite FTS5(trigram 分词) |
| 向量检索 | 没有 |
要不要上向量库,这个问题我们前后讨论了三遍,结论都是维持原状。理由不是省钱,是一个更底层的判断:战略层的知识,根本不需要大数据库。一个董事长做一个值钱的决策,依据的不是海量语料,是几张纸。我自己这套系统就是实证,全部战略级内容就是一页态势纸,64 行,加一份章程,127 行,就这么多。
真正会膨胀的是工具文献类的固有知识,那类东西的作用是查询,要求是信息精准、检索准确,不是语义联想。所以路线是分级分类存储、分场景调用,而不是堆一个更大的库。
但不上向量库,不等于没问题。
第一坑:五个治理字段,填充数 0/1784

entries 表早就预留了五个治理字段:document_class(文档分类)、confidence(可信度)、valid_until(有效期)、source_url(来源)、fetched_at(采集时间)。我打开 Navicat 一看:
bash
document_class 已填: 0 / 1784
confidence 已填: 0 / 1784
valid_until 已填: 0 / 1784
source_url 已填: 0 / 1784
fetched_at 已填: 0 / 1784
五个字段,全军覆没。根因很快查到:索引器 sync() 只从 front matter 里取 title、category、tags,根本没读这五个字段。字段是死字段,闸门从来没运转过。
修法不是提醒大家记得填,是机器闸:不填就不许入库。
入库闸门:跑在代码里,不是写在文档里
闸门函数全文贴出来,可以直接抄:
bash
def ingest_gate_check(path: str, meta: dict) -> str | None:
"""入库闸门:返回拒收原因,放行返回 None。"""
dclass = str(meta.get("document_class") or "").strip()
vu = str(meta.get("valid_until") or "").strip()
if dclass and dclass not in VALID_DOCUMENT_CLASSES:
return f"document_class 非法值 {dclass!r}(可选: decision/canon/timely)"
if dclass == "timely" and not vu:
return "timely 条目必须填 valid_until(YYYY-MM-DD)"
if path.startswith(CANON_DIR_PREFIX) and dclass != "canon":
return "常识库分区条目必须标 document_class: canon"
return None
分类只设三档,多了没人记得住:
| document_class | 内容 | valid_until |
|---|---|---|
| decision | 战略决策、裁定(常青) | 不填 |
| canon | 常识经典、基础概念(常青) | 不填 |
| timely | 会过时的时效信息 | 必填 |
上闸当天我故意丢进去三个违规文件:缺分类的、timely 缺有效期的、分类拼错的。三条全部被拒收,拒收原因逐条正确;合规文件正常入库。闸门这东西,写在文档里是给人添堵,跑在代码里才算数。
第二坑:会上拍板的规矩,章程里零命中
这个坑我个人觉得最典型。10 月 9 号我们开会定过一条规矩:任务卡发出前,AI 必须先复述三行,干什么、验收标准、动哪些文件,我过目了才发。当场拍板,从建议升级为硬闸。
10 月 11 号我抽查,在开发团队的章程文件里 grep 复述和三行,零命中。这条闸只活在会议记录里,而执行干活的 AI 实例读的是章程文件。对它来说,这条规矩从来没存在过。
这暴露的是入库时机问题。定下来的触发器有三个:共识达成,聊天中确认以后就这么干,当场落成规则文档入索引;拍板冻结,态势纸一行状态加台账详情加 kb 可检索,三处落点缺一不可;外部采集,入库时当场填齐治理字段,填不齐不入库。
一句话:只活在会话里的共识,等于没共识。
第三坑:90 天一刀切,被我自己否了
第一版方案里,时效类条目有效期默认 90 天。我当场把这个设计否了。不同内容衰减速度根本不一样:模型价格 30 天就过期,Python 语法十年不变,项目计划不按日期过期,它是被新决定取代的。
更要命的是维护成本。定时批量给 1800 条存量做回源核验,里面 90% 的条目一年没人查一次,为它们做核验是纯浪费。
改成触发式核验:谁检索命中,谁看这条的采集时间和有效期;可疑才回源核验;验完必须回填,有效就刷新有效期,失效就作废。作废操作很轻,把 front matter 里 valid_until 改成过去日期,检索结果立刻标上已过期。
定时任务只保留零成本的曝光:kb stats 报过期条数,一句 SQL 查询,不占任何模型调用。
第四坑:Navicat 三连抓包
SQLite 是文件库,没有账号密码,我直接用 Navicat 直连 .db 文件抽查,连抓三个。
一是日期格式不统一。1775 条是 2026-10-11 这种标准格式,混着 20 条早期导入的紧凑格式 20260424。
二是 created_at 只写不更新。sync 的 UPDATE 语句漏了 created_at,就算把源文件改了,库里也不跟着改。文件即真相源的原则,破了个洞。
三是时间精度只有天。我干了三十多年开发,不能接受这个。同一天上午下午晚上三轮修改,天粒度连先后顺序都排不出来,出了问题要排查,没有时间线怎么查。
军师的回应是当晚全部修掉:时间精度升到秒级 ISO;时间来源定优先级,front matter 带时分就采用,只有日期就拼接文件系统真实时刻,文件不会撒谎;文件日期和 front matter 对不上时,整条信文件;存量 1795 条全部回填,非标格式清零;回归测试 13 个用例全过。
还有个小插曲。查询日志它第一版写成了 jsonl 文件,我问了一句,都上数据库了为什么还用文件记日志。它改成了库里的 query_log 表。遥测数据的消费者是库内查询,就该进库。顺手用文件是肌肉记忆,不是设计。
记忆隔离:不靠更大的上下文,靠分级按需调用

很多人做 Agent 记忆,第一反应是把更多东西塞进上下文。我的做法相反,记忆隔离靠分类检索,按需调用:
| 层 | 载体 | 加载方式 | 上下文占用 |
|---|---|---|---|
| L0 章程层 | AGENTS.md | 每会话自动注入 | 恒占,<200 行硬预算 |
| L1 岗位层 | 岗位 agent.md + 技能 | 岗位激活时加载 | 按需 |
| L2 文档层 | docs/(SOP/台账/登记册) | L0 一行指针,按需读 | 按需 |
| L3 检索层 | kb.db(FTS5) | 查询制,不自动加载 | 零 |
| L4 冷归档 | _archive | 不检索不加载 | 零 |
战略层住 L0 和 L2,就那一屏纸;知识层住 L3,查的时候才进门;垃圾住 L4,永不见面。每个 Agent 实例只看到它岗位该看的,这就是隔离。不需要向量相似度,需要的是分类纪律。
配套的配置治理一个思路:配置文件分 P0、P1、P2 三级管控,登记册在册 146 件;AI 写配置的三大毛病,记流水账、滥用绝对禁词、小毛病就加枷锁,用 lint 脚本机器闸卡死,违规不落盘。之前一轮治理把 108 条负向禁令改写成正面模板,禁令只留给有故障台账证据的红线,其余一律写应该怎么做。
调用侧也补了埋点:每次检索落 query_log 表,时间、查询词、命中数。一个月后哪些场景在查、哪些词查不到,用数据说话,不靠感觉。
这套做法搬进公司,值多少
这套东西不挑规模,搬进公司业务系统换算很直接:入库闸门拦下的每一份缺字段文档,省的都是将来排查事故的工时;定时普查改触发式核验,1800 条存量里 90% 一年没人查一次,核验成本直接砍掉;SQLite 文件库直连 Navicat 抽查,AI 报一百遍已验证,不如自己进去看一眼,这是人对 AI 最便宜的审计通道。
一小时收工:7 个 commit,测试从 9 涨到 13
这一晚的全部改动落在 7 个 git commit 里,21:55 到 22:51,不到一小时:入库闸门、触发式核验、调用埋点、时间精度升级、存量迁移。pytest 从 9 个用例涨到 13 个,全绿。
回到标题的问题:AI 知识库一定要上向量库吗?我的答案是,检索精度的问题用分类和闸门解决,语义联想的需求等常识库建起来再评估。sqlite-vec 混合检索方案在候排里躺着,但它的启动条件是第一批常识条目入库,不是感觉库大了。
战略层几页纸,知识层按需查,垃圾层不见面。小而准,比大而全值钱。
六条可以直接抄的清单
- 先审计再建设:打开你的库,跑一句
SELECT COUNT(*) FROM entries WHERE document_class IS NULL,治理字段零填充的,先修索引器再谈别的; - 入库闸门代码化:非法分类、缺有效期的文件,拒收比提醒管用一万倍;
- 共识三处落点:章程一行、台账详情、可检索库,只活在会话里的共识等于没共识;
- 新鲜度触发式核验:谁用谁验、验完回填,定时只曝光不普查;
- 时间用秒级 ISO,来源优先级:front matter 优先,其次文件系统真实时刻;
- SQLite 文件库直连 Navicat 抽查,人对 AI 最便宜有效的审计通道,没有之一。
常见问题(FAQ)
不上向量库,语义搜索怎么办? 目前 kb 里战略级内容就一页态势纸加一份章程,工具文献类要的是关键词精准命中,FTS5 够用。语义联想的需求等常识库第一批条目入库再评估,sqlite-vec 混合检索在候排里躺着。
1795 条存量回填,工作量多大? 这次改的是索引器和闸门逻辑,存量回填只做了时间字段,脚本跑一遍,非标格式清零。document_class 这类需要判断的字段走触发式,谁用谁补,不搞全员普查。
SQLite 撑得住更大的库吗? 现在 FTS5 毫秒级返回,离 SQLite 的极限差着两个数量级。真到撑不住那天,先动的也是分级归档,把冷数据挪进 _archive,而不是急着换引擎。
AI 定的规矩,怎么保证后续实例执行? 三处落点:章程一行、台账详情、kb 可检索。只发在会话里的规矩,干活的实例读不到,等于没定。这条是被零命中抽查教育出来的。
我是野生码农,AI实战派。17年全栈工程师,一人AI公司实践者。打造个人IP内容体系、软件全链路产品产线,拥有百套企业AI方案、200多个岗位Agent;自研知识库、AI数字员工系统,公开实战复盘。
本文所有内容均为本人 AI 实战的过程和结果,经 AI 整理后发布,无任何瞎编虚构内容。
这篇来自《AI员工团队》系列。
关注我,看真的。
野生码农AI实战 · 全网同名