致知录
第 XXXIII 卷 · 第 06 篇 · gbrain · 1970.01.01

检索(下):图谱与矛盾探针

gbrain 工具拆解 · 1970.01.01 · 12 分钟阅读 · 2,857 字
目录 · 7
gbrain 怎么从你写的链接自动织网、又怎么帮你揪出前后矛盾的观点——以及为什么这么设计

第 4 课讲混合检索(关键词 + 向量)。本课讲 gbrain 检索的两个「增值层」:知识图谱矛盾探针。但我不想按「gbrain 有什么函数」来讲——那样你读完还是不知道自己该怎么用、以及造自己的工具时该抄什么。所以本课始终从两个立场讲:你作为用户要做什么、gbrain 自动替你做什么;以及作为架构师,这些设计背后的决策是什么、为什么值得抄。

一、图谱:你写链接,gbrain 自动织网

你作为用户只需要做一件事:写笔记时,用 markdown 链接把相关笔记连起来。gbrain 认两种写法:

[特斯拉](companies/tesla)        # 标准 markdown 链接,指向另一篇笔记的路径
[[苹果公司]]                     # Obsidian 风格双括号,指向同名笔记

gbrain 自动替你做的事:它扫描你所有笔记,把「A 提到 B」织成一张网(A→B 一条边)。你完全无感——不用建图、不用标注、不花一分钱 LLM 成本。它用的是确定性正则extractEntityRefs)扫你写下的链接语法,连代码块里的内容都自动排除(不会把代码示例当链接)1

为什么这么设计(架构师视角):gbrain 完全可以像很多知识工具那样,用 LLM 去「抽取实体、自动建图」。但它刻意不这么做。理由是 LLM 抽实体慢、贵、而且每次结果可能漂移(同一段文字今天抽出一个实体、明天抽不出)。而「用户写链接」是一个免费、稳定、用户已经自愿提供的结构信号——你写 [特斯拉](companies/tesla) 时,网络结构就已经在文字里了,gbrain 只是读出来。可抄点:如果你造自己的工具,优先利用用户已有的书写习惯做结构提取,别急着上 大模型(LLM);LLM 该用在「用户没提供的信号」上,而不是去重新发现用户已经明写的东西。

图谱给你什么能力:当你检索「特斯拉」,gbrain 不只做关键词/向量匹配,还能顺着网跳到相邻笔记(比如你写特斯拉时链了「电池供应链」那篇,就能把那篇也带出来)。这是普通搜索做不到的「顺藤摸瓜」。图谱是 markdown 之上的派生结构,重建 brain 时随 markdown 一起重生——它永远是「缓存」,不是「事实源」2

一个必须厘清的概念:链接 ≠ 实体。 你之前纠结过这俩是不是一回事,答案是不是,而且这是造工具时最容易混的两个维度:

  • 链接(link)= 你主动写的 [名字](路径);gbrain 还会读链接周围的动词,把这条边标成带类型的关系works_at / invested_in / founded / advises / mentions),而非无类型的「页连页」3
  • 实体(entity)= gbrain 用另一套机制(NER)从正文文字里抠出来的真实对象,比如「苹果公司」「马斯克」,标成 person / company 类型;而且高频实体它还会自动建一篇空笔记 + 反向链接extractEntities → enrichment-service)4。 所以:链接是你写的语法,实体是 gbrain 从正文识别的对象。两套结构、两个维度。你做工具时若把二者混为一谈,图谱和实体索引会互相污染。

二、矛盾探针:gbrain 帮你揪出前后打架的观点

你作为用户遇到的真实痛点:投资笔记里常有前后冲突的观点——1 月写「Q1 看空特斯拉」,9 月写「Q3 看多特斯拉」。普通搜索你一检索,两篇都蹦出来,得自己在脑子里判断「哪个还作数」。gbrain 的矛盾探针专干这事:它找出你知识里「检索时会被一起召回、但观点可能打架」的配对,让 LLM 判断是不是冲突,把可疑的标出来给你复核

命令是你主动跑的:

