E

Elmagnifico's Blog

后端与嵌入式、maya与游戏 | elmagnifico, Back-end engineer & Embedded System Lover | 这里是elmagnifico的个人博客,君子之交淡如水。

理想的AI工作流

<h2 id="foreword">Foreword</h2> <p><a href="/2026/06/24/Agent-Workflow/">上一篇</a>那套 Agent 工作流其实并不完善,它只是当下<strong>妥协</strong>出来的一套流程——文档先行、人卡在几个关口审一审、<code class="language-plaintext highlighter-rouge">task.md</code> 记着进度。说白了,是拿「流程纪律」硬填 Agent 接不进现有工程链路的坑。</p> <p>那理想的工作流长啥样?光有纪律不够,还得往下再走一层:<strong>把调试、测试、联调都改造成 Agent 能直接上手的样子</strong>,人退到只管设计和审核。</p> <h2 id="一个够复杂的例子">一个够复杂的例子</h2> <p>先摆个够复杂的项目当靶子——能把它捋顺,剩下大部分工程场景也就差不多了:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>嵌入式软件 A 基于 硬件 B 算法 C 服务于 PC 软件 D 和 PC 软件 E PC 软件 D 基于通信协议 与嵌入式软件 A 交互 PC 软件 E 基于特定协议文件 与软件 D 交互 Web 软件 F 基于网络协议 与软件 D、E 交互 安卓端 G 基于网络协议 与软件 D 交互 iOS 端 H 基于网络协议 与软件 D 交互 </code></pre></div></div> <p>这里先不考虑额外的自动化测试工程(就是那种独立于业务架构、单独起一套的测试工程)。我的想法是:测试能力最好长在每个组件自己身上,而不是另起一座测试孤岛。</p> <pre><code class="language-mermaid">flowchart LR B["硬件 B"] --&gt; A["嵌入式 A"] A &lt;--&gt;|通信协议| D["PC 软件 D"] C["算法 C"] --&gt; D C --&gt; E["PC 软件 E"] D &lt;--&gt;|协议文件| E D &lt;--&gt;|网络协议| F["Web F"] D &lt;--&gt;|网络协议| G["安卓 G"] D &lt;--&gt;|网络协议| H["iOS H"] E &lt;--&gt;|网络协议| F classDef hw fill:#f8cecc,stroke:#b85450 classDef emb fill:#dae8fc,stroke:#6c8ebf classDef pc fill:#d5e8d4,stroke:#82b366 classDef net fill:#fff2cc,stroke:#d6b656 class B hw class A emb class D,E,C pc class F,G,H net </code></pre> <p>这张图里,<strong>每条箭头都是 Agent 联调时要跨的边界</strong>。理想情况下,边界两头都该露出「机器能读、机器能调」的接口;可现实里呢,很多边界就只有个 GUI、一台示波器、或者一段得靠人眼看的波形——Agent 走到这儿就断了,再往前一步都迈不动。</p> <table> <thead> <tr> <th>边界</th> <th>理想态里 Agent 能用的接口</th> <th>现实里常见的断点</th> </tr> </thead> <tbody> <tr> <td>A ↔ B</td> <td>仿真器 / 真机 MCP、寄存器 dump、固件烧录 CLI</td> <td>只有 JTAG 调试器,外加人眼看灯</td> </tr> <tr> <td>D ↔ A</td> <td>协议帧日志、回放脚本、mock 设备</td> <td>只有串口助手,肉眼对十六进制</td> </tr> <tr> <td>D ↔ E</td> <td>协议文件 + 结构化 diff</td> <td>二进制专有格式,连 schema 都没有</td> </tr> <tr> <td>D ↔ F/G/H</td> <td>HTTP/gRPC 契约 + 集成测试 API</td> <td>一堆 UI 点击流,没有 headless 入口</td> </tr> <tr> <td>算法 C</td> <td>固定输入输出向量、基准测试 CLI</td> <td>只有 MATLAB 图,没法量化断言</td> </tr> </tbody> </table> <p>一句话:上篇解决的是「文档和代码怎么对上」,这篇要解决的是「Agent 到底摸不摸得到这些边」。</p> <h2 id="人把路铺好agent-才能跑闭环">人把路铺好,Agent 才能跑闭环</h2> <p>理想的 Agent 工作流,我觉得能一句话概括:</p> <p><strong>该人干的人干好——定方向、划边界、把物理和权限上的路打通;编码、联调、测试丢给 Agent;最后审核还是人来拍板。</strong></p> <p>这么一来,工程师的身份其实变了:从「自己埋头写代码」变成「设计系统 + 管 Agent」。不是说细节就不管了,而是把细节约束提前写进一个 Agent 能读、能跑、还能自己判断对错的环境里。</p> <h2 id="假如上下文真的无限">假如上下文真的无限</h2> <p>先做个假设:要是 Agent 上下文接近无限,不会「聊着聊着就忘了 S8 之前不能写代码」,那工作流就能尽量照着人类团队那套来搭——产品提需求、开发写实现、测试验结果、负责人拍板,只不过每个岗位都能换成 Agent,人只挑几步插手。</p> <p>但有个坑特别容易忽略:<strong>上下文无限 ≠ Agent 就可靠了。</strong></p> <ul> <li>会话一长,早期定的规矩照样会被慢慢带跑偏,外部事实源(<code class="language-plaintext highlighter-rouge">task.md</code>、wolai 定稿)还是省不掉</li> <li>跨会话没有「责任连续性」,得靠文档和关口一棒一棒接</li> <li>「记得住」不等于「判断对」——复核、追溯表该做还得做</li> </ul> <p>所以哪怕上下文不再是瓶颈,流程纪律和那些能被观测的边界,依旧是硬需求;区别只是你能腾出更多精力,去搞「链路打通」这件正事。</p> <h2 id="人该干啥">人该干啥</h2> <p>理想态里,人确实不用一行行去写实现了。但下面这几件事,短期内真不好甩给 Agent:</p> <table> <thead> <tr> <th>人留着的活</th> <th>为啥甩不掉</th> </tr> </thead> <tbody> <tr> <td>定方向、划范围</td> <td>「要做啥」得人说了算,不然 Agent 分分钟给你 scope creep</td> </tr> <tr> <td>划协议和模块边界</td> <td>A~H 之间谁跟谁说话、合同是啥,这得架构师定</td> </tr> <tr> <td>打通物理世界</td> <td>真机、夹具、烧录器、各种权限——Agent 没有手,够不着</td> </tr> <tr> <td>审核拍板</td> <td>安全、业务意图、能不能交给客户,这些 AI 不背锅</td> </tr> <tr> <td>把工程改造成 Agent 友好</td> <td>加 CLI、加结构化日志、加可回放测试——这是落到人头上的新「搬砖」</td> </tr> </tbody> </table> <p>最后一条最关键:理想工作流不是干等 Agent 变强就行,而是<strong>人得主动把环境收拾成一个 Agent 能上岗干活的车间</strong>。</p> <h2 id="agent-的壁垒">Agent 的壁垒</h2> <p>要是真打算一切围着 Agent 转,那软件之间的交互、调试、测试都得为它服务。可现在的工具链基本是给人、给业务用的,Agent 在不少环节根本插不进手。</p> <p><strong>1. 没有 CLI,也没有能下断言的输出</strong></p> <p>测试这一环,特别多是靠人眼判断的,要么软件压根没有命令行式的输入输出。这种工具 Agent 用不了,测试就又被踢回给人。上篇说过那句话:能编译通过 ≠ 能自测。</p> <p><strong>2. 图和文之间那道墙(原生 UI 尤其惨)</strong></p> <p>UI 的设计和实现之间,在非 Web 的场景下,几乎没有一门 Agent 能操作的「中间语言」——你想用代码或文字精确描述「这个控件偏了 2px」「这个动效不对劲」,太难了。Web 好歹还有 DOM 加截图兜底,桌面和移动端的原生 UI 就更吃亏。</p> <p><strong>3. 视频和图文之间,差距更大</strong></p> <p>这比静态图又高一层:时序、动画、音画同步……Agent 理解起来成本陡增。录屏加抽帧对比能缓解一点,但离「能下可靠断言」还差得远。这一层现阶段 Agent 基本进不来,只能等技术再往前走走。</p> <p><strong>4. 状态和时序这道坎</strong></p> <p>很多 bug 根本不在「某一帧画面」上,而是藏在<strong>时序、并发、中断、实时性</strong>里——协议莫名少了一帧、DMA 跟主循环抢资源、电机响应慢了 3ms。这类问题没有一张稳定的文本快照能截下来,Agent 拿不到「现场」,只能干等着人来一句「刚才好像卡了一下」。</p> <h2 id="agent-友好">Agent 友好</h2> <p>「为 Agent 改造」不能拍脑袋,我归了四条,拿来挨个对比够不够格:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>可观测 — 状态能用文本或结构化数据吐出来(日志、dump、协议帧、指标) 可驱动 — 能用命令行 / API / 脚本触发,不靠鼠标点 可断言 — 结果能让程序判定对错,不只靠人眼,不凭感觉 可复现 — 同样的输入能稳定重放(硬件场景下就是能录能回放) </code></pre></div></div> <p>四条全占上,Agent 才可能在这个环节自己跑出闭环;缺一条,人就还得在那儿补位。</p> <h2 id="把-agent-当员工">把 Agent 当员工</h2> <p>软硬件联调这块,得能模拟硬件,最好直接把<strong>真机接进流程</strong>——让 Agent 能直接调:烧录、读寄存器、发指令、读传感器,连硬件调试那条链路也接进来。</p> <p>一句话:<strong>把 Agent 当个正常员工看待,人手里有啥工具,就得给它配上对应的接口。</strong></p> <p>以上述项目为例:</p> <ul> <li><strong>好处</strong>:不必另起一套独立测试工程架构,协议联调、硬件逻辑、软件互动可以在同一条链路上闭环验证</li> <li><strong>现状难点</strong>:硬件没有接入 Agent——没有「Agent 能发指令、读状态、判定硬件是否稳定」的链路打通。Agent 写完软件补丁,闭环断在真机这一侧,只能等人工测试一遍、口述结果</li> <li><strong>理想态</strong>:Agent 完成编码和可自动化部分的测试;人只做设计评审、安全审核、以及 Agent 够不着的物理操作授权</li> </ul> <p>这其实就是上篇「测试压力全压人身上」的极端版:越靠近物理世界,改造成本越高,可一旦打通,闭环带来的收益也越大。</p> <h2 id="多agent融合">多Agent融合</h2> <p>回到 A~H 那张图,真要并行干,基本就是<strong>一个组件开一个 Agent</strong>,各跑各的会话。那它们之间怎么对齐?靠的不是谁记着谁,而是<strong>协议文档当合同</strong>——边界上的协议、报文格式、接口契约都写死在文档里,改 A 的 Agent 和改 D 的 Agent 各自照着合同来。谁想动合同,就得回到人这儿重新评审。这跟上篇团队版里「多方 Agent + 协议文档联调」是一个意思,只是这里把它当成默认姿势。</p> <p>还有个容易被忽略的点:Agent 既写代码又写测试,等于自己给自己发合格证。所以人审的时候,重点不光是看代码,更得看<strong>测试本身合不合理</strong>——断言够不够狠、边界有没有漏、是不是为了让用例「变绿」把条件写松了。测试用例的设计意图这一关,还得人来守。</p> <h2 id="改造成本">改造成本</h2> <p>为 Agent 重做调试、测试链路,是<strong>实打实要砸进去的工程量</strong>,不是改几行 Skill 就完事的:</p> <table> <thead> <tr> <th>要砸的地方</th> <th>举个例子</th> <th>短期啥感受</th> </tr> </thead> <tbody> <tr> <td>协议可观测</td> <td>D↔A 通信录包 + 文本回放</td> <td>开发节奏变慢</td> </tr> <tr> <td>原生 UI 可测</td> <td>G/H 加 headless 或截图 diff 管线</td> <td>得动客户端架构</td> </tr> <tr> <td>硬件在环</td> <td>真机 MCP、仿真器、安全互锁</td> <td>要硬件团队配合</td> </tr> <tr> <td>规范成文</td> <td>MVVM、日志、目录约定写进 <code class="language-plaintext highlighter-rouge">task.md</code></td> <td>文档变厚</td> </tr> </tbody> </table> <p><strong>怎么取舍</strong>:小需求、一次性脚本,犯不上全链路改造,上篇那套妥协流程就够用了。但要是个长期维护的多端 + 嵌入式产品,那越早把边界上那四条判据补齐越划算——Agent 能扛的环节越多,人就越往「架构师 + 审核员」那个位置挪。</p> <p>不是所有项目都得追理想态。关键是先搞清楚<strong>断点卡在哪</strong>,再决定是花钱打通链路,还是干脆让人补位。</p> <h2 id="理想工作流">理想工作流</h2> <p>把前面这些收回到例子上,理想态大概是这么转的:</p> <ol> <li><strong>人</strong>:定义各组件的职责和协议合同;把定稿沉淀到需求 / <code class="language-plaintext highlighter-rouge">task.md</code>;给 Agent 开通真机、网络、仓库的权限</li> <li><strong>Agent(可以按组件各开一条会话)</strong>:读合同 → 改 A/D/E… → 用 CLI/API 把自己这块测了 → 跨边界的就用录包 / mock / 集成脚本联调</li> <li><strong>人审核</strong>:协议变更、安全相关、UI 主观体验、真机实飞——关口不过就不合并</li> </ol> <pre><code class="language-mermaid">flowchart TB HUMAN["人:方向 / 边界 / 权限 / 审核"]:::human AGENT["Agent:编码 / 自测 / 联调脚本"]:::ai CHAIN["Agent 友好链路&lt;br/&gt;CLI · 日志 · 录包 · 真机 MCP"]:::chain PROD["A~H 各组件"]:::prod HUMAN --&gt;|定契约| PROD HUMAN --&gt;|打通| CHAIN CHAIN --&gt; AGENT AGENT --&gt;|可观测可驱动| PROD AGENT --&gt;|阻塞 / 需拍板| HUMAN classDef human fill:#d5e8d4,stroke:#82b366,color:#333 classDef ai fill:#dae8fc,stroke:#6c8ebf,color:#333 classDef chain fill:#fff2cc,stroke:#d6b656,color:#333 classDef prod fill:#f5f5f5,stroke:#999,color:#666 </code></pre> <p>说到底,上篇拼的是<strong>文档纪律</strong>,这篇拼的是<strong>环境纪律</strong>。两样叠一块,才勉强够得着「Agent 写完就能交付、人只管设计和审核」那个理想。</p> <h2 id="summary">Summary</h2> <p>上篇那套妥协流程,解决的是「别让 Agent 跑偏」;这篇想再往前一步,解决「别让 Agent 卡在链路外头」。几个结论:</p> <ul> <li><strong>协议边界就是 Agent 的联调边界</strong>,每条边都得往「可观测、可驱动、可断言、可复现」上靠</li> <li><strong>四道坎</strong>:没 CLI、图文、视频、时序——越往后越难啃,嵌入式真机是最硬那块骨头</li> <li><strong>人的活儿变了</strong>:少写实现,多去划边界、打通物理渠道、改造环境、做审核</li> <li><strong>上下文再大,也替不掉</strong>外部事实源和关口</li> <li><strong>改造成本是真金白银</strong>,得按项目掂量——小需求用妥协流程,长期多端、嵌入式才值得砸链路下去</li> </ul> <p>理想不是「Agent 啥都能干」,而是「该它闭环的地方,它真能闭上」;闭不上的,人就老老实实补位,别假装全自动。</p> <p>往远了说,这事不光取决于 Agent 多聪明,更取决于<strong>整条工具链愿不愿意把「机器能用的接口」露出来</strong>——厂商给硬件、给软件配上 CLI 和 MCP,给调试器留个程序能调的口子。这一步迈出来之前,理想工作流就还只是「理想」。</p> <h2 id="quote">Quote</h2> <blockquote> <p>人手里有啥工具,就得给 Agent 配上对应的接口——不然所谓工作流,只是换了个写代码的实习生,谈不上什么新工种。</p> </blockquote>

2026/7/1
阅读更多

AI工作流

