2026-08-07 14:16:25
<p>Manjaro Linux 用 WiFi(<code>wlp7s0</code>)上网,把网线口(<code>enp8s0</code>)共享给一台下游设备。共享用的不是独立 dnsmasq,而是 NetworkManager 自带的 <code>shared</code> 模式。下游设备能正常上网,但 IP 是 DHCP 动态分的,今天 <code>.108</code>,下次可能 <code>.109</code>。想把那台设备固定成 <code>10.42.0.2</code>,方便后面做端口转发和固定访问。</p><h2 id="现场"><a href="#现场" class="headerlink" title="现场"></a>现场</h2><p>笔记本同时连着两张网卡:</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"> 上游 WiFi(出口)</span><br><span class="line"> wlp7s0 192.168.1.x/24 gw 192.168.1.1 (示例网段)</span><br><span class="line"> │</span><br><span class="line">┌────┴─────┐</span><br><span class="line">│ 笔记本 │ Manjaro 26.1 / Kernel 7.1.4</span><br><span class="line">│ │ NetworkManager 1.58(nmcli)/ dnsmasq 2.93</span><br><span class="line">│ │ ipv4.method=shared(共享连接)</span><br><span class="line">└────┬─────┘</span><br><span class="line"> │ enp8s0 10.42.0.1/24</span><br><span class="line"> │ └─ NM 内置 dnsmasq:DHCP 池 10.42.0.10–254,租约 3600s</span><br><span class="line"> ▼</span><br><span class="line">下游设备(share client)</span><br><span class="line">MAC aa:bb:cc:dd:ee:01 (示例) 当前拿到 10.42.0.108</span><br></pre></td></tr></table></figure><span id="more"></span><p>NM 用 <code>shared</code> 模式把 <code>enp8s0</code> 当 LAN 口,自动开了:</p><ul><li>本机 <code>enp8s0 = 10.42.0.1/24</code>(shared 模式固定用 <code>.1</code>,改不了)</li><li>一个内置 dnsmasq 提供 DHCP,动态池 <code>10.42.0.10 – 10.42.0.254</code></li><li><code>net.ipv4.ip_forward=1</code> + 自动加 iptables NAT,把流量从 <code>enp8s0</code> 转到 <code>wlp7s0</code> 上网</li></ul><p>确认连接是 shared 模式(下面命令里的 <code><共享连接名></code> 换成你自己的,比如我的叫 <code>ETH_SHARE</code>):</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ nmcli connection show ETH_SHARE | grep ipv4.method</span><br><span class="line">ipv4.method: shared</span><br></pre></td></tr></table></figure><p>下游那台设备(MAC <code>aa:bb:cc:dd:ee:01</code>,示例)当前租约:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">sudo</span> <span class="built_in">cat</span> /var/lib/NetworkManager/dnsmasq-enp8s0.leases</span><br><span class="line">1700000000 aa:bb:cc:<span class="built_in">dd</span>:ee:01 10.42.0.108 mydevice 01:aa:bb:cc:<span class="built_in">dd</span>:ee:01</span><br></pre></td></tr></table></figure><!-- more --><h2 id="定位:DHCP-实际由谁发出"><a href="#定位:DHCP-实际由谁发出" class="headerlink" title="定位:DHCP 实际由谁发出"></a>定位:DHCP 实际由谁发出</h2><p>shared 模式的 DHCP 不是系统级的 <code>dnsmasq.service</code> 发的——它是 <code>inactive</code> 的:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ systemctl status dnsmasq</span><br><span class="line">○ dnsmasq.service ... ; Active: inactive (dead)</span><br></pre></td></tr></table></figure><p>真正发 DHCP 的是 NM 拉起的另一个 dnsmasq 实例,看进程就能定位到它和它的配置入口:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">$ ps aux | grep dnsmasq | grep -v grep</span><br><span class="line">nobody 1234 /usr/bin/dnsmasq --conf-file=/dev/null --no-hosts --keep-in-foreground \</span><br><span class="line"> --bind-interfaces --except-interface=lo --clear-on-reload --strict-order \</span><br><span class="line"> --listen-address=10.42.0.1 \</span><br><span class="line"> --dhcp-range=10.42.0.10,10.42.0.254,3600 \</span><br><span class="line"> --dhcp-leasefile=/var/lib/NetworkManager/dnsmasq-enp8s0.leases \</span><br><span class="line"> --pid-file=/run/nm-dnsmasq-enp8s0.pid \</span><br><span class="line"> --conf-dir=/etc/NetworkManager/dnsmasq-shared.d</span><br></pre></td></tr></table></figure><p>这条启动参数里有三个关键点:</p><ul><li><code>--conf-file=/dev/null</code> —— 这个实例显式忽略 <code>/etc/dnsmasq.conf</code>,所以 DHCP 的定制入口不在那里。</li><li><code>--conf-dir=/etc/NetworkManager/dnsmasq-shared.d</code> —— 真正的配置目录,NM 给 shared 模式专用,默认是空目录。<strong>这就是塞 <code>dhcp-host</code> 的地方。</strong></li><li>它的生命周期挂在那个共享连接上——NM 激活连接时拉起、停用时杀掉,不归 <code>dnsmasq.service</code> 管。所以重载配置要靠重连,而不是 <code>systemctl restart dnsmasq</code>。</li></ul><blockquote><p>保持 NM 全托管即可,不要去启用 <code>dnsmasq.service</code>。它和这个内置实例会抢 53/67 端口,造成 DHCP 双重应答、DNS 冲突。</p></blockquote><h2 id="修复:往-conf-dir-放-dhcp-host-静态绑定"><a href="#修复:往-conf-dir-放-dhcp-host-静态绑定" class="headerlink" title="修复:往 conf-dir 放 dhcp-host 静态绑定"></a>修复:往 conf-dir 放 dhcp-host 静态绑定</h2><p>目标:把下游设备(MAC <code>aa:bb:cc:dd:ee:01</code>,示例)固定成 <code>10.42.0.2</code>。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">sudo</span> <span class="built_in">mkdir</span> -p /etc/NetworkManager/dnsmasq-shared.d</span><br><span class="line"></span><br><span class="line">$ <span class="built_in">sudo</span> <span class="built_in">tee</span> /etc/NetworkManager/dnsmasq-shared.d/static-leases.conf >/dev/null <<<span class="string">'EOF'</span></span><br><span class="line"><span class="comment"># 共享连接 (enp8s0) 客户端固定 IP 绑定</span></span><br><span class="line"><span class="comment"># 10.42.0.2 在默认动态池 10.42.0.10–254 之外,dnsmasq 不会动态发出,无冲突</span></span><br><span class="line">dhcp-host=aa:bb:cc:<span class="built_in">dd</span>:ee:01,10.42.0.2,mydevice,infinite</span><br><span class="line">EOF</span><br></pre></td></tr></table></figure><p><code>dhcp-host</code> 的格式:<code><MAC>,<IP>,<hostname>[,infinite]</code>。<code>infinite</code> 是永久租约,IP 永远属于这台设备。</p><p>写完先做语法自检,别等重连了才发现 dnsmasq 起不来:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">sudo</span> dnsmasq --<span class="built_in">test</span> --conf-file=/dev/null --conf-dir=/etc/NetworkManager/dnsmasq-shared.d</span><br><span class="line">dnsmasq: syntax check OK.</span><br></pre></td></tr></table></figure><p>然后让 NM 重启它的 dnsmasq。最干净的方式是重连那个共享连接(下文记作 <code>ETH_SHARE</code>,换成你自己的连接名),NM 会自动杀掉旧 dnsmasq、起新的并加载 conf-dir:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">sudo</span> nmcli connection down ETH_SHARE && <span class="built_in">sudo</span> nmcli connection up ETH_SHARE</span><br></pre></td></tr></table></figure><blockquote><p>为什么不直接 <code>kill -HUP</code> 那个 dnsmasq?也能用,<code>sudo kill -SIGHUP $(cat /run/nm-dnsmasq-enp8s0.pid)</code> 会让它重读配置、不中断现有连接。但重连更彻底——尤其当配置改了 DHCP 池范围时,<code>HUP</code> 不一定全量重载。这次只加 dhcp-host,两者都行,我选了重连。</p></blockquote><p>验证新 dnsmasq 起来了、且带上了 conf-dir:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">cat</span> /run/nm-dnsmasq-enp8s0.pid</span><br><span class="line">5678 <span class="comment"># PID 变了(重启前是另一个值),确认实例重启</span></span><br><span class="line"></span><br><span class="line">$ ps -o args= -p $(<span class="built_in">cat</span> /run/nm-dnsmasq-enp8s0.pid) | <span class="built_in">tr</span> <span class="string">' '</span> <span class="string">'\n'</span> | grep conf-dir</span><br><span class="line">--conf-dir=/etc/NetworkManager/dnsmasq-shared.d</span><br></pre></td></tr></table></figure><p>到这一步服务端就配完了。</p><h2 id="客户端必须重拿一次-DHCP"><a href="#客户端必须重拿一次-DHCP" class="headerlink" title="客户端必须重拿一次 DHCP"></a>客户端必须重拿一次 DHCP</h2><p>配完绑定,下游设备的 IP 不会自动从 <code>.108</code> 变成 <code>.2</code>。<strong>静态绑定只在客户端下次续约/重连时生效</strong>——这是最容易漏的一步。</p><ul><li>Linux 客户端:<code>sudo dhclient -r && sudo dhclient</code></li><li>嵌入式/摄像头/手机:拔插网线或重启设备即可</li></ul><p>重连后回笔记本看租约:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">$ <span class="built_in">sudo</span> <span class="built_in">cat</span> /var/lib/NetworkManager/dnsmasq-enp8s0.leases</span><br><span class="line"><span class="comment"># 期望:aa:bb:cc:dd:ee:01 10.42.0.2 mydevice ...</span></span><br><span class="line"></span><br><span class="line">$ ping -c2 10.42.0.2</span><br><span class="line">$ ip neigh show dev enp8s0</span><br><span class="line"><span class="comment"># 期望:10.42.0.2 lladdr aa:bb:cc:dd:ee:01 REACHABLE</span></span><br></pre></td></tr></table></figure><h2 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h2><p>NetworkManager 的 <code>shared</code> 模式是个黑盒:表面上是 NM 一个连接配置,背后它替你拉起了一整套 dnsmasq + iptables + ip_forward。好处是开箱即用,代价是 DHCP 的定制入口藏得很深——不是 <code>/etc/dnsmasq.conf</code>,而是 <code>/etc/NetworkManager/dnsmasq-shared.d/</code>。</p><p>记住这个映射关系就够了:<strong>改 shared 模式的 DHCP 行为,找 NM 内置 dnsmasq 的 conf-dir,别找系统的 dnsmasq.service。</strong></p>
2026-08-04 11:00:00
<p>容器化微服务环境,前置 nginx 反代到 Spring Cloud Gateway。某次 gateway 容器重建后,所有经 nginx 的 <code>/api/**</code> 请求开始返回 500,而 gateway 自身、服务发现、各业务服务均正常。</p><p>排查绕了一大圈,根因是 nginx 的一个经典行为:<strong><code>proxy_pass</code> 写主机名时只在启动时解析一次,之后永久缓存。上游容器重建换 IP 后,nginx 仍在连旧 IP——而旧 IP 已被 Docker 分配给了另一个服务。</strong></p><h2 id="现场"><a href="#现场" class="headerlink" title="现场"></a>现场</h2><p>前置 nginx + Spring Cloud Gateway + Nacos 架构,全部跑在同一个 Docker 自定义网络(<code>172.18.0.0/16</code>)里:</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"> Docker 网络 172.18.0.0/16</span><br><span class="line">┌─────────┐ ┌──────────────────────────────────────────────┐</span><br><span class="line">│ 客户端 │ ──8000─▶│ nginx 容器 172.18.0.10 │</span><br><span class="line">└─────────┘ │ location /api/ { proxy_pass ...:8080 } │</span><br><span class="line"> └───────────────────┬──────────────────────────┘</span><br><span class="line"> │ proxy_pass http://project-gateway:8080</span><br><span class="line"> ▼ (nginx 在启动时把主机名解析成 IP 并缓存)</span><br><span class="line"> ┌─────────────────────────────┴─────────────────────────────┐</span><br><span class="line"> ▼ ▼ ▼</span><br><span class="line">┌───────────────────┐ ┌───────────────────┐ ┌───────────────────┐</span><br><span class="line">│ project-gateway │ │ project-order │ │ project-auth │</span><br><span class="line">│ Spring Cloud │ │ 业务服务 │ │ 业务服务 │</span><br><span class="line">│ Gateway │ │ 172.18.0.20 │ │ 172.18.0.22 │</span><br><span class="line">│ 172.18.0.21 │ └───────────────────┘ └───────────────────┘</span><br><span class="line">│ 订阅 Nacos 实例 │ ▲</span><br><span class="line">└─────────┬─────────┘ │</span><br><span class="line"> │ │ nginx worker 实际连的是这个旧 IP</span><br><span class="line"> ▼ │ —— gateway 重建前它属于 gateway,</span><br><span class="line">┌───────────────────┐ │ 重建后被 Docker 重新分配给了 order</span><br><span class="line">│ Nacos │ │</span><br><span class="line">│ 172.18.0.2 │ ─ ─ ─ ─ ─ ─ ─ ┘</span><br><span class="line">└───────────────────┘ 服务发现正常,但与 nginx 转发目标无关</span><br></pre></td></tr></table></figure><p>请求链路本该是 <code>客户端 → nginx → gateway → 业务服务</code>,gateway 再按 Nacos 的实例列表把请求路由到 <code>project-order</code> / <code>project-auth</code>。但出问题时 nginx 根本没把请求交给 gateway——某个经 nginx 的接口请求报错:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">GET http://10.20.30.40:8000/api/xxx</span><br><span class="line">{"traceId":null,"code":1,"data":null,"message":"unknow.exception"} HTTP 500</span><br></pre></td></tr></table></figure><span id="more"></span><p>几个看似矛盾的现象,把排查方向带偏了数次:</p><ul><li><strong>服务发现正常</strong>:目标服务已注册到 Nacos,gateway 也订阅到了实例。</li><li><strong>gateway 容器内直连正常</strong>:<code>curl gateway:8080/xxx</code> 返回 200。</li><li><strong>但经 nginx 的请求,gateway 一条日志都没有</strong>——请求根本没到 gateway。</li><li><strong>nginx 配置看不出问题</strong>:<code>location /api/ { proxy_pass http://project-gateway:8080/; }</code>,<code>proxy_pass</code> 带尾部 <code>/</code> 会剥前缀,没毛病。</li><li><strong><code>docker exec nginx curl project-gateway:8080</code> 也是通的。</strong></li></ul><p>配置对、直连通、<code>exec</code> 也通,唯独经 nginx 就 500 且 gateway 收不到——问题出在 nginx worker 实际把请求转发到了哪。抓 nginx worker 的真实 TCP 连接目标(<code>/proc/net/tcp</code> 解码):</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">38 -> 172.18.0.20:8080 ← nginx worker 在连这个 IP</span><br></pre></td></tr></table></figure><p>对照各容器当前 IP:</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">project-gateway -> 172.18.0.21</span><br><span class="line">project-order -> 172.18.0.20 ← nginx 连的是它,不是 gateway</span><br><span class="line">project-auth -> 172.18.0.22</span><br></pre></td></tr></table></figure><p>nginx 把请求转发到了 <code>172.18.0.20</code>(业务服务 <code>project-order</code>),而非 gateway(<code>.21</code>)。该服务没有对应路由,抛异常被框架兜底成 500。</p><blockquote><p>为什么 <code>docker exec</code> 通、worker 却不通?<code>exec</code> 启动的新 shell 用<strong>当前 DNS</strong>(解析到 <code>.21</code>),而 nginx worker 用的是启动时缓存的旧 IP(<code>.20</code>)。同一容器、同一网络栈,DNS 解析的<strong>时机</strong>不同。</p></blockquote><h2 id="根因"><a href="#根因" class="headerlink" title="根因"></a>根因</h2><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">location</span> /api/ {</span><br><span class="line"> <span class="attribute">proxy_pass</span> http://project-gateway:8080/; <span class="comment"># 静态主机名,全配置无 resolver</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li><code>proxy_pass</code> 写的是主机名,且全配置<strong>没有 <code>resolver</code> 指令</strong> → nginx 在<strong>启动时</strong>解析一次并<strong>永久缓存</strong>,之后不再重新解析。</li><li>gateway 容器重建后 IP 由 <code>.20</code> 变 <code>.21</code>,旧 IP <code>.20</code> 被 Docker 重新分配给了 <code>project-order</code>。</li><li>nginx 仍在连旧 IP,于是所有 <code>/api/**</code> 请求都打到了 <code>project-order</code>。</li></ul><p>一句话:<strong><code>proxy_pass</code> 写主机名 = 启动期解析一次后缓存,容器 IP 一变就连错。</strong></p><h2 id="修复"><a href="#修复" class="headerlink" title="修复"></a>修复</h2><p><code>resolver</code> + 变量版 <code>proxy_pass</code>,让 nginx 按 TTL 动态解析:</p><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">http</span> {</span><br><span class="line"> <span class="attribute">resolver</span> <span class="number">127.0.0.11</span> valid=<span class="number">30s</span> ipv6=<span class="literal">off</span>; <span class="comment"># Docker 内置 DNS</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="section">location</span> /api/ {</span><br><span class="line"> <span class="attribute">set</span> <span class="variable">$upstream_gateway</span> project-gateway; <span class="comment"># 变量触发动态解析</span></span><br><span class="line"> <span class="attribute">proxy_set_header</span> Host <span class="variable">$host</span>;</span><br><span class="line"> <span class="attribute">proxy_set_header</span> X-Forwarded-For <span class="variable">$proxy_add_x_forwarded_for</span>;</span><br><span class="line"> <span class="attribute">proxy_set_header</span> X-Forwarded-Proto <span class="variable">$scheme</span>;</span><br><span class="line"></span><br><span class="line"> <span class="attribute">rewrite</span><span class="regexp"> ^/api/(.*)$</span> /<span class="variable">$1</span> <span class="literal">break</span>; <span class="comment"># 显式剥 /api/ 前缀</span></span><br><span class="line"></span><br><span class="line"> <span class="attribute">proxy_pass</span> http://<span class="variable">$upstream_gateway</span>:8080; <span class="comment"># 不带尾部 /,配 rewrite 用纯地址</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>三个关键点:</p><ol><li><strong><code>resolver 127.0.0.11 valid=30s</code></strong> —— Docker 内置 DNS,解析结果 30 秒过期。</li><li><strong><code>set $upstream</code> + 变量版 <code>proxy_pass</code></strong> —— <code>proxy_pass</code> 一旦含变量,nginx 就不再启动期静态解析,而是运行时走 <code>resolver</code>。这是社区版 nginx 动态解析上游的唯一方式。</li><li><strong><code>rewrite ^/api/(.*)$ /$1 break</code></strong> —— 必须显式剥前缀(原因见下)。</li></ol><h3 id="连环坑:变量版-proxy-pass-不剥前缀"><a href="#连环坑:变量版-proxy-pass-不剥前缀" class="headerlink" title="连环坑:变量版 proxy_pass 不剥前缀"></a>连环坑:变量版 proxy_pass 不剥前缀</h3><p>从纯文本 <code>proxy_pass http://x:8080/;</code> 改成变量版后,原来自动剥 <code>/api/</code> 前缀的能力<strong>消失了</strong>,后端会收到错误的 path(实测 gateway 收到的是 <code>/</code>)。所以必须配 <code>rewrite ... break</code> 显式剥,并且 <code>proxy_pass</code> 去掉尾部 <code>/</code>(配 <code>rewrite break</code> 时必须是纯地址,带 URI 会二次改写)。</p><h3 id="别走这条路"><a href="#别走这条路" class="headerlink" title="别走这条路"></a>别走这条路</h3><p><code>upstream {}</code> 块里写主机名<strong>同样是启动期一次性解析</strong>,不动态刷新(只有 Nginx Plus 的 <code>resolve</code> 参数才动态)。<code>upstream</code> 块解决不了这个问题。</p><p>改完 <code>nginx -t && nginx -s reload</code>,容器怎么重建、IP 怎么变,nginx 都会按 30 秒 TTL 自动跟上。</p>
2026-07-27 00:00:00
<p>自从 Karpathy 提出 <strong>llm-wiki</strong> 这套理念,我就一直想自己动手搭一个 AI 知识库——用它记录笔记、学习知识,也试着让它指引生活。</p><p>几经拖延,最后先让 AI 帮我把 llm-wiki 的生态通盘调研了一遍。结果出乎意料地详实:llm-wiki 为什么出现、解决了什么问题,理念和社区如何发展,有哪些开源实现,又该怎么亲手创建一个——都讲清楚了。</p><p>整理成文,分享至此,供君参考。</p><blockquote><p>本文涉及版本、星标数、项目状态等信息,截至 2026-07 月的公开仓库/文档,后续可能变化,请以官方最新信息为准。</p></blockquote><hr><h2 id="先用一个比喻理解-llm-wiki"><a href="#先用一个比喻理解-llm-wiki" class="headerlink" title="先用一个比喻理解 llm-wiki"></a>先用一个比喻理解 llm-wiki</h2><p>传统 RAG 像一个“临时资料员”:</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">你问问题 → 它去仓库里翻几箱资料 → 抽出几页 → 临时拼一个答案</span><br></pre></td></tr></table></figure><p>llm-wiki 更像一个“长期图书管理员 + 研究助理”:</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">新资料进来 → 它读懂、归档、做索引、写摘要、加交叉引用、标注冲突</span><br><span class="line">你问问题 → 它先查已经整理好的知识图谱 → 必要时再回原始资料核验</span><br><span class="line">好答案 → 继续沉淀回知识库</span><br></pre></td></tr></table></figure><p>一句话:</p><blockquote><p><strong>RAG 每次临时找资料;llm-wiki 平时就把资料整理成会复利的知识资产。</strong></p></blockquote><span id="more"></span><hr><h2 id="为什么需要-llm-wiki?"><a href="#为什么需要-llm-wiki?" class="headerlink" title="为什么需要 llm-wiki?"></a>为什么需要 llm-wiki?</h2><p>LLM 已经很会“读”,但它有几个现实问题:</p><table><thead><tr><th>问题</th><th>直观表现</th><th>后果</th></tr></thead><tbody><tr><td>上下文会丢</td><td>新 session 不知道旧结论</td><td>重复解释、重复踩坑</td></tr><tr><td>检索是临时的</td><td>每次 query 都重新找片段</td><td>推理不能复利</td></tr><tr><td>资料没有结构</td><td>文档、网页、issue、PDF 堆在一起</td><td>很难回答全局问题</td></tr><tr><td>答案不沉淀</td><td>好答案只存在聊天窗口</td><td>下次还要重来</td></tr><tr><td>冲突不显式</td><td>A 文档和 B 文档矛盾但没人记录</td><td>知识库越来越不可信</td></tr><tr><td>旧事实不失效</td><td>过期结论继续被引用</td><td>agent 可能自信地说错</td></tr></tbody></table><p>llm-wiki 试图解决的不是“怎么搜到更多资料”,而是:</p><blockquote><p><strong>怎么让 LLM 的每次阅读、问答、纠错和总结,都变成可复用、可审计、可维护的长期知识。</strong></p></blockquote><hr><h2 id="一张图看懂-llm-wiki"><a href="#一张图看懂-llm-wiki" class="headerlink" title="一张图看懂 llm-wiki"></a>一张图看懂 llm-wiki</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">flowchart TD</span><br><span class="line"> A[Raw Sources\n网页 / PDF / 代码 / issue / transcript] --> B[Ingest\n读取、理解、拆解]</span><br><span class="line"> B --> C[Wiki Knowledge Layer\nMarkdown 页面 + wikilinks + citations]</span><br><span class="line"> C --> D[Query\n基于 wiki 回答问题]</span><br><span class="line"> D --> E{答案有长期价值吗?}</span><br><span class="line"> E -- 是 --> C</span><br><span class="line"> E -- 否 --> F[只返回答案]</span><br><span class="line"> C --> G[Lint / Maintain\n查断链、无引用、冲突、陈旧事实]</span><br><span class="line"> G --> C</span><br><span class="line"> C --> H[Derived Indexes\n全文搜索 / 向量 / 图索引 / backlinks]</span><br><span class="line"> H --> D</span><br></pre></td></tr></table></figure><p>这张图的核心循环是:</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">资料进入 → 知识编译 → 问答复用 → 好答案回写 → 定期维护 → 知识继续变好</span><br></pre></td></tr></table></figure><p>这就是“知识复利”。</p><hr><h2 id="三层架构:原始资料、知识层、操作手册"><a href="#三层架构:原始资料、知识层、操作手册" class="headerlink" title="三层架构:原始资料、知识层、操作手册"></a>三层架构:原始资料、知识层、操作手册</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">flowchart TB</span><br><span class="line"> subgraph L1[第一层:Raw Sources 原始事实层]</span><br><span class="line"> R1[网页快照]</span><br><span class="line"> R2[PDF]</span><br><span class="line"> R3[代码仓库]</span><br><span class="line"> R4[会议记录]</span><br><span class="line"> R5[issue / PR]</span><br><span class="line"> end</span><br><span class="line"></span><br><span class="line"> subgraph L2[第二层:Wiki 知识编译层]</span><br><span class="line"> W1[概念页]</span><br><span class="line"> W2[实体页]</span><br><span class="line"> W3[决策页]</span><br><span class="line"> W4[冲突页]</span><br><span class="line"> W5[开放问题]</span><br><span class="line"> W6[索引页]</span><br><span class="line"> end</span><br><span class="line"></span><br><span class="line"> subgraph L3[第三层:Schema / CLAUDE.md / AGENTS.md 操作手册层]</span><br><span class="line"> S1[页面模板]</span><br><span class="line"> S2[引用规则]</span><br><span class="line"> S3[新建/合并规则]</span><br><span class="line"> S4[Lint 规则]</span><br><span class="line"> S5[审批规则]</span><br><span class="line"> end</span><br><span class="line"></span><br><span class="line"> L1 --> L2</span><br><span class="line"> L3 --> L2</span><br></pre></td></tr></table></figure><h3 id="Raw-Sources:像“证据柜”"><a href="#Raw-Sources:像“证据柜”" class="headerlink" title="Raw Sources:像“证据柜”"></a>Raw Sources:像“证据柜”</h3><p>这里保存原始资料,尽量不要改。</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">raw/</span><br><span class="line"> web/</span><br><span class="line"> pdf/</span><br><span class="line"> code/</span><br><span class="line"> transcripts/</span><br><span class="line"> issues/</span><br></pre></td></tr></table></figure><p>它的职责是:</p><ul><li>保存事实来源;</li><li>让 wiki 中的 claim 可追溯;</li><li>当模型生成内容可疑时,可以回到原文核验。</li></ul><h3 id="Wiki:像“研究员写的知识图谱”"><a href="#Wiki:像“研究员写的知识图谱”" class="headerlink" title="Wiki:像“研究员写的知识图谱”"></a>Wiki:像“研究员写的知识图谱”</h3><p>这里不是简单摘要堆,而是结构化知识:</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">wiki/</span><br><span class="line"> index.md</span><br><span class="line"> concepts/</span><br><span class="line"> entities/</span><br><span class="line"> decisions/</span><br><span class="line"> practices/</span><br><span class="line"> conflicts.md</span><br><span class="line"> open-questions.md</span><br></pre></td></tr></table></figure><p>它的职责是:</p><ul><li>把资料整理成概念;</li><li>把概念互相连接;</li><li>记录引用;</li><li>标注冲突;</li><li>支持后续问答。</li></ul><h3 id="Schema-Instructions:像“图书馆馆规”"><a href="#Schema-Instructions:像“图书馆馆规”" class="headerlink" title="Schema / Instructions:像“图书馆馆规”"></a>Schema / Instructions:像“图书馆馆规”</h3><p>没有规则,agent 会乱写;有了规则,wiki 才能长期维护。</p><p>例如:</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">每个非平凡 claim 必须有 citation。</span><br><span class="line">无法验证的内容标记 [UNVERIFIED]。</span><br><span class="line">来源冲突标记 [CONFLICT]。</span><br><span class="line">删除或合并关键页面前必须人工审批。</span><br></pre></td></tr></table></figure><hr><h2 id="llm-wiki-与-RAG-的区别"><a href="#llm-wiki-与-RAG-的区别" class="headerlink" title="llm-wiki 与 RAG 的区别"></a>llm-wiki 与 RAG 的区别</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">flowchart LR</span><br><span class="line"> subgraph RAG[传统 RAG]</span><br><span class="line"> RQ[用户问题] --> RS[检索 top-k chunks]</span><br><span class="line"> RS --> RA[LLM 临时综合答案]</span><br><span class="line"> RA --> RO[答案结束\n通常不沉淀]</span><br><span class="line"> end</span><br><span class="line"></span><br><span class="line"> subgraph WIKI[llm-wiki]</span><br><span class="line"> S[新资料] --> I[Ingest 编译]</span><br><span class="line"> I --> K[Markdown 知识图谱]</span><br><span class="line"> Q[用户问题] --> K</span><br><span class="line"> K --> A[带引用答案]</span><br><span class="line"> A --> B{有复用价值?}</span><br><span class="line"> B -- 是 --> K</span><br><span class="line"> end</span><br></pre></td></tr></table></figure><table><thead><tr><th>维度</th><th>RAG</th><th>llm-wiki</th></tr></thead><tbody><tr><td>工作时机</td><td>问的时候搜</td><td>平时就整理,问时复用</td></tr><tr><td>知识形态</td><td>chunks + embeddings</td><td>Markdown pages + wikilinks + citations</td></tr><tr><td>是否复利</td><td>弱</td><td>强</td></tr><tr><td>可审计性</td><td>依赖检索日志</td><td>Git diff、引用、页面历史</td></tr><tr><td>冲突处理</td><td>临时判断</td><td>显式记录 conflicts</td></tr><tr><td>人类可读性</td><td>较弱</td><td>强</td></tr><tr><td>适合场景</td><td>局部事实查询、大规模原文召回</td><td>长期知识沉淀、概念图谱、决策记录、研究综合</td></tr></tbody></table><p>更准确地说,二者不是敌人:</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">RAG retrieves.</span><br><span class="line">llm-wiki compiles.</span><br><span class="line">GraphRAG connects.</span><br><span class="line">MCP exposes.</span><br><span class="line">Git audits.</span><br><span class="line">Lint maintains.</span><br><span class="line">Human arbitrates.</span><br></pre></td></tr></table></figure><hr><h2 id="三个核心动作:Ingest-Query-Lint"><a href="#三个核心动作:Ingest-Query-Lint" class="headerlink" title="三个核心动作:Ingest / Query / Lint"></a>三个核心动作:Ingest / Query / Lint</h2><h3 id="Ingest:不是“摘要”,而是“入库编目”"><a href="#Ingest:不是“摘要”,而是“入库编目”" class="headerlink" title="Ingest:不是“摘要”,而是“入库编目”"></a>Ingest:不是“摘要”,而是“入库编目”</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">sequenceDiagram</span><br><span class="line"> participant U as User</span><br><span class="line"> participant A as Agent</span><br><span class="line"> participant R as Raw Sources</span><br><span class="line"> participant W as Wiki</span><br><span class="line"> participant L as Log</span><br><span class="line"></span><br><span class="line"> U->>A: 导入一篇文章 / PDF / repo</span><br><span class="line"> A->>R: 保存原始资料</span><br><span class="line"> A->>W: 读取 index 和相关页面</span><br><span class="line"> A->>A: 提取概念、事实、冲突、引用</span><br><span class="line"> A->>W: 更新多个页面</span><br><span class="line"> A->>W: 添加 wikilinks 和 citations</span><br><span class="line"> A->>L: 记录 ingest log</span><br></pre></td></tr></table></figure><p>关键点:一篇资料不应该只生成“一篇摘要”。</p><p>更好的做法是:</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">一篇新文章</span><br><span class="line"> ├─ 更新 concept A</span><br><span class="line"> ├─ 更新 concept B</span><br><span class="line"> ├─ 新建 decision C</span><br><span class="line"> ├─ 给 practice D 加一个反例</span><br><span class="line"> ├─ 在 conflicts.md 记录冲突</span><br><span class="line"> └─ 在 sources.md 记录来源</span><br></pre></td></tr></table></figure><h3 id="Query:先查-wiki,再回-raw-source"><a href="#Query:先查-wiki,再回-raw-source" class="headerlink" title="Query:先查 wiki,再回 raw source"></a>Query:先查 wiki,再回 raw source</h3><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">用户问题</span><br><span class="line"> ↓</span><br><span class="line">查 wiki/index.md</span><br><span class="line"> ↓</span><br><span class="line">读相关页面 TLDR</span><br><span class="line"> ↓</span><br><span class="line">沿 wikilinks 扩展</span><br><span class="line"> ↓</span><br><span class="line">必要时回 raw source 核验</span><br><span class="line"> ↓</span><br><span class="line">输出带引用答案</span><br><span class="line"> ↓</span><br><span class="line">有长期价值则回写 wiki</span><br></pre></td></tr></table></figure><h3 id="Lint:知识库的“体检”"><a href="#Lint:知识库的“体检”" class="headerlink" title="Lint:知识库的“体检”"></a>Lint:知识库的“体检”</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">mindmap</span><br><span class="line"> root((Wiki Health))</span><br><span class="line"> Links</span><br><span class="line"> broken links</span><br><span class="line"> orphan pages</span><br><span class="line"> missing backlinks</span><br><span class="line"> Claims</span><br><span class="line"> uncited claims</span><br><span class="line"> unsupported claims</span><br><span class="line"> stale claims</span><br><span class="line"> Structure</span><br><span class="line"> duplicate pages</span><br><span class="line"> overlong pages</span><br><span class="line"> index drift</span><br><span class="line"> Trust</span><br><span class="line"> unverified facts</span><br><span class="line"> unresolved conflicts</span><br><span class="line"> missing provenance</span><br><span class="line"> Time</span><br><span class="line"> expired facts</span><br><span class="line"> superseded decisions</span><br><span class="line"> stale summaries</span><br></pre></td></tr></table></figure><p>没有 Lint,wiki 会慢慢腐化。</p><hr><h2 id="2025–2026-的新演化"><a href="#2025–2026-的新演化" class="headerlink" title="2025–2026 的新演化"></a>2025–2026 的新演化</h2><p>调研显示,llm-wiki 相关理念正在与多个方向合流。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">flowchart TD</span><br><span class="line"> K[llm-wiki\nAgent-maintained Markdown Knowledge Graph]</span><br><span class="line"></span><br><span class="line"> A[Basic Memory\nLocal-first Markdown Memory] --> K</span><br><span class="line"> B[DeepWiki\nRepo-to-wiki] --> K</span><br><span class="line"> C[GraphRAG\nGlobal sensemaking] --> K</span><br><span class="line"> D[LightRAG\nGraph + Vector retrieval] --> K</span><br><span class="line"> E[Graphiti\nTemporal agent memory] --> K</span><br><span class="line"> F[MCP\nResources / Tools] --> K</span><br><span class="line"> G[llms.txt\nLLM-facing docs entry] --> K</span><br><span class="line"> H[Docs-as-code\nGit + Markdown + Review] --> K</span><br></pre></td></tr></table></figure><h3 id="Basic-Memory:Markdown-是真相层"><a href="#Basic-Memory:Markdown-是真相层" class="headerlink" title="Basic Memory:Markdown 是真相层"></a>Basic Memory:Markdown 是真相层</h3><p>启发:</p><blockquote><p>Markdown 不只是导出格式,而是 canonical store。</p></blockquote><p>派生索引可以有很多种:</p><ul><li>SQLite FTS;</li><li>embeddings;</li><li>entity/relation table;</li><li>backlinks;</li><li>temporal facts。</li></ul><p>但它们都应该可以重建。</p><h3 id="DeepWiki:代码库可以自动长出-wiki"><a href="#DeepWiki:代码库可以自动长出-wiki" class="headerlink" title="DeepWiki:代码库可以自动长出 wiki"></a>DeepWiki:代码库可以自动长出 wiki</h3><p>启发:</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">GitHub repo → AI 生成 wiki → 搜索 / 聊天 / 理解架构</span><br></pre></td></tr></table></figure><p>这说明 <code>llm-wiki</code> 可以优先支持代码库:</p><ul><li>架构图;</li><li>模块职责;</li><li>调用链;</li><li>关键概念;</li><li>设计决策;</li><li>onboarding guide。</li></ul><h3 id="GraphRAG:回答全局问题"><a href="#GraphRAG:回答全局问题" class="headerlink" title="GraphRAG:回答全局问题"></a>GraphRAG:回答全局问题</h3><p>传统 RAG 擅长:</p><blockquote><p>“这个函数在哪?”<br>“这段文档怎么说?”</p></blockquote><p>GraphRAG 更适合:</p><blockquote><p>“整个项目有哪些核心模块?”<br>“这些概念之间是什么关系?”<br>“语料中有哪些冲突观点?”</p></blockquote><h3 id="LightRAG:图和向量不是二选一"><a href="#LightRAG:图和向量不是二选一" class="headerlink" title="LightRAG:图和向量不是二选一"></a>LightRAG:图和向量不是二选一</h3><p>最佳结构更像:</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Markdown canonical store</span><br><span class="line"> + Full-text search</span><br><span class="line"> + Vector search</span><br><span class="line"> + Graph relations</span><br><span class="line"> + Community summaries</span><br></pre></td></tr></table></figure><h3 id="Graphiti:事实需要时间维度"><a href="#Graphiti:事实需要时间维度" class="headerlink" title="Graphiti:事实需要时间维度"></a>Graphiti:事实需要时间维度</h3><p>旧事实不失效,是 agent memory 的大坑。</p><p>所以重要事实最好有:</p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">valid_from:</span> <span class="number">2025-01-01</span></span><br><span class="line"><span class="attr">valid_until:</span> <span class="number">2026-03-01</span></span><br><span class="line"><span class="attr">supersedes:</span> <span class="string">old-decision.md</span></span><br><span class="line"><span class="attr">superseded_by:</span> <span class="string">new-decision.md</span></span><br></pre></td></tr></table></figure><h3 id="MCP:让知识库可被-agent-使用"><a href="#MCP:让知识库可被-agent-使用" class="headerlink" title="MCP:让知识库可被 agent 使用"></a>MCP:让知识库可被 agent 使用</h3><p>MCP 适合作为暴露层:</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">list resources</span><br><span class="line">read page</span><br><span class="line">search wiki</span><br><span class="line">get backlinks</span><br><span class="line">get source metadata</span><br><span class="line">propose patch</span><br></pre></td></tr></table></figure><p>但 MCP 不解决治理问题。写回仍然需要 review、diff、approval。</p><h3 id="llms-txt:给外部-LLM-的入口"><a href="#llms-txt:给外部-LLM-的入口" class="headerlink" title="llms.txt:给外部 LLM 的入口"></a>llms.txt:给外部 LLM 的入口</h3><p><code>llm-wiki</code> 可以导出:</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">/llms.txt</span><br><span class="line">/llms-full.txt</span><br><span class="line">/wiki/index.md</span><br><span class="line">/wiki/topic-map.md</span><br><span class="line">/wiki/source-map.md</span><br></pre></td></tr></table></figure><p>让外部 agent 快速理解这个知识库。</p><h3 id="新进场者:从”想法”到”工厂-城市规划标准”"><a href="#新进场者:从”想法”到”工厂-城市规划标准”" class="headerlink" title="新进场者:从”想法”到”工厂 + 城市规划标准”"></a>新进场者:从”想法”到”工厂 + 城市规划标准”</h3><p>Karpathy 的 llm-wiki 是一份<strong>想法文件</strong>——把规则塞进 CLAUDE.md/AGENTS.md,让 agent 自己长出 wiki。2026 年的新故事是:有人开始<strong>专门造工厂</strong>(自动生成/维护 wiki 的工具),有人开始<strong>写城市规划标准</strong>(让不同来源的 wiki 能互通)。下面这张生态图把它们按职能分组。</p><h4 id="2026-OSS-实现生态图"><a href="#2026-OSS-实现生态图" class="headerlink" title="2026 OSS 实现生态图"></a>2026 OSS 实现生态图</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line">graph TD</span><br><span class="line"> Idea["Karpathy llm-wiki<br/>想法文件 (2026-04)"]</span><br><span class="line"></span><br><span class="line"> subgraph F1["🏭 制造工具:生成 + 维护 wiki"]</span><br><span class="line"> OW["OpenWiki (LangChain)<br/>repo 文档自动测绘队"]</span><br><span class="line"> OKB["OpenKB (VectifyAI/PageIndex)<br/>多格式知识编译车间"]</span><br><span class="line"> NSU["nashsu/llm_wiki<br/>可视化桌面 app"]</span><br><span class="line"> AS["AutoSci (PKU DAIR)<br/>科研全流程流水线"]</span><br><span class="line"> end</span><br><span class="line"></span><br><span class="line"> subgraph F2["📐 交换标准:让 wiki 互通"]</span><br><span class="line"> OKF["OKF (Google Cloud)<br/>城市规划标准 / 知识版 HTTP"]</span><br><span class="line"> end</span><br><span class="line"></span><br><span class="line"> subgraph F3["🔍 检索/工具配件"]</span><br><span class="line"> QMD["qmd (Tobi Lütke)<br/>本地混合搜索引擎"]</span><br><span class="line"> AM["AGENTS.md (Linux Foundation)<br/>agent 入场须知"]</span><br><span class="line"> end</span><br><span class="line"></span><br><span class="line"> Idea --> OW & OKB & NSU & AS</span><br><span class="line"> Idea -.->|形式化| OKF</span><br><span class="line"> OW -->|注入 pointer| AM</span><br><span class="line"> OKB -->|遵循| OKF</span><br><span class="line"> NSU -->|可选调用| QMD</span><br><span class="line"> OKF -.->|被消费| AM</span><br><span class="line"></span><br><span class="line"> classDef idea fill:#fff4e6,stroke:#f59f00,color:#000</span><br><span class="line"> classDef factory fill:#e7f5ff,stroke:#1c7ed6,color:#000</span><br><span class="line"> classDef standard fill:#e6fcf5,stroke:#0ca678,color:#000</span><br><span class="line"> classDef tool fill:#f3f0ff,stroke:#7048e8,color:#000</span><br><span class="line"> class Idea idea</span><br><span class="line"> class OW,OKB,NSU,AS factory</span><br><span class="line"> class OKF standard</span><br><span class="line"> class QMD,AM tool</span><br></pre></td></tr></table></figure><p>把这张图翻译成我们一直在用的<strong>城市比喻</strong>:</p><ul><li><strong>Karpathy 的想法文件</strong> = 一份手抄的”怎么自己盖一座城”的施工笔记。</li><li><strong>OpenWiki</strong> = 自动测绘队:扫一遍代码库就把地图(wiki)画好,还每天派 diff 巡逻队把变化补上。</li><li><strong>OpenKB</strong> = 编译车间 + 知识炼金炉:把 PDF/Word/PPT/网页统统投进去,炼成互相链接的 Markdown 知识库。</li><li><strong>nashsu/llm_wiki</strong> = 一座带 3D 地图、社区聚类、观光电梯的现代化知识城(桌面 app)。</li><li><strong>AutoSci</strong> = 全自动科研流水线:从读论文到做实验、写论文、做海报一条龙。</li><li><strong>OKF (Google)</strong> = 城市规划标准 / 知识版 HTTP:规定每栋楼(每个概念)必须挂什么门牌(<code>type</code> 字段)、街道怎么命名(文件路径即身份),让不同城市之间能互相读懂地图。</li><li><strong>qmd</strong> = 本地搜索引擎,相当于城里的”按意义找路”导航仪。</li><li><strong>AGENTS.md</strong> = 给所有 agent 的入场须知,告诉它们”进城先读哪份地图”。</li></ul><blockquote><p>一句话区分:<strong>制造工具解决”怎么把 wiki 长出来”,交换标准解决”长出来的 wiki 怎么互通”。</strong> 2026 年的变化是这两件事第一次被分开做。</p></blockquote><h3 id="四位新玩家速写"><a href="#四位新玩家速写" class="headerlink" title="四位新玩家速写"></a>四位新玩家速写</h3><p>下面每个小条目都遵守同一格式:<strong>是什么 / 与 llm-wiki 的关系 / 一个要小心的坑</strong>。</p><h4 id="OpenWiki(LangChain)—-自动测绘队"><a href="#OpenWiki(LangChain)—-自动测绘队" class="headerlink" title="OpenWiki(LangChain)— 自动测绘队"></a>OpenWiki(LangChain)— 自动测绘队</h4><ul><li><strong>是什么</strong>:TypeScript CLI(<code>npm i -g openwiki</code>),基于 LangChain 的 DeepAgents,给代码库生成一份 <code>openwiki/</code> 目录的 Markdown wiki;再在顶层 AGENTS.md/CLAUDE.md 里<strong>只插一小段指路牌</strong>(pointer),让已有编码 agent 按需去读 wiki,而不是把整本 wiki 塞进上下文。配套 GitHub Action 每天按 git diff 自动开 PR 保鲜。</li><li><strong>与 llm-wiki 的关系</strong>:把 Karpathy 的”人类手工 + 通用 agent 维护 wiki”升级为<strong>专用生成器 + CI 自维护器</strong>;专门解决 Karpathy 留给用户的”wiki 怎么和 agent 接线”和”怎么不腐烂”两个痛点。范围比 llm-wiki 窄——目前只面向代码库(博客说未来可能扩到其他工作流)。</li><li><strong>坑</strong>:v0.0.1、repo 仅约两周大(2026-06-22 创建)、约 7k 星基本是发布博客带起来的热度,<strong>不是耐久度</strong>。预设模型清单(constants.ts 核验)实为 GLM 5.2 / Kimi K2.7 Code / Claude Sonnet 5——部分二手报道误写成 K2.6。无 MCP、无 llms.txt、无任何 FTS/向量/图索引——“wiki for agents”的框架下,检索其实只是 agent 直接读 Markdown。</li></ul><blockquote><p><strong>比喻</strong>:OpenWiki 是”只在城门口立一块指路牌”的设计——地图(wiki)和指路牌(AGENTS.md 里那几行)分开,既避免上下文爆炸,又让 wiki 可以独立长大。</p></blockquote><h4 id="OpenKB(VectifyAI-PageIndex)—-编译车间-知识炼金炉"><a href="#OpenKB(VectifyAI-PageIndex)—-编译车间-知识炼金炉" class="headerlink" title="OpenKB(VectifyAI / PageIndex)— 编译车间 + 知识炼金炉"></a>OpenKB(VectifyAI / PageIndex)— 编译车间 + 知识炼金炉</h4><ul><li><strong>是什么</strong>:Apache-2.0 Python CLI(<code>pip install openkb</code>),把 PDF/Word/PPT/Excel/HTML/CSV/URL 等多格式原料编译成一份结构化、互相链接的 Markdown wiki(<code>summaries/ concepts/ entities/</code>),用 <code>[[wikilinks]]</code> 串联,Obsidian 可直接打开。卖点”<strong>无向量数据库</strong>“:长 PDF(默认 ≥20 页)走 PageIndex 的<strong>无向量、推理式树索引</strong>,短文档直接全文喂给 LLM。带 query/chat/skill factory/可视化/deck 等生成器。</li><li><strong>与 llm-wiki 的关系</strong>:README 明说”基于 Karpathy 描述的概念”,并逐条对比自己比 Karpathy 多做了什么——其中最关键一条是<strong>直接解决 Karpathy 自己点名的”长 PDF 难题”</strong>(Karpathy 承认长文档会上下文腐烂)。把”丢网页剪报到 .md”的输入扩到 PDF/Office/URL 全家桶;把手工维护概念页换成自动实体抽取(人/组织/地点/产品)。</li><li><strong>坑</strong>:仍是 Alpha(pyproject 分类器写明 Development Status :: 3 - Alpha)。”长 PDF 质量”完全押在 PageIndex 引擎上,开源版能力有限,进阶功能(扫描版 PDF OCR、更快结构生成)要走付费的 PageIndex Cloud(<code>PAGEINDEX_API_KEY</code>)。PageIndex 树索引目前<strong>只支持 PDF</strong>,非 PDF 长文仍走全文读取,照样撞上下文墙。</li></ul><blockquote><p><strong>比喻</strong>:OpenKB 是”只炼不埋”的炼金炉——知识在 ingest 时就被炼成结构化页面,query 时只是去取成品,而不是每次重新淘金(这正是它对标 RAG 的核心论点)。</p></blockquote><h4 id="nashsu-llm-wiki-—-一座可视化桌面知识城"><a href="#nashsu-llm-wiki-—-一座可视化桌面知识城" class="headerlink" title="nashsu/llm_wiki — 一座可视化桌面知识城"></a>nashsu/llm_wiki — 一座可视化桌面知识城</h4><ul><li><strong>是什么</strong>:跨平台 Tauri v2 桌面 app(macOS/Windows/Linux),把文档变成互相链接的 Markdown wiki,配 GUI、4 信号知识图谱(直接链接 ×3.0 / 来源重叠 ×4.0 / Adamic-Adar ×1.5 / 类型亲和 ×1.0)、Louvain 社区检测、可选 LanceDB 向量搜索、深度研究、Chrome 剪藏扩展、本地 HTTP API + MCP server + 可装 agent skill。仓库自带一份 <code>llm-wiki.md</code>,把 Karpathy 的模式文字逐字收录。</li><li><strong>与 llm-wiki 的关系</strong>:README 写明”based on Karpathy’s LLM Wiki pattern”,<strong>忠实保留</strong>三层架构(raw 不可变 / wiki LLM 生成 / schema 规则)、Ingest/Query/Lint 三操作、index.md/log.md/[[wikilinks]]/YAML frontmatter/Obsidian 兼容;<strong>大幅扩展</strong>为产品化 app:两步思维链 ingest(先分析后生成)、purpose.md(wiki 的方向意图,每次 ingest/query 都读)、SHA256 增量缓存、持久化 ingest 队列、文件夹监听、深度研究、异步 review 队列、级联删除等。</li><li><strong>坑</strong>:GPL-3.0(copyleft,商用嵌入要留意)。仓库仅约 3 个月大(2026-04-08 创建)就有 1.37 万星,增速惊人但<strong>长期维护未经验证</strong>。README 自报的”recall 58.2%→71.4%”是自测,无第三方复现。本地 PDF 解析实际用 <code>pdfium-render</code>(README 误标为 “pdf-extract”);<strong>可选的 MinerU 云端 PDF 解析(默认关闭,失败回退本地)会把文件传第三方云</strong>,与 “local-first” 叙事略有张力。</li></ul><blockquote><p><strong>比喻</strong>:nashsu/llm_wiki 是”带观光电梯的现代化知识城”——你既能像 Obsidian 一样在地上走,也能坐电梯(GUI + 图谱)从空中看全城分区。</p></blockquote><h4 id="Google-OKF-—-城市规划标准-知识版-HTTP"><a href="#Google-OKF-—-城市规划标准-知识版-HTTP" class="headerlink" title="Google OKF — 城市规划标准 / 知识版 HTTP"></a>Google OKF — 城市规划标准 / 知识版 HTTP</h4><ul><li><strong>是什么</strong>:Google Cloud 在 2026-06-12 发布的开放规范 v0.1 Draft。一个”知识包”就是一目录 Markdown 文件(一个概念一个文件),唯一<strong>必填</strong> frontmatter 字段是 <code>type</code>;推荐字段 title/description/resource/tags/timestamp。文件路径(去掉 .md)就是概念身份。保留文件名 <code>index.md</code>(渐进式目录)和 <code>log.md</code>(按日期分组的变更史)。交叉链接用普通 Markdown 链接,把目录变成比父子层级更丰富的图。<strong>显式</strong>不规定存储/服务/查询基础设施,不定义 FTS/向量/图索引——这些全部留给消费端。</li><li><strong>与 llm-wiki 的关系</strong>:Google 博客直接引 Karpathy 原话(”LLMs 不会无聊、不会忘记更新交叉引用、一次能改 15 个文件”),把 OKF 定位为”把 LLM-wiki 模式正式化为可移植、可互操作的格式”。SPEC 第 10 节把”用 Markdown + frontmatter 做 agent 可读知识库的 LLM wiki 仓库”列为最近的同类模式,区别在于 OKF 是<strong>被规范化的</strong>——钉死了最小互操作约定(必填 type、保留文件名、链接语义、宽容一致性)。可看作 Karpathy 模式的”最小公约数超集”:任何已有 wiki 只要加一个 <code>type</code> 字段就合规。</li><li><strong>坑</strong>:v0.1 Draft,会变。仓库挂 GoogleCloudPlatform 名却自带”not an official Google product”免责声明。发布会现场唯一确认的生产消费者是 Google 自家的 Knowledge Catalog(前 Dataplex)——跨生产者/消费者的真实互操作<strong>尚未被证明</strong>。规范本身<strong>不含</strong> MCP/llms.txt/任何运行时协议;它只是一份文件格式契约。</li></ul><blockquote><p><strong>比喻</strong>:OKF 不盖楼,只发布”城市规划标准”——只要每栋楼挂对门牌(type),任何城市的地图(不同生产者产出的 wiki)都能被任何游客(agent)读懂。它是知识界的 HTTP:一个最小约定,换最大互通。</p></blockquote><h3 id="我该选哪个?一张决策表"><a href="#我该选哪个?一张决策表" class="headerlink" title="我该选哪个?一张决策表"></a>我该选哪个?一张决策表</h3><p>下面这张表把本章出现的新工具按”最适合干嘛”排成一列,帮你按场景对号入座。<strong>重要前提</strong>:它们大多数非常年轻(几周到几个月大),star 数 ≠ 耐久度;任何生产采用前请回源核对最新状态。</p><table><thead><tr><th>你的场景</th><th>优先考虑</th><th>为什么</th><th>一句话 caveat</th></tr></thead><tbody><tr><td>想给一个 <strong>GitHub 代码库</strong>自动生成并 CI 自维护一份给 agent 用的文档</td><td><strong>OpenWiki</strong></td><td>自动测绘队 + 每天按 git diff 开 PR,AGENTS.md 只插 pointer 不撑爆上下文</td><td>v0.0.1、仅 ~2 周大,无向量/FTS/图索引,检索靠 agent 直读 Markdown</td></tr><tr><td>有<strong>长 PDF / Word / PPT / 网页</strong>混合资料,想编译成 Obsidian 可读的知识库</td><td><strong>OpenKB</strong></td><td>多格式 ingest + 无向量 PageIndex 树索引,专治 Karpathy 点名的长 PDF 难题</td><td>Alpha 阶段;长 PDF 质量押在 PageIndex,进阶功能走付费云;非 PDF 长文仍撞上下文墙</td></tr><tr><td>想要一个<strong>带 GUI / 图谱 / 可视化</strong>的桌面”第二大脑”,跨平台</td><td><strong>nashsu/llm_wiki</strong></td><td>Tauri 桌面 app,4 信号图谱 + Louvain 社区 + 可选向量 + 深度研究 + Chrome 剪藏</td><td>GPL-3.0(copyleft);3 个月大 1.37 万星但长期维护未证;自测 recall 未第三方复现</td></tr><tr><td>要做<strong>科研全流程</strong>:读论文→点子→实验→写论文→海报</td><td><strong>AutoSci</strong></td><td>30+ Claude Code 技能覆盖全生命周期 + 双模型交叉评审 + 远程 GPU + arXiv 配套论文</td><td>仅 Claude Code 耦合;README 自承”No native MCP”是错的(实际含 llm-review MCP);3 个月大、internal beta</td></tr><tr><td>你已经有 wiki,想让<strong>不同工具/团队/agent</strong>能互相读懂对方的 wiki</td><td><strong>OKF</strong>(给所有页面加 <code>type</code> 字段)</td><td>最小公约数换最大互通,知识版 HTTP;Google Knowledge Catalog 已 ingest</td><td>v0.1 Draft;唯一确认生产消费者是 Google 自家;跨组织互操作未被证明</td></tr><tr><td>你只想给 agent 一个<strong>本地混合搜索</strong>(BM25 + 向量 + 重排),不换 wiki 形态</td><td><strong>qmd</strong>(Tobi Lütke)</td><td>完全本地、GGUF 模型、CLI + MCP server,Karpathy gist 亲自推荐</td><td>首跑下载 ~2GB 模型;Node.js ≥22;默认 glob 是 <code>**/*.md</code></td></tr><tr><td>你只想给 agent 一份<strong>入场须知</strong>,让它知道”进城先读哪份地图”</td><td><strong>AGENTS.md</strong>(Linux Foundation)</td><td>跨厂商事实标准,60k+ 项目在用,MCP 同基金会托管</td><td>不是知识库,只是单文件约定;60k 数字是自报营销;托管方是 Linux Foundation(非 OpenAI)</td></tr></tbody></table><h4 id="三条决策捷径"><a href="#三条决策捷径" class="headerlink" title="三条决策捷径"></a>三条决策捷径</h4><ol><li><strong>要 CI 自维护的 repo 文档 → OpenWiki。</strong> 它是唯一一个把”git diff 驱动每日 PR”做成头等公民的。</li><li><strong>要长 PDF / 多格式知识库 → OpenKB。</strong> 它是唯一一个把”无向量长文档检索”当核心卖点的。</li><li><strong>要让多个工具互通 → 给所有输出加 OKF 的 <code>type</code> 字段。</strong> 这是成本最低的”未来兼容”保险。</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">flowchart LR</span><br><span class="line"> Q1{"要给代码库<br/>做文档?"}</span><br><span class="line"> Q2{"有长 PDF/<br/>多格式资料?"}</span><br><span class="line"> Q3{"要可视化<br/>桌面端?"}</span><br><span class="line"> Q4{"要让多个工具<br/>互通?"}</span><br><span class="line"></span><br><span class="line"> Q1 -- 是 --> OW[OpenWiki]</span><br><span class="line"> Q1 -- 否 --> Q2</span><br><span class="line"> Q2 -- 是 --> OKB[OpenKB]</span><br><span class="line"> Q2 -- 否 --> Q3</span><br><span class="line"> Q3 -- 是 --> NSU[nashsu/llm_wiki]</span><br><span class="line"> Q3 -- 否 --> Q4</span><br><span class="line"> Q4 -- 是 --> OKF[给页面加 OKF type 字段]</span><br><span class="line"> Q4 -- 否 --> RAW[继续用 Karpathy 原版<br/>+ AGENTS.md 指针]</span><br><span class="line"></span><br><span class="line"> classDef pick fill:#d3f9d8,stroke:#2f9e44,color:#000</span><br><span class="line"> class OW,OKB,NSU,OKF pick</span><br></pre></td></tr></table></figure><blockquote><p><strong>一句话总结这一节</strong>:2026 年的变化不是”又有了一个新 llm-wiki”,而是<strong>生态开始分工</strong>——有人专做制造(OpenWiki/OpenKB),有人专做标准(OKF),有人专做配件(qmd/AGENTS.md)。你不再需要在”一个工具搞定一切”和”从零手搓”之间二选一。</p></blockquote><hr><h2 id="推荐的现代架构"><a href="#推荐的现代架构" class="headerlink" title="推荐的现代架构"></a>推荐的现代架构</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line">flowchart TB</span><br><span class="line"> subgraph Canonical[Markdown Canonical Store 真相层]</span><br><span class="line"> C1[wiki pages]</span><br><span class="line"> C2[source notes]</span><br><span class="line"> C3[decisions]</span><br><span class="line"> C4[observations]</span><br><span class="line"> C5[llms.txt / index]</span><br><span class="line"> end</span><br><span class="line"></span><br><span class="line"> subgraph Raw[Raw Source Store 原始资料层]</span><br><span class="line"> R1[web snapshots]</span><br><span class="line"> R2[PDFs]</span><br><span class="line"> R3[transcripts]</span><br><span class="line"> R4[code dumps]</span><br><span class="line"> end</span><br><span class="line"></span><br><span class="line"> subgraph Index[Derived Indexes 可重建索引层]</span><br><span class="line"> I1[SQLite FTS]</span><br><span class="line"> I2[Embeddings]</span><br><span class="line"> I3[Entity / Relation Table]</span><br><span class="line"> I4[Backlinks]</span><br><span class="line"> I5[Temporal Facts]</span><br><span class="line"> I6[Community Summaries]</span><br><span class="line"> end</span><br><span class="line"></span><br><span class="line"> subgraph Interface[Agent Interface 交互层]</span><br><span class="line"> A1[CLI]</span><br><span class="line"> A2[MCP Resources]</span><br><span class="line"> A3[MCP Tools]</span><br><span class="line"> A4[Editor Integration]</span><br><span class="line"> A5[Scheduled Workflows]</span><br><span class="line"> end</span><br><span class="line"></span><br><span class="line"> subgraph Gov[Governance 治理层]</span><br><span class="line"> G1[Citations]</span><br><span class="line"> G2[Provenance]</span><br><span class="line"> G3[Confidence]</span><br><span class="line"> G4[valid_from / valid_until]</span><br><span class="line"> G5[Diff Review]</span><br><span class="line"> G6[Approval Policy]</span><br><span class="line"> G7[Evaluation Metrics]</span><br><span class="line"> end</span><br><span class="line"></span><br><span class="line"> Raw --> Canonical</span><br><span class="line"> Canonical --> Index</span><br><span class="line"> Index --> Interface</span><br><span class="line"> Interface --> Canonical</span><br><span class="line"> Gov --> Canonical</span><br><span class="line"> Gov --> Interface</span><br></pre></td></tr></table></figure><p>设计原则:</p><blockquote><p>Markdown 是真相层;索引是派生层;agent 写回必须受治理约束。</p></blockquote><hr><h2 id="一个页面应该长什么样?"><a href="#一个页面应该长什么样?" class="headerlink" title="一个页面应该长什么样?"></a>一个页面应该长什么样?</h2><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line">---</span><br><span class="line">type: concept</span><br><span class="line">title: Agent-maintained wiki</span><br><span class="line">status: draft</span><br><span class="line">confidence: medium</span><br><span class="line">sources:</span><br><span class="line"><span class="bullet"> -</span> raw/web/karpathy-llm-wiki.md</span><br><span class="line"><span class="bullet"> -</span> raw/web/basic-memory.md</span><br><span class="line">valid<span class="emphasis">_from: 2025-01-01</span></span><br><span class="line"><span class="emphasis">valid_</span>until:</span><br><span class="line">generated<span class="emphasis">_by: claude</span></span><br><span class="line"><span class="emphasis">reviewed_</span>by:</span><br><span class="line">---</span><br><span class="line"></span><br><span class="line"><span class="section"># Agent-maintained wiki</span></span><br><span class="line"></span><br><span class="line"><span class="section">## TLDR</span></span><br><span class="line"></span><br><span class="line">Agent-maintained wiki 是由 LLM 持续维护的 Markdown 知识图谱,用于把阅读、问答、纠错沉淀为长期可复用知识。</span><br><span class="line"></span><br><span class="line"><span class="section">## Key Claims</span></span><br><span class="line"></span><br><span class="line"><span class="bullet">-</span> 它与传统 RAG 的区别在于:知识不是只在 query-time 临时检索,而是在 ingest/maintenance 阶段持续编译。[source: raw/web/karpathy-llm-wiki.md]</span><br><span class="line"><span class="bullet">-</span> Markdown 适合作为 canonical store,因为它可读、可 diff、可迁移。[source: raw/web/basic-memory.md]</span><br><span class="line"></span><br><span class="line"><span class="section">## Relations</span></span><br><span class="line"></span><br><span class="line"><span class="bullet">-</span> related<span class="emphasis">_to: [[RAG]]</span></span><br><span class="line"><span class="emphasis">- contrasts_</span>with: [[Vector Database]]</span><br><span class="line"><span class="bullet">-</span> enables: [[Knowledge Compounding]]</span><br><span class="line"><span class="bullet">-</span> exposed<span class="emphasis">_by: [[MCP Resources]]</span></span><br><span class="line"><span class="emphasis"></span></span><br><span class="line"><span class="emphasis">## Open Questions</span></span><br><span class="line"><span class="emphasis"></span></span><br><span class="line"><span class="emphasis">- 如何自动判断页面粒度?</span></span><br><span class="line"><span class="emphasis">- 哪些 agent 写回可以自动合并?</span></span><br><span class="line"><span class="emphasis"></span></span><br><span class="line"><span class="emphasis">## Conflicts</span></span><br><span class="line"><span class="emphasis"></span></span><br><span class="line"><span class="emphasis">- [CONFLICT] 某些实践主张纯 Markdown 足够,GraphRAG 路线主张额外构建图索引。</span></span><br></pre></td></tr></table></figure><hr><h2 id="失败模式:知识花园也会长杂草"><a href="#失败模式:知识花园也会长杂草" class="headerlink" title="失败模式:知识花园也会长杂草"></a>失败模式:知识花园也会长杂草</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">flowchart TD</span><br><span class="line"> F[失败模式]</span><br><span class="line"> F --> A[幻觉固化\n生成内容被当事实]</span><br><span class="line"> F --> B[引用漂移\ncitation 不支持 claim]</span><br><span class="line"> F --> C[旧事实不失效\nstale knowledge]</span><br><span class="line"> F --> D[结构腐化\nindex 和页面不同步]</span><br><span class="line"> F --> E[图抽取错误\n实体重复/关系错]</span><br><span class="line"> F --> G[写回污染\nagent 无审查改 wiki]</span><br><span class="line"> F --> H[粒度失控\n页面太粗或太碎]</span><br><span class="line"></span><br><span class="line"> A --> M1[claim-level citation]</span><br><span class="line"> B --> M2[source quote / provenance]</span><br><span class="line"> C --> M3[valid_from / valid_until]</span><br><span class="line"> D --> M4[lint / health report]</span><br><span class="line"> E --> M5[entity resolution / graph diff]</span><br><span class="line"> G --> M6[propose patch + review]</span><br><span class="line"> H --> M7[evolve workflow]</span><br></pre></td></tr></table></figure><p>最重要的原则:</p><blockquote><p>生成内容不是事实,带来源、可核验、可审计的内容才逐渐接近事实。</p></blockquote><hr><h2 id="评估指标:怎么知道-wiki-真的在变好?"><a href="#评估指标:怎么知道-wiki-真的在变好?" class="headerlink" title="评估指标:怎么知道 wiki 真的在变好?"></a>评估指标:怎么知道 wiki 真的在变好?</h2><h3 id="回答质量"><a href="#回答质量" class="headerlink" title="回答质量"></a>回答质量</h3><table><thead><tr><th>指标</th><th>含义</th></tr></thead><tbody><tr><td>answer groundedness</td><td>答案是否被来源支持</td></tr><tr><td>citation coverage</td><td>关键 claim 是否有引用</td></tr><tr><td>unsupported claim rate</td><td>无来源 claim 的比例</td></tr><tr><td>query success rate</td><td>用户问题是否被有效回答</td></tr><tr><td>source fallback rate</td><td>回 raw source 的频率</td></tr></tbody></table><h3 id="Wiki-健康"><a href="#Wiki-健康" class="headerlink" title="Wiki 健康"></a>Wiki 健康</h3><table><thead><tr><th>指标</th><th>含义</th></tr></thead><tbody><tr><td>broken link rate</td><td>断链比例</td></tr><tr><td>orphan page rate</td><td>孤儿页比例</td></tr><tr><td>duplicate entity rate</td><td>重复实体比例</td></tr><tr><td>stale claim count</td><td>过期 claim 数量</td></tr><tr><td>unresolved conflict count</td><td>未解决冲突数量</td></tr><tr><td>source coverage</td><td>raw source 被 wiki 表达的比例</td></tr></tbody></table><h3 id="Agent-写回治理"><a href="#Agent-写回治理" class="headerlink" title="Agent 写回治理"></a>Agent 写回治理</h3><table><thead><tr><th>指标</th><th>含义</th></tr></thead><tbody><tr><td>proposed patch count</td><td>agent 提议修改数</td></tr><tr><td>accepted patch rate</td><td>被接受比例</td></tr><tr><td>rejected patch rate</td><td>被拒绝比例</td></tr><tr><td>revert rate</td><td>回滚比例</td></tr><tr><td>human edit latency</td><td>人工审查延迟</td></tr><tr><td>high-risk write attempts</td><td>高风险写入尝试</td></tr></tbody></table><h3 id="成本"><a href="#成本" class="headerlink" title="成本"></a>成本</h3><table><thead><tr><th>指标</th><th>含义</th></tr></thead><tbody><tr><td>ingest cost per source</td><td>每个 source 的导入成本</td></tr><tr><td>query token cost</td><td>每次回答 token 成本</td></tr><tr><td>index rebuild cost</td><td>重建索引成本</td></tr><tr><td>graph extraction cost</td><td>图抽取成本</td></tr><tr><td>source-to-wiki compression ratio</td><td>原文到 wiki 的压缩比例</td></tr></tbody></table><hr><h2 id="推荐路线图"><a href="#推荐路线图" class="headerlink" title="推荐路线图"></a>推荐路线图</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">gantt</span><br><span class="line"> title llm-wiki 路线图</span><br><span class="line"> dateFormat YYYY-MM-DD</span><br><span class="line"> section Phase 0</span><br><span class="line"> 定义目标对象 :a1, 2026-06-20, 7d</span><br><span class="line"> section Phase 1</span><br><span class="line"> Markdown canonical schema :a2, after a1, 14d</span><br><span class="line"> section Phase 2</span><br><span class="line"> 可重建索引 :a3, after a2, 21d</span><br><span class="line"> section Phase 3</span><br><span class="line"> Ingest / Query / Lint CLI :a4, after a3, 21d</span><br><span class="line"> section Phase 4</span><br><span class="line"> MCP resources first :a5, after a4, 21d</span><br><span class="line"> section Phase 5</span><br><span class="line"> Temporal provenance layer :a6, after a5, 21d</span><br><span class="line"> section Phase 6</span><br><span class="line"> Evaluation and governance :a7, after a6, 21d</span><br></pre></td></tr></table></figure><h3 id="Phase-0:定义目标对象"><a href="#Phase-0:定义目标对象" class="headerlink" title="Phase 0:定义目标对象"></a>Phase 0:定义目标对象</h3><p>先决定 <code>llm-wiki</code> 优先服务什么:</p><ul><li>代码库文档;</li><li>个人知识管理;</li><li>团队决策记录;</li><li>research corpus;</li><li>agent memory。</li></ul><p>推荐先从:</p><blockquote><p>research corpus + project knowledge</p></blockquote><p>开始,最容易验证闭环。</p><h3 id="Phase-1:Markdown-canonical-schema"><a href="#Phase-1:Markdown-canonical-schema" class="headerlink" title="Phase 1:Markdown canonical schema"></a>Phase 1:Markdown canonical schema</h3><p>先定义页面结构,而不是先做复杂 UI。</p><p>必须明确:</p><ul><li>页面类型;</li><li>frontmatter;</li><li>source/provenance;</li><li>confidence;</li><li>valid_from / valid_until;</li><li>generated_by / reviewed_by;</li><li>typed relations。</li></ul><h3 id="Phase-2:可重建索引"><a href="#Phase-2:可重建索引" class="headerlink" title="Phase 2:可重建索引"></a>Phase 2:可重建索引</h3><p>建立:</p><ul><li>full-text search;</li><li>backlinks;</li><li>source map;</li><li>entity/relation table;</li><li>embeddings;</li><li>temporal fact table。</li></ul><h3 id="Phase-3:核心-CLI"><a href="#Phase-3:核心-CLI" class="headerlink" title="Phase 3:核心 CLI"></a>Phase 3:核心 CLI</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">llm-wiki ingest <<span class="built_in">source</span>></span><br><span class="line">llm-wiki query <span class="string">"<question>"</span></span><br><span class="line">llm-wiki lint</span><br><span class="line">llm-wiki evolve</span><br></pre></td></tr></table></figure><h3 id="Phase-4:MCP-resources-first"><a href="#Phase-4:MCP-resources-first" class="headerlink" title="Phase 4:MCP resources first"></a>Phase 4:MCP resources first</h3><p>先做只读 MCP:</p><ul><li>list pages;</li><li>read page;</li><li>search;</li><li>backlinks;</li><li>sources;</li><li>health report。</li></ul><p>写操作只提供 propose patch,不直接改。</p><h3 id="Phase-5:Temporal-and-provenance-layer"><a href="#Phase-5:Temporal-and-provenance-layer" class="headerlink" title="Phase 5:Temporal and provenance layer"></a>Phase 5:Temporal and provenance layer</h3><p>加入:</p><ul><li>valid_from;</li><li>valid_until;</li><li>supersedes;</li><li>superseded_by;</li><li>source quote;</li><li>source trust;</li><li>stale lint。</li></ul><h3 id="Phase-6:Evaluation-and-governance"><a href="#Phase-6:Evaluation-and-governance" class="headerlink" title="Phase 6:Evaluation and governance"></a>Phase 6:Evaluation and governance</h3><p>建立:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">llm-wiki health</span><br></pre></td></tr></table></figure><p>输出 health report,让 wiki 可长期维护。</p><hr><h2 id="最终心智模型"><a href="#最终心智模型" class="headerlink" title="最终心智模型"></a>最终心智模型</h2><p>如果把知识系统比作城市:</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">Raw Sources 是档案馆</span><br><span class="line">Wiki Pages 是城市街区</span><br><span class="line">Wikilinks 是道路</span><br><span class="line">Index 是地图</span><br><span class="line">Citations 是门牌和产权证明</span><br><span class="line">Lint 是城管和质检</span><br><span class="line">MCP 是城市 API</span><br><span class="line">llms.txt 是游客指南</span><br><span class="line">GraphRAG 是城市规划图</span><br><span class="line">Temporal Memory 是历史档案</span><br><span class="line">Human Review 是市政审批</span><br><span class="line">Agent 是图书管理员 + 城市维护工</span><br></pre></td></tr></table></figure><p>真正的 llm-wiki 不是“自动写几篇 Markdown”,而是:</p><blockquote><p>一个由 agent 持续维护、由 human 审查裁决、以 Markdown 为真相层、以引用和时间维度保证可信、以索引和协议连接外部工具的知识基础设施。</p></blockquote><hr><h2 id="可以直接对外讲的版本"><a href="#可以直接对外讲的版本" class="headerlink" title="可以直接对外讲的版本"></a>可以直接对外讲的版本</h2><h3 id="30-秒版本"><a href="#30-秒版本" class="headerlink" title="30 秒版本"></a>30 秒版本</h3><p><code>llm-wiki</code> 是一种让 LLM 长期维护知识库的方法。它不是每次问问题时临时 RAG,而是把资料提前整理成带引用、带链接、可审计的 Markdown 知识图谱。每次导入资料、回答问题、发现冲突,都会让知识库变得更好。</p><h3 id="2-分钟版本"><a href="#2-分钟版本" class="headerlink" title="2 分钟版本"></a>2 分钟版本</h3><p>传统 RAG 像临时翻资料:用户问问题,系统检索几个片段,然后让 LLM 拼答案。问题是,每次推理都不一定沉淀,冲突和纠错也很难长期保留。</p><p><code>llm-wiki</code> 的做法是把 LLM 变成长期图书管理员。新资料进入时,agent 把它保存为 raw source,然后更新多个 Markdown wiki 页面,添加引用、交叉链接、冲突标记和开放问题。用户提问时,agent 先读已经整理好的 wiki,必要时回原始资料核验。好的答案还可以回写进 wiki。</p><p>现代版本的 <code>llm-wiki</code> 还可以叠加全文搜索、向量检索、图索引、MCP、llms.txt 和 temporal memory。但核心原则不变:Markdown 是可读、可 diff、可迁移的真相层;索引是可重建的派生层;agent 写回必须受治理约束。</p><h3 id="一句话项目宣言"><a href="#一句话项目宣言" class="headerlink" title="一句话项目宣言"></a>一句话项目宣言</h3><blockquote><p><code>llm-wiki</code> is an agent-maintained, source-cited, Markdown-native knowledge graph with rebuildable search, graph, and vector indexes. It turns reading, reasoning, Q&A, and corrections into a persistent, auditable, temporally aware compounding artifact.</p></blockquote><hr><h2 id="Sources"><a href="#Sources" class="headerlink" title="Sources"></a>Sources</h2><p>主要参考:</p><ul><li>Karpathy Gist:<span class="exturl" data-url="aHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20va2FycGF0aHkvNDQyYTZiZjU1NTkxNDg5M2U5ODkxYzExNTE5ZGU5NGY=">https://gist.github.com/karpathy/442a6bf555914893e9891c11519de94f<i class="fa fa-external-link-alt"></i></span></li><li>Karpathy Gist raw:<span class="exturl" data-url="aHR0cHM6Ly9naXN0LmdpdGh1YnVzZXJjb250ZW50LmNvbS9rYXJwYXRoeS80NDJhNmJmNTU1OTE0ODkzZTk4OTFjMTE1MTlkZTk0Zi9yYXcvbGxtLXdpa2kubWQ=">https://gist.githubusercontent.com/karpathy/442a6bf555914893e9891c11519de94f/raw/llm-wiki.md<i class="fa fa-external-link-alt"></i></span></li><li>Basic Memory:<span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2Jhc2ljbWFjaGluZXMtY28vYmFzaWMtbWVtb3J5">https://github.com/basicmachines-co/basic-memory<i class="fa fa-external-link-alt"></i></span></li><li>DeepWiki:<span class="exturl" data-url="aHR0cHM6Ly9jb2duaXRpb24uY29tL2Jsb2cvZGVlcHdpa2k=">https://cognition.com/blog/deepwiki<i class="fa fa-external-link-alt"></i></span></li><li>Graphiti:<span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2dldHplcC9ncmFwaGl0aQ==">https://github.com/getzep/graphiti<i class="fa fa-external-link-alt"></i></span></li><li>Microsoft GraphRAG:<span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL21pY3Jvc29mdC9ncmFwaHJhZw==">https://github.com/microsoft/graphrag<i class="fa fa-external-link-alt"></i></span></li><li>GraphRAG paper:<span class="exturl" data-url="aHR0cHM6Ly9hcnhpdi5vcmcvYWJzLzI0MDQuMTYxMzA=">https://arxiv.org/abs/2404.16130<i class="fa fa-external-link-alt"></i></span></li><li>LightRAG paper:<span class="exturl" data-url="aHR0cHM6Ly9hcnhpdi5vcmcvYWJzLzI0MTAuMDU3Nzk=">https://arxiv.org/abs/2410.05779<i class="fa fa-external-link-alt"></i></span></li><li>LightRAG repo:<span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL0hLVURTL0xpZ2h0UkFH">https://github.com/HKUDS/LightRAG<i class="fa fa-external-link-alt"></i></span></li><li>MCP Resources:<span class="exturl" data-url="aHR0cHM6Ly9tb2RlbGNvbnRleHRwcm90b2NvbC5pby9kb2NzL2NvbmNlcHRzL3Jlc291cmNlcw==">https://modelcontextprotocol.io/docs/concepts/resources<i class="fa fa-external-link-alt"></i></span></li><li>llms.txt:<span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL0Fuc3dlckRvdEFJL2xsbXMtdHh0">https://github.com/AnswerDotAI/llms-txt<i class="fa fa-external-link-alt"></i></span></li><li>Claude Code memory docs:<span class="exturl" data-url="aHR0cHM6Ly9jb2RlLmNsYXVkZS5jb20vZG9jcy9lbi9tZW1vcnk=">https://code.claude.com/docs/en/memory<i class="fa fa-external-link-alt"></i></span></li></ul><h3 id="2026-07-07-增量(§6-8–6-10)新增来源"><a href="#2026-07-07-增量(§6-8–6-10)新增来源" class="headerlink" title="2026-07-07 增量(§6.8–6.10)新增来源"></a>2026-07-07 增量(§6.8–6.10)新增来源</h3><ul><li>OpenWiki(LangChain):<span class="exturl" data-url="aHR0cHM6Ly93d3cubGFuZ2NoYWluLmNvbS9ibG9nL2ludHJvZHVjaW5nLW9wZW53aWtpLWFuLW9wZW4tc291cmNlLWFnZW50LWZvci1yZXBvLWRvY3VtZW50YXRpb24=">https://www.langchain.com/blog/introducing-openwiki-an-open-source-agent-for-repo-documentation<i class="fa fa-external-link-alt"></i></span>、<span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2xhbmdjaGFpbi1haS9vcGVud2lraQ==">https://github.com/langchain-ai/openwiki<i class="fa fa-external-link-alt"></i></span></li><li>OpenKB(VectifyAI):<span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL1ZlY3RpZnlBSS9PcGVuS0I=">https://github.com/VectifyAI/OpenKB<i class="fa fa-external-link-alt"></i></span>、<span class="exturl" data-url="aHR0cHM6Ly9wYWdlaW5kZXguYWkvYmxvZy9pbnRyb2R1Y2luZy1vcGVua2I=">https://pageindex.ai/blog/introducing-openkb<i class="fa fa-external-link-alt"></i></span></li><li>nashsu/llm_wiki:<span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL25hc2hzdS9sbG1fd2lraQ==">https://github.com/nashsu/llm_wiki<i class="fa fa-external-link-alt"></i></span></li><li>AutoSci(PKU DAIR):<span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL3NreWxsd3QvQXV0b1NjaQ==">https://github.com/skyllwt/AutoSci<i class="fa fa-external-link-alt"></i></span>、arXiv 2505.31468:<span class="exturl" data-url="aHR0cHM6Ly9hcnhpdi5vcmcvYWJzLzI1MDUuMzE0Njg=">https://arxiv.org/abs/2505.31468<i class="fa fa-external-link-alt"></i></span></li><li>Karpathy 衍生实现:<span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL0FzdHJvLUhhbi9rYXJwYXRoeS1sbG0td2lraQ==">https://github.com/Astro-Han/karpathy-llm-wiki<i class="fa fa-external-link-alt"></i></span>、<span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL1NhbXVyQUlHUFQvbGxtLXdpa2ktYWdlbnQ=">https://github.com/SamurAIGPT/llm-wiki-agent<i class="fa fa-external-link-alt"></i></span>、<span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL252ay9sbG0td2lraQ==">https://github.com/nvk/llm-wiki<i class="fa fa-external-link-alt"></i></span>、<span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2x1Y2FzYXN0b3JpYW4vbGxtd2lraQ==">https://github.com/lucasastorian/llmwiki<i class="fa fa-external-link-alt"></i></span></li><li>qmd(Tobi Lütke):<span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL3RvYmkvcW1k">https://github.com/tobi/qmd<i class="fa fa-external-link-alt"></i></span></li><li>AGENTS.md:<span class="exturl" data-url="aHR0cHM6Ly9hZ2VudHMubWQv">https://agents.md/<i class="fa fa-external-link-alt"></i></span></li><li>Google Open Knowledge Format:<span class="exturl" data-url="aHR0cHM6Ly9jbG91ZC5nb29nbGUuY29tL2Jsb2cvcHJvZHVjdHMvZGF0YS1hbmFseXRpY3MvaG93LXRoZS1vcGVuLWtub3dsZWRnZS1mb3JtYXQtY2FuLWltcHJvdmUtZGF0YS1zaGFyaW5n">https://cloud.google.com/blog/products/data-analytics/how-the-open-knowledge-format-can-improve-data-sharing<i class="fa fa-external-link-alt"></i></span>、SPEC <span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL0dvb2dsZUNsb3VkUGxhdGZvcm0va25vd2xlZGdlLWNhdGFsb2cvYmxvYi9tYWluL29rZi9TUEVDLm1k">https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md<i class="fa fa-external-link-alt"></i></span></li><li>GitHub 话题:<span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL3RvcGljcy9rYXJwYXRoeS1sbG0td2lraQ==">https://github.com/topics/karpathy-llm-wiki<i class="fa fa-external-link-alt"></i></span>、<span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL3RvcGljcy9sbG0td2lraQ==">https://github.com/topics/llm-wiki<i class="fa fa-external-link-alt"></i></span></li></ul>
2026-05-14 00:00:00
<p>VibeCoding 大半年,最大的感受是:<strong>慢</strong>。一个需求跑大半天,高峰期 API 限速更是雪上加霜。你想走开干点别的,又怕 AI 卡在权限弹窗上等你审批——走也不是,守也不是。</p><p>实践久了之后会发现: VibeCoding 需要的不是持续盯盘,而是一种<strong>间歇性、片段化的持续注意力</strong>。<br>AI 自己跑着就行,你只在关键节点出现——审批权限、纠正方向、拍板决策。<strong>你不是监控器,你是把关人。</strong></p><p><span class="exturl" data-url="aHR0cHM6Ly9oYXBweS5lbmdpbmVlcmluZy8=">Happy Coder<i class="fa fa-external-link-alt"></i></span> 恰好解决了两个问题:</p><ul><li><strong>“守”</strong>——手机随时查看进度、审批、发指令,不用守在电脑前。</li><li><strong>“等”</strong>——通勤路上掏出手机接着推需求,碎片时间变生产力。</li></ul><p>这篇文章分享一下我从零开始用 Happy 的全过程,覆盖日常使用、后台常驻、开机自启、以及自建服务器。</p><span id="more"></span><h2 id="快速上手:五分钟连上手机"><a href="#快速上手:五分钟连上手机" class="headerlink" title="快速上手:五分钟连上手机"></a>快速上手:五分钟连上手机</h2><h3 id="安装-happy-cli"><a href="#安装-happy-cli" class="headerlink" title="安装 happy-cli"></a>安装 <span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL3Nsb3B1cy9oYXBweQ==">happy-cli<i class="fa fa-external-link-alt"></i></span></h3><p>前提是你已经装好了 <span class="exturl" data-url="aHR0cHM6Ly9kb2NzLmFudGhyb3BpYy5jb20vZW4vZG9jcy9jbGF1ZGUtY29kZQ==">Claude Code<i class="fa fa-external-link-alt"></i></span>(<code>claude</code> 命令可用)。然后一行命令搞定:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install -g happy</span><br></pre></td></tr></table></figure><h3 id="下载手机端-APP"><a href="#下载手机端-APP" class="headerlink" title="下载手机端 APP"></a>下载手机端 APP</h3><p>两端的应用名不太一样,直接点链接最省事:iOS 是 <span class="exturl" data-url="aHR0cHM6Ly9hcHBzLmFwcGxlLmNvbS91cy9hcHAvaGFwcHktY2xhdWRlLWNvZGUtY2xpZW50L2lkNjc0ODU3MTUwNQ==">Happy: Claude Code Client<i class="fa fa-external-link-alt"></i></span>,Android 是 <span class="exturl" data-url="aHR0cHM6Ly9wbGF5Lmdvb2dsZS5jb20vc3RvcmUvYXBwcy9kZXRhaWxzP2lkPWNvbS5leDNuZHIuaGFwcHk=">Happy Coder<i class="fa fa-external-link-alt"></i></span>。两端都免费下载,装完即可使用,也提供应用内购买。</p><h3 id="扫码连接"><a href="#扫码连接" class="headerlink" title="扫码连接"></a>扫码连接</h3><p>在电脑端运行:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">happy auth login</span><br></pre></td></tr></table></figure><p>终端里会显示一个二维码。打开手机上的 Happy Coder APP,扫码完成配对。认证信息存储在本地 <code>~/.happy/</code> 目录下,私钥不会离开你的设备。</p><h3 id="启动第一个会话"><a href="#启动第一个会话" class="headerlink" title="启动第一个会话"></a>启动第一个会话</h3><p>直接运行:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">happy</span><br></pre></td></tr></table></figure><p>和直接运行 <code>claude</code> 的区别在于,<code>happy</code> 启动的会话可以被手机端实时看到和控制。你在电脑终端输入的内容会同步显示在手机上,反过来也一样。手机端接管会话后,想切回电脑操作,在终端按任意键就行,<strong>切换是无缝的,会话不会中断</strong>。</p><p>顺便提一句,Happy 不只支持 Claude,还支持 <span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL29wZW5haS9jb2RleA==">Codex<i class="fa fa-external-link-alt"></i></span>、<span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2dvb2dsZS1nZW1pbmkvZ2VtaW5pLWNsaQ==">Gemini<i class="fa fa-external-link-alt"></i></span> 等:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">happy codex # 启动 Codex 会话</span><br><span class="line">happy gemini # 启动 Gemini CLI 会话</span><br></pre></td></tr></table></figure><h2 id="后台常驻:让手机随时发起会话"><a href="#后台常驻:让手机随时发起会话" class="headerlink" title="后台常驻:让手机随时发起会话"></a>后台常驻:让手机随时发起会话</h2><p>上面 <code>happy</code> 命令需要手动启动,关掉终端会话就断了。如果我想随时随地从手机发起会话,电脑上得有个常驻后台的服务。这就是 <strong>daemon(守护进程)</strong> 的作用。</p><p>daemon 在后台持续运行,手机 APP 可以随时通过它创建新的 Claude Code 会话。创建会话时 APP 会让你选择工作目录,Claude 就在那个目录下跑,读取该项目的 <code>CLAUDE.md</code> 和上下文。</p><h3 id="基本操作"><a href="#基本操作" class="headerlink" title="基本操作"></a>基本操作</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">happy daemon start # 启动守护进程</span><br><span class="line">happy daemon stop # 停止守护进程</span><br><span class="line">happy daemon status # 查看运行状态</span><br><span class="line">happy daemon list # 列出活跃会话</span><br><span class="line">happy daemon logs # 查看日志文件路径</span><br></pre></td></tr></table></figure><h2 id="开机自启:Linux-systemd-配置"><a href="#开机自启:Linux-systemd-配置" class="headerlink" title="开机自启:Linux systemd 配置"></a>开机自启:Linux systemd 配置</h2><p>可能会高频使用 happy, 暂时设置了开机自启。<br>因为我的主力机是 Linux 系统,开机自启使用 <span class="exturl" data-url="aHR0cHM6Ly93d3cuZnJlZWRlc2t0b3Aub3JnL3dpa2kvU29mdHdhcmUvc3lzdGVtZC8=">systemd<i class="fa fa-external-link-alt"></i></span> 用户服务来实现。</p><p>创建服务文件 <code>~/.config/systemd/user/happy-daemon.service</code>:</p><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">[Unit]</span></span><br><span class="line"><span class="attr">Description</span>=Happy Coder Daemon</span><br><span class="line"><span class="attr">After</span>=network-<span class="literal">on</span>line.target</span><br><span class="line"><span class="attr">Wants</span>=network-<span class="literal">on</span>line.target</span><br><span class="line"></span><br><span class="line"><span class="section">[Service]</span></span><br><span class="line"><span class="attr">Type</span>=simple</span><br><span class="line"><span class="attr">ExecStart</span>=/path/to/happy daemon start-sync</span><br><span class="line"><span class="attr">WorkingDirectory</span>=/your/workspace</span><br><span class="line"><span class="attr">Restart</span>=always</span><br><span class="line"><span class="attr">RestartSec</span>=<span class="number">10</span></span><br><span class="line"><span class="attr">Environment</span>=PATH=/home/xxx/.local/bin:/usr/local/bin:/usr/bin:/bin</span><br><span class="line"><span class="attr">Environment</span>=HOME=/home/xxx</span><br><span class="line"></span><br><span class="line"><span class="section">[Install]</span></span><br><span class="line"><span class="attr">WantedBy</span>=default.target</span><br></pre></td></tr></table></figure><p>这里面有几个<strong>关键细节</strong>,逐一说清楚。</p><h3 id="start-sync-而不是-start"><a href="#start-sync-而不是-start" class="headerlink" title="start-sync 而不是 start"></a><code>start-sync</code> 而不是 <code>start</code></h3><p><code>happy daemon start</code> 会 spawn 一个子进程然后父进程退出,systemd 检测到主进程退出就认为服务结束了。而 <code>start-sync</code> 是前台阻塞模式,systemd 可以正确跟踪进程状态。用错了的话,daemon 会不断被 systemd 重启又退出,陷入死循环。</p><h3 id="Restart-always"><a href="#Restart-always" class="headerlink" title="Restart=always"></a><code>Restart=always</code></h3><p>不要用 <code>Restart=on-failure</code>。daemon 收到正常关机信号时退出码是 0,<code>on-failure</code> 不会重启正常退出的进程。我们需要的是无论什么原因退出都自动重启。</p><h3 id="Environment-不要包含-CLAUDECODE-变量"><a href="#Environment-不要包含-CLAUDECODE-变量" class="headerlink" title="Environment 不要包含 CLAUDECODE 变量"></a>Environment 不要包含 <code>CLAUDECODE</code> 变量</h3><p>如果 daemon 的环境里有 <code>CLAUDECODE</code> 或 <code>CLAUDE_CODE_ENTRYPOINT</code> 这类变量,从手机发起的会话会<strong>直接失败</strong>。症状是:手机上能看到会话创建成功,但一发消息就挂。</p><p>这条是我自己踩坑排查出来的,官方文档没写,但原理上说得通:daemon 派生会话时会透传完整的 <code>process.env</code>,而这两个变量正是 Claude Code 用来标记”我在自己派生的子进程里”的,被继承进去就会干扰它的判断。排查这类问题,这里是第一个要检查的。</p><h3 id="loginctl-enable-linger"><a href="#loginctl-enable-linger" class="headerlink" title="loginctl enable-linger"></a><code>loginctl enable-linger</code></h3><p>systemd 用户服务默认只在用户登录时运行。执行 <code>loginctl enable-linger</code> 后,即使没有登录,用户服务也能启动。</p><h3 id="启用服务"><a href="#启用服务" class="headerlink" title="启用服务"></a>启用服务</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">loginctl enable-linger $(whoami)</span><br><span class="line">systemctl --user daemon-reload</span><br><span class="line">systemctl --user enable --now happy-daemon.service</span><br></pre></td></tr></table></figure><p>验证:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl --user status happy-daemon.service</span><br></pre></td></tr></table></figure><p>看到 <code>active (running)</code> 就对了。可以故意杀掉进程测试自动恢复:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">kill $(pgrep -f "happy daemon start-sync")</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">等约 10 秒</span></span><br><span class="line">systemctl --user status happy-daemon.service</span><br></pre></td></tr></table></figure><p>应该看到它又自动重启了。</p><h2 id="自建-Happy-Server"><a href="#自建-Happy-Server" class="headerlink" title="自建 Happy Server"></a>自建 Happy Server</h2><p>Happy 默认使用官方中继服务器。所有通信端到端加密,服务器只能看到加密后的数据块,无法读取代码内容。用官方服务器在安全性上没问题。<br>但如果有数据合规要求、想在内网部署、或者纯粹想自己掌控基础设施,自建也很简单。</p><p><em>主要是官网真的太太太太太太太太太太太太太太太太太太太太太太太太太太太太太太太太慢了……………….</em></p><h3 id="Docker-部署(推荐)"><a href="#Docker-部署(推荐)" class="headerlink" title="Docker 部署(推荐)"></a>Docker 部署(推荐)</h3><blockquote><p>注意:下文中的 happy.example.com 仅为示例占位域名,部署时请全部替换为你自己的实际 HTTPS 域名。</p></blockquote><p>Happy Server 独立模式内置了 <span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2VsZWN0cmljLXNxbC9wZ2xpdGU=">PGlite<i class="fa fa-external-link-alt"></i></span>(嵌入式 <span class="exturl" data-url="aHR0cHM6Ly93d3cucG9zdGdyZXNxbC5vcmcv">PostgreSQL<i class="fa fa-external-link-alt"></i></span>),<strong>不需要额外安装 Postgres、Redis 或 S3</strong>,一个容器搞定:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">构建镜像(在仓库根目录执行)</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">根目录的 Dockerfile 就是独立模式镜像</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">另有 Dockerfile.server(需外部 PG/Redis/S3)和 Dockerfile.webapp,别选错</span></span><br><span class="line">docker build -t happy-server -f Dockerfile .</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">运行</span></span><br><span class="line">docker run -d \</span><br><span class="line"> --name happy-server \</span><br><span class="line"> -p 3005:3005 \</span><br><span class="line"> -e HANDY_MASTER_SECRET=your-secret-here \</span><br><span class="line"> -e PUBLIC_URL=https://happy.example.com \</span><br><span class="line"> -e METRICS_ENABLED=false \</span><br><span class="line"> -v happy-data:/data \</span><br><span class="line"> --restart unless-stopped \</span><br><span class="line"> happy-server</span><br></pre></td></tr></table></figure><p>几个关键说明:</p><ul><li><strong><code>HANDY_MASTER_SECRET</code> 是必须设置的</strong>,用于认证和加密。务必生成一个足够长的随机字符串</li><li><code>PUBLIC_URL</code> 设为你的公网可访问的 HTTPS 地址,影响文件链接的生成</li><li>数据持久化在 Docker volume <code>happy-data</code> 中,容器重启不丢数据</li><li><strong>Prometheus 指标默认是开着的</strong>,会在 9090 端口另起一个服务。个人用不上,上面显式关掉了;想用就去掉那行并加上 <code>-p 9090:9090</code></li><li><strong>服务器本身不处理 TLS</strong>,需要配合反向代理</li></ul><p>健康检查:访问 <code>GET /health</code>,返回 <code>{"status":"ok","timestamp":"..."}</code> 说明服务正常。</p><h3 id="环境变量一览"><a href="#环境变量一览" class="headerlink" title="环境变量一览"></a>环境变量一览</h3><p><strong>必须设置:</strong></p><table><thead><tr><th>变量</th><th>说明</th></tr></thead><tbody><tr><td><code>HANDY_MASTER_SECRET</code></td><td>认证和加密的主密钥,必须设置</td></tr></tbody></table><p><strong>可选(独立部署):</strong></p><table><thead><tr><th>变量</th><th>默认值</th><th>说明</th></tr></thead><tbody><tr><td><code>PORT</code></td><td><code>3005</code></td><td>服务监听端口</td></tr><tr><td><code>PUBLIC_URL</code></td><td><code>http://localhost:3005</code></td><td>公网访问 URL</td></tr><tr><td><code>DATA_DIR</code></td><td><code>/data</code></td><td>数据存储目录</td></tr><tr><td><code>PGLITE_DIR</code></td><td><code>/data/pglite</code></td><td>PGlite 数据库目录</td></tr><tr><td><code>METRICS_ENABLED</code></td><td><code>true</code></td><td>Prometheus 指标,设 <code>false</code> 关闭</td></tr><tr><td><code>METRICS_PORT</code></td><td><code>9090</code></td><td>指标服务端口</td></tr></tbody></table><p><strong>可选(扩展部署):</strong></p><table><thead><tr><th>变量</th><th>说明</th></tr></thead><tbody><tr><td><code>DATABASE_URL</code></td><td>外部 PostgreSQL 连接地址(替代 PGlite)</td></tr><tr><td><code>REDIS_URL</code></td><td>Redis 地址(仅多副本部署需要)</td></tr><tr><td><code>S3_HOST</code> 等</td><td>S3/MinIO 对象存储(替代本地文件存储)</td></tr></tbody></table><p>个人使用的话,设一个 <code>HANDY_MASTER_SECRET</code> 就够了。</p><h3 id="TLS-配置"><a href="#TLS-配置" class="headerlink" title="TLS 配置"></a>TLS 配置</h3><p>生产环境用 HTTPS,最省事的方式是用 <span class="exturl" data-url="aHR0cHM6Ly9jYWRkeXNlcnZlci5jb20v">Caddy<i class="fa fa-external-link-alt"></i></span> 做反向代理,它会<strong>自动申请和续期 <span class="exturl" data-url="aHR0cHM6Ly9sZXRzZW5jcnlwdC5vcmcv">Let’s Encrypt<i class="fa fa-external-link-alt"></i></span> 证书</strong>:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">happy.example.com {</span><br><span class="line"> reverse_proxy localhost:3005</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>两行配置,Caddy 帮你搞定证书。用 Nginx 的话需要自己配 certbot,稍微麻烦一点。</p><h2 id="CLI-指向自建服务器"><a href="#CLI-指向自建服务器" class="headerlink" title="CLI 指向自建服务器"></a>CLI 指向自建服务器</h2><p>自建服务器部署好之后,通过 <code>HAPPY_SERVER_URL</code> 环境变量让 happy-cli 连接你的服务器:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">export HAPPY_SERVER_URL=https://happy.example.com</span><br><span class="line">happy</span><br></pre></td></tr></table></figure><p>或者写到 shell 配置文件里一劳永逸。加到 <code>~/.zshrc</code> 或 <code>~/.bashrc</code>:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">export HAPPY_SERVER_URL=https://happy.example.com</span><br></pre></td></tr></table></figure><p>如果前面用 systemd 管理 daemon,别忘了在 service 文件的 <code>Environment</code> 里也加上:</p><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">Environment</span>=HAPPY_SERVER_URL=https://happy.example.com</span><br></pre></td></tr></table></figure><p>改完之后 <code>systemctl --user restart happy-daemon.service</code> 让配置生效。</p><h2 id="APP-指向自建服务器"><a href="#APP-指向自建服务器" class="headerlink" title="APP 指向自建服务器"></a>APP 指向自建服务器</h2><p>Happy APP 内置了服务器配置页面,切换很方便:</p><ol><li>打开 APP,进入<strong>设置</strong></li><li>找到 <strong>Relay Server URL</strong>(中继服务器地址)</li><li>输入自建服务器地址,比如 <code>https://happy.example.com</code></li><li>APP 会自动验证:访问这个 URL,检查是否返回 “Welcome to Happy Server!”</li><li>验证通过后保存,之后所有连接走你的自建服务器</li><li>想切回官方服务器?同一个页面重置即可</li></ol><p>切换过程不需要重新登录。</p><hr><p>Happy Coder 解决的问题很小也很具体:让你不用坐在电脑前也能用 Claude Code。但就是这个便利,改变了我跟 Claude 协作的方式。通勤路上想到什么,掏出手机就能接着聊;周末出门在外,Claude 在家里的机器上跑着任务,手机上随时查看进度。</p><p>开源、免费、端到端加密,自托管完全可选。如果你也在用 Claude Code,不妨试试。</p><h2 id="参考文献"><a href="#参考文献" class="headerlink" title="参考文献"></a>参考文献</h2><ul><li><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL3Nsb3B1cy9oYXBweQ==">slopus/happy - GitHub<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9oYXBweS5lbmdpbmVlcmluZy9kb2NzL2ZhcS8=">Happy Engineering - Documentation<i class="fa fa-external-link-alt"></i></span></li><li><span class="exturl" data-url="aHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vbGlhbWRhcm1vZHkvNGFiYTA4M2MyNmNjYjFiM2IwZjEwNjhlYzE4NWVmNjY=">How to build a 24/7 personal AI agent with Claude Code - Liam Darmody<i class="fa fa-external-link-alt"></i></span></li></ul>
2026-01-21 00:00:00
<h3 id="资源"><a href="#资源" class="headerlink" title="资源"></a>资源</h3><ul><li><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2FudGhyb3BpY3Mvc2tpbGxz">Anthropic 官方 Skills 示例<i class="fa fa-external-link-alt"></i></span> Skills 示例代码仓库, 可以学习创建自己的 Skills 武器库。</li></ul><h3 id="实践"><a href="#实践" class="headerlink" title="实践"></a>实践</h3><ul><li>逐渐深入使用 ClaudeCode,开始接触 Skills,Hooks,Permissions,好工具的设计真是巧妙,流程简约且高度可定制。</li><li>尝试用 ClaudeCode + Github SpecKit,想从零到一写一个翻译工具。效果层面目前还不好说,核心翻译能力还没写。时间层面,提效感觉不明显,specify,clarify,plan,task,analyze,implement 一套流程下来,一个小需求得花费大半天。</li><li>Anthropic 发布了 code-simplifier 工具,<strong>代码优化效果极好</strong>,可以在不改变业务逻辑的前提下优化代码,感觉可以集成到 CICD 帮忙做代码 review 了。</li><li>ClaudeCode 的潜力真是无穷无尽,写确定性的代码效果很好(写整个项目经验不足还不好评价)。帮我把日报汇总成年终总结,几乎一个字都不用改。后面准备尝试用 NotionMCP 帮我做开源服务指南自动化发布的最后一公里,感觉能行。</li><li>01/16 卸载了抖音,头脑清净了许多。卸载抖音的当天上午,上班路上写完了两周的周报草稿。</li><li><span class="exturl" data-url="aHR0cHM6Ly93d3cuYmlnbW9kZWwuY24vZ2xtLWNvZGluZz9pYz1ST0VFQUFXTFhP">GLM Coding Plan<i class="fa fa-external-link-alt"></i></span> 5h 实践窗口居然有 2亿 token, 根本用不完。用 nginx 反代给同事接入,反馈也不错。</li></ul><h3 id="妙想"><a href="#妙想" class="headerlink" title="妙想"></a>妙想</h3><ul><li>我之前的笔记 + 知识库是用 markdown 格式 + VSCode 编辑器 + Git 版本控制 + Github 同步来实现的,后面找机会让 ClaudeCode 把我历史知识库整理发部成公共知识库,好东西就是要分享出去。</li><li>计划了 100 年的周复盘一直没有启动,想试一下让 ClaudeCode 学习我历史博客的写作风格,然后帮我写周复盘。</li></ul>
2026-01-20 00:00:00
<ul><li>购买了 <span class="exturl" data-url="aHR0cHM6Ly93d3cuYmlnbW9kZWwuY24vZ2xtLWNvZGluZz9pYz1ST0VFQUFXTFhP">GLM Coding Plan<i class="fa fa-external-link-alt"></i></span>,可以随意玩 ClaudeCode 了。虽然模型智能不如国外,好在量大管饱,入门 ClaudeCode 是不错的。</li><li>新买的丐版 MacMini 内存和硬盘都不多,ClaudeCode 开发过程中会用到一些开发环境(Go 语言, Podman, PostGreSQL),不想浪费 MacMini 的空间。索性就把之前淘汰下来的 Manjaro Linux 24h 开机,当作服务器用。<strong>Tmux 会话保持 + ClaudeCode 终端沟通 + VSCode 远程开发</strong>,整个流程非常顺滑。</li><li>有一个叫 <span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL3Nsb3B1cy9oYXBweQ==">happy<i class="fa fa-external-link-alt"></i></span> 的工具,可以让你远程控制 ClaudeCode 工作,感兴趣的话可以试一下。</li><li>测试了几个 AI 编程工具(GeminiCLI,GithubCopilot),最终还是觉得 ClaudeCode 更好用。其实真没必要折腾各种免费或者白嫖的工具,<strong>免费的往往也是最贵的,时间、精力、机会这些方面的成本不是金钱能够衡量的</strong>。</li><li>之前帮同事写过一个号码认证自动拨测脚本,这次又有需求,借助 AI 编程工具把脚本升级到了 GUI。纯 VibeCoding,调测时间远大于开发时间,且 AI 经常会在实现一个新需求的时候搞出来一个旧功能的 bug。后面可能会多尝试一下 <span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2NvZGVydmlzb3IvbGVhbi1zcGVj">LeanSpec<i class="fa fa-external-link-alt"></i></span> 或者 <span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2dpdGh1Yi9zcGVjLWtpdA==">SpecKit<i class="fa fa-external-link-alt"></i></span> 这样的 SDD 框架。</li></ul>