gbrain eval suspected-contradictions --query "特斯拉" --top-k 5   # 针对某个主题跑一轮
gbrain eval suspected-contradictions trend --days 30              # 看 30 天趋势
gbrain eval suspected-contradictions review                       # 交互式逐条复核最近一轮发现

gbrain 不替你自动跑——这是关键,也是我之前讲错的。全仓搜不到任何 定时任务(cron) / scheduler 调它;它是纯手动命令,或你的 agent 经 MCP 接口协议(让 agent 连上 brain 的标准协议)(find_contradictions)按需调用。而且 gbrain doctor(健康体检)会提醒你「你 7 天没跑探针了,去跑一下」——这反证它不是后台自动的5为什么 gbrain 不默认自动跑(架构师视角):探针要烧 LLM 钱(judge 判每对配对)。如果默认自动、无端天天跑,你的 向量化(embedding)/LLM 账单会悄悄膨胀。gbrain 把控制权留给你——你决定什么时候跑、跑哪些主题、花多少预算(--budget-usd 封顶)。它只提供「让你能挂自动」的钩子(比如 cron 每天跑 gbrain dream 那种方式),但绝不偷偷自己跑

探针怎么标、标出来你在哪能看到

  • 命令行直接打印:哪些页 HIGH 级冲突、冲突维度、给一条 resolution_command 修复命令。
  • review 子命令:交互式看最近一轮发现,逐条复核。
  • gbrain doctor 面板:把最近一次跑批结果读出来,HIGH 冲突直接列在体检报告里[^contra-体检命令(doctor)]。
  • 你的 agent(MCP find_contradictions:对话中随时能查「我 brain 里关于特斯拉有什么矛盾」。

为什么这么设计(架构师视角,几个值得抄的决策)

  1. 采样检索配对,而非全量两两比对。N 篇笔记两两比对是 N² 爆炸。gbrain 的做法是:先跑 hybridSearch,对「会被一起召回」的配对才送 LLM 判——把成本压到可承受6可抄点:做质量自检别全量跑,借检索的「什么会被一起召回」来定位可疑对,成本随检索规模线性增长而非平方增长。

  2. date pre-filter:>30 天不算矛盾。两篇都带明确日期、且相差 >30 天,探针默认跳过——它假定「1 月看空、9 月看多」大概率是观点随时间正常演化,不是真打架。但这个规则有精妙的保护:任一方缺日期不跳(让 judge 决定);同一段话里先说看空再说看多(flip-flop)也不跳——这种才是真问题,照样标7可抄点:时间维度是矛盾判定的关键上下文,别把「时间演进」误判成「bug」;但同一时空内的自我打脸必须抓得住。

  3. 判定分细类,不是二元。verdict 不是简单「矛盾/不矛盾」,而是:contradiction(同时点的真冲突)/ temporal_supersession(新观点取代旧观点,不是错误)/ temporal_regression(指标倒退)/ temporal_evolution(合理演进)/ negation_artifact(judge 误读否定词)/ no_contradiction。你一眼能分清哪是真问题、哪只是时间推移[^contra-判定结论(verdict)]。

  4. 持久缓存 + prompt_version 版本化。每对配对的 judge 结论存进缓存表,key 含 chunk hash + model_id + prompt_version + truncation_policy——判定逻辑(prompt)一变就自动 miss、重判,保证「当时为什么这么判」可追溯到具体版本8可抄点:任何 LLM 评判都要缓存 + 版本化,否则结果不可复现、问题无法追溯。

  5. 它只标不改。探针给的是 resolution_command(修复命令),最终判断权和修改权在你——gbrain 不替你删笔记、不替你合并观点9。这是「AI 监督者」定位的体现:机器负责发现,人负责决断。

三、eval run-all 与 compare:检索质量可量化

检索本身也有量化闭环:gbrain eval run-all 跑全套评测,gbrain eval compare 对比两次运行(baseline vs 当前策略)10。这让「我改了检索逻辑到底变好还是变坏」可测量,而非凭感觉——架构师视角:任何检索/排序改动都应配可回归的评测,否则你永远不知道一次「优化」是真优化还是把某些查询搞坏了。

四、能力边界(监督者须知)

  • 矛盾探针不自动跑:要你手动触发或自己挂 cron;不挂就永远不跑,doctor 只会提醒你。
  • 图谱零成本自动织:只要你用链接语法写,gbrain 无感建图;你不写链接,就没有图可跳。
  • 实体(NER)和链接是两回事:实体是正文识别的对象,链接是你写的、带类型的边;造工具时别混。
  • 探针标的是「可疑」不是「定论」:给修复命令,不自动改;最终判断权在你。
  • 成本是你可控的--budget-usd 封顶,不跑则不花钱;gbrain 不会无端烧钱。

练习题

1

gbrain 的图谱(带类型的边 works_at/invested_in 等)主要靠什么建立?

2

在 gbrain 里,「链接」(你写的 [名字](路径))和「实体」(NER 抽出的 苹果公司/马斯克)是什么关系?

3

矛盾探针(suspected-contradictions)是 gbrain 后台自动跑的吗?

4

1 月写「看空特斯拉」、9 月写「看多特斯拉」,矛盾探针大概率怎么处理?

5

矛盾探针标出冲突后,gbrain 会怎么做?


参考出处

Footnotes

  1. 代码 src/core/link-extraction.tsextractEntityRefs:先 stripCodeBlocks 去代码块,正则匹配 markdown 链接 [Name](path) 与 Obsidian 式 [[path]] / 裸 slug;代码块内 slug 排除;addLinksBatchlinks 表)。零 LLM 成本、确定性。

  2. 文档 docs/architecture/system-of-record.md §「System of record」(图谱是 markdown 之上的派生结构,重建 brain 时随 markdown 重生;与第 1 课「DB 是派生缓存」一致,图谱也是缓存非事实源)。

  3. 代码 src/core/link-extraction.tsextractEntityRefs 抽取 markdown 链接后,用正则 WORKS_AT_RE/INVESTED_RE/ZH_INVESTED_RE 等匹配链接周围的动词上下文,把边推断为 works_at/invested_in/founded/advises/mentions;优先级 founded > invested_in > advises > works_at > mentions;零 LLM 调用,与 README 所述 typed-edge graph 为同一机制)。

  4. 代码 src/core/enrichment-service.tsextractEntities 用正则从正文抠出 person/company 命名实体,按 Inc/Corp/Labs 等后缀粗分类;高频实体由 enrichment-service 自动建页 + 反向链接)。与 link-extraction 由链接上下文推断出的「带类型边」是两套独立结构(前者来自正文 NER,后者来自你写的链接语法)。

  5. 代码 src/commands/eval.ts + src/commands/eval-suspected-contradictions.ts(矛盾探针是手动子命令,全仓无 cron/scheduler 调它;src/commands/doctor.ts:8166 提示「No probe runs in the last 7 days. Run gbrain eval suspected-contradictions …」反证非自动);src/core/operations.ts:4452 经 MCP find_contradictions 暴露给 agent 按需调。

  6. 代码 src/core/eval-contradictions/runner.ts(先 hybridSearch 取每 query 的 top-K 召回,对「会被一起召回」的配对才送 LLM judge;pair 数 = queries × min(topK(topK-1)/2+topK, 50),成本随检索线性而非 N²)。

  7. 代码 src/core/eval-contradictions/date-filter.tsDATE_SEPARATION_DAYS=30;规则:两 chunk 都带显式日期且相差>30天→SKIP;任一方缺日期→不跳(judge 决定);同一段含两个不同日期(flip-flop)→不跳。保守偏 false-negative,宁可多烧 token 不漏真矛盾)。

  8. 代码 src/core/eval-contradictions/cache.tsbuildCacheKey 含 chunk hash + model_id + prompt_version + truncation_policyPROMPT_VERSION 一变即 miss 重判,verdict 存 eval_contradictions_cache 表,结果可复现可追溯到判定版本)。

  9. 代码 src/core/eval-contradictions/auto-supersession.tstypes.ts(每发现带 resolution_command 修复命令,gbrain 不自动删/改笔记,判断与修改权留给人)。

  10. 代码 src/commands/eval.tsrun-alleval-run-all.tscompareeval-compare.ts;BaselineStrategy 调 hybridSearch 作基线对比,使检索改动可回归测量)。