<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>Yin</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <id>https://yrb127ing.ccwu.cc/</id>
  <link href="https://yrb127ing.ccwu.cc/" rel="alternate"/>
  <link href="https://yrb127ing.ccwu.cc/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, Yin</rights>
  <subtitle>愿每一次都有回响</subtitle>
  <title>Yin 的小站</title>
  <updated>2026-10-21T07:03:37.906Z</updated>
  <entry>
    <author>
      <name>Yin</name>
    </author>
    <category term="技术" scheme="https://yrb127ing.ccwu.cc/categories/%E6%8A%80%E6%9C%AF/"/>
    <category term="知识图谱" scheme="https://yrb127ing.ccwu.cc/tags/%E7%9F%A5%E8%AF%86%E5%9B%BE%E8%B0%B1/"/>
    <category term="规范判定" scheme="https://yrb127ing.ccwu.cc/tags/%E8%A7%84%E8%8C%83%E5%88%A4%E5%AE%9A/"/>
    <category term="推理" scheme="https://yrb127ing.ccwu.cc/tags/%E6%8E%A8%E7%90%86/"/>
    <content>
      <![CDATA[<h2 id="起点：一个装饰性图谱"><a href="#起点：一个装饰性图谱" class="headerlink" title="起点：一个装饰性图谱"></a>起点：一个装饰性图谱</h2><p>我的知识库门户里一直有个”图谱”页面：力导向布局、节点按来源着色、能拖拽缩放。<br>看起来很像回事。</p><p>直到我看了一眼数据：</p><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">nodes=1104  links=3</span><br></pre></td></tr></table></figure><p><strong>1104 个节点，3 条边。</strong> 边全部来自正文里的 <code>[[双链]]</code>，而我几乎不写双链。<br>这个页面唯一的用途是截图好看。</p><h2 id="为什么不直接用-LLM-抽"><a href="#为什么不直接用-LLM-抽" class="headerlink" title="为什么不直接用 LLM 抽"></a>为什么不直接用 LLM 抽</h2><p>2026 年这个方向最热的是 GraphRAG（微软）和 LightRAG（港大），<br>它们的做法都是：<strong>用 LLM 从文本里抽实体和关系</strong>。</p><p>我想过，但算了三笔账：</p><ol><li><strong>额度</strong>：免费 10,000 neurons&#x2F;天。用 LLM 抽 1187 篇文档，一次就可能吃掉大半，<br>而且抽取质量不稳定，重跑一次结果就变；</li><li><strong>可复现</strong>：规范判定要求”同输入同输出”。LLM 抽出来的图，今天和明天不一样，<br>基于它做的判定就没法解释；</li><li><strong>可维护</strong>：词表写错了，我能定位到具体词条；模型抽错了，我只能”再抽一次看看”。</li></ol><p>所以我选了确定性路线：<strong>结构化事实优先，LLM 留到以后按需补充</strong>。</p><h2 id="三层抽取"><a href="#三层抽取" class="headerlink" title="三层抽取"></a>三层抽取</h2><table><thead><tr><th>层</th><th>来源</th><th>产出</th><th>覆盖率</th></tr></thead><tbody><tr><td>L0 结构事实</td><td>路径、front-matter</td><td>文档→目录&#x2F;来源&#x2F;设备&#x2F;标签</td><td>100%</td></tr><tr><td>L1 显式链接</td><td><code>[[双链]]</code>、Markdown 相对链接</td><td>文档→文档</td><td>约 1250 条</td></tr><tr><td>L2 词典实体</td><td>内置词表 + 正则</td><td>文档→实体</td><td>约 540 条</td></tr></tbody></table><p>L0 是覆盖率的关键：每篇文档都”属于”某个目录、来自某个工具、在某台设备上。<br>这些关系不需要”理解”，只需要解析。<strong>先把确定的东西全拿到，再谈语义。</strong></p><p>最终：</p><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">nodes=1649  edges=15955</span><br><span class="line">belongs_to 9875  tagged 1907  mdlink 1248</span><br><span class="line">from_source 1187  on_device 1187  mentions 539</span><br></pre></td></tr></table></figure><h2 id="三个必须处理的坑"><a href="#三个必须处理的坑" class="headerlink" title="三个必须处理的坑"></a>三个必须处理的坑</h2><h3 id="坑-1：枢纽节点会毁掉可视化"><a href="#坑-1：枢纽节点会毁掉可视化" class="headerlink" title="坑 1：枢纽节点会毁掉可视化"></a>坑 1：枢纽节点会毁掉可视化</h3><p><code>device</code> 和 <code>source</code> 这两个节点几乎连到所有文档。从任意文档出发走两跳：</p><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">文档 → 设备 → 另外 295 篇文档</span><br></pre></td></tr></table></figure><p>图上一秒变毛线球。解法是<strong>展示但不穿透</strong>：枢纽类节点画出来，但不再从它继续扩展；<br>再加单层 60 个节点的上限。</p><h3 id="坑-2：伪双链"><a href="#坑-2：伪双链" class="headerlink" title="坑 2：伪双链"></a>坑 2：伪双链</h3><p>正文里的 Markdown 示例会被误当成真链接：</p><figure class="highlight markdown"><table><tr><td class="code"><pre><span class="line">比如可以写 [[&#123; &quot;tag&quot;: &quot;md&quot;, &quot;text&quot;: &quot;...&quot; &#125;]]</span><br></pre></td></tr></table></figure><p>原来的 31 条”断链”里，有 24 条是这种噪声。加了一条过滤规则<br>（长度、非法字符、协议前缀）后剩 7 条真实断链。</p><h3 id="坑-3：中文分词"><a href="#坑-3：中文分词" class="headerlink" title="坑 3：中文分词"></a>坑 3：中文分词</h3><p>FTS5 用 <code>unicode61</code>，会把一整串中文当成一个 token。<br>所以「索引管线怎么分批嵌入」这种整句查询，MATCH 命中是 0，LIKE 兜底也难。<br>短期靠”查两个关键词”，中期要接 <code>jieba</code> 预分词。</p><h2 id="规范判定：让规则可写、可复现"><a href="#规范判定：让规则可写、可复现" class="headerlink" title="规范判定：让规则可写、可复现"></a>规范判定：让规则可写、可复现</h2><p>规则放在内容仓的 <code>policy/rules/*.yaml</code>，和笔记一起版本化：</p><figure class="highlight yaml"><table><tr><td class="code"><pre><span class="line"><span class="bullet">-</span> <span class="attr">id:</span> <span class="string">fm.required</span></span><br><span class="line">  <span class="attr">name:</span> <span class="string">front-matter</span> <span class="string">必填字段</span></span><br><span class="line">  <span class="attr">kind:</span> <span class="string">front_matter</span></span><br><span class="line">  <span class="attr">severity:</span> <span class="string">error</span></span><br><span class="line">  <span class="attr">params:</span></span><br><span class="line">    <span class="attr">required:</span> [<span class="string">&quot;title&quot;</span>, <span class="string">&quot;source&quot;</span>]</span><br></pre></td></tr></table></figure><p>关键设计是 <strong>kind 是封闭枚举</strong>，YAML 只传参数、不写 SQL。<br>内容仓是可写的（笔记软件、网页、客户端都能改），如果规则里能塞 SQL，<br>等于给内容仓开了一个注入面。</p><h2 id="结果"><a href="#结果" class="headerlink" title="结果"></a>结果</h2><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">1187 篇 × 13 条规则 → 2068 条判定记录</span><br><span class="line">违规 881 条：warn 125 + info 756，error 0</span><br><span class="line">按规则：doc.orphan 756 / title.dup 107 / naming.no_space 11 / 断链 7</span><br></pre></td></tr></table></figure><p><code>error = 0</code> 说明敏感信息扫描（私钥、API Key）在内容仓里零命中——这是我最想看到的结果。</p><p>至于那 756 条”孤立文档”：它们全是机器导入的会话记录，本来就没有入链。<br><strong>规则的意义不是消灭数字，而是让数字可解释。</strong></p><h2 id="还没做的"><a href="#还没做的" class="headerlink" title="还没做的"></a>还没做的</h2><ul><li>传递闭包目前只到 10 轮，复杂层级还没压测；</li><li>图谱的社区聚类（Leiden）没做——要做也打算用纯 TS，不调 LLM；</li><li>增量判定：现在每次全量重算，规模再大就得改。</li></ul><p>下一步如果做，我会先做<strong>增量</strong>，而不是做更花哨的图算法。<br>因为真实使用中，”改一篇笔记后多久能看到判定更新”比”图好看不好看”重要得多。</p>]]>
    </content>
    <id>https://yrb127ing.ccwu.cc/posts/graph-from-3-to-15955/</id>
    <link href="https://yrb127ing.ccwu.cc/posts/graph-from-3-to-15955/"/>
    <published>2026-10-21T02:00:00.000Z</published>
    <summary>一个只有 3 条边的&quot;图谱&quot;不算图谱。记录我怎么用确定性抽取把它变成 15955 条，以及为什么不用 LLM。</summary>
    <title>知识图谱：从 3 条边到 15955 条边</title>
    <updated>2026-10-21T07:03:37.906Z</updated>
  </entry>
  <entry>
    <author>
      <name>Yin</name>
    </author>
    <category term="技术" scheme="https://yrb127ing.ccwu.cc/categories/%E6%8A%80%E6%9C%AF/"/>
    <category term="Cloudflare" scheme="https://yrb127ing.ccwu.cc/tags/Cloudflare/"/>
    <category term="Workers" scheme="https://yrb127ing.ccwu.cc/tags/Workers/"/>
    <category term="D1" scheme="https://yrb127ing.ccwu.cc/tags/D1/"/>
    <category term="Vectorize" scheme="https://yrb127ing.ccwu.cc/tags/Vectorize/"/>
    <content>
      <![CDATA[<h2 id="架构一览"><a href="#架构一览" class="headerlink" title="架构一览"></a>架构一览</h2><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">Markdown 仓库（私有）</span><br><span class="line">   │ git push</span><br><span class="line">   ▼</span><br><span class="line">GitHub Actions  ── 抽取/切分/嵌入/判定 ──▶ Cloudflare</span><br><span class="line">                                            ├─ D1（文档、切片、三元组、判定）</span><br><span class="line">                                            ├─ Workers KV（索引产物）</span><br><span class="line">                                            ├─ Vectorize（语义向量）</span><br><span class="line">                                            └─ Worker（查询 API）</span><br><span class="line">                                                   ▲</span><br><span class="line">                                     Pages + Access（只给自己看）</span><br></pre></td></tr></table></figure><p>选这套的原因很朴素：<strong>没有一个组件需要常驻服务器</strong>。<br>Neo4j、OpenSPG 这类图数据库确实更强，但要一台机器一直开着，就不符合”零成本”。</p><h2 id="四个撞过的硬限制"><a href="#四个撞过的硬限制" class="headerlink" title="四个撞过的硬限制"></a>四个撞过的硬限制</h2><h3 id="1-嵌入请求有-6-万-token-的总上限"><a href="#1-嵌入请求有-6-万-token-的总上限" class="headerlink" title="1. 嵌入请求有 6 万 token 的总上限"></a>1. 嵌入请求有 6 万 token 的总上限</h3><p>第一次跑索引，第一批就 400：</p><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">AiError: Max context reached 99392 tokens but model supports only 60000</span><br></pre></td></tr></table></figure><p>原因是按固定 64 条一批，而中文分片每片接近 900 token，64 × 900 直接顶破。<br>改成<strong>按估算 token 预算动态分批</strong>，并对单条做字符上限保护；仍失败就二分重试。</p><h3 id="2-KV-的单键上限是-25-MiB"><a href="#2-KV-的单键上限是-25-MiB" class="headerlink" title="2. KV 的单键上限是 25 MiB"></a>2. KV 的单键上限是 25 MiB</h3><p>索引产物里有一份 <code>embeddings.jsonl</code>，88 MB，PUT 直接 413：</p><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">content size of 87905171 bytes exceeds maximum allowed size of 27MiB</span><br></pre></td></tr></table></figure><p>后来发现这个键<strong>运行时根本没人读</strong>——向量在 Vectorize 里，Worker 只读<br><code>docs.json</code> 和 <code>meta.json</code>。删掉即可。<strong>先查清楚谁在读，再决定怎么存。</strong></p><h3 id="3-D1-单条语句的绑定参数有上限"><a href="#3-D1-单条语句的绑定参数有上限" class="headerlink" title="3. D1 单条语句的绑定参数有上限"></a>3. D1 单条语句的绑定参数有上限</h3><p>想在一条 SQL 里从 300 个节点取边：</p><figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="keyword">WHERE</span> e.src <span class="keyword">IN</span> (?,?,...) <span class="keyword">OR</span> e.dst <span class="keyword">IN</span> (?,?,...)   <span class="comment">-- 600 个参数</span></span><br></pre></td></tr></table></figure><p>直接 500。官方文档没写这个数，实测大约 100。改成拆两条 SQL、每批 50 个 id，<br>再用 id 去重合并。</p><h3 id="4-免费神经元额度是-10-000-天"><a href="#4-免费神经元额度是-10-000-天" class="headerlink" title="4. 免费神经元额度是 10,000&#x2F;天"></a>4. 免费神经元额度是 10,000&#x2F;天</h3><p>全量重建一次约 3000 neurons（4290 片 × 约 700 token），<br>所以<strong>一天最多重建三次</strong>。这直接决定了：增量索引不是”优化”，是”必需”。</p><h2 id="一个反直觉的设计：判定放在离线"><a href="#一个反直觉的设计：判定放在离线" class="headerlink" title="一个反直觉的设计：判定放在离线"></a>一个反直觉的设计：判定放在离线</h2><p>一开始我想把规则引擎放进 Worker，请求时现算。算了一下：1187 篇 × 13 条规则 ≈ 1.5 万条判定，<br>而 Workers 免费档单请求 CPU 只有 10 ms——跑不完，也写不完。</p><p>于是把判定挪到管线里离线跑（一次约 3 秒），Worker 只做”读”。<br>副产品是：判定结果成了<strong>可查看的历史快照</strong>，而不是每次请求都变的临时值。</p><h2 id="代价与收益"><a href="#代价与收益" class="headerlink" title="代价与收益"></a>代价与收益</h2><table><thead><tr><th>项</th><th>结果</th></tr></thead><tbody><tr><td>月成本</td><td>0 元</td></tr><tr><td>全量索引耗时</td><td>约 4 分钟（Actions）</td></tr><tr><td>查询延迟</td><td>毫秒级（D1 &#x2F; KV 命中）</td></tr><tr><td>规模上限</td><td>Vectorize 5M 维度，当前已用 87.8%</td></tr></tbody></table><p>最后一行是唯一的隐患：知识库再涨约 14%，语义检索就会超限。<br>到那天的退路已经想好了——降级成纯关键词检索，功能不崩，只是没那么”聪明”。</p><h2 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h2><p>免费额度的真正价值不是”省钱”，而是<strong>逼你把架构想清楚</strong>：<br>不能堆组件，就得想清楚每一层到底在解决什么问题。<br>这套系统里，真正不可替代的只有两件事——<strong>分片策略</strong>和<strong>规则</strong>。<br>其余的，都是可以替换的实现细节。</p>]]>
    </content>
    <id>https://yrb127ing.ccwu.cc/posts/cloudflare-free-kb-stack/</id>
    <link href="https://yrb127ing.ccwu.cc/posts/cloudflare-free-kb-stack/"/>
    <published>2026-10-20T02:00:00.000Z</published>
    <summary>不绑卡、不租服务器，把检索、图谱、规范判定都跑在免费额度里，以及一路上踩到的四个硬限制。</summary>
    <title>用 Cloudflare 免费额度搭一套私有知识库</title>
    <updated>2026-10-20T16:00:00.000Z</updated>
  </entry>
  <entry>
    <author>
      <name>Yin</name>
    </author>
    <category term="杂记" scheme="https://yrb127ing.ccwu.cc/categories/%E6%9D%82%E8%AE%B0/"/>
    <category term="Cloudflare" scheme="https://yrb127ing.ccwu.cc/tags/Cloudflare/"/>
    <category term="知识管理" scheme="https://yrb127ing.ccwu.cc/tags/%E7%9F%A5%E8%AF%86%E7%AE%A1%E7%90%86/"/>
    <category term="自托管" scheme="https://yrb127ing.ccwu.cc/tags/%E8%87%AA%E6%89%98%E7%AE%A1/"/>
    <content>
      <![CDATA[<h2 id="起因"><a href="#起因" class="headerlink" title="起因"></a>起因</h2><p>我的笔记散在四个地方：Obsidian 里一部分、几个 AI 工具的会话记录里一部分、浏览器书签里一部分、<br>还有一部分在「等我有空再整理」的文件夹里。</p><p>结果是：<strong>收藏越多，越找不到</strong>。</p><p>真正让我下决心的是一个很具体的问题——我想找半年前写过的一段<br>「Cloudflare Workers 怎么复用连接」的笔记，翻了三个 App 都没找到。<br>那一刻我意识到，我缺的不是存储，是<strong>检索和结构</strong>。</p><h2 id="我想要的到底是什么"><a href="#我想要的到底是什么" class="headerlink" title="我想要的到底是什么"></a>我想要的到底是什么</h2><p>我把需求写成了四条，后来整个系统都是围绕这四条长出来的：</p><ol><li><strong>一个地方</strong>：所有笔记最终汇到一个仓库，不管原来在哪；</li><li><strong>搜得到</strong>：关键词能搜，语义也能搜；</li><li><strong>看得见关系</strong>：这篇笔记和哪些文档有关，为什么有关；</li><li><strong>判得准</strong>：我的知识库有没有违反自己定的规范（缺元数据、断链、过期、含密钥）。</li></ol><p>第 4 条听起来最玄，其实是最后落地时最有用的一条——见下面。</p><h2 id="为什么不用现成的"><a href="#为什么不用现成的" class="headerlink" title="为什么不用现成的"></a>为什么不用现成的</h2><p>我试过几个方向：</p><ul><li><strong>云笔记 + 全平台同步</strong>：同步没问题，但检索只有关键词，没有关系；</li><li><strong>现成的 RAG 工具</strong>：能问答，但索引是黑盒，我改不了它的分片策略；</li><li><strong>笔记软件自带的图谱</strong>：好看，但只是”双链的可视化”，不是可计算的图。</li></ul><p>共同的问题是：<strong>它们不让我碰索引</strong>。</p><p>而知识库的价值恰恰在索引层——分片怎么切、实体怎么抽、规则怎么判。<br>所以我决定自己写一个，只在索引层花功夫，其他都尽量简单。</p><h2 id="最后的形态"><a href="#最后的形态" class="headerlink" title="最后的形态"></a>最后的形态</h2><ul><li><strong>存储</strong>：Markdown 仓库（GitHub 私有仓），跨设备靠 git 同步；</li><li><strong>索引</strong>：GitHub Actions 里跑，产出切片、向量、三元组、判定结果；</li><li><strong>查询</strong>：Cloudflare Worker + D1 + Vectorize，全部落在免费额度内；</li><li><strong>入口</strong>：一个网页门户 + 一个桌面客户端 + 一套 MCP 工具。</li></ul><p>关键取舍是：<strong>不绑卡</strong>。所以没有用 R2，索引产物直接写 Workers KV，<br>原文由 Worker 通过 GitHub API 直读。</p><h2 id="第-4-条需求意外地有用"><a href="#第-4-条需求意外地有用" class="headerlink" title="第 4 条需求意外地有用"></a>第 4 条需求意外地有用</h2><p>我原本以为”规范判定”是个锦上添花的功能，直到它第一次跑出结果：</p><figure class="highlight text"><table><tr><td class="code"><pre><span class="line">warn  标题重复    knowledge/memory/dsh/profiles/desktop/cordis.yml</span><br><span class="line">      与 1 篇文档同名，容易混淆</span><br><span class="line">warn  双链断链    31 处 → 过滤掉代码示例里的伪链接后剩 7 处</span><br><span class="line">info  孤立文档    756 篇没有入链</span><br></pre></td></tr></table></figure><p>756 这个数字很刺眼，但它是对的：那批文档是机器导入的会话记录，本来就没有入链。<br><strong>规则的价值不是”发现问题”，而是”让问题可度量”</strong>。有了度量，才知道先修什么。</p><h2 id="下一步"><a href="#下一步" class="headerlink" title="下一步"></a>下一步</h2><p>语义检索和关系图谱已经能用了，但我还想加两件：</p><ul><li>中文分词后再进全文索引（现在 <code>unicode61</code> 会把整句中文当成一个 token）；</li><li>增量索引（现在每次全量重建都吃一次嵌入额度）。</li></ul><p>这两件事都不难，难的是别把系统搞复杂。这个博客大概会记录它们。</p>]]>
    </content>
    <id>https://yrb127ing.ccwu.cc/posts/why-my-own-kb/</id>
    <link href="https://yrb127ing.ccwu.cc/posts/why-my-own-kb/"/>
    <published>2026-10-18T02:00:00.000Z</published>
    <summary>从「到处收藏」到「能查、能判、能推理」，我做了一个只给自己用的知识库。</summary>
    <title>为什么我要做一个自己的知识库</title>
    <updated>2026-10-20T16:00:00.000Z</updated>
  </entry>
</feed>
