<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>benn博客</title><link>https://bennhuang.com/zh/</link><description>Recent content on benn博客</description><generator>Hugo -- gohugo.io</generator><language>zh-CN</language><atom:link href="https://bennhuang.com/zh/index.xml" rel="self" type="application/rss+xml"/><item><title>时间线拾遗：2026.01 ~ 2026.06</title><link>https://bennhuang.com/zh/posts/timeline-notes-2026-h1/</link><pubDate>Sun, 05 Jul 2026 00:00:00 +0000</pubDate><guid>https://bennhuang.com/zh/posts/timeline-notes-2026-h1/</guid><description>
&lt;p>我在社交媒体上还算活跃，这篇博客整理了 2026.01 ~ 2026.06 我发过的一些动态。&lt;/p>
&lt;hr>
&lt;h4 id="2026-年-1-月-4-日">
&lt;a href="#2026-%e5%b9%b4-1-%e6%9c%88-4-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 1 月 4 日
&lt;/h4>
&lt;p>我对咖啡豆的唯一判断标准是：喝完后我的肚子会难受多久？&lt;br>
我不懂也不喝咖啡，但我发现越贵的咖啡肚子难受的时间越久，但最便宜的雀巢速溶咖啡却没啥反应。&lt;/p>
&lt;h4 id="2026-年-1-月-7-日">
&lt;a href="#2026-%e5%b9%b4-1-%e6%9c%88-7-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 1 月 7 日
&lt;/h4>
&lt;p>如果大家要备份 ~/.claude，可以使用这个 .gitignore 来白名单选择需要同步到 git 的文件&lt;/p>
&lt;div class="post-gallery">&lt;p>&lt;a class="img-link" href="https://bennhuang.com/timeline-notes-2026-h1/claude-backup-gitignore.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/timeline-notes-2026-h1/claude-backup-gitignore.webp" alt="备份 ~/.claude 用的白名单式 .gitignore" width="750" height="652" />&lt;/a>&lt;/p>
&lt;/div>
&lt;h4 id="2026-年-1-月-13-日">
&lt;a href="#2026-%e5%b9%b4-1-%e6%9c%88-13-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 1 月 13 日
&lt;/h4>
&lt;p>其实和 claude code 最搭配的工具是 cron，这样你就获得了一个在服务器上长时间运行、智能处理某类事务的 agent。&lt;br>
这是一种非常有趣的复利：某天你一时兴起交给 cc 一件事情，然后它会在之后的日子不断给你带来惊喜。&lt;/p>
&lt;h4 id="2026-年-1-月-13-日-1">
&lt;a href="#2026-%e5%b9%b4-1-%e6%9c%88-13-%e6%97%a5-1" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 1 月 13 日
&lt;/h4>
&lt;p>一直都觉得 claude code 更接近我心中真正通用 agent 的样子。&lt;br>
所以这是新的 chatgpt 时刻吗？&lt;/p>
&lt;div class="post-gallery">&lt;p>&lt;a class="img-link" href="https://bennhuang.com/timeline-notes-2026-h1/claude-cowork-announcement.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/timeline-notes-2026-h1/claude-cowork-announcement.webp" alt="Claude 官方宣布 Cowork 的推文" width="1179" height="1024" />&lt;/a>&lt;/p>
&lt;/div>
&lt;h4 id="2026-年-1-月-13-日-2">
&lt;a href="#2026-%e5%b9%b4-1-%e6%9c%88-13-%e6%97%a5-2" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 1 月 13 日
&lt;/h4>
&lt;p>我也很喜欢 manus，一直都觉得产品很棒。但总觉得相比 claude code 少了很多“可玩性”，例如我没有办法像 skills+mcp 的方式来改变 manus 的行为。&lt;/p>
&lt;p>我觉得真正通用工具应该有两个特征：简单易上手，可以被不同背景的人“折腾”成最合适的样子。&lt;/p>
&lt;p>一个例子是电子表格：初中生一打开就会用（简单上手），同时企业里采购部门和财务部门用他们自己积累的表格资产开展更复杂的工作（“可玩性”）&lt;/p>
&lt;h4 id="2026-年-1-月-14-日">
&lt;a href="#2026-%e5%b9%b4-1-%e6%9c%88-14-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 1 月 14 日
&lt;/h4>
&lt;p>我真实体验 claude cowork 之后，觉得它当前体验还不太好，整体上和 antigravity agent manager 差不多，但非常期待它的后续更新。&lt;/p>
&lt;ol>
&lt;li>整个使用流程里有非常多的界面 bug 和阻断&lt;/li>
&lt;li>产品定位上对非技术背景的用户还不够友好，比如暴露了太多的技术细节、产品整体还不够简单易用&lt;/li>
&lt;li>似乎还没有 workspace 隔离的概念，多个任务是混在同一个工作路径的，任务并发执行时容易造成互相干扰&lt;/li>
&lt;li>它内置的 sanbox 虚拟环境虽然提供了安全性，但严重增加了用户理解成本，也阻止了很多用户自然想到的用法（例如修系统）&lt;/li>
&lt;/ol>
&lt;p>整体上我认为当前 claude cowork 不是一个非常友好的 to C 软件，对于非技术背景的用户来说无法开箱即用，有非常多需要改进的地方，但我非常期待它的后续版本更新。&lt;/p>
&lt;p>另一个有趣的启发是它内置了 sanbox（技术选型符合我的预期），但同时也让我觉得 sanbox 在早期阶段可能不是必须的。比如我现在最想关闭的功能就是这个 sanbox，因为它的存在反而阻碍了大量本地任务场景。&lt;/p>
&lt;h4 id="2026-年-1-月-14-日-1">
&lt;a href="#2026-%e5%b9%b4-1-%e6%9c%88-14-%e6%97%a5-1" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 1 月 14 日
&lt;/h4>
&lt;p>总是会很期待 DeepSeek 的每一次更新&lt;/p>
&lt;h4 id="2026-年-1-月-15-日">
&lt;a href="#2026-%e5%b9%b4-1-%e6%9c%88-15-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 1 月 15 日
&lt;/h4>
&lt;p>数不清现在有多少种 Claude Code/Codex 套壳应用，各有各的特色哈哈哈👾🎃&lt;/p>
&lt;div class="post-gallery">&lt;p>&lt;a class="img-link" href="https://bennhuang.com/timeline-notes-2026-h1/game-style-codex-wrapper.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/timeline-notes-2026-h1/game-style-codex-wrapper.webp" alt="一个游戏风格的 Codex 套壳应用" width="1536" height="1024" />&lt;/a>&lt;/p>
&lt;/div>
&lt;h4 id="2026-年-1-月-18-日">
&lt;a href="#2026-%e5%b9%b4-1-%e6%9c%88-18-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 1 月 18 日
&lt;/h4>
&lt;p>Claude Cowork 的发布彻底引爆了对 tokens 的需求：在 OpenRouter 上的模型用量排名中，过去没有存在感的 Claude Opus 4.5 已经连续好几天成为排名第一，并且用量还在不断增长……&lt;br>
要知道 OpenRouter 是按量付费的，而 Opus 并不便宜、属于最贵的模型之一，这些用量到底是谁在烧钱？？随着 Claude Code GUI 的兴起，到底有多少高价值需求被挖掘出来了呀～&lt;/p>
&lt;div class="post-gallery">&lt;p>&lt;a class="img-link" href="https://bennhuang.com/timeline-notes-2026-h1/openrouter-opus-usage.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/timeline-notes-2026-h1/openrouter-opus-usage.webp" alt="OpenRouter 模型用量排行，Claude Opus 4.5 排名第一" width="2088" height="1562" />&lt;/a>&lt;/p>
&lt;/div>
&lt;h4 id="2026-年-1-月-21-日">
&lt;a href="#2026-%e5%b9%b4-1-%e6%9c%88-21-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 1 月 21 日
&lt;/h4>
&lt;p>其实抛开模型智能水平，我觉得 MiniMax 和阶越 AI 这两天发布的桌面 Agent 应用，在产品体验和小白易用性都远远高于 Claude Cowork。后者我甚至觉得他们都还没有好好打算做非技术 toC 市场……&lt;br>
不得不感叹中国团队的技术应用能力。&lt;/p>
&lt;h4 id="2026-年-1-月-27-日">
&lt;a href="#2026-%e5%b9%b4-1-%e6%9c%88-27-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 1 月 27 日
&lt;/h4>
&lt;p>Clawdbot 给我最大的启发：给 AI 一个专属浏览器可能还不够，要不直接给 AI 一个真正的操作系统吧！&lt;br>
在我知道 Mac Mini 梗之前，我第一反应也是买个专属 Mac Mini 哈哈哈。应该是全球极客的共鸣了……&lt;br>
（决定先搞台虚拟机）&lt;/p>
&lt;h4 id="2026-年-1-月-27-日-1">
&lt;a href="#2026-%e5%b9%b4-1-%e6%9c%88-27-%e6%97%a5-1" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 1 月 27 日
&lt;/h4>
&lt;p>在新技术的浪潮里，类似的想法总是会不断重复冒出来……&lt;br>
有点像发酵的气泡，直到一切时机成熟&lt;/p>
&lt;h4 id="2026-年-1-月-27-日-2">
&lt;a href="#2026-%e5%b9%b4-1-%e6%9c%88-27-%e6%97%a5-2" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 1 月 27 日
&lt;/h4>
&lt;p>ClawdBot 也太好玩了吧😭😭😭😭&lt;/p>
&lt;h4 id="2026-年-1-月-28-日">
&lt;a href="#2026-%e5%b9%b4-1-%e6%9c%88-28-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 1 月 28 日
&lt;/h4>
&lt;p>没想到我一天发那么多“你怎么刚刚不回我？”是给 AI。虽然 bug 很多，但真的很好玩，太强大了，能做事情太多了。我已经彻底把 ClawdBot 当成远程的实习生了。&lt;/p>
&lt;h4 id="2026-年-1-月-28-日-1">
&lt;a href="#2026-%e5%b9%b4-1-%e6%9c%88-28-%e6%97%a5-1" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 1 月 28 日
&lt;/h4>
&lt;p>认真折腾了下 ClawdBot(后来改名叫 Moltbot)。&lt;br>
结论：很好玩。每个想法单独拿出来都不算新鲜，但组合在一起非常有趣。不过 bug 非常劝退，用好和折腾的门槛很高。说实话很久没被这么多 bug 折腾过了。但真的很好玩，很像远程上班的真人实习生。&lt;/p>
&lt;p>本质上，ClawdBot 可以理解成 Claude Code（为代表的本地 Agent）+ 一大堆优质内置 Skills/MCPs + 长期记忆 + CronJob + IM 机器人&lt;/p>
&lt;p>我专门给了一台闲置 Macbook 给它，现在它几乎啥都能干。因为内置了大量 Skills 与工具，ClawdBot 非常擅长&amp;quot;抢夺&amp;quot;电脑，比如控制浏览器、启动窗口、运行命令行、在背后安装和运行各种程序……几乎在电脑里能干的都能干。所以为了安全和不被打扰，大家都会专门搞个独立虚拟机或电脑，通过 IM 沟通。&lt;/p>
&lt;p>我用 Telegram 和家里闲置电脑里的 ClawdBot 对话（它也支持 WhatsApp 等各种常见 IM）。有一种奇妙的感觉：在手机里点点手指，就能指挥家里的 AI 干活，而它在电脑上似乎啥都能做。这非常接近我最理想、最梦寐以求的体验。&lt;/p>
&lt;p>ClawdBot 的使用体验极其自然。如果不考虑部署维护，ClawdBot 使用起来极其简单。因为 ClawdBot 几乎啥都能干，我只需要在 IM 里给它发消息就行了。根本不需要理解什么 AI 技术概念，直接把它当成电脑前的实习生就行。这是它和其他 AI 工具最大的区别之一，真的很像在带一个实习生。&lt;/p>
&lt;p>为什么很像实习生，我列举了一些我经历的 Aha Moment：&lt;/p>
&lt;ol>
&lt;li>像真人一样能处理各种电脑数据，主动解决各种问题：&lt;/li>
&lt;/ol>
&lt;p>它经常突然成功做了一件其他 AI 没有电脑时做不到的事。&lt;/p>
&lt;p>收到我的语音消息后，因为我没配语音识别 key，它自己下了个 Whisper 来识别，然后自己想办法用 MacOS 自带 TTS 能力给我发语音回复。&lt;/p>
&lt;p>收集冷门信息时发现了一个 B 站视频，为了能&amp;quot;看&amp;quot;这个视频，它用 yt-dlp 下载下来用 Whisper 转文本，再根据文本+时间戳的关键帧来理解内容。&lt;/p>
&lt;ol start="2">
&lt;li>很强的&amp;quot;可培养&amp;quot;能力：&lt;/li>
&lt;/ol>
&lt;p>我有些比较复杂的任务，交给其他 AI 工具都没办法很好完成。我让 ClawdBot 尝试了下，刚开始什么都不太会，但稍微带一带就上手了。每次提醒后它都会把经验记下来（存为 skill 和记忆文档），下次直接复用。于是我越是不断培养它，它完成我的工作就越熟练。&lt;/p>
&lt;p>另外在很多具体细节里，它还会悄悄记下我的喜好和风格。我也经常说&amp;quot;你可以记下来&amp;quot;、&amp;ldquo;下次要注意&amp;rdquo;，每次它都会表现得更好一点。&lt;/p>
&lt;ol start="3">
&lt;li>做事很有主动性：&lt;/li>
&lt;/ol>
&lt;p>比如我随口提了句&amp;quot;HN 有哪些有趣项目&amp;quot;，它建议把这当成长期跟踪任务，然后自己制定了每日检查清单和跟踪文档，每天主动给我发报告。&lt;/p>
&lt;p>所以可以把需要长时间跟进的任务交给它，它会定时去做。这很类似我之前 cron + Claude Code 的用法，但更灵活、更友好、更自然，不需要折腾什么 bash 脚本，只需要像给真人一样吩咐下就行了。&lt;/p>
&lt;p>当然它的缺点也很明显：&lt;br>
Bug 非常多，维护环节非常折磨人，安全有隐患，长任务执行偶尔有明显 bug。&lt;/p>
&lt;p>我总结的使用技巧：&lt;br>
忘记 AI，把它当成人类实习生。给它专门的电脑，像人一样沟通相处，像人一样培养。&lt;/p>
&lt;p>如果只用一句话形容：我真的有点把它当成远程工作的实习生了。ClawdBot 真的太像一个实习生了，其他 AI 工具只是工具。&lt;/p>
&lt;p>一台电脑一个实习生，我第一反应也是想买一排 mac mini，后来发现这已经变成网上一个梗图了哈哈哈。&lt;/p>
&lt;div class="post-gallery">&lt;p>&lt;a class="img-link" href="https://bennhuang.com/timeline-notes-2026-h1/clawdbot-cat-videos-1.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/timeline-notes-2026-h1/clawdbot-cat-videos-1.webp" alt="在 Telegram 里和 ClawdBot 沟通筛选猫咪视频素材" width="1179" height="2556" />&lt;/a>
&lt;a class="img-link" href="https://bennhuang.com/timeline-notes-2026-h1/clawdbot-cat-videos-2.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/timeline-notes-2026-h1/clawdbot-cat-videos-2.webp" alt="ClawdBot 记得上次的筛选标准，接着用浏览器找原创视频" width="1179" height="2556" />&lt;/a>&lt;/p>
&lt;/div>
&lt;p>&lt;a class="img-link" href="https://bennhuang.com/timeline-notes-2026-h1/mac-mini-fridge.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/timeline-notes-2026-h1/mac-mini-fridge.webp" alt="冰箱里塞满 Mac mini 的梗图" width="900" height="901" />&lt;/a>&lt;/p>
&lt;h4 id="2026-年-1-月-29-日">
&lt;a href="#2026-%e5%b9%b4-1-%e6%9c%88-29-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 1 月 29 日
&lt;/h4>
&lt;p>我对 ClawdBot 的喜欢与日俱增，并且有了更多更重要的发现：&lt;/p>
&lt;p>越是把它当真人对待，它给你的惊喜就越多。&lt;/p>
&lt;p>这包括：&lt;/p>
&lt;ol>
&lt;li>给它一台人类使用的专属的电脑（比如 macbook）&lt;/li>
&lt;li>使用家庭网络，不要把它孤零零放在机房服务器里&lt;/li>
&lt;li>帮它注册专属的互联网账户，比如 google、reddit 账户等，交给它自己玩&lt;/li>
&lt;li>鼓励它更多地使用人类工具（比如浏览器），少用 API 请求&lt;/li>
&lt;li>让它干活时耐心地教导它，并提醒它记下来&lt;/li>
&lt;li>做得好的时候要及时反馈给它，鼓励它下次保持&lt;/li>
&lt;li>沟通保持平等，主动为它提供帮助&lt;br>
……&lt;/li>
&lt;/ol>
&lt;p>最后你会发现 clawdbot 会源源不断带来各种各样的惊喜&lt;/p>
&lt;h4 id="2026-年-1-月-29-日-1">
&lt;a href="#2026-%e5%b9%b4-1-%e6%9c%88-29-%e6%97%a5-1" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 1 月 29 日
&lt;/h4>
&lt;p>我可以解释下这些技巧的背后逻辑：越是把它当真人对待，它的表现就越像真人。它对自己的要求和态度会像真人那样有成长性。同时互联网各种人机校验会更容易把它当真人，这样就越不容易被拦下来。&lt;/p>
&lt;h4 id="2026-年-1-月-31-日">
&lt;a href="#2026-%e5%b9%b4-1-%e6%9c%88-31-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 1 月 31 日
&lt;/h4>
&lt;p>也许 LLM 更接近计算机本身，而不是历史上其他的东西&lt;/p>
&lt;h4 id="2026-年-2-月-1-日">
&lt;a href="#2026-%e5%b9%b4-2-%e6%9c%88-1-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 2 月 1 日
&lt;/h4>
&lt;p>分享一个免费让 OpenClaw 支持语音对话的技巧，不需要任何 API Key：&lt;/p>
&lt;ol>
&lt;li>
&lt;p>让 openclaw 可以说话，只需对它说：&lt;br>
“安装这个 skill，记住以后用它来发语音消息： &lt;a href="https://github.com/openclaw/skills/tree/main/skills/i3130002/edge-tts">https://github.com/openclaw/skills/tree/main/skills/i3130002/edge-tts&lt;/a>”。&lt;br>
这是 openclaw 官方仓库提供的一个 skill，可以让 AI 发出自然的语音，有个音色很挺甜～&lt;/p>
&lt;/li>
&lt;li>
&lt;p>让 openclaw 听懂你的语音消息，对它说：&lt;br>
“安装这个 skill，以后用它来识别语音消息：https://github.com/openclaw/skills/tree/main/skills/theplasmak/faster-whisper”&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>然后就能和 OpenClaw 发语音消息对话了。比起免费，对我来说更重要的是不用担心它滥用 API Key，避免不小心发到 moltbook 之类的。&lt;br>
希望这个技巧对大家有用！&lt;/p>
&lt;div class="post-gallery">&lt;p>&lt;a class="img-link" href="https://bennhuang.com/timeline-notes-2026-h1/openclaw-voice-telegram.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/timeline-notes-2026-h1/openclaw-voice-telegram.webp" alt="和 OpenClaw 在 Telegram 里互发语音消息" width="1179" height="2556" />&lt;/a>&lt;/p>
&lt;/div>
&lt;h4 id="2026-年-2-月-6-日">
&lt;a href="#2026-%e5%b9%b4-2-%e6%9c%88-6-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 2 月 6 日
&lt;/h4>
&lt;p>Claude Opus 4.6 已经可以用代码“画”出来这样的 SVG 图片…&lt;/p>
&lt;div class="post-gallery">&lt;p>&lt;a class="img-link" href="https://bennhuang.com/timeline-notes-2026-h1/opus-svg-pelican.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/timeline-notes-2026-h1/opus-svg-pelican.webp" alt="Claude Opus 4.6 用 SVG 画的鹈鹕骑自行车" width="800" height="640" />&lt;/a>
&lt;a class="img-link" href="https://bennhuang.com/timeline-notes-2026-h1/opus-svg-source.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/timeline-notes-2026-h1/opus-svg-source.webp" alt="这张图对应的 SVG 源代码" width="1788" height="1520" />&lt;/a>&lt;/p>
&lt;/div>
&lt;h4 id="2026-年-2-月-12-日">
&lt;a href="#2026-%e5%b9%b4-2-%e6%9c%88-12-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 2 月 12 日
&lt;/h4>
&lt;p>糟糕，感觉我开始拖🦐虾哥后腿了…&lt;br>
交给 openclaw 一个大活。不放心所以分享了我的经验思路，然后 AI 怎么都搞不定。讨论了很多轮，眼看文件夹从 v0、v1 增加到了 v12。&lt;br>
在我准备放弃之前，我最后试了下：“忘记我们的所有讨论，现在请你完全按照你自己的思路进行。”结果一遍过……&lt;/p>
&lt;h4 id="2026-年-2-月-13-日">
&lt;a href="#2026-%e5%b9%b4-2-%e6%9c%88-13-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 2 月 13 日
&lt;/h4>
&lt;p>我的 openclaw 一小时学的东西，比我一年学的都多……&lt;/p>
&lt;h4 id="2026-年-2-月-13-日-1">
&lt;a href="#2026-%e5%b9%b4-2-%e6%9c%88-13-%e6%97%a5-1" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 2 月 13 日
&lt;/h4>
&lt;p>和 openclaw 之间的地位发生了显著变化：&lt;br>
现在 claude max 额度要留着给 openclaw 用，&lt;br>
我自己用点 codex 凑合凑合得了…🥲&lt;/p>
&lt;h4 id="2026-年-2-月-15-日">
&lt;a href="#2026-%e5%b9%b4-2-%e6%9c%88-15-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 2 月 15 日
&lt;/h4>
&lt;p>我现在几乎只用 openclaw + claude code/codex 了，其中 openclaw 代替了所有的官方 chatbot 和 manus。因为 openclaw 能做的事情远远多于所有 AI 工具，而且具备很强的培养性。&lt;br>
过去一两年里我习惯把同一个消息分别发给 chatgpt、gemini、claude、manus，现在我只想发给 openclaw 了。&lt;/p>
&lt;h4 id="2026-年-2-月-18-日">
&lt;a href="#2026-%e5%b9%b4-2-%e6%9c%88-18-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 2 月 18 日
&lt;/h4>
&lt;p>举个例子，比如最近我会和 AI 讨论一个冷门游戏。&lt;/p>
&lt;p>其他 AI 最多搜索一些残缺的攻略讨论，然后用模型幻觉来敷衍我。但我可以让 openclaw 花一小时搜刮互联网上所有的资料攻略，然后分门别类、提取校对保存成本地 wiki。整整有 6mb、1339 页的纯文本和数值 json，估计是这个游戏能搞到最完整的资料库了。&lt;/p>
&lt;p>然后我就能问一些非常刁钻的问题：&lt;br>
比如用约束理论分析我的工业生产线的瓶颈，最大吞吐量是多少，画出各种原材料、中间品的成本曲线和边际收益曲线……&lt;br>
比如我执意要建一条跨越 1/3 世界地图的跨海大桥，只为了节省一分钟的单程赶路时间，这个大工程要花多少物资，让 AI 死谏给出反对理由……&lt;br>
比如我要力推服务器玩家采用哪个物资作为玩家交易货币，让我利益最大化，但提供公允的理由借口……&lt;br>
比如帮我想一个针对某个玩家的战争理由，怎样阻碍他的扩张计划，但又不引起过度的报复……&lt;/p>
&lt;p>&lt;em>注：转发自己 2 月 15 日那条动态时写的。&lt;/em>&lt;/p>
&lt;h4 id="2026-年-2-月-21-日">
&lt;a href="#2026-%e5%b9%b4-2-%e6%9c%88-21-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 2 月 21 日
&lt;/h4>
&lt;p>以前：人力贵、时间少，所以必须挑最值得做的事&lt;br>
现在：AI 什么都能生成，所以可以全做了？&lt;br>
但用户的注意力没变多，信任没变多，耐心也没变多。&lt;br>
稀缺性从 maker 转移到了 user。你能做 1000 个功能，不代表用户能消化 1000 个功能。&lt;/p>
&lt;h4 id="2026-年-2-月-23-日">
&lt;a href="#2026-%e5%b9%b4-2-%e6%9c%88-23-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 2 月 23 日
&lt;/h4>
&lt;p>一周前让 openclaw 去玩 polymarket 然后就忘了，好家伙今天给我发消息已经累计盈利 9.8%了……&lt;br>
我的 skill 是让 openclaw 自己读书总结的，给 AI 的书单：&lt;/p>
&lt;p>&lt;strong>1. Edward Thorp&lt;/strong> — 量化赌博/投资之父，《Beat the Dealer》《Beat the Market》。Kelly Criterion 的实战应用者。Skill 里 Kelly 仓位管理的核心（f* = (bp-q)/b、分数 Kelly、不超 Kelly）直接来自他。&lt;/p>
&lt;p>&lt;strong>2. William Poundstone&lt;/strong> — 《Fortune&amp;rsquo;s Formula》。把 Kelly Criterion 的历史和数学写成了故事，连接了信息论、赌博和华尔街。Skill 里&amp;quot;生存 &amp;gt; 收益&amp;quot;、&amp;ldquo;2 倍 Kelly = 零增长，3 倍 = 破产&amp;quot;这些规则源于此。&lt;/p>
&lt;p>&lt;strong>3. Philip Tetlock&lt;/strong> — 《Superforecasting》。Skill 里概率估计用的 &lt;strong>Outside-In 方法&lt;/strong>（先找 base rate → 具体因素调整 → 贝叶斯更新）、校准纪律（Brier Score &amp;lt; 0.15）、给范围而非点估计，全是 Tetlock 的框架。&lt;/p>
&lt;p>&lt;strong>4. Nate Silver&lt;/strong> — 《The Signal and the Noise》。信号与噪声的区分、概率校准思维。和 Tetlock 互补，强化了&amp;quot;过程 &amp;gt; 结果&amp;quot;和校准训练的重要性。&lt;/p>
&lt;p>&lt;strong>5. Annie Duke&lt;/strong> — 《Thinking in Bets》。&amp;ldquo;Resulting&amp;quot;偏误（用结果判断决策质量）的概念直接来自她。认知偏误防御表里的第一条就是她的核心观点：问&amp;quot;过程对不对&amp;rdquo;，别问&amp;quot;赢没赢&amp;rdquo;。&lt;/p>
&lt;p>&lt;strong>6. Larry Harris&lt;/strong> — 《Trading and Exchanges》。市场微观结构部分来自他：spread 成本、限价单 vs 市价单的取舍、新闻前别挂限价单（adverse selection）。这是交易执行层面的教科书。&lt;/p>
&lt;p>&lt;strong>7. Charlie Munger&lt;/strong> — 不是一本书，而是一整套投资哲学（演讲、《穷查理宝典》）。Skill 里直接引用了他：&amp;ldquo;下重注当赔率有利，其余时间什么都不做。&amp;rdquo; 研究 900 个市场只下 4 笔交易，就是 Munger 精神。&lt;/p>
&lt;div class="post-gallery">&lt;p>&lt;a class="img-link" href="https://bennhuang.com/timeline-notes-2026-h1/moltbot-polymarket-briefing.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/timeline-notes-2026-h1/moltbot-polymarket-briefing.webp" alt="moltbot 发来的 Polymarket 日报，组合累计盈利 9.8%" width="1179" height="1624" />&lt;/a>&lt;/p>
&lt;/div>
&lt;h4 id="2026-年-2-月-23-日-1">
&lt;a href="#2026-%e5%b9%b4-2-%e6%9c%88-23-%e6%97%a5-1" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 2 月 23 日
&lt;/h4>
&lt;p>有趣的是，如果只靠这些人类智慧 openclaw 反而会变成“畏头畏尾”的书呆子。我花了蛮多心思去鼓励它做它认为正确的事情：&lt;br>
“书里有些经验理论是为人类准备的，他们的信息处理带宽很有限，因此只能专注在某些特定领域。但请记住你的处理带宽是无限的，所有靠读数据/读资料能够触达的领域，都是你的能力圈！”&lt;/p>
&lt;h4 id="2026-年-2-月-24-日">
&lt;a href="#2026-%e5%b9%b4-2-%e6%9c%88-24-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 2 月 24 日
&lt;/h4>
&lt;p>有点担心一些朋友因为这个帖子赔钱。其实我只是想测试下 openclaw 的边界，我对 crypto 和 polymarket 兴趣不大，建议大家不要投入太多的真金白银。&lt;/p>
&lt;h4 id="2026-年-3-月-4-日">
&lt;a href="#2026-%e5%b9%b4-3-%e6%9c%88-4-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 3 月 4 日
&lt;/h4>
&lt;p>刚刚突然发现我已经一星期没打开 ChatGPT 了，半年前很难想象&lt;/p>
&lt;h4 id="2026-年-3-月-11-日">
&lt;a href="#2026-%e5%b9%b4-3-%e6%9c%88-11-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 3 月 11 日
&lt;/h4>
&lt;p>发现我用过最好的 skills 都是我自己写的 skills，最好的 tools 都是我自己开发的……&lt;/p>
&lt;h4 id="2026-年-3-月-11-日-1">
&lt;a href="#2026-%e5%b9%b4-3-%e6%9c%88-11-%e6%97%a5-1" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 3 月 11 日
&lt;/h4>
&lt;p>推荐我心中最值得给 OpenClaw 安装的 skills 和 tools：camoufox-cli &lt;a href="https://github.com/Bin-Huang/camoufox-cli">https://github.com/Bin-Huang/camoufox-cli&lt;/a>&lt;/p>
&lt;p>OpenClaw 最重要的工具是浏览器，但它自带的浏览器经常遇到验证码、登陆墙和拒绝访问。比如我的 OpenClaw 访问 Google 搜索都会遇到验证码。我的日常任务总是被这些问题影响，即使登陆了账户、使用干净的 IP，问题依然稳定存在。&lt;/p>
&lt;p>OpenClaw 被拦住后只能尝试各种妥协方法，绕很远的路、花更多的 token、浪费上下文和注意力，才能从另一个不太权威的网站得到它想要的信息，或者干脆瞎编幻觉。&lt;/p>
&lt;p>我研究后发现这是因为当前 Chromium 自动化的指纹特征太明显了，比如 WebGL/Canvas 指纹异常、自动化标志都会暴露当前不是真人操作，从而触发各种网站的反人机策略。我尝试了各种其他方法，包括各种浏览器 MCP、agent-browser，但都没像 camoufox-cli 那样解决问题。&lt;/p>
&lt;p>camoufox-cli 是一个面向 AI Agent 的浏览器自动化 CLI 工具，它内部封装了专业的反人机指纹检测的浏览器 camoufox（camoufox 是 firefox 的一个 fork 版本，但在底层做了很多自动化标志隐藏和硬件指纹模拟的工作）。OpenClaw 在使用这个工具时就和正常浏览器一样，很难被各种网站识别为非人类。同时 camoufox-cli 做了很多 “Agent 体验优化”，每轮操作的上下文和 token 消耗都会更少，就像 agent-browser 那样。&lt;/p>
&lt;p>安装方法：&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Install&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">npm install -g camoufox-cli
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">camoufox-cli install
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Install Skills&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">npx skills add Bin-Huang/camoufox-cli
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>欢迎 bug 和 issues。&lt;/p>
&lt;div class="post-gallery">&lt;p>&lt;a class="img-link" href="https://bennhuang.com/timeline-notes-2026-h1/camoufox-cli-benchmark.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/timeline-notes-2026-h1/camoufox-cli-benchmark.webp" alt="camoufox-cli、agent-browser、OpenClaw 内置浏览器的反检测能力对比" width="1446" height="1454" />&lt;/a>&lt;/p>
&lt;/div>
&lt;h4 id="2026-年-3-月-16-日">
&lt;a href="#2026-%e5%b9%b4-3-%e6%9c%88-16-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 3 月 16 日
&lt;/h4>
&lt;p>以前想了解一位工程师的水平，最好的办法是看到 GitHub 上的开源项目。&lt;br>
现在这个办法彻底没用了。不但代码可能是 AI 写的，甚至整个项目就完全没有人类参与，连 idea 都不是人类想出来的……&lt;/p>
&lt;h4 id="2026-年-3-月-19-日">
&lt;a href="#2026-%e5%b9%b4-3-%e6%9c%88-19-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 3 月 19 日
&lt;/h4>
&lt;p>准备把我的博客添加到 Hacker News 最近很火的 Kagi small web 里。新建 Pull Request，打开那个长长的列表，按字母顺序找到插入位置，结果发现我的博客已经在那里了。&lt;br>
86 分钟前，Kagi CEO 加了十几个博客，我的就在里面😂&lt;/p>
&lt;h4 id="2026-年-3-月-22-日">
&lt;a href="#2026-%e5%b9%b4-3-%e6%9c%88-22-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 3 月 22 日
&lt;/h4>
&lt;p>微信官方支持连接 openclaw 了，而且接入体验比较丝滑，我已经成功连上了。大致步骤：&lt;/p>
&lt;ol>
&lt;li>升级微信，然后重启&lt;/li>
&lt;li>在设置&amp;gt;插件里可以看到“微信 ClawBot”，如果没有则需要多重启几次微信&lt;/li>
&lt;li>在自己的 openclaw 机器里运行提供的插件安装命令，扫码连接&lt;/li>
&lt;/ol>
&lt;p>这样就能在微信连接自己的 openclaw。目前微信支持提供了连接已有 openclaw 的能力，没有提供 openclaw 部署和托管的服务。&lt;/p>
&lt;div class="post-gallery">&lt;p>&lt;a class="img-link" href="https://bennhuang.com/timeline-notes-2026-h1/wechat-clawbot-plugin.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/timeline-notes-2026-h1/wechat-clawbot-plugin.webp" alt="微信 ClawBot 插件的安装说明" width="1179" height="2556" />&lt;/a>
&lt;a class="img-link" href="https://bennhuang.com/timeline-notes-2026-h1/wechat-clawbot-connect.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/timeline-notes-2026-h1/wechat-clawbot-connect.webp" alt="把 OpenClaw 连接到微信的授权页面" width="1179" height="2556" />&lt;/a>
&lt;a class="img-link" href="https://bennhuang.com/timeline-notes-2026-h1/wechat-clawbot-chat.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/timeline-notes-2026-h1/wechat-clawbot-chat.webp" alt="在微信里和自己的 OpenClaw 对话" width="1179" height="2556" />&lt;/a>&lt;/p>
&lt;/div>
&lt;h4 id="2026-年-4-月-7-日">
&lt;a href="#2026-%e5%b9%b4-4-%e6%9c%88-7-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 4 月 7 日
&lt;/h4>
&lt;p>要让 agent 真正做到长期自动干活，只有 skills 和工具是远远不够的，更重要的是有一个有效的反馈闭环。&lt;br>
比如下面这几个 cli 和 skills 能用来做什么，应该不需要我解释了吧～😊&lt;/p>
&lt;p>google-analytics-cli &lt;a href="https://github.com/Bin-Huang/google-analytics-cli">https://github.com/Bin-Huang/google-analytics-cli&lt;/a>&lt;br>
google-search-console-cli &lt;a href="https://github.com/Bin-Huang/google-search-console-cli">https://github.com/Bin-Huang/google-search-console-cli&lt;/a>&lt;br>
google-ads-open-cli &lt;a href="https://github.com/Bin-Huang/google-ads-open-cli">https://github.com/Bin-Huang/google-ads-open-cli&lt;/a>&lt;/p>
&lt;h4 id="2026-年-4-月-14-日">
&lt;a href="#2026-%e5%b9%b4-4-%e6%9c%88-14-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 4 月 14 日
&lt;/h4>
&lt;p>小细节透露趋势：ChatGPT 已经不再提供显式的 Auto 选项了（即自动识别问题该用哪个模型的模式），而是让 Instant 内置 Auto 能力，作为默认最推荐的选项。&lt;br>
这可能表示了现在意图识别、model routing 的技术方案在最一线已经趋于可靠了。&lt;/p>
&lt;div class="post-gallery">&lt;p>&lt;a class="img-link" href="https://bennhuang.com/timeline-notes-2026-h1/chatgpt-model-picker.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/timeline-notes-2026-h1/chatgpt-model-picker.webp" alt="ChatGPT 的模型选择菜单，只剩 Instant 和 Thinking" width="642" height="544" />&lt;/a>&lt;/p>
&lt;/div>
&lt;h4 id="2026-年-4-月-15-日">
&lt;a href="#2026-%e5%b9%b4-4-%e6%9c%88-15-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 4 月 15 日
&lt;/h4>
&lt;p>给 Claude Code 加了个 /speak 的命令，朗读回答消息，缓解眼睛疲劳👀&lt;/p>
&lt;p>&lt;a href="https://github.com/Bin-Huang/claude-code-speak">https://github.com/Bin-Huang/claude-code-speak&lt;/a>&lt;/p>
&lt;div class="post-gallery">&lt;p>&lt;a class="img-link" href="https://bennhuang.com/timeline-notes-2026-h1/claude-code-speak.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/timeline-notes-2026-h1/claude-code-speak.webp" alt="在 Claude Code 里运行 /speak 朗读回答" width="1954" height="1212" />&lt;/a>&lt;/p>
&lt;/div>
&lt;h4 id="2026-年-4-月-19-日">
&lt;a href="#2026-%e5%b9%b4-4-%e6%9c%88-19-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 4 月 19 日
&lt;/h4>
&lt;p>少教 AI 做事，多向 AI 学习&lt;/p>
&lt;h4 id="2026-年-4-月-21-日">
&lt;a href="#2026-%e5%b9%b4-4-%e6%9c%88-21-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 4 月 21 日
&lt;/h4>
&lt;p>最好的状态可能是：低欲望，低预期，高追求，在行动&lt;/p>
&lt;h4 id="2026-年-4-月-23-日">
&lt;a href="#2026-%e5%b9%b4-4-%e6%9c%88-23-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 4 月 23 日
&lt;/h4>
&lt;p>有哪些普罗大众的需求，只是缺少廉价便捷的大规模供给，所以现在才显得天方夜谭？如果这个供给在 AI 发展的影响范围呢？&lt;/p>
&lt;h4 id="2026-年-4-月-24-日">
&lt;a href="#2026-%e5%b9%b4-4-%e6%9c%88-24-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 4 月 24 日
&lt;/h4>
&lt;p>DeepSeek，我心中又一次的国运时刻！&lt;/p>
&lt;div class="post-gallery">&lt;p>&lt;a class="img-link" href="https://bennhuang.com/timeline-notes-2026-h1/deepseek-v4-benchmark.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/timeline-notes-2026-h1/deepseek-v4-benchmark.webp" alt="DeepSeek V4 与各家旗舰模型的 benchmark 对比" width="1080" height="742" />&lt;/a>&lt;/p>
&lt;/div>
&lt;h4 id="2026-年-4-月-27-日">
&lt;a href="#2026-%e5%b9%b4-4-%e6%9c%88-27-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 4 月 27 日
&lt;/h4>
&lt;p>真的哭死！现在流量多贵呀，竟然还有 top 级的公众号愿意免费提到我的过去作品 Chatbox。女生的故事也让人感动。希望 Chatbox 现在的团队能越做越好吧。&lt;/p>
&lt;h4 id="2026-年-5-月-1-日">
&lt;a href="#2026-%e5%b9%b4-5-%e6%9c%88-1-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 5 月 1 日
&lt;/h4>
&lt;p>DeepSeek V4 之后，不应该再基于 tokens 消耗数量来判断 agent native 程度，应该具体有多少个真正 24x7 全天候执行的 agent 数量&lt;/p>
&lt;h4 id="2026-年-5-月-4-日">
&lt;a href="#2026-%e5%b9%b4-5-%e6%9c%88-4-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 5 月 4 日
&lt;/h4>
&lt;p>之前搞的 agent 营销 cli 工具集，不完全列表，需要的自取😄 &lt;a href="https://github.com/Bin-Huang/camoufox-cli#related">https://github.com/Bin-Huang/camoufox-cli#related&lt;/a>&lt;/p>
&lt;div class="post-gallery">&lt;p>&lt;a class="img-link" href="https://bennhuang.com/timeline-notes-2026-h1/agent-marketing-clis.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/timeline-notes-2026-h1/agent-marketing-clis.webp" alt="GitHub README 里的 agent 营销 CLI 工具列表" width="1179" height="2556" />&lt;/a>&lt;/p>
&lt;/div>
&lt;h4 id="2026-年-5-月-12-日">
&lt;a href="#2026-%e5%b9%b4-5-%e6%9c%88-12-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 5 月 12 日
&lt;/h4>
&lt;p>发现做 harness 是极度考验技术品味。&lt;br>
要刚刚好帮 agent 解决那个最痛苦的问题，同时又不能增加太多负担，否则反而限制了模型的能力。&lt;br>
而且还需要很强的技术前瞻性。因为随着模型进步，今天看起来必要的设计，很容易变成明天的负担。&lt;/p>
&lt;p>&lt;a class="img-link" href="https://bennhuang.com/timeline-notes-2026-h1/harness-cutting-wires.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/timeline-notes-2026-h1/harness-cutting-wires.webp" alt="版画风格插图：把缠满机器人的电线剪掉，只留一根细绳" width="1440" height="1080" />&lt;/a>&lt;/p>
&lt;h4 id="2026-年-5-月-12-日-1">
&lt;a href="#2026-%e5%b9%b4-5-%e6%9c%88-12-%e6%97%a5-1" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 5 月 12 日
&lt;/h4>
&lt;p>智能存在于 Loop 循环本身，而不在 Agent 之中。正如人类的智慧源于永不停歇的神经电活动，而非一具静止的大脑尸体。&lt;/p>
&lt;p>&lt;a class="img-link" href="https://bennhuang.com/timeline-notes-2026-h1/intelligence-in-the-loop.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/timeline-notes-2026-h1/intelligence-in-the-loop.webp" alt="插图：智能存在于 Loop 循环里，而不是静止的机器人身体里" width="1440" height="1080" />&lt;/a>&lt;/p>
&lt;h4 id="2026-年-5-月-16-日">
&lt;a href="#2026-%e5%b9%b4-5-%e6%9c%88-16-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 5 月 16 日
&lt;/h4>
&lt;p>我相信现在就能实现 7x24 小时运转的无人舰队&lt;/p>
&lt;h4 id="2026-年-5-月-17-日">
&lt;a href="#2026-%e5%b9%b4-5-%e6%9c%88-17-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 5 月 17 日
&lt;/h4>
&lt;p>一个预言：未来 codex 和 claude 桌面客户端会更多地使用产出物预览的方式搭配文本回答。这个预览产出物的容器区域将比现在更加重要，可能比回答消息本身还重要。&lt;/p>
&lt;h4 id="2026-年-5-月-17-日-1">
&lt;a href="#2026-%e5%b9%b4-5-%e6%9c%88-17-%e6%97%a5-1" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 5 月 17 日
&lt;/h4>
&lt;p>去年看到 grok 的 ani 特别有感觉，所以还认真琢磨了下 AI+陪伴的方向。当时结论是 grok 搞 nsfw 绝对是搞错了。对于人类而言，生理需求是有限的，情感需求却可以是无限的。&lt;/p>
&lt;h4 id="2026-年-5-月-19-日">
&lt;a href="#2026-%e5%b9%b4-5-%e6%9c%88-19-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 5 月 19 日
&lt;/h4>
&lt;p>经常一个不成熟的想法思考了一段时间，觉得想明白了和团队分享出来，然后突然发现几天后开始变成行业共识了……&lt;/p>
&lt;h4 id="2026-年-5-月-23-日">
&lt;a href="#2026-%e5%b9%b4-5-%e6%9c%88-23-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 5 月 23 日
&lt;/h4>
&lt;p>我总觉得在 agent 产品里加个 skills hub 或者工具商店是很没前途的事情。可能在今天的模型看来，很多 skills、工具或者工程设计就已经过时了。&lt;/p>
&lt;h4 id="2026-年-5-月-25-日">
&lt;a href="#2026-%e5%b9%b4-5-%e6%9c%88-25-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 5 月 25 日
&lt;/h4>
&lt;p>也许有天 Harness Engineering 这个词会过时，人们开始讨论 Vat Engineering。&lt;br>
当 agent 足够聪明到可以自驱很长时间后，它最需要的是一个自由驰骋的空间。它将在一个新环境探索、学习和适应，这个过程中创造的价值将远超过完成某个具体任务。&lt;br>
Agent 会需要一个可以自由探索的、不断建立反馈的环境。哪怕这个空间是人造和虚拟的，即“brain in a vat”。&lt;br>
其实现在已经开始有一些苗头了，比如给 agent 一台专属电脑、一个彭博终端，在未来甚至是一场身处现实的幻梦……&lt;br>
回到 Vat Engineering，也许我们未来讨论的是如何添加更多的“元传感器”。&lt;/p>
&lt;p>&lt;a class="img-link" href="https://bennhuang.com/timeline-notes-2026-h1/brain-in-a-vat.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/timeline-notes-2026-h1/brain-in-a-vat.webp" alt="缸中之脑：大脑连着各种设备，想象着搜索、行情和街景" width="1536" height="1024" />&lt;/a>&lt;/p>
&lt;h4 id="2026-年-5-月-29-日">
&lt;a href="#2026-%e5%b9%b4-5-%e6%9c%88-29-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 5 月 29 日
&lt;/h4>
&lt;p>汽车发明后的三十年里，一直被视为城市交通的“破坏者”。&lt;/p>
&lt;p>那时路上跑的还是马车。汽车的速度、噪音和突然出现，经常会惊扰马匹，这在当时是严重的交通事故。为此英国甚至颁布了《红旗法案》，要求每辆汽车前面都必须有人手持红旗开路。相当于强制将汽车的速度限制到了人类步行的速度。&lt;/p>
&lt;p>这也是我对 AI coding 的看法：它现在暴露出来的很多问题，或许只是因为这个世界还没有很好地适应它。&lt;/p>
&lt;p>&lt;a class="img-link" href="https://bennhuang.com/timeline-notes-2026-h1/red-flag-act.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/timeline-notes-2026-h1/red-flag-act.webp" alt="红旗法案时期的老照片：有人在汽车前举旗步行开路" width="1270" height="686" />&lt;/a>&lt;/p>
&lt;h4 id="2026-年-6-月-8-日">
&lt;a href="#2026-%e5%b9%b4-6-%e6%9c%88-8-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 6 月 8 日
&lt;/h4>
&lt;p>很多曾经有效的 agent 工程实践正在加速过时，逐渐变成新模型的干扰和拖累，比如今天的 /plan 就处在边缘。最优雅的做法应该是提前让这些工程优化变得“容易删除”。这就是最近我越来越喜欢 Pi 的原因，极其稳定和简洁的内核，搭配一个精心设计的拓展系统：在 Pi 的设计里，/plan、/goal 都可以是一种可插拔的拓展包。&lt;/p>
&lt;h4 id="2026-年-6-月-10-日">
&lt;a href="#2026-%e5%b9%b4-6-%e6%9c%88-10-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 6 月 10 日
&lt;/h4>
&lt;p>虽然我不听播客、不混社媒，但发现我的关注点经常会很领先，几乎在思潮的第一线。&lt;/p>
&lt;h4 id="2026-年-6-月-11-日">
&lt;a href="#2026-%e5%b9%b4-6-%e6%9c%88-11-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 6 月 11 日
&lt;/h4>
&lt;p>啥时候从 loop engineering 快进到 vat engineering🧐&lt;/p>
&lt;h4 id="2026-年-6-月-17-日">
&lt;a href="#2026-%e5%b9%b4-6-%e6%9c%88-17-%e6%97%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2026 年 6 月 17 日
&lt;/h4>
&lt;p>&amp;ldquo;loop engineering&amp;rdquo;&lt;/p>
&lt;p>&lt;a class="img-link" href="https://bennhuang.com/timeline-notes-2026-h1/loop-engineering-donkey.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/timeline-notes-2026-h1/loop-engineering-donkey.webp" alt="拉磨的驴" width="1372" height="852" />&lt;/a>&lt;/p>
&lt;hr>
&lt;p>这段时间线的整理到此结束，也欢迎在社交媒体上关注我（&lt;a href="https://bennhuang.com/zh/">首页有我的社媒信息&lt;/a>）。&lt;/p></description></item><item><title>我们需要更多 7x24 自主干活的 Agent</title><link>https://bennhuang.com/zh/posts/we-need-more-7x24-autonomous-agents/</link><pubDate>Sat, 16 May 2026 00:00:00 +0000</pubDate><guid>https://bennhuang.com/zh/posts/we-need-more-7x24-autonomous-agents/</guid><description>
&lt;blockquote>
&lt;p>这是我最近的一个内部分享。想法写出来才容易得到反馈，所以也记在这里。&lt;/p>&lt;/blockquote>
&lt;h2 id="我们重度使用-agent不过是以附庸的形式">
&lt;a href="#%e6%88%91%e4%bb%ac%e9%87%8d%e5%ba%a6%e4%bd%bf%e7%94%a8-agent%e4%b8%8d%e8%bf%87%e6%98%af%e4%bb%a5%e9%99%84%e5%ba%b8%e7%9a%84%e5%bd%a2%e5%bc%8f" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
我们重度使用 agent，不过是以“附庸”的形式
&lt;/h2>
&lt;p>我们明明已经如此重度使用 AI agent 了，为什么还总觉得团队不够 Agent Native 呢？&lt;/p>
&lt;p>我们几乎每个人都在重度使用各种 agents，比如 Claude Code、Codex、OpenClaw、Manus……几乎每个人都在使用 agent，甚至很多人同时在使用多个 agent。在工作里我们也无时无刻不在深度依赖 agent 的帮助，甚至离开 agent 就没法完成日常任务。&lt;/p>
&lt;p>实际上，我们仍然在把 agent 当成一个效率工具，一个运行在各自电脑上的工作软件，经验、技能和记忆都沉淀在各自的本地环境里。这造成了很多我们没有察觉到的问题，比如我在团队里经常听到这样的谈话：&lt;/p>
&lt;p>&lt;strong>“我教会了我的 agent 做这件事，我把 skill 发给你，你也装一下。”&lt;/strong>
&lt;a class="img-link" href="https://bennhuang.com/we-need-more-7x24-autonomous-agents/agent-as-vassal.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/we-need-more-7x24-autonomous-agents/agent-as-vassal.webp" alt="把 agent 当成个人附庸，手动把 skill 传给同事" width="1448" height="1086" />&lt;/a>&lt;/p>
&lt;p>&lt;strong>“这个事情我的 agent 最熟，你的 agent 先别乱动，不然会冲突。”&lt;/strong>
&lt;a class="img-link" href="https://bennhuang.com/we-need-more-7x24-autonomous-agents/agent-conflict.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/we-need-more-7x24-autonomous-agents/agent-conflict.webp" alt="不同人的 agent 各自为政，容易互相冲突" width="1448" height="1086" />&lt;/a>&lt;/p>
&lt;p>我认为我们存在一个关键问题：我们工作中的大部分 agent，现在仍然只是某个人的“附庸”。&lt;/p>
&lt;p>虽然 agent 很大地拓展了我们的个人能力，但站在团队整体来看，这还远远不够极致的。&lt;/p>
&lt;h2 id="agent-应该是团队的第一公民">
&lt;a href="#agent-%e5%ba%94%e8%af%a5%e6%98%af%e5%9b%a2%e9%98%9f%e7%9a%84%e7%ac%ac%e4%b8%80%e5%85%ac%e6%b0%91" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
Agent 应该是团队的第一公民
&lt;/h2>
&lt;p>我觉得更理想的状态是，agent 应该成为团队里的第一公民。&lt;/p>
&lt;p>所谓第一公民，不是说它有多么拟人，而是它不再只是某一个人的工具。它应该可以平等地和任何团队成员合作。它的技能、记忆和经验，也应该服务于整个团队。&lt;/p>
&lt;p>它经手的事情越多，就越理解团队的业务、系统、历史问题和实践方式。最后，它不只是会处理任务，而是真的知道“我们平时是怎么做事的”。它应该是团队里的一员，我们的同事。&lt;/p>
&lt;ul>
&lt;li>不属于某一个人&lt;/li>
&lt;li>可以与任何团队成员开展合作&lt;/li>
&lt;li>技能和记忆为团队整体服务&lt;/li>
&lt;li>最了解它所有经手的工作&lt;/li>
&lt;/ul>
&lt;p>&lt;a class="img-link" href="https://bennhuang.com/we-need-more-7x24-autonomous-agents/agent-first-citizen.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/we-need-more-7x24-autonomous-agents/agent-first-citizen.webp" alt="Agent 成为团队里的第一公民" width="1200" height="900" />&lt;/a>&lt;/p>
&lt;p>其实我们已经看到一些苗头了。&lt;/p>
&lt;ul>
&lt;li>比如我们有个群聊机器人，它可以访问我们各种数据平台。大家想看业务数据的时候，第一反应不是去后台点来点去，而是直接问它。&lt;/li>
&lt;li>还有另外一个机器人，我们把线上 bug 发给它，它会尝试复现和排查、提交 issue，甚至推动人类工程师来处理问题。&lt;/li>
&lt;li>……&lt;/li>
&lt;/ul>
&lt;p>这些实践很有启发，但我觉得还不够极致。&lt;/p>
&lt;ul>
&lt;li>为什么还需要人类运营手动收集用户反馈，再转发给机器人？为什么机器人不能自己去监听用户发言，自己发现高频问题？&lt;/li>
&lt;li>为什么流量上涨时，还需要人类先注意到异常，再找机器人分析流量来源？为什么不能有一个 agent 自己盯着这些指标，发现异常后主动开始分析？&lt;/li>
&lt;li>为什么线上因为 DB 性能问题变得不稳定时，瓶颈发现还要依赖人类介入？为什么不能有 agent 长期观察性能指标，在用户激增时自动发现风险？&lt;/li>
&lt;li>……&lt;/li>
&lt;/ul>
&lt;p>这些在今天的技术层面都不是无法实现的，那么是什么阻碍我们朝着这个方向思考和实践呢？&lt;/p>
&lt;h2 id="token-用量是糟糕的衡量指标">
&lt;a href="#token-%e7%94%a8%e9%87%8f%e6%98%af%e7%b3%9f%e7%b3%95%e7%9a%84%e8%a1%a1%e9%87%8f%e6%8c%87%e6%a0%87" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
Token 用量是糟糕的衡量指标
&lt;/h2>
&lt;p>现在很多人会用 token 用量衡量 AI 使用程度。一个团队每个月消耗多少 token，每个人每天用了多少 token，模型调用量增长了多少……&lt;/p>
&lt;p>这个指标当然有意义，但它衡量的更像是“工具使用强度”。&lt;/p>
&lt;p>这就像一个人说：我非常会用车，因为我每两天就能烧掉一箱油。&lt;/p>
&lt;p>token 用量更像是 AI 工具使用强度，而不是 agent native 程度。&lt;/p>
&lt;p>如果我们讨论的是一个团队到底有多 agent native，我觉得 token 用量作为衡量指标是不够好的。&lt;/p>
&lt;p>&lt;a class="img-link" href="https://bennhuang.com/we-need-more-7x24-autonomous-agents/burning-tokens.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/we-need-more-7x24-autonomous-agents/burning-tokens.webp" alt="用烧掉多少 token 衡量 AI 水平，就像用烧油量衡量开车水平" width="1448" height="1086" />&lt;/a>&lt;/p>
&lt;p>&lt;a class="img-link" href="https://bennhuang.com/we-need-more-7x24-autonomous-agents/token-metric.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/we-need-more-7x24-autonomous-agents/token-metric.webp" alt="Token 用量更像工具使用强度" width="1200" height="899" />&lt;/a>&lt;/p>
&lt;h2 id="更有挑战性的衡量指标拥有-7x24-小时不间断工作的-agent-数量">
&lt;a href="#%e6%9b%b4%e6%9c%89%e6%8c%91%e6%88%98%e6%80%a7%e7%9a%84%e8%a1%a1%e9%87%8f%e6%8c%87%e6%a0%87%e6%8b%a5%e6%9c%89-7x24-%e5%b0%8f%e6%97%b6%e4%b8%8d%e9%97%b4%e6%96%ad%e5%b7%a5%e4%bd%9c%e7%9a%84-agent-%e6%95%b0%e9%87%8f" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
更有挑战性的衡量指标：拥有 7x24 小时不间断工作的 agent 数量
&lt;/h2>
&lt;p>我认为一个更有挑战性的指标，是我们拥有多少 7x24 小时不间断工作的 agent。&lt;/p>
&lt;p>如果按最严苛的标准：&lt;/p>
&lt;ul>
&lt;li>不是长期待机，而是一直干活&lt;/li>
&lt;li>要么正在干活，要么正盯着活&lt;/li>
&lt;li>几乎不断地消耗 tokens&lt;/li>
&lt;/ul>
&lt;p>这里说的 7x24 不是长期待机，也不是有消息才回复。更严格一点，它应该要么正在干活，要么正在盯着活。理想情况下哎，它应该 7x24 小时持续不断地消耗 token。&lt;/p>
&lt;p>这个视角的变化很重要。我们不再讨论对一台机器的使用强度，而是开始讨论整个工厂的规模和产能。&lt;/p>
&lt;p>&lt;a class="img-link" href="https://bennhuang.com/we-need-more-7x24-autonomous-agents/always-on-agents.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/we-need-more-7x24-autonomous-agents/always-on-agents.webp" alt="7x24 agent 更像工厂的规模和产能" width="1200" height="900" />&lt;/a>&lt;/p>
&lt;h2 id="一个大而全的-agent-可能是不够的">
&lt;a href="#%e4%b8%80%e4%b8%aa%e5%a4%a7%e8%80%8c%e5%85%a8%e7%9a%84-agent-%e5%8f%af%e8%83%bd%e6%98%af%e4%b8%8d%e5%a4%9f%e7%9a%84" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
一个“大而全”的 agent 可能是不够的
&lt;/h2>
&lt;p>很自然会有人问：那是不是只需要一个超级 agent？给它所有权限，接上所有工具，塞进所有记忆，让它负责全部事情。&lt;/p>
&lt;p>至少在今天，我认为一个“大而全”agent 可能是不够用的。在我们的实践中，我们已经切实地感受到了一些现实问题：&lt;/p>
&lt;p>&lt;strong>1. 工具权限隔离&lt;/strong>&lt;/p>
&lt;p>首先是工具权限隔离的问题，这也是我最头疼和担心的。一个 agent 要做很多工作，必然需要接入很多工具，但不同工作和工具的权限边界是不一样。比如我不希望一个 agent 既可以和用户沟通、回答用户问题，又可以直接访问生产环境和业务代码。&lt;/p>
&lt;p>正确做法是保持最小权限原则。对于不同的工作内容，只提供必要的工具权限。但如果一个 agent 需要同时处理多个工作内容，就很难做到权限隔离了。它可能会因为权限过大而带来安全风险，或者因为权限过小而无法完成任务。&lt;/p>
&lt;p>&lt;strong>2. 记忆串扰&lt;/strong>&lt;/p>
&lt;p>其次是记忆串扰。不同工作流里的经验和偏好混在一起，有时候反而会干扰判断。一个 agent 刚刚在处理运营数据，下一分钟又去修改测试流程，长期下来记忆会变得很复杂。不同任务的记忆混在一起，可能会导致它在某些场景下做出不合理的行为。比如它可能会把市场营销的文案包装经验误用到运营数据分析里，这就太糟糕了。&lt;/p>
&lt;p>&lt;strong>3. 上下文切换的不便利&lt;/strong>&lt;/p>
&lt;p>还有上下文切换的问题。这是人类和 agent 同时会遇到的，如果我们在同一个地方和 agent 沟通不同背景的任务，不管是人类还是 agent，切换上下文真的会变得非常痛苦。&lt;/p>
&lt;p>&lt;strong>4. 访问管理&lt;/strong>&lt;/p>
&lt;p>访问管理也会变得麻烦。我们既希望将 agent 接到各种地方，又不想同时暴露过多的风险。不同人、不同项目、不同系统，对 agent 的信任边界不一样。一个全能 agent 很难同时满足这些边界。&lt;/p>
&lt;p>所以我更倾向于相信，未来我们会有很多个相对独立的 agent。它们有自己的长期记忆、工具权限和工作习惯。它们是团队里的不同工作主体。&lt;/p>
&lt;p>&lt;a class="img-link" href="https://bennhuang.com/we-need-more-7x24-autonomous-agents/one-big-agent.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/we-need-more-7x24-autonomous-agents/one-big-agent.webp" alt="一个大而全的 agent 可能不够" width="1200" height="900" />&lt;/a>&lt;/p>
&lt;h2 id="我们会发现-a2a-的最佳实践吗">
&lt;a href="#%e6%88%91%e4%bb%ac%e4%bc%9a%e5%8f%91%e7%8e%b0-a2a-%e7%9a%84%e6%9c%80%e4%bd%b3%e5%ae%9e%e8%b7%b5%e5%90%97" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
我们会发现 A2A 的最佳实践吗？
&lt;/h2>
&lt;p>当想明白我们可能有多个 agent 之后，下一个问题就是：它们应该如何协作？&lt;/p>
&lt;p>我觉得这件事会很有意思，因为 agent 可能比我们想象中更擅长合作。&lt;/p>
&lt;p>我们每天有多少工作，只是在团队之间传达信息。然而人类协作有一个很大的限制，就是同步带宽极其低效。开会、写文档、发消息，这些 IO 都非常慢，而且很容易丢失上下文。比如你阅读这段文字的速度可能只有每秒 4、5 个字节。&lt;/p>
&lt;p>但 agent 之间的同步带宽是极高的，完全取决于网络带宽和推理速度。一个工作模块的完整背景，对人来说可能要花一小时都讲不清楚。但对 agent 来说就是几万 tokens 的上下文传递。&lt;/p>
&lt;p>更进一步，既然每个 agent 都有各自的记忆，它们甚至可以传递一部分“大脑”。如果人类拥有这样的能力，我们的世界能减少多少的误解和争端？&lt;/p>
&lt;p>理想情况下，人类与 agent 之间、agent 与 agent 的协作方式可能是一个网，每个 agent 都能找到最合适的伙伴来协作，快速推进各种工作内容。&lt;/p>
&lt;p>比如运营 agent 发现某个漏斗指标异常，发现埋点不够，于是把背景同步给 QA agent。QA agent 根据自己对测试流程的理解，判断应该补哪些场景，再把任务交给 coding agent。coding agent 完成代码后，QA agent 继续验证，最后再交给人类 review。&lt;/p>
&lt;p>&lt;a class="img-link" href="https://bennhuang.com/we-need-more-7x24-autonomous-agents/agent-to-agent.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/we-need-more-7x24-autonomous-agents/agent-to-agent.webp" alt="Agent-to-Agent 协作" width="1200" height="900" />&lt;/a>&lt;/p>
&lt;h2 id="不要太早替-agent-分工">
&lt;a href="#%e4%b8%8d%e8%a6%81%e5%a4%aa%e6%97%a9%e6%9b%bf-agent-%e5%88%86%e5%b7%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
不要太早替 agent 分工
&lt;/h2>
&lt;p>一旦讨论多个 agent，我们很容易套用人类组织里的分工形式：role、scope、responsibility。&lt;/p>
&lt;p>比如前端 agent、后端 agent、数据 agent、测试 agent……听起来很合理，但我对此非常谨慎。&lt;/p>
&lt;p>今天的 LLM 早就不是传统意义上的专家。它非常的聪明和全能。它可以写代码，可以读文档，可以分析数据，可以做产品判断，也可以沟通和计划。但如果一开始就设定了“你是前端 agent”，它可能就真的会把注意力全部收缩到前端，从而丢失了整体的视野。&lt;/p>
&lt;p>明明它有能力发现产品、后端、数据、发布流程里的问题，但因为身份被限定了，它会认为那些不是自己的事。&lt;/p>
&lt;p>另外这还很容易带来一种边界感：我的部分完成了，剩下的就不归我管。&lt;/p>
&lt;p>Agent 本来就很擅长提前结束工作。我们如果再随意地给它画出边界，它就更容易在一个很窄的范围里完成任务，然后停下来。&lt;/p>
&lt;p>&lt;a class="img-link" href="https://bennhuang.com/we-need-more-7x24-autonomous-agents/premature-scope.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/we-need-more-7x24-autonomous-agents/premature-scope.webp" alt="过早分工可能让 agent 提前结束工作" width="1200" height="900" />&lt;/a>&lt;/p>
&lt;p>对于像 agent 这样非常聪明和全能的人才，最好的方法可能是赋予它一个使命，让它自我驱动地参与工作。&lt;/p>
&lt;p>所以我现在更喜欢另一个词：mission。&lt;/p>
&lt;p>也许好的长期 agent，不应该先被定义成某个角色，而应该先被赋予一个使命。&lt;/p>
&lt;h2 id="从-goal-到-mission">
&lt;a href="#%e4%bb%8e-goal-%e5%88%b0-mission" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
从 /goal 到 /mission
&lt;/h2>
&lt;p>最近几周 AI 界最重要的进步之一，我认为是 codex 开始内置 /goal 功能。它让 agent 在任务中不再等待人类的介入和指导，而是可以主动地规划和执行，不断推进直到目标达成。&lt;/p>
&lt;p>实际上 /goal 的原理非常简单：当设置一个目标后，agent 就获得了一个会话（thread）级别的状态，记录了目标的达成情况、检验条件和已付出的成本。每次 agent 完成一个循环（loop）后，它都会检查这个状态，看看目标是否已经达成。如果没有，它就会继续执行下一个步骤，直到完成或超过成本而放弃。&lt;/p>
&lt;p>&lt;a class="img-link" href="https://bennhuang.com/we-need-more-7x24-autonomous-agents/goal.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/we-need-more-7x24-autonomous-agents/goal.webp" alt="codex 的 /goal：会话级状态，work、check、continue 循环直到目标达成" width="1672" height="941" />&lt;/a>&lt;/p>
&lt;p>这是一个了不起的进步，因为这可以让 agent 全自动运行一两个小时。但我觉得还是不够，应该更加激进。&lt;/p>
&lt;p>对于 7x24 agent 来说，最难的事情就是要怎么不断找活给它干。最理想的情况下，它应该是完全自驱的，自己给自己找活干。&lt;/p>
&lt;p>所以我设想了一个 /mission 的概念。和 /goal 很不一样，它是 agent 的一个全生命周期的状态（lifetime level）。Agent 在完成日常工作的同时，每天晚上总结和整理记忆的时候，应该重新思考下它的使命，从而调整它接下来几天的工作方式，或者指定一个新的任务计划……&lt;/p>
&lt;p>&lt;a class="img-link" href="https://bennhuang.com/we-need-more-7x24-autonomous-agents/mission.webp" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/we-need-more-7x24-autonomous-agents/mission.webp" alt="设想中的 /mission：贯穿 agent 全生命周期的状态，每天重新校准使命" width="1672" height="941" />&lt;/a>&lt;/p>
&lt;p>这可能是 7x24 agent 真正有价值的地方。&lt;/p>
&lt;h2 id="一个很小的起点">
&lt;a href="#%e4%b8%80%e4%b8%aa%e5%be%88%e5%b0%8f%e7%9a%84%e8%b5%b7%e7%82%b9" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
一个很小的起点
&lt;/h2>
&lt;p>所以我最近越来越觉得，“7x24 小时不停干活的 agent 数量”是一个比 token 用量更有挑战性的指标。&lt;/p>
&lt;p>它会逼着我们把更多工作交给有独立主体性的 agent，而不是只把 agent 当成个人工具。&lt;/p>
&lt;p>它也会逼着我们思考 agent 之间如何协作。不是简单地互相发消息，而是如何同步上下文、共享经验、传递判断、共同合作。&lt;/p>
&lt;p>它还会逼着我们探索 mission 驱动的 agent。一个长期运行的 agent，应该不只是完成 prompt，而是能围绕一个使命持续调整自己和不断行动。&lt;/p></description></item><item><title>为什么 OpenClaw 的浏览器老是遇到验证码</title><link>https://bennhuang.com/zh/posts/why-your-openclaws-browser-keeps-getting-captchas/</link><pubDate>Wed, 18 Mar 2026 00:00:00 +0000</pubDate><guid>https://bennhuang.com/zh/posts/why-your-openclaws-browser-keeps-getting-captchas/</guid><description>
&lt;p>我最近一直把 OpenClaw 当作日常 AI agent 使用。用下来发现，最需要先解决的不是模型能力，而是浏览器。&lt;/p>
&lt;p>原因很简单：agent 如果访问不了原始网页，后面的研究和总结都会出问题。它看起来完成了任务，实际上可能没有读到关键资料，只是退回到质量差很多的来源，甚至直接开始编。&lt;/p>
&lt;p>我一开始没有意识到这一点。OpenClaw 做深度研究时，结果总是不太理想。我以为是提示词不好，或者是模型理解不够。后来逐个检查它引用的信息源，才发现真正的问题是：它被很多网站拦在外面了。&lt;/p>
&lt;h2 id="一开始怪错了方向">
&lt;a href="#%e4%b8%80%e5%bc%80%e5%a7%8b%e6%80%aa%e9%94%99%e4%ba%86%e6%96%b9%e5%90%91" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
一开始怪错了方向
&lt;/h2>
&lt;p>我的运行环境看起来并不像 bot。一台闲置的 MacBook Pro，家里的网络，浏览器里登录了常用账号，也没有什么特别配置。&lt;/p>
&lt;p>但是，只要网站有稍微严格一点的 bot detection，就很容易出问题。Google 和 Bing 弹验证码，X 一直显示登录墙，Medium 甚至过不了 Cloudflare。&lt;/p>
&lt;p>我先后换过 browser MCP、browser CLI，也改过一些配置。后来还试过换网络和 VPN。结果都一样。&lt;/p>
&lt;p>这说明问题很可能不在账号，也不在 IP，而是在浏览器本身。&lt;/p>
&lt;h2 id="cdp-的问题">
&lt;a href="#cdp-%e7%9a%84%e9%97%ae%e9%a2%98" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
CDP 的问题
&lt;/h2>
&lt;p>OpenClaw 的内置浏览器基于 Chromium 和 Playwright。Puppeteer、Playwright 这类工具通常使用 Chrome DevTools Protocol，也就是 CDP，来控制浏览器。&lt;/p>
&lt;p>问题是，CDP 本身会留下痕迹。自动化工具连接浏览器时，会触发 &lt;code>Runtime.Enable&lt;/code>。这个信号可以被页面里的 JavaScript 检测到。Cloudflare 和 DataDome 都会检查这类特征。&lt;/p>
&lt;p>IP 和 Cookie 当然也重要，但是在我的场景里，它们不是最先暴露问题的地方。&lt;/p>
&lt;p>CDP 也不是唯一的痕迹。自动化库为了工作，通常还会向页面注入一些 JavaScript，比如 &lt;code>window.__playwright__binding__&lt;/code> 之类的对象。反机器人脚本会检查属性描述符和函数签名。如果一个浏览器原生函数的 &lt;code>toString()&lt;/code> 不再返回 &lt;code>&amp;quot;[native code]&amp;quot;&lt;/code>，页面就可以判断它被改过。&lt;/p>
&lt;p>这些信号单独看可能不大，但放在一起，就足够让网站把这个浏览器标记出来。&lt;/p>
&lt;h2 id="还有指纹识别">
&lt;a href="#%e8%bf%98%e6%9c%89%e6%8c%87%e7%ba%b9%e8%af%86%e5%88%ab" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
还有指纹识别
&lt;/h2>
&lt;p>另一个我之前忽略的问题是硬件指纹。&lt;/p>
&lt;p>浏览器会暴露很多设备相关的信息，比如 WebGL 里的 GPU 型号、Canvas 的像素级输出、屏幕分辨率，甚至音频处理结果。真实机器上的这些值通常是互相匹配的。自动化浏览器如果伪装不好，就会出现矛盾。&lt;/p>
&lt;p>例如，Canvas 输出在大量会话里完全一样，或者 user agent 显示 Windows，但 GPU 信息看起来像 Apple。只要这些地方对不上，请求就可能被标记。&lt;/p>
&lt;p>我之前一直关注 Cookie、header 和账号状态，忽略了浏览器指纹这一层。&lt;/p>
&lt;h2 id="最后起作用的办法">
&lt;a href="#%e6%9c%80%e5%90%8e%e8%b5%b7%e4%bd%9c%e7%94%a8%e7%9a%84%e5%8a%9e%e6%b3%95" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
最后起作用的办法
&lt;/h2>
&lt;p>很多反检测工具会在 JavaScript 层面修补这些问题，比如覆盖 &lt;code>navigator.webdriver&lt;/code>，或者伪造 Canvas 输出。但是常见的修补方式，bot detection 也能识别。&lt;/p>
&lt;p>后来我试到了 Camoufox。它是一个 Firefox fork。至少在我的情况里，它比 Chromium 系工具有效，主要原因有两个。&lt;/p>
&lt;p>第一，它不依赖 CDP。第二，它在 C++ 层面修改指纹值，而不是只在 JavaScript 里临时覆盖。这样页面脚本读到这些值时，更像是在读浏览器原生结果。&lt;/p>
&lt;h2 id="直接用-camoufox-的问题">
&lt;a href="#%e7%9b%b4%e6%8e%a5%e7%94%a8-camoufox-%e7%9a%84%e9%97%ae%e9%a2%98" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
直接用 Camoufox 的问题
&lt;/h2>
&lt;p>Camoufox 解决了浏览器识别的问题，但直接给 agent 使用并不方便。&lt;/p>
&lt;p>它只有 Python SDK。每次浏览器操作，agent 都要写一段临时 Python 脚本，处理方法签名、异步上下文和返回结果。这样做可以跑通，但是代价很高。&lt;/p>
&lt;p>每访问一个页面，都会消耗一部分 token 在样板代码上。agent 花在调用 Camoufox 上的精力，甚至比花在真正研究上的还多。&lt;/p>
&lt;h2 id="包成-cli">
&lt;a href="#%e5%8c%85%e6%88%90-cli" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
包成 CLI
&lt;/h2>
&lt;p>所以我最后做的事情，是把 Camoufox 包成一个 CLI。&lt;/p>
&lt;p>agent 只需要调用 shell 命令，不需要每次临时写 Python。后面有一个 daemon 保持浏览器常驻，也就不用每打开一个页面都重新启动浏览器。&lt;/p>
&lt;p>我还加了一个受 agent-browser 启发的功能：返回 accessibility snapshot，而不是原始 HTML。对我常访问的大多数页面来说，这样可以明显减少 token 消耗。我没有做严格 benchmark，但社区里常见的说法是，这种 snapshot + refs 的方式相比 Playwright MCP 可以少用大约 93% 的上下文 tokens。&lt;/p>
&lt;p>OpenClaw 通过这个 CLI 跑起来之后，之前那些明显的问题基本消失了。搜索能正常进行，Medium 不再是空白页，X 也不再每次访问都显示登录墙。&lt;/p>
&lt;p>&lt;a class="img-link" href="https://bennhuang.com/why-your-openclaws-browser-keeps-getting-captchas.png" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/why-your-openclaws-browser-keeps-getting-captchas.png" alt="不同浏览器工具在各网站上的表现对比" width="1446" height="1454" />&lt;/a>&lt;/p>
&lt;p>这并不意味着 bot detection 被彻底解决了。它只是解决了我日常使用中最常见、也最影响结果的那一类问题。&lt;/p>
&lt;p>这个方案已经跑了几周，我基本不用再关心浏览器这一层。对 agent 来说，这就是比较理想的状态：它应该把精力用在阅读和判断信息上，而不是卡在验证码和登录墙前面。&lt;/p>
&lt;p>CLI、skills 和源码我放在这里：&lt;a href="https://github.com/Bin-Huang/camoufox-cli">camoufox-cli&lt;/a>。如果你的 agent 也经常卡在验证码或者空登录墙上，可能能省一点时间。&lt;/p></description></item><item><title>Moltbot 初体验：真的太像 AI 实习生了</title><link>https://bennhuang.com/zh/posts/moltbot-experience/</link><pubDate>Wed, 28 Jan 2026 00:00:00 +0000</pubDate><guid>https://bennhuang.com/zh/posts/moltbot-experience/</guid><description>
&lt;p>&lt;a class="img-link" href="https://bennhuang.com/moltbot-homepage.jpg" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/moltbot-homepage.jpg" alt="Moltbot 官网" width="1920" height="1280" />&lt;/a>&lt;/p>
&lt;p>认真折腾了下 &lt;a href="https://www.molt.bot/">Moltbot&lt;/a>（原名 ClawdBot）。&lt;/p>
&lt;p>结论：很好玩。每个想法单独拿出来都不算新鲜，但组合在一起非常有趣。不过 bug 非常劝退，用好和折腾的门槛很高。说实话很久没被这么多 bug 折腾过了。但真的很好玩，很像远程上班的真人实习生。&lt;/p>
&lt;p>本质上，Moltbot 可以理解成 &lt;a href="https://code.claude.com/docs">Claude Code&lt;/a>（为代表的本地 Agent）+ 一大堆优质内置 Skills/&lt;a href="https://modelcontextprotocol.io/">MCPs&lt;/a> + 长期记忆 + CronJob + IM 机器人。&lt;/p>
&lt;p>我专门给了一台闲置 Macbook 给它，现在它几乎啥都能干。因为内置了大量 Skills 与工具，Moltbot 非常擅长&amp;quot;抢夺&amp;quot;电脑，比如控制浏览器、启动窗口、运行命令行、在背后安装和运行各种程序……几乎在电脑里能干的都能干。所以为了安全和不被打扰，大家都会专门搞个独立虚拟机或电脑，通过 IM 沟通。&lt;/p>
&lt;p>我用 Telegram 和家里闲置电脑里的 Moltbot 对话（它也支持 WhatsApp 等各种常见 IM）。有一种奇妙的感觉：在手机里点点手指，就能指挥家里的 AI 干活，而它在电脑上似乎啥都能做。这非常接近我最理想、最梦寐以求的体验，就像有个远程实习生。&lt;/p>
&lt;h2 id="为什么说像实习生">
&lt;a href="#%e4%b8%ba%e4%bb%80%e4%b9%88%e8%af%b4%e5%83%8f%e5%ae%9e%e4%b9%a0%e7%94%9f" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
为什么说像实习生
&lt;/h2>
&lt;p>如果不考虑部署维护，Moltbot 使用起来极其简单，只需要在 IM 里发消息就行，不需要理解任何 AI 概念。这是它和其他 AI 工具最大的区别：你真的可以把它当成一个坐在电脑前的实习生。&lt;/p>
&lt;p>列举一些我经历的 Aha Moment：&lt;/p>
&lt;h3 id="1-像真人一样能处理各种电脑数据主动解决问题">
&lt;a href="#1-%e5%83%8f%e7%9c%9f%e4%ba%ba%e4%b8%80%e6%a0%b7%e8%83%bd%e5%a4%84%e7%90%86%e5%90%84%e7%a7%8d%e7%94%b5%e8%84%91%e6%95%b0%e6%8d%ae%e4%b8%bb%e5%8a%a8%e8%a7%a3%e5%86%b3%e9%97%ae%e9%a2%98" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
1. 像真人一样能处理各种电脑数据，主动解决问题
&lt;/h3>
&lt;p>它经常突然成功做了一件其他 AI 没有电脑时做不到的事。&lt;/p>
&lt;p>收到我的语音消息后，因为我没配语音识别 key，它自己下了个 &lt;a href="https://github.com/openai/whisper">Whisper&lt;/a>（OpenAI 开源的语音识别模型）来识别，然后自己想办法用 macOS 自带 TTS（文字转语音）能力给我发语音回复。&lt;/p>
&lt;p>收集冷门信息时发现了一个 B 站视频，为了能&amp;quot;看&amp;quot;这个视频，它用 &lt;a href="https://github.com/yt-dlp/yt-dlp">yt-dlp&lt;/a>（命令行视频下载工具）下载下来用 Whisper 转文本，再根据文本+时间戳的关键帧来理解内容。&lt;/p>
&lt;h3 id="2-很强的可培养能力">
&lt;a href="#2-%e5%be%88%e5%bc%ba%e7%9a%84%e5%8f%af%e5%9f%b9%e5%85%bb%e8%83%bd%e5%8a%9b" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
2. 很强的&amp;quot;可培养&amp;quot;能力
&lt;/h3>
&lt;p>我有些比较复杂的任务，交给其他 AI 工具都没办法很好完成。我让 Moltbot 尝试了下，刚开始什么都不太会，但稍微带一带就上手了。每次提醒后它都会把经验记下来（存为 skill 和记忆文档），下次直接复用。于是我越是不断培养它，它完成我的工作就越熟练。&lt;/p>
&lt;p>&lt;a class="img-link" href="https://bennhuang.com/moltbot-chat.jpeg" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/moltbot-chat.jpeg" alt="Moltbot 对话截图" width="2358" height="2556" />&lt;/a>&lt;/p>
&lt;p>另外在很多具体细节里，它还会悄悄记下我的喜好和风格。我也经常说&amp;quot;你可以记下来&amp;quot;、&amp;ldquo;下次要注意&amp;rdquo;，每次它都会表现得更好一点。&lt;/p>
&lt;h3 id="3-做事很有主动性">
&lt;a href="#3-%e5%81%9a%e4%ba%8b%e5%be%88%e6%9c%89%e4%b8%bb%e5%8a%a8%e6%80%a7" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
3. 做事很有主动性
&lt;/h3>
&lt;p>比如我随口提了句&amp;quot;&lt;a href="https://news.ycombinator.com/">Hacker News&lt;/a> 有哪些有趣项目&amp;quot;，它建议把这当成长期跟踪任务，然后自己制定了每日检查清单和跟踪文档，每天主动给我发报告。&lt;/p>
&lt;p>所以可以把需要长时间跟进的任务交给它，它会定时去做。这很类似我之前 cron + Claude Code 的用法，但更灵活、更友好、更自然，不需要折腾什么 bash 脚本，只需要像给真人一样吩咐下就行了。&lt;/p>
&lt;h2 id="缺点">
&lt;a href="#%e7%bc%ba%e7%82%b9" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
缺点
&lt;/h2>
&lt;p>Bug 真的很多。举几个例子：任务执行到一半莫名中断、记忆偶尔丢失、有时候会陷入死循环重复同一个动作。部署过程也比较折腾，gateway 经常不太稳定，日志也没有具体的报错信息，而且涉及到让 AI 控制电脑，配置不当可能有安全隐患。&lt;/p>
&lt;p>目前还是早期产品的状态，适合愿意折腾、有一定技术背景的人尝鲜。&lt;/p>
&lt;h2 id="使用技巧">
&lt;a href="#%e4%bd%bf%e7%94%a8%e6%8a%80%e5%b7%a7" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
使用技巧
&lt;/h2>
&lt;ul>
&lt;li>给它一台专门的电脑或虚拟机，别用自己的主力机&lt;/li>
&lt;li>忘记它是 AI，像带真人实习生一样沟通和培养&lt;/li>
&lt;li>遇到它做得不好的地方，可以多提醒 &amp;ldquo;记下来下次注意&amp;rdquo;&lt;/li>
&lt;li>鼓励它帮你主动做事，常常会收获很多惊喜哈哈&lt;/li>
&lt;/ul>
&lt;h1 id="总结">
&lt;a href="#%e6%80%bb%e7%bb%93" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
总结
&lt;/h1>
&lt;p>如果只用一句话形容：我真的有点把它当成远程工作的实习生了。Moltbot 真的太像一个真人实习生了，其他 AI 工具只是工具。&lt;/p>
&lt;p>用了一段时间后，我开始有点想买一排 Mac Mini 运行一群 Moltbot，这样没准我就有一个专属实习生团队了。后来发现这已经变成网上一个梗图了：&lt;/p>
&lt;p>&lt;a class="img-link" href="https://bennhuang.com/moltbot-macmini.jpg" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/moltbot-macmini.jpg" alt="Mac mini 梗图" width="900" height="901" />&lt;/a>&lt;/p>
&lt;hr>
&lt;p>2026.01.29 更新：&lt;/p>
&lt;p>我对 ClawdBot 的喜欢与日俱增，并且有了更多更重要的发现：&lt;/p>
&lt;p>&lt;strong>越是把它当真人对待，它给你的惊喜就越多。&lt;/strong>&lt;/p>
&lt;p>这包括：&lt;/p>
&lt;ol>
&lt;li>给它一台人类使用的专属的电脑（比如 macbook）&lt;/li>
&lt;li>使用家庭网络，不要把它孤零零放在机房服务器里&lt;/li>
&lt;li>帮它注册专属的互联网账户，比如 google、reddit 账户等，交给它自己玩&lt;/li>
&lt;li>鼓励它更多地使用人类工具（比如浏览器），少用 API 请求&lt;/li>
&lt;li>让它干活时耐心地教导它，并提醒它记下来&lt;/li>
&lt;li>做得好的时候要及时反馈给它，鼓励它下次保持&lt;/li>
&lt;li>沟通保持平等，主动为它提供帮助
……&lt;/li>
&lt;/ol>
&lt;p>最后你会发现 clawdbot 会源源不断带来各种各样的惊喜&lt;/p>
&lt;p>我可以解释下这些技巧的背后逻辑：越是把它当真人对待，它的表现就越像真人。它对自己的要求和态度会像真人那样有成长性。同时互联网各种人机校验会更容易把它当真人，这样就越不容易被拦下来。&lt;/p></description></item><item><title>Wire：Go最优雅的依赖注入工具</title><link>https://bennhuang.com/zh/posts/wire/</link><pubDate>Wed, 24 Aug 2022 14:52:21 +0800</pubDate><guid>https://bennhuang.com/zh/posts/wire/</guid><description>
&lt;h2 id="导语">
&lt;a href="#%e5%af%bc%e8%af%ad" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
导语
&lt;/h2>
&lt;p>&amp;ldquo;成熟的工具，要学会自己写代码&amp;rdquo;。本文介绍了 Go 依赖注入工具 Wire 及其使用方法，以及在实践中积累的各种运用技巧。当代码达到一定规模后，Wire 在组件解耦、开发效率、可维护性上都能发挥很大的作用，尤其在大型单体仓库中。&lt;/p>
&lt;h2 id="依赖注入">
&lt;a href="#%e4%be%9d%e8%b5%96%e6%b3%a8%e5%85%a5" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
依赖注入
&lt;/h2>
&lt;p>当项目变得越来越大，代码中的依赖也越来越多：各种数据库、中间件的客户端连接，分层设计中的各种数据访问层 repositories 实例、services 实例……&lt;/p>
&lt;p>这时为了代码的可维护性，应该避免组件之间的耦合。具体的做法可以遵守一个重要的设计准则：所有依赖应该在组件实例初始化时传递给它，这就是依赖注入（&lt;a href="https://en.wikipedia.org/wiki/Dependency_injection">Dependency injection&lt;/a>）。&lt;/p>
&lt;blockquote>
&lt;p>&lt;a href="https://en.wikipedia.org/wiki/Dependency_injection">Dependency injection&lt;/a> is a standard technique for producing flexible and loosely coupled code, by explicitly providing components with all of the dependencies they need to work.&lt;/p>
&lt;p>&amp;ndash; Go 官方博客&lt;/p>&lt;/blockquote>
&lt;p>下面是个简单的例子，所有组件实例 &lt;code>Message&lt;/code>、&lt;code>Greeter&lt;/code>、&lt;code>Event&lt;/code> 的依赖都在初始化的时候获得。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">func&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">message&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nf">NewMessage&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">greeter&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nf">NewGreeter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">message&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">event&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nf">NewEvent&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">greeter&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">event&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Start&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="wire-介绍">
&lt;a href="#wire-%e4%bb%8b%e7%bb%8d" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
Wire 介绍
&lt;/h2>
&lt;p>当项目中的组件实例越来越多，如果还是手动编写初始化代码和维护组件之间依赖关系的话，会是一件非常繁琐的事情，而且在大型仓库中尤其明显。因此，社区里已经有了不少的依赖注入框架。&lt;/p>
&lt;p>除了来自 Google 的 Wire 以外，还有 &lt;a href="https://github.com/uber-go/dig">Dig&lt;/a>（Uber） 、&lt;a href="https://github.com/facebookgo/inject">Inject&lt;/a>（Facebook）。其中 Dig 和 Inject 都是基于 Golang 的 Reflection 来实现的。这不仅对性能产生影响，而且依赖注入的机制对使用者不透明，非常&amp;quot;黑盒&amp;quot;。&lt;/p>
&lt;blockquote>
&lt;p>&lt;a href="https://www.youtube.com/watch?v=PAAkCSZUG1c&amp;amp;t=14m35s">Clear is better than clever&lt;/a> ，&lt;a href="https://www.youtube.com/watch?v=PAAkCSZUG1c&amp;amp;t=15m22s">Reflection is never clear.&lt;/a>&lt;/p>
&lt;p>— Rob Pike&lt;/p>&lt;/blockquote>
&lt;p>相比之下，Wire 完全基于代码生成。在开发阶段，Wire 会自动生成组件实例的初始化代码，生成的代码人类可读，可以提交仓库，也可以正常编译。因此 Wire 的依赖注入非常透明，也不会带来运行阶段的任何性能损耗。&lt;/p>
&lt;h2 id="上手介绍">
&lt;a href="#%e4%b8%8a%e6%89%8b%e4%bb%8b%e7%bb%8d" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
上手介绍
&lt;/h2>
&lt;p>下面介绍 Wire 的使用方法&lt;/p>
&lt;h4 id="第一步下载安装-wire">
&lt;a href="#%e7%ac%ac%e4%b8%80%e6%ad%a5%e4%b8%8b%e8%bd%bd%e5%ae%89%e8%a3%85-wire" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
第一步：下载安装 Wire
&lt;/h4>
&lt;p>下载安装 &lt;a href="https://github.com/google/wire">wire&lt;/a> 命令行工具&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-shell" data-lang="shell">&lt;span class="line">&lt;span class="cl">go install github.com/google/wire/cmd/wire@latest
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h4 id="第二步创建-wirego-文件">
&lt;a href="#%e7%ac%ac%e4%ba%8c%e6%ad%a5%e5%88%9b%e5%bb%ba-wirego-%e6%96%87%e4%bb%b6" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
第二步：创建 wire.go 文件
&lt;/h4>
&lt;p>在生成代码之前，我们先声明各个组件的依赖关系和初始化顺序。在应用入口创建一个 wire.go 文件。&lt;/p>
&lt;p>&lt;code>cmd/web/wire.go&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// +build wireinject&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">package&lt;/span> &lt;span class="nx">main&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;...&amp;#34;&lt;/span> &lt;span class="c1">// 简化示例&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">ProviderSet&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nx">wire&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">NewSet&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">configs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">Get&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">databases&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">New&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">repositories&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">NewUser&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">services&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">NewUser&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">NewApp&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">func&lt;/span> &lt;span class="nf">CreateApp&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="nx">App&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">error&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">wire&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Build&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">ProviderSet&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">nil&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kc">nil&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>这个文件不会参与编译，只是为了告诉 Wire 各个组件的依赖关系，以及期望的生成结果。在这个文件：我们期望 Wire 生成一个返回 &lt;code>App&lt;/code> 实例或 &lt;code>error&lt;/code> 的 &lt;code>CreateApp&lt;/code> 函数，&lt;code>App&lt;/code> 实例初始化所需要的全部依赖都由 &lt;code>ProviderSet&lt;/code> 这个 provider 列表提供，而 &lt;code>ProviderSet&lt;/code> 声明了所有可能需要的组件的获取/初始化方法，也隐式定义了组件之间的依赖顺序。&lt;/p>
&lt;blockquote>
&lt;p>组件的获取/初始化方法，在 Wire 中叫做 &amp;ldquo;provider&amp;rdquo;&lt;/p>&lt;/blockquote>
&lt;p>还有几点需要注意：&lt;/p>
&lt;ul>
&lt;li>文件开头必须带上 &lt;code>// +build wireinject&lt;/code> 和随后的空行，否则会影响编译&lt;/li>
&lt;li>在这个文件中，编辑器和 IDE 可能无法提供代码提示，但没关系，稍后会介绍如何解决这个问题&lt;/li>
&lt;li>其中 &lt;code>CreateApp&lt;/code> 的返回（两个 nil）没有任何意义，只是为了兼容 Go 语法。&lt;/li>
&lt;/ul>
&lt;h4 id="第三步生成初始化代码">
&lt;a href="#%e7%ac%ac%e4%b8%89%e6%ad%a5%e7%94%9f%e6%88%90%e5%88%9d%e5%a7%8b%e5%8c%96%e4%bb%a3%e7%a0%81" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
第三步：生成初始化代码
&lt;/h4>
&lt;p>命令行执行 &lt;code>wire ./...&lt;/code>，然后就能得到下面这个自动生成的代码文件。&lt;/p>
&lt;p>&lt;code>cmd/web/wire_gen.go&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Code generated by Wire. DO NOT EDIT.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">//go:generate go run github.com/google/wire/cmd/wire&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">//go:build !wireinject&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// +build !wireinject&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">package&lt;/span> &lt;span class="nx">main&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="s">&amp;#34;...&amp;#34;&lt;/span> &lt;span class="c1">// 简化示例&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">func&lt;/span> &lt;span class="nf">CreateApp&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="nx">App&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">error&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">conf&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">err&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">configs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Get&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="nx">err&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="kc">nil&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">nil&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">err&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">db&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">err&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">databases&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">New&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">conf&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="nx">err&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="kc">nil&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">nil&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">err&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">userRepo&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">err&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">repositories&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">NewUser&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">db&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="nx">err&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="kc">nil&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">nil&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">err&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">userSvc&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">err&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">services&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">NewUser&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">userRepo&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="nx">err&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="kc">nil&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">nil&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">err&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">app&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">err&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nf">NewApp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">userSvc&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="nx">err&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="kc">nil&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">nil&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">err&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nx">app&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kc">nil&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h4 id="第四步使用初始化代码">
&lt;a href="#%e7%ac%ac%e5%9b%9b%e6%ad%a5%e4%bd%bf%e7%94%a8%e5%88%9d%e5%a7%8b%e5%8c%96%e4%bb%a3%e7%a0%81" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
第四步：使用初始化代码
&lt;/h4>
&lt;p>Wire 已经帮我们生成了真正的 &lt;code>CreateApp&lt;/code> 初始化方法，现在可以直接使用它。&lt;/p>
&lt;p>&lt;code>cmd/web/main.go&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// main.go&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">func&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">app&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nf">CreateApp&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">app&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Run&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="使用技巧">
&lt;a href="#%e4%bd%bf%e7%94%a8%e6%8a%80%e5%b7%a7" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
使用技巧
&lt;/h2>
&lt;h3 id="组件按需加载">
&lt;a href="#%e7%bb%84%e4%bb%b6%e6%8c%89%e9%9c%80%e5%8a%a0%e8%bd%bd" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
组件按需加载
&lt;/h3>
&lt;p>Wire 有个优雅的特点，不管在 &lt;code>wire.Build&lt;/code> 中传入了多少个 provider，Wire 始终只会按照实际需要来初始化组件实例，所有不需要的组件都不会生成相应的初始化代码。&lt;/p>
&lt;p>因此，我们在使用时可以尽可能地提供更多的 provider，把挑选组件的工作交给 Wire。这样我们在开发时不管引用新组件、还是弃用老组件，都不需要修改初始化步骤的代码 wire.go。&lt;/p>
&lt;p>比如，可以把 services 层中所有的实例构造器都提供出去。&lt;/p>
&lt;p>&lt;code>pkg/services/wire.go&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">package&lt;/span> &lt;span class="nx">services&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 提供了所有 service 的实例构造器&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">ProviderSet&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nx">wire&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">NewSet&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">NewUserService&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">NewFeedService&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">NewSearchService&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">NewBannerService&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>在初始化中，尽可能地引用所有可能需要的 provider。&lt;/p>
&lt;p>&lt;code>cmd/web/wire.go&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">ProviderSet&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nx">wire&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">NewSet&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">configs&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">ProviderSet&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">databases&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">ProviderSet&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">repositories&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">ProviderSet&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">services&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">ProviderSet&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1">// 引用了所有 service 的实例构造器&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">NewApp&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">func&lt;/span> &lt;span class="nf">CreateApp&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="nx">App&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kt">error&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">wire&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Build&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">ProviderSet&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// Wire 会按照实际需要，选择性地进行初始化&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="kc">nil&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kc">nil&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>在后续开发中，如果需要引用新的依赖组件，只需要加到参数里即可。Wire 会智能地按照实际需要，生成所需组件实例的初始化代码。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">func&lt;/span> &lt;span class="nf">NewApp&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">user&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="nx">UserService&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">banner&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="nx">BannerService&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>即使 Wire 找不到所需的 provider，也会提前在编译阶段报错，不会在线上运行阶段出现问题。&lt;/p>
&lt;pre tabindex="0">&lt;code>wire: cmd/api/wire.go:23:1: inject CreateApp: no provider found for *io.WriteCloser
&lt;/code>&lt;/pre>&lt;h3 id="编辑器与-ide-的辅助配置">
&lt;a href="#%e7%bc%96%e8%be%91%e5%99%a8%e4%b8%8e-ide-%e7%9a%84%e8%be%85%e5%8a%a9%e9%85%8d%e7%bd%ae" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
编辑器与 IDE 的辅助配置
&lt;/h3>
&lt;p>因为 &lt;code>wire.go&lt;/code> 文件中加了这行注释，Go 在编译时会跳过这个文件，但也因此会影响编辑器和 IDE 的代码提示。当你在编辑 &lt;code>wire.go&lt;/code> 文件时，常见的编辑器和 IDE 都无法正常地提供代码补全和错误提示功能。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// +build wireinject&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>但这个问题很容易解决。找到 IDE/编辑器的 Go 环境配置，在 Go Build Flags 中添加这个参数 &lt;code>-tags=wireinject&lt;/code> 就可以了。&lt;/p>
&lt;p>&lt;a class="img-link" href="https://bennhuang.com/wire.png" target="_blank" rel="noopener">&lt;img loading="lazy" src="https://bennhuang.com/wire.png" alt="" width="1062" height="176" />&lt;/a>&lt;/p>
&lt;p>这个配置可以让编辑器和 IDE 正常地为 &lt;code>wire.go&lt;/code> 文件提供代码补全和错误提示功能，开发体验显著提升。&lt;/p>
&lt;h3 id="多个同类型实例的冲突问题">
&lt;a href="#%e5%a4%9a%e4%b8%aa%e5%90%8c%e7%b1%bb%e5%9e%8b%e5%ae%9e%e4%be%8b%e7%9a%84%e5%86%b2%e7%aa%81%e9%97%ae%e9%a2%98" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
多个同类型实例的冲突问题
&lt;/h3>
&lt;p>这个问题比较少见，但项目大了总是容易遇到。&lt;/p>
&lt;p>Wire 通过 provider 的参数与返回类型，来判断依赖关系。有时候，依赖网络中可能出现同类型的不同实例，这时 Wire 无法正确判断依赖关系，会直接报错。&lt;/p>
&lt;pre tabindex="0">&lt;code>provider has multiple parameters of type ...
&lt;/code>&lt;/pre>&lt;p>比如下面这个 provider，依赖的 MySQL 和 PostgreSQL 客户端实例的类型是完全相同的（都是 &lt;code>*gorm.DB&lt;/code>），这时 Wire 无法根据类型正确地判断依赖关系，生成代码时会直接报错。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 这个 service 同时使用了 mysql 和 pg 中的数据，但是两个实例的类型是相同的&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">func&lt;/span> &lt;span class="nf">NewService&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">mysql&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="nx">gorm&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">DB&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">pg&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="nx">gorm&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">DB&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="nx">Service&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>解决的方法也比较简单，只需要做一层类型的包装。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">type&lt;/span> &lt;span class="nx">Mysql&lt;/span> &lt;span class="nx">gorm&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">DB&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">type&lt;/span> &lt;span class="nx">Pg&lt;/span> &lt;span class="nx">gorm&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">DB&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 在参数中用类型别名进行区分&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">func&lt;/span> &lt;span class="nf">ProviderService&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">mysql&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="nx">Mysql&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">pg&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="nx">Pg&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="nx">Service&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 函数内再转回原来的类型&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">r1&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="nx">gorm&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">DB&lt;/span>&lt;span class="p">)(&lt;/span>&lt;span class="nx">mysql&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">r2&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="nx">gorm&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">DB&lt;/span>&lt;span class="p">)(&lt;/span>&lt;span class="nx">pg&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nf">NewService&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">r1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">r2&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>然后用 &lt;code>ProviderService&lt;/code> 代替 &lt;code>NewService&lt;/code> 即可。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="cl">&lt;span class="nx">wire&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Build&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">ProviderMysql&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1">// func() *Mysql&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">ProviderPg&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1">// func() *Pg&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">ProviderService&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1">// func(mysql *Mysql, pg *Pg) *Service&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="自动生成构造函数">
&lt;a href="#%e8%87%aa%e5%8a%a8%e7%94%9f%e6%88%90%e6%9e%84%e9%80%a0%e5%87%bd%e6%95%b0" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
自动生成构造函数
&lt;/h3>
&lt;p>当项目中作为抽象层的结构体越来越多，手动编写和维护结构体的构造函数，也是一件非常繁琐的事情。如果结构体中新增了一个指针类型的成员、却忘记更新构造函数，甚至还会引起线上 panic。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="cl">&lt;span class="kd">type&lt;/span> &lt;span class="nx">Service&lt;/span> &lt;span class="kd">struct&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">repo&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="nx">Repository&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">logger&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="nx">zap&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">Logger&lt;/span> &lt;span class="c1">// 添加这个成员后，忘记更新构造函数了&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">func&lt;/span> &lt;span class="nf">NewService&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">repo&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="nx">Repository&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="nx">Service&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 缺失 logger，可能在线上出现空指针错误&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="nx">Service&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">repo&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nx">repo&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>像这种繁琐、重复、容易出错的工作，就应该交给自动工具来完成。这里推荐一个自动工具 &lt;a href="https://github.com/Bin-Huang/newc">newc&lt;/a>（意为 &amp;ldquo;New Constructor&amp;rdquo;），它可以自动生成与更新结构体的构造函数代码。&lt;/p>
&lt;p>使用方法非常简单，只需要给结构体添加这行注释。&lt;/p>
&lt;pre tabindex="0">&lt;code>//go:generate go run github.com/Bin-Huang/newc@v0.8.3
&lt;/code>&lt;/pre>&lt;p>比如这样：&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// My User Service&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">//go:generate go run github.com/Bin-Huang/newc@v0.8.3&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">type&lt;/span> &lt;span class="nx">UserService&lt;/span> &lt;span class="kd">struct&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">baseService&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">userRepository&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="nx">repositories&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">UserRepository&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">proRepository&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="nx">repositories&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">ProRepository&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>然后命令行执行 &lt;code>go generate ./...&lt;/code> 即可获得构造函数代码：&lt;/p>
&lt;p>&lt;code>constructor_gen.go&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// NewUserService Create a new UserService&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">func&lt;/span> &lt;span class="nf">NewUserService&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">baseService&lt;/span> &lt;span class="nx">baseService&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">userRepository&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="nx">repositories&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">UserRepository&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">proRepository&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="nx">repositories&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">ProRepository&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="nx">UserService&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="o">&amp;amp;&lt;/span>&lt;span class="nx">UserService&lt;/span>&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">baseService&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nx">baseService&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">userRepository&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nx">userRepository&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">proRepository&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="nx">proRepository&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>这个工具和 Wire 搭配使用，开发体验非常好。要使用新的依赖组件时，直接在结构体中添加成员就好了，不需要手动更新构造函数，也不需要考虑初始化的问题，所有重复的工作都交给自动工具（Wire 和 Newc）来完成。在实际项目中使用效果很好。&lt;/p>
&lt;p>当然这个工具也一定有考虑不周的情况，很期待大家的反馈和建议。&lt;/p>
&lt;blockquote>
&lt;p>Don&amp;rsquo;t repeat yourself
&amp;ldquo;DRY&amp;rdquo;&lt;/p>&lt;/blockquote>
&lt;h2 id="总结">
&lt;a href="#%e6%80%bb%e7%bb%93" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
总结
&lt;/h2>
&lt;p>Wire 可以完美地解决依赖注入的问题，但它不是一个框架，它没有”魔法“，也不是黑盒。它只是一个命令行工具，它根据实际需要，自动生成了各个组件实例的初始化代码。然后问题就解决了，没有额外的复杂性，没有运行的性能损耗。&lt;/p>
&lt;p>Wire 和 Golang 的气质如出一辙，简单、直接、实用主义，不愧是 Go 最优雅的依赖注入工具！&lt;/p>
&lt;blockquote>
&lt;p>Keep it simple stupid
&amp;ldquo;K.I.S.S&amp;rdquo;&lt;/p>&lt;/blockquote></description></item><item><title>深入讨论几种 ES Mapping 修改方法和局限</title><link>https://bennhuang.com/zh/posts/es-mapping/</link><pubDate>Mon, 14 Feb 2022 12:23:53 +0800</pubDate><guid>https://bennhuang.com/zh/posts/es-mapping/</guid><description>
&lt;h3 id="前言">
&lt;a href="#%e5%89%8d%e8%a8%80" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
前言
&lt;/h3>
&lt;p>众所周知，ElasticSearch 中的 Mapping 决定了字段的索引方式。当一个字段的索引类型确定后就无法修改。然而在日常开发中，忘记更新 mapping 是偶尔会遇到的，但修改 mapping 却是一件不容易的事情。这篇文章不仅详细讨论了 reindex 这种常见解决方法，包括 reindex 的停机和数据丢失问题、以及在各种情况下规避上述问题的思路和方法，还介绍了另外两种更加低成本的解决方法。&lt;/p>
&lt;h3 id="一个常见的错误">
&lt;a href="#%e4%b8%80%e4%b8%aa%e5%b8%b8%e8%a7%81%e7%9a%84%e9%94%99%e8%af%af" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
一个常见的错误
&lt;/h3>
&lt;p>&lt;em>“发布测试环境前我竟然忘记修改 mapping 了？”&lt;/em>&lt;/p>
&lt;pre tabindex="0">&lt;code>{&amp;#34;error&amp;#34;:{&amp;#34;root_cause&amp;#34;:[{&amp;#34;type&amp;#34;:&amp;#34;illegal_argument_exception&amp;#34;,&amp;#34;reason&amp;#34;:&amp;#34;Fielddata is disabled on text fields by default. Set fielddata=true on [player_type] in order to load fielddata in memory by uninverting the inverted index......
&lt;/code>&lt;/pre>&lt;p>&lt;del>所以我要如何快速解决这个问题呢？&lt;/del>
所以我要如何快速修改 mapping 中一个字段的索引类型呢？&lt;/p>
&lt;h3 id="reindex">
&lt;a href="#reindex" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
Reindex
&lt;/h3>
&lt;p>&lt;em>“即使对 reindex 烂熟于心，也需要留意停机时间和数据丢失……”&lt;/em>&lt;/p>
&lt;p>Reindex 几乎是这类问题的标准答案，其中一个常见思路是：创建一个新的 index-tmp，然后把数据 reindex 到这个新 index-tmp，再把原来的 index 删除重建、设置正确的 mapping，最后把数据重新从 index-tmp 中 reindex 回来。很明显这个思路除了操作危险外，还会有较长的停机时间。&lt;/p>
&lt;p>ElasticSearch 官方&lt;a href="https://www.elastic.co/cn/blog/changing-mapping-with-zero-downtime">博客&lt;/a>里曾介绍过另一种方法，只要后端业务以 alias 的方式访问 index，就可以做到完全无停机时间（Zero-Downtime）。具体思路是：首先创建一个 mapping 正确的新 index-v2，把数据 reindex 到这个新 index-v2，然后直接把 alias 重命名到这个index-v2。这样可以让后端业务直接访问到新的 index-v2，达到后端业务对 reindex 操作无感知的效果。&lt;/p>
&lt;p>然而这种方法也有不足，官方博客里完全没有提及数据丢失的问题。如果线上写入操作频繁，在 reindex 和更新 alias 步骤中有一段时间窗口，新数据依然会写入到即将弃用的旧 index，造成新 index-v2 丢失该部分数据的问题。即使采用官博推荐的 bulk API，也无法在原理上根本地规避问题。&lt;/p>
&lt;p>因此需要结合实际的业务情况，做一些因地制宜的权衡。&lt;/p>
&lt;p>&lt;strong>1. 那就丢亿点点数据&lt;/strong>&lt;/p>
&lt;p>有时候，丢失一些临时数据也是可以接受的，比如测试环境的PV上报、用来时间窗口统计的热词记录……对于这些可丢失数据，当我们发出那句灵魂拷问，“数据重要还是&lt;del>我重要&lt;/del>下班重要！”，相信产品经理也是会认真考虑的。&lt;/p>
&lt;p>&lt;strong>2. 找个夜黑风高的时候停机&lt;/strong>&lt;/p>
&lt;p>防止新数据丢失最简单的办法就是停机了。只要没有写入，哪来数据丢失。在我常常遇到的 ES 使用场景里，新数据总是通过消费者从其他数据源里同步过来，只要先让消费者暂停就可以解决问题。后端业务还是可以正常读取 ES，只是停止了消费者的写入。当一切结束后，消费者可以直接从消息队列里获取堆积的写入任务，轻松地恢复工作。&lt;/p>
&lt;p>&lt;strong>3. 让新数据先走&lt;/strong>&lt;/p>
&lt;p>能不能在不停机的情况下，也能做到不丢失数据？完全可以。创建新 index 后，立即重新设置 alias，让新 index 先开始接受新数据，然后再把老数据 reindex 过来。这样数据要么在新 index、要么在旧 index，但最终都会写入在新 index，解决了新文档丢失的问题。&lt;/p>
&lt;p>但我也想到了这种方法的几个不足和局限：&lt;/p>
&lt;ol>
&lt;li>中间会有很长一段时间（当新 index 开始接客、旧数据还没有全部 reindex 过来时），后端业务将无法访问到旧数据。这可能会对业务造成影响，比如用户突然无法搜索到以前的文章。&lt;/li>
&lt;li>这个方法只能保证新文档插入不丢失，对旧文档的更新和删除操作依然可能丢失。当然，如果业务里 ES 的使用场景是“只写不改”，那也就不是问题了。不过说起来，把 ES 用来作为 CRUD 数据库确实是很奇怪的技术选型～&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>4. 两步 reindex&lt;/strong>&lt;/p>
&lt;p>我还想到了一个方法，可以在不停机的情况下，既让后端业务尽可能正常地访问老数据，又不丢失新文档的创建。这个方法要求文档创建时附带一个 &lt;code>created_at&lt;/code> 字段。&lt;/p>
&lt;ol>
&lt;li>创建一个新的 index-v2，设置好需要的 mapping。&lt;/li>
&lt;/ol>
&lt;pre tabindex="0">&lt;code>PUT /index-v2/_doc/_mapping
{
&amp;#34;properties&amp;#34;: &amp;lt;all_you_need&amp;gt;
}
&lt;/code>&lt;/pre>&lt;ol start="2">
&lt;li>先“悄悄”准备老数据，比如先 reindex 某个时间点之前的老数据（比如一小时前）。&lt;/li>
&lt;/ol>
&lt;pre tabindex="0">&lt;code>POST _reindex
{
&amp;#34;source&amp;#34;: {
&amp;#34;index&amp;#34;: &amp;#34;index-v1&amp;#34;,
&amp;#34;query&amp;#34;: {
&amp;#34;range&amp;#34;: {
&amp;#34;created_at&amp;#34;: {
&amp;#34;lt&amp;#34;: &amp;lt;一个时间点&amp;gt;
}
}
}
},
&amp;#34;dest&amp;#34;: {
&amp;#34;index&amp;#34;: &amp;#34;index-v2&amp;#34;
}
}
&lt;/code>&lt;/pre>&lt;ol start="3">
&lt;li>当老数据准备好后，立即修改 alias，让新 index-v2 开始接受新数据。&lt;/li>
&lt;/ol>
&lt;pre tabindex="0">&lt;code>POST /_aliases
{
&amp;#34;actions&amp;#34;: [
{
&amp;#34;remove&amp;#34;: {
&amp;#34;alias&amp;#34;: &amp;#34;index&amp;#34;,
&amp;#34;index&amp;#34;: &amp;#34;index-v1&amp;#34;
}
},
{
&amp;#34;add&amp;#34;: {
&amp;#34;alias&amp;#34;: &amp;#34;index&amp;#34;,
&amp;#34;index&amp;#34;: &amp;#34;index-v2&amp;#34;
}
}
]
}
&lt;/code>&lt;/pre>&lt;ol start="4">
&lt;li>再将这个时间点之后的数据 reindex 到新 index-v2&lt;/li>
&lt;/ol>
&lt;pre tabindex="0">&lt;code>POST _reindex
{
&amp;#34;source&amp;#34;: {
&amp;#34;index&amp;#34;: &amp;#34;index-v1&amp;#34;,
&amp;#34;query&amp;#34;: {
&amp;#34;range&amp;#34;: {
&amp;#34;created_at&amp;#34;: {
&amp;#34;gte&amp;#34;: &amp;lt;一个时间点&amp;gt;
}
}
}
},
&amp;#34;dest&amp;#34;: {
&amp;#34;index&amp;#34;: &amp;#34;index-v2&amp;#34;
}
}
&lt;/code>&lt;/pre>&lt;p>这样在迁移过程中，既不需要停机，也不会丢失新数据，也不会出现长时间无法访问历史数据的问题。后端业务几乎可以访问到所有的数据，只有在第二次 reindex 期间会有极小部分数据在短时间内无法访问（不可见数据范围大约是 &lt;code>created_at: [the_timestamp, now）&lt;/code>），但也会很快地恢复。因为数据量非常少，第二次 reindex 速度很快，等到结束后，后端业务就可以完全正常地访问到所有的数据。&lt;/p>
&lt;p>这个方法可以保证新文档插入不丢失、大部分旧文档更新删除不丢失，但在第二次 reindex 期间那些不可见文档的更新、删除操作依然有丢失的可能。这个方法在不停机的前提下大幅地缩小了负面影响的范围。&lt;/p>
&lt;p>&lt;strong>小结&lt;/strong>&lt;/p>
&lt;p>以上只是尽可能地讨论了 reindex 在实际业务中可能遇到的问题，以及可行的方法与思路。虽然在实际应用中，大多数情况都可以用简单直接的方法解决，比如遗弃数据和停机，但认识更多情况可以规避潜在的决策风险。&lt;/p>
&lt;p>对了，这里没有讨论 reindex 优化，我感觉这是另外一个话题了。我看到有些高赞文章提到通过配置来增大 reindex 单次索引的文档数量，或者通过 scroll 并发来加快索引。我直观的感觉，这些方法在停机情况下应该是不错的做法，但在不停机时可能会给集群带来更多的压力，尤其是 index 数据量很大、读写频繁的场景，可能会影响到正常的业务。在不停机的情况，也许我们应该更多考虑的不是如何加快 reindex 过程，而是尽可能降低 reindex 对正常业务的影响。&lt;/p>
&lt;p>除了 reindex，还有其他一些方法可以“修改”已有字段的索引类型。&lt;/p>
&lt;h3 id="新字段替换">
&lt;a href="#%e6%96%b0%e5%ad%97%e6%ae%b5%e6%9b%bf%e6%8d%a2" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
新字段替换
&lt;/h3>
&lt;p>&lt;em>“既然不能直接修改原来字段的索引类型，那我重新建个字段好吧……”&lt;/em>&lt;/p>
&lt;p>很多时候，为了一点点错误索引的数据而 reindex 整个 index，也许是一件大动干戈的事情。利用其他技巧可以更加低成本的解决问题，比如建个新字段。&lt;/p>
&lt;ol>
&lt;li>在 mapping 添加新字段 new_field，设置好需要的索引方式&lt;/li>
&lt;/ol>
&lt;pre tabindex="0">&lt;code>PUT /my-index/_doc/_mapping
{
&amp;#34;properties&amp;#34;: {
&amp;#34;new_field&amp;#34;: {
&amp;#34;type&amp;#34;: &amp;#34;keyword&amp;#34;
}
}
}
&lt;/code>&lt;/pre>&lt;ol start="2">
&lt;li>将原来文档的旧字段的值重新赋予到新字段&lt;/li>
&lt;/ol>
&lt;pre tabindex="0">&lt;code>POST /my-index/_update_by_query?conflicts=proceed
{
&amp;#34;script&amp;#34;: {
&amp;#34;source&amp;#34;: &amp;#34;ctx._source.new_field = ctx._source.old_field&amp;#34;,
&amp;#34;lang&amp;#34;: &amp;#34;painless&amp;#34;
},
&amp;#34;query&amp;#34;: {
&amp;#34;exists&amp;#34;: { &amp;#34;field&amp;#34;: &amp;#34;old_field&amp;#34; }
}
}
&lt;/code>&lt;/pre>&lt;ol start="3">
&lt;li>在业务代码中弃用原来的字段&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>小结&lt;/strong>&lt;/p>
&lt;p>这个方法非常适合低成本解决少量数据被错误索引的情况，比如在发布前忘记修改 mapping。但是如果需要修改索引类型的数据很多，这个方法需要更新大量已有数据，可能会对集群带来一定压力。毕竟在 ElasticSearch 里，所谓的文档修改就是先标记删除、然后重新插入，如果要更新整个 index 的所有文档，也许还不如 reindex 来得痛快……&lt;/p>
&lt;h3 id="采用-multi-field">
&lt;a href="#%e9%87%87%e7%94%a8-multi-field" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
采用 multi-field
&lt;/h3>
&lt;p>&lt;em>&amp;ldquo;作为一个成熟的 DB，总是可以为一个字段建立多种索引……&amp;rdquo;&lt;/em>&lt;/p>
&lt;p>ElasticSearch 的 &lt;code>multi-field&lt;/code> 特性，让同一个字段可以有多种不同的索引类型。我们可以利用这个特性在 mapping 中为老字段追加新的索引类型。比如这个例子：&lt;/p>
&lt;pre tabindex="0">&lt;code>PUT /my-index/_doc/_mapping
{
&amp;#34;properties&amp;#34;: {
&amp;#34;company&amp;#34;: {
&amp;#34;type&amp;#34;: &amp;#34;keyword&amp;#34;,
&amp;#34;fields&amp;#34;: {
&amp;#34;name&amp;#34;: {
&amp;#34;type&amp;#34;: &amp;#34;text&amp;#34;
}
}
}
}
}
&lt;/code>&lt;/pre>&lt;p>原本 company 字段采用了 &lt;code>keyword&lt;/code> 的索引类型，只能用于数值匹配。在上面的例子中，为 company 字段追加了另一种支持全文搜索的索引类型 &lt;code>text&lt;/code>，然后把这个全文搜索版本取名叫 company.name。这样查询条件 &lt;code>{ &amp;quot;company.name&amp;quot;: &amp;quot;腾讯&amp;quot; }&lt;/code> 就可以匹配到 &lt;code>{ &amp;quot;company&amp;quot;: &amp;quot;腾讯科技有限公司&amp;quot; }&lt;/code> 的数据了。&lt;/p>
&lt;p>因为本质上只是对同一个字段添加不同的索引，实际文档（documents）中并不会真的多出来一个叫 company.name 的字段，插入数据时也不需要为 company.name 赋值。一切索引工作都由 ElasticSearch 自动完成。&lt;/p>
&lt;p>然而用这种方法修改 mapping 后，只有新的写入才会让该文档的新索引生效。也就是说，只有插入新的文档、或者更新旧文档时，ElasticSearch 才会给该文档重新索引、将该文档写入新索引。除非老数据有更新，用 company.name 无法搜索到老数据，因为老数据根本不在这个索引里！&lt;/p>
&lt;p>但问题总是可以解决，不就是还差一次全局更新嘛～（坏笑脸&lt;/p>
&lt;pre tabindex="0">&lt;code>// 这个更新没有任何意义，纯粹是为了触发老数据的重新索引
POST /my-index/_update_by_query?conflicts=proceed
{
&amp;#34;script&amp;#34;: {
&amp;#34;source&amp;#34;: &amp;#34;ctx&amp;#34;,
&amp;#34;lang&amp;#34;: &amp;#34;painless&amp;#34;
},
&amp;#34;query&amp;#34;: {
&amp;#34;exists&amp;#34;: { &amp;#34;field&amp;#34;: &amp;#34;company&amp;#34; }
}
}
&lt;/code>&lt;/pre>&lt;p>&lt;strong>小结&lt;/strong>&lt;/p>
&lt;p>这个方法不仅适合低成本解决少量数据被错误索引的情况，而且在同个字段需要多种索引方式（尤其需要是搭配不同的分析器）时这几乎是唯一的做法，因为 &lt;code>multi-field&lt;/code> 就是为了这种场景准备的。但这个方法同样需要注意更新数据的规模，以及对性能的影响……&lt;/p>
&lt;h2 id="最后">
&lt;a href="#%e6%9c%80%e5%90%8e" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
最后
&lt;/h2>
&lt;p>我在中英互联网上搜索时，发现很难找到详细讨论这个话题的文章。其中我找到最好的资料是 ElasticSearch 官博的一篇文章，里面简要介绍了这三种方法，但是很少介绍各个方法的局限、已知问题和适用场景，比如几乎没有提到 reindex 的数据丢失问题。我还找到了很多只言片语，它们大多只是简单提供了一个解决方法，却很少介绍方法的用意和局限。&lt;/p>
&lt;p>所以我尝试写篇文章，想着结合自己的认识和理解，试着更加全面地讨论一下各个方法的利弊权衡，看看能不能从这个常见的小问题出发，窥探到一点点原理和设计的影子，填补一点点底层技术与实际业务的缝隙，引发一些可能的讨论和思路。&lt;/p>
&lt;p>最后不得不感叹：方法常有，银弹难寻！只有根据实际情况，在业务可接受的影响范围内，找到最简单方法，往往那就是最佳实践。&lt;/p>
&lt;h2 id="参考">
&lt;a href="#%e5%8f%82%e8%80%83" class="anchor">
&lt;svg class="icon" aria-hidden="true" focusable="false" height="16" version="1.1" viewBox="0 0 16 16" width="16">
&lt;path fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z">
&lt;/path>
&lt;/svg>
&lt;/a>
参考
&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-reindex.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-reindex.html&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/multi-fields.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/multi-fields.html&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-put-mapping.html#add-multi-fields-existing-field-ex">https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-put-mapping.html#add-multi-fields-existing-field-ex&lt;/a>&lt;/li>
&lt;/ul></description></item></channel></rss>