<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"><channel><title>est の 输入 输出和出入</title><link>https://blog.est.im/</link><description>This blog is rated 🔞, viewer discretion is advised</description><lastBuildDate>Sun, 16 Aug 2026 14:06:00 +0800</lastBuildDate><item><title>git fetch 实现断点续传</title><link>https://blog.est.im/2026/stdout-33</link><description>&lt;p&gt;&lt;code&gt;git fetch origin main --depth=1&lt;/code&gt; 一次只下一个 pack，包含所有缺失对象，国内这网络你懂的，断开就废了，然后从头下载，往往又出事；&lt;/p&gt;
&lt;p&gt;老外不懂国内网络条件这么艰苦，只能自己让AI改造。结果：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/est/snippets/tree/master/git-fr"&gt;https://github.com/est/snippets/tree/master/git-fr&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;步骤：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;git fetch --filter=blob:none --depth=1&lt;/code&gt; —— 只拉 commit+tree，这个速度很快，只有KB级别的传输&lt;/li&gt;
&lt;li&gt;用 &lt;code&gt;rev-list --objects --missing=print&lt;/code&gt; 算缺失集合，500 个 blob 一批回填&lt;/li&gt;
&lt;li&gt;每轮重算缺失、只补缺的。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;踩过的坑&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;git fetch origin &amp;lt;blobsha&amp;gt;&lt;/code&gt; 每次都会打印 &lt;code&gt;fatal: bad object &amp;lt;sha&amp;gt;&lt;/code&gt; + &lt;code&gt;error: ... did not send all necessary objects&lt;/code&gt;，但事后检查对象blob却真的下载了。后来发现因为&lt;code&gt;cat-file&lt;/code&gt; 会拉数据,&lt;code&gt;rev-list --missing=print&lt;/code&gt; 不会。&lt;/li&gt;
&lt;li&gt;普通 &lt;code&gt;git fetch origin &amp;lt;sha&amp;gt;&lt;/code&gt; 拿到的 pack 是薄包(thin pack)——服务器按客户端声明做 delta 压缩。如果本地声明的是 &lt;code&gt;refs/remotes/origin/main&lt;/code&gt;(一个 commit),服务器据此假定我们拥有整棵树的全部 blob所以就啥都不给&lt;/li&gt;
&lt;li&gt;git 原生 lazy fetch ，用 &lt;code&gt;GIT_TRACE=1 git cat-file blob &amp;lt;missing&amp;gt;&lt;/code&gt; 抓到了 git 自己 lazy fetch 时实际执行的命令:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;git -c fetch.negotiationAlgorithm=noop fetch origin --no-tags \
  --no-write-fetch-head --recurse-submodules=no --filter=blob:none --stdin
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;关键:&lt;br /&gt;
- &lt;strong&gt;&lt;code&gt;fetch.negotiationAlgorithm=noop&lt;/code&gt;&lt;/strong&gt; —— 不发 haves,服务器没法薄包化,只能发完整对象;&lt;br /&gt;
- &lt;strong&gt;&lt;code&gt;--filter=blob:none&lt;/code&gt;&lt;/strong&gt; —— 显式声明的 want 会绕过过滤器直接发送(partial clone 语义);&lt;br /&gt;
- &lt;strong&gt;&lt;code&gt;--stdin&lt;/code&gt;&lt;/strong&gt; —— want 列表从 stdin 读,天然支持批量。&lt;/p&gt;
&lt;p&gt;还有很多放到 &lt;a href="https://lab.est.im/git-fr/"&gt;README.md&lt;/a&gt; 里了&lt;/p&gt;
&lt;p&gt;安装&lt;/p&gt;
&lt;p&gt;把 &lt;code&gt;fr.sh&lt;/code&gt; 放到 PATH(如 &lt;code&gt;~/.local/bin/git-fr&lt;/code&gt;)，即可 &lt;code&gt;git fr&lt;/code&gt; 使用。&lt;/p&gt;
&lt;p&gt;或 &lt;code&gt;git config --global alias.fr '!&amp;lt;绝对路径&amp;gt;/fr.sh'&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;感觉，现在搞这些东西似乎意义不大了？反正大家都是让AI自己临时写一个脚本。。。🤣&lt;/p&gt;
&lt;p&gt;有空让AI写个支持多线程并发 fetch 的。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">est</dc:creator><pubDate>Sun, 16 Aug 2026 14:06:00 +0800</pubDate><guid isPermaLink="false">tag:None,2026-08-16:/2026/stdout-33</guid><category>stdout</category></item><item><title>继续搓英汉双解词典v3</title><link>https://blog.est.im/2026/stdout-32</link><description>&lt;p&gt;去年&lt;a href="https://blog.est.im/2025/stdout-12"&gt;搓了个词典&lt;/a&gt;，本来懒得动了，但是看到opencode订阅还没用完，deepseek那么便宜，想着不用白不用，找了个最浪费token的方式，让AI再写一部词典&lt;/p&gt;
&lt;p&gt;当年的AI我记得还是 gemini-2，其实很多东西不成熟。我也对AI脾气没摸准，很自然的就：“请输出 JSON”。今年学聪明了，直接上YAML。AI高呼你这想法真离经叛道但又极度合理。&lt;/p&gt;
&lt;p&gt;甚至，block scalar（&lt;code&gt;|&lt;/code&gt;）支持多行文本，不转义！&lt;/p&gt;
&lt;p&gt;一个小技巧是，尽量避免嵌套的，什么 map套entries，每个 entry 再挂一个 senses 列表、每个 sense 再挂一个 examples 列表，别玩这一套。直接拍扁，层级尽可能少，整个 schema 里不允许出现一个方括号！&lt;/p&gt;
&lt;p&gt;AI帮我写了个 validator，调教这一块还得是AI卷AI。不对劲的就返回错误让AI二次输出。但是基本都是1-pass通过。之前JSON翻车太多了。&lt;/p&gt;
&lt;p&gt;跑了一圈还发现，短码对模型不友好。词性枚举最初写成 n/v/adj/adv，模型就开始输出 v.、V、vb、verb，改成全称 noun/verb/adjective 。我觉得这个跟 LLM 预训练 token 的分布高度相关，不要以为「缩写」对人和机器更友好！LLM是反过来的。&lt;/p&gt;
&lt;p&gt;10年前第一版想的是薅Google Dictionary羊毛，去年第二版静态站中毒，想弄json，后来发现不对。20k的词汇量，对应20k个零碎小文件不可控。&lt;/p&gt;
&lt;p&gt;这次第三版，回到传统RDBMS。一开始想一张 FTS5 全文索引表，让用户能模糊搜索、子串匹配，甚至搜中文释义——感觉这才配得上"AI 词典"的科技感。&lt;/p&gt;
&lt;p&gt;然后又想了下，问了自己一个本该一开始就问的问题：用户到底是怎么用词典的？&lt;/p&gt;
&lt;p&gt;输入一个完整的词，得到词条。前缀联想 输入 "run" 提示 "running" 用一句 &lt;code&gt;LIKE 'run%'&lt;/code&gt; 就够了，一共三张表&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;words&lt;/code&gt;：词头&lt;/li&gt;
&lt;li&gt;&lt;code&gt;senses&lt;/code&gt;：义项&lt;/li&gt;
&lt;li&gt;&lt;code&gt;surfaces&lt;/code&gt;：一切能解析到这个词的可供检索字符串：原形、变形、同义词、反义词、搭配&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一个激进的决定，&lt;code&gt;words&lt;/code&gt; 这个表甚至不保存词汇的归一化原始形式！直接作为 lemma 放到 surfaces 表里！&lt;/p&gt;
&lt;p&gt;接下来，让AI写了个「递归」采集器，很简单，随便想几个单词，prompt就是让AI做词典；然后词典里的解释、例句再分词，再翻译。直到所有翻译和解释能自我包含，这样自动生成一部完整的词典。&lt;/p&gt;
&lt;p&gt;让AI搓 BFS，起初几万词汇很舒服，很快发现，漂移进生僻词陷阱了：water 的释义带出了 odorless、colorless、tasteless，这些是英语词没错，所以又让AI给每个词标上分级，A1 A2 B1 B2 C1 C2 按顺序遍历。但我脑子抽了，没想到，这词在生成YAML之前，不知道自己的等级，AI提醒我，假设子词继承父词级别——够用就行。&lt;/p&gt;
&lt;p&gt;后来想了下，反正AI闲着也是闲着，于是下载了一个权威 CEFR 词表，17 万词&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/Maximax67/Words-CEFR-Dataset/"&gt;https://github.com/Maximax67/Words-CEFR-Dataset/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这个词表的 level 是浮点，1.0=A1 … 6.0=C2，1.5 是 A1/A2 边界，天然可以先处理常用词后采集偏科的&lt;/p&gt;
&lt;p&gt;甚至还提供了真实词频，the 出现了 928 亿次，还有 lemma 链接：ran→run、went→go、children→child，甚至还可以求出 clothes 没有链接，所以它是真词头。&lt;/p&gt;
&lt;p&gt;跑起来之后，词典开始自己生长，敲入 &lt;code&gt;caffeinate&lt;/code&gt; 睡了一觉。第二天起来一看，额度才用了  10% 不到。。Deepseek太耐烧了&lt;/p&gt;
&lt;p&gt;顺便发现opencode关只在流式模式下返回内容，非流式直接返回空 body。挺浪费的说实话。&lt;/p&gt;
&lt;p&gt;整理发现这个 CEFR 也tmd掺水，AI看了下挺多 复数、连字符、西语、意大利语词汇混进去，后来干脆一刀切100w以上词频才纳入采集&lt;/p&gt;
&lt;p&gt;哎，还得二次清洗&lt;/p&gt;
&lt;p&gt;后续会把这个词典做出 on-demand 的：用户查一个词，命中缓存直接返回；没命中，当场调一次 AI 生成、校验、入库&lt;/p&gt;
&lt;p&gt;最后，地址依然是：&lt;a href="https://def.est.im/"&gt;https://def.est.im/&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;清洗的时候AI又说怎么这么多 人名 地名 乐队名，噪音可以跳过。&lt;/p&gt;
&lt;p&gt;我想了下，其实对 language learner 还挺有用的。你输入一个名字，其实想知道这个名字的内涵，来源，是否得体，有坑的。&lt;/p&gt;
&lt;p&gt;传统词典那些老学究那有时间给你折腾这那的。&lt;/p&gt;
&lt;p&gt;一个地名儿，既然你查了，肯定是从某个书 杂志 地图册 上碰到的，你是冲着大新闻、 奇闻逸事 来的。传统词典只告诉这是某国某地，有啥用？&lt;/p&gt;
&lt;p&gt;其次AI又挑三拣四，说这西语词汇，扔了吧。老美现在西语人口那么多，流行文化我感觉都半边天了，用户查词汇碰到的概率很高。&lt;/p&gt;
&lt;p&gt;过去纸质时代，让双语高手静下来编一部这样的词典，不容易&lt;/p&gt;
&lt;p&gt;但是AI时代，有机会了。&lt;/p&gt;
&lt;p&gt;我想就从这样的第一性原理，做一个完全服务语言学习者，感兴趣的词典。&lt;/p&gt;
&lt;p&gt;不过 tokens 已经耗尽了，下次再说。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">est</dc:creator><pubDate>Sat, 08 Aug 2026 09:53:00 +0800</pubDate><guid isPermaLink="false">tag:None,2026-08-08:/2026/stdout-32</guid><category>stdout</category></item><item><title>邮箱生态调研2026</title><link>https://blog.est.im/2026/stdout-31</link><description>&lt;p&gt;起初一个很简单的想法，把一个app/服务的私人数据，集中存数据库麻烦，不想维护担责，干脆放用户自己邮箱里，所谓"BYOS（自带存储）"。反正协议 SMTP/POP3/IMAP 很方便，然后调查了下很快发现，时代变了。&lt;/p&gt;
&lt;p&gt;本来寄希望IMAP 这个协议，感觉能缝成一个读写API，&lt;/p&gt;
&lt;p&gt;-&lt;code&gt;APPEND&lt;/code&gt; 写（一封邮件 = 一个对象），&lt;code&gt;FETCH&lt;/code&gt; 读，&lt;code&gt;STORE&lt;/code&gt; 改 flag，&lt;code&gt;COPY/MOVE&lt;/code&gt; 移动&lt;br /&gt;
- "目录 + KV"模型，flag（&lt;code&gt;\Seen&lt;/code&gt;、&lt;code&gt;\Flagged&lt;/code&gt; 等）即元数据位&lt;br /&gt;
- &lt;code&gt;SEARCH&lt;/code&gt;查询 主题、日期、自定义 header等&lt;br /&gt;
- 增量同步： &lt;code&gt;UID&lt;/code&gt; + &lt;code&gt;UIDVALIDITY&lt;/code&gt;，&lt;code&gt;IDLE&lt;/code&gt; 可做准实时推送（仅单文件夹）&lt;/p&gt;
&lt;p&gt;其实古董的 GMailFS / GMail Drive 之类把 Gmail 当虚拟磁盘的开源项目很多，各类 邮件备份 工具、笔记类应用的同步，都走过这条路&lt;/p&gt;
&lt;p&gt;以前输入帐号密码这种简单方式，早被废了；甚至专用密码、动态密码都下掉了。主流邮箱（Gmail/Outlook/Yahoo）已全面转向 OAuth 2.0，就是它协议上是要走一个握手然后验证token的流程，用户门槛太高了。&lt;/p&gt;
&lt;p&gt;让AI跑了一圈发现：&lt;/p&gt;
&lt;h3&gt;邮箱供应商对比：&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;供应商&lt;/th&gt;
&lt;th&gt;开发者接入方式&lt;/th&gt;
&lt;th&gt;开发者审核门槛&lt;/th&gt;
&lt;th&gt;用户授权操作&lt;/th&gt;
&lt;th&gt;用户麻烦程度&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Gmail&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;OAuth 2.0（SASL XOAUTH2），scope &lt;code&gt;https://mail.google.com/&lt;/code&gt;，需建 GCP 项目&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;最重&lt;/strong&gt;：restricted scope，正式对外必须过 OAuth 验证 + 安全评估，&lt;strong&gt;每年复审&lt;/strong&gt;；未过审只能 ≤100 测试用户或内部使用&lt;/td&gt;
&lt;td&gt;跳转 Google 授权页点同意（OAuth）；或开 2FA 后生成 16 位应用专用密码粘贴&lt;/td&gt;
&lt;td&gt;低（OAuth）~ 中（app password）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Outlook.com&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;OAuth 2.0（SASL XOAUTH2），scope &lt;code&gt;https://outlook.office.com/IMAP.AccessAsUser.All&lt;/code&gt;，需注册 Microsoft Entra 应用&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;中等&lt;/strong&gt;：Entra 注册免费即时；无强制审核；Publisher verification（去掉"未验证应用"警示）可选，需 EV 证书约 $100/年&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;必须先到网页设置手动打开 IMAP（默认关）&lt;/strong&gt;；之后走 OAuth 自动授权，或应用密码&lt;/td&gt;
&lt;td&gt;中（多一步开 IMAP）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Yahoo&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;OAuth 2.0（SASL OAUTHBEARER），需在 YDN 注册应用；或应用密码&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;低&lt;/strong&gt;：无 Google 式受限 scope 审核&lt;/td&gt;
&lt;td&gt;OAuth 授权页；或设置里生成应用密码&lt;/td&gt;
&lt;td&gt;低（OAuth）~ 中（app password）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;iCloud&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;官方支持三方应用 OAuth 授权，或应用专用密码&lt;/td&gt;
&lt;td&gt;低-中&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;必须开 2FA&lt;/strong&gt;，到 account.apple.com 生成应用专用密码（每应用一个，上限 25 个）&lt;/td&gt;
&lt;td&gt;中&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;QQ 邮箱&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;无 OAuth，只有"授权码"&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;无&lt;/strong&gt;（无审核无文档）&lt;/td&gt;
&lt;td&gt;设置 → 账户 → 开启 IMAP/SMTP → &lt;strong&gt;短信验证&lt;/strong&gt; → 生成 16 位授权码 → 粘贴进 App&lt;/td&gt;
&lt;td&gt;中（2~3 分钟）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;163 / 126&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;同上（客户端授权密码）&lt;/td&gt;
&lt;td&gt;无&lt;/td&gt;
&lt;td&gt;同上&lt;/td&gt;
&lt;td&gt;中（2~3 分钟）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;硬限制&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;供应商&lt;/th&gt;
&lt;th&gt;IMAP 服务器&lt;/th&gt;
&lt;th&gt;容量&lt;/th&gt;
&lt;th&gt;单封大小&lt;/th&gt;
&lt;th&gt;连接/会话限制&lt;/th&gt;
&lt;th&gt;明文密码状态&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Gmail&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;imap.gmail.com:993&lt;/td&gt;
&lt;td&gt;15GB（与 Drive/相册共享）&lt;/td&gt;
&lt;td&gt;25MB&lt;/td&gt;
&lt;td&gt;15 并发连接；会话约 24h&lt;/td&gt;
&lt;td&gt;已废除，需 OAuth 或 app password&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Outlook.com&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;outlook.office365.com:993&lt;/td&gt;
&lt;td&gt;15GB&lt;/td&gt;
&lt;td&gt;约 35MB 量级&lt;/td&gt;
&lt;td&gt;多客户端并发触发风控&lt;/td&gt;
&lt;td&gt;已废除（2022-10 起强制 Modern Auth）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Yahoo&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;imap.mail.yahoo.com:993&lt;/td&gt;
&lt;td&gt;1TB&lt;/td&gt;
&lt;td&gt;25MB 附件&lt;/td&gt;
&lt;td&gt;无公开数字&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2024-05-15 起停用明文密码&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;iCloud&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;imap.mail.me.com:993&lt;/td&gt;
&lt;td&gt;免费 5GB&lt;/td&gt;
&lt;td&gt;约 20MB 量级&lt;/td&gt;
&lt;td&gt;无公开数字&lt;/td&gt;
&lt;td&gt;需应用专用密码&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;QQ 邮箱&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;imap.qq.com:993&lt;/td&gt;
&lt;td&gt;约 16GB 级&lt;/td&gt;
&lt;td&gt;普通附件约 50MB，大文件走中转站（有时效）&lt;/td&gt;
&lt;td&gt;无公开文档，风控靠账号安全策略&lt;/td&gt;
&lt;td&gt;无 OAuth，仅授权码&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;163 / 126&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;imap.163.com:993&lt;/td&gt;
&lt;td&gt;免费容量较大（自动扩容）&lt;/td&gt;
&lt;td&gt;普通附件约 50MB，大文件走"超大附件"（有时效）&lt;/td&gt;
&lt;td&gt;无公开文档&lt;/td&gt;
&lt;td&gt;无 OAuth，仅授权码&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ 以上数字除标注官方来源者外均为常用量级，上线前需逐家实测；QQ/163 无官方公开 API/协议文档，以实操惯例为准。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;操作路径&lt;/h3&gt;
&lt;h4&gt;路径 A：OAuth 授权&lt;/h4&gt;
&lt;p&gt;Gmail / Outlook / Yahoo&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户操作：简单。点"继续用 Google/微软登录" → 同意 → 跳回，约 30 秒，体验最好，还能随时撤销。&lt;/li&gt;
&lt;li&gt;开发者代价：Google 的 restricted scope 审核是真实的时间黑洞——提交安全评估、回答数据使用问卷、&lt;strong&gt;每年复审&lt;/strong&gt;；没下来之前 App 无法对真实用户上线（只能测试名单）。微软无强制审核、Yahoo 无审核，相对顺。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;路径 B：应用专用密码 / 授权码&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;用户要依次完成：开 2FA（Google/Apple 强制）→ 进设置页 → 生成 16 位码 → 回 App 粘贴。&lt;strong&gt;平均 5~15 分钟&lt;/strong&gt;，而且这是客服工单的主要来源：没开 2FA、改了主密码（所有应用密码自动吊销）、粘贴带空格、公司/学校账号禁开……&lt;/li&gt;
&lt;li&gt;Google 官方明说 app password "not recommended and unnecessary"，方向是逼大家走 OAuth。&lt;strong&gt;把产品押在 app password 上是逆政策而动&lt;/strong&gt;，微软/Yahoo 已先后封死明文密码，这条路只会越来越窄。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;结论：&lt;/h3&gt;
&lt;p&gt;算了。不要折腾。&lt;/p&gt;
&lt;h3&gt;附：参考来源&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Gmail 应用专用密码与 2FA 要求：&lt;a href="https://support.google.com/mail/answer/185833"&gt;https://support.google.com/mail/answer/185833&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Gmail 附件 25MB 限制：&lt;a href="https://support.google.com/mail/answer/6584"&gt;https://support.google.com/mail/answer/6584&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Gmail IMAP 会话 / 连接限制、IMAP 常开（2025-01 起）：&lt;a href="https://support.google.com/mail/answer/7126229"&gt;https://support.google.com/mail/answer/7126229&lt;/a&gt; &lt;a href="https://developers.google.com/gmail/"&gt;https://developers.google.com/gmail/&lt;/a&gt;imap/imap-smtp&lt;/li&gt;
&lt;li&gt;Google OAuth 验证与受限 scope 年度复审：&lt;a href="https://support.google.com/cloud/answer/9110914"&gt;https://support.google.com/cloud/answer/9110914&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Outlook.com 设置页（IMAP 默认关闭、强制 Modern Auth）：&lt;a href="https://support.microsoft.com/en-us/outlook/"&gt;https://support.microsoft.com/en-us/outlook/&lt;/a&gt;pop-imap-and-smtp-settings-for-outlook-com&lt;/li&gt;
&lt;li&gt;微软 IMAP OAuth 接入（scope、授权码 / 设备码流程）：&lt;a href="https://learn.microsoft.com/en-us/exchange/client-developer/legacy-protocols/how-to-authenticate-an-imap-pop-smtp-application-by-using-oauth"&gt;https://learn.microsoft.com/en-us/exchange/client-developer/legacy-protocols/how-to-authenticate-an-imap-pop-smtp-application-by-using-oauth&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;微软 basic auth 废除（Exchange Online，2022-10）：&lt;a href="https://learn.microsoft.com/en-us/exchange/clients-and-mobile-in-exchange-online/deprecation-of-basic-authentication-exchange-online"&gt;https://learn.microsoft.com/en-us/exchange/clients-and-mobile-in-exchange-online/deprecation-of-basic-authentication-exchange-online&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Yahoo 明文密码 IMAP 停用（2024-05-15）与 OAuth：&lt;a href="https://help.yahoo.com/kb/SLN36636.html"&gt;https://help.yahoo.com/kb/SLN36636.html&lt;/a&gt; &lt;a href="https://senders.yahooinc.com/developer/"&gt;https://senders.yahooinc.com/developer/&lt;/a&gt;documentation/&lt;/li&gt;
&lt;li&gt;Apple 应用专用密码（2FA 强制、25 个上限、改密吊销）：&lt;a href="https://support.apple.com/en-us/102654"&gt;https://support.apple.com/en-us/102654&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">est</dc:creator><pubDate>Fri, 07 Aug 2026 10:35:00 +0800</pubDate><guid isPermaLink="false">tag:None,2026-08-07:/2026/stdout-31</guid><category>stdout</category></item><item><title>“畜牲”</title><link>https://blog.est.im/2026/stderr-27</link><description>&lt;p&gt;最近观察到娃学会了一些脱口而出的骂人的话，他骑车遇到看不惯的现象，就会骂一句 “牲口” ！&lt;/p&gt;
&lt;p&gt;我也没太多去干预，毕竟比 “肏” 这类秽语要委婉那么一丢丢。&lt;/p&gt;
&lt;p&gt;然后我最近也喜欢一边开 Vibe Coding 一边挂机 Rimworld 种田，&lt;/p&gt;
&lt;p&gt;然后就发现一个事儿，我在牧场区域种的 恶蘑菇，一种非食用植物，不会被动物吃掉；如果种玉米 稻米 土豆就会被偷吃，然后基地的粮食就少了一份。&lt;/p&gt;
&lt;p&gt;所以突然就得到这么一个莫名其妙的理论：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;动物并不会去主动破坏自己吃不了的东西&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;可能也有反例，狼、狮子会杀死竞争者的幼崽，黑猩猩会打架，一些鸟会破坏别的鸟的蛋；松鼠会偷走自己暂时吃不了的东西；海豚玩弄猎物；&lt;/p&gt;
&lt;p&gt;通过这些例子，感觉破坏性和智力正相关，也就是利用预测能力和因果性去糟蹋东西。骂人是动物，仿佛动物低人一等，但是人心有的时候，甚至还不如“畜牲”&lt;/p&gt;
&lt;p&gt;如果把这个限定缩小一点：&lt;/p&gt;
&lt;p&gt;动物作恶的能力仅限身体。&lt;/p&gt;
&lt;p&gt;人类里的坏逼，可能是唯一为了某个概念性的目标，会系统性破坏自己无法直接利用、甚至未来有价值东西的动物&lt;/p&gt;
&lt;p&gt;智力让生物获得了创造未来的能力，也让它获得了毁灭未来的能力。&lt;/p&gt;
&lt;p&gt;植物貌似也只会利用身体去占领局部环境，比如分泌毒素，遮挡阳光，向环境释放某种抑制剂。&lt;/p&gt;
&lt;p&gt;但人类可以把攻击性扩大到远超生存需求的规模。为了荣誉、信仰、身份、复仇去糟蹋自己甚至不认识的人或者物。&lt;/p&gt;
&lt;p&gt;这是一种非常特殊的“脱离现实反馈”的能力。&lt;/p&gt;
&lt;p&gt;所以「畜牲」这个骂法有点讽刺——很多时候，骂别人「像动物」，其实是在指责对方缺少克制；但换个角度看，动物反而经常遵循一种很严格的生态逻辑：消耗资源、竞争、生存，不会为了纯粹抽象的理由把世界变得更糟。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;btw 这个游戏真的有毒。好多年前尝试畜牧，结果直接生了一小崽，指数增长，然后过冬吃光了粮食，就纷纷饿死。然后来年就严格限制动物数量，定期宰杀，发现最简单的办法是砍掉雄性，留下1-2个传种，留下产奶产蛋的雌性。在感叹残酷的同时，结果无意中发现了 回交 。&lt;/p&gt;
&lt;p&gt;据说宋朝马政废弛，就是因为儒生不忍心这么干，所以导致良马欠缺。&lt;/p&gt;
&lt;p&gt;你说这个这个是人类的扭曲的道德还是动物的天性呢？&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">est</dc:creator><pubDate>Mon, 03 Aug 2026 23:24:00 +0800</pubDate><guid isPermaLink="false">tag:None,2026-08-03:/2026/stderr-27</guid><category>stderr</category></item><item><title>飞书并入豆包，文档是否减少？</title><link>https://blog.est.im/2026/stderr-26</link><description>&lt;p&gt;飞书并入豆包&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;7月30日，字节跳动发布内部邮件，宣布飞书产品团队与豆包产品团队将整合，成立新的豆包产品团队，由豆包负责人赵祺负责，飞书负责人谢欣向赵祺汇报。GTM（市场、销售、客户服务）体系方面，飞书GTM团队将与火山引擎团队整合，成立新的ToB GTM组织“创造力服务平台（Creativity Service Platform）”。整体负责字节 MaaS和SaaS等云服务的市场、销售和客户服务，由火山引擎负责人谭待负责，飞书销售负责人林婵、飞书战略及市场负责人史志隽向谭待汇报。重组之后，原有的飞书产品和服务保持不变，飞书还将和豆包在生产力场景进行更深度的产品协作。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;然后刷到&lt;a href="https://x.com/xicilion/status/2082673304033480732"&gt;一个推&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;办公文档恰恰是 AI 要淘汰的信息交互协议。以前在两个信息孤岛传递信息，需要两边的对接人来进行消息组包和分解，来消除两边信息不对称的问题。&lt;br /&gt;
企业要推行 AI，那么两边各自准备一个智能体，他俩自己聊就行了。&lt;br /&gt;
没必要让智能体写一个报告或者 ppt，交给人类，再转交给另一个人类，再丢给智能体。&lt;br /&gt;
今后只会出现三个场景需要文档：&lt;br /&gt;
AI 写出来给 AI 看，作为阶段性消息压缩。&lt;br /&gt;
AI 写出来给人看，人写出来给 AI 看，作为人类和 AI 的两个信息孤岛的信息交互协议。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我想了下，不对啊。&lt;code&gt;AGENTS.md&lt;/code&gt;、&lt;code&gt;CLAUDE.md&lt;/code&gt;、&lt;code&gt;.rules&lt;/code&gt;、&lt;code&gt;MEMORY.md&lt;/code&gt;、&lt;code&gt;DESIGN.md&lt;/code&gt;、&lt;code&gt;SOUL.md&lt;/code&gt;  vibe coding 发明出来多少妖魔鬼怪的文档环节&lt;/p&gt;
&lt;p&gt;当然，有人说，你这码农自 high，非研发哪里需要这么多文档。但 vibe coding 暴露的问题不是码农特有的，而是大模型根本缺陷——没有连续性。&lt;/p&gt;
&lt;p&gt;就算你用 A2A通信，打通 sub-agent又如何？同一个 agent 的今天和明天之间，隔着一堵完全遗忘的墙，比任何组织间的信息壁垒都彻底。&lt;/p&gt;
&lt;p&gt;这一点已经被无数个 &lt;code&gt;A\&lt;/code&gt; 上的 blog 证明了。他们家甚至搞出来个逆天的 constitution 文档。为啥？两个 agent 的聊天记录是流水账，没法有意义地做版本对比。但一份 markdown spec 可以被 git diff、被 review、被回滚&lt;/p&gt;
&lt;p&gt;当然，华丽排版的 Word、PPT 这种给人看的“表演”性质文档确实在这套流程里基本绝迹了。。。。吧？呃，不对。你汇报不做 ppt 能升值加薪吗？AI 能做 ppt，现在是卖点！&lt;/p&gt;
&lt;p&gt;说到这里，我刚好遇到个工作里真实的事，有个说不清道不明的感受，不知道如何形容。&lt;/p&gt;
&lt;p&gt;有个需求属于两、三个部门的业务数据流转&lt;/p&gt;
&lt;p&gt;字段出了点差错，推送方和接受方都能做，管道方也能做，但是就推诿&lt;/p&gt;
&lt;p&gt;这个时候，开个会，主持人出了个文档，突然事情就能进行下去了&lt;/p&gt;
&lt;p&gt;本来我一直觉得，事在人为，人是做事的主体，但是这个情况里，人虽然有做事的「潜力」，但是种种原因，实际都懒得去做；反而一个文档被「讨论」出来之后，形成某种魔力，「驱动」人们去做事&lt;/p&gt;
&lt;p&gt;然后我又想起，我在学生时代还有一个神奇的误解，小时候只知道美式三权分立，国会负责立“法”。具体立了什么法没太多概念 直到贸易战，发现都是各种 act 。什么《民权 act》《清洁空气 act》《CHIPS Act》 现在琢磨一下，有点类似戏剧里的 Act 1, Act 2，也有点“行动”的意思，这里的“法”其实和生活中“民法”有点微妙差异。 它不是约束，而是推动。&lt;/p&gt;
&lt;p&gt;AI看到这里，指出：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;开会 + 出文档做的事情,恰好就是把私下的、各自心照不宣的认知,变成公开的、被见证过的认知。文档本身可能一个字新信息都没有,但"在场所有人一起看着这行字被写下来"这件事,把"我知道"升级成了"我们都知道,而且我们都知道我们都知道"。这就是谢林点(Schelling point)成立的条件——不是文档有魔力,是文档完成了一次"公证仪式",把博弈从"猜对方会不会先动"变成了"规则已经摆在这儿,不动才是异类"。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;但是繁文缛节一多，这不就回到科层制，制度化（institutionalization）了吗？&lt;/p&gt;
&lt;p&gt;我突然发现，spawn 一个 agent 是廉价的，那么理论上就如同 orchestrate 一个 subagent 集群写代码一样，需要形成很多 act 才能统一行动。 &lt;/p&gt;
&lt;p&gt;所以我得到一个阶段性结论：&lt;/p&gt;
&lt;p&gt;将来办公文档恐怕不是变少，而是会海量的被agent生成出来。。。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;继续下去，如果生成 act 的成本趋近于零，文档可靠性必然被稀释。就像货币超发会通胀——如果人人(agent)都能一句话甩出一份文档，那以谁的为准？&lt;/p&gt;
&lt;p&gt;你别说，查一下claude code那几十万字的 system prompt。。。我甚至都怀疑里面冲突和矛盾有多少。。。&lt;/p&gt;
&lt;p&gt;openai，A\ 这种 frontier 也是堆屎山，地球上有多少人还能做的更好呢？&lt;/p&gt;
&lt;p&gt;也许，以后数据结构定义清晰，理解成本低，协议设计干练，RPC职权分明 的数据驱动公司，和 “面条文档” AI驱动的公司，可能有天差地别的生产力悬殊对比。。。。&lt;/p&gt;
&lt;p&gt;AI反驳说，真是世界没有唯一正确答案。不是一些 schema 套一点 enum 类型枚举就能穷尽的。&lt;/p&gt;
&lt;p&gt;呃，业务建模当然存在各种问题，我想说的其实是，合理分工问题&lt;/p&gt;
&lt;p&gt;现实当然是 messy的，往往没法写成一个固定 schema 的。就如同数学不可能背答案学好一样。&lt;/p&gt;
&lt;p&gt;但是特定步骤和分工往往能解决一大片类似问题。&lt;/p&gt;
&lt;p&gt;所谓部门结构决定代码架构，很多业务里的乱往往是部门墙导致的。过去部门调整往往伤筋动骨，顶层设计缺这少哪欠考虑&lt;/p&gt;
&lt;p&gt;但是agent swarm呢？你的试错成本几乎为0 ，给agent赋予一个角色只需要一段 system prompt。&lt;/p&gt;
&lt;p&gt;如果你懂业务，你可以几个小时构建一套完整流程，然后不停试错迭代。&lt;/p&gt;
&lt;p&gt;这才是巨大的机遇。按照传统行业分工固定模式生产，想着AI 去充当裱糊匠，这个格局没打开。&lt;/p&gt;
&lt;p&gt;想到这里，我突然回忆起这个炸裂的文章：&lt;/p&gt;
&lt;p&gt;&lt;a href="https://trinkle23897.github.io/learning-beyond-gradients/"&gt;https://trinkle23897.github.io/learning-beyond-gradients/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;EnvPool 的作者，他维护环境库时想找一种便宜、可复现的方式测试游戏环境是否跑得对，于是用 Codex(gpt-5.4)写纯规则策略，不训练任何神经网络。结果远超预期：一个打砖块游戏 Atari Breakout，策略从 387 -&amp;gt; 507 -&amp;gt; 839 -&amp;gt; 864，最后打到理论最高分；Breakout 从最开始简单的 “球在左边就往左” 发展出一套成熟完整的策略&lt;/p&gt;
&lt;p&gt;作者说，专家系统、规则系统的失败，不是因为它表现不好，而是这玩意的维护成本十分高昂。人类手工维护 heuristic 很容易变成这样：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;今天加一条规则修 case A。&lt;/li&gt;
&lt;li&gt;明天发现 case B 被修坏了。&lt;/li&gt;
&lt;li&gt;后天再加一个 if。&lt;/li&gt;
&lt;li&gt;大后天没人敢删了。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;那么有了 coding agent 之后呢？随着大模型能力提升，人类介入次数会逐渐变少，这个反馈循环就有机会在某些边界明确的系统里自动闭合，从而能够实现自动化用 HL 批量生产 HS：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;环境反馈 / 测试失败 / 日志异常&lt;/li&gt;
&lt;li&gt;coding agent 读 context&lt;/li&gt;
&lt;li&gt;修改 policy / test / memory&lt;/li&gt;
&lt;li&gt;重新运行&lt;/li&gt;
&lt;li&gt;把结果写回 trials 和 summary&lt;/li&gt;
&lt;li&gt;下一轮继续&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我的takeaway可能更露骨：以前组织架构靠部门关系和体制运转&lt;/p&gt;
&lt;p&gt;国会维护的 act 可能各种冲突、短视，矛盾，所以做事的主体，还得是人。&lt;/p&gt;
&lt;p&gt;agent 时代不一样了。代码还是很乱，文档也很乱，但可能某种很牛的规则“醒过来”了&lt;/p&gt;
&lt;p&gt;以后某个重要的岗位可能不是一个资深的员工，而是某个角落一段被反复验证过的核心代码  &lt;/p&gt;
&lt;p&gt;其实 quant 行业早就是这个形状了吧？&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;大多数人对AI 的态度，可能停留在 提效 上面。对于彻底掀翻桌子，固定岗位没了这种颠覆性的冲击可能没预料到，我这里的预测也有可能是错的。不过写到这，我突然发现，这篇blog核心观点就一句话：生产力的提升必然带来生产关系的变革。 &lt;/p&gt;
&lt;p&gt;刚好最近几天，肉眼可见这一轮AI 到顶了。美股 科技股都在很大波动。&lt;/p&gt;
&lt;p&gt;但是AI 对各行各业带来的冲击，我觉得刚开始。就看美国这一轮巨头会释放多少capex折损和二手设备流通，就像当年 dotcom bubble 带来廉价的fiber一样。&lt;/p&gt;
&lt;p&gt;希望明年能用上 128G CAMM2 接口能跑 nvfp4 的本地推理AI！&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">est</dc:creator><pubDate>Thu, 30 Jul 2026 15:41:00 +0800</pubDate><guid isPermaLink="false">tag:None,2026-07-30:/2026/stderr-26</guid><category>stderr</category></item><item><title>从菲尔兹奖谈「包养」</title><link>https://blog.est.im/2026/stderr-25</link><description>&lt;p&gt;美国当地时间2026年7月23日上午，在费城举办的国际数学家大会上，官方正式公布2026年菲尔兹奖完整获奖名单，北大2007级本科校友王虹、邓煜双双上榜。这是自菲尔兹奖设立近九十年以来，首次有中国籍数学家拿下该奖项&lt;/p&gt;
&lt;p&gt;然后网上各国各路反思怪就开始表演了，我也未能免俗，对其中有个议题感兴趣，数学强国，是否要允许养十年冷板凳的学科？&lt;/p&gt;
&lt;p&gt;首先，这个「十年」冷板凳的说法有点误导的。Fields Medal 奖励给40岁以下的人，正是因为数学这玩意出成果可以当庭验证，不用等诺贝尔奖那种从理论刷新实验和工业需要几十年。&lt;/p&gt;
&lt;p&gt;王虹：Kakeya 猜想（三维情形）开始于2024–2025年前后，与 Zahl 的工作集中攻克，2025年发表突破性证明（127页论文）。&lt;/p&gt;
&lt;p&gt;邓煜：Boltzmann方程 到 流体方程（Hilbert第六问题方向）一系列，他这个周期的确比较长，但也是2024–2025年前后与合作者完成严格推导相关关键结果。&lt;/p&gt;
&lt;p&gt;所以数学这玩意属于发大招的前摇很长。但是结果突破了就立马见效。&lt;/p&gt;
&lt;p&gt;然后就回到这个议题，科学技术被「包养」10年，甚至可能不出成果，国家或者结构敢这么干吗？能这么干吗？会不会导致关系户吃空饷？有没有什么问题？&lt;/p&gt;
&lt;p&gt;与其对这个问题辩经，不如看看历史上真实的「科研」是怎么进行的。&lt;/p&gt;
&lt;p&gt;很多人包括我，对近现代科学史的定义，是从 哥白尼 开始，我觉得要不就从 第谷 开始，我让 &lt;code&gt;A\&lt;/code&gt;帮我做了一个调查，有哪些 ≥第谷 档次的重要科学技术发明人&lt;/p&gt;
&lt;p&gt;很快AI 给了这样一个表格：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;年代&lt;/th&gt;
&lt;th&gt;人物&lt;/th&gt;
&lt;th&gt;主要贡献&lt;/th&gt;
&lt;th&gt;与第谷相当/超越的理由&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1609–1619&lt;/td&gt;
&lt;td&gt;开普勒&lt;/td&gt;
&lt;td&gt;行星运动三大定律&lt;/td&gt;
&lt;td&gt;直接用第谷数据推翻旧宇宙观,理论层面已超越&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1610s–1630s&lt;/td&gt;
&lt;td&gt;伽利略&lt;/td&gt;
&lt;td&gt;望远镜天文学、力学、科学方法论&lt;/td&gt;
&lt;td&gt;开创实验科学范式,影响力远超单一学科&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1628&lt;/td&gt;
&lt;td&gt;威廉·哈维&lt;/td&gt;
&lt;td&gt;血液循环理论&lt;/td&gt;
&lt;td&gt;生理学革命的起点&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1687&lt;/td&gt;
&lt;td&gt;牛顿&lt;/td&gt;
&lt;td&gt;万有引力、运动定律、微积分&lt;/td&gt;
&lt;td&gt;公认整个科学史影响力最大者之一&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1735&lt;/td&gt;
&lt;td&gt;林奈&lt;/td&gt;
&lt;td&gt;生物分类系统&lt;/td&gt;
&lt;td&gt;至今仍是生物学基础语言&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1789&lt;/td&gt;
&lt;td&gt;拉瓦锡&lt;/td&gt;
&lt;td&gt;质量守恒、现代化学奠基&lt;/td&gt;
&lt;td&gt;开创一门学科的量化范式&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1798&lt;/td&gt;
&lt;td&gt;詹纳&lt;/td&gt;
&lt;td&gt;牛痘疫苗&lt;/td&gt;
&lt;td&gt;免疫学起点,直接拯救数亿人&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1800&lt;/td&gt;
&lt;td&gt;伏打&lt;/td&gt;
&lt;td&gt;电池&lt;/td&gt;
&lt;td&gt;开启电学实用化时代&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1805–1808&lt;/td&gt;
&lt;td&gt;道尔顿&lt;/td&gt;
&lt;td&gt;原子理论&lt;/td&gt;
&lt;td&gt;化学从定性走向定量的关键&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1831&lt;/td&gt;
&lt;td&gt;法拉第&lt;/td&gt;
&lt;td&gt;电磁感应&lt;/td&gt;
&lt;td&gt;现代电力文明的直接源头&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1859&lt;/td&gt;
&lt;td&gt;达尔文&lt;/td&gt;
&lt;td&gt;进化论&lt;/td&gt;
&lt;td&gt;生物学乃至世界观层面的范式革命&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1865&lt;/td&gt;
&lt;td&gt;孟德尔&lt;/td&gt;
&lt;td&gt;遗传学定律&lt;/td&gt;
&lt;td&gt;生物学隐藏的另一条主线,后来居上&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1861–1873&lt;/td&gt;
&lt;td&gt;麦克斯韦&lt;/td&gt;
&lt;td&gt;电磁场理论&lt;/td&gt;
&lt;td&gt;统一光、电、磁,爱因斯坦称其为牛顿之后最重要&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1857–1895&lt;/td&gt;
&lt;td&gt;巴斯德&lt;/td&gt;
&lt;td&gt;细菌学说、疫苗、消毒法&lt;/td&gt;
&lt;td&gt;医学史上救人最多的人之一&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1869&lt;/td&gt;
&lt;td&gt;门捷列夫&lt;/td&gt;
&lt;td&gt;元素周期表&lt;/td&gt;
&lt;td&gt;化学的"第谷式"系统整理+预言能力&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1895–1898&lt;/td&gt;
&lt;td&gt;伦琴 / 居里夫妇&lt;/td&gt;
&lt;td&gt;X射线 / 放射性&lt;/td&gt;
&lt;td&gt;打开原子内部世界的大门&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1905–1915&lt;/td&gt;
&lt;td&gt;爱因斯坦&lt;/td&gt;
&lt;td&gt;狭义/广义相对论&lt;/td&gt;
&lt;td&gt;科学史知名度和范式颠覆力最高者之一&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1900–1927&lt;/td&gt;
&lt;td&gt;普朗克 / 玻尔 / 海森堡 / 薛定谔&lt;/td&gt;
&lt;td&gt;量子力学&lt;/td&gt;
&lt;td&gt;与相对论并列的20世纪物理两大支柱之一&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1928&lt;/td&gt;
&lt;td&gt;弗莱明&lt;/td&gt;
&lt;td&gt;青霉素&lt;/td&gt;
&lt;td&gt;抗生素时代开端,救人数以亿计&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1936–1950&lt;/td&gt;
&lt;td&gt;图灵&lt;/td&gt;
&lt;td&gt;计算理论、图灵机&lt;/td&gt;
&lt;td&gt;整个信息时代的理论奠基人&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1948&lt;/td&gt;
&lt;td&gt;香农&lt;/td&gt;
&lt;td&gt;信息论&lt;/td&gt;
&lt;td&gt;数字时代的底层数学语言&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1953&lt;/td&gt;
&lt;td&gt;沃森、克里克、富兰克林、威尔金斯&lt;/td&gt;
&lt;td&gt;DNA双螺旋结构&lt;/td&gt;
&lt;td&gt;分子生物学时代的起点&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1989&lt;/td&gt;
&lt;td&gt;蒂姆·伯纳斯-李&lt;/td&gt;
&lt;td&gt;万维网&lt;/td&gt;
&lt;td&gt;重塑人类信息交流方式&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2012&lt;/td&gt;
&lt;td&gt;杜德纳 &amp;amp; 沙尔庞捷&lt;/td&gt;
&lt;td&gt;CRISPR基因编辑&lt;/td&gt;
&lt;td&gt;生命科学的"第谷式"精确操控工具&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2005–2020&lt;/td&gt;
&lt;td&gt;卡里科 &amp;amp; 魏斯曼&lt;/td&gt;
&lt;td&gt;mRNA疫苗技术&lt;/td&gt;
&lt;td&gt;新冠疫情中验证的范式级突破&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2020&lt;/td&gt;
&lt;td&gt;Hassabis / Jumper(DeepMind)&lt;/td&gt;
&lt;td&gt;AlphaFold蛋白质结构预测&lt;/td&gt;
&lt;td&gt;AI解决半世纪悬而未决的科学难题&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;AI给的几点补充说明:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;早期(1600–1900)明显比后期"密度更高"&lt;/strong&gt;:因为现代科学建制尚未形成,单个人的贡献边界更清晰,也更容易和第谷这种"孤胆式"人物类比。20世纪后科学越来越工业化、团队化(比如人类基因组计划、大型对撞机、AlphaFold团队),个人英雄式的叙事变少了。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;第谷本人的定位其实很微妙&lt;/strong&gt;:他不是理论家,而是"数据基建"式人物——用极致的观测精度为后人铺路。如果按这个标准严格类比,像&lt;strong&gt;哈勃&lt;/strong&gt;(观测确立宇宙膨胀)、&lt;strong&gt;萨顿·汤姆森测序团队/人类基因组计划&lt;/strong&gt;这类"以海量精确数据推动范式转移"的人/团队,可能比爱因斯坦这种理论天才更贴近第谷的"角色",而不只是"级别"。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;看过给出的列表，我问了第二个问题，TA们的funding是如何的？&lt;/p&gt;
&lt;p&gt;AI说：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这个角度非常犀利——科学史书写往往聚焦"发现了什么",却选择性地忽略"靠什么活下来"。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;人物&lt;/th&gt;
&lt;th&gt;资助/职业方式&lt;/th&gt;
&lt;th&gt;轻松程度&lt;/th&gt;
&lt;th&gt;备注&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;第谷&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;丹麦国王腓特烈二世赐予汶岛+巨额年俸(据估算占丹麦国库约1%)&lt;/td&gt;
&lt;td&gt;极轻松→后期崩盘&lt;/td&gt;
&lt;td&gt;换了国王克里斯蒂安四世后失宠,被迫流亡布拉格投靠鲁道夫二世&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;开普勒&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;帝国数学家头衔(理论上),实际靠占星糊口+教书&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;很惨&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;皇室长期拖欠薪水,他多年追讨欠款;母亲还被控行巫术,他得亲自辩护&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;伽利略&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;帕多瓦大学教职→美第奇宫廷数学家&lt;/td&gt;
&lt;td&gt;中等偏好&lt;/td&gt;
&lt;td&gt;靠把木星卫星命名为"美第奇星"换取赞助,堪称科学史第一代"公关高手";后期被宗教裁判所软禁致死&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;哈维&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;詹姆士一世/查理一世的御医&lt;/td&gt;
&lt;td&gt;轻松&lt;/td&gt;
&lt;td&gt;医生本业收入稳定,王室背书加持&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;牛顿&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;剑桥卢卡斯教授→皇家造币厂厂长&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;越老越轻松&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;造币厂是肥缺,晚年相当富有,还当上皇家学会主席&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;林奈&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;乌普萨拉大学教授&lt;/td&gt;
&lt;td&gt;中等偏好&lt;/td&gt;
&lt;td&gt;平民出身,靠学术晋升,晚年封爵、相对富裕&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;拉瓦锡&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;私人身份是"包税官"(Ferme Générale)&lt;/td&gt;
&lt;td&gt;极轻松→被砍头&lt;/td&gt;
&lt;td&gt;用包税收入自建豪华实验室;大革命时因"包税官"身份被送上断头台&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;詹纳&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;乡村医生+英国议会拨款(约1万→2万英镑)&lt;/td&gt;
&lt;td&gt;中等&lt;/td&gt;
&lt;td&gt;国家事后买单,但过程有争议&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;道尔顿&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;贵格会教师+朋友募集年金+政府公民名单养老金&lt;/td&gt;
&lt;td&gt;清苦但稳定&lt;/td&gt;
&lt;td&gt;生活极简朴,靠圈子互助&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;法拉第&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;皇家研究所助理起家(戴维的技术员)→终身研究员+维多利亚女王赐宅&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;逆袭典范&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;铁匠之子、书籍装订学徒出身,靠机构体系一路托底&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;达尔文&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;家族财富(韦奇伍德陶瓷+医生世家)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;完全无忧&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;终身未任职,自费出海、自费研究,名单里最"躺平"的人&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;孟德尔&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;布尔诺修道院供养,后升任院长&lt;/td&gt;
&lt;td&gt;轻松但&lt;strong&gt;默默无闻&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;教会包养换来的是35年无人问津,死后才被重新发现&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;麦克斯韦&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;苏格兰地产家族+卡文迪许讲席教授(德文郡公爵捐资)&lt;/td&gt;
&lt;td&gt;轻松&lt;/td&gt;
&lt;td&gt;本身有庄园收入,教职是锦上添花&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;巴斯德&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;法国国家教职→巴斯德研究所(政府+国际公众捐款)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;成功的众筹&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;狂犬病疫苗成功后全球捐款蜂拥而至,堪称19世纪版"众筹成功案例"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;门捷列夫&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;圣彼得堡大学教授&lt;/td&gt;
&lt;td&gt;中等&lt;/td&gt;
&lt;td&gt;学术生涯稳定,但因政治原因被拒于俄国科学院大门外&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;伦琴&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;德国大学教职体系+诺贝尔奖(首届物理奖)&lt;/td&gt;
&lt;td&gt;轻松&lt;/td&gt;
&lt;td&gt;典型德国教授晋升路线&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;居里夫妇&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;索邦大学,早期极度贫困(棚屋实验室)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;早期惨,后期爆红&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;美国妇女发起"镭募捐运动"送她一克镭,靠国际名气才翻身&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;爱因斯坦&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1905年是伯利专利局小职员&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;早期惨&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;"奇迹年"论文是业余时间写的;成名后才拿到苏黎世、柏林教职&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;普朗克/玻尔/海森堡/薛定谔&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;各国大学教职;玻尔研究所由&lt;strong&gt;嘉士伯啤酒基金会&lt;/strong&gt;资助&lt;/td&gt;
&lt;td&gt;普遍轻松&lt;/td&gt;
&lt;td&gt;玻尔研究所靠卖啤酒的钱养量子力学,是个有趣的冷知识&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;弗莱明&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;圣玛丽医院教职,发现青霉素后长期被冷落&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;发现容易,落地惨&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;真正把青霉素变成药的是弗洛里和钱恩,靠美国战时政府+洛克菲勒基金会砸钱才成&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;图灵&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;剑桥研究员→英国政府战时机密资助(布莱切利园)&lt;/td&gt;
&lt;td&gt;战时极轻松→&lt;strong&gt;战后被国家毁掉&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;因同性恋被定罪、化学阉割,44岁去世,是名单里结局最悲惨的&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;香农&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;贝尔实验室&lt;/td&gt;
&lt;td&gt;轻松&lt;/td&gt;
&lt;td&gt;工业界顶级研发机构,待遇优渥&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;沃森/克里克/富兰克林/威尔金斯&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;英国医学研究理事会(MRC)拨款&lt;/td&gt;
&lt;td&gt;中等偏好&lt;/td&gt;
&lt;td&gt;已进入现代"政府科研拨款"体系&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;伯纳斯-李&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;CERN雇员&lt;/td&gt;
&lt;td&gt;轻松&lt;/td&gt;
&lt;td&gt;万维网是"副业",欧洲多国联合资助的大型实验室养活了他&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;杜德纳&amp;amp;沙尔庞捷&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;大学教职+NIH/霍华德休斯医学研究所巨额资助+后期创业融资&lt;/td&gt;
&lt;td&gt;轻松&lt;/td&gt;
&lt;td&gt;现代"学术拨款+风投"双轨制的受益者&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;卡里科&amp;amp;魏斯曼&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;宾大长期&lt;strong&gt;拒绝&lt;/strong&gt;其mRNA研究拨款,被降级&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;名单里最惨的现代案例&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;卡里科多年申请不到经费,一度濒临放弃,直到转投BioNTech(企业资金)才翻身,新冠疫苗验证了她&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hassabis/Jumper(DeepMind)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;风投起家→2014年被谷歌以约5亿美元收购&lt;/td&gt;
&lt;td&gt;极轻松&lt;/td&gt;
&lt;td&gt;大厂算力+资本,现代AI研究的资助模式&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;AI发现几个有意思的规律：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;"贵族/私产型"最省心&lt;/strong&gt;:第谷(早期)、达尔文、拉瓦锡(早期)、麦克斯韦——但拉瓦锡的例子提醒你,私产型资助有政治风险,大革命一来照样人头落地。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;"体制拖欠型"最折磨人&lt;/strong&gt;:开普勒是典型代表——头衔光鲜、待遇纸面上不错,但皇室实际不给钱,他等于用占星术这份"副业"养活了现代天文学的诞生。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;"教会/修道院型"稳定但可能换来彻底沉默&lt;/strong&gt;:孟德尔衣食无忧,代价是被历史遗忘35年——这提醒我们"资助稳定"和"影响力"未必成正比。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;"先穷后爆红"是个反复出现的剧本&lt;/strong&gt;:爱因斯坦、居里夫人、卡里科都是先坐冷板凳,成名/成功后资助才如潮水涌来——这某种程度上说明&lt;strong&gt;资助体系本身经常是滞后的、事后追认的&lt;/strong&gt;,而不是有远见地提前下注。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;国家战争机器是隐藏的大金主&lt;/strong&gt;:图灵(二战)、弗莱托与钱恩的青霉素产业化(二战)都靠战时政府不计成本砸钱才落地,和平年代未必能拿到同等规模的支持。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;然后我问了第三个问题：按照列表加入一个 资方 出发点 视角。本来是想拿这笔钱或者这个项目目的是干嘛的？&lt;/p&gt;
&lt;p&gt;AI回答：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这个视角非常关键——你其实点出了科学史书写的一个系统性偏差:我们只看到"赌赢了"的案例,资方当初的真实动机往往和最终成果风马牛不相及,而"陪跑"的绝大多数投入早就被历史遗忘了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;人物&lt;/th&gt;
&lt;th&gt;资方&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;资方真实目的("这笔钱本来是要干嘛")&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;最终成果是否"跑题"&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;第谷&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;丹麦国王腓特烈二世&lt;/td&gt;
&lt;td&gt;宫廷占星(为国王择日、预测战争吉凶)+国家门面工程(丹麦要在欧洲学术圈刷存在感)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;完全跑题&lt;/strong&gt;——精确观测只是占星的"副业副产品"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;开普勒&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;神圣罗马帝国皇帝鲁道夫二世&lt;/td&gt;
&lt;td&gt;帝国数学家的本职是占星预测+编历法表(《鲁道夫星历表》,给贵族用)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;跑题&lt;/strong&gt;——行星定律是他"偷偷"塞进占星工作里的私货&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;伽利略&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;美第奇家族&lt;/td&gt;
&lt;td&gt;家族宣传公关(把木星卫星命名为"美第奇星")+帕多瓦大学教军事工程/弹道计算&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;半跑题&lt;/strong&gt;——日心说支持是他自己夹带的,资方要的是名声和实用军事技术&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;哈维&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;詹姆士一世/查理一世&lt;/td&gt;
&lt;td&gt;单纯要个好御医看病&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;跑题&lt;/strong&gt;——血液循环论纯属他自己的业余研究&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;牛顿&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;剑桥卢卡斯讲席 / 英国皇家造币厂&lt;/td&gt;
&lt;td&gt;教数学 / 打击伪币、稳定英镑币值(国家财政问题)&lt;/td&gt;
&lt;td&gt;讲席教职算对口;造币厂&lt;strong&gt;完全跑题&lt;/strong&gt;,和万有引力毫无关系&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;林奈&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;瑞典王室+乌普萨拉大学&lt;/td&gt;
&lt;td&gt;找可替代进口的本土经济作物(茶、香料"国产化"),外加药用植物鉴定&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;半跑题&lt;/strong&gt;——分类系统是这个经济任务的副产品,规模远超预期&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;拉瓦锡&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;包税官身份(私人生意)&lt;/td&gt;
&lt;td&gt;纯粹收税赚钱,跟化学毫无关系&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;完全跑题&lt;/strong&gt;——化学是他用私人财富养的"业余爱好"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;詹纳&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;英国议会&lt;/td&gt;
&lt;td&gt;例外!这是&lt;strong&gt;事后追认型&lt;/strong&gt;——先证明疫苗有效,议会才拨款奖励&lt;/td&gt;
&lt;td&gt;不跑题,但属于"结果已出再下注"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;道尔顿&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;贵格会社区互助&lt;/td&gt;
&lt;td&gt;培养教师、维持社区教育&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;跑题&lt;/strong&gt;——原子论是他个人兴趣的副产品&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;法拉第&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;皇家研究所&lt;/td&gt;
&lt;td&gt;面向伦敦上流社会的科普讲座+社交场所(机构靠贵族会员费运营)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;半跑题&lt;/strong&gt;——电磁感应是"讲课之余"研究出来的&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;达尔文&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;家族财富 / 英国海军"小猎犬号"&lt;/td&gt;
&lt;td&gt;家族财富无目的;海军航行目的是&lt;strong&gt;海岸测绘+殖民地军事勘察&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;完全跑题&lt;/strong&gt;——进化论是搭军舰便车的博物学家副产品&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;孟德尔&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;修道院&lt;/td&gt;
&lt;td&gt;培养神职人员+可能想改良豌豆等园艺品种(自给自足)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;完全跑题&lt;/strong&gt;——教会根本不知道自己资助了现代遗传学,而且35年无人理睬&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;麦克斯韦&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;卡文迪许实验室(德文郡公爵)&lt;/td&gt;
&lt;td&gt;剑桥要提升实验物理声誉,跟牛津竞争的"大学军备竞赛"&lt;/td&gt;
&lt;td&gt;基本对口,但电磁波预言超出预期&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;巴斯德&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;法国政府+酒商/蚕丝业主&lt;/td&gt;
&lt;td&gt;具体产业救火:葡萄酒变酸、蚕病摧毁法国丝绸产业&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;半跑题&lt;/strong&gt;——细菌学说是解决产业危机时提炼出的理论&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;门捷列夫&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;大学教职+石油产业顾问(巴库油田)&lt;/td&gt;
&lt;td&gt;教学、写教科书+解决俄国石油裂解等实际工业问题&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;半跑题&lt;/strong&gt;——周期表是他"写教材"时整理出来的副产品&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;伦琴&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;大学常规科研经费&lt;/td&gt;
&lt;td&gt;常规阴极射线管实验,毫无特定目标&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;纯意外&lt;/strong&gt;——著名的实验室"事故"发现&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;居里夫妇&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;几乎无资助(索邦借的破棚屋)&lt;/td&gt;
&lt;td&gt;无目的探索沥青铀矿残渣之谜&lt;/td&gt;
&lt;td&gt;不算跑题,但资方几乎不存在&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;爱因斯坦&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;伯尔尼专利局&lt;/td&gt;
&lt;td&gt;审查专利申请,养家糊口&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;完全跑题&lt;/strong&gt;——相对论是上班"摸鱼"写的&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;玻尔研究所&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;嘉士伯啤酒基金会&lt;/td&gt;
&lt;td&gt;丹麦国家科学荣誉+啤酒公司企业形象/慈善&lt;/td&gt;
&lt;td&gt;半对口——资方押的是"国家声望",不是量子力学本身&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;弗莱明&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;圣玛丽医院&lt;/td&gt;
&lt;td&gt;临床细菌学教学诊断,日常工作&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;纯意外&lt;/strong&gt;——著名的"没洗培养皿"事故&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;青霉素产业化&lt;/td&gt;
&lt;td&gt;二战盟军政府+洛克菲勒基金会&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;纯军事需求&lt;/strong&gt;:救治战场伤员感染&lt;/td&gt;
&lt;td&gt;对口——这是少数"目的和结果高度一致"的案例&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;图灵&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;英国政府/布莱切利园&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;纯军事情报&lt;/strong&gt;:破解德军Enigma密码&lt;/td&gt;
&lt;td&gt;半跑题——图灵机/计算机雏形是破译密码的副产品&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;香农&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;贝尔实验室(AT&amp;amp;T)&lt;/td&gt;
&lt;td&gt;改善电话线路信号质量、降低长途通话噪声(纯商业工程问题)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;半跑题&lt;/strong&gt;——信息论是解决电话工程问题时提炼的数学理论&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;沃森/克里克/富兰克林&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;英国医学研究理事会(MRC)&lt;/td&gt;
&lt;td&gt;医学相关基础研究方向,但1953年DNA结构的实际应用价值并不明确&lt;/td&gt;
&lt;td&gt;半对口——某种程度上MRC也是在"赌"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;伯纳斯-李&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;CERN&lt;/td&gt;
&lt;td&gt;高能物理实验(强子对撞机等)才是CERN的核心任务&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;完全跑题&lt;/strong&gt;——万维网是他为解决CERN内部文档管理/科学家协作难题做的"内部小工具"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;杜德纳&amp;amp;沙尔庞捷&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;NIH/HHMI&lt;/td&gt;
&lt;td&gt;纯基础好奇心驱动:研究细菌如何抵抗病毒感染&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;完全跑题&lt;/strong&gt;——基因编辑工具是意外的应用副产品,申请经费时没人能预见&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;卡里科&amp;amp;魏斯曼&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;宾大(早期几乎拒绝)→BioNTech&lt;/td&gt;
&lt;td&gt;最初想做mRNA通用蛋白替代疗法平台,不是疫苗&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;半跑题&lt;/strong&gt;——疫苗只是后来才发现的应用场景之一&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hassabis/Jumper&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;谷歌收购DeepMind&lt;/td&gt;
&lt;td&gt;通用人工智能/游戏AI(AlphaGo系列)才是谷歌的主营目标&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;半跑题&lt;/strong&gt;——AlphaFold是公司内部"顺手"做的科学项目&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;AI总结的几个扎心的结论：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;"完全对口"的案例极少&lt;/strong&gt;:整个名单里,资方目的和最终科学价值高度一致的,大概只有詹纳(疫苗已验证后拨款)和青霉素产业化(军事紧急需求)——而且这两个都是&lt;strong&gt;"结果已经初步显现,资方才敢下注"&lt;/strong&gt;,不是提前押中的。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;"跑题率"高到惊人&lt;/strong&gt;:占星、税收、御医、公关、军事测绘、密码破译、电话降噪、文档管理系统……这些才是历史上真正的"招标书",科学突破几乎全是"顺手做的"或者"钻空子塞进去的"。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;你说得完全对——这份名单本身就是幸存者偏差的产物&lt;/strong&gt;。第谷时代还有无数宫廷占星师拿着差不多的资助,一辈子没算出任何有价值的东西;孟德尔的修道院同期资助的可能还有几十个神职人员搞园艺,没人记得他们。我们能列出这张表,恰恰是因为"科学价值"是&lt;strong&gt;事后被追认的标签&lt;/strong&gt;,而不是资方当初购买的商品。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;一个推论&lt;/strong&gt;:如果按"资方本意是否达成"来打分,这些人在当时的语境下,很多其实是“项目失败”或“跑题挪用经费”——开普勒如果被鲁道夫二世按KPI考核占星准确率,大概率是不及格的;伯纳斯-李如果被CERN按"你的对撞机数据分析进度"考核,万维网这个"副业"说不定还会被叫停。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;最后，图穷匕见：&lt;/p&gt;
&lt;p&gt;现代科研基金委的"结果导向"评审(要求预设可衡量产出、里程碑、KPI),可能恰恰系统性地筛掉了历史上产生最大价值的那种"跑题式"研究。&lt;/p&gt;
&lt;p&gt;我的暴论：&lt;/p&gt;
&lt;p&gt;资方为了装逼去包养才是科学研究第一必要条件。🤣 🤣 🤣 🤣 🤣 🤣 &lt;/p&gt;
&lt;p&gt;科学家得有品味和敢做副业的决心，才有可能搞出来大新闻&lt;/p&gt;
&lt;p&gt;穷逼就不要去幻想搞什么科研了。除非要么你能混成网红，要么你需要遇到一个贵人&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">est</dc:creator><pubDate>Mon, 27 Jul 2026 14:39:00 +0800</pubDate><guid isPermaLink="false">tag:None,2026-07-27:/2026/stderr-25</guid><category>stderr</category></item><item><title>iosevka字体让中文 ASCII diagram 图表对齐</title><link>https://blog.est.im/2026/stdout-30</link><description>&lt;p&gt;对齐前：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌──────────────┐     ┌──────────────┐
│  用户请求     │────▶ │  网关服务     │
│  User Req    │     │  Gateway     │
└──────┬───────┘     └──────┬───────┘
       │                    │
       ▼                    ▼