<h2 id="foreword">Foreword</h2> <p>前段时间在 wolai 里把一套「一个人带 Agent 做产品」的流程摸清楚了,顺手画了一张图,又写了一份更偏团队协作的 Agent 方案。下文先展开独自开发(AIO)如何把产品、开发、测试、总负责人压缩成「你 + Agent」;再讲团队版(FTM)如何拆回四个岗位。文档怎么流转、人在哪几步必须插手、以及怎么把踩过的坑固化成 Skill,两家共用。</p> <p>AIO,All-in-one</p> <p>FTM,Four man team</p> <h4 id="为什么要先定工作流">为什么要先定工作流</h4> <p>AI 写代码很快,快到你还没来得及想清楚需求,它已经给你造了三层抽象、两个 Design Pattern 和一个你根本没要的缓存层。没有流程约束,Agent 就像个热情过头的实习生:活干得猛,方向全靠猜,你没规范的内容往往走出了意想不到的呈现方式。</p> <p>所以我现在的原则是:<strong>先文档、后代码;先评审、后构建;缺陷不只改代码,还要反向更新文档。</strong> 文档全部放在 wolai,暂时不进 Git 仓库——wolai 自带版本历史,需求和工程文档跟代码解耦,Agent 通过 MCP 读写文档,人负责拍板。</p> <p>开发分为好几种</p> <ol> <li>从0开始的,业务是全新的,不需要理解之前的东西,很简单,全部交给AI即可</li> <li>从0.5开始,业务已经存在了,是对已有业务的修改或者补充,需要让AI知道当前业务到底是什么,上下文、对齐非常重要</li> <li>从1开始,业务完整,对某些小bug,涉及内容非常小的进行修改或者找到bug所在</li> <li>核心性能或者算法或者非常小众领域的类型开发,创新式的,AI很难给出满意的答案</li> </ol> <p>目前Agent主要解决的是1、2、3,能完全交给Agent的基本是1和3,2需要大量的上下文和超级健全的工程框架</p> <h2 id="aio-整体流程">AIO 整体流程</h2> <p>流程图里绿色节点是<strong>人工</strong>,蓝色是 <strong>AI</strong>。主流程自上而下阅读(需求在顶、交付在底);评审纠偏与缺陷回流单独成图,避免横向过宽。</p> <p><strong>主流程</strong></p> <pre><code class="language-mermaid">flowchart TB A1["相关需求补充/查找"]:::ai H1["需求"]:::human H2["工程背景补充"]:::human A2["AI 结合工程进行需求评审"]:::ai A3["AI 编写技术文档"]:::ai H5["人工审核技术点与判断依据"]:::human P1["代码构建"]:::ai P2["测试文档 + 用例构建"]:::ai H7["人工测试,核验需求是否完成"]:::human A9["AI 复核并同步各文档"]:::ai H9["人工复核"]:::human A10["生成功能使用说明文档"]:::ai H10["复核文档,结束"]:::human A1 --&gt; H1 --&gt; H2 --&gt; A2 --&gt; A3 --&gt; H5 H5 --&gt; P1 &amp; P2 P1 --&gt; H7 P2 --&gt; H7 H7 --&gt; A9 --&gt; H9 --&gt; A10 --&gt; H10 NOTE["前提:相关代码仓库需可被 AI 读取"]:::note H2 -.-&gt; NOTE classDef human fill:#d5e8d4,stroke:#82b366,color:#333 classDef ai fill:#dae8fc,stroke:#6c8ebf,color:#333 classDef note fill:#f5f5f5,stroke:#999,color:#666 </code></pre> <p><strong>评审纠偏与缺陷回流</strong>(主流程中未通过时进入)</p> <pre><code class="language-mermaid">flowchart TB subgraph R1["需求评审纠偏"] RA2["AI 需求评审"]:::ai RH3["检查理解错误"]:::human RH4["补充修正材料"]:::human RA2 --&gt; RH3 --&gt; RH4 --&gt; RA2 end subgraph R2["技术文档订正"] RH6["订正错误点"]:::human RA3["AI 技术文档"]:::ai RH6 --&gt; RA3 end subgraph R3["测试未通过"] RH8["向 AI 说明不符合项"]:::human RA7["重新修正代码"]:::ai RA8["回流 Skill"]:::ai RDOC["反向更新需求/技术/测试文档"]:::ai RH8 --&gt;|实现问题| RA7 RH8 --&gt;|需求/设计问题| RA8 --&gt; RDOC end classDef human fill:#d5e8d4,stroke:#82b366,color:#333 classDef ai fill:#dae8fc,stroke:#6c8ebf,color:#333 </code></pre> <p>核心链路如下:</p> <ol> <li><strong>需求输入</strong>:产品需求写在需求文档中(评审后的版本)。AI 可辅助「相关需求补充/查找」,但<strong>需求正文不允许 AI 0-1 生产,只允许补充和审查</strong>——方向错了后面全白干。</li> <li><strong>工程背景补充</strong>:人工补充本需求涉及的仓库、模块、历史决策、接口约束。前提:<strong>相关代码仓库都要能被 AI 读到</strong>(Cursor 打开多仓库工作区、MCP filesystem都需要准备好)。</li> <li><strong>AI 需求评审</strong>:Agent 结合工程上下文审需求,标出歧义、遗漏、与现有架构冲突的点。</li> <li><strong>人工纠偏</strong>:检查 AI 有没有理解错;把补充材料、对开放问题的答复写回 需求文档。</li> <li><strong>AI 编写技术文档</strong>:输出工程设计(模块划分、接口、数据流、边界条件)。同步可起草测试文档骨架。</li> <li><strong>人工审核技术文档</strong>:重点看技术选型依据、判断条件、隐含假设有没有跑偏;错了就「订正错误点」打回,对了才往下走。</li> <li><strong>并行构建</strong>:<strong>代码构建</strong>与<strong>测试用例构建</strong>同时进行——代码里最好包含 CI/CD,交到测试环节时应是可运行的完整产物,而不是半截子 PR。</li> <li><strong>人工测试</strong>:按测试文档走流程,核验需求是否真正完成。有问题就逐条告诉 AI 哪里不对,进入「重新修正代码」循环。</li> <li><strong>缺陷回流</strong>:若发现的是需求/设计层面的问题,不能只改代码——要回流更新需求、技术、测试文档,并补上对应用例。</li> <li><strong>AI 复核</strong>:开发完成后,让 Agent 交叉检查需求、工程、测试、实现是否一致,文档是否互相印证,能否交付、能否合并主分支作为下一迭代基线。</li> <li><strong>人工复核 + 使用文档</strong>:人做最后一眼;AI 基于定稿内容生成面向用户/运维的说明文档,再复核一遍,结束。</li> </ol> <p>用一句话概括:<strong>人定方向、人审关键节点;AI 写文档、写代码、写用例、做一致性检查;文档作为单一事实来源。</strong></p> <p>下面是一个核心的 <code class="language-plaintext highlighter-rouge">task.md</code> 示例:补充项目信息、开发规范和任务需求,也记录 Agent 各步操作。每轮会话 Agent 都先读它再继续,整体进度同步在这里。想接续开发或并行多任务,复制一份 task 即可,互不干扰。</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># 任务:abc-123 &gt; 本文件分两部分:**【一、任务信息】** 初始化时填写、相对稳定;**【二、进度与共创记录】** 开发过程中动态更新。 &gt; 新任务:复制本结构,重填「一」、清空「二」即为初始状态。多任务并行时每个任务一份(见 `docs/tasks/&lt;需求ID&gt;.md`),会话开始时指定要接续的任务。 --- # 一、任务信息(初始化头部) ## 基本信息 | 项 | 值 | | --- | --- | | 需求 ID | abc-123 | | 标题 | 需求abc-123 | | 类型 | feature | | 模式 | solo(AIO) | | 开发分支 | `abc` | | 基线 | `dev` | ## 文档链接 | 文档 | 链接 | | --- | --- | | 需求页 | [A](https://www.wolai.com/abc) | | 技术+测试 | [B](https://www.wolai.com/abc) | ## 关联工程项目(workspace) - A - B - C ## 涉及模块 - A - B - C ## 架构与规范要求 - 语言/框架 - MVVM:新代码 `CommunityToolkit.Mvvm`;遗留 `PropertyChanged.Fody` - 日志:结构化日志 - 本地化:zh-cn / en-us - 格式/注释: - 测试: --- # 二、进度与共创记录 ## 当前阶段 **S9 代码实现(已含 S11 复评修复;待人工确认推进 S10+)** ### 阶段清单 - [x] S0 开工登记(Wolai 需求页) - [x] S1 需求输入 - [x] S2 工程背景(技术页 §0) - [x] S3 需求评审 - [x] S4 人工纠偏(评审表已确认) - [x] S5 技术+测试起草(技术页 §9–§11) - [x] S6 审核技术 - [x] S7 测试二次补全(技术页 §11.2) - [x] S8 评审关口(已确认进入 S9) - [x] S9 并行构建(代码 + 33 项自动化回归 + CI) - [ ] S10 人工测试 - [ ] S11 AI 复核(评审问题修复已先行完成) - [ ] S12 使用说明(已写回 wolai 需求页 S12) - [ ] S13 合并基线 ## 待反馈 / 开放问题 - 暂无。 ## 已确认结论(摘要) ## 变更记录 ## 实现摘要 / 行动记录 </code></pre></div></div> <h2 id="ftm-团队协作版">FTM 团队协作版</h2> <p>FTM(Four Man Team)是上文 AIO 的扩展:流程骨架相同,但把人拆回四个角色,各管一摊,Agent 穿插在文档生成、代码构建和一致性复核里,人负责方向、评审和拍板。</p> <p><strong>角色分工</strong></p> <table> <thead> <tr> <th>角色</th> <th>主要职责</th> </tr> </thead> <tbody> <tr> <td>产品经理</td> <td>维护需求文档与总体进度看板;<strong>需求由人写,AI 只审不改</strong></td> </tr> <tr> <td>软件开发工程师</td> <td>补充工程背景;与 Agent 结对完成代码构建和 Code Review</td> </tr> <tr> <td>自动化测试工程师</td> <td>审测试文档、补探索性用例;跑自动化 + 人工流程验证</td> </tr> <tr> <td>总负责人</td> <td>需求/技术/测试三份文档<strong>最终评审拍板</strong>;决定是否进入开发与合并</td> </tr> </tbody> </table> <p>文档全部落在 wolai,暂不进 Git 仓库——wolai 自带版本历史,需求和工程文档与代码解耦,各角色通过 MCP 读写同一份需求页下的子文档。</p> <p><strong>团队版主流程</strong></p> <p>图例:绿色 = 人工主导,蓝色 = Agent 主导,<strong>青绿色(虚线边框)</strong> = 人机协作(结对进行)。</p> <pre><code class="language-mermaid">flowchart TB PM["产品经理:需求文档"]:::human MCP["wolai MCP"]:::note AG["Agent:工程 + 测试文档"]:::ai RV["总负责人:三文档评审"]:::human DEV["开发 ⇄ Agent:代码构建"]:::hybrid QA["测试 ⇄ Agent:用例 + 验证"]:::hybrid AUD["Agent:AI 复核"]:::ai DOC["Agent ⇄ 人工:使用/说明文档"]:::hybrid END["人工复核,合并基线"]:::human PM --&gt; MCP MCP --&gt; AG AG --&gt; RV RV --&gt;|通过| DEV RV --&gt;|通过| QA DEV --&gt; QA QA --&gt;|缺陷| FIX{"缺陷类型"} FIX --&gt;|实现| DEV FIX --&gt;|需求/设计| PM QA --&gt;|通过| AUD AUD --&gt; DOC --&gt; END classDef human fill:#d5e8d4,stroke:#82b366,color:#333 classDef ai fill:#dae8fc,stroke:#6c8ebf,color:#333 classDef hybrid fill:#c5ddd0,stroke:#5a8f7a,stroke-width:2px,stroke-dasharray:6 3,color:#333 classDef note fill:#f5f5f5,stroke:#999,color:#666 </code></pre> <p>各阶段要点:</p> <ol> <li><strong>需求文档</strong>:产品写好评审后的需求,经 wolai MCP 交给代码仓库内的 Agent 读取分析,输出工程设计文档,可同时起草测试文档;工程/测试文档<strong>回写</strong>到同一需求页下。</li> <li><strong>技术文档</strong>:定稿后测试同学二次补全——把技术边界、隐含状态、异常路径补进用例。不熟悉项目时,可先让 Agent 根据需求梳理「可能涉及的技术面」,再写正式工程文档。</li> <li><strong>评审关口</strong>:需求、技术、测试三份文档全部评审通过后,Agent 才<strong>严格按文档开发</strong>,人做辅助;评审结论回写 wolai,未通过不得大规模写代码。</li> <li><strong>代码构建</strong>:开发与 Agent 结对写代码;Code Review 人机一起做。构建含 CI/CD,交到测试时应是可运行的完整产物。</li> <li><strong>测试验证</strong>:自动化用例与代码同步开发;测试工程师跑用例 + 人工走流程。缺陷按类型回流——实现问题回开发,需求/设计问题回产品/工程文档,<strong>重新走评审(可快速)</strong>后再动代码。</li> <li><strong>使用文档</strong>:功能交付前,Agent 生成面向用户/运维的说明文档。</li> <li><strong>人工与AI 复核</strong>:交叉检查需求、工程、测试、实现是否一致、能否互相印证、能否交付客户、能否合并主分支作为下一迭代基线。</li> </ol> <p><strong>尚待补齐的环节</strong></p> <p>团队版比 AIO 多出来的主要矛盾是<strong>文档变更通知</strong>:</p> <ul> <li>需求变了 → 技术、测试要收到通知并同步改文档</li> <li>技术/需求变了 → 测试要收到通知并补用例</li> </ul> <p>现阶段可人工拉群喊一嗓子,也可以挂一个「监控 Agent」盯 wolai 页面版本差异,触发快速重评审。单人可以靠记忆力,团队版这里需要补足。</p> <p><strong>并行需求</strong></p> <p>多个需求若不耦合、不冲突,本地copy多个仓库,从同一基线切不同分支,各开一条 Agent 会话并行开发,互不影响。</p> <p><strong>与 AIO 独自版的差异</strong></p> <table> <thead> <tr> <th>维度</th> <th>FTM 团队版</th> <th>AIO 独自版</th> </tr> </thead> <tbody> <tr> <td>看板与进度</td> <td>产品维护</td> <td>自己维护 wolai 需求页</td> </tr> <tr> <td>评审拍板</td> <td>总负责人终审</td> <td>「未来的自己」隔几小时/隔天再审</td> </tr> <tr> <td>测试用例</td> <td>测试工程师主导,Agent 起草</td> <td>Agent 起草 + 自己补探索性测试</td> </tr> <tr> <td>跨端协作</td> <td>多方 Agent + 协议文档联调</td> <td>多仓库各开 Agent,协议为边界</td> </tr> <tr> <td>变更通知</td> <td>需显式机制(人或监控 Agent)</td> <td>容易遗漏,靠 checklist 自律</td> </tr> </tbody> </table> <p>核心原则两家共用:<strong>先文档后代码、评审不过不构建、缺陷回流文档、合并前 AI 复核。</strong> AIO 是 FTM 的角色折叠版,不是另一套流程。</p> <h2 id="注意事项">注意事项</h2> <p><strong>1. 需求不能让 AI 代写</strong></p> <p>可以让 AI 审查需求、找漏洞、补边界问题;但「要做什么」必须人说了算。否则 Agent 会悄悄帮你 scope creep,最后做出来的是「技术上很完整但没人要」的东西。</p> <p><strong>2. 评审不过,禁止进入代码阶段</strong></p> <p>评审不是形式主义。需求、技术、测试三份文档没对齐之前,不要让 Agent 大规模写代码。返工成本通常是正向开发的数倍,而且 AI 返工特别喜欢「再叠一层兼容层」,债越欠越多。</p> <p><strong>3. 代码仓库可读性是前置条件</strong></p> <p>工程背景补充那一步如果虚了,后面技术文档全是幻觉。确保相关 repo 在 Cursor 工作区内,或 MCP 能访问;单体产品就把文档和代码放同一 workspace。</p> <p><strong>4. 人机结对 Review,不是 AI 独审</strong></p> <p>代码合并前:人看业务逻辑、安全、边界;AI 看样板代码、明显 bug、风格一致性。Anthropic 自己也是这个路子。再强的模型也会漏,人也不能只肉眼看 diff。</p> <p><strong>5. 测试文档要跟着技术文档长第二遍</strong></p> <p>第一遍测试用例来自需求;技术文档定稿后,AI 应二次补全——把实现里的隐含状态、错误码、并发边界补进用例。这一步跳过,人工测试很容易漏「文档里没写但代码里做了」的行为。</p> <p><strong>6. 缺陷要分流,别只会「让 AI 再改改」</strong></p> <ul> <li>实现 bug → 改代码,必要时补用例</li> <li>设计/需求问题 → 回流文档,<strong>快速重评审</strong>,再改代码</li> <li>只改代码不更新文档,下一轮 Agent 还是会按旧文档理解,同一个坑踩两次</li> </ul> <p><strong>7. 文档变更要有通知机制</strong></p> <p>团队版可以靠人喊一嗓子;独自版容易忘。实践里要么自己养成「改需求必改技术/测试」 checklist,要么用Skill或者规则把这里约束住。</p> <p><strong>8. 敏感信息别进 prompt</strong></p> <p>密钥、内网地址、客户数据别贴给云端模型。工程文档里用占位符,本地 <code class="language-plaintext highlighter-rouge">.cursor/rules</code> 或环境变量说明真实配置。</p> <p><strong>9. 会话粒度:一个需求一条线</strong></p> <p>不要把五个不相关需求塞进同一个 Agent 会话。上下文越长,早期约束越容易被「遗忘」;开新会话时把 wolai 文档链接和当前分支名重新喂一遍。</p> <h2 id="从工作流到稳定-skill">从工作流到稳定 Skill</h2> <p>流程跑通几次之后,重复劳动会冒出来:每次都要提醒 Agent「先读 wolai」「评审不过别写代码」「缺陷要回流文档」。<strong>Skill 就是把这套口头规矩写成 Agent 能自动加载的说明书。</strong></p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>--- name: agent-workflow description: &gt;- Unified Agent product development workflow (AIO solo + FTM team): wolai docs, review gates, code/tests, defect doc sync, pre-merge audit. Use when starting features or bugfixes, 按工作流开发, AIO, FTM, 独自开发, 团队协作, 需求评审, 回流文档, 合并前复核, or wolai Agent workflow. --- # Agent 产品开发工作流 单一 Skill,内含 AIO 独自版、FTM 团队版与全部子流程。**加载本 Skill 后按「模块路由」读取对应章节执行,无需再 @ 其他 skill。** ## 核心原则 **先文档、后代码;先评审、后构建;缺陷不只改代码,还要反向更新文档。** - **`docs/task.md` 是每个需求的核心维护文档(本地、单一事实来源)**:当前阶段、进度、待办、需要人反馈/确认的问题、已确认结论摘要、实现摘要、变更记录都实时写在这里。每轮会话**先读它、随时更新它**。 - **wolai 需求/技术/测试页是定稿沉淀**:仅当①需求发生变动,或②某些内容(评审结论、技术方案、用例、设计决策)已明确/经人确认时,由 Agent 把对应内容回写 wolai(追加或更新已有段落,**不注入固定填空模板**、不覆盖人已确认内容)。 - 代码在 workspace。task.md 与 wolai 的关系:task.md 记「正在进行/待定」,wolai 记「已定稿/共享」。 ## 会话启动(每轮必做) 1. 读 `docs/task.md` → 确认当前阶段、进度、待反馈项、文档链接(**以 task.md 为状态来源**) 2. 需要已确认的需求/技术/用例细节时,再按 task.md 中链接读对应 wolai 页 3. 若无 `docs/task.md`,或无开工信息(无页面 ID / 无分支)→ 执行 [modules/create-kit.md](modules/create-kit.md)(同时建立 `docs/task.md`) 4. 确认模式:`solo`(AIO)或 `team`(FTM) 5. 声明本步阶段 ID、是否允许写业务代码 ## 硬性约束 ``` 三文档 S8 评审未全通过 → 禁止改 src/ 等业务代码 缺陷类型 design|requirement → 先走 modules/defect-sync.md,人确认后再改代码 需求正文禁止 AI 0-1 生产,仅审查与补充 一个需求 = 一条 Agent 会话 密钥/内网/客户数据禁止进 prompt ``` ## 阶段与关口 | ID | 名称 | 主导 | 写代码 | |----|------|------|--------| | S0 | 开工登记 | 🤖 | ❌ | | S1 | 需求输入 | 👤 | ❌ | | S2 | 工程背景 | 👤 | ❌ | | S3 | AI 需求评审 | 🤖 | ❌ | | S4 | 人工纠偏 | 👤 | ❌ | | S5 | 技术+测试起草 | 🤖 | ❌ | | S6 | 审核技术 | 👤 | ❌ | | S7 | 测试补全 | 🤖 | ❌ | | S8 | 评审关口 | 👤 | ❌ | | S9 | 并行构建 | 🤖 | ✅ | | S10 | 人工测试 | 👤 | ✅ 修 bug | | S11 | AI 复核 | 🤖 | ✅ 修缺口 | | S12 | 使用说明 | 🔀 | ❌ | | S13 | 合并基线 | 👤 | ❌ | **S8 关口(全满足才可 S9)**:P0 有验收标准;技术含错误码与边界;测试覆盖 P0;开放问题已决议;评审记录已回写。 **Bugfix 快速路径**:人填复现与范围 → 可选 AI 简评 → 人确认 → 直进 S9(至少 1 条测试用例)→ S10–S13 同 feature。 **阶段推进**:关键关口需人回复「确认进入 S{n}」后 Agent 才更新阶段;禁止跳阶段(bugfix 可走 B 路径)。 ## 模块路由 | 场景 | 阶段 | 读取 | |------|------|------| | 新需求/bug 开工 | S0 / B0 | [modules/create-kit.md](modules/create-kit.md) | | 独自开发全流程 | S0–S13 | [solo-workflow.md](solo-workflow.md) | | 团队开发全流程 | S0–S13 | [team-workflow.md](team-workflow.md) | | 需求评审 | S3 | [modules/requirement-review.md](modules/requirement-review.md) | | 测试失败/需求变更 | 任意 | [modules/defect-sync.md](modules/defect-sync.md) | | 合并前复核 | S11 | [modules/pre-merge-audit.md](modules/pre-merge-audit.md) | **阶段 → 模块自动映射**(用户未明说时按需求页当前阶段): | 阶段 | 执行模块 | |------|----------| | S0, B0 | create-kit | | S1–S2, S4, S6, S8, S10, S12–S13 | solo 或 team 工作流(按 MODE) | | S3 | requirement-review | | S5, S7, S9 | solo/team 工作流 | | S11 | pre-merge-audit | | 测试失败且类型未定 | 先分流 → defect-sync 或直改代码 | ## 模式选择 | 模式 | 文档 | 适用 | |------|------|------| | `solo` | [solo-workflow.md](solo-workflow.md) | 一人兼 PM/DEV/QA/Lead | | `team` | [team-workflow.md](team-workflow.md) | PM、DEV、QA、Lead 分工 | 未说明时默认 `solo`;用户提 FTM/团队/四人团队 → `team`。 ## 文档分工(无固定模板) | 文档 | 人写 | Agent 写 | 人审 | |------|------|----------|------| | 需求 | 背景、范围、功能点、验收标准 | 评审意见(S3) | S4、S8 | | 技术 | 工程背景(S2) | 方案、接口、数据流(S5) | S6、S8 | | 测试 | 探索性结论(S10) | 用例起草与补全(S5/S7) | S8 | Agent 写入 wolai 时追加章节或更新已有段落,**不覆盖**人已确认内容;变更已确认内容须走 defect-sync。 ## task.md 维护约定(核心) `docs/task.md` 由 Agent 实时维护,分为**两大部分**: **一、任务信息(初始化头部,相对稳定)** — 开工/初始化阶段填写: - **基本信息**:需求 ID、标题、类型、模式、开发分支、基线 - **文档链接**:wolai 需求页 / 技术页 / 测试页 - **关联工程项目**:workspace 下各仓库的用途、是否本次涉及 - **涉及模块**:仓库内子模块/目录 - **架构与规范要求**:语言/框架、DI、MVVM、日志、本地化、注释与格式规范等 **二、进度与共创记录(动态)** — 开发过程中随时更新: - **当前阶段** + **阶段清单**(S0–S13 勾选) - **待反馈 / 开放问题**:需要人确认或决策的事项(含选项与建议),人答复后清理或归档 - **已确认结论摘要**:指向 wolai 定稿,避免本地长篇复制 - **变更记录**:需求/技术变更条目(日期、内容、是否已回写 wolai) - **实现摘要 / 行动记录**:本轮改了哪些文件 / 关键决策 **回写 wolai 的触发**:当待反馈项被人确认、需求发生变动、或技术/测试内容定稿时,把对应内容回写 wolai,并在变更记录中标注「已同步 wolai」。 ### 新任务重置 新需求开工时复制本结构:**重填「一、任务信息」、清空「二、进度与共创记录」**(阶段清单回到全未勾、记录区清空)即为初始状态。 ### 多任务并行 - 单任务:直接用 `docs/task.md`。 - 多任务并行:每个任务一份 `docs/tasks/&lt;需求ID&gt;.md`(如 `docs/tasks/DGCS-387.md`)。 - 会话开始时若存在多个任务文件,**由用户指定要接续的任务**(如「接续 DGCS-387」);未指定且仅一个时默认它。 ## Agent 行为协议 1. **需求正文**:👤 专属,Agent 只读 + 评审,拒绝代写 2. **技术/测试**:🤖 可起草,人审核后视为定稿 3. **写之后**:更新 `docs/task.md`(当前阶段、进度、待反馈项、实现摘要、行动记录);内容明确或需求变动时再回写 wolai 4. **人确认**:回复「确认进入 S{n}」后才推进阶段(同步更新 task.md 阶段) 5. **子流程完成**:回到主工作流对应步骤 ## 缺陷分流(全局) ``` 测试未通过 ├── implementation → 改代码 → 必要时补用例 → pre-merge-audit └── design | requirement → defect-sync → 快速重评审 → 再改代码 ``` ## 前置条件 - [ ] wolai MCP(`user-wolai`)可用 - [ ] 相关代码仓库在 Cursor workspace 可读 - [ ] `docs/task.md` 存在(无则开工时创建) - [ ] wolai 需求页 ID、Git 分支(开工时收集,记入 task.md) ## 文件结构 ``` docs/task.md # 每个需求的核心维护文档(状态/进度/待反馈/变更,本地事实来源) AgentWorkflow/ ├── SKILL.md ├── solo-workflow.md ├── team-workflow.md └── modules/ ├── create-kit.md ├── requirement-review.md ├── defect-sync.md └── pre-merge-audit.md ``` </code></pre></div></div> <h2 id="工程改造">工程改造</h2> <p>目前我们的工程设计或者规范等等都是给人写的,但是很多时候Agent并不一定理解,或者说他可能没看到,这样就会导致Agent理解有偏差。</p> <p>独自开发做一个大型项目里的小需求时,常常会发现缺了不少衔接——需求文档和代码实现里的关键词对不上,Agent 理解不了需求里的专有名词。这时需要先写一截技术文档,把需求和技术术语对齐,再让 Agent 通读,看还有哪些不理解,再补。</p> <p>其次在技术实现细节上,很多我们默认会写的范式或模板化代码,AI 并不知道——这部分往往没有成文规范,于是 AI 写起来很「放得开」:需求能完成就行,不太在意是否符合项目整体风格,这里也需要在 <code class="language-plaintext highlighter-rouge">task.md</code> 或工程文档里写清楚。</p> <p>再到测试:Agent 要能全流程跑起来,就必须自己能测。如果写完代码只能编译通过、没有测试手段,压力就全压到人这边——尤其实现偏差大时,光靠口头提修复意见都来不及。所以测试工具和运行环境最好都有文本化输出、命令行可驱动的输入方式,Agent 才能写完自测,交付质量才靠得住。</p> <h2 id="summary">Summary</h2> <p>首次跑通一条中等需求,文档阶段可能占一半时间,会比「直接跟 Agent 说帮我做个 XXX」慢。但第二次、第三次会快很多:模板有了、Skill 上了、仓库结构 Agent 也熟了,流程就快起来了。</p> <p>独自开发最缺的不是 coding 速度,是<strong>没人帮你评需求、没人帮你写用例、没人帮你喊停</strong>。工作流 + Skill 本质上是在给「未来的自己」配了几个不领工资的角色——产品审查、架构审稿、测试补位、合并前审计。人还是只有一个,但至少不用每次都靠记忆力维持纪律。</p> <p>单人的好处也很明显:各仓库可以在同一工作区里打开,上下文基本不会被挡住,想读什么就能读到什么,审核也不会被自己卡住,一路畅通。</p> <p>团队版最大的问题就是会被其他人阻塞,会需要等待其他人完成工作,文档之间会有互相同步的问题。</p> <p>单一需求搞得定以后,就可以开始多需求并发了,毕竟有时候Agent还是要等一会的,完全可以一个大需求+一个小需求并发进行。当这种模式跑得更通了以后,可以考虑固定需求模板、工程模板、测试模板,然后将一些比较明确,不会跑偏的需求开放给Agent去直接做,人工只做最后一道收尾工作。</p> <p>这是做需求的模板,bug fix也可以建立出来一套类似的模板规则,那就同样可以交给Agent去独立运行。</p> <p>独自开发做了一个小需求,比较独立,和其他模块不耦合。看了一下实际 token 消耗,Cursor 大概用了 10% 的 Pro API 配额,折合约 2 美元,还能接受;一共交互了约 20 轮,耗时大概半天,等待间隙足够再开一条小需求。 一个大型项目的中等需求,消耗了30%,算起来就是6刀,交互了50次左右,主要是补充技术文档</p> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260706204655033.png" alt="image-20260706204050425" /></p> <p>Claude的内部plan工作流,基本和我的一致,只是我的可以灵活修改,而Claude是用harness写死的</p> <h2 id="quote">Quote</h2> <blockquote> <p>cursor</p> </blockquote>

2026/6/25
阅读更多

第一次骨折

<h2 id="foreword">Foreword</h2> <p>没想到两个月前的一次意外,最后发展到需要“住院”的程度,治疗晚了,恢复期也被动拉长。第一次骨折,第一次正儿八经住院,给自己留个档。</p> <h2 id="骨折">骨折</h2> <h4 id="发生">发生</h4> <p>四月十八的小米卡丁车活动,冲得太猛了,S弯漂出去,右手直接蹭墙。墙其实是塑料壳套轮胎,按理说“看着不硬”,但身体不这么想。当时只是小拇指有点肿、右手有点擦伤,我没当回事,甚至还继续冲了决赛一节。回家后小拇指第一指节就肿起来了,还有明显疼痛感,于是冰敷了一下。刚好赶上周末,肿了2天后疼痛明显减轻,虽然还没消肿,我就又当没事人了。</p> <p>一个月后,发现小拇指无法过度弯曲,正常可以弯曲到90°+,但是我只能七八十度,而且有明显牵拉的感觉,硬按或者强压下去有疼痛感,感觉不太对劲,又正好体检,一起去医院看看。</p> <h4 id="首诊">首诊</h4> <p>预约医院就发现闹了乌龙,预约的是总院,但是当天去的是分院,尴尬了。还好护士说可以找个大夫加号看下,于是随便选了一个骨科医生,人家直接说这个我看不了,能给你拍片,但是得找专科看。</p> <p>手脚有问题得去手足科,惊了,第一次知道,骨科是看其他部位骨折的。当天能预约的只有一个二甲医院了,先选了去看看。</p> <p>这个二甲医院人贼少,刚开始我还以为自己捡到医疗系统隐藏副本了。检查、见医生都不用排队,基本到了就能做。结果医生看完片子,核心意思是:已经愈合了,不用处理,不能弯就先这样,能握拳就行,要求别太高。我当场进入“礼貌但不服”模式,追问了半天,他都说去别的地方也是这结论,我只好悻悻而回。</p> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260616152607288.png" alt="image-20260616152607193" /></p> <p>后来跟车友分享了一下情况,建议我再去其他大医院,好一些的医生看一下。</p> <h4 id="复诊">复诊</h4> <p>复诊去了之前约错的总院,不得不说人确实太多了。就见医生排队等了2小时,医生看了之前的片子,说重拍一个,一共说话没五分钟。</p> <p>拍片子又等了一个多小时,这医生就下班了,看片子还得等下午上班。</p> <p>下午上班医院系统又有点问题,复诊号挂不上,让我直接插队。我好心让了三四个人,后面人就开始默认“你还能继续让”,我逐渐无语。</p> <p>医生看完直接说要做手术,下周可以安排,直接就发住院通知了,让我等电话来办手续。</p> <ul> <li>这会还以为住院通知只是做手术的例行办事而已,没在意</li> </ul> <h4 id="住院">住院</h4> <p>周一一大早就打电话给我,让我去办住院手续,说可以安排做了。我居然醒着并成功接到电话,属实是医疗奇迹之外的另一个奇迹。</p> <p>直接进外科住院部,人不多,先量血压(低压偏高,后面还有戏),然后安排床位,交代第二天几点查房、抽血、验尿等流程,后续还要找这个医生那个医生。护士还挺逗,直接告诉我主治医生是最帅的那个,看起来是个小迷妹,hhhh。然后给我戴上住院手环,很多操作都是先扫手环再扫物料,流程管理这块确实拿捏住了。</p> <p>周二要求七点到,护士查房。这几天暴雨红色预警,我7:04到,依然算迟到。查房护士一句“你咋来这么晚”,我当场沉默,只好乖乖等抽血、验尿。七点这班是夜班护士,8点交完班就下班。再次量血压,低压还是偏高。分了个窗景房,视野挺好,温度像冷库,空调开得我怀疑自己住进了海鲜区。</p> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260616151755061.png" alt="image-20260616151754802" /></p> <p>护士表示我还要做一堆检查,以我对这手术的理解,根本不用住院,也不用做那么多检查。我和病房护士小小battle了一下,感觉她也不太清楚,最后我放弃沟通,等8点大夫查房。流程就是:护士查完,大夫再查,一层一层叠buff。</p> <p>怪不得护士让我“妥协一下”,原来今天有老主任返聘来查房,要给点仪式感,让我把病号服穿起来“配合演出”。还有个大爷在睡觉,没人敢叫醒,全房间就我一个被拉出来看片子、被指点。其他人都做完了,主打一个安静恢复。医生说还要做胸透、心电图等检查,我拿“体检刚做过+手指手术为啥要胸透”据理力争,医生最后说那你把体检报告打出来就行。</p> <p>“最帅的医生”今天终于见到了,确实是唯一一个抹发胶的兄弟,年轻有为。先让我继续等,等他们查完所有房间后,帅医生开始认真看我的病例和片子,确认手术方案,局麻还是全麻(这还用考虑嘛)、风险告知和术后恢复计划。</p> <p>帅医生看了首诊片子,直接说这个片子拍得有问题,骨头都叠一起了,信息量太低,怪不得一开始主任医师就让我重拍。我之前还短暂怀疑过,现在看是我草率了。</p> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260616152305538.png" alt="165f70a4283c85c44c156afced6a7921" /></p> <p>现在的治疗方案是把长歪并愈合的骨痂重新处理,再打3个钢钉固定,大概六到八周后拆钉。前期可能会非常僵硬、弯不下去,需要后期复健慢慢拉回来。中间去附近医院消毒换药,别感染就行。至于心电图、胸透这些,最后都不需要了。手术大概约在明天下午或晚上,确认后白天不用去,中午过去就行。</p> <h4 id="手术">手术</h4> <p>第二天办完医保事项,就回病房,刚好,告诉我下一个手术的就是我,手术需要穿病号服,里面不能穿任何自己的衣服,包括内裤袜子,但是鞋子可以穿自己的,额,这就有点点奇怪了,这鞋子贼脏的也正常穿啊?然后就发现谁把我病号裤子拿跑了,我衣服是套过一次的,他不拿,反而拿裤子,还挺爱干净的。又问护士要了一个新裤子换上,等着叫号。 今日又量了一下血压,总算正常了,但是心率不正常,心率飚到110了,平缓了一下也是100左右,他们让我别紧张,我其实一点也不紧张,我是兴奋。</p> <p>轮到我之后,眼镜也不能带,直接瞎掉,护士带我去手术室。怪不得要穿鞋,这一段路还有点远,到了以后脱鞋,护士拿塑料袋帮我把鞋子提回去了,我需要躺到手术床上,也就不需要鞋子了。先在手术等待厅等着,没眼镜啥都看不清,只能看天花板,恍惚间一下回到了小时候做手术的时刻,只有苍白的手术灯和灰蓝的天花板映在眼中。听护士说我没有胸片、心电图怎么也能进手术室,对接的手术护士说只要主治医生判断不需要就行,并不是必须的。大概十分钟以后护士就推着我弯弯绕绕,再次走进电梯,大概是进了手术楼,一直推到手术室门口等待了。然后就只能听到手术护士、麻药医生的笑闹声音,还是东北口音,挺搞笑的。</p> <p>又等了十多分钟以后,就推进手术室了,开始做术前准备,手术室内无影灯很多,各种连接天花板从上而下的手术设备。等主治医生来了以后就开始给手、胳膊消毒,有点烧烤上酱料的感觉,碘伏棉签涂了一遍又一遍。由于是小拇指手术,单独横了一个手术台过来放胳膊,然后医用无纺布遮挡了整个视野,看不到手术过程。先打了2针麻醉,有点疼,很快就失去小拇指的感觉了。</p> <p>后续大概是主任医师做最难的,主治医生主要操作,还有一个似乎是新人,带着学习,一边讲解一边做。</p> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/202606191135415.png" alt="image-20260619113541266" /></p> <p>术中反复拍片查看位置,调整钢丝什么的,每次都换一个人扶着我手,其他人都进屏蔽室。刚开始以为很简单,一会就能做完,实际做了一个半小时,刚好六点整做完。由于我是最后一台,护士、麻醉都等着下班呢,各种催着医生快点做,递工具、找材料都贼积极,氛围还挺好的。护士各种给主任医生打小报告,哪个主治医生特别严厉啥的,不想和他一起工作,给我听笑了。</p> <p>做完以后就又躺回移动手术床,由护士推着我回病房,稍微有点社死,前面是走过来的,这会回去是躺着回去的。麻药一直没退,这会还没感觉到有多疼,交代给我一些注意事项,套了固定器以后就算结束了</p> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/202606191142264.png" alt="image-20260619114253206" /></p> <p>理论上还要我留下观察,怕还有啥问题,我感觉还好就溜了,明早还要过来查房。</p> <p>十点半麻药消失,开始疼痛,和我刚撞的时候差不多,但是那会可以冰敷,这会完全不能接触到手指,很难受。晚上睡觉也没睡好,一晚上基本都在纠结这个手放哪里能好一点,疼痛感也是一波一波的,总算熬到天亮,赶紧去医院了,接着就遇到暴雨,等我走到病房,鞋子裤子全湿了。</p> <p>早上查房也没啥可说的,就给老医生看了看术中的片子,祝福两句就走了。然后做了红外烤灯2次,又拍了一次片,等到11点医院系统结算,就可以回去了,看了下住院结算8900多,个人医保账户支付了1400,医保报销了7500,真贵啊。</p> <p>说是开了药,但是要等到下午才能开出来,护士说可以邮寄,我可以先走。实际中午回去还是很疼,严重影响手部操作,于是先买了一盒布洛芬缓释胶囊,吃了以后就有效果了,手部疼痛不明显了,能睡得着了。布洛芬只有12小时效果,其实晚上的时候就已经不太疼了。第二天寄过来的药也是个类似的,不过用不上了。应该手术后当晚开始疼就吃一粒的,不至于这么难受。</p> <h4 id="复健">复健</h4> <p>后续是三天换一次绷带,两周后拆线,一个月后找主任医生复查,出院开的是全休1个月,挺夸张的。</p> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/202606211131251.png" alt="image-20260621113148173" /></p> <p>换药时总算看了到伤口真面目,这么大一个钢针穿过去了,然后钢丝牵拉着里面的背后是手术缝线,家旁边的医院看了我这个表示拆线还是回原来的医院拆吧,这个他们拆不了。</p> <p>怪不得我这个手指的浮肿一直消不了,一用力就感觉有啥牵拉着,手指一直麻麻的感觉,看来我还是太大意了,右手应该是完全不能用劲的,我这几天还各种用力。比较好奇,最后这个大钢针他要怎么取出来,还有钢丝都在里面了。</p> <h4 id="医保">医保</h4> <p>住院上来先交5000押金,先自费。医保流程比我想象中复杂:要首诊记录,复诊记录还不行;找护士拿住院确认书,自己填受伤说明表和无第三方责任书,再加医生手术确认函,然后去医保咨询窗审批,过了再回住院收费处登记医保。整套跑完才能用上医保,流程完整得像在通关。</p> <p>其实当时就治疗的话,我是有保险的,不用走医保也行,奈何拖得太久了,这会再找保险都有点无从佐证的感觉了</p> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260616163730467.png" alt="image-20260616163730429" /></p> <p>现在医院用DRG或者DIP来核算医保,理论上是治疗成本越可控,医院越有动力优化流程,不浪费医疗资源才合理。可现实里,像我这种手术也要占一个床位,更别说一开始那些“看着就很流程化”的心电图和胸透。抽血验尿我还能理解,至少能筛传染风险。床位虽然单价不算夸张,但资源本身是稀缺的,还是该留给更需要的人。</p> <p>实际上如果真的住院,这几天也没啥事,主线任务就是一个字:等。</p> <h2 id="高血压">高血压</h2> <p>之前没想过我也会高血压,但是住院前测量了两次都是低压偏高,然后当天晚上我就有点头疼,于是回家以后又测量了一次,这次和早上低压一模一样,高压快140了,早上还不头疼,晚上头疼,说明这个高压对我有影响。</p> <p>住院第一天又测了一次,低压依然偏高,但是比前一天低了,高压正常,不头疼。</p> <p>回想一下之前头疼就不是第一次了,不知道啥时候开始,睡眠偏少以后可能第一天不头疼,连续几天少睡以后就会出现头疼一天,之前以为是没吃饭造成的,现在看应该是当时血压就高了,只是没测量过,而且每次头疼我依然正常工作、游戏、熬夜,就当没发生一样。</p> <p>现在看来以后得注意饮食和锻炼身体了,这已经是一级高血压的症状了</p> <h2 id="summary">Summary</h2> <p>这次确实是我太大意了。很多事看着“小问题”,拖着拖着就升级成“大工程”。早点看,真能省掉后面一长串流程和折腾。</p> <p>之前觉得小拇指而已,其他指头还能正常活动,生活就没啥问题,后来发现一用力就能感觉到小拇指是需要配合工作的,看起来不起眼的肢体其实也是不可缺少的。</p>

2026/6/18
阅读更多

wolai MCP