┌──────────────┐     ┌──────────────┐
│  认证服务     │      │  业务逻辑     │
│  Auth Svc    │     │  BizLogic    │
└──────────────┘     └──────┬───────┘
                            │
                            ▼
                     ┌──────────────┐
                     │  数据存储😆   │
                     │  Database😂  │
                     └──────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对齐后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
&lt;style style="display: inherit;"&gt;
@font-face {
  font-family: "iosevka";
  src: url("https://iosevka-webfonts.github.io/iosevka-term/woff2/iosevka-term-regular.woff2") format("woff2");
}
#after &gt; pre &gt; code {
   font-family: iosevka
}
&lt;/style&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;font id="after"&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;┌──────────────┐     ┌──────────────┐
│  用户请求    │────▶│  网关服务    │
│  User Req    │     │  Gateway     │
└──────┬───────┘     └──────┬───────┘
       │                    │
       ▼                    ▼
┌──────────────┐     ┌──────────────┐
│  认证服务    │     │  业务逻辑    │
│  Auth Svc    │     │  BizLogic    │
└──────────────┘     └──────┬───────┘
                            │
                            ▼
                     ┌──────────────┐
                     │  数据存储😆  │
                     │  Database😂  │
                     └──────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;AI 的解释：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Iosevka 的作者 be5invis 当年做这个字体时明确说过：因为他和很多朋友生活在中国、日本，所以他把这款字体做成严格的 1/2 em 宽，专门用来跟汉字对齐——面向亚洲用户，用这个就能保住完美对齐。也就是说 Iosevka 的西文字形宽度天生就是 0.5em，不需要任何 CSS 补偿或 size-adjust 魔法，配任何满格 1em 的 CJK 字体（Hiragino、PingFang、Source Han Sans 等）都是精确 2:1。而且它的构建系统是声明式的，用 TOML 配置文件驱动，可以精细控制粗细、宽度、每个字形的风格变体。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;中英混合是搞定了，最后那个 数据存储 Database 带emoji错位了。&lt;/p&gt;