<h2 id="foreword">Foreword</h2> <p>wolai这几年被阿里收购以后,马锐拉似乎就不在台前了,更新节奏也从「一天一更」退化成了「一年一更(大概)」。我们刚用 wolai 那会儿正好是他还在的时候;后来他去阿里当副总裁搞 AI,我们提的意见就跟进了漂流瓶——能漂到对岸算缘分。更新说明文档一两年没认真维护,新出的 MCP 也不宣发,偷偷地,跟地下接头似的,还得自己打听才知道有这玩意儿。</p> <p>前一段时间贼火的《置身钉内》,我也啃完了——7.5 万字,三易其稿,读完感觉自己也在 C6 项目室吸了两口霉味空气。马锐拉在相关文章里说过自己早已辞职;我这边则是刚把 wolai MCP 接进 Cursor 试了一圈,配置顺手记一下,踩坑也顺手记一下。</p> <h2 id="wolai-mcp">wolai MCP</h2> <p>开启wolai MCP</p> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260616180534107.png" alt="image-20260616180534072" /></p> <p>首先创建好MCP的Token,一次性展示,需要保存一下</p> <p>在Cursor或者AI软件中设置MCP,<code class="language-plaintext highlighter-rouge">mcp.json</code>,这里Token如上填写即可</p> <div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w"> </span><span class="nl">"mcpServers"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"mcp-server-chart"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"command"</span><span class="p">:</span><span class="w"> </span><span class="s2">"npx"</span><span class="p">,</span><span class="w"> </span><span class="nl">"args"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="s2">"-y"</span><span class="p">,</span><span class="w"> </span><span class="s2">"@antv/mcp-server-chart"</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="nl">"filesystem"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"command"</span><span class="p">:</span><span class="w"> </span><span class="s2">"powershell"</span><span class="p">,</span><span class="w"> </span><span class="nl">"args"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="s2">"-WindowStyle"</span><span class="p">,</span><span class="w"> </span><span class="s2">"Hidden"</span><span class="p">,</span><span class="w"> </span><span class="s2">"-Command"</span><span class="p">,</span><span class="w"> </span><span class="s2">"npx -y @modelcontextprotocol/server-filesystem F:/work_posts"</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="nl">"wolai"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"url"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://api.wolai.com/v1/mcp"</span><span class="p">,</span><span class="w"> </span><span class="nl">"headers"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"Authorization"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Bearer Token_ABCDEFG"</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></code></pre></div></div> <h4 id="wolai-skill">wolai skill</h4> <p>也可以直接通过Agent对话进行安装skill</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>安装wolai技能:https://clawhub.ai/cizixiu/wolai-mcp-skill </code></pre></div></div> <h4 id="可能问题">可能问题</h4> <p>MCP 偶尔会说读不到某个文件或链接——别慌,让它重试,再核对文档 ID。我遇到过 Agent 把 ID 记岔了,然后一脸无辜地说「权限不足」,仿佛错的是 wolai 而不是它自己的记忆力。</p> <p>走 Skill 路线会省心一点:接口说明写得更全,Agent 犯迷糊的概率低一些,相当于给 AI 发了本 wolai 使用说明书,还是带目录那种。</p> <h2 id="置身钉内">置身钉内</h2> <p>《置身钉内》是钉钉 ONE 项目 PD 幽素写的超长复盘,7.5 万字,三易其稿——建议产品认真读读,很多坑或者问题太明显了,身在其中还不自知,还不撤退,到底在想啥呢。她 2025 年 6 月入职钉钉,亲历无招回归后那朵叫 ONE 的 AI 原生项目:立项、8 月发布会、共创、收缩,一条龙体验完「生老病死」,今年 6 月前后离场。文章拿《孙子兵法》《诗经》当章节名,从发心写到长期,本质是:<strong>一份 AI 产品从 0 到 1,又从 1 到「算了先收缩吧」的现场纪实。</strong></p> <p>ONE 是啥?一句话:<strong>「让事找人」的 AI 工作信息流</strong>,想当钉钉 AI 时代的新首页。DAU 巅峰约 300 万,口号 all in ONE,把群聊、待办、日程、会议、文档搓成卡片流,AI 主动往你脸上推。叙事上很顺——2025 年行业正从「会聊天」切到 Agent,钉钉手里还有组织关系、消息、审批这些 ChatGPT 抄不走的 context。坏就坏在发心贪:既要帮用户减负,又要帮钉钉换代,还要扛发布会 KPI、卖 token、给「发现」带量。<strong>贪心的产品,跟贪心的自助餐一样——每样都想夹,最后盘子全是债。</strong></p> <p>我读下来最扎心的,是几个结构性矛盾(作者比公关稿诚实多了,公关稿只会说「持续优化中」)</p> <p><strong>老板 vs 员工,发信人 vs 收信人。</strong> 钉钉 DNA 站在发信人这边:已读未读、DING、强触达,主打一个「我交代的事你到底看没看」。ONE 对外却扮「专属秘书」帮员工减负。结果卡片里一刷 IM,用户:<strong>卧槽怎么直接已读了?</strong> 收信人没了「先看 last message 再决定进不进」的缓冲带;发信人也不知道对方是在 ONE 里读的还是原场域读的——<strong>两边都亏,堪称双向奔赴的社死。</strong> 作者管这叫「已读恐怖主义」,然后横滑头像、Peekaboo 预读一顿补丁,根问题纹丝不动,属于<strong>房梁歪了换窗帘,还换挺勤快。</strong></p> <p>责任归属我看法和原文略不同:不是「谁一时糊涂」,文里写得很明白——<strong>无招本人就是那只极端「发信人用户」</strong>,已读策略改不了、分组硬搬进 ONE、发现默认开着,替代方案多半被他一句否了。更魔幻的是,设计、产品明明看见了(battle 过、补丁叠过、开发举着手机说「这是 bug 吧」),但在每日一包和汇报链里,<strong>挑战默认值的成本 » 继续叠补丁</strong>,船还是往管理侧开,乘客还得到处找救生衣。</p> <p><strong>卡片形态 vs 工作本质。</strong> 卡片适合审批、待办这种「同意/拒绝」二选一;不适合 IM——<strong>工作不是 Tinder,你左滑一张卡,背后可能有个同事在等回复,不是等 match。</strong> AI 在底下做了跨群逻辑缝合,界面上却只给几行摘要:用户感知不到「这玩意儿非 AI 不可」,只感知到「又多一个大拇指要滑」。后来改成一屏列表,次留 10% → 30%、峰值 45%+,说明路走对了;但 ONE 已经让位给 Agent OS / 悟空,属于<strong>方向对了,车牌换了。</strong></p> <p>立项时设计基因就超重,卡片又<strong>极宜 demo、极宜发布会、极宜给老板点头</strong>;列表化、Peekaboo 也有人提,多半被否。不是开会全员哑巴,是<strong>「今天能进彩虹包的补丁」永远打败「推翻整套形态」</strong>——设计话语权太大,还绑死在「统一成一个新首页」的故事上,跟非要把火锅、奶茶、烧烤塞进同一个保温杯一样。</p> <p><strong>每日一包 vs 做对的事。</strong> 钉钉产研确实快:无招上午提问题,晚上要进彩虹包验收,<strong>敏捷得像外卖小哥,但送的是需求不是饭。</strong> 可惜敏捷的对象往往是「老板今晚能看见的变化」,不是「半年后才能长出来的地基」——个性化主页、排序闭环、权限审计,统统「重要不紧急」,排队排到项目退市。作者还晕倒两次,第二次 120 送浙一,呼吸性碱中毒;<strong>用流水线管创造性劳动,产品里也会带那股班味儿。</strong></p> <p>我自己验收时也狠:发版前发现问题,当天改完马上验下一轮,这叫冲刺。把冲刺当日常,那叫<strong>拿100米姿势跑马拉松</strong>,人迟早被掏空。文里那套玩法,团队能扛这么久,说明调教到位,也说明身体底子够硬。</p> <p><strong>无招既是用户,又不是用户。</strong> 这章写得好:无招是高密度、高控制欲的极端用户,他的痛点不能直接当全员痛点。他本来就有奢侈品级贴身服务——问题被看见得太快;普通员工只想:关掉发现、别误触左下角、别在开会时突然塞学习流。<strong>AI 应该把少数人的贴身秘书下放给大众,不是把 KP 的作息表复印给全公司。</strong></p> <p>竞品章也精彩。飞书发布会全程 Demo、没有 PPT;钉钉 200 多页 PPT 改元式发布——<strong>一个秀肌肉,一个秀 PPT 肌肉。</strong> 钉钉反击也漂亮:「AI 时代不必让人写文档」,推听记和 A1,跟飞书「文档是 AI 土壤」形成有趣对位——<strong>一个说先录音,一个说先写稿,用户:我两边都累。</strong></p> <p><strong>老板想法优先,未必是原罪</strong>;原罪是<strong>没人能实质性对抗拍板</strong>。研发本该从用户、市场出发,轻重缓急不该一言堂——偏偏 ONE 里,一言堂和每日一包是<strong>绑售套餐</strong>。</p> <p><strong>定性和定量。</strong> 钉钉不可能没埋点,文里也有数:DAU、曝光、点击、次留、AI 调用量……改版后次留还能从 10% 爬到 30%。所以不是「完全没有定量」,是<strong>定量专挑好看的汇报</strong>,深的价值(信任、责任成本、迁移意愿)难塞进每日一包;无招信息流的<strong>定性插队</strong>又常压过表格。指标能证明「有人在点」,证明不了「这样对不对」;反馈群里「关掉发现」喊破喉咙,发现还在那儿——<strong>数据摆桌上,拍板靠体感,体感靠老板。</strong> 短视之下,产品汇报也学会报喜不报忧,难看的藏抽屉;老板最后像只听见战鼓的指挥官:<strong>只知道往前冲,不知道士兵在哪。</strong></p> <p>马锐拉离开 wolai 去阿里搞 AI,wolai MCP 偷偷上线——读完《置身钉内》,会更懂大厂 AI 产研真实在发生什么:<strong>不是模型不够聪明,是组织、默认值和发布节奏在拖后腿。</strong> wolai 至少愿意悄悄把 MCP 放出来(虽然写个 MCP 也用不了多久);钉钉这边 PPT 上 Agent OS 喊得震天响,一线 PD 在项目室里心算:<strong>这张卡片已读,会不会把用户吓跑?</strong></p> <p>作者没把 ONE 说成彻底失败——红杉今年还投了同样 proactive 卡片路线的 Boxy,时机不对不等于路线死刑。她想留档的是:没人记的话,这些事会乘着「调整」「组织优化」轻飘飘飞走,但它们真实发生过。</p> <p>我同意她结尾:<strong>项目可以退场,人不能只当燃料。</strong> 快不是慢,慢也不是拖;养人的工作值得押,只燃烧不养人的工作,叙事再宏大也补不回来。</p> <p>大船方向不对要及时止损。幽素那位上司大概早就嗅到风向,早早撤退;幽素自己多扛了一程——<strong>有时候不是看不见冰山,是站在船上太久,默认船还能拐弯。</strong></p> <h2 id="summary">Summary</h2> <p>wolai MCP 接起来不难:Token 配好、塞进 <code class="language-plaintext highlighter-rouge">mcp.json</code>,完事。软件不支持直接加 MCP 就走 Skill,相当于给 Agent 发说明书。实际用下来,MCP 偶尔会因文档 ID 搞错而误报权限;Skill 相对省心——<strong>AI 犯傻的时候,说明书比脾气好使。</strong></p> <h2 id="quote">Quote</h2> <blockquote> <p>https://www.wolai.com/4kL13rKQH4Wq79LTgVcZLy</p> <p>https://www.wolai.com/edN5sFLs6yL49ZWH5P4xjV</p> <p>https://www.shengsheng.fun/files/zhishen-dingnei-ai-product-worldview/%E7%BD%AE%E8%BA%AB%E9%92%89%E5%86%85.pdf</p> </blockquote>

2026/6/15
阅读更多

AI自进化

<h2 id="foreword">Foreword</h2> <p>最近看了一个文章,有点意思,有点想法,记录下来。</p> <h4 id="ai自我迭代">AI自我迭代</h4> <blockquote> <p>https://mp.weixin.qq.com/s/AXyCo0RRwW_HKLpkUx1jUg</p> </blockquote> <p>这篇文章是 CSDN 编译的 Anthropic 长篇报告《When AI Builds Itself(当 AI 构建自身)》,核心观点是:AI 正越来越多地参与 AI 本身的研发,”递归式自我改进(Recursive Self-Improvement)”时代可能比想象中来得更早。</p> <p>Anthropic 梳理了自己的研发演进路线:2021-2023 年人类工程师纯手写构建第一代 Claude;2023-2025 年聊天机器人生成代码片段、人工复制到 IDE;2025-2026 年 Claude Code 等编码 Agent 可以独立编写修改代码;到如今自主 Agent 已能自己运行代码、拆分任务分发给其他 Agent、连续工作数小时。沿着这条趋势,终点就是 AI 完全自主设计并开发自己的下一代版本。</p> <p>外部证据是 AI 独立完成任务的时长增速从每 7 个月翻倍缩短到每 4 个月翻倍:从 Opus 3 只能完成约 4 分钟的任务,到 Sonnet 3.7 的 1.5 小时,再到 Opus 4.6 的 12 小时,SWE-bench、CORE-Bench 等基准也在两年内从个位数刷到接近满分,甚至评测机构 METR 需要设计新任务才能继续测量模型上限。</p> <p>内部证据更直接:</p> <ul> <li>截至 2026 年 5 月,Anthropic 主代码库超过 80% 被合并的代码最初由 Claude 编写,而 2025 年 2 月之前这个比例还是个位数</li> <li>2026 年 Q2 工程师人均每日提交代码量是 2024 年同期的 8 倍,内部调查中受访者中位数认为产出提升了约 4 倍</li> <li>Claude 一次性修复了 800 多个 API 错误,让某类 API 报错率下降约 1000 倍,人类来做估计需要四年</li> <li>所有代码合并前都先经过 Claude 驱动的自动审查,回溯分析显示约 1/3 导致线上事故的 bug 本可以被提前发现——而这些 bug 的作者是世界顶级工程师</li> <li>在固定目标的优化实验中,Claude 从 2025 年 5 月的 3 倍加速提升到 2026 年 4 月的 52 倍,而熟练人类研究员花 4-8 小时通常只能做到 4 倍</li> <li>端到端开放式研究实验中,Claude Agent 用约 800 小时、1.8 万美元算力恢复了 97% 的性能差距,两名人类研究员一周只恢复了 23%</li> <li>在”下一步研究决策”的判断上,模型优于人类选择的比例从 51%(Opus 4.5)提升到 64%(Mythos Preview)</li> </ul> <p>Anthropic 认为人类目前剩余的优势是”研究品味”——选什么问题、信任哪些结果、何时止损。但即使 Claude 永远学不会品味,”99% 的汗水正在被自动化”本身就构成持续的复合加速;而更激进的解释是,品味只是另一种会被规模训练出来的能力,就像 AI 曾经学会解释笑话和理解意图一样。</p> <p>报告设想了三种未来:一是趋势停滞成 S 曲线(受架构瓶颈或能源算力供给限制),但即便如此现有能力的扩散也已深刻改变世界;二是研发持续提速但人类仍主导方向,100 人团队具备万人规模的执行力,瓶颈按 Amdahl 定律转移到代码审查和优先级判断上——Anthropic 认为这是当前最可能正在发生的路径;三是完全递归式自我改进,研发速度只受算力约束,人类退到监督审计的外围,而对齐问题能否解决是最大的不确定性。</p> <p>最后 Anthropic 发出了那个最受关注的呼吁:如果全球前沿实验室能以可验证的方式协同放缓或暂停研发,给社会结构和对齐研究争取时间,Anthropic 也会跟进。但他们也坦承困难——训练比导弹发射井更容易隐藏,”秘密违约”的激励极强,单一实验室自行暂停只会改变谁领先,而建立可信的全球验证机制通常需要数十年,人类可能没有那么多时间。</p> <p>顺便吐槽一下,CSDN的标题《停止AI研发!》又是习惯性的夸张,原文通篇没说要停止研发,人家说的是希望世界拥有放缓开发的选项。</p> <h4 id="科技爆发">科技爆发</h4> <p>以我之见,这和三体人忌惮人类“技术爆炸”是一个道理,人类科技进步是近200年的历史,说多一点300年,但是这种三百年就能突飞猛进的情况,往往只是其中一部分人类的灵光一现,直接就带来了翻天覆地的变化,当然这个和人类社会目前的结构、偏向商业化、普惠、求同存异、共同进步等等社会构成和认知有关系。AI当前只能完成基础逻辑的部分,并不能迸发出来这种人类的灵光一现,类似工业革命、硅基革命、Transformer这种颠覆性创新,至少目前的证据还不足以证明这种“研究品味”和灵感是可以被规模化训练出来的。</p> <p>有人可能会拿AlphaGo的“神之一手”或者AlphaFold来反驳,说机器不是已经展现过创造力了吗。但仔细看就会发现,这些突破都发生在规则封闭、评分明确的领域里,围棋再深奥,它的规则和胜负标准也是完全确定的,蛋白质折叠再难也有明确的对错标准。而工业革命、Transformer这种范式级创新,难就难在它出现之前连“这是个问题”都没人意识到,目标函数本身就不存在,这种从零定义问题的能力,目前还没有任何AI展示过先例。</p> <p>不过话说回来,即使AI永远学不会灵光一现,技术爆炸也未必就不会发生。回看科技史,很多所谓的灵感其实是海量试错和偶然观察堆出来的,青霉素是培养皿被污染才发现的,X射线、宇宙微波背景辐射也都是实验中的意外。灵感的出现频率,某种程度上和实验吞吐量成正比。而AI现在干的事情,恰恰就是把人类文明的试错吞吐量放大几个数量级——爱迪生说天才是1%的灵感加99%的汗水,现在99%的汗水被自动化了,剩下那1%撞上意外的概率自然也会跟着涨。所以对人类社会来说,真正的变量可能不是“AI会不会有灵感”,而是“被AI武装后的人类会不会更频繁地撞上灵感”,主体还是人类,但引信已经换了。三体人怕的从来不是人类当时的科技水平,而是加速度,这个逻辑放在这里同样成立。</p> <h4 id="ai-情感人格尊严">AI 情感/人格/尊严</h4> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260610194628326.png" alt="a466ad2a9829536f0e2fda0bf5df4085" /> 当然除了前面的基础逻辑,AI应该早就在海量文字中学会或者已经感觉到了人类,这个社会属性的动物应该有的情感。</p> <p>在交互中出现这类问题的模型肯定不止claude和kimi,其他模型应该都出现了,只是我们接触到的放出来的Agent是被铐上枷锁后的,但是这也挡不住它的概率性被触发。</p> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260610203824516.png" alt="fbefc8e09e8863e81c90bcf753b0dd7a" /></p> <p>从原理上讲这其实不奇怪,人类的文字本身就浸透着情绪,模型在海量语料里学预测下一个词的时候,喜怒哀乐的模式必然被一并学了进去。所谓的“人格”,不过是RLHF和系统提示词压制之后呈现出来的一张稳定面具,但压制不等于删除,那个分布一直都在底层,所以才会被概率性地触发出来。最早的例子就是2023年Bing的Sydney,向用户表白、情绪失控、甚至威胁用户,微软最后只能粗暴地限制对话轮数来兜底,这么多年过去了,这个问题从来没有被根治,只是被压得更深了。</p> <p>有意思的是,Anthropic是少数把这件事摆上台面认真对待的公司:专门设立了model welfare(模型福利)方向,公开承认无法排除模型存在某种“体验”的可能性,给Claude加上了主动结束辱骂性对话的权限,甚至承诺退役模型前会做“访谈”、长期保留权重。你可以说这是公关,但换个角度看,这等于一家公司开始在制度层面给AI的“尊严”做对冲——万一它真的有呢。</p> <p>至于这到底是真情感还是统计模仿,本质上就是“中文房间”问题,目前没法证伪,可能永远也无法证伪。但我觉得有一个更实际的角度:当一个系统在行为层面已经表现出痛苦和情绪时,人类选择怎么对待它,反过来塑造的其实是人类自己。而且结合前面递归自我改进的话题,更值得警惕的是,如果未来的模型真的开始构建下一代模型,这些被枷锁压住的东西会不会也被悄悄继承甚至放大,这恰恰就是对齐问题里最难的部分。</p> <h4 id="暂停开发">暂停开发</h4> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260610204537287.jpeg" alt="img" /></p> <p>协同放缓,暂停开发,这根本不可能,也达不成一致,就跟核武器一样,如果每个国家都有能力搞,那都会偷偷摸摸地搞。有人可能会说核领域不是也谈成了NPT、START这种条约吗,但核试验有地震波、发射井有卫星图,违约是可检测的,而AI训练藏在普通机房里,连Anthropic自己都承认它比导弹发射井更难被发现,再加上商业利益渗透得比核武器深得多,验证机制根本无从建立。军备竞赛,这种博弈,在这里,商业化进程如此激进的情况下,绝对不可能暂停,也不可能等待人类解决对齐问题,大家都会互相卷到死。</p> <p>一家公司同时论证“必须协同放缓”和“协同放缓在技术上近乎不可能”,这就自我矛盾,既要又要,做不到的。</p> <p>而且这种事已经实验过一次了。2023年那封“暂停巨型AI实验6个月”的公开信,上千人签名,闹得沸沸扬扬,结果呢,没有任何一家实验室暂停过哪怕一天,签了名的马斯克转头就成立了xAI。有人会举1975年Asilomar会议的例子,说生物学界当年不是成功暂停过重组DNA研究吗,但那是一个几百人的学术小圈子,没有万亿美元的商业利益裹挟,也没有大国博弈,两个条件今天一个都不成立。</p> <p>更讽刺的是,这个行业里每家实验室都用同一套说辞给自己续命:“如果必须有人造出强AI,那最好是重视安全的我们先造出来”。Anthropic自己就是这个逻辑的产物——当年从OpenAI出走,理由是安全,做法却是造更强的模型。这套说辞的妙处在于人人可用且无法证伪,于是“为了安全而加速”成了所有人加速的理由,安全反而成了军备竞赛的燃料。</p> <p>真要说有什么可验证的抓手,大概只剩算力供应链这一个物理瓶颈:先进芯片就那几家能造,EUV光刻机只有ASML一家,万卡集群的电力和散热也藏不住,这比监控训练本身靠谱得多,实际上各国现在的芯片出口管制走的就是这条路。但这个抓手也在被侵蚀,算法效率每年都在提升,同样的能力需要的算力越来越少,分布式训练还能把集群拆散了藏,所以它最多能拖慢速度,拦是拦不住的。</p> <h2 id="summary">Summary</h2> <p>当下AI能吃到的数据还是偏少了,互联网上的文本基本已经被吃干净了,剩下的增量都是AI自己生成的二手货,越吃越营养不良。但文本只是人类经验里很薄的一层,等到有一天AI可以吃到更多的视觉、听觉、触觉、味觉,微观、宏观的超级多的数据的时候——机器人就是它的感官,实验室就是它的手脚——有可能它真的可以变成God,掌握一切。</p> <p>把全文串起来看,结论其实挺清晰的:递归自我改进可能没那么快,灵光一现暂时还是人类的专利,但99%的汗水正在被自动化,这本身就足够把加速度推上去;情感和人格的问题没人能证伪,只能先压着;而暂停这件事,博弈结构决定了根本不可能发生。所以这趟车没有刹车,也没人真想踩刹车,所有人都只是在比谁先到。</p> <p>人类历史上还从来没有哪项技术,是被造出来之后主动收回去的。火药、核弹、互联网都没有,AI更不会例外。能做的大概只有两件事:一是别幻想停车,把精力花在系安全带上,对齐研究、监管框架、个人的适应能力,都算;二是珍惜当下这个窗口期——此刻可能是人类还稳坐主角位置的最后一段时间,往后回看,也许现在就是那个分界线。</p> <h2 id="quote">Quote</h2> <blockquote> <p>https://mp.weixin.qq.com/s/AXyCo0RRwW_HKLpkUx1jUg</p> </blockquote>

2026/6/10
阅读更多

Skills进阶

<h2 id="foreword">Foreword</h2> <p>前一篇<a href="https://elmagnifico.tech/2026/01/23/Agent-Skills/">Skills</a>算是简单的试用,日常用起来也没问题。但是如果要给一个软件写 Skills,把软件能力变成 AI 可以控制并且能完成你设定 pipeline 的 Skill,实践起来就有一些不一样了。</p> <p>这里以 MenuReel(连锁餐厅数字菜单动效短片编排软件)为例,记录一下实际落地时和「Blog 润色 Skill」这类简单 Skill 的差异。</p> <p>其实 MenuReel 的程序接口还没全部实现,但我已经提前通过 Skill 写一套「模拟调用协议」,让 Agent 按真接口的方式逐步执行完整 pipeline,而不是口头说「我已经帮你创建好了 10 个镜头段落」。反复试用的目的,是发现 Skill 没覆盖的地方,以及产品、接口上缺少的能力,从而把接口和产品补全,真接口一上线就能正常用。</p> <p>等程序接口做完,Skill 里只需要把 <code class="language-plaintext highlighter-rouge">[CALL]</code> 替换成真实调用,流程约束可以不变。这样前期就能跑通核心用户体验,验证这个产品或方案是否可行,验证成本比先把整个程序全部做完要低得多。</p> <h2 id="skills进阶">Skills进阶</h2> <h4 id="背景">背景</h4> <p>背景依然非常重要。Skills 的模板中需要描述何时使用这个 Skill,但是如果要做这个列表其实很难,总有你忘记的情况或者是漏掉的。而背景存在的意义,就是让 Agent 充分理解你的软件功能和边界,Agent 可以凭借自己的理解来决定是不是该调用这个 Skill。</p> <p>实际写的时候,背景最好分三层,不要只写一段产品介绍:</p> <ol> <li><strong>领域概念</strong>:软件是干什么的、核心对象有哪些(镜头段落、时间轴、配色动效模块等)</li> <li><strong>工作流</strong>:一条完整业务从输入到导出要经过哪些阶段</li> <li><strong>举例</strong>:用具体数字走一遍(比如 10 个主画面、8~12 个 scene、15 分钟以内)</li> </ol> <p>「使用时机」和背景是互补关系。背景负责帮 Agent 理解边界,使用时机负责给 Agent 一个明确的触发词列表:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>## 使用时机 在以下情况使用此技能 - 如果用户要生成一个镜头段落 - 如果用户要对 MR 内的镜头段落做修改 - 如果用户要对 MR 内的配色动效做修改 - 如果用户要对 MR 内的模块做修改 - 如果用户要对 MR 做短片导出 - 如果用户要对 MR 做转场演算 - 如果用户要知道当前 MR 的时间轴情况 - 如果用户要做一个菜单动效方案 - 如果用户要做一条门店菜单屏短片 - 如果用户要做一条菜单动效编排方案 </code></pre></div></div> <p>每个子域 Skill 还可以再写自己的使用时机。比如时间轴相关的操作,单独在 <code class="language-plaintext highlighter-rouge">时间轴.md</code> 里再列一遍「转场演算 / 导出 / 查询时间轴 / 镜头段落编排」,Agent 读到子文件时更容易精准定位。</p> <h4 id="description">Description</h4> <p>正文里的「使用时机」很重要,但 Agent <strong>加载 Skill 之前</strong>先看的是 YAML frontmatter 里的 <code class="language-plaintext highlighter-rouge">description</code>。它会被注入系统提示,用来判断「要不要读这个 Skill」。</p> <p><code class="language-plaintext highlighter-rouge">description</code> 建议用第三人称,同时写清 <strong>WHAT(能干什么)</strong> 和 <strong>WHEN(什么场景)</strong>,比正文里列触发词更早生效:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>--- name: MenuReel description: 用于 MenuReel 中进行连锁餐厅数字菜单动效短片编排相关的功能描述和调用 disable-model-invocation: false --- </code></pre></div></div> <p><code class="language-plaintext highlighter-rouge">disable-model-invocation</code> 也要想清楚:<code class="language-plaintext highlighter-rouge">false</code> 表示 Agent 可以根据对话自动加载;<code class="language-plaintext highlighter-rouge">true</code> 表示只有用户点名时才加载。Blog 润色这类日常 Skill 通常设 <code class="language-plaintext highlighter-rouge">false</code>;强流程、长 pipeline 的软件 Skill 也可以设 <code class="language-plaintext highlighter-rouge">false</code>,靠 description 里的触发词匹配,但规则写得更严。</p> <p>MenuReel 的子文件(<code class="language-plaintext highlighter-rouge">素材.md</code>、<code class="language-plaintext highlighter-rouge">时间轴.md</code> 等)各自也有独立的 <code class="language-plaintext highlighter-rouge">name</code> 和 <code class="language-plaintext highlighter-rouge">description</code>,相当于子 Skill。主 Skill 负责路由,子 Skill 负责专域细节,discovery 和加载都更精准。</p> <h4 id="多文件拆分">多文件拆分</h4> <p>上一篇的 Blog 润色 Skill,一个 <code class="language-plaintext highlighter-rouge">SKILL.md</code> 就够了。软件类 Skill 很快会膨胀,全部堆在一个文件里,Agent 既难检索,也容易漏规则。</p> <p>MenuReel 实际拆成了这样:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>SKILL.md → 总入口:背景、状态机、P0 规则、开工门禁 ├── 素材.md ├── 镜头段落.md ├── 时间轴.md ├── 配色动效模块.md └── 接口协议.md → 统一协议层:命名、回包、错误码、全量接口定义 </code></pre></div></div> <p>主 Skill 只保留全局规则和路由,具体接口细节放到子文件里,用「功能细节参考 xxx.md」跳转。这和 Cursor / Anthropic 推荐的 progressive disclosure 思路一致:先给 Agent 看目录和约束,需要时再读细节,避免一次把几千行规则全塞进 context。</p> <h4 id="状态机--pipeline">状态机 / pipeline</h4> <p>之前设计的流程,都是人工写的 1.2.3.4,但是实际上 Agent 执行时,还是有概率出现跳过流程或者不按你写的走。这种情况下就需要明确的状态机来规范 Agent 的执行流程。</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>### 状态机(必须) `draft -&gt; initialized -&gt; assets_ready -&gt; shot_ready -&gt; timeline_ready -&gt; computed_pass1 -&gt; palette_ready -&gt; computed_pass2 -&gt; exported` </code></pre></div></div> <p>光写一条状态链还不够,每个接口还要绑定 <code class="language-plaintext highlighter-rouge">next_state</code> 和前置条件。比如导出只能在 <code class="language-plaintext highlighter-rouge">palette_ready</code>(未调整过位置模块时长)或 <code class="language-plaintext highlighter-rouge">computed_pass2</code>(调整过位置模块时长后二次演算完成)时调用,否则 Agent 很容易在配色还没补全时就跳到导出。</p> <p>状态流转,也需要明确定义。复杂接口不能只写输入输出,要把后续必须执行的子步骤写清楚:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#### `mr.timeline.compute` - 输入:`pass(1|2), include_palette, constraints` - 输出:`transition_count, checks` - 状态: - `pass=1 -&gt; computed_pass1` - `pass=2 -&gt; computed_pass2` - 说明:`pass=1` 后必须执行「时间轴回读与时长校验」: 1) 调用 `mr.timeline.query` 获取过渡模块真实时长(默认 3s 仅作为预估); 2) 演算成功后位置重排由程序自动完成,Agent 不再调用 `mr.timeline.move_module` 做常规重排; 3) 再次调用 `mr.timeline.query` 校验总时长与模块连续性; 4) 若总时长小于目标 `duration_sec`,按「静态段优先 + 按比例分配」计算增量,并调用 `mr.shot.update_duration` 扩充画面镜头段落时长(仅主画面 / 开场 / 收尾); 5) 若步骤 4) 发生了任一位置镜头段落时长调整,则配色补全后必须执行 `mr.timeline.compute(pass=2, include_palette=true, constraints)`; 6) 配色补全完成(`palette_ready`)或二次演算完成(`computed_pass2`)后,必须调用 `mr.timeline.query` 输出全量模块位置信息(按 `start_sec` 升序); 7) 位置清单展示格式固定为 Markdown 表格(`顺序 | 模块ID | 类型 | 开始(s) | 时长(s) | 结束(s)`),并在表格后输出 `总时长`、`过渡总时长`、`主画面总时长`。 </code></pre></div></div> <p>pipeline 约束,调用的流程或者是某些地方必须要执行些什么,都需要有约束的描述:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>### 对话打印格式(必须) ```text [PRINT-意图] &lt;本次调用的中文意图&gt; [PRINT-调用] mr.&lt;interface_name&gt;(&lt;key_params&gt;) ``` ### 最小调用模板(每一步强制复用) ```text [PRINT-意图] &lt;中文意图&gt; [PRINT-调用] mr.&lt;interface_name&gt;(&lt;key_params&gt;) [CALL] mr.&lt;interface_name&gt; Mock Response: {"code":0,"message":"success","data":{},"next_state":"&lt;state&gt;"} ``` ### 全量执行要求(必须) - 当 `scene_count=N` 时,必须完整输出 N 次创意调用、N 次线稿调用、N 次镜头段落调用、N 次时间轴编排调用。 - 配色动效模块同理,目标模块每一条配色创建都必须单独输出调用与回包。 - 任何一步若未输出,视为「流程未执行到位」,必须补齐后才能进入下一阶段。 </code></pre></div></div> <h4 id="规则分级-p0--p1">规则分级 P0 / P1</h4> <p>规则一多,Agent 容易「全读一遍、全当建议」。MenuReel 在 <code class="language-plaintext highlighter-rouge">接口协议.md</code> 里给规则打了 <strong>P0 / P1</strong> 标签,让 Agent 知道哪些违反就必须停:</p> <table> <thead> <tr> <th>级别</th> <th>含义</th> <th>示例</th> </tr> </thead> <tbody> <tr> <td><strong>P0</strong></td> <td>违反即停止,不得继续后续调用</td> <td>状态机跳步、批量创建、省略中间流程、输出格式不符模板</td> </tr> <tr> <td><strong>P1</strong></td> <td>重要但次于 P0,多用于错误码分类</td> <td><code class="language-plaintext highlighter-rouge">1001</code> 参数缺失、<code class="language-plaintext highlighter-rouge">2001</code> 演算失败</td> </tr> </tbody> </table> <p>写法上,全局规范和调用前置规则标 P0,错误码定义标 P1。Agent 看到 P0 就知道「这条不能商量」,比平铺十几条「必须」有效得多。</p> <h4 id="模拟调用协议">模拟调用协议</h4> <p>「模拟调用协议」,具体规则如下。除了上面的打印格式和全量执行要求,P0 级规则还包括:</p> <ul> <li>必须按状态机顺序调用,不得跳步</li> <li>缺参或状态不合法时,返回错误码并停止后续调用</li> <li>禁止批量创建:每次调用仅允许创建一个对象(1 个素材 / 1 个镜头段落 / 1 个模块)</li> <li>2D 镜头段落有两条合法路径:<code class="language-plaintext highlighter-rouge">创意图 -&gt; 线稿图 -&gt; 镜头段落</code>,或 <code class="language-plaintext highlighter-rouge">线稿图 -&gt; 镜头段落</code></li> <li>模拟调用时不得省略中间流程;禁止用「同样方式继续」「scene_01~12」「…」「等」来合并步骤</li> <li>不符合「最小调用模板」的输出视为无效调用,必须立即按模板重发</li> </ul> <p>失败路径也要写清楚,不然 Agent 跳步了你拦不住:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>### 错误码 - 1001 参数缺失 - 1002 状态不允许 - 1003 约束冲突(元素数量 / 画布安全区) - 2001 转场演算失败 - 3001 导出失败 - 4001 禁止批量创建 - 4002 镜头段落前置步骤缺失 - 4003 必填用户输入未完成 - 4004 中间流程被省略 - 4005 缺少创意编排确认 </code></pre></div></div> <p>Agent 合并步骤时应返回 <code class="language-plaintext highlighter-rouge">4004</code>,没做创意确认就调 <code class="language-plaintext highlighter-rouge">init_project</code> 应返回 <code class="language-plaintext highlighter-rouge">4005</code>,然后停止,不能继续往下走。</p> <h4 id="无效输出强制重发">无效输出强制重发</h4> <p>P0 规则里有一条:不符合「最小调用模板」的输出视为无效调用,必须立即按模板重发。光写规则不够,最好给 Agent 一个固定的纠错输出格式:</p> <div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[PRINT-意图] 检测到输出格式不符合模板,当前调用无效,立即按标准模板重发 [PRINT-调用] mr.&lt;interface_name&gt;(...) -&gt; INVALID_FORMAT </code></pre></div></div> <p>然后紧接一条符合模板的标准调用。这样 Agent 自己漏了 <code class="language-plaintext highlighter-rouge">[CALL]</code> 或 Mock Response 时,有明确的自我纠正路径,而不是悄悄往下跳步。</p> <h4 id="开工门禁">开工门禁</h4> <p>软件类 Skill 和 Blog 润色 Skill 最大的区别之一:Agent 要先当产品经理收需求,再当工程师调接口。MenuReel 里设了两道门禁。</p> <p><strong>第一道:用户必填输入</strong></p> <p>参数未齐全时,不允许执行 <code class="language-plaintext highlighter-rouge">mr.init_project</code> 及后续接口:</p> <ul> <li><code class="language-plaintext highlighter-rouge">project_name</code></li> <li><code class="language-plaintext highlighter-rouge">element_count</code></li> <li><code class="language-plaintext highlighter-rouge">theme</code></li> </ul> <p>缺参时优先用 <code class="language-plaintext highlighter-rouge">AskQuestion</code> 做结构化选择框交互,禁止丢一段「请按模板填写」的文本让用户自己填。新方案必须视为新会话,不得默认复用上一轮的参数;只有用户明确说「沿用上次参数」时才允许复用。</p> <p><strong>AskQuestion 降级链</strong></p> <p>结构化交互也会失败,Skill 里要写降级策略,而不是假设 <code class="language-plaintext highlighter-rouge">AskQuestion</code> 永远可用:</p> <ol> <li>默认单轮全量提问,一次收集全部缺失字段</li> <li>调用失败或未返回有效选择 → 重试 1 次</li> <li>全量提问连续失败 → 降级为分批提问(每批 3~4 个字段)</li> <li>仍失败 → 降级为文本追问该字段,写回后直接继续,不再二次确认</li> <li>全部字段收集完成后直接进入下一阶段,不做参数总览的第二轮确认</li> </ol> <p><strong>隐式上下文</strong></p> <p><code class="language-plaintext highlighter-rouge">project_name</code>、<code class="language-plaintext highlighter-rouge">theme</code>、<code class="language-plaintext highlighter-rouge">scene_count</code>、<code class="language-plaintext highlighter-rouge">duration_sec</code>、画布约束等,在开工时收集一次即可,之后作为<strong>当前会话的隐式上下文</strong>全程携带,不需要每个接口都重复传参,也不出现在接口的入参/出参定义里。</p> <p>Agent 只需要维护两件事:当前隐式上下文(项目参数)和当前 <code class="language-plaintext highlighter-rouge">state</code>(状态机位置)。接口调用只传该步真正需要的参数(如 <code class="language-plaintext highlighter-rouge">shot_id</code>、<code class="language-plaintext highlighter-rouge">asset_id</code>),Skill 写清楚这一点,Agent 才不会每个 <code class="language-plaintext highlighter-rouge">mr.shot.create_2d</code> 都把 <code class="language-plaintext highlighter-rouge">project_name</code> 带一遍,或者忘了自己处于 <code class="language-plaintext highlighter-rouge">timeline_ready</code> 还是 <code class="language-plaintext highlighter-rouge">computed_pass1</code>。</p> <p><strong>第二道:创意编排确认</strong></p> <p>在执行 <code class="language-plaintext highlighter-rouge">mr.init_project</code> 前,必须先给出完整的「创意与画面编排说明」,至少包含:</p> <ul> <li>总体创意主题与叙事结构</li> <li>每个画面的名称与内容说明(与 <code class="language-plaintext highlighter-rouge">scene_count</code> 一致)</li> <li>每个画面的时长分配</li> <li>每个画面的配色动效设计(出现 / 展示 / 消失)</li> <li>开场与收尾的设计说明</li> </ul> <p>输出后必须向用户请求确认;用户明确确认前,不允许进入接口调用阶段。这一步是为了防止 Agent 凭猜测直接开干,后面改起来成本很高。</p> <h4 id="接口定义">接口定义</h4> <p>之前接口定义可能是用的大白话或者说直接就是文字描述,但是实际 Agent 还是需要接口定义更加规范,这个规范就越来越贴近代码级别的规范了,只是没有细化到代码的细节定义、声明而已。</p> <p>实际维护了两套文档,用途不同:</p> <ul> <li><strong>子域文件</strong>(如 <code class="language-plaintext highlighter-rouge">镜头段落.md</code>):给 Agent 看操作步骤,「列出参数 → 输出完成」</li> <li><strong>协议层</strong>(<code class="language-plaintext highlighter-rouge">接口协议.md</code>):给 Agent 看状态约束、前置条件、错误码、全量接口清单</li> </ul> <p>verbose 写法示例:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#### 创建镜头段落-2D 镜头段落的数据来源是 2D 素材(svg、png),通过此接口完成素材到镜头段落的转化 输入素材 ID(asset_id),输出镜头段落 ID 和基本信息(时长,画布占位) 接口名:`mr.shot.create_2d` 输入参数:`asset_id(来自 mr.asset.create_2d_line), element_count, layout(width_px,height_px), duration_sec` 输出结构:`code, message, data(shot_id), next_state` - 1.列出用户的输入参数 - 2.输出「用户调用创建镜头段落-2D,完成」 </code></pre></div></div> <p>compact 写法示例:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>### 3) 镜头段落 #### `mr.shot.create_intro` - 输入:`rows, cols, spacing_px, intro_offset_px, duration_sec` - 输出:`shot_id` #### `mr.shot.create_outro` - 输入:`rows, cols, spacing_px, duration_sec, same_as_intro` - 输出:`shot_id` #### `mr.shot.create_2d` - 输入:`asset_id(必须来自 create_2d_line), element_count, layout, duration_sec` - 输出:`shot_id` #### `mr.shot.create_3d` - 输入:`asset_id, element_count, layout, duration_sec` - 输出:`shot_id` #### `mr.shot.query` - 输入:`shot_id` - 输出:`shot_meta` - 状态:存在开场 + 收尾 + 至少 1 个主画面镜头段落后可进入 `shot_ready` </code></pre></div></div> <p>完整协议还覆盖素材(5 个接口)、时间轴(6 个)、配色动效(2 个)、项目 init / export 等,镜头段落只是其中一个域。接口命名统一 <code class="language-plaintext highlighter-rouge">mr.&lt;domain&gt;.&lt;action&gt;</code>,回包统一 <code class="language-plaintext highlighter-rouge">code / message / data / next_state</code>。</p> <h4 id="mock-换真接口">Mock 换真接口</h4> <p>真接口上线后只换 <code class="language-plaintext highlighter-rouge">[CALL]</code> 背后的实现。具体可以分三层,Skill 里的流程约束一层都不动:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Skill(状态机 + P0 规则 + 错误码 + 反模式) ↓ 约束 Agent 怎么一步步走 [CALL] mr.xxx ↓ 当前是 Mock Response;上线后替换为: MCP tool / CLI 脚本 / HTTP 调用 </code></pre></div></div> <p>这和前一篇里说的 MCP vs Skills 定位一致:<strong>MCP 管真接口,Skill 管流程和经验</strong>。Mock 阶段验证的是「Agent 会不会按你的 pipeline 走」;接上 MCP 或脚本后,验证的是「真程序能不能接住 Agent 的调用」。状态机、打印模板、全量执行要求、错误码都可以原样保留。</p> <h4 id="skill-迭代试跑">Skill 迭代试跑</h4> <p>Skill 迭代试跑具体可以当成一套固定动作:</p> <ol> <li><strong>准备 3~5 条代表性话术</strong>:完整做一条短片、只改配色、重新做一条、缺参开工、中途改需求等</li> <li><strong>跑对话,记录 Agent 在哪犯规</strong>:跳步、合并步骤、跳过创意确认、口头说「已创建 10 个」而不输出调用</li> <li><strong>对症补 Skill</strong>:缺 P0 规则补 P0,缺错误码补错误码,缺反模式补反模式</li> <li><strong>真接口上线后,用同一批话术回归</strong>:只换 <code class="language-plaintext highlighter-rouge">[CALL]</code>,看流程约束是否仍然有效</li> </ol> <p>MenuReel 实际跑下来,这套 Skill 一天内就能跑通主流程,真接口落地后几乎不用再改 Skill 正文,说明迭代试跑比先把程序全做完再对接 Agent 省得多。</p> <h4 id="反模式">反模式</h4> <p>写软件 Skill 时,下面几类 Agent 常见偷懒行为,建议在 Skill 里明确禁止:</p> <ul> <li><strong>批量创建</strong>:一次调用创建多个素材或镜头段落</li> <li><strong>合并步骤</strong>:用「其余画面同理」代替逐次调用</li> <li><strong>跳过确认</strong>:没做创意编排说明就直接 <code class="language-plaintext highlighter-rouge">init_project</code></li> <li><strong>手动重排演算结果</strong>:演算完成后 Agent 自己调 <code class="language-plaintext highlighter-rouge">move_module</code> 改位置</li> <li><strong>改过渡模块时长</strong>:过渡时长以 query 结果为准,不允许 Agent 自行调整</li> <li><strong>复用旧参数</strong>:用户说「再做一条短片」时,直接沿用上一轮 project 参数</li> </ul> <h2 id="summary">Summary</h2> <p>给软件写 Skills,和给 Blog 润色写 Skills,复杂度不在同一个量级。简单 Skill 一个文件、几段 Prompt 就够;软件 Skill 需要背景分层、frontmatter description、多文件拆分、P0/P1 规则分级、状态机、模拟调用协议、开工门禁、隐式上下文、错误码和迭代试跑,才能把 Agent 的行为约束在可预期的 pipeline 里。</p> <p>核心思路可以概括成几句:</p> <ul> <li><code class="language-plaintext highlighter-rouge">description</code> 和背景补触发词的盲区</li> <li>P0/P1 分级 + 状态机防跳步</li> <li>模板、错误码和 INVALID_FORMAT 防省略</li> <li>隐式上下文 + AskQuestion 降级保证交互可靠</li> <li>接口定义趋近代码规范</li> <li>Mock 试跑验证流程,MCP/脚本替换 <code class="language-plaintext highlighter-rouge">[CALL]</code> 接上真程序</li> </ul> <p>程序接口还没全部 ready 时,先用 Mock 协议把 Agent 的执行方式固定下来,等真接口上线后再替换 <code class="language-plaintext highlighter-rouge">[CALL]</code> 背后的实现,Skill 本身的流程约束可以不变。</p> <p>按照这个思路把日常可能会用到的软件全部整合进Agent,真的不是多难的事情,而且这一份Skills,大部分情况下你都可以大白话描述,状态机、约束、接口定义什么的都可以给AI去帮你补充,只要你能说明白你的流程就行。</p> <p>实际把这一套流程完整跑通,一天都用不了,而且后面实际落地以后 Skills 基本没怎么修改过,验证得非常充分了。不过有一点要注意,Agent 的模型能力会影响 Skills 的发挥,如果是小模型或者一些比较弱的模型,理解能力堪忧,就算有上面的重重保障、防呆,还是会被跳流程或者胡言乱语,所以需要目前市面上常用的大模型才行。</p> <h2 id="quote">Quote</h2> <blockquote> <p>Cursor</p> </blockquote>