&lt;p&gt;emoji 还有个zwj的问题：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;农民 emoji 🧑‍🌾 其实是"人"+ 零宽连接符（ZWJ）+ "农作物"两个 emoji 码位拼成的&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在 wcwidth 计算，会分别得到宽度 2、0、2，加起来变成 4 列宽导致错位&lt;/p&gt;
&lt;p&gt;目前暂时无解&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">est</dc:creator><pubDate>Thu, 23 Jul 2026 18:24:00 +0800</pubDate><guid isPermaLink="false">tag:None,2026-07-23:/2026/stdout-30</guid><category>stdout</category></item><item><title>为什么 Github OAuth 故意拦截 CORS</title><link>https://blog.est.im/2026/stdout-29</link><description>&lt;p&gt;跟AI发闹骚学到的&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/isaacs/github/issues/330"&gt;https://github.com/isaacs/github/issues/330&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Allowing CORS for the endpoint you mentioned would mean that you could complete this step of the Web flow from a browser:&lt;br /&gt;
And this would mean that you're hard-coding your client_id and client_secret into a webpage (or JS file loaded into that webpage) for everyone to see. This would indeed cause security concerns since the client_secret should be kept secret. If someone got hold of your client_id and client_secret, they could impersonate you application, and for example -- wipe all the tokens for that application:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果允许在浏览器通过 &lt;code&gt;client_id&lt;/code&gt;, &lt;code&gt;client_secret&lt;/code&gt; 交换得到 &lt;code&gt;access_token&lt;/code&gt;，那么实际上你的账号等于公开裸奔，你所有的 github 资产等于公开被人控制。所以必须走一个服务端流程，然后再把 &lt;code&gt;access_token&lt;/code&gt; 下发&lt;/p&gt;
&lt;p&gt;呃，好像很有道理。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">est</dc:creator><pubDate>Sat, 18 Jul 2026 19:32:00 +0800</pubDate><guid isPermaLink="false">tag:None,2026-07-18:/2026/stdout-29</guid><category>stdout</category></item><item><title>gitweets改版，复刻微信「朋友圈」</title><link>https://blog.est.im/2026/stdout-28</link><description>&lt;p&gt;去年搓了个 &lt;a href="https://blog.est.im/2025/stdout-05"&gt;gitweets&lt;/a&gt;，一个 .html 实现了「微博」，拿git历史当feed流～发推&lt;/p&gt;
&lt;p&gt;这个周末看着 coding plan 还剩 20% 要到期，没用完，怎么办呢？想来想去，挖大坑干不完，小修小改，就拿这个 gitweets 继续填坑了&lt;/p&gt;
&lt;p&gt;首先是让AI把界面改成模仿微信 朋友圈，啪一下，很快啊，结果让人非常印象深刻，很逼真&lt;/p&gt;
&lt;p&gt;&lt;a href="https://f.est.im/est"&gt;https://f.est.im/est&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="" src="/images/2026/stdout-28.01.avif" /&gt;&lt;/p&gt;
&lt;p&gt;现在的AI真厉害。让我去调CSS可能这辈子都搞不出来这个效果了。&lt;/p&gt;
&lt;p&gt;后面是我的一些唠叨，不感兴趣的可以关闭页面，或者去上面那个围观一下。&lt;/p&gt;
&lt;p&gt;想起来独乐乐不如众乐乐，要不，支持个评论功能？&lt;/p&gt;
&lt;p&gt;项目的初衷是 static page，要实现互动肯定得用一些API了。&lt;/p&gt;
&lt;p&gt;最能想到的思路，走传统的 github issue 什么的，和这个 gitweets 最大的出发点冲突了：一个 git repo 包含所有数据，随时搬家，不用导出。&lt;/p&gt;
&lt;p&gt;而且麻烦的是，post 是绑定到 commit 上的。如果你用一个 JSON 之类的来存评论，势必也会新增一个 commit，这样会污染post时间线。&lt;/p&gt;
&lt;p&gt;突然想起来一个古老的东西，&lt;a href="https://blog.est.im/2023/stdout-17"&gt;git notes&lt;/a&gt;，这是连 ChatGPT 和 Claude 都没想到的邪路，不过它们很快确认这个办法甚好，可行。&lt;/p&gt;
&lt;p&gt;git notes选型定下里，建立这个数据模型让我纠结了很久。围绕 github 开展流程，让我一度误入歧途&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;oauth 登录，不要任何scope&lt;/li&gt;
&lt;li&gt;用来存 github notes的repo邀请登录人加入项目&lt;/li&gt;
&lt;li&gt;浏览器通过该用户access token发起 notes append&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;最后想明白了，压根不应该走浏览器这一套。而是只能走后端代劳，用 Fine-Grained PAT 来和 github API 交互&lt;/p&gt;
&lt;p&gt;其间还考虑 github 越来越拉垮，想避免 vendor lock-in，直接走git http协议。&lt;/p&gt;
&lt;p&gt;首先想到的是 Cloudflare 那个牛逼的 &lt;a href="https://blog.cloudflare.com/artifacts-git-for-agents-beta/"&gt;zig 写的 100kb 的 wasm 可以 http 读写任意 git 仓库&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;git protocol engine is written in pure Zig (no libc), compiled to a ~100KB WASM binary. Support for both v1 and v2 of the git protocol. Support capabilities including ls-refs, shallow clones (deepen, deepen-since, deepen-relative), and incremental fetch with have/want negotiation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;仔细读了下文档，让AI一起调研，发现tmd这玩意仅限 Worker 内部使用，只能读写 CF 内部的 假 git，不支持读写外部任意 git http。&lt;/p&gt;
&lt;p&gt;用 &lt;a href="https://blog.est.im/2026/stdout-08"&gt;isomorphic-git 坑也挺多&lt;/a&gt; 。还是先走 github API 吧&lt;/p&gt;
&lt;p&gt;这个 git notes 要走REST API 有查询放大 3+N 的问题，怕掉用次数爆掉，于是让AI走 GraphQL。我自己手动是搓不动 GraphQL，太难了。AI虽然是 flash 普通智商版本，也分分钟拼接好。一次成功。真猛 😭&lt;/p&gt;
&lt;p&gt;于是 Vibe 出来了。&lt;/p&gt;
&lt;p&gt;搓完了想起一个问题，如果有人刷评论怎么办？于是让AI搓了个 &lt;code&gt;/.admin&lt;/code&gt; 管理页面。也是秒写好。太方便了。&lt;/p&gt;
&lt;p&gt;明显欠缺的功能搓完之后，感觉又进入了贤者时间，索然无味了。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">est</dc:creator><pubDate>Sun, 12 Jul 2026 17:53:00 +0800</pubDate><guid isPermaLink="false">tag:None,2026-07-12:/2026/stdout-28</guid><category>stdout</category></item><item><title>MiMoCode 干完活儿发通知</title><link>https://blog.est.im/2026/stdout-27</link><description>&lt;p&gt;AI在 coding 的时候我其实在玩别的。希望agent 每次干完活，macOS 弹个通知。&lt;/p&gt;
&lt;p&gt;手上是 MimoCode，就让它自己写个。啪，很快写好了。结果还是折腾了好一会儿， 记录几个有意思的小坑。&lt;/p&gt;
&lt;p&gt;首先是如果当前CLI是活动的，就不弹通知。&lt;/p&gt;
&lt;p&gt;需要判断活动窗口。最初用 &lt;code&gt;osascript&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;osascript -e 'tell application &amp;quot;System Events&amp;quot; to get name of first application process whose frontmost is true'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;直接报错 &lt;code&gt;Not authorized to send Apple events to System Events (-1743)&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;于是换 &lt;code&gt;lsappinfo&lt;/code&gt;，走 macOS Launch Services API，不需要任何额外授权：&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;lsappinfo info -only name $(lsappinfo front)
# → &amp;quot;LSDisplayName&amp;quot;=&amp;quot;Terminal&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;还能拿 PID：&lt;code&gt;lsappinfo info -only pid $(lsappinfo front)&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;然后如何判定活动窗口是不是 CLI？&lt;/p&gt;
&lt;p&gt;写死个&lt;code&gt;["iTerm2", "Terminal", "Alacritty", "kitty", ...]&lt;/code&gt; 列表&lt;/p&gt;
&lt;p&gt;太笨了。当前hook是子进程，直接遍历 parent 进程树啊！找到终端模拟器的 PID，再跟前台 app 的 PID 比对。&lt;/p&gt;
&lt;p&gt;但是在 tmux 里爬出来是这样的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;node → zsh → tmux → launchd(1) → init(0)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Terminal.app 的 PID 根本不在树上。因为 tmux server 启动后被 reparent 到了 launchd，跟 Terminal.app 断开了父子关系。&lt;/p&gt;
&lt;p&gt;又想到一个办法，直接查 &lt;code&gt;$TMUX_PANE&lt;/code&gt; 是否是当前 active pane：&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;tmux list-panes -F '#{pane_id} #{pane_active}' | awk '$2==1 {print $1}'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果 &lt;code&gt;$TMUX_PANE&lt;/code&gt; == active pane ID，说明用户就在看这个窗口，不需要通知。完全不需要知道前台是哪个 app。&lt;/p&gt;
&lt;p&gt;非 tmux 场景才用进程树 + &lt;code&gt;lsappinfo&lt;/code&gt; 的 PID 比对。&lt;/p&gt;
&lt;p&gt;然后就是挑选具体哪些事件要弹通知了。&lt;/p&gt;
&lt;p&gt;权限通知：&lt;code&gt;permission.ask&lt;/code&gt;，但文档说 "not yet wired"。试了一下，确实没触发。尴尬。雷军！！！金凡！！！&lt;/p&gt;
&lt;p&gt;最后的方案：注册 &lt;code&gt;permission.ask&lt;/code&gt; 占位，如果哪天接入了就能精确捕获。目前靠 &lt;code&gt;tool.execute.before&lt;/code&gt; 抢占并推断。工具跑完了说明权限已过或不需要。&lt;/p&gt;
&lt;p&gt;还有个情况就是 Subagent 完成也给我哐哐弹。最初硬编码了 &lt;code&gt;SUBAGENT_TYPES = ["general", "explore"]&lt;/code&gt;；后来发现 &lt;code&gt;actor.preStop&lt;/code&gt; / &lt;code&gt;actor.postStop&lt;/code&gt; 的 input 里有 &lt;code&gt;mode: "subagent" | "peer"&lt;/code&gt;。于是就做了个计数器&lt;/p&gt;
&lt;p&gt;最后通知到时候带上 Session 名字，折腾了一圈 直接 &lt;code&gt;sqlite3 ~/.local/share/mimocode/mimocode.db "SELECT title FROM session WHERE id = '$SESSION_ID'"&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;完整代码放在 &lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/est/snippets/blob/master/mimocode-hooks/notify-done.ts"&gt;https://github.com/est/snippets/blob/master/mimocode-hooks/notify-done.ts&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;复制到 &lt;code&gt;~/.config/mimocode/hooks/&lt;/code&gt; 就可以试试效果&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">est</dc:creator><pubDate>Sat, 11 Jul 2026 11:53:00 +0800</pubDate><guid isPermaLink="false">tag:None,2026-07-11:/2026/stdout-27</guid><category>stdout</category></item><item><title>写作能力和 locate cost</title><link>https://blog.est.im/2026/stderr-24</link><description>&lt;p&gt;自从自个儿琢磨出 &lt;a href="https://blog.est.im/2026/stdin-17"&gt;locate cost&lt;/a&gt; 之后便开始关注这方面问题。最近看到两篇喷 harness 问题的&lt;/p&gt;
&lt;p&gt;第一个是 Can Bölük &lt;a href="https://blog.can.ac/2026/02/12/the-harness-problem/"&gt;https://blog.can.ac/2026/02/12/the-harness-problem/&lt;/a&gt; 今年2月的时候发现：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Codex uses &lt;code&gt;apply_patch&lt;/code&gt;: It takes a string as input, which is essentially an OpenAI-flavored diff, and instead of relying on a structured schema, the harness just expects this blob to follow a strict set of rules&lt;br /&gt;
Claude Code (and most others) use &lt;code&gt;str_replace&lt;/code&gt;: find the exact old text, swap in the new text. Very simple to think about. But the model must reproduce every character perfectly, including whitespace and indentation.&lt;br /&gt;
Cursor trained a separate neural network: a fine-tuned 70B model whose entire job is to take a draft edit and merge it into the file correctly&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果你在 Codex 用别的模型&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Grok 4’s patch failure rate in my benchmark was 50.7%, GLM-4.7’s was 46.2%.&lt;/p&gt;
&lt;p&gt;Aider’s &lt;a href="https://aider.chat/docs/benchmarks.html"&gt;own benchmarks&lt;/a&gt; show that format choice alone swung GPT-4 Turbo from 26% to 59%, but GPT-3.5 scored only 19% with the same format because it couldn’t reliably produce valid diffs. &lt;/p&gt;
&lt;p&gt;The &lt;a href="https://arxiv.org/abs/2510.12487"&gt;Diff-XYZ benchmark&lt;/a&gt; from JetBrains confirmed it systematically: no single edit format dominates across models and use cases. &lt;a href="https://arxiv.org/abs/2511.04486"&gt;EDIT-Bench&lt;/a&gt; found that only one model achieves over 60% pass@1 on realistic editing tasks.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;懒得看原文的我直接说结论：大家都在争论哪个模型编程更强，但很多模型都知道要改什么，失败其实发生在具体改哪里。&lt;/p&gt;
&lt;p&gt;他做了个实验，同样的 16 个模型，只换编辑这个 tool call，改成他自己发明的 hashline，给每行内容打一个短哈希做锚点，Grok Code Fast 1 从 6.7% 直接跳到 68.3%。&lt;/p&gt;
&lt;p&gt;Can Bölük 这个老哥非常生猛，2021年有篇博客讲他在Intel CPU 发现一个指令可以序列化/反序列化打印所有 x86 指令集。微码立功了！&lt;/p&gt;
&lt;p&gt;他这个 hashline 也很巧思，我也是最近才琢磨明白。你仔细想就会有个疑问，为啥不直接用 行号？&lt;/p&gt;
&lt;p&gt;有个相关的问题一直困扰我。我经常让 Gemini 去搜我博客，我博客网址都是类似 stderr-XX 其中 XX 是数字，然后 Gemini 经常把别的文章内容给我总结批判一番。我得到的结论是 LLM 不识数。&lt;/p&gt;
&lt;p&gt;后来在学 RAG embedding vs BM25 的时候突然顿悟了，tmd 这个基于 基于语义空间的相似度匹配 有利有弊。好处是比如你检索 汽车，它能联想到 车辆，无需 FTS 那里你自己要维护一套分词近义词表。坏处是行号 223 233 它觉得很「近似」直接搞混 😂&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;扯远了。&lt;/p&gt;
&lt;p&gt;然后是前几天 Armin Ronacher 的 &lt;a href="https://lucumr.pocoo.org/2026/7/4/better-models-worse-tools/"&gt;https://lucumr.pocoo.org/2026/7/4/better-models-worse-tools/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这老哥是 Flask/Werkzeug/Jinja2作者，现在主要在撸 Pi 这个agent（值得一题的是上面的老哥在撸 oh-my-pi 这个 fork）&lt;/p&gt;
&lt;p&gt;他发现 Opus 4.8 和 Sonnet 5 在非 Claude Code 的 harness（比如他自己的 Pi 项目）里调用嵌套 &lt;code&gt;edits[]&lt;/code&gt; 数组时会莫名其妙地塞进一堆乱七八糟的 &lt;code&gt;&amp;lt;antml:function_calls&amp;gt;&lt;/code&gt; 这种内部控制字符。老的模型反而没这个毛病。他推测是 A\ 家训新模型强耦合了 Claude Code。逆向发现 Claude Code 客户端对格式错误极其宽容，有一整套别名映射、Unicode 修复、静默过滤多余字段的逻辑。结果就是模型在RL中适应了格式差不多就行，反正harness 会兜底。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;看完这两篇我觉得印证了我前面 locate cost 一问的所有猜想。AI 指出，真正可能的机制更朴素：&lt;/p&gt;
&lt;p&gt;RL 训练信号里，整段重写 往往比 精确定位再小改 更容易拿到奖励。重写不会因为空白符不匹配而报错。这跟第二篇里 Armin 讲的模型在宽容的 harness 里学会了偷懒，是同一个因果链条,不需要引入纹理/结构的形而上区分也能解释。&lt;/p&gt;
&lt;p&gt;也就是说，LLM上课答题只给答案分，不给过程分，导致背题偷懒 🤣 这个方向在研究界是有名字的，叫 process supervision / process reward model，过程奖励模型。OpenAI 那篇《Let's Verify Step by Step》基本就是在数学推理场景做这件事。&lt;/p&gt;
&lt;p&gt;但这条路有两个真实的代价，其一是 过程标注比结果标注贵得多；其二 如果训练时的 harness 比部署时的 harness 更宽容,学出来的好过程标准本身就是错的。&lt;/p&gt;
&lt;p&gt;所以又回到一个老生常谈的话题。各大模型厂家都在推出自己的 CLI。观察「过程」比最终结果更值钱！&lt;/p&gt;
&lt;p&gt;我让AI去 fact check了下。果然&lt;/p&gt;
&lt;h4&gt;Claude Code&lt;/h4&gt;
&lt;p&gt;数据使用文档里明确写着两条完全独立的通道:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;consumer 账号里"Help improve Claude"那个 toggle 控制的是"conversation content"——如果你打开它,用于训练的数据 包括整个相关对话,连带任何内容、自定义样式或对话偏好。这是"代码/对话内容"这条线。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DISABLE_TELEMETRY&lt;/code&gt; 一条完全独立的遥测通道，文档原话是:Claude Code 会从用户的机器连接到 Anthropic，记录延迟、可靠性、使用模式这类运营指标。这类日志不包含任何代码或文件路径。关掉这条通道要单独操作，跟训练开关是两个开关、两套机制、两份文档。 &lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;Kiro(AWS)&lt;/h4&gt;
&lt;p&gt;设置页面里直接摆着两个并列开关&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Content Collection For Service Improvement，关掉它就是不许训练&lt;/li&gt;
&lt;li&gt;Usage Analytics And Performance Metrics 官方描述是"这是一个单独的、用于使用遥测的设置"。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;也就是说厂商自己都承认这是两套独立治理的东西——只是大多数用户可能只会想起关第一个开关。&lt;/p&gt;
&lt;h4&gt;Codex(OpenAI)&lt;/h4&gt;
&lt;p&gt;官方文档列出了它 OTel 遥测会上报的事件类型，其中包括&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;codex.tool_decision&lt;/code&gt; 工具调用是被批准还是拒绝,以及这个决定来自配置还是用户&lt;/li&gt;
&lt;li&gt;&lt;code&gt;codex.tool_result&lt;/code&gt; 耗时、是否成功、外加一段输出片段&lt;/li&gt;
&lt;li&gt;&lt;code&gt;codex.user_prompt&lt;/code&gt; 默认只记录长度、内容会被打码&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;听起来很克制,但 工具决策 + 输出片段 + 时长 这几项拼起来 就是前面说那种 过程信号，不是代码本身。精确刻画了模型在 harness 里怎么试错、被拒了多少次、跑了多久。这条 OTel 通道是靠单独的 &lt;code&gt;config.toml&lt;/code&gt; 开关控制的，跟 ChatGPT 账号层面的训练数据开关是两件事。&lt;/p&gt;
&lt;h4&gt;Google Antigravity&lt;/h4&gt;
&lt;p&gt;方向比较模糊，它把训练相关的退出开关本身命名为 Enable Telemetry，把两件事的名字焊在一起。&lt;/p&gt;
&lt;p&gt;Google Groups 的讨论帖里用户在问这个开关到底关不关得掉训练,官方也没给出干脆的回答。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;所以接下去的推论就很简单。利用公开语料能训练出 2025年级别的sota llm。但是往后就看各家谁能拿到更多的轨迹数据了。无论靠CLI / app 装机量，还是买数据，偷数据，各显神通。其中装机量/DAU几乎正比于以后的智力天花板。所谓的 trillion tokens models 估计就是从各种日志里来的（而不是人类语料）&lt;/p&gt;
&lt;p&gt;继续推演下去，有意思的一点是，可预见的将来，AI 的智力增长几乎全来自于coding&lt;/p&gt;
&lt;p&gt;因为 coding 有个编译器师爷能把关，保证产出可验证！&lt;/p&gt;
&lt;p&gt;别的什么 具身 世界模型，我觉得难了 😆&lt;/p&gt;
&lt;p&gt;还有一个考虑的，装机量看 2C，各行业应用 2B 也很重要。比如design类的。这种“轨迹” 如何收集改进也很讲究。&lt;/p&gt;
&lt;p&gt;但是design想了下又挺主观的。不过可以降低一些看上去很笨的地方。&lt;/p&gt;
&lt;p&gt;甚至如果从公平的角度来说，AI厂家，除了按成本收费之外，还应该给高价值数据返钱才对。不是之前有报道说Anthropic 和 OpenAI 都签了七位数金额的 RL 环境和人类专家数据合同，预计投入还要再涨 3-5 倍。就是拿来训练“过程”的吧。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;今晚娃又沉迷pad，我给他pad锁了 😆  &lt;/p&gt;
&lt;p&gt;为啥说起这个呢，我一直让娃坚持写「&lt;a href="https://blog.est.im/202105/stderr-004"&gt;语音日记&lt;/a&gt;」&lt;/p&gt;
&lt;p&gt;但是孩子长大了，他写得越来越不耐烦了，而且我苦恼作文没有批改，所以这个日记习惯实际上成了低水平重复。&lt;/p&gt;
&lt;p&gt;其实把复制粘贴到deepseek，提示词 “以XX年级的标准点评改进下这篇” 就能搞定，奈何我家娃太懒。&lt;/p&gt;
&lt;p&gt;所以我一直想给娃弄一个 作文训练 app。本来想不就是AI一问一答批改么。&lt;/p&gt;
&lt;p&gt;但是想到 locate cost 突然觉得有点难。。。。。甚至比AI coding 还难。。&lt;/p&gt;
&lt;p&gt;代码为什么定位相对容易。 哪怕 &lt;code&gt;str_replace&lt;/code&gt; 因为空白符不匹配而报错,它要定位的目标本身是离散、有边界的——一行代码、一个函数,有语法(AST)天然把文档切成可寻址的单元。&lt;/p&gt;
&lt;p&gt;或者 hashline，行号就每句话一个稳定锚点，把找位置从模糊的文本匹配变成精确的 ID 查找。这招完全可以照搬到「改病句」场景。做个 diff 也容易&lt;/p&gt;
&lt;p&gt;但写作的问题，往往根本不是一个可以圈起来的line或者span，而是句子之间关系的性质。 “这段论证缺乏内在逻辑”，“这句话和上一句衔接生硬”，“全文的语气从第二段开始飘了”——这些反馈即便你精确指出“第3段第2句”,真正需要改的可能是第1句、连接词，或者整段重组。&lt;/p&gt;
&lt;p&gt;代码的 bug 通常局限在一个可编辑单元里，作文的"bug"经常是分布式的、关系性的。定位到具体文字之后，改哪、怎么改这一步反而更模糊，比代码多绕一层&lt;/p&gt;
&lt;p&gt;AI说，写作其实分两个层次&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;可验证层  &lt;br /&gt;
语法错误、拼写、用词重复、被动语态滥用、句长方差、可读性指标（类似 Flesch-Kincaid 这类公式）、有没有明确主题句 &lt;br /&gt;
这些跟代码的 compiler/linter 是同一类东西,规则可判定&lt;/li&gt;
&lt;li&gt;不可验证层  &lt;br /&gt;
论证有没有说服力、有没有原创视角、语气是否统一、是否“有意思”？  &lt;br /&gt;
可以叫“品味”层。只有经验丰富的人的判断。而且专业阅卷老师之间对开放式作文打分的一致性本身就不高&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;怎么切入呢？&lt;/p&gt;
&lt;p&gt;后者也有一些实践，比如借鉴 AP 阅卷没，用锚定范文（anchor papers）做少样本参照。而不是让模型凭空判断“这篇好不好”&lt;/p&gt;
&lt;p&gt;也可以做高亮 + 提问式 而非直接改。比如第 2 段第 3 句话里，“非常开心”这个词能不能换一个更具体的？比如描述一下你当时的表情或动作？&lt;/p&gt;
&lt;p&gt;甚至可以 示例驱动：AI 给出 改前 / 改后 小对比，只改 1-2 处；然后 多轮对话，孩子自己决定要改哪里，AI 只辅助，而不是 AI 主导大改。&lt;/p&gt;
&lt;p&gt;要么就局部训练，针对常见作文类型（记事、写景、议论），开头、过渡、结尾分别训练&lt;/p&gt;
&lt;p&gt;这样看来，写作文直接给娃一张无限大的白纸并不好。参考 Notion 的 Block 概念，强迫孩子在输入时就把“骨架”和“血肉”分开。比如，第一步只允许输入 3 个论点（形式）；第二步再针对每个论点去填充素材（质料）。通过产品机制，人为制造出“伪 AST（语法树）”。&lt;/p&gt;
&lt;p&gt;或者阻断直接生成，只给“反向约束”。不输出完整的句子让孩子抄，扮演“刁钻的苏格拉底”。比如，当孩子写“今天我很开心”，AI 的反馈不应该是“你可以改成：今天我心花怒放”，而应该是抛出环境约束（Harness）：“你当时手里拿了什么东西？你的心跳有多快？”——逼迫孩子自己去完成“从潜能到现实”的推导。&lt;/p&gt;
&lt;p&gt;当然，做好 diff 和版本控制是基础。记录孩子打磨一句话的过程。让孩子直观看到词汇的微调是如何让语义的边界越来越清晰的。&lt;/p&gt;
&lt;p&gt;哎，这么一拆解又有点思路了，但比预计的感觉麻烦得多啊。不过语文教育有大问题啊。明明是工程上可以细化训练的（虽然很难，过去没AI需要大量人工精力）。上课根本不讲。全靠孩子天生悟性。以上种种，今年4月才喷过一篇《&lt;a href="https://blog.est.im/2026/stdin-10"&gt;语文学习和考试&lt;/a&gt;》 &lt;/p&gt;
&lt;p&gt;作文从小学一上来就300 字 500字，其实真应该「刻意练习」的是语言 primitive。什么 铺垫、呼应、留白、对比、节奏、悬念、感官、动作、心理、对话等等，都上手了，然后再各种变化，组合。&lt;/p&gt;
&lt;p&gt;学编程也是从少量 keywords ，赋值语句，条件，循环这样一步一步来的嘛。&lt;/p&gt;
&lt;p&gt;过去没太好的语文教学条件，归根结底因为一个班上50个娃只有一个语文老师。&lt;/p&gt;
&lt;p&gt;但是现在有LLM了。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">est</dc:creator><pubDate>Thu, 09 Jul 2026 23:01:00 +0800</pubDate><guid isPermaLink="false">tag:None,2026-07-09:/2026/stderr-24</guid><category>stderr</category></item><item><title>grep vs sqlite 谁更适合微信聊天记录？</title><link>https://blog.est.im/2026/stdout-26</link><description>&lt;p&gt;一个爆火的讨论&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;云风 @cloudwu &lt;a href="https://xcancel.com/cloudwu/status/2071533904977428611"&gt;2026-06-29&lt;/a&gt;&lt;br /&gt;
微信的开发人员根本就不懂该怎么储存数据。这种聊天软件，文本和媒体文件分开存，文本根本就不应该保存在什么数据库(sqlite)里, 一个对话一个文本文件追加就可以了。需要搜索的时候 grep 一下性能完全符合需求。一个对话能有多少文本？一秒一个字 24 小时不间断，一年也就 30M 个字。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;网上的争论都是猜测，我呢，决定让 opus 跑一局。&lt;/p&gt;
&lt;p&gt;首先让AI去搜微信聊录表结构&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;微信（Android）聊天记录存储在加密 SQLite 数据库 &lt;code&gt;EnMicroMsg.db&lt;/code&gt; 中，使用 SQLCipher（AES-256-CBC，PBKDF2 256000 轮派生密钥）。核心 &lt;code&gt;message&lt;/code&gt; 表：&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class="language-sql"&gt;CREATE TABLE message (
    msgId      INTEGER PRIMARY KEY,  -- 本地自增 ID
    msgSvrId   INTEGER,              -- 服务器消息 ID
    type       INTEGER,              -- 1=文字, 3=图片, 34=语音, 43=视频
    isSend     INTEGER,              -- 0=接收, 1=发送
    createTime INTEGER,              -- Unix 时间戳
    talker     TEXT,                 -- wxid 或群 chatroom ID
    content    TEXT,                 -- 消息正文
    imgPath    TEXT                  -- 附件路径
);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;测试设计&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;数据量&lt;/strong&gt;：50 万条模拟消息（模拟中度用户 ~2 年）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;搜索关键词&lt;/strong&gt;：&lt;code&gt;微信支付&lt;/code&gt;、&lt;code&gt;服务器&lt;/code&gt;、&lt;code&gt;数据库&lt;/code&gt;、&lt;code&gt;会议&lt;/code&gt;、&lt;code&gt;周末&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;环境&lt;/strong&gt;：macOS Apple Silicon, Python 3.14, ripgrep 15.1, DuckDB 1.5.4, Polars 1.42&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;每项测试 3 轮取最小值&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;参赛选手&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;分类&lt;/th&gt;
&lt;th&gt;方案&lt;/th&gt;
&lt;th&gt;思路&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;传统文本&lt;/td&gt;
&lt;td&gt;grep (BSD)&lt;/td&gt;
&lt;td&gt;最朴素的逐字节匹配&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SIMD文本&lt;/td&gt;
&lt;td&gt;ripgrep&lt;/td&gt;
&lt;td&gt;AVX2/NEON 并行 + 多线程&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;零拷贝&lt;/td&gt;
&lt;td&gt;mmap 直接搜索&lt;/td&gt;
&lt;td&gt;OS page cache + Python bytes.find&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;压缩文本&lt;/td&gt;
&lt;td&gt;zstd 流式解压搜索&lt;/td&gt;
&lt;td&gt;省空间，边解压边搜&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;索引&lt;/td&gt;
&lt;td&gt;倒排索引 (2-gram)&lt;/td&gt;
&lt;td&gt;搜索引擎思路，内存索引&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;索引&lt;/td&gt;
&lt;td&gt;Bloom Filter 分块&lt;/td&gt;
&lt;td&gt;概率型预过滤&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RDBMS&lt;/td&gt;
&lt;td&gt;SQLite LIKE&lt;/td&gt;
&lt;td&gt;微信的实际方案(去掉加密)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RDBMS&lt;/td&gt;
&lt;td&gt;SQLite mmap 模式&lt;/td&gt;
&lt;td&gt;mmap I/O 加速&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RDBMS FTS&lt;/td&gt;
&lt;td&gt;SQLite FTS5 (trigram)&lt;/td&gt;
&lt;td&gt;全文搜索引擎&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;列式DB&lt;/td&gt;
&lt;td&gt;DuckDB contains()&lt;/td&gt;
&lt;td&gt;OLAP 列式扫描&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;列式DB&lt;/td&gt;
&lt;td&gt;DuckDB FTS&lt;/td&gt;
&lt;td&gt;DuckDB 的全文搜索扩展&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;列式文件&lt;/td&gt;
&lt;td&gt;Parquet(zstd) + DuckDB&lt;/td&gt;
&lt;td&gt;列式文件直接查询&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DataFrame&lt;/td&gt;
&lt;td&gt;Polars lazy scan&lt;/td&gt;
&lt;td&gt;Rust实现的极速 DataFrame&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DataFrame&lt;/td&gt;
&lt;td&gt;Polars in-memory&lt;/td&gt;
&lt;td&gt;全量载入内存&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;并行文本&lt;/td&gt;
&lt;td&gt;ripgrep 多文件并行&lt;/td&gt;
&lt;td&gt;分块文件 + rg 多线程&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;测试结果&lt;/h3&gt;
&lt;h4&gt;关键词搜索延迟（ms, 3轮最小值）&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;方案&lt;/th&gt;
&lt;th style="text-align: right;"&gt;微信支付&lt;/th&gt;
&lt;th style="text-align: right;"&gt;服务器&lt;/th&gt;
&lt;th style="text-align: right;"&gt;数据库&lt;/th&gt;
&lt;th style="text-align: right;"&gt;会议&lt;/th&gt;
&lt;th style="text-align: right;"&gt;周末&lt;/th&gt;
&lt;th style="text-align: right;"&gt;&lt;strong&gt;平均&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;SQLite FTS5 (trigram)&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: right;"&gt;0.65&lt;/td&gt;
&lt;td style="text-align: right;"&gt;0.46&lt;/td&gt;
&lt;td style="text-align: right;"&gt;0.37&lt;/td&gt;
&lt;td style="text-align: right;"&gt;❌²&lt;/td&gt;
&lt;td style="text-align: right;"&gt;❌²&lt;/td&gt;
&lt;td style="text-align: right;"&gt;&lt;strong&gt;0.31&lt;/strong&gt;¹&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Polars lazy scan&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: right;"&gt;3.51&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2.56&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2.43&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2.49&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2.47&lt;/td&gt;
&lt;td style="text-align: right;"&gt;&lt;strong&gt;2.69&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;倒排索引 (2-gram)&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2.71&lt;/td&gt;
&lt;td style="text-align: right;"&gt;3.26&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2.78&lt;/td&gt;
&lt;td style="text-align: right;"&gt;3.24&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2.37&lt;/td&gt;
&lt;td style="text-align: right;"&gt;&lt;strong&gt;2.87&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Polars in-memory&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2.67&lt;/td&gt;
&lt;td style="text-align: right;"&gt;3.61&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2.98&lt;/td&gt;
&lt;td style="text-align: right;"&gt;3.21&lt;/td&gt;
&lt;td style="text-align: right;"&gt;3.21&lt;/td&gt;
&lt;td style="text-align: right;"&gt;&lt;strong&gt;3.13&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;DuckDB contains()&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: right;"&gt;3.72&lt;/td&gt;
&lt;td style="text-align: right;"&gt;3.23&lt;/td&gt;
&lt;td style="text-align: right;"&gt;3.18&lt;/td&gt;
&lt;td style="text-align: right;"&gt;3.91&lt;/td&gt;
&lt;td style="text-align: right;"&gt;4.41&lt;/td&gt;
&lt;td style="text-align: right;"&gt;&lt;strong&gt;3.69&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Parquet + DuckDB&lt;/td&gt;
&lt;td style="text-align: right;"&gt;4.63&lt;/td&gt;
&lt;td style="text-align: right;"&gt;4.37&lt;/td&gt;
&lt;td style="text-align: right;"&gt;4.55&lt;/td&gt;
&lt;td style="text-align: right;"&gt;4.88&lt;/td&gt;
&lt;td style="text-align: right;"&gt;4.84&lt;/td&gt;
&lt;td style="text-align: right;"&gt;&lt;strong&gt;4.65&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;ripgrep 多文件并行&lt;/td&gt;
&lt;td style="text-align: right;"&gt;10.65&lt;/td&gt;
&lt;td style="text-align: right;"&gt;10.26&lt;/td&gt;
&lt;td style="text-align: right;"&gt;9.48&lt;/td&gt;
&lt;td style="text-align: right;"&gt;10.32&lt;/td&gt;
&lt;td style="text-align: right;"&gt;9.05&lt;/td&gt;
&lt;td style="text-align: right;"&gt;&lt;strong&gt;9.95&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;DuckDB FTS (BM25)&lt;/td&gt;
&lt;td style="text-align: right;"&gt;12.53&lt;/td&gt;
&lt;td style="text-align: right;"&gt;11.77&lt;/td&gt;
&lt;td style="text-align: right;"&gt;12.85&lt;/td&gt;
&lt;td style="text-align: right;"&gt;11.82&lt;/td&gt;
&lt;td style="text-align: right;"&gt;12.78&lt;/td&gt;
&lt;td style="text-align: right;"&gt;&lt;strong&gt;12.35&lt;/strong&gt;³&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;ripgrep (SIMD, 单文件)&lt;/td&gt;
&lt;td style="text-align: right;"&gt;13.24&lt;/td&gt;
&lt;td style="text-align: right;"&gt;13.77&lt;/td&gt;
&lt;td style="text-align: right;"&gt;13.40&lt;/td&gt;
&lt;td style="text-align: right;"&gt;14.14&lt;/td&gt;
&lt;td style="text-align: right;"&gt;13.10&lt;/td&gt;
&lt;td style="text-align: right;"&gt;&lt;strong&gt;13.53&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;mmap 直接搜索&lt;/td&gt;
&lt;td style="text-align: right;"&gt;17.00&lt;/td&gt;
&lt;td style="text-align: right;"&gt;22.62&lt;/td&gt;
&lt;td style="text-align: right;"&gt;22.86&lt;/td&gt;
&lt;td style="text-align: right;"&gt;31.36&lt;/td&gt;
&lt;td style="text-align: right;"&gt;30.52&lt;/td&gt;
&lt;td style="text-align: right;"&gt;&lt;strong&gt;24.87&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;Bloom Filter + 扫描&lt;/td&gt;
&lt;td style="text-align: right;"&gt;25.34&lt;/td&gt;
&lt;td style="text-align: right;"&gt;25.25&lt;/td&gt;
&lt;td style="text-align: right;"&gt;25.06&lt;/td&gt;
&lt;td style="text-align: right;"&gt;26.68&lt;/td&gt;
&lt;td style="text-align: right;"&gt;27.01&lt;/td&gt;
&lt;td style="text-align: right;"&gt;&lt;strong&gt;25.87&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;SQLite mmap LIKE&lt;/td&gt;
&lt;td style="text-align: right;"&gt;37.45&lt;/td&gt;
&lt;td style="text-align: right;"&gt;37.45&lt;/td&gt;
&lt;td style="text-align: right;"&gt;37.92&lt;/td&gt;
&lt;td style="text-align: right;"&gt;37.83&lt;/td&gt;
&lt;td style="text-align: right;"&gt;37.81&lt;/td&gt;
&lt;td style="text-align: right;"&gt;&lt;strong&gt;37.69&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;SQLite LIKE&lt;/td&gt;
&lt;td style="text-align: right;"&gt;43.13&lt;/td&gt;
&lt;td style="text-align: right;"&gt;41.40&lt;/td&gt;
&lt;td style="text-align: right;"&gt;41.50&lt;/td&gt;
&lt;td style="text-align: right;"&gt;41.51&lt;/td&gt;
&lt;td style="text-align: right;"&gt;41.46&lt;/td&gt;
&lt;td style="text-align: right;"&gt;&lt;strong&gt;41.80&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;grep (BSD)&lt;/td&gt;
&lt;td style="text-align: right;"&gt;139.10&lt;/td&gt;
&lt;td style="text-align: right;"&gt;136.86&lt;/td&gt;
&lt;td style="text-align: right;"&gt;141.42&lt;/td&gt;
&lt;td style="text-align: right;"&gt;122.54&lt;/td&gt;
&lt;td style="text-align: right;"&gt;124.16&lt;/td&gt;
&lt;td style="text-align: right;"&gt;&lt;strong&gt;132.82&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;zstd 流式解压搜索&lt;/td&gt;
&lt;td style="text-align: right;"&gt;161.32&lt;/td&gt;
&lt;td style="text-align: right;"&gt;164.22&lt;/td&gt;
&lt;td style="text-align: right;"&gt;164.56&lt;/td&gt;
&lt;td style="text-align: right;"&gt;170.23&lt;/td&gt;
&lt;td style="text-align: right;"&gt;170.73&lt;/td&gt;
&lt;td style="text-align: right;"&gt;&lt;strong&gt;166.21&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;¹ FTS5 只对 ≥3字符 的关键词有效，取3个有效关键词平均&lt;br /&gt;
² trigram tokenizer 无法匹配 2 字符的中文词&lt;br /&gt;
³ DuckDB FTS 默认 tokenizer 不支持中文，返回 0 结果（延迟仍可参考）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;视觉化排名&lt;/h4&gt;
&lt;p&gt;&lt;small&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; 1.                                                            █   0.31ms SQLite FTS5
 2.                                                            █   2.69ms Polars lazy
 3.                                                            █   2.87ms 倒排索引
 4.                                                            █   3.13ms Polars in-mem
 5.                                                            █   3.69ms DuckDB contains
 6.                                                           ██   4.65ms Parquet+DuckDB
 7.                                                         ████   9.95ms rg多文件并行
 8.                                                       ██████  12.35ms DuckDB FTS
 9.                                                       ██████  13.53ms ripgrep (SIMD
10.                                                 ████████████  24.87ms mmap 直接搜索
11.                                                 ████████████  25.87ms Bloom+扫描
12.                                           ██████████████████  37.69ms SQLite mmap LIKE
13.                                         ████████████████████  41.80ms SQLite LIKE
14. ████████████████████████████████████████████████████████████ 132.82ms grep (BSD
15. ████████████████████████████████████████████████████████████ 166.21ms zstd流式解压
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;/small&gt;&lt;/p&gt;
&lt;h4&gt;复合条件查询（指定用户 + 时间范围 + 关键词"会议"）&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;方案&lt;/th&gt;
&lt;th style="text-align: right;"&gt;延迟 (ms)&lt;/th&gt;
&lt;th style="text-align: right;"&gt;倍率(vs grep)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SQLite indexed&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: right;"&gt;&lt;strong&gt;2.80&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: right;"&gt;76x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DuckDB&lt;/td&gt;
&lt;td style="text-align: right;"&gt;4.57&lt;/td&gt;
&lt;td style="text-align: right;"&gt;47x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Polars in-memory&lt;/td&gt;
&lt;td style="text-align: right;"&gt;7.02&lt;/td&gt;
&lt;td style="text-align: right;"&gt;30x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ripgrep pipe&lt;/td&gt;
&lt;td style="text-align: right;"&gt;20.47&lt;/td&gt;
&lt;td style="text-align: right;"&gt;10x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;grep pipe&lt;/td&gt;
&lt;td style="text-align: right;"&gt;213.90&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1x&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;存储大小&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;格式&lt;/th&gt;
&lt;th style="text-align: right;"&gt;大小&lt;/th&gt;
&lt;th style="text-align: right;"&gt;vs TSV&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Parquet (zstd)&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: right;"&gt;&lt;strong&gt;8.3 MB&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: right;"&gt;0.18x&lt;/td&gt;
&lt;td&gt;列式 + 字典编码 + 压缩&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;zstd 压缩 TSV&lt;/td&gt;
&lt;td style="text-align: right;"&gt;12.7 MB&lt;/td&gt;
&lt;td style="text-align: right;"&gt;0.27x&lt;/td&gt;
&lt;td&gt;纯压缩&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DuckDB + FTS&lt;/td&gt;
&lt;td style="text-align: right;"&gt;26.0 MB&lt;/td&gt;
&lt;td style="text-align: right;"&gt;0.55x&lt;/td&gt;
&lt;td&gt;含全文索引&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TSV 纯文本&lt;/td&gt;
&lt;td style="text-align: right;"&gt;47.0 MB&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1.00x&lt;/td&gt;
&lt;td&gt;基线&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SQLite&lt;/td&gt;
&lt;td style="text-align: right;"&gt;69.2 MB&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1.47x&lt;/td&gt;
&lt;td&gt;B-tree 开销&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SQLite + FTS5&lt;/td&gt;
&lt;td style="text-align: right;"&gt;116.8 MB&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2.49x&lt;/td&gt;
&lt;td&gt;trigram 索引翻倍&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;各方案深度分析&lt;/h3&gt;
&lt;h4&gt;Tier 1: 亚毫秒级（&amp;lt; 1ms）&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;SQLite FTS5 (trigram)&lt;/strong&gt;&lt;br /&gt;
- 原理：对 content 字段的每个 3 字符子串建倒排索引&lt;br /&gt;
- 优点：查询极快（0.3-0.6ms），无需额外依赖&lt;br /&gt;
- 缺点：&lt;strong&gt;索引体积翻倍&lt;/strong&gt;（+68MB）；trigram 无法匹配 ≤2 字符的关键词&lt;br /&gt;
- 适用：搜索词通常 ≥3 字符的场景&lt;/p&gt;
&lt;h4&gt;Tier 2: 低毫秒级（2-5ms）&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Polars (lazy/in-memory)&lt;/strong&gt;&lt;br /&gt;
- 原理：Rust 实现的 DataFrame 引擎，列式内存布局 + SIMD 字符串匹配&lt;br /&gt;
- 优点：&lt;strong&gt;Parquet 文件仅 8.3MB&lt;/strong&gt;（最小！），查询 2-3ms，复合查询也快（7ms）&lt;br /&gt;
- 缺点：需要加载到内存；Python 库依赖&lt;br /&gt;
- 杀手锏：&lt;strong&gt;8MB 的 Parquet 文件 + 3ms 搜索延迟，这是存储效率和速度的最佳平衡点&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;倒排索引 (2-gram, 内存)&lt;/strong&gt;&lt;br /&gt;
- 原理：搜索引擎最经典的思路，对所有 2-gram 建 posting list&lt;br /&gt;
- 优点：构建仅 0.78s，查询 2.9ms，&lt;strong&gt;支持任意长度关键词&lt;/strong&gt;&lt;br /&gt;
- 缺点：纯内存（需要序列化/加载），索引构建需要全量遍历&lt;br /&gt;
- 适用：append-only 数据可以增量更新索引&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DuckDB contains()&lt;/strong&gt;&lt;br /&gt;
- 原理：列式存储，content 列连续存放，CPU cache 友好 + SIMD 扫描&lt;br /&gt;
- 优点：无需专门索引即可 3.7ms；复合查询也仅 4.6ms；&lt;strong&gt;文件仅 26MB&lt;/strong&gt;&lt;br /&gt;
- 缺点：需要 DuckDB 运行时&lt;br /&gt;
- 杀手锏：&lt;strong&gt;不建任何索引，纯靠列式布局就比 SQLite LIKE 快 11 倍&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Parquet 文件 + DuckDB 零拷贝查询&lt;/strong&gt;&lt;br /&gt;
- 原理：Parquet 本身就是列式格式，DuckDB 可以直接查询不需导入&lt;br /&gt;
- 优点：文件仅 8.3MB，不需要数据库进程，查询 4.6ms&lt;br /&gt;
- 缺点：每次查询需要启动 DuckDB 连接&lt;br /&gt;
- 杀手锏：&lt;strong&gt;一个 8MB 的文件就是完整的"数据库"，任何语言都能读&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;Tier 3: 10ms 级&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;ripgrep 多文件并行&lt;/strong&gt;&lt;br /&gt;
- 原理：把消息分块成多个文件，ripgrep 的 work-stealing 线程池并行搜索&lt;br /&gt;
- 优点：比单文件 ripgrep 快 ~35%（10ms vs 13.5ms）&lt;br /&gt;
- 缺点：文件管理复杂&lt;br /&gt;
- 适用：数据天然按时间分文件存储的场景&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ripgrep (SIMD, 单文件)&lt;/strong&gt;&lt;br /&gt;
- 原理：AVX2/NEON 每周期处理 16-32 字节，多线程（对单文件仍用单线程）&lt;br /&gt;
- 优点：零配置，即装即用&lt;br /&gt;
- 缺点：对单文件只能单线程&lt;/p&gt;
&lt;h4&gt;Tier 4: 失败/不推荐的"邪路"&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Bloom Filter 分块预过滤&lt;/strong&gt;&lt;br /&gt;
- 问题：中文常用 2-gram 只有 ~690 种，&lt;strong&gt;每个块都包含所有 n-gram&lt;/strong&gt;，过滤率为 0&lt;br /&gt;
- 结论：对高频 n-gram 的数据集完全无效，白费构建时间&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;zstd 流式解压搜索&lt;/strong&gt;&lt;br /&gt;
- 问题：Python 解压+搜索 166ms，比不压缩的 grep 还慢&lt;br /&gt;
- 结论：CPU 密集的解压抵消了 I/O 节省。如果数据在 SSD 上，不如直接读原文&lt;br /&gt;
- 可能有用的场景：数据在网络存储/HDD 上，I/O 是瓶颈时&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DuckDB FTS (BM25)&lt;/strong&gt;&lt;br /&gt;
- 问题：默认 tokenizer（类似 ICU word boundary）不支持中文&lt;br /&gt;
- 结论：需要自定义 tokenizer 或等 DuckDB 支持 trigram/CJK&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;mmap 直接搜索&lt;/strong&gt;&lt;br /&gt;
- 表现：24.87ms，比 ripgrep 慢 2 倍&lt;br /&gt;
- 原因：Python 的 &lt;code&gt;mmap.find()&lt;/code&gt; 是朴素搜索，没有 SIMD 优化&lt;br /&gt;
- 如果用 C/Rust 实现的 mmap + SIMD，预期接近 ripgrep 水平&lt;/p&gt;
&lt;h3&gt;推荐方案排名&lt;/h3&gt;
&lt;h4&gt;如果从零设计微信聊天存储&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: center;"&gt;优先级&lt;/th&gt;
&lt;th&gt;方案&lt;/th&gt;
&lt;th style="text-align: right;"&gt;搜索延迟&lt;/th&gt;
&lt;th style="text-align: right;"&gt;存储&lt;/th&gt;
&lt;th&gt;理由&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;🥇&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Parquet + Polars/DuckDB&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: right;"&gt;3-5ms&lt;/td&gt;
&lt;td style="text-align: right;"&gt;8 MB&lt;/td&gt;
&lt;td&gt;存储最小、搜索极快、格式通用、append 友好&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;🥈&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;DuckDB 数据库&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: right;"&gt;3.7ms&lt;/td&gt;
&lt;td style="text-align: right;"&gt;26 MB&lt;/td&gt;
&lt;td&gt;单文件数据库、列式、SQL 查询、FTS 索引可选&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;🥉&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;SQLite + FTS5&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: right;"&gt;0.3ms&lt;/td&gt;
&lt;td style="text-align: right;"&gt;117 MB&lt;/td&gt;
&lt;td&gt;最快搜索(有索引)、但索引太大&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;4&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;ripgrep + 分块 TSV&lt;/strong&gt;&lt;/td&gt;
&lt;td style="text-align: right;"&gt;10ms&lt;/td&gt;
&lt;td style="text-align: right;"&gt;47 MB&lt;/td&gt;
&lt;td&gt;最简单、无依赖、人类可读&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;如果要"一行命令搜聊天记录"&lt;/h4&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;# 方案 A#: ripgrep 搜纯文本 (~10ms)
rg &amp;quot;微信支付&amp;quot; messages.tsv

## 方案 B: DuckDB 直接查 Parquet (~5ms)
duckdb -c &amp;quot;SELECT * FROM read_parquet('messages.parquet') WHERE contains(content, '微信支付')&amp;quot;

## 方案 C: DuckDB 复合查询 (~5ms)  
duckdb -c &amp;quot;SELECT * FROM read_parquet('messages.parquet')
           WHERE talker='wxid_xxx' AND createTime &amp;gt; 1672531200
           AND contains(content, '会议')&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;最终结论&lt;/h3&gt;
&lt;h4&gt;"用 grep 代替 SQLite" — 部分正确，但格局太小&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;ripgrep 比 SQLite LIKE 快 3 倍&lt;/strong&gt;（13ms vs 42ms）— "grep 派"的论据成立&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;但 DuckDB/Polars 比 ripgrep 又快 4 倍&lt;/strong&gt;（3ms vs 13ms）— 列式才是正道&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Parquet 比纯文本还小 5.6 倍&lt;/strong&gt;（8MB vs 47MB）— 省空间还更快&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;复合查询（按人+时间+关键词）SQLite 仍然最强&lt;/strong&gt;（2.8ms）&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;真正的启示&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;聊天记录是 append-only 数据 → 最适合列式存储 (Parquet/DuckDB)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不需要 RDBMS 的事务/锁/B-tree 开销&lt;/li&gt;
&lt;li&gt;列式布局让 &lt;code&gt;content&lt;/code&gt; 列连续存放，CPU cache 极度友好&lt;/li&gt;
&lt;li&gt;zstd 字典压缩对重复模式多的聊天文本压缩率惊人（82%）&lt;/li&gt;
&lt;li&gt;追加写入只需要 append 新的 row group&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;微信搜索慢的根因&lt;/strong&gt;：不是 SQLite vs grep 的问题，而是 &lt;strong&gt;SQLCipher 加密的 PBKDF2 256000 轮&lt;/strong&gt; + 行式存储对全文扫描不友好。如果用 Parquet + 硬件 AES，可以同时做到加密和极速搜索。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;脑洞：终极方案&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;messages.parquet (8MB, zstd压缩, 硬件AES加密)
  → DuckDB/Polars 直接查询 (3-5ms)
  → 可选: 内存倒排索引 for &amp;lt; 1ms 搜索
  → 追加: 新消息 append 到 staging 文件, 定期 merge
  → 导出: parquet 是开放格式, 任何语言/工具可读
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;复现&lt;/h3&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;pip install duckdb polars zstandard cryptography
python3 benchmark.py 500000     # 基础测试 (SQLite/grep)  
python3 benchmark_v2.py 500000  # 扩展测试 (DuckDB/Polars/mmap/...)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;源码放在 &lt;a href="https://github.com/est/snippets/tree/master/grep_vs_sqlite"&gt;https://github.com/est/snippets/tree/master/grep_vs_sqlite&lt;/a&gt; 。&lt;/p&gt;
&lt;p&gt;模拟聊天记录有500,000行 一个 50MB 的 .tsv 太大了。自己让AI根据文章和最上面表结构生成一份吧。&lt;/p&gt;
&lt;h3&gt;后记&lt;/h3&gt;
&lt;p&gt;被Polars的性能震惊了。说实话如果换我肯定不会选sqlite。聊天记录又不会改。ACID的 OLTP 明显浪费&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">est</dc:creator><pubDate>Thu, 09 Jul 2026 11:02:00 +0800</pubDate><guid isPermaLink="false">tag:None,2026-07-09:/2026/stdout-26</guid><category>stdout</category></item><item><title>[AI] curl -NT. 导致100% CPU原因</title><link>https://blog.est.im/2026/stdout-25</link><description>&lt;p&gt;有AI就是好使，搁以前自己得盯半天也看不明白。。。&lt;/p&gt;
&lt;h3&gt;问题确认&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;curl -NT.&lt;/code&gt; 在连接一个持续推送数据的 streaming 服务器时，会产生一个 &lt;strong&gt;紧密的 pause/unpause 循环&lt;/strong&gt;，导致 100% CPU。&lt;/p&gt;
&lt;h3&gt;根因分析&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;-T.&lt;/code&gt;（注意是点号，不是减号）将 stdin 设为&lt;strong&gt;非阻塞模式&lt;/strong&gt;，然后依赖 &lt;code&gt;EAGAIN&lt;/code&gt; + &lt;code&gt;CURL_READFUNC_PAUSE&lt;/code&gt; 机制来避免阻塞。核心循环发生在三个回调之间：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第一步 — 上传尝试失败&lt;/strong&gt;（&lt;code&gt;src/tool_cb_rea.c&lt;/code&gt;）：&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-c"&gt;  {
    rc = read(per-&amp;gt;infd, buffer, sz * nmemb);
    if(rc &amp;lt; 0) {
      if(errno == EAGAIN) {
        errno = 0;
        config-&amp;gt;readbusy = TRUE;
        return CURL_READFUNC_PAUSE;
      }
      /* since size_t is unsigned we cannot return negative values fine */
      rc = 0;
    }
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;stdin 没数据 → &lt;code&gt;read()&lt;/code&gt; 返回 &lt;code&gt;EAGAIN&lt;/code&gt; → 设 &lt;code&gt;readbusy=TRUE&lt;/code&gt; → 暂停上传。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第二步 — 下载数据到达立刻解除暂停&lt;/strong&gt;（&lt;code&gt;src/tool_cb_wrt.c&lt;/code&gt;）：&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-c"&gt;  if(config-&amp;gt;readbusy) {
    config-&amp;gt;readbusy = FALSE;
    curl_easy_pause(per-&amp;gt;curl, CURLPAUSE_CONT);
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;streaming 服务器持续发送数据 → &lt;code&gt;tool_write_cb&lt;/code&gt; 被不断调用 → 每次都&lt;strong&gt;无等待地立刻解除上传暂停&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第三步 — 进度回调只有 1ms 退避&lt;/strong&gt;（&lt;code&gt;src/tool_cb_rea.c&lt;/code&gt;）：&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-c"&gt;  if(config-&amp;gt;readbusy) {
    if(ulprev == ulnow) {
#ifndef _WIN32
      waitfd(1, per-&amp;gt;infd);
#else
      /* sleep */
      curlx_wait_ms(1);
#endif
    }

    config-&amp;gt;readbusy = FALSE;
    curl_easy_pause(per-&amp;gt;curl, CURLPAUSE_CONT);
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;tool_readbusy_cb&lt;/code&gt; 有 1ms 的 &lt;code&gt;waitfd&lt;/code&gt; 退避，但被 &lt;code&gt;tool_write_cb&lt;/code&gt; 的无等待解除抢先了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;完整的死循环（每次 &lt;code&gt;curl_multi_perform&lt;/code&gt; 内）&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;在 &lt;code&gt;lib/transfer.c&lt;/code&gt; 的 &lt;code&gt;Curl_sendrecv&lt;/code&gt; 中，处理顺序是&lt;strong&gt;先下载后上传&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-c"&gt;  if(k-&amp;gt;keepon &amp;amp; KEEP_RECV) {
    result = sendrecv_dl(data, k);
    if(result || data-&amp;gt;req.done)
      goto out;
  }

  /* If we still have writing to do, we check if we have a writable socket. */
  if(Curl_req_want_send(data)) {
    result = sendrecv_ul(data);
    if(result)
      goto out;
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;所以单次迭代内：&lt;br /&gt;
1. &lt;code&gt;sendrecv_dl&lt;/code&gt; → 读到 streaming 数据 → &lt;code&gt;tool_write_cb&lt;/code&gt; → 看到 &lt;code&gt;readbusy=TRUE&lt;/code&gt; → &lt;strong&gt;立刻解除暂停&lt;/strong&gt;（零等待）&lt;br /&gt;
2. &lt;code&gt;sendrecv_ul&lt;/code&gt; → &lt;code&gt;tool_read_cb&lt;/code&gt; → stdin &lt;code&gt;EAGAIN&lt;/code&gt; → &lt;strong&gt;又暂停&lt;/strong&gt;，&lt;code&gt;readbusy=TRUE&lt;/code&gt;&lt;br /&gt;
3. 回到 &lt;code&gt;curl_multi_poll&lt;/code&gt; → 下载 socket 有数据 → &lt;strong&gt;立刻返回&lt;/strong&gt;（不会 sleep）&lt;br /&gt;
4. 重复 1-3&lt;/p&gt;
&lt;p&gt;而 &lt;code&gt;lib/easy.c&lt;/code&gt; 的主循环：&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-c"&gt;  while(!done &amp;amp;&amp;amp; !mresult) {
    int still_running = 0;

    mresult = curl_multi_poll(multi, NULL, 0, 1000, NULL);

    if(!mresult)
      mresult = curl_multi_perform(multi, &amp;amp;still_running);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;curl_multi_poll&lt;/code&gt; 的 1000ms 超时形同虚设——因为下载 socket 始终可读，&lt;code&gt;poll()&lt;/code&gt; 立刻返回。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;结果&lt;/strong&gt;：每秒跑上千次这个循环，每次包含多个系统调用（&lt;code&gt;poll&lt;/code&gt;、&lt;code&gt;read&lt;/code&gt;、&lt;code&gt;write&lt;/code&gt;），CPU 直接打满。&lt;/p&gt;
&lt;h3&gt;问题本质&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;stdin 没有被加入 &lt;code&gt;curl_multi_poll&lt;/code&gt; 的 pollset&lt;/strong&gt;。只有网络 socket 参与了 poll。所以 curl 无法高效地"同时等待 stdin 和网络数据"，只能靠 &lt;code&gt;tool_write_cb&lt;/code&gt; 里的盲目 unpause 来弥补，在 streaming 场景下退化成忙等。&lt;/p&gt;
&lt;h3&gt;用户侧解决方案&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;如果你不需要从 stdin 上传数据&lt;/strong&gt;（只是想看 streaming 响应），不要用 &lt;code&gt;-T.&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;# 正确的方式：只看 streaming 输出
curl -N https://streaming-server/events

# 或者重定向 stdin 为空
curl -NT. https://streaming-server/events &amp;lt; /dev/null
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;&amp;lt; /dev/null&lt;/code&gt; 会让 &lt;code&gt;read()&lt;/code&gt; 返回 0（EOF）而不是 EAGAIN，不会进入 pause/unpause 循环。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如果确实需要双向 streaming&lt;/strong&gt;（边上传 stdin 边接收），目前没有完美的用户侧 workaround。可以考虑：&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;# 用管道加一层缓冲，减轻空转（效果有限）
cat | curl -NT. https://streaming-server/events
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;源码级修复思路&lt;/h3&gt;
&lt;p&gt;如果要在源码层面修复，最直接的方案是&lt;strong&gt;在 &lt;code&gt;tool_write_cb&lt;/code&gt; 中去掉盲目 unpause&lt;/strong&gt;，改为只在 &lt;code&gt;tool_readbusy_cb&lt;/code&gt; 中带退避地 unpause，并增大退避时间：&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-c"&gt;// tool_cb_wrt.c — 去掉这段，或加条件限制
// 不再从 write callback 无脑解除上传暂停
if(config-&amp;gt;readbusy) {
    config-&amp;gt;readbusy = FALSE;
    curl_easy_pause(per-&amp;gt;curl, CURLPAUSE_CONT);  // 删除或改为有条件触发
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class="language-c"&gt;// tool_cb_rea.c — 增大退避时间
if(config-&amp;gt;readbusy) {
    if(ulprev == ulnow) {
        waitfd(100, per-&amp;gt;infd);  // 从 1ms 提高到 100ms
    }
    config-&amp;gt;readbusy = FALSE;
    curl_easy_pause(per-&amp;gt;curl, CURLPAUSE_CONT);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更彻底的方案是把 stdin fd 加入 &lt;code&gt;curl_multi_poll&lt;/code&gt; 的 extra fds，但这需要改 &lt;code&gt;curl_multi_poll&lt;/code&gt; 的调用方式，涉及面更大。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">est</dc:creator><pubDate>Wed, 08 Jul 2026 16:05:00 +0800</pubDate><guid isPermaLink="false">tag:None,2026-07-08:/2026/stdout-25</guid><category>stdout</category></item><item><title>或许「数羊」真是个有效的入睡法</title><link>https://blog.est.im/2026/stderr-23</link><description>&lt;p&gt;无聊刷博客，《&lt;a href="https://yage.ai/ai-sleep.html"&gt;AI如何导致和修复了我的失眠问题&lt;/a&gt;》 这老哥真猛，通过统计规律发现自己 失眠 的罪魁祸首。（不剧透。感兴趣点开阅读）&lt;/p&gt;
&lt;p&gt;我自己也写过 &lt;a href="https://blog.est.im/2024/stdout-05"&gt;快速入睡的技巧和原理&lt;/a&gt; 以及 &lt;a href="https://blog.est.im/2024/stderr-15"&gt;强行入睡方法 v2.0&lt;/a&gt; 其实我都忘记这个 2.0 方法了。都不知道自己当时怎么想到这个办法的，原来自己写的东西也能常看常新（老登健忘症😂），所以还是要多写，多记录&lt;/p&gt;
&lt;p&gt;本文章的讨论都是基于这个 2.0方法的，接着看之前请务必点开 2.0  那个链接，不长，一会儿就看完。&lt;/p&gt;
&lt;p&gt;然后我就无聊让AI 评价一下这个 2.0 方法是不是真的，然后AI说真有学者在搞类似的，关键词 ：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;睡前“认知打断 / imagery distraction&lt;/li&gt;
&lt;li&gt;cognitive shuffle&lt;/li&gt;
&lt;li&gt;serial diverse imagining (SDI)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;然后我去搜了下&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;TikTok和Instagram上爆火的“认知洗牌法”，火到连医生都开始推荐。选一个随机的单词（比如 cake，蛋糕），专注于这个词的第一个字母（C），然后列出一串以这个字母开头的词：cat（猫）、carrot（胡萝卜）、calendar（日历）等等，一边列举，一边在脑中想象这些词的画面。当你准备好了，就转到下一个字母（A），重复上述过程，继续进行下去（K、E），直到你睡着或者想换一个新词为止&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;嗯，和我的方法居然殊途同归，只是更加麻烦，需要调用大脑的语言区。&lt;/p&gt;
&lt;p&gt;但是自媒体这个标题让我产生了兴趣 《别再数羊了》，我恰好周末刷了 西藏那曲拉姆 的视频 &lt;a href="https://www.douyin.com/video/7602897143380135178"&gt;藏族人家里几十上百头牦牛，如何识别是不是自己家的？&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;然后突然发现一个被大多数人忽略的惊人的事实：放牧人的白天是极度无聊和空虚的，以至于他/她们能辨识自己每一头羊的特征、性别，甚至给每头羊起个名字。视频说牦牛和人一样，每一头都有独一无二的毛色、长相、形态等。&lt;/p&gt;
&lt;p&gt;脸上有点黑？叫小黑；黑白相间的？叫花脸。按脾气起名字，暴躁哥，温顺妹；还有谁和谁喜欢一起吃草，小牛的母牛妈妈是谁等等。&lt;/p&gt;
&lt;p&gt;所以这两件事就串起来了。「数羊」这事儿一定是牧区的人发明出来的，比如英国乡下，但是城里人哪里知道这些细节啊。&lt;/p&gt;
&lt;p&gt;牧民晚上躺床上，没事干，说不定就给自己牛羊编故事造剧情啊。而且关键词是「数」，你不能陷入一个逻辑推理细节，必须不停地轮换，把羊变成高频切换的具象个体（有名字、有外形、有性格），才能保证大脑疲惫然后入睡。&lt;/p&gt;
&lt;p&gt;AI总结：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;对于古代或乡村的牧羊人来说，夜晚盘点羊群是一天结束时最让人安心的闭环。他们脑海中的羊，确实是毛发质感、体态特征各异的具象实体。&lt;br /&gt;
现代城市人剥离了这种生活语境，把一幅丰富的田园3D渲染图，降维成了枯燥的Excel递增表格，自然也就失去了助眠的神奇功效。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我觉得AI真有点东西的。清点生产资料也是被忽略的一环。如果我睡前都能盘点自己该做的事儿都做了，羊吃饱了，明天会更好，没啥落下的，那我肯定也睡得安稳啊。&lt;/p&gt;
&lt;p&gt;但是现代人难就难在很多事是跨很多天的，入睡是非常不情愿的。如果有精力很多人甚至愿意熬夜。&lt;/p&gt;
&lt;p&gt;都怪爱迪生，本来以为发明电灯泡给人类漫长的黑夜带来光明，没想到人类却用这玩意来加班和难眠！！😤 😤 😤 如果太阳下山就睡觉，就算失眠4小时你到23点也睡着了 😂&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">est</dc:creator><pubDate>Mon, 06 Jul 2026 15:51:00 +0800</pubDate><guid isPermaLink="false">tag:None,2026-07-06:/2026/stderr-23</guid><category>stderr</category></item><item><title>唯物主义「天命」论</title><link>https://blog.est.im/2026/stderr-22</link><description>&lt;p&gt;看到一篇雄文《&lt;a href="https://www.zhihu.com/question/576083946/answer/2055730121491879314"&gt;明末士大夫为什么毫无气节纷纷变节投降满清？&lt;/a&gt;》大受启发，想看原文的可以点开链接，下面是精简和摘录:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;因为程朱理学在理论存面存在漏洞，被鞑子无意之间利用了，事实上大部分的鞑子统治者在这方面，也都是知其然而不知所以然。&lt;br /&gt;
不否认明末也有很多了不起的仁人志士，但如果你对中国历史有些疑惑，觉得似乎宋朝之后中国就有点不一样了，那恭喜你，你的直觉是对的。由于元代留下的遗毒过甚，明朝没能拨乱反正，元明清三代，所有的皇帝和“儒家士大夫”，都是失礼而不自知之人。元明清三代的所谓“礼法”，放在先秦两汉的大学者们面前，诸子百家不管哪家，都一眼就能看出来全是假礼。如果墨子这个儒家最大的反对者看见了，估计更是嘲笑孔子能笑的棺材板都压不住。这些“假礼”，就是元明清三代那些僵化的等级秩序、规规矩矩。出于汉人的直觉，厌恶这些是再正常不过了。&lt;br /&gt;
一、建用皇极&lt;br /&gt;
宋以前儒学，与宋明理学不是同一种思想。先秦至汉唐儒学的最高原则是天命与大中之道，而不是君主本身。朱熹重新解释《尚书·洪范》"皇极"，从九畴排第五提高到最高优先级， 把它解释为 君主是天下的最高标准，天下围绕君主建立秩序。，从而改变了儒家的政治哲学。&lt;br /&gt;
二 · 定于一尊&lt;br /&gt;
元朝恢复科举时规定：四书、五经必须按照朱熹注释考试，使其成为与功名利禄直接挂钩的唯一标准。于是理学不再只是一个前朝有争议的一个"逆党"学说，而成为整个帝国唯一的意识形态。明清完全继承了这一制度。&lt;br /&gt;
三、诸夏之亡&lt;br /&gt;
《论语》中孔子其实始终强调，华夏共同体高于个人君臣关系。例如孔子称赞管仲，就是因为即使“不忠”，改事新君，只要能够保卫华夏，也仍然值得肯定。但程朱理学更加重视君臣名分、上下秩序、皇权连续性，于是出现一种新的逻辑：即使皇帝是异族，也不能没有皇帝。1908年孔令贻把德国皇帝威廉二世肖像迎进了孔府&lt;br /&gt;
四、天命之礼&lt;br /&gt;
孔子的礼，本质上来源于 天命。所以：礼约束君主，君主不能创造礼。而理学实践中却逐渐变成皇帝成为礼法的最终解释者。于是礼不再约束权力，而成为权力工具。&lt;br /&gt;
五、凡心之仁&lt;br /&gt;
基督教的本质是爱与诫二元一体的罪文化，那么发源自中国的东亚文化，本质就是仁与礼二元一体的耻文化。&lt;br /&gt;
基督教中所谓的爱，叫做“Agape”。这是一个专有词，它有多重要呢？欧洲所有国家，不管哪种语言，它的拼写方式都是一致的，一字不易。“Agape”的源头是神，它是一种具有普世性的博爱。而“仁”和“Agape”的区别在于，中国的“仁”，其源头是凡人，是“己所不欲勿施于人”，它是一种推己及人的有差等之爱。&lt;br /&gt;
华夷之辩是“礼”的边界，“礼”是对“仁”的约束。面对民族危机时，个人、家庭利益、官职利益、君臣秩序都会压倒共同体利益。因此许多人最终选择保身、顺从、投降，而不是抗清。&lt;br /&gt;
（注：这里其实用 “异端” 和 “有经人” 对比更加强烈）&lt;br /&gt;
六、知行合一&lt;br /&gt;
孔子、董仲舒的礼法，理论源头是天帝，实践中确实也按天帝至上来执行。而程朱理学的礼法，理论源头是天理，但是实践中，理学的礼法源头压根不是天理！在以前，经筵都是大儒给皇帝讲课，到了乾隆那，变成皇帝给大儒讲课了。&lt;br /&gt;
先秦两汉礼法的源头是神？因为礼法的源头就不能是一个具体的人！礼法是用来栓人的保守性，如果礼法的源头是人，那么栓着你的绳子就牵在那个人手上，你就是那个人的奴才，礼法就成了赤裸裸的等级压迫。&lt;br /&gt;
如果天帝无法约束皇权，那么天帝也不能保护皇权。天帝不能保护皇权，皇帝就只能自己保护自己，于是朱元璋废除了丞相制度。所谓明清飞速膨胀的君权，其实和南北朝盛产的疯子皇帝有异曲同工之妙。跟着龙椅遗传的精神病，本质是因为坐在龙椅上的人没有安全感。没有人相信天命，连皇帝本人都不相信自己真正“受命于天”。而对于儒生大臣，后人说张居正是“常务副皇帝”。&lt;br /&gt;
七、失礼之国&lt;br /&gt;
（作者的一些感想，比较杂，不引述了）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;看完之后真过瘾。本来想着今天的键政就到这了。&lt;/p&gt;
&lt;p&gt;特别是第二点，最近几年我逐渐从对“科举”的好感，降低了。学生时代总有那么一些“考功名”的亲切感，但是现实世界还是觉得“军功合伙人”更优。&lt;/p&gt;
&lt;p&gt;但是有一个更大的疑惑，转念一想不对劲。于是补充一点我自己的观点。&lt;/p&gt;
&lt;p&gt;皇帝这个岗位，从秦到唐，都是一把手承包了世俗君权，和神权的双重责任。皇帝在赵政之前实际上是两个岗位，大祭司负责给「帝」传话，王中王称皇负责行政。&lt;/p&gt;
&lt;p&gt;宋以后皇帝把道德秩序这一块外包给儒生了，自己关起门做皇家经营了，剩下的全是算计。&lt;/p&gt;
&lt;p&gt;说得直白点汉唐的皇帝还勉强要点b脸，遇到难堪的事，还得想办法给手下和民间一点说法。&lt;/p&gt;
&lt;p&gt;宋以后就是无情的 打工 - 服从 叙事。&lt;/p&gt;
&lt;p&gt;我是真的越来越看不起大怂国。我把内心抱怨说给AI，AI指出&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;宋代皇帝其实仍然非常受士大夫制约&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我反驳：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;例如宋代皇帝其实仍然非常受士大夫制约，需要合理分赃才能一起搜刮老百姓。造成有史以来遍地造反运动。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;AI当时就不乐意了。把教科书和网上常见吹捧宋朝的资料抬出来了。比如说宋朝其实造反的规模和烈度没那么多&lt;/p&gt;
&lt;p&gt;但是我想说，你把大半个中国都丢干净了，西夏 辽金的汉人躺棺材里了，当然北境无人“造反”了。因为别人都被占领了。&lt;/p&gt;
&lt;p&gt;秦汉 隋唐造反不就是关中和河北人打架吗？这一毛病从姬发那一辈儿就没停过。天子这一岗位说的直白点就是给大家当调停人，pax sinica 。你宋说白了就一个节度使，偏安江淮一隅，还这么多造反的。呸！&lt;/p&gt;
&lt;p&gt;AI 被这个角度刁钻的回答干懵逼了。说你这个框架，衡量皇朝优劣的标准不是"有没有起义"，而是 能不能维持整个华夏共同体的秩序。那么很多评价都会变。最后还嘴硬一句，宋朝其实内部治理得很好啦，最终是被蒙古人迫不得已干趴下的。&lt;/p&gt;
&lt;p&gt;我当时就火了。对蒙古你好意思讲“战争”？实际上周 秦 汉 唐 的草原治理能力，也是 “天命” 的支柱啊。周武王牧誓，手里拿着的就是牦牛尾巴！不是象征汉人农耕的的锄头！纵观宋、金两朝，对草原的经略就是完全失败的。垃圾！&lt;/p&gt;
&lt;p&gt;因为刚刚前一阵子看到 《&lt;a href="https://www.bilibili.com/video/BV1u8KZ68E1R/"&gt;金朝对草原的减丁，为何遏制不了蒙古的崛起&lt;/a&gt;》 这里 cue 一下&lt;/p&gt;
&lt;p&gt;宋辽金真是一群乡镇企业家暴发户械斗。烂得要命。唉。你仔细想一下宋吹，那些证据，多少是近代人牵强附会的？宋朝人自己觉得骄傲吗？给好评的，都是后世明清没当上官的文人吧？&lt;/p&gt;
&lt;p&gt;天命最大的意义在哪里？给人指明前行的道路，给人以希望。即便黑暗中世纪教会和君权也是这么分工的。挫宋做到了啥？苟且罢了。&lt;/p&gt;
&lt;p&gt;有人说，大宋“杯酒释兵权”终结了五代十国，功劳巨大。但从“天命”的角度讲，国之大事，在祀与戎。你老赵家没能给一个民族找到希望，也干不过架，你这个王权就没有存在的根基。说得直白一点，东亚这篇土地，从周天子那一辈人开始就是武装殖民模式。你不殖民，有的是蒙古人 女真人殖你的民。&lt;/p&gt;
&lt;p&gt;其实一开始那个文章的框架来讨论一个具体的事就很有力度。如何评价北宋赵光义毁掉太原？&lt;/p&gt;
&lt;p&gt;具体的事迹大家可以问下AI。正如文章里所说的，丢掉了 华夷之辩 这个“天命”。那别人河北幽州人全体投夷你也怨不了谁。你之后靖康之变都是报应。&lt;/p&gt;
&lt;p&gt;网上对 “内亚” 的说法一直有巨大争议，阿姨那边一直说“武德注入”，实际上征服，殖民 和扩张这些说法太粗暴。但是如果天子不提供秩序，那么你也别怨替代秩序的出现；无德，丢天命，天命归别人。似乎就是这么简单的道理&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;政治空间是没有真空的&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;谁的组织度更高，谁的天命就更强。&lt;/p&gt;
&lt;p&gt;联系到欧洲发家，启蒙运动 文艺复兴，是在抛弃君权 神权 这个思维定势下做到的。更厉害。&lt;/p&gt;
&lt;p&gt;不过替代品似乎是——资本？一个侧面就是牛津剑桥主打神学专业，改成政治经济学&lt;/p&gt;
&lt;p&gt;资本的扩张我觉得按照脉络去捋，是蒸汽机，发展纺织业，全球贸易。 归根结底是煤铁革命，但是仔细想，实际上是把战争的边界改成向几百亿年的太阳能存款挖出来消耗了。&lt;/p&gt;
&lt;p&gt;农牧时代是拿当季的太阳能来pk。谁能提供摩擦最小的当季太阳能分配，谁就在古代“有德”，有“天命”&lt;/p&gt;
&lt;p&gt;现代社会一样的。全球变暖，污染，绿色能源等，一直到社会公平正义。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;天命天命，天就是天上射下来的能量，命就是草木人间生命。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;哈哈哈这个解释如何？是不是很唯物。&lt;/p&gt;
&lt;p&gt;天（能源）与命（生命负载）之间，能否实现最高效的转换与分配？&lt;/p&gt;
&lt;p&gt;生命本身就是一个“负熵的过程”。生命存在的意义，就是把“天”射下来的能量，通过光合作用、通过食物链，转化为有序的社会结构、文明形态和思想结晶。&lt;/p&gt;
&lt;p&gt;如果转换效率高、分配摩擦小： 生命、社会繁荣，这就叫“天命有归”。&lt;/p&gt;
&lt;p&gt;如果中间商抽成太多，腐败、内卷、战略自残（如毁太原）： 能量（天）射下来了，却无法高效转化为“命（繁荣）”，能量在内部耗散了，这就是天命将尽。&lt;/p&gt;
&lt;p&gt;大宋这种对外又送又怂，把“皇帝”这个singleton强行改成“兄弟之国”， 对内三冗，取缔军功兑现，换成“理学”考试，用首都的局部繁荣掩盖整体的失败。就是丢 天命 的典型。&lt;/p&gt;
&lt;p&gt;古代的战争：争夺的是对“天光（土地）”的占有权。&lt;/p&gt;
&lt;p&gt;现代的危机：焦虑的是“天光（太阳能存款）”快烧完了，我们该如何重新设计“命（人类社会）”的分配效率。&lt;/p&gt;
&lt;p&gt;政治的本质就是能量管理工程。&lt;/p&gt;
&lt;p&gt;天命 在过去，看重国体和人君，现代看政治制度科技政策。资本这个玩意，纵然有那么多毛病，但是很好的执行了“天命”&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">est</dc:creator><pubDate>Thu, 02 Jul 2026 16:07:00 +0800</pubDate><guid isPermaLink="false">tag:None,2026-07-02:/2026/stderr-22</guid><category>stderr</category></item><item><title>我的 Vibe Coding 最佳实践——ADR文档</title><link>https://blog.est.im/2026/stdout-24</link><description>&lt;p&gt;工作和业余也用AI写代码，大大小小项目都经历了。从 rules, skills, spec, agent 到  harness 都玩过了&lt;/p&gt;
&lt;p&gt;从AI嘴里发现一条比较稳的套路——ADR文档&lt;/p&gt;
&lt;p&gt;rule, skills, spec 这些东西最大的问题就是瞎jb指挥。ADR 的好处是记录why，以及决策演变历史。&lt;/p&gt;
&lt;p&gt;贴一段&lt;a href="https://github.com/est/rss_aggr/blob/main/docs/ADR/001.project.ADR-howto.md"&gt;我整理的 ADR 文档&lt;/a&gt;就明白了： &lt;/p&gt;
&lt;pre&gt;&lt;code class="language-markdown"&gt;---
title: 如何使用 ADR
id: ADR-001
date: 2026-06-26 09:01:21
status: accepted
---
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;ADR&lt;/h1&gt;
&lt;p&gt;ADR（Architecture Decision Record，架构决策记录）的核心目标很简单：&lt;strong&gt;记录为什么做出了某个重要技术决策，而不是记录系统长什么样。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;目前比较常见的是 MADR、Nygard ADR 两种风格，但组织方式都大同小异。&lt;/p&gt;
&lt;p&gt;一个团队通常会按下面几个层次组织。&lt;/p&gt;
&lt;h2&gt;1. 一个 ADR 对应一个决策&lt;/h2&gt;
&lt;p&gt;不要一个 ADR 写整个系统设计。&lt;/p&gt;
&lt;p&gt;好的粒度例如：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ADR-001 使用 PostgreSQL 作为主数据库&lt;br /&gt;
ADR-002 API 使用 REST 而不是 GraphQL&lt;br /&gt;
ADR-003 服务间通信采用 gRPC&lt;br /&gt;
ADR-004 用户认证采用 OAuth2 + JWT&lt;br /&gt;
ADR-005 使用事件驱动 Outbox Pattern&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;而不是&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;系统架构设计.md&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;因为几年以后，很难知道某个结论为什么来的。&lt;/p&gt;
&lt;h2&gt;2. 编号保持永久&lt;/h2&gt;
&lt;p&gt;一般都会固定编号。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;adr/

0001-use-postgresql.md
0002-use-rest-api.md
0003-use-grpc.md
0004-use-oauth2.md
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;编号一旦存在，就不要修改。&lt;/p&gt;
&lt;p&gt;即使后来废弃：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0003-use-grpc.md
Status: Superseded by ADR-0018
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样引用不会失效。&lt;/p&gt;
&lt;h2&gt;3. Status 非常重要&lt;/h2&gt;
&lt;p&gt;一般都有状态。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Proposed&lt;/li&gt;
&lt;li&gt;Accepted&lt;/li&gt;
&lt;li&gt;Deprecated ❌&lt;/li&gt;
&lt;li&gt;Superseded 🔄&lt;/li&gt;
&lt;li&gt;Rejected ⛔️&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Status: Accepted
Date: 2026-06-19 01:02:03
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果后来换了：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Status: Superseded
Superseded by: ADR-0018
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而新的 ADR：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ADR-0018
Supersedes: ADR-0003
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;形成完整历史。&lt;/p&gt;
&lt;h2&gt;4. 一个 ADR 的典型模板&lt;/h2&gt;
&lt;pre&gt;&lt;code class="language-markdown"&gt;---
title: ADR-008 使用 PostgreSQL
id: ADR-008
date: 2026-06-18 12:32:46
status: accepted
---


## Context

目前需要：

- ACID
- JSON 查询
- 成熟生态

候选：

- PostgreSQL
- MySQL
- MongoDB

## Decision

选择 PostgreSQL。

## Consequences

优点：

- SQL 功能完整
- JSONB 支持优秀
- 社区成熟

缺点：

- 运维复杂度略高
- 分库分表方案需要额外设计
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以再加：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Alternatives

Decision Drivers

Trade-offs

References
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5. 按领域组织，而不是按时间（可选）&lt;/h2&gt;
&lt;p&gt;在一个目录，用文件名体现领域：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;008.backend.use-grpc.md
010.security.use-oauth.md
012.frontend.react-query.md
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样编号保持连续，查找也方便。&lt;/p&gt;
&lt;h2&gt;6. ADR 之间允许引用&lt;/h2&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ADR-0015

Context

依赖：
- ADR-0002
- ADR-0008

Decision

由于 ADR-0008 已经确定 PostgreSQL，
因此 Outbox Pattern 可以直接利用事务。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;形成决策网络，而不是孤立文档。&lt;/p&gt;
&lt;h2&gt;7. ADR 只记录"为什么"&lt;/h2&gt;
&lt;p&gt;这是很多团队最容易犯的错误。&lt;/p&gt;
&lt;p&gt;不要写：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Controller
Service
Repository
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这是设计文档。&lt;/p&gt;
&lt;p&gt;ADR 应该写：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;为什么不用 MongoDB？

为什么不用 GraphQL？

为什么采用 Saga？

为什么拆成多个 Service？

为什么 Event Sourcing 被放弃？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;重点永远是 &lt;strong&gt;Why&lt;/strong&gt;，而不是 &lt;strong&gt;What&lt;/strong&gt;。&lt;/p&gt;
&lt;h2&gt;8. 和设计文档分开&lt;/h2&gt;
&lt;p&gt;过去很多团队会这样组织：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;文档&lt;/th&gt;
&lt;th&gt;回答的问题&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;RFC / Proposal&lt;/td&gt;
&lt;td&gt;未来准备怎么做？&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ADR&lt;/td&gt;
&lt;td&gt;为什么这样做？&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Architecture Doc&lt;/td&gt;
&lt;td&gt;系统如何组织？&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Design Doc&lt;/td&gt;
&lt;td&gt;某个功能如何实现？&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runbook&lt;/td&gt;
&lt;td&gt;如何运维？&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;流程是 RFC → ADR → Design Doc → Code。&lt;/p&gt;
&lt;p&gt;RFC 用于讨论方案，达成决策后沉淀为 ADR；随后具体实现细节写入设计文档，最终落实到代码。这样既保留了决策依据，又避免 ADR 演变成冗长的设计说明。&lt;/p&gt;
&lt;p&gt;在AI 时代，更简洁，易维护的方式是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ADR 形成决策历史；&lt;/li&gt;
&lt;li&gt;DESIGN.md （小项目也可以直接放 README.md） 反应当前设计，大量引用 ADR 而不是重复。&lt;/li&gt;
&lt;li&gt;迭代排期（spec，phase文档等）引用ADR作为缘由&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;AI编写的项目，到后期，泥潭就是大量的docs。ADR 的好处是不用修订，全面引用+supersed。保证决策链清晰，低上下文成本&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">est</dc:creator><pubDate>Fri, 26 Jun 2026 09:40:00 +0800</pubDate><guid isPermaLink="false">tag:None,2026-06-26:/2026/stdout-24</guid><category>stdout</category></item><item><title>MacOS 快速插入当前时间</title><link>https://blog.est.im/2026/stdout-23</link><description>&lt;h2&gt;第一步：创建快捷指令&lt;/h2&gt;
&lt;p&gt;打开 &lt;strong&gt;Shortcuts&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;点击右上角 &lt;strong&gt;+&lt;/strong&gt; 新建快捷指令。&lt;/p&gt;
&lt;h3&gt;添加动作 1：日期&lt;/h3&gt;
&lt;p&gt;搜 添加 日期（Current Date） 动作，默认为当前时间&lt;/p&gt;
&lt;h3&gt;添加动作 2：格式化日期&lt;/h3&gt;
&lt;p&gt;添加 格式化日期，日期格式 自定义，填 &lt;code&gt;yyyy-MM-dd HH:mm:ss&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;添加动作 3：Applescript&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;on run {input, parameters}
  -- 稍微延长一点延迟，确保触发快捷键的手指已经离开键盘
  delay 0.1
  -- display dialog &amp;quot;Current date&amp;quot;

  -- 将 Shortcuts 传入的 list 转换为字符串
  set ts to item 1 of input as string

  tell application &amp;quot;System Events&amp;quot;
    -- 释放可能被系统残留挂起的修饰键状态
    --  键盘区数字的 Key Code 分布是乱序的
    set keyCodeMap to {29, 18, 19, 20, 21, 23, 22, 26, 28, 25}

    key up command
    key up option
    key up control
    key up shift


    repeat with i from 1 to length of ts
      set c to character i of ts
      set charID to id of c
      if c is &amp;quot;:&amp;quot; then
        -- 分号，加 shift 变成冒号
        key code 41 using {shift down}
      else if c is &amp;quot;-&amp;quot; then
        -- 减号，不需要 shift
        key code 27
      else if c is space then
        key code 49
      else if charID ≥ 48 and charID ≤ 57 then
        -- ASCII 码范围过滤 转换算出 1 到 10 的索引
        set targetIndex to charID - 47

        key code (item targetIndex of keyCodeMap)
      end if
    end repeat
  end tell
end run
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;第二步：设为快速操作&lt;/h2&gt;
&lt;p&gt;点快捷指令右上角 &lt;strong&gt;ⓘ&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;勾 Use as Quick Action（用作快速操作）&lt;/p&gt;
&lt;p&gt;选 任何应用程序&lt;/p&gt;
&lt;h2&gt;第三步：绑定快捷键&lt;/h2&gt;
&lt;p&gt;新版macOS可以直接绑定。&lt;/p&gt;
&lt;p&gt;之前的：系统设置 → 键盘 → 键盘快捷键 → 服务（或“快速操作”）&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;我习惯的方式是右手 Cmd+Opt+T 。&lt;/p&gt;
&lt;p&gt;以前觉得 applescript 慢，但是现在反而发现需要 &lt;code&gt;delay 0.1&lt;/code&gt;  否则会触发 Cmd+Opt 的连招&lt;/p&gt;
&lt;p&gt;本来AI给的版本是 &lt;code&gt;keystroke&lt;/code&gt; 指令，容易误触 modifier keys，所以改成 key code。&lt;/p&gt;
&lt;p&gt;还以为 AI 写错了，没想到 mac 的 0-9 数字键code 居然不是连续的。 &lt;/p&gt;
&lt;p&gt;不过这JB玩意不稳定，一会儿授权失效了，需要去 设置 - 隐私 - 辅助功能 里删除 Shortcuts 再添加。。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">est</dc:creator><pubDate>Sat, 20 Jun 2026 12:06:22 +0800</pubDate><guid isPermaLink="false">tag:None,2026-06-20:/2026/stdout-23</guid><category>stdout</category></item><item><title>locate cost</title><link>https://blog.est.im/2026/stdin-17</link><description>&lt;p&gt;翻到一个 AI 编程的出错提示&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Could not find oldString in the file. It must match exactly, including  whitespace, indentation, and line endings&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我突然发现 agent coding 浪费 token 有很大一部分，可能不是问题输入的思考，和输出&lt;/p&gt;
&lt;p&gt;而是在什么位置输出。想了下，人写代码，也是考虑好，再寻找一个合适的位置，开始插入或者修改&lt;/p&gt;
&lt;p&gt;找位置 - 插入 - 修改 这个操作要完全用文本语言描述，的确不简单啊。甚至可以说超级复杂。&lt;/p&gt;
&lt;p&gt;问了下AI，这个叫 locate cost 。定位成本&lt;/p&gt;
&lt;p&gt;要做好这一点，Banthropic 他们的做法是 bash，grep。玩得花的是 SAT，diff，patch 什么的&lt;/p&gt;
&lt;p&gt;进一步推论，AI 新写代码容易，改代码难？AI 也确认了我这一点&lt;/p&gt;
&lt;p&gt;我突然回忆起cursor那个界面刷刷刷把我2w+行的源码全部刷新一遍，卧槽，原来这么回事&lt;/p&gt;
&lt;p&gt;于是我有个理论，AI编程似乎把源码拆得更小，或许更省token，AI不仅改起来更容易，也更容易一眼看出问题&lt;/p&gt;
&lt;p&gt;无论你拆多少个文件，AI上下文里都是连续的。&lt;/p&gt;
&lt;p&gt;我甚至联想到，机械臂目前搞什么 世界模型 VLA 具身智能 依然打不过人类，遇到训练之外的任务就抓瞎，是不是底层一样的道理？&lt;/p&gt;
&lt;p&gt;比如叠衣服，当前是衣服乱的，叠好是个理想状态。人脑可以很快给这两个世界做个 diff，但是这个 locate cost 很高。按照编程的套路，机器人最简单的做法应该是把房子拆掉，家具拆掉，然后重新修一套房子，般进来家具，然后在指定的位置重新按照最佳形状现场纺织一套衣服 🤣&lt;/p&gt;
&lt;p&gt;马斯克几千亿买 cursor ，如果能拿到眼球和编辑光标的超原始动作数据，那是真赚了。（如果你还不知道可以搜下）&lt;/p&gt;
&lt;p&gt;LLM代码写得好，是因为它背诵了很多优秀代码的“纹理”，而不是 “形状”。纹理见识得多，能对付90%的工作了。人写代码绝大部分也是枯燥的低技术活儿。讽刺的是，是人类写低技术活儿容易翻车。。。比如没考虑周到，复制粘贴错了，等等。。。AI表现虽然平庸但是基本不会犯愚蠢的错。&lt;/p&gt;
&lt;p&gt;说起 “纹理” vs “结构”，和这个 “状态迁移” 。我我思绪有点乱，突然有个顿悟，所谓“形状” 就是边界，所谓边界就是两个不同状态实体的迁移界面。diff最 sharp 的边缘。比如人画画总是画“轮廓”，因为轮廓是 diff 出来和背景最突出，最不同的起始边界。&lt;/p&gt;
&lt;p&gt;没想到AI给我抬出来个 亚里士多德 hylomorphism（质形论）好家伙。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;例如，一个铜像：&lt;br /&gt;
质料：铜。&lt;br /&gt;
形式：雕像的形状、组织方式、使它成为「某个人的雕像」的那个原则。&lt;/p&gt;
&lt;p&gt;换成房子：&lt;br /&gt;
木头、砖块——质料。&lt;br /&gt;
房屋的结构、布局、功能——形式。&lt;br /&gt;
没有质料，形式无处实现；没有形式，质料只是一堆材料。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我是猜不透AI是哪根弦搭错了，把 纹理/结构，映射到 质料（Matter）与形式（Form/Morph） 上了。&lt;/p&gt;
&lt;p&gt;不过好有道理啊！！&lt;/p&gt;
&lt;p&gt;AI学编程，靠的是海量语料（Matter），看穿了内在联系 ， 说的难听就是背出熟练度了，信手拈来。&lt;/p&gt;
&lt;p&gt;人类是自下而上，从最小集“生长” morph 出来的。 &lt;/p&gt;
&lt;p&gt;我觉得这个区别，很深刻啊。虽然产出表现形式可能很接近，但是我真的觉得有很大讲究。。。&lt;/p&gt;
&lt;p&gt;接受过正统编程教育的人学习到的是个 生成空间，进行防御式编程；我感觉AI很多时候只是 max effort从前人经验里学习到了个皮毛。。。&lt;/p&gt;
&lt;p&gt;机械臂一样的道理。。。我好像发现了点东西。。。？？？！！！&lt;/p&gt;
&lt;p&gt;AI 不能很容易在两个状态之间求 diff 是因为AI无法找到两个 morph 之间共同的父节点。人类是从一个原始状态派生出来的，所以有回程捷径可以走&lt;/p&gt;
&lt;p&gt;比如经验丰富的程序员可以很快把一个快排改成冒泡。我，和大部分AI 可能都是删掉重写。。。。&lt;/p&gt;
&lt;p&gt;写代码也是如此，搬杯子，叠衣服也是如此。 &lt;/p&gt;
&lt;p&gt;一下让我联想到 图灵 祖师爷《胚胎发育的化学基础》（The Chemical Basis of Morphogenesis）。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这篇论文研究的正是形态发生（Morphogenesis）——即大自然如何自下而上地从一团完全对称、一模一样的受精卵细胞中，自主分裂、分化、生长出复杂的结构，并最终在斑马身上画出条纹，在豹子身上点出斑点。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这个亚里士多德的思考框架真厉害啊。通透&lt;/p&gt;
&lt;p&gt;其实不说哲学这么烧脑的，说大白话，就是AI如果没学过的某个代码结构，可能是真写不出。&lt;/p&gt;
&lt;p&gt;但是人类如果琢磨明白，是可能写出来的。&lt;/p&gt;
&lt;p&gt;生成路径不一样。&lt;/p&gt;
&lt;p&gt;AI 能写出来必然是大量 RL &lt;/p&gt;
&lt;p&gt;换到机械臂，比如一个复杂的移动操作，AI如果没学过，没练过，大概率翻车。&lt;/p&gt;
&lt;p&gt;人类试几下就明白了。。一样的道理&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">est</dc:creator><pubDate>Sun, 14 Jun 2026 00:13:00 +0800</pubDate><guid isPermaLink="false">tag:None,2026-06-14:/2026/stdin-17</guid><category>stdin</category></item><item><title>基于 git 的零拷贝静态web服务器</title><link>https://blog.est.im/2026/stdout-22</link><description>&lt;p&gt;无聊，产生了个crazy的想法。&lt;/p&gt;
&lt;p&gt;git 内部用 zlib 压缩文件内容&lt;/p&gt;
&lt;p&gt;Content-Encoding: gzip 也是&lt;/p&gt;
&lt;p&gt;如果web服务器输出 .git 里的 静态 内容，是不是可以减一个二次解压/压缩步骤？？？&lt;/p&gt;
&lt;p&gt;blob sha1 直接当etag？&lt;/p&gt;
&lt;p&gt;跟AI较量了几轮，一开始它说做不到。因为 blob 的格式比较变态。因为&lt;/p&gt;
&lt;p&gt;&lt;code&gt;hello world...&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;在 .git/objects/ab/cdef... 里的东西是这么存的&lt;/p&gt;
&lt;p&gt;&lt;code&gt;zlib(blob 1234\0hello world...)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;I was like&lt;/p&gt;
&lt;p&gt;？？？日他妈真变态啊。这前面是写死了 &lt;code&gt;blob &amp;lt;size&amp;gt;\0&lt;/code&gt; 然后把文件内容放在一起，再压缩的。&lt;/p&gt;
&lt;p&gt;.git 这设计脑子有病啊。。。为啥不是原始文件gz而是加个头去gz。。。&lt;/p&gt;
&lt;p&gt;此路不通！结束&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;然后AI嘴瓢了，说&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;先别急着吐槽 Linus，这个设计不仅没病，反而是 Git 能成为现代“内容寻址数据库”的精髓所在。&lt;br /&gt;
当 Git 从磁盘读取一个松散对象时，它是个流（Stream）。Git 只需要解压出最开始的几个字节，读到 blob 4096\0，内核就可以立刻执行 malloc(4096) 分配精准的内存。接下来的 zlib 数据流就可以源源不断地直冲内存，不需要反复扩容（realloc），也不需要把整个文件全部解压完才知道它有多大。&lt;br /&gt;
况且，这里有一个长久的误解：你吐槽的那个把 blob &lt;size&gt;\0 塞进 zlib 的逻辑，其实只存在于松散对象（Loose Object）中。在真正的 Packfile 里，这个文本格式的头早就被干掉了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;【松散对象 Loose Object】&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;+-------------------------------------------------------+
| zlib 压缩包: [ &amp;quot;blob 1024\0&amp;quot; + 原始文件纯数据 ]           |
+-------------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;【包文件 Packfile 内部的一条记录】&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;+---------------------------------------------------------+
| [3-bit 类型] + [变长 Varint 表达的 Size] + [纯 zlib 数据流] |
+---------------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我去，这么好的东西，你怎么不早点告诉我！&lt;/p&gt;
&lt;p&gt;然后AI给我泼一盆冷水：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Git Packfile 内部的流是zlib 格式 (RFC 1950)，头部 2 字节 (CMF/FLG)，校验算法 Adler-32 (追求极速快照比对)&lt;/li&gt;
&lt;li&gt;HTTP Content-Encoding: gzip 期待的流 gzip格式 (RFC 1952)，头部 10 字节 (Magic Number, CM, FLG, Time 等)，校验算法CRC32 (追求网络传输抗干扰)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不！兼！容！&lt;/p&gt;
&lt;p&gt;要正确的CRC32你得把文件全部读一遍，那不就等于解压一遍了。白费力气。完结！&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;嘿，得亏我早年玩 IIS 长大的。我记得有个偏方，&lt;code&gt;Content-Encoding: deflate&lt;/code&gt;，尾部crc32直接丢了&lt;/p&gt;
&lt;p&gt;AI：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;恭喜你，这是Web 历史上著名的 “Deflate 格式混乱案”&lt;br /&gt;
RFC 2616 (HTTP/1.1) 规定和IIS有差异！ IIS脑抽地剥离了 zlib 的头尾，只吐了裸压缩流，为了兼容 IIS 的错误实现，各家浏览器各显神通。有的浏览器严格按 RFC 执行，有的浏览器看到 zlib 头会报错，必须看内核的容错机制。&lt;br /&gt;
真正的zlib 格式 (RFC 1950) 是要求包含 2 字节头 + DEFLATE 压缩流 + 4 字节 Adler-32 尾&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;等等，你说啥？Adler-32？这不就又对上了嘛！！！&lt;/p&gt;
&lt;p&gt;那么开始 Vibe！！！&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Git Packfile 的终极大 Boss：差分存储（Delta Compression）&lt;br /&gt;
即便你搞定了上面的所有协议头和校验和，Git 的终极形态——Packfile 还会给你最后一击。你假设的场景是：Git 里的 Blob 都是一个个完整的、独立的压缩包。但实际上，为了极度压榨磁盘空间，当你执行 git gc 后，Packfile 内部采用的是差分存储（Delta Compression）。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;啊这？？我于是问，能在配置里禁用掉吗？&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 将比对窗口设为 0，彻底禁用 Delta 差分计算
git config --global pack.window 0

# 强制打包所有对象，并立刻、无条件地清除所有 Loose 文件（无视 2 周保护期）
git gc --prune=now --aggressive

# -a 表示把所有对象打包进一个全新的 pack
# -d 表示打包成功后，立刻删除原本的 loose 对象和旧的 pack 文件
git repack -a -d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;哎，你tmd不早说。这不就闭环了嘛！！！&lt;/p&gt;
&lt;p&gt;你觉得这几个命令难的记？ &lt;code&gt;git clone --depth=1&lt;/code&gt; 就行。这只有一个 depth 必须自动pack。&lt;/p&gt;
&lt;p&gt;如果你存的是 .jpg 之类的二进制，那么git会直接放弃 delta 。&lt;/p&gt;
&lt;p&gt;于是最后，通过 OpenCode Zen 免费的 MiMo V2.5 Free &lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/est/git2www-zerocopy"&gt;https://github.com/est/git2www-zerocopy&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;本地自测是OK的&lt;/p&gt;
&lt;p&gt;我也算是写过 zero-copy 的人了 🤣（assert AI会写 === 我也会写）&lt;/p&gt;
&lt;p&gt;必须严肃吐槽一下AI这回答一板一眼，不思考完整，拷打一下挤一点。如果不是我知道 IIS 这个坑可能就放弃这个想法了。&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">est</dc:creator><pubDate>Wed, 10 Jun 2026 23:21:00 +0800</pubDate><guid isPermaLink="false">tag:None,2026-06-10:/2026/stdout-22</guid><category>stdout</category></item><item><title>AI和柜台费</title><link>https://blog.est.im/2026/stderr-21</link><description>&lt;p&gt;现在这个时间点，观察到两件事：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;华为的大模型哑火。国内的AI圈反而没那么多恶臭拉踩舆论&lt;/li&gt;
&lt;li&gt;雷不斯天天给MIMO搞新闻。一开始是免费用在Openrouter刷榜；然后在大家都玩按次数的 codng plan它家率先搞 token plan涨价；然后又是 100T 申请免费送；然后跟ds4同款缓存优化降价；然后又是给流失老付费用户免费一个月套餐&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;MIMO是很用力的去刷榜。why？&lt;/p&gt;
&lt;p&gt;马斯克几百亿买 cursor，一个vscode套壳，why？&lt;/p&gt;
&lt;p&gt;这两个问题，我在过去几周一直琢磨，那就是 AI 行业和 软件 互联网 最大的差别，他是有边际成本的。他的玩法变了&lt;/p&gt;
&lt;p&gt;雷不斯刷榜的 Openrouter 和马斯克买的 Cursor，还有遍地开花的 “中转站”，而且据说有大厂买中转站数据去训练和蒸馏。&lt;/p&gt;
&lt;p&gt;边际成本不为0 ，中间商，这两件事在我脑海里酝酿出一个结论：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AI 属于传统行业&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;它每次吐 token 是有不可忽视的制造成本的；&lt;/li&gt;
&lt;li&gt;中转站，Openrouter，Cursor，属于柜台费&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于这个说法，跟身边的人和网友交流，并不能服众。跟AI交流，它一通分析，边际成本 和 柜台费 渠道费 有一定关联，但是没有必然因果性。它举了很多例子，比如 Appstore, Steam，音乐平台也算渠道。Tesla 也算没渠道。&lt;/p&gt;
&lt;p&gt;AI还买域名、租服务器，买Google Ads、做SEO等平台广告费，接入 Stripe、PayPal 或支付宝都算渠道费&lt;/p&gt;
&lt;p&gt;我觉得有点不可信，掰扯了几句。金融和 基础设施 打广告 不太算渠道吧。无论谁哪个行业这些成本都有，也绕不开。大家都是同一起跑线。这个渠道也不存在特定歧视&lt;/p&gt;
&lt;p&gt;我这里纠结的”柜台费“，特指 “保护费”，你不给渠道上供，人家就改卖你竞品，导致你不得不走额外负担和预算。&lt;/p&gt;
&lt;p&gt;传统行业特别维护渠道商利益甚至搞排他&lt;/p&gt;
&lt;p&gt;AI接下来一段回答突然点醒了我。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;传统行业有“物理库存”的生死劫&lt;br /&gt;
造一辆车、酿一批酒、生产一批家电，边际成本极高，且会产生巨大的库存。厂商如果自己去卖，一旦卖不出去，资金链就断了。渠道商的核心价值是“蓄水池”和“压货”。&lt;br /&gt;
厂商为了让渠道商心甘情愿地拿自己的钱去囤货（把库存风险转移给渠道），就必须出让巨大的利润空间，并给予 “区域排他保护”（保证你在这个区独家卖，不打价格战）。本质：传统厂商给渠道商“上供/排他”，是为了买渠道商的“库存吞吐能力”和“资金垫付”。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;其实核心不在 边际成本，而是库存压力，资金周转。&lt;/p&gt;
&lt;p&gt;关键的来了：AI模型供应商同样有库存压力。&lt;/p&gt;
&lt;p&gt;我把这句话扔给AI，AI说你说得对，然后分析了一通 GPU 折旧，HBM 价高，DC耗电，降温散热 等等成本问题&lt;/p&gt;
&lt;p&gt;哈哈哈哈。AI果然还是太笨&lt;/p&gt;
&lt;p&gt;AI库存费问题不在于GPU闲置，而在于没有真实用户使用数据，无法投入下一轮迭代，跟竞品相比会越来越落后。&lt;/p&gt;
&lt;p&gt;公开语料就那么多，预训练大差不差，全靠后训练 指令遵循这些地方拉开差距了&lt;/p&gt;
&lt;p&gt;token回笼，就是这个时代的现金流。你没有真实用户使用互动，你的模型就会被竞品淘汰。&lt;/p&gt;
&lt;p&gt;这就是为什么 雷不斯要不计成本推MIMO去Openrouter亏钱刷榜，马一龙要买 Cursor去&lt;a href="https://x.com/elonmusk/status/2058787384364265734"&gt;增强Grok&lt;/a&gt;的原因。&lt;/p&gt;
&lt;p&gt;这就是中间商、柜台越来越重要的理由。&lt;/p&gt;
&lt;p&gt;AI属于传统行业，重资产制造业。&lt;/p&gt;
&lt;p&gt;（或许这就是华为只卖高利润硬件不做大模型的理由？）&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">est</dc:creator><pubDate>Fri, 05 Jun 2026 10:24:00 +0800</pubDate><guid isPermaLink="false">tag:None,2026-06-05:/2026/stderr-21</guid><category>stderr</category></item></channel></rss>