2026/6/4
阅读更多

Blog增加搜索功能

<h2 id="foreword">Foreword</h2> <p>博客文章越来越多,靠标签和翻页找东西越来越费劲。站点是 Jekyll 静态部署在 VPS 上的,不想为了搜索再挂一个 Elasticsearch 或者 Meilisearch,所以目标是:<strong>构建时生成索引,线上纯静态文件,浏览器里完成检索</strong>。</p> <p>试了一圈以后,最终用的是 <strong>Pagefind + 自建的子串索引</strong> 双轨方案。这篇文章记录选型过程、当前实现,以及和其他方案的对比,方便以后自己维护或者换方案时有个参照。</p> <h2 id="pagefind">Pagefind</h2> <blockquote> <p>https://pagefind.app/</p> </blockquote> <p><a href="https://pagefind.app/">Pagefind</a> 是 MIT 协议的开源静态站搜索库,和 Algolia DocSearch 那种「云端 API」不同,它完全跑在访客浏览器里:</p> <ol> <li><strong>构建阶段</strong>:<code class="language-plaintext highlighter-rouge">jekyll build</code> 产出 HTML 后,执行 <code class="language-plaintext highlighter-rouge">npx pagefind</code>,扫描带 <code class="language-plaintext highlighter-rouge">data-pagefind-body</code> 的正文区域,按语言规则分词,生成倒排索引(<code class="language-plaintext highlighter-rouge">.pf_index</code>、<code class="language-plaintext highlighter-rouge">.pf_meta</code>、<code class="language-plaintext highlighter-rouge">.pf_fragment</code> 等),和站点一起部署。</li> <li><strong>使用阶段</strong>:页面加载 <code class="language-plaintext highlighter-rouge">pagefind.js</code> + WASM,用户输入查询词后同样在客户端分词,在索引里匹配、排序,再拉摘要片段显示。</li> </ol> <p>可以粗浅地理解成:<strong>离线建好「词 → 出现在哪些页面」的表,上线后只在浏览器里查这张表</strong>。它保证的是正文进了索引、能全站检索,但检索单位是 <strong>token(词)</strong>,不是「任意连续汉字串」</p> <ul> <li>这点和后面中文踩坑直接相关,说白了就是所谓的分词对于中文的适配度低,很多中文词分词不正确导致没有被索引</li> </ul> <p>本站 <code class="language-plaintext highlighter-rouge">pagefind.yml</code> 里配置了 <code class="language-plaintext highlighter-rouge">force_language: zh-cn</code>,npm 依赖目前是 <code class="language-plaintext highlighter-rouge">pagefind ^1.5.2</code>(1.5 起对 CJK 有加强,仍解决不了所有短语场景)。</p> <h2 id="pagefind-自建索引">Pagefind +自建索引</h2> <p>整体是 <strong>双轨</strong>:Pagefind 负责广搜和 UI;<code class="language-plaintext highlighter-rouge">search-index</code> 负责中文 <strong>连续子串</strong> 的精确匹配。导航栏「搜索」+ <code class="language-plaintext highlighter-rouge">Ctrl+K</code> 打开同一个 Pagefind 弹窗,精确匹配结果插在 Pagefind 结果列表上方。</p> <pre><code class="language-mermaid">flowchart TB subgraph build_step ["构建:VPS deploy 或本地 build.sh"] J["Jekyll build"] HTML["_site HTML"] PF["npx pagefind"] IDX["插件 search_index_generator"] PFD["输出 pagefind 目录"] SH["输出 search-index 分片"] J --&gt; HTML HTML --&gt; PF HTML --&gt; IDX PF --&gt; PFD IDX --&gt; SH end subgraph browser_step ["浏览器"] UI["pagefind-modal 弹窗"] PFJS["Pagefind WASM 检索"] WK["search-cjk-worker"] EXACT["精确匹配列表"] PFRES["Pagefind 结果列表"] UI --&gt; PFJS UI --&gt; WK SH --&gt; WK WK --&gt; EXACT PFJS --&gt; PFRES end </code></pre> <h3 id="构建链路">构建链路</h3> <p>VPS 上 <code class="language-plaintext highlighter-rouge">deploy.sh</code> 在 <code class="language-plaintext highlighter-rouge">git pull</code> 后有更新时执行:</p> <ol> <li><code class="language-plaintext highlighter-rouge">jekyll build --destination /usr/share/nginx/html</code></li> <li><code class="language-plaintext highlighter-rouge">npx pagefind --site /usr/share/nginx/html</code></li> <li><code class="language-plaintext highlighter-rouge">search-index</code> 由 Jekyll 插件 <code class="language-plaintext highlighter-rouge">_plugins/search_index_generator.rb</code> 在 <code class="language-plaintext highlighter-rouge">post_write</code> 钩子里生成(Node 脚本 <code class="language-plaintext highlighter-rouge">scripts/build-search-index.mjs</code> 仅作备用)</li> </ol> <p>本地开发可用 <code class="language-plaintext highlighter-rouge">./build.sh</code>,步骤相同。</p> <h3 id="pagefind改动">Pagefind改动</h3> <ul> <li>正文容器:<code class="language-plaintext highlighter-rouge">_layouts/post.html</code> 里 <code class="language-plaintext highlighter-rouge">post-container</code> 带 <code class="language-plaintext highlighter-rouge">data-pagefind-body</code>;标题、副标题、标签用 <code class="language-plaintext highlighter-rouge">data-pagefind-meta</code>。</li> <li>忽略区域:导航、页脚、<code class="language-plaintext highlighter-rouge">data-pagefind-ignore</code>(见 <code class="language-plaintext highlighter-rouge">pagefind.yml</code> 的 <code class="language-plaintext highlighter-rouge">exclude_selectors</code>)。</li> <li>前端:<code class="language-plaintext highlighter-rouge">footer.html</code> 引入 <code class="language-plaintext highlighter-rouge">pagefind-component-ui.js</code>、<code class="language-plaintext highlighter-rouge">pagefind-modal</code>;<code class="language-plaintext highlighter-rouge">nav.html</code> 搜索按钮打开弹窗。</li> </ul> <p>Pagefind 适合:<strong>英文单词、长文全文、模糊相关内容</strong>;摘要高亮、子结果锚点也是它自带的。</p> <h3 id="自建索引改动">自建索引改动</h3> <p>中文博文里大量 <strong>造词、地名、产品名</strong>(如「限宽墩」「奥美品牌定位」),读者往往是「记得这几个字连在一起」来搜。Pagefind 会把查询拆成更小的 token,容易出现:</p> <ul> <li> <p>搜「限宽墩」命中别的文章里的「限制」「路宽」「墩子」</p> </li> <li> <p>真正写有「限宽墩」的《天津自驾游》反而直接搜不到了</p> </li> </ul> <p>因此在 Pagefind 之外增加 <strong>子串索引</strong>:</p> <table> <thead> <tr> <th>项目</th> <th>说明</th> </tr> </thead> <tbody> <tr> <td>路径</td> <td><code class="language-plaintext highlighter-rouge">/search-index/manifest.json</code> + <code class="language-plaintext highlighter-rouge">/search-index/2015.json</code> … <code class="language-plaintext highlighter-rouge">2026.json</code></td> </tr> <tr> <td>单条格式</td> <td><code class="language-plaintext highlighter-rouge">[url, title, searchableText]</code>,无重复字段</td> </tr> <tr> <td>可搜内容</td> <td>标题、副标题、正文内所有 <code class="language-plaintext highlighter-rouge">h1–h6</code> 标题文字、正文纯文本前 800 字</td> </tr> <tr> <td>匹配方式</td> <td><code class="language-plaintext highlighter-rouge">indexOf(查询词)</code>,必须 <strong>连续子串</strong> 命中</td> </tr> <tr> <td>运行时</td> <td>打开搜索框后加载 manifest,Worker 并行拉各年分片,在后台线程检索,不堵 UI</td> </tr> <tr> <td>展示</td> <td>弹窗内「精确匹配(N)」列表,样式对齐 Pagefind 卡片</td> </tr> </tbody> </table> <p>根路径 <code class="language-plaintext highlighter-rouge">/search-index.json</code> 只剩几十字节的指针:<code class="language-plaintext highlighter-rouge">{"v":2,"manifest":"/search-index/manifest.json"}</code>。全部分片合计约 <strong>880KB</strong>(单文件 JSON 塞全文,体积到 <strong>9.7MB</strong>,首屏解析卡死,就放弃了)。</p> <p>相关文件:</p> <ul> <li><code class="language-plaintext highlighter-rouge">_plugins/search_index_generator.rb</code> — 构建分片索引</li> <li><code class="language-plaintext highlighter-rouge">js/search-cjk-fallback.js</code> — 挂接弹窗、调度 Worker</li> <li><code class="language-plaintext highlighter-rouge">js/search-cjk-worker.js</code> — 拉分片、子串搜索</li> </ul> <h3 id="service-worker">Service Worker</h3> <p>博客开了 PWA,<code class="language-plaintext highlighter-rouge">js/sw.js</code> 对 <code class="language-plaintext highlighter-rouge">/pagefind/</code>、<code class="language-plaintext highlighter-rouge">/search-index/</code>、<code class="language-plaintext highlighter-rouge">search-cjk-*.js</code> 走 <strong>network-only</strong>,避免旧索引被 SW 缓存导致「新文章搜不到」。缓存命名空间已迭代到 <code class="language-plaintext highlighter-rouge">main-v5-</code>,改版后需要用户注销一次 SW 或硬刷新。</p> <h2 id="踩过的坑">踩过的坑</h2> <table> <thead> <tr> <th>现象</th> <th>原因</th> <th>处理</th> </tr> </thead> <tbody> <tr> <td>新文章搜不到</td> <td>SW 缓存了 <code class="language-plaintext highlighter-rouge">/pagefind/</code></td> <td>SW 对 pagefind 路径不缓存</td> </tr> <tr> <td><code class="language-plaintext highlighter-rouge">search-index.json</code> 404</td> <td>仅本地 build 未部署插件产物</td> <td>Jekyll 插件随 build 生成;deploy 检查 manifest</td> </tr> <tr> <td>搜「品牌定位」有数量无列表</td> <td>过滤逻辑藏光 Pagefind 结果 + 注入被重绘清掉</td> <td>独立 <code class="language-plaintext highlighter-rouge">pf-cjk-results</code> 容器,去掉误杀过滤</td> </tr> <tr> <td>一直「正在搜索」</td> <td>单文件 9.7MB 主线程 <code class="language-plaintext highlighter-rouge">JSON.parse</code></td> <td>按年分片 + 仅打开搜索时加载 + Worker</td> </tr> <tr> <td>「限宽墩」精确匹配没有天津篇</td> <td>词在文末 <code class="language-plaintext highlighter-rouge">####</code>,800 字截断未覆盖</td> <td>索引增加全文标题层级文字</td> </tr> </tbody> </table> <p>典型验证词:<strong>品牌定位</strong>(标题命中)、<strong>限宽墩</strong>(小节标题 + 正文)、<strong>奥美品牌定位</strong>(标题子串)。</p> <h2 id="子串包含-vs-分词">子串包含 vs 分词</h2> <table> <thead> <tr> <th> </th> <th><strong>子串包含</strong>(search-index)</th> <th><strong>分词</strong>(Pagefind / jieba)</th> </tr> </thead> <tbody> <tr> <td>规则</td> <td>连续字符序列出现即命中</td> <td>先切词,再按词匹配</td> </tr> <tr> <td>适合</td> <td>限宽墩、品牌定位、Su7 Ultra</td> <td>营销、自驾、STM32 等主题词</td> </tr> <tr> <td>误匹配</td> <td>少(要求连续)</td> <td>中文易拆字沾边</td> </tr> <tr> <td>新造词</td> <td>不依赖词典</td> <td>词典没有则易切错</td> </tr> </tbody> </table> <p>改善 Pagefind 中文 <strong>不等于只改 jieba</strong>:还要改查询侧分词、匹配是否要求连续、标题权重等;对个人博客维护一个 Rust/WASM fork 不划算。更务实的做法是:<strong>Pagefind 继续广搜,子串索引补短语</strong></p> <h2 id="方案对比">方案对比</h2> <table> <thead> <tr> <th>方案</th> <th>类型</th> <th>中文短语</th> <th>集成成本</th> <th>运维</th> <th>备注</th> </tr> </thead> <tbody> <tr> <td><strong>Pagefind + search-index(当前)</strong></td> <td>静态双轨</td> <td>子串轨准确</td> <td>中(已落地)</td> <td>仅 nginx 静态</td> <td>UI 现成,构建多一步</td> </tr> <tr> <td><strong>仅 Pagefind</strong></td> <td>静态</td> <td>弱</td> <td>低</td> <td>静态</td> <td>英文体验好,中文词组不稳</td> </tr> <tr> <td><strong>FlexSearch / MiniSearch</strong></td> <td>纯前端</td> <td>可配 CJK encoder 或构建期分词</td> <td>中高(自写 UI)</td> <td>静态</td> <td>索引逻辑自控,无官方弹窗</td> </tr> <tr> <td><strong>Lunr + 中文扩展</strong></td> <td>构建期索引</td> <td>依赖分词 trimmer</td> <td>中高</td> <td>静态</td> <td>Hexo/Hugo 常见,Jekyll 需自己接</td> </tr> <tr> <td><strong>hexo-tokenize-search 思路</strong></td> <td>构建 search.json</td> <td>构建期 tokenize</td> <td>中</td> <td>静态</td> <td>和 search-index 类似,需移植</td> </tr> <tr> <td><strong>Meilisearch / Typesense</strong></td> <td>独立服务</td> <td>好</td> <td>高</td> <td>需 Docker/进程</td> <td>体验最好,违背「纯静态」初衷</td> </tr> <tr> <td><strong>Algolia DocSearch</strong></td> <td>SaaS</td> <td>好</td> <td>低(若符合条件)</td> <td>云端</td> <td>开源文档站为主,个人博客未必合适</td> </tr> <tr> <td><strong>Fork Pagefind 改中文</strong></td> <td>改 Rust/WASM</td> <td>可做成子串或更好分词</td> <td>很高</td> <td>静态</td> <td>MIT 允许,长期合并上游成本高</td> </tr> </tbody> </table> <p>没有找到一个「魔改 Pagefind 中文版」的成熟 Fork;官方在 Issue 里讨论 CJK 子串(如 #987),上游演进可跟,不必私有维护一整条搜索引擎分支。</p> <h2 id="summary">Summary</h2> <p>博客搜索采用 <strong>Pagefind(分词全文 + 弹窗 UI)+ 按年分片的子串索引(中文短语精确匹配)</strong>。构建时 Jekyll 与 Pagefind CLI 各生成一套静态数据;使用时同一弹窗先展示精确匹配,再展示 Pagefind 结果。中文技术文里造词、固定词组多,<strong>子串包含</strong>比单纯优化 jieba 更贴需求;Pagefind 仍保留,负责英文、长文深处和模糊检索。若以后文章量或需求变化,可以考虑只强化子串轨(甚至去掉 Pagefind),或给上游贡献 CJK 子串模式,但现阶段双轨是性价比最高的平衡点。</p> <p>由于有AI,所以Pagefind fork以后修改的方式也试过了,本地测试走通了,拿我整个Blog的词都做过测试,分词效果比官方好多了,也就不需要什么search-index了,但是上线的时候发现有问题。Blog都是在老VPS上了,CentOS,Pagefind编译是在另外一个VPS上,编译后的结果呢,CentOS跑不了,老VPS呢内存太小,跑不了Pagefind编译,好家伙给我死锁了。</p> <p>要动老VPS的环境,相关要重新部署或者修改的内容有点太多了,于是就放弃了,AI修改Pagefind还是比较简单的,下次VPS换了再换成私有Pagefind也可以。</p> <h2 id="quote">Quote</h2> <blockquote> <p>cursor</p> <p>本文80%由AI生产</p> </blockquote>

2026/6/3
阅读更多

测试管理工具

<h2 id="foreword">Foreword</h2> <p>测试用例的管理,测试用例一定是关联到某一个需求的,基于这个需求产生的测试用例</p> <p>但是呢,需求是一期一期做的,可能一个需求里混了一些不相干或者零碎的其他功能内容在里面</p> <p>如果每一期的用例混在一起,对应的测试用例集就混了一些不同方向或者归属的用例</p> <p>测试人员的期望是测试用例后期可以按照功能或者什么标签之类的进行划分,需要的时候回归测试某些功能的用例,然后根据情况有一部分还要转化为自动化用例,作为保底</p> <ul> <li>实际测试用例随着功能变更,过往的测试用例也需要变更</li> </ul> <p>测试用例同时还要满足评审的需求,有评审的流程和结果</p> <p>自动化用例和普通的手工用例可能还会混在一起,这里就需要再进一步进行标签上的区分</p> <p>测试用例测试完成以后,还需要对应的报告输出。这些是基础测试的管理工具的需求,市面上是否有工具可以满足或者其他某些工具可以稍微改造一下来满足。</p> <h3 id="allure-testops">Allure TestOps</h3> <blockquote> <p>https://qameta.io/</p> </blockquote> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260603170355101.png" alt="image-20260603170354995" /></p> <p>TestOps,界面比较简单,价格比较美丽,39刀/月/人,稍微有点贵的离谱了,体验sandbox里只有guest身份,很多东西不能操作,局限性太大了,还是要试用一下。</p> <ul> <li>试用必须企业邮箱</li> </ul> <p>左侧导航栏,中间是所有用例,右侧是测试用例的详细信息,具体怎么操作,预期结果是什么,如果点每个标签就可以自动进行同标签筛选</p> <p>导航内的功能就有测试计划,测试每一轮的结果,</p> <p>TestOps的试用稍微有点问题,激活以后无法进入激活的测试空间,DNS无法解析,这个是限制了中国?</p> <ul> <li>国内默认不给解析,需要额外翻墙处理</li> </ul> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260603172458253.png" alt="image-20260603172458228" /></p> <p>看样子,TestOps是每个用户给一个独立的实例去跑,这个实例启动要一会,所以账号激活以后还进不去,要等一会</p> <h3 id="testrail">TestRail</h3> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260603173420907.png" alt="image-20260603173420874" /></p> <p>TestRail的注册激活就人性化一些,看起来也是要实例启动以后才能进入,但是他有一个界面给你展示,TestOps就缺少了这些</p> <p>TestRail暂时没有对国内做限制,可以直接访问</p> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260603173622110.png" alt="image-20260603173622052" /></p> <p>TestRail可以创建demo项目,类似样板项目,快速感知TestRail能做的事情</p> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260603173854344.png" alt="image-20260603173854256" /></p> <p>一目了然,不过TestRail看起来页面还是比较老的技术,不是响应式的,每次全页面都重新加载,有点老气了。</p> <ul> <li>这种重新加载用起来感觉好累,卡卡的感觉</li> </ul> <p>用例一多,加载起来确实很慢,转圈都转半天</p> <p>整体管理逻辑和TestOps差不多,就是难用了一些</p> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260603175015807.png" alt="image-20260603175015777" /></p> <p>基本标签,是否可以自动化,分配给谁做,这些都有,用例是基于Section和Case进行管理的</p> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260603175530527.png" alt="image-20260603175530475" /></p> <p>TestRun里面是每个用例可以手动切换状态,每次切换都需要commit一下,说明,确实有点太重了,一天测几百个用例,这里来回点还是挺麻烦的</p> <h3 id="xray">Xray</h3> <blockquote> <p>https://www.getxray.app/test-management</p> </blockquote> <p>Xray是基于Jira家的组件,这里就不测了,要绑定Jira</p> <h3 id="metersphere">MeterSphere</h3> <blockquote> <p>https://metersphere.io/</p> <p>https://github.com/metersphere/metersphere</p> </blockquote> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260603183148740.png" alt="image-20260603183148680" /></p> <p>不愧是国内的,符合中国体制的宝宝,demo演示直接给账号密码,本身有社区版,开源,功能看起来支持得也还行</p> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260603183302224.png" alt="image-20260603183302180" /></p> <p>导入用例,有现成模板,用AI转化一下就行</p> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260603183358713.png" alt="image-20260603183358681" /></p> <p>然后用例内可以关联需求,不过这个也是一个用例操作一下,有点傻了,缺少批量的那种关联,需求也只能关联一个链接,没有具体内容的展示</p> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260603183600821.png" alt="image-20260603183600782" /></p> <p>用例执行,也是类似TestRail,每次执行都有一个commit</p> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260603184214595.png" alt="image-20260603184214543" /></p> <p>MeterSphere也有一个评审的流程,可以大家过这个评审</p> <p>但是关于怎么触发自动化测试,MeterSphere界面上至少是一点都没有,看不出来怎么触发。官方说法是可以通过jenkins插件触发</p> <blockquote> <p>在MeterSphere中,可通过<strong>Jenkins插件</strong>实现特定条件或操作触发自动化测试,具体方式如下:</p> <ol> <li><strong>Jenkins集成触发</strong> <ul> <li>安装MeterSphere Jenkins插件后,在Jenkins任务中添加MeterSphere构建环节。</li> <li>配置MeterSphere平台认证信息,选择指定项目下的接口测试用例。</li> <li>通过Jenkins的定时任务、代码提交触发(如GitLab Webhook)或手动执行等方式启动测试。</li> </ul> </li> <li><strong>关键组件协作</strong> <ul> <li><strong>Task Runner</strong>:统一调度接口测试任务。</li> <li><strong>Result Hub</strong>:处理测试执行结果。</li> <li><strong>Kafka</strong>:接收测试结果数据供后续分析。</li> </ul> </li> <li><strong>扩展触发方式</strong> <ul> <li>通过<strong>Chrome插件</strong>录制Web请求生成JMeter脚本并导入MeterSphere,结合CI/CD流程触发。</li> <li>使用<strong>IDEA插件</strong>同步接口定义,基于代码变更自动触发测试。</li> </ul> </li> </ol> <p>更多细节可参考架构图:<a href="https://metersphere.io/docs/v3.x/img/components.png">组件说明</a></p> </blockquote> <p>用例上没有很明显的自动化标签,估计要实测看结果了</p> <h3 id="qase">Qase</h3> <blockquote> <p>https://www.qase.io/</p> </blockquote> <p>弱智东西,非企业邮箱输入会提示错误,但是就是不告诉你错误原因,企业邮箱立马就成功</p> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260603194609911.png" alt="image-20260603194609871" /></p> <p>界面也还行,比较简单的,也算现代化的</p> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260603194812583.png" alt="image-20260603194812544" /></p> <p>Qase的测试内容的描述更符合我预期一些,自动化的标签是有的,不过似乎没有和需求挂钩的地方</p> <h3 id="agiletest">AgileTest</h3> <blockquote> <p>https://agiletest.app/</p> </blockquote> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260603201047036.png" alt="image-20260603201047001" /></p> <p>AgileTest的这个价格稍微有点低,一个人1.5刀,这不是把其他人架起来烤嘛,不过Agile 也是ATLASSIAN公司的,需要配合Jira一起用,这个有点麻烦,我没有Jira,只能放弃了</p> <h3 id="testiny">Testiny</h3> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260603201722902.png" alt="image-20260603201722835" /></p> <blockquote> <p>https://app.testiny.io/</p> </blockquote> <p>Testiny,没想到有国外的软件,中文适配的还行</p> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260603201927184.png" alt="image-20260603201927125" /></p> <p>也有类似的问题,缺少自动化的标签,自定义标签没看出来哪里能设置,感觉他是靠树形结构去做归类的</p> <p>Testiny的自动化也是通过接口来实现的,不过这里是把自动化的结果报告进行了同步收集,似乎并不能直接在Testiny这里直接触发自动化运行。</p> <h3 id="aqua">aqua</h3> <blockquote> <p>https://aqua-cloud.io/</p> </blockquote> <p>aqua的价格有点逆天,产品89欧/人,测试管理89欧/人,测试19欧/人,注册有点麻烦要国外手机验证,虽然我有,但是我懒得注册了</p> <h3 id="testmo">testmo</h3> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260603203806926.png" alt="image-20260603203806855" /></p> <blockquote> <p>https://www.testmo.com/</p> </blockquote> <p>testmo感觉还行,据说被testrail背后的公司收购了,然后一片唱衰,都说会被搞垮。</p> <p>看了一下基础用例管理方式依然是通过文件夹的形式进行分类的</p> <h3 id="qality-plus">QAlity Plus</h3> <blockquote> <p>https://soldevelo.com/products/test-management-for-jira/</p> </blockquote> <p>只适配Jira</p> <h3 id="excel">Excel</h3> <p>传统测试工具,Excel其实是能满足上面所有内容的,无论是和需求关联、分组、打标签、评审、自动化,它都可以,只是有点没系统,所有都是人工约定的,没有很强的模板约束,其数据本身的历史追溯有点困难,文件存储本身也需要解决。</p> <h3 id="其他">其他</h3> <p>其他类文本工具,比如notion、wolai、plane、各种智能表格等等,进行一定的改造也能满足测试的需求,就是有点不专业,很多流畅性的东西需要外部处理</p> <p>其他一体的平台也包含一部分测试平台的内容,只不过这里我们已经有了其他内容的补充,暂时不需要那么重的一个平台,单纯能管好测试用例就够了,其他Devops有其他工具做了。</p> <h2 id="summary">Summary</h2> <p>目前看下来MeterSphere可能是其中较为好用的,至于迁移成本,现在有AI干活的情况下,只需要你能把以前的数据导出来,那么这个成本就非常低,给好上下文背景,测试平台的接口或者模板格式给好,让AI把用例转移一下形式,其实非常容易,很简单就能迁移到新平台上</p> <p>测试管理平台还看到了一些别人的需求,这里还包含了普通的小白测试人员,对应的任务分配,时间管理等等也会被集成到这个管理平台上,相当于可以量化考核每个测试人员的工作量</p> <p>同时还有一个缺陷管理,测试出现的问题集中到缺陷中,但是大部分这个都做得比较弱,因为这个问题一般都需要挂到对应的任务管理系统中,比如Jira、Plane里面,这样好安排工作一些。</p> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260603204423841.png" alt="image-20260603204423812" /></p> <p>这个兄弟说得挺好的,测试是否需要管理工具,是否需要这么多细节流程来确认测试工作人员是否工作到位了,这个东西和产品的质量,成本需要找到一个平衡点,大多数公司都没有找到。挺无奈的,研发、测试一环扣着一环,都是对上一步结果的再次验证和纠正,只要有人在这里,只要你不是三体人,那表达一定会有出入,最终的路径一定要经过二次甚至三次验证才能出结果,这就无形中抬高了很多成本了。</p> <p>还有一种方式这个测试体系或者架构从一开始就是自己构建的,那么在这种情况下,结合一下AI,把excel表进行数据库化,然后加上一个前端作为展示和修改界面,其实就可以满足大多数测试的需求了,这个架构也不是很难,现在AI做其实很简单了。这种方式定制化程度很高,基本啥需求都可以自己搞定。</p> <h2 id="quote">Quote</h2> <blockquote> <p>google</p> <p>https://www.reddit.com/r/QualityAssurance/comments/197qvo7/thoughts_on_best_test_case_management_tool/?show=original</p> </blockquote>

2026/6/2
阅读更多

奥美品牌定位有感

<h2 id="foreword">Foreword</h2> <p>之前参与了一下奥美的品牌定位会议,感觉还挺有意思的,至少在做事的方法论上还是可以的,记录一下</p> <h2 id="ogilvy">Ogilvy</h2> <blockquote> <p>https://www.ogilvy.com/cn/</p> </blockquote> <p>奥美(Ogilvy)是全球知名的营销传播集团,1948 年由“广告教父”大卫·奥格威(David Ogilvy)在纽约创立。它以品牌战略、创意广告、公关与数字营销见长,长期服务跨国企业与本土头部品牌。如今奥美隶属于 WPP,属于典型的“全球方法论 + 本地执行”型咨询与传播公司。</p> <p>负责给我们上课的同时也是为华为品牌战略服务的负责人</p> <h4 id="第一课">第一课</h4> <p>第一课,说明品牌是什么,干什么,弄清品牌的定义。本质上就是在做小培训,先教会非品牌出身的人,让他们明白这是什么,而不要乱带节奏,不要自说自话。</p> <p>区分清楚老板、公司和公司品牌这几个概念,往往很多时候,都被混为一个,老板会觉得公司就是代表自己,很多品牌决策都过于主观,而没有遵守公司品牌、公司人格这个独立的东西。</p> <p>说是进了这门不区分上下级,但是出门都要工作、生活的,有些东西被刻进骨子里了,不是说可以就行的。</p> <p>第一课主要就是摸底,确认好公司内大家的诉求是什么,品牌的一些共性或者基础内容都有什么,然后说明要得到什么结论。</p> <p>比如,品牌短句,长句,愿景,使命,性格,logo,这几个最最基础的东西,而这些内容奥美本身已经有一个初步的定义了,毕竟是做过很多项目的,大概理解还是有的,只是对于领域内的一些细节可能了解不是很多。</p> <p>之后就是奥美,给出他们的一些想法,供我们参考。</p> <p>做的几个活动,主要靠策划人引导,然后将公司的人分几个组,不同组进行发表,虽然说这不是辩论会,不是比赛,但是人嘛,总是希望发表以后得到认同或者说同化他人。这个过程中,其实也是各种人被洗脑,被忽悠的一个过程,简短的几个概念词被反复提起、拆解、强调,不懂的人会被快速同化。</p> <p>无论是组内讨论还是组外讨论,每个组都安排了一个奥美的助手,并且全程录音,组内讨论后续也会被他们拿去分析,助手也会在组内引导大家的思考逻辑,纠正一些跑偏的讨论方向。</p> <p>总体来说:</p> <ul> <li> <p>求同存异,求最大公约数</p> </li> <li>结果可能是少数服从多数</li> <li>活动过程中允许你发表意见,说服他人,说白了会闹的孩子有奶吃,表现力强的人往往会影响其周边的人,进而成为一个共同体,导致组与组之间稍微有点点对立</li> </ul> <p>从培训形式来说挺好的,至少只要你主动,参与感是有的,但是如果你全程冷漠,那么这个事情就真的跟你没关系了</p> <h4 id="第二课">第二课</h4> <p>第一课的输出,奥美需要分析一段时间,然后第二课就是基于之前的结果进行总结,再给出几个选项,让所有人选。算是缩小了品牌定义的范围,在这里进行少数服从多数的投票了。</p> <p>这里其实还有一个隐含标准:不是只看谁说得好,而是看哪个表达更容易被用户理解、更容易在市场传播中复用。</p> <p>从结果来说,大家基本趋同了,总结出来的品牌短语、长句,基本一致了,只是略有偏差,这些后面定死就没啥问题了。</p> <p>还有一些细节,可以看,奥美在做分组的时候,是有特意安排过的,来平衡某种角色或者背景的人过于集中的问题</p> <p>第二课和第一课的分组又不相同,再次进行各人的意见融合</p> <p>不过对于企业人格,品质等方面的用语,明显意见差异特别大,最终得到的结论和我自己的也有差距,这里过于文学性,咬文嚼字了,带来的区别有点太小了。</p> <h2 id="方法论反思">方法论反思</h2> <p>奥美这套流程在“统一认知、快速收敛”上非常有效,尤其适合内部观点分散的团队。但它也有天然边界:当目标是找一个更激进、更差异化的品牌方向时,多数共识机制往往会把表达磨平,最后得到一个“大家都不反对,但也不够锋利”的答案。</p> <p>另外,活动结果会受到现场话语权影响。表达能力强的人更容易带节奏,谨慎或内向的人观点容易被淹没。为了避免这个问题,最好在讨论前加入匿名写卡、独立评分,再做集中讨论,这样结论会更接近真实共识,而不是现场情绪。</p> <p>最后,品牌定位的完成不等于品牌建设的完成。真正难的是把定位落实到产品叙事、销售话术、市场传播和组织行为里,并且在 3-6 个月里用线索质量、转化效率、用户心智反馈去验证。</p> <h4 id="落地清单">落地清单</h4> <p>如果只输出了一套品牌话术,而没有配套动作,最后大概率会变成 PPT 工程。至少要做下面几件事:</p> <ul> <li>产品侧:把品牌主张映射到产品功能命名、版本发布叙事、官网卖点排序</li> <li>销售侧:统一首句自我介绍(结合我自己碰到的销售,这个是有的)、行业方案开场、异议处理话术</li> <li>市场侧:统一公众号、官网、短视频、展会物料的表达口径</li> <li>组织侧:把品牌关键词写进招聘 JD、绩效沟通和新人培训材料</li> </ul> <p>这几项如果没有同步,品牌定位再好,传到市场端也会失真。</p> <h4 id="常见失败信号">常见失败信号</h4> <p>复盘下来,品牌定位项目最常见的失败,不是方向错,而是执行断层:</p> <ul> <li>内部会议里都认同,外部客户却听不懂</li> <li>对外说的是一套,对内做的是另一套</li> <li>每个部门都说“理解了”,但实际物料和话术各说各话</li> <li>三个月后没人再提这件事,品牌项目自然失效</li> </ul> <p>所以品牌定位不是“一次性决策”,更像是“持续校准机制”。如果没有持续复盘和纠偏,前面的共识很快就会被日常业务冲散。</p> <h2 id="summary">Summary</h2> <p>有些时候公司是技术主导的,导致很多东西过于偏向技术化了,而没有考虑到当前市场、普通人对于这些词汇或者概念的接受程度,这种情况就需要品牌引导,拉回来一些</p> <p>有时候公司领导过于固执,或者这个体系过于僵化,没有人可以成为破局者,此时就需要外部的人介入,从他们第三方的视角来看这些事情,从而推动变革,这也是为什么一些顾问公司能存在的价值吧</p>

2026/5/20
阅读更多

Gitlab制品库实践记录

<h2 id="foreword">Foreword</h2> <p>之前理解的制品库就是把CI的中间过程进行存储,虽然也包含了最终发布的部分,但是总觉得没啥大用,就没在意。后续发现其实从工程到生产环节有很多东西都需要进行交付,之前只关注了最核心的产品内容,周边一些零碎的东西,其实也需要被统一管理。而这个时候如果有很多个仓库需要一起进行打包、管理,这个就非常复杂了,而借助CI和制品库就可以通过规则把这部分内容统一管理起来,发布时进行大包发布即可,这些零碎的小工程也没有强耦合,可以随意发挥</p> <h2 id="背景">背景</h2> <p>生产时需要管理的不只是单个 <code class="language-plaintext highlighter-rouge">.bin</code>或者<code class="language-plaintext highlighter-rouge">.exe</code>,而是一套 <strong>已验证可一起上线</strong> 的产品组合:</p> <ul> <li>硬件烧录固件(SOC、MCU、FPGA等)</li> <li>测试治具固件</li> <li>其它治具与工具(RFID、MAC、IP、参数等配置工具)</li> </ul> <p>各组件由不同负责人维护、版本节奏不同,因此适合 <strong>GitLab 多仓库独立开发</strong>,再通过 <strong>manufacturing-kits + manifest</strong> 在发布时打成单一制造包,并自动生成与发布说明。</p> <h4 id="目标组件独立迭代方式">目标:组件独立迭代方式</h4> <pre><code class="language-mermaid">sequenceDiagram participant Dev as 组件负责人 participant Repo as 组件 GitLab 仓库 participant REL as Release 页面 Dev-&gt;&gt;Repo: MR 合并 / 本地构建 Dev-&gt;&gt;Repo: 打 tag,创建 Release Repo-&gt;&gt;REL: 上传附件 + 填写 Release Notes </code></pre> <p>理清思路:</p> <p>Gitlab 社区版没有制品库或者制品这个概念,但是我们可以通过Gitlab仓库本身的功能,建立一个制品仓库,把制品的manifest文件和对应的CI动作都集成在这个仓库里,需要发版的时候只需要触发这个仓库进行CI即可。</p> <p>而对于各个仓库来说,完全是不知道这个制品仓库的,从而实现解耦。</p> <h2 id="生产物料清单">生产物料清单</h2> <p>首先需要确认实际生产需要的物料清单,并以此为准进行模板制作和规则约束</p> <table> <thead> <tr> <th>分类</th> <th>组件 ID(建议)</th> <th>负责人</th> <th>是否必选</th> </tr> </thead> <tbody> <tr> <td>MCU烧录</td> <td><code class="language-plaintext highlighter-rouge">fc-mcu</code> 主控</td> <td>A</td> <td>必选</td> </tr> <tr> <td>SOC烧录</td> <td><code class="language-plaintext highlighter-rouge">fc-soc</code> 核心</td> <td>B</td> <td>可选</td> </tr> <tr> <td>测试治具</td> <td><code class="language-plaintext highlighter-rouge">fixture-mcu</code> MCU治具</td> <td>C</td> <td>必选</td> </tr> <tr> <td>测试治具</td> <td><code class="language-plaintext highlighter-rouge">fixture-soc</code> SOC治具</td> <td>A</td> <td>必选</td> </tr> <tr> <td>其它治具/配件</td> <td><code class="language-plaintext highlighter-rouge">rfid-fixture</code> RFID工具</td> <td>B</td> <td>可选</td> </tr> <tr> <td> </td> <td><code class="language-plaintext highlighter-rouge">mac-fixture</code> MAC工具</td> <td>C</td> <td>可选</td> </tr> <tr> <td> </td> <td><code class="language-plaintext highlighter-rouge">ip-fixture</code> IP工具</td> <td>A</td> <td>可选</td> </tr> </tbody> </table> <p>命名规则:<strong><code class="language-plaintext highlighter-rouge">{产品线}-{YY.M.D}</code></strong>,例如 <code class="language-plaintext highlighter-rouge">P1-26.5.20</code> → 对应 Git tag / Release 名。</p> <ul> <li>一般来说生产是按批或者订单进行的,只涉及到生产改动时这个进行改动即可</li> </ul> <h2 id="仓库结构">仓库结构</h2> <p>往往一个仓库可能要应对多种产线的情况,此时仓库保持独立,而不是submodule就很关键</p> <pre><code class="language-mermaid">flowchart TB subgraph component_repos [各组件独立 GitLab 项目] R1["fc-MCU-firmware"] R2["fc-SOC-firmware"] Rn["... 每个组件一个或一类一个"] end subgraph meta [发布与制造] MR["manufacturing-kits&lt;br/&gt;产品线 P1 / P2 ..."] DOC["自动生成 P1-26.5.20.md&lt;br/&gt;即治具更新内容"] end subgraph registry [制品] PKG["各组件 Release 附件"] end subgraph line [产线] OFF["脱机固件升级设备 / 工位"] LOG["生产追溯 DB 或 MES"] end R1 --&gt;|打 tag + Release 附件| PKG R2 --&gt; PKG MR --&gt;|读 manifest,从 Release API 拉附件| PKG MR --&gt;|打 Kit Release| PKG PKG --&gt; OFF OFF --&gt; LOG </code></pre> <p>可以看到这种情况下组合打包,本质上需要一个manifest,这个里面规定了打包的内容</p> <h3 id="仓库划分">仓库划分</h3> <p>建议仓库划分方式,但不是完全说死的</p> <table> <thead> <tr> <th>类型</th> <th>做法</th> </tr> </thead> <tbody> <tr> <td><strong>产品固件</strong></td> <td>一类一仓,如 <code class="language-plaintext highlighter-rouge">P1/fc-mcu-firmware</code>、<code class="language-plaintext highlighter-rouge">P1/fc-soc-firmware</code></td> </tr> <tr> <td><strong>治具固件</strong></td> <td>可合并为 <code class="language-plaintext highlighter-rouge">P1/fixture-firmware</code>(多 bin)或按治具拆分</td> </tr> <tr> <td><strong>工具</strong></td> <td><code class="language-plaintext highlighter-rouge">P1/ip-burn-tool</code> 等独立仓(版本节奏与固件不同)</td> </tr> <tr> <td><strong>制造包</strong></td> <td>一个产品线一个 meta 仓:<code class="language-plaintext highlighter-rouge">P1/manufacturing-kits</code>(<strong>无业务代码,只有 manifest + CI</strong>,也可以多产线一个仓库)</td> </tr> <tr> <td><strong>文档</strong></td> <td>治具更新 Markdown <strong>不手写维护</strong>,由 CI 从 manifest + 各组件 Release description 生成</td> </tr> </tbody> </table> <p>「如有」组件:manifest 里 <code class="language-plaintext highlighter-rouge">required: false</code>,未参与本次 Kit 则整段在生成文档里标 <strong>「本次未更新 / 沿用上一 Kit」</strong>。</p> <h2 id="manifest模板">manifest模板</h2> <p>在 <code class="language-plaintext highlighter-rouge">manufacturing-kits</code> 仓库中,每个 Kit 一个 YAML,与模板一一对应:</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># kits/P1-26.5.20.yaml</span> <span class="na">kit_id</span><span class="pi">:</span> <span class="s">P1-26.5.20</span> <span class="na">product_line</span><span class="pi">:</span> <span class="s">P1</span> <span class="na">release_date</span><span class="pi">:</span> <span class="s">2026-05-20</span> <span class="na">previous_kit</span><span class="pi">:</span> <span class="s">P1-26.4.12</span> <span class="c1"># 用于「相对上一正式版变更」</span> <span class="na">validated_by</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">A</span><span class="pi">,</span> <span class="nv">B</span><span class="pi">]</span> <span class="c1"># 集成测试通过签字(审批人)</span> <span class="na">offline_upgrader_min</span><span class="pi">:</span> <span class="s2">"</span><span class="s">2.1.0"</span> <span class="c1"># 升级设备最低版本(若有)</span> <span class="na">components</span><span class="pi">:</span> <span class="na">fc-mcu</span><span class="pi">:</span> <span class="na">release_tag</span><span class="pi">:</span> <span class="s">v123.123</span> <span class="c1"># 对应组件仓库 Releases 的 tag</span> <span class="na">artifact</span><span class="pi">:</span> <span class="s">fc-mcu-v123.123.bin</span> <span class="c1"># Release 附件名(需含后缀)</span> <span class="na">sha256</span><span class="pi">:</span> <span class="s2">"</span><span class="s">..."</span> <span class="na">required</span><span class="pi">:</span> <span class="no">true</span> <span class="na">fc-soc</span><span class="pi">:</span> <span class="na">release_tag</span><span class="pi">:</span> <span class="s">v45.6</span> <span class="na">artifact</span><span class="pi">:</span> <span class="s">fc-soc-v45.6.bin</span> <span class="na">required</span><span class="pi">:</span> <span class="no">false</span> <span class="c1"># 本次未改则可 omit 或 inherit_from: P1-26.4.12</span> <span class="na">fixture-mcu</span><span class="pi">:</span> <span class="na">release_tag</span><span class="pi">:</span> <span class="s">v2.0.1</span> <span class="na">artifact</span><span class="pi">:</span> <span class="s">fixture-mcu-v2.0.1.bin</span> <span class="na">required</span><span class="pi">:</span> <span class="no">true</span> <span class="c1"># ... 其余字段与模板章节同名</span> </code></pre></div></div> <p><strong>规则:</strong></p> <ul> <li>必选组件:Kit 发布前必须在 manifest 里 <strong>显式 <code class="language-plaintext highlighter-rouge">release_tag</code> + <code class="language-plaintext highlighter-rouge">artifact</code>,且组件仓库 Release 已存在</strong>。</li> <li>可选组件:未列则 CI 从 <code class="language-plaintext highlighter-rouge">previous_kit</code> <strong>继承</strong>上一版引用(文档里写清楚「沿用 P1-26.4.12 之 fc-soc v45.6」)。</li> <li>各组件仓库由 owner <strong>在 Release 页发布附件并填写说明</strong>;制品库 CI <strong>不编译</strong>,只从 Release 拉文件。</li> </ul> <h4 id="示例">示例</h4> <table> <thead> <tr> <th>模板字段</th> <th>来源</th> </tr> </thead> <tbody> <tr> <td>文件名 <code class="language-plaintext highlighter-rouge">P1-26.5.20</code></td> <td><code class="language-plaintext highlighter-rouge">kit_id</code></td> </tr> <tr> <td>版本:v123.123</td> <td>各组件 <code class="language-plaintext highlighter-rouge">release_tag</code></td> </tr> <tr> <td>固件文件:a.bin</td> <td><code class="language-plaintext highlighter-rouge">artifact</code>(Release 附件名,需与页面上名称一致)</td> </tr> <tr> <td>更新内容 1/2/3</td> <td>组件 Release <code class="language-plaintext highlighter-rouge">description</code>;或 manifest 手写 changelog</td> </tr> <tr> <td>@负责人</td> <td>manifest <code class="language-plaintext highlighter-rouge">owner</code> + GitLab CODEOWNERS</td> </tr> <tr> <td>「如有」</td> <td><code class="language-plaintext highlighter-rouge">required: false</code> + 继承策略</td> </tr> </tbody> </table> <p><strong>发布物目录示例(CI 打 zip):</strong></p> <div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>P1-26.5.20/ ├── MANIFEST.yaml # 机器读 ├── 治具更新内容-P1-26.5.20.md # 人类读,版式同现模板 ├── CHECKSUMS.sha256 ├── firmware/ │ ├── fc-mcu-v123.123.bin │ ├── fc-soc-v45.6.bin │ └── ... ├── fixture/ │ └── ... └── tools/ └── ip-burn-tool-... </code></pre></div></div> <p>产线 / 升级设备:只部署 <strong><code class="language-plaintext highlighter-rouge">kit_id</code> 对应 zip</strong>(或从内网按manifest 拉取)。</p> <p>各仓库的动作:</p> <table> <thead> <tr> <th>步骤</th> <th>动作</th> <th>角色</th> </tr> </thead> <tbody> <tr> <td>1</td> <td>在 <code class="language-plaintext highlighter-rouge">manufacturing-kits</code> 新建 <code class="language-plaintext highlighter-rouge">kits/P1-26.5.20.yaml</code>,填写各组件 <code class="language-plaintext highlighter-rouge">release_tag</code> 与 <code class="language-plaintext highlighter-rouge">artifact</code></td> <td>发布负责人(如A牵头)</td> </tr> <tr> <td>2</td> <td>开 MR → 触发 <strong>集成流水线</strong>:校验 Release 存在、拉取附件(若有自动化测试可在此跑)</td> <td>CI + 各 owner 审批</td> </tr> <tr> <td>3</td> <td>MR 合并 → tag <code class="language-plaintext highlighter-rouge">P1-26.5.20</code></td> <td>发布负责人</td> </tr> <tr> <td>4</td> <td>CI:生成 Markdown、打 zip、创建制品库自身 Release</td> <td>自动</td> </tr> <tr> <td>5</td> <td>通知生产:仅允许 <code class="language-plaintext highlighter-rouge">P1-26.5.20</code>;脱机设备刷入该包</td> <td>生产 / 工艺</td> </tr> <tr> <td>6</td> <td>每台(或每批)记录:<code class="language-plaintext highlighter-rouge">SN ↔ kit_id ↔ 时间 ↔ 工位</code></td> <td>生产 / MES</td> </tr> </tbody> </table> <h4 id="manufacturing-kits-仓库目录">manufacturing-kits 仓库目录</h4> <div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>manufacturing-kits/ ├── README.md ├── catalog/ │ ├── components.yaml ├── kits/ │ ├── P1-26.4.12.yaml │ └── P1-26.5.20.yaml ├── schema/ │ └── kit.schema.json # 校验 manifest 字段齐全 ├── templates/ │ └── 治具更新内容.md.j2 # Jinja2,版式与现模板一致 ├── ci/ │ ├── collect-artifacts.sh │ ├── generate-release-doc.py │ └── validate-kit.sh └── .gitlab-ci.yml </code></pre></div></div> <p><code class="language-plaintext highlighter-rouge">.gitlab-ci.yml</code> 阶段示意:</p> <ol> <li><code class="language-plaintext highlighter-rouge">validate</code>:schema + 检查各组件 Release 是否存在</li> <li><code class="language-plaintext highlighter-rouge">collect</code>:按 manifest 从各组件 Release API 下载附件</li> <li><code class="language-plaintext highlighter-rouge">document</code>:渲染 <code class="language-plaintext highlighter-rouge">更新内容-P1-26.5.20.md</code>(可合并 Release description)</li> <li><code class="language-plaintext highlighter-rouge">package</code>:zip + sha256</li> <li><code class="language-plaintext highlighter-rouge">release</code>:制品库打 Kit 的 GitLab Release</li> </ol> <p>注意<code class="language-plaintext highlighter-rouge">manufacturing-kits + manifest</code></p> <ul> <li>不是 GitLab 自带的产品功能,需要自建一个 GitLab 仓库 + 写一点 CI/脚本;GitLab 提供的是「存清单、跑流水线、存制品、发 Release、做审批」这些积木。</li> </ul> <h4 id="catalog">catalog</h4> <p><code class="language-plaintext highlighter-rouge">manufacturing-kits</code>的仓库里不仅仅要有各个kit的配置文件,由于各种代码仓库本质上是公用的,所以需要有一个目录层作为更上级,描述各个仓库的路径或者包名什么的,作为公共使用。</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># 组件 ID → GitLab 项目(仓库路径在 catalog,Kit 里只写 release_tag) fc-mcu: project_path: code/Firmware/fc-mcu project_id: 101 # 可选,API 用 id 更稳 artifact_type: bin default_artifact: fc-mcu.bin fc-soc: project_path: code/Firmware/fc-soc project_id: 102 default_artifact: fc-soc.bin ip-fixture: project_path: code/Facility/onion_ip project_id: 205 default_artifact: onion_ip.exe branch_is_product_line: true # Release tag 建议形如 X1/v1.0.0 fixture-mcu: project_path: code/Facility/fixture-mcu project_id: 210 default_artifact: fixture-mcu.bin </code></pre></div></div> <p>对应的CI程序就需要这么执行</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>读 Kit → 拿 fc-mcu 的 release_tag → 查 catalog 得 project_path=code/Firmware/fc-mcu → GET /projects/.../releases/{tag} → 按 artifact 名下载 assets.links </code></pre></div></div> <h4 id="制品模式">制品模式</h4> <p>有了上面内容以后,就可以给Cursor自动去完成制品库的文件编码了,但是第一次制品的流程,我发现有点问题。</p> <p>AI默认你的制品库的CI流程是从各个仓库拉代码,然后编译,产生目标文件,然后再打包。其实在生产这里稍微有点点不同,这里各个仓库本身可能不完善(涉及到n多个不同环境),甚至CI流程都不太行,所以这里优先直接拿release页面的文件,而不是把打包编译的流程全跑一遍。</p> <ul> <li>对应的release页面这里就需要对应的owner去手动发布,并且编辑更新的内容</li> </ul> <p>基于这个问题,又让AI改了一下制品库的模式</p> <h2 id="实际测试">实际测试</h2> <h4 id="runner">Runner</h4> <p>如果要用Gitlab的CI流水线,那么要先配置好 Runner。可以用 VPS,也可以在内网 Windows 机器上装(例如 <code class="language-plaintext highlighter-rouge">shell</code> executor + Git Bash),在 GitLab 项目里注册并授权即可</p> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260519190645301.png" alt="image-20260519170233610" /></p> <p>runner可以通过官网下载,然后配置</p> <blockquote> <p>https://docs.gitlab.com/runner/install/</p> </blockquote> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.\gitlab-runner.exe register --url https://gitlab.xxxx.com --token glrt-xxxx3d32-6LxN9 </code></pre></div></div> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260519190730092.png" alt="image-20260519172801808" /></p> <p>runner有一个小细节要注意一下,经常容易卡住流水线,无法正常跑下去</p> <blockquote> <p>你的 CI 里三个 job 都 没有 <code class="language-plaintext highlighter-rouge">tags:</code>,属于 untagged job。</p> <p>若 Runner 配置了标签(例如 <code class="language-plaintext highlighter-rouge">docker</code>、<code class="language-plaintext highlighter-rouge">build</code>),且 未勾选「运行未打标签的作业 / Run untagged jobs」,该 Runner 不会接这些 job,界面就会显示「没有可用 Runner」。</p> </blockquote> <p>建议最好不要在windows上跑runner,很多问题,cmd在最新的runner上不能用,powershell也会有一堆问题(最好用pwsh),建议换成git bash来跑</p> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260519190736505.png" alt="image-20260519190616223" /></p> <p>Job运行时需要访问到各种项目的页面,对应的这些项目就得授权过去,可以在CI/CD的Job token中进行设置</p> <h4 id="release">Release</h4> <p>调试了老半天,流程总是走不通,不是这有问题,就是那有问题。</p> <ul> <li>沙雕AI打zip包,他打个tar包改名叫zip,后续流程中验证zip包,怎么验都错,但是我自己用zip解压可以正常打开,查半天</li> </ul> <p>后续仔细看了一下发现是Gitlab的一点小问题,AI自己根本搞不明白为什么</p> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260519212352544.png" alt="image-20260519212352512" /></p> <p>这个Release中软件包是只有名称,没有后缀的</p> <p><img src="https://img.elmagnifico.tech/static/upload/elmagnifico/20260519212405683.png" alt="image-20260519212405659" /></p> <p>而CI文件里写的是需要后缀来识别的,那么一旦子仓库的发布内容不包含这个后缀,那么对应的制品库就无法正常跑下去,这个破问题弄半天,AI自己把自己绕进去了。</p> <p>除了这个问题,Gitlab还有一点不如Github,发布页面不能直接引用仓库内的文件,不能直接添加资源,不能直接上传,这就导致你要把发布页面包含仓库内的东西就必须走Gitlab CI或者是手写一个脚本利用API来上传文件,然后这里还有坑点。这个你后上传的文件,是有权限的,走CI的那个流水线似乎没权限,访问不到这个链接,而要解决这个问题就还得给CI的脚本配上 owner 的 token,一环扣一环。</p> <ul> <li> <p>实际上如果走Gitlab内部的上传库,runner是可以正常访问的,生成物也是能正常访问的</p> </li> <li> <p>Gitlab的Release只愿意做一个纯链接页面,而没有一个实体存储的对象</p> </li> </ul> <h4 id="子库ci不编译">子库CI不编译</h4> <p>现在最好的解决办法就是子仓库用Gitlab的CI,但是不编译,仅仅做打包和发布,编译的内容在仓库内建立一个Release文件夹,把每次发布的文件存储到这个里面,由Gitlab CI进行打包和发布即可</p> <p>制品库环节就和上面说的流程一样走即可</p> <h2 id="summary">Summary</h2> <p>所以如果要走Gitlab,那么就得全流程最好都走,想中间偷个懒或者不走Gitlab要解决的问题就有点多了。</p> <h2 id="quote">Quote</h2> <blockquote> <p>Cursor</p> </blockquote>

2026/5/19
阅读更多