<?xml version="1.0" encoding="UTF-8"?><rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title>掘金本周最热</title><link>https://juejin.im/recommended?sort=weekly_hottest</link><atom:link href="http://rsshub.umzzz.com/juejin/trending/all/weekly" rel="self" type="application/rss+xml"></atom:link><description>掘金本周最热 - Powered by RSSHub</description><generator>RSSHub</generator><webMaster>contact@rsshub.app (RSSHub)</webMaster><language>en</language><lastBuildDate>Thu, 28 May 2026 06:05:55 GMT</lastBuildDate><ttl>5</ttl><item><title>【SpringBoot 3.x 第254节】夯爆了，数据库访问性能优化实战详解！</title><description>&lt;div align=&quot;center&quot;&gt; &lt;img width=&quot;1000&quot; src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/92d4d0d881da4a9590b782ee6fd946dc~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgYnVn6I-M:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780480696&amp;amp;x-signature=1q3puBZP0D7kE2Nvb7kC7SYAqGY%3D&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt; &lt;/div&gt;
&lt;blockquote&gt;
&lt;p&gt;🏆 本文收录于 &lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fblog.csdn.net%2Fweixin_43970743%2Fcategory_12795608.html&quot; target=&quot;_blank&quot; title=&quot;https://blog.csdn.net/weixin_43970743/category_12795608.html&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;《滚雪球学 Spring Boot 3.x》&lt;/a&gt; 专栏，&lt;strong&gt;专注 Spring Boot 3.x 系统学习与实战进阶，内容持续更新中。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;本专栏致力于打造高质量、体系化的 Spring Boot 3.x 学习路线，从零基础入门到进阶实战，帮助你快速掌握核心知识与企业级开发经验。
 
📌 想快速定位学习内容，可查看：&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fblog.csdn.net%2Fweixin_43970743%2Farticle%2Fdetails%2F151115907&quot; target=&quot;_blank&quot; title=&quot;https://blog.csdn.net/weixin_43970743/article/details/151115907&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;【Spring Boot 3 教程导航帖】&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;🎉 &lt;strong&gt;当前专栏限时优惠中：一次订阅，终身阅读，后续更新章节全部免费解锁&lt;/strong&gt; 👉 &lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fblog.csdn.net%2Fweixin_43970743%2Fcategory_12795608.html&quot; target=&quot;_blank&quot; title=&quot;https://blog.csdn.net/weixin_43970743/category_12795608.html&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;立即订阅&lt;/a&gt; 👈️
 
🎁 想系统打通 Spring Boot 各主流版本？还可以查看：
👉 &lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fblog.csdn.net%2Fweixin_43970743%2Fcategory_11599389.html&quot; target=&quot;_blank&quot; title=&quot;https://blog.csdn.net/weixin_43970743/category_11599389.html&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;《Spring Boot 2.x 实战》&lt;/a&gt;
👉 &lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fblog.csdn.net%2Fweixin_43970743%2Fcategory_12795608.html&quot; target=&quot;_blank&quot; title=&quot;https://blog.csdn.net/weixin_43970743/category_12795608.html&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;《Spring Boot 3.x 实战》&lt;/a&gt;
👉 &lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fblog.csdn.net%2Fweixin_43970743%2Fcategory_13167695.html&quot; target=&quot;_blank&quot; title=&quot;https://blog.csdn.net/weixin_43970743/category_13167695.html&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;《Spring Boot 4.x 实战》&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;🚀 推荐合集：&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fblog.csdn.net%2Fweixin_43970743%2Fcategory_11599389.html&quot; target=&quot;_blank&quot; title=&quot;https://blog.csdn.net/weixin_43970743/category_11599389.html&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;《Spring Boot 全栈实战合集》&lt;/a&gt;，一站式覆盖 Spring Boot 2.x、3.x、4.x 核心特性、项目实战与架构进阶内容。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;演示环境说明：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;开发工具：IDEA 2021.3&lt;/li&gt;
&lt;li&gt;JDK版本： JDK 17（推荐使用 JDK 17 或更高版本，因为 Spring Boot 3.x 系列要求 Java 17，Spring Boot 3.5.4 基于 Spring Framework 6.x 和 Jakarta EE 9，它们都要求至少 JDK 17。）&lt;/li&gt;
&lt;li&gt;Spring Boot版本：3.5.4（于25年7月24日发布）&lt;/li&gt;
&lt;li&gt;Maven版本：3.8.2 （或更高）&lt;/li&gt;
&lt;li&gt;Gradle：（如果使用 Gradle 构建工具的话）：推荐使用 Gradle 7.5 或更高版本，确保与 JDK 17 兼容。&lt;/li&gt;
&lt;li&gt;操作系统：Windows 11&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h2 data-id=&quot;heading-0&quot;&gt;1. 为什么数据库访问性能会成为系统瓶颈？&lt;/h2&gt;
&lt;p&gt;在大多数业务系统中，数据库访问几乎一定会出现在性能链路的中心位置。很多初学者在写 Spring Boot 应用时，往往把注意力集中在 Controller 是否能正常返回、Service 是否能完成业务逻辑，却忽视了最容易被放大的问题：数据库访问次数过多、单次 SQL 过慢、索引不合理、连接池配置不当、ORM 自动生成了低效 SQL。&lt;/p&gt;
&lt;p&gt;数据库性能问题有一个典型特征：它不一定在功能上线当天就暴露出来，而是在数据量增长、并发升高、业务链路变长之后，逐步演化为“偶发卡顿”“接口超时”“线程堆积”“数据库 CPU 飙高”等症状。此时，系统表面看起来像是“Java 代码慢”，实际上往往是数据库访问策略出了问题。&lt;/p&gt;
&lt;p&gt;在 Spring Boot 3.x 中，数据库访问方式非常灵活。你可以使用 JDBC、JdbcTemplate、Spring Data JPA、MyBatis，甚至是 R2DBC。不同方案有不同的抽象层级，但本质都绕不开同一个问题：如何让数据访问更高效、更稳定、更可观测。&lt;/p&gt;
&lt;p&gt;如果把数据库访问优化比作一条链路，那么链路上至少有四个关键节点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据结构设计：索引、字段类型、范式与反范式&lt;/li&gt;
&lt;li&gt;SQL 设计：查询条件、排序、分页、聚合、更新方式&lt;/li&gt;
&lt;li&gt;连接与并发：连接池、事务、锁、线程调度&lt;/li&gt;
&lt;li&gt;应用层组织：ORM 生成 SQL、缓存、批处理、异步化&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;任何一个节点失衡，都可能拖垮整体性能。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-1&quot;&gt;2. Spring Boot 3.x 视角下的数据库访问栈&lt;/h2&gt;
&lt;p&gt;Spring Boot 3.x 带来的变化，不只是版本号升级，更重要的是基础生态的现代化：JDK 17 起步、Jakarta 命名空间迁移、对现代 observability 的更好支持，以及与 Hibernate 6、Spring Data 3 的适配。&lt;/p&gt;
&lt;p&gt;从数据库访问的角度看，一个典型的 Spring Boot 3.x 应用通常会经过如下链路：&lt;/p&gt;
&lt;p&gt;示意图绘制如下，仅供参考：&lt;/p&gt;
&lt;div align=&quot;center&quot;&gt; &lt;img width=&quot;400&quot; src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/34cc153df478468286415f2e83d64a87~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgYnVn6I-M:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780480696&amp;amp;x-signature=KKfuPFj5sf7XcpAAZSa5sFj79vo%3D&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt; &lt;/div&gt;
&lt;p&gt;这里面最容易出问题的地方有三个：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Repository 层隐藏了 SQL 复杂度，开发者容易忽略真实执行语句。&lt;/li&gt;
&lt;li&gt;连接池把“连接创建成本”隐藏起来，开发者容易误以为连接是免费的。&lt;/li&gt;
&lt;li&gt;ORM 将对象世界映射到关系世界时，可能产生额外查询、N+1、隐式 join、分页偏差等问题。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在 Spring Boot 3.x 中，推荐你建立一种思维：&lt;strong&gt;不要只看“代码写得简洁不简洁”，更要看“最终执行的 SQL 是否合理”&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-2&quot;&gt;3. 性能优化的总原则：先定位，再改造，再验证&lt;/h2&gt;
&lt;p&gt;数据库访问优化不是“经验主义艺术”，而是一个可重复的工程过程。最佳实践通常遵循下面这条主线：&lt;/p&gt;
&lt;p&gt;示意图绘制如下，仅供参考：&lt;/p&gt;
&lt;div align=&quot;center&quot;&gt; &lt;img width=&quot;1000&quot; src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/3fc79ba3c73e4c659304f0398adc0e98~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgYnVn6I-M:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780480696&amp;amp;x-signature=x%2BYKtICr2P1j8uv%2BX1Z4%2Bkl02fg%3D&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt; &lt;/div&gt;
&lt;p&gt;这条链路强调两个关键事实：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;你不能凭感觉改 SQL，必须看执行计划、扫描行数、实际耗时。&lt;/li&gt;
&lt;li&gt;你不能只优化数据库，还要回到 Java 代码，确认是不是 ORM 或调用方式导致的低效访问。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;很多优化失败，都是因为直接跳到了“加索引”这一步。事实上，索引只是优化手段之一，不是万能钥匙。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-3&quot;&gt;4. 索引优化：从“能查到”到“查得快”&lt;/h2&gt;
&lt;h3 data-id=&quot;heading-4&quot;&gt;4.1 索引是什么&lt;/h3&gt;
&lt;p&gt;索引本质上是一种加速查找的数据结构。对于关系型数据库来说，常见的是 B+ 树索引。你可以把索引理解为一本书的目录：没有目录，想找某一页内容只能从头翻；有目录，就能快速定位。&lt;/p&gt;
&lt;p&gt;但索引不是免费午餐。索引会占用存储空间，也会降低写入性能，因为每次插入、更新、删除，数据库都要维护索引结构。&lt;/p&gt;
&lt;p&gt;因此，索引优化的第一原则不是“多建几个”，而是“建对、用对、少而精”。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-5&quot;&gt;4.2 适合建立索引的字段&lt;/h3&gt;
&lt;p&gt;通常来说，以下字段很适合建索引：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;经常出现在 WHERE 条件中的字段&lt;/li&gt;
&lt;li&gt;经常出现在 JOIN 条件中的字段&lt;/li&gt;
&lt;li&gt;经常出现在 ORDER BY 中的字段&lt;/li&gt;
&lt;li&gt;经常出现在 GROUP BY 中且基数较高的字段&lt;/li&gt;
&lt;li&gt;业务上需要唯一性的字段，例如手机号、订单号、用户名&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-id=&quot;heading-6&quot;&gt;4.3 不适合滥用索引的场景&lt;/h3&gt;
&lt;p&gt;以下场景通常不建议盲目加索引：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;字段区分度太低，例如性别、状态位&lt;/li&gt;
&lt;li&gt;查询数据量本身很小&lt;/li&gt;
&lt;li&gt;写入非常频繁而查询较少&lt;/li&gt;
&lt;li&gt;条件上大量使用函数、模糊前缀、隐式类型转换&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;例如下面这条 SQL 看起来没问题，但其实可能无法有效使用索引：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-sql&quot; lang=&quot;sql&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;*&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;FROM&lt;/span&gt; user_account
&lt;span class=&quot;hljs-keyword&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;DATE&lt;/span&gt;(create_time) &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&#39;2026-04-15&#39;&lt;/span&gt;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;原因是对字段做了函数运算，数据库很可能无法直接利用 create_time 上的索引。&lt;/p&gt;
&lt;p&gt;更好的写法是：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-sql&quot; lang=&quot;sql&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;*&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;FROM&lt;/span&gt; user_account
&lt;span class=&quot;hljs-keyword&quot;&gt;WHERE&lt;/span&gt; create_time &lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&#39;2026-04-15 00:00:00&#39;&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;AND&lt;/span&gt; create_time &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt;  &lt;span class=&quot;hljs-string&quot;&gt;&#39;2026-04-16 00:00:00&#39;&lt;/span&gt;;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-id=&quot;heading-7&quot;&gt;4.4 联合索引的使用顺序&lt;/h3&gt;
&lt;p&gt;联合索引不是多个单列索引的简单叠加。它遵循最左前缀原则。比如有这样一个索引：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-sql&quot; lang=&quot;sql&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;CREATE&lt;/span&gt; INDEX idx_order_user_status_time &lt;span class=&quot;hljs-keyword&quot;&gt;ON&lt;/span&gt; t_order(user_id, status, create_time);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;那么下面这些查询通常更容易利用索引：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-sql&quot; lang=&quot;sql&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;FROM&lt;/span&gt; t_order &lt;span class=&quot;hljs-keyword&quot;&gt;WHERE&lt;/span&gt; user_id &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; ?;
&lt;span class=&quot;hljs-keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;FROM&lt;/span&gt; t_order &lt;span class=&quot;hljs-keyword&quot;&gt;WHERE&lt;/span&gt; user_id &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; ? &lt;span class=&quot;hljs-keyword&quot;&gt;AND&lt;/span&gt; status &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; ?;
&lt;span class=&quot;hljs-keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;FROM&lt;/span&gt; t_order &lt;span class=&quot;hljs-keyword&quot;&gt;WHERE&lt;/span&gt; user_id &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; ? &lt;span class=&quot;hljs-keyword&quot;&gt;AND&lt;/span&gt; status &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; ? &lt;span class=&quot;hljs-keyword&quot;&gt;AND&lt;/span&gt; create_time &lt;span class=&quot;hljs-operator&quot;&gt;&amp;gt;=&lt;/span&gt; ?;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但如果你只写：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-sql&quot; lang=&quot;sql&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;FROM&lt;/span&gt; t_order &lt;span class=&quot;hljs-keyword&quot;&gt;WHERE&lt;/span&gt; status &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; ?;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就可能无法充分利用这个联合索引。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-8&quot;&gt;4.5 覆盖索引与回表&lt;/h3&gt;
&lt;p&gt;如果查询所需字段都包含在索引里，数据库可能只扫描索引，不必再回表读取整行数据，这就是覆盖索引。覆盖索引在高并发读场景下非常重要。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-sql&quot; lang=&quot;sql&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;SELECT&lt;/span&gt; user_id, status, create_time
&lt;span class=&quot;hljs-keyword&quot;&gt;FROM&lt;/span&gt; t_order
&lt;span class=&quot;hljs-keyword&quot;&gt;WHERE&lt;/span&gt; user_id &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; ?
  &lt;span class=&quot;hljs-keyword&quot;&gt;AND&lt;/span&gt; status &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; ?;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果联合索引恰好包含这些列，那么数据库可能直接通过索引返回结果，减少一次回表访问。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-9&quot;&gt;4.6 索引优化的 Java 侧案例&lt;/h3&gt;
&lt;p&gt;下面这个 Repository 代码看似简单，但背后决定了是否能吃到索引红利。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-java&quot; lang=&quot;java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.example.demo.repository;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.example.demo.entity.OrderEntity;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.data.jpa.repository.JpaRepository;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.data.jpa.repository.Query;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.data.repository.query.Param;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.time.LocalDateTime;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.List;

&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;OrderRepository&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;JpaRepository&lt;/span&gt;&amp;lt;OrderEntity, Long&amp;gt; {

    &lt;span class=&quot;hljs-comment&quot;&gt;// 通过用户ID、状态和时间范围查询订单&lt;/span&gt;
    &lt;span class=&quot;hljs-comment&quot;&gt;// 该查询更容易命中 (user_id, status, create_time) 联合索引&lt;/span&gt;
    &lt;span class=&quot;hljs-meta&quot;&gt;@Query(&quot;select o from OrderEntity o where o.userId = :userId and o.status = :status and o.createTime between :startTime and :endTime&quot;)&lt;/span&gt;
    List&amp;lt;OrderEntity&amp;gt; &lt;span class=&quot;hljs-title function_&quot;&gt;findByUserIdAndStatusAndCreateTimeBetween&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(
            &lt;span class=&quot;hljs-meta&quot;&gt;@Param(&quot;userId&quot;)&lt;/span&gt; Long userId,
            &lt;span class=&quot;hljs-meta&quot;&gt;@Param(&quot;status&quot;)&lt;/span&gt; Integer status,
            &lt;span class=&quot;hljs-meta&quot;&gt;@Param(&quot;startTime&quot;)&lt;/span&gt; LocalDateTime startTime,
            &lt;span class=&quot;hljs-meta&quot;&gt;@Param(&quot;endTime&quot;)&lt;/span&gt; LocalDateTime endTime)&lt;/span&gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这段代码表面上是 JPA 查询，实际上是否高效，取决于底层表结构和索引设计。你必须在表层做配合，而不是指望 ORM 自动解决一切。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-10&quot;&gt;4.7 索引设计的实战建议&lt;/h3&gt;
&lt;p&gt;你可以按以下顺序思考：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;先看查询模式，再看表结构。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;按高频过滤条件设计联合索引。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;把区分度高的字段尽量放在索引前部。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;避免在索引列上进行函数、计算、隐式转换。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;关注是否能形成覆盖索引。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;用 EXPLAIN 验证，不要凭感觉。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-id=&quot;heading-11&quot;&gt;5. 批量操作：从单条写入到吞吐提升&lt;/h2&gt;
&lt;h3 data-id=&quot;heading-12&quot;&gt;5.1 单条写入为什么慢&lt;/h3&gt;
&lt;p&gt;很多新手会写出这样的代码：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-java&quot; lang=&quot;java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (OrderEntity order : orders) {
    orderRepository.save(order);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这段代码的问题在于：每次 save 都可能触发一次数据库交互。如果数据量稍大，就会出现明显的性能瓶颈。&lt;/p&gt;
&lt;p&gt;单条写入的成本主要包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Java 方法调用成本&lt;/li&gt;
&lt;li&gt;ORM 状态管理成本&lt;/li&gt;
&lt;li&gt;SQL 发送成本&lt;/li&gt;
&lt;li&gt;网络往返成本&lt;/li&gt;
&lt;li&gt;数据库解析与执行成本&lt;/li&gt;
&lt;li&gt;事务提交成本&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当这些成本乘以成百上千条数据时，整体耗时会非常可观。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-13&quot;&gt;5.2 批量写入的核心价值&lt;/h3&gt;
&lt;p&gt;批量写入的价值不只是“少发几条 SQL”，更重要的是减少网络往返、减少事务提交次数、降低数据库解析压力。&lt;/p&gt;
&lt;p&gt;批量操作通常有两类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;批量插入&lt;/li&gt;
&lt;li&gt;批量更新&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-id=&quot;heading-14&quot;&gt;5.3 JPA 批量插入示例&lt;/h3&gt;
&lt;p&gt;JPA 并不是天然高性能批量工具。若使用不当，&lt;code&gt;saveAll&lt;/code&gt; 也未必真的批量。&lt;/p&gt;
&lt;p&gt;下面给出一个适合批量插入的 Service 示例：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-java&quot; lang=&quot;java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.example.demo.service;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.example.demo.entity.OrderEntity;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.example.demo.repository.OrderRepository;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; jakarta.persistence.EntityManager;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; jakarta.persistence.PersistenceContext;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.stereotype.Service;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.transaction.annotation.Transactional;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.List;

&lt;span class=&quot;hljs-meta&quot;&gt;@Service&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;OrderBatchService&lt;/span&gt; {

    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;final&lt;/span&gt; OrderRepository orderRepository;

    &lt;span class=&quot;hljs-meta&quot;&gt;@PersistenceContext&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; EntityManager entityManager;

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;OrderBatchService&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(OrderRepository orderRepository)&lt;/span&gt; {
        &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.orderRepository = orderRepository;
    }

    &lt;span class=&quot;hljs-meta&quot;&gt;@Transactional&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;batchInsert&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(List&amp;lt;OrderEntity&amp;gt; orders)&lt;/span&gt; {
        &lt;span class=&quot;hljs-comment&quot;&gt;// 分批处理，避免一次性持有过多持久化上下文对象&lt;/span&gt;
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;batchSize&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;50&lt;/span&gt;;
        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; orders.size(); i++) {
            orderRepository.save(orders.get(i));

            &lt;span class=&quot;hljs-comment&quot;&gt;// 每批提交前刷新并清空，释放一部分内存压力&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (i &amp;gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &amp;amp;&amp;amp; i % batchSize == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;) {
                entityManager.flush();
                entityManager.clear();
            }
        }

        &lt;span class=&quot;hljs-comment&quot;&gt;// 处理剩余数据&lt;/span&gt;
        entityManager.flush();
        entityManager.clear();
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-id=&quot;heading-15&quot;&gt;5.4 为什么要 flush 和 clear&lt;/h3&gt;
&lt;p&gt;JPA 在持久化时会把实体放入一级缓存，也就是持久化上下文。如果你一次性插入大量数据，不及时 flush 和 clear，就会导致内存占用不断上升，同时脏检查成本也会增加。&lt;/p&gt;
&lt;p&gt;因此，批量处理常见的写法是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每 50 条 flush 一次&lt;/li&gt;
&lt;li&gt;每 50 条 clear 一次&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这个数字不是绝对值，需要结合业务和数据库压力测试调整。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-16&quot;&gt;5.5 原生 JDBC 批处理示例&lt;/h3&gt;
&lt;p&gt;在强吞吐场景下，JDBC 批处理往往比 JPA 更直接、更可控。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-java&quot; lang=&quot;java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.example.demo.service;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.jdbc.core.JdbcTemplate;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.stereotype.Service;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.transaction.annotation.Transactional;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.List;

&lt;span class=&quot;hljs-meta&quot;&gt;@Service&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;OrderJdbcBatchService&lt;/span&gt; {

    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;final&lt;/span&gt; JdbcTemplate jdbcTemplate;

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;OrderJdbcBatchService&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(JdbcTemplate jdbcTemplate)&lt;/span&gt; {
        &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.jdbcTemplate = jdbcTemplate;
    }

    &lt;span class=&quot;hljs-meta&quot;&gt;@Transactional&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;batchInsert&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(List&amp;lt;OrderInput&amp;gt; inputs)&lt;/span&gt; {
        &lt;span class=&quot;hljs-type&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;sql&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;INSERT INTO t_order(user_id, order_no, status, create_time) VALUES (?, ?, ?, ?)&quot;&lt;/span&gt;;

        &lt;span class=&quot;hljs-comment&quot;&gt;// 使用 JDBC 的 batchUpdate 进行批量插入&lt;/span&gt;
        jdbcTemplate.batchUpdate(sql, inputs, &lt;span class=&quot;hljs-number&quot;&gt;100&lt;/span&gt;, (ps, item) -&amp;gt; {
            ps.setLong(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, item.getUserId());
            ps.setString(&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;, item.getOrderNo());
            ps.setInt(&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;, item.getStatus());
            ps.setTimestamp(&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;, java.sql.Timestamp.valueOf(item.getCreateTime()));
        });
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这类写法的优点是明确、可控，缺点是业务代码和 SQL 耦合更高。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-17&quot;&gt;5.6 批量更新的注意点&lt;/h3&gt;
&lt;p&gt;批量更新比批量插入更容易出问题，因为更新通常伴随着条件、锁、版本号控制和业务状态流转。&lt;/p&gt;
&lt;p&gt;建议注意以下几点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;避免逐条 update&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;尽量合并同类条件&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;注意事务范围不要过大&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在高并发下考虑乐观锁&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;必要时拆批，防止长事务&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-id=&quot;heading-18&quot;&gt;6. 连接池：HikariCP 的核心参数与调优思路&lt;/h2&gt;
&lt;h3 data-id=&quot;heading-19&quot;&gt;6.1 为什么需要连接池&lt;/h3&gt;
&lt;p&gt;数据库连接不是轻量对象。每次创建连接都要经过认证、握手、初始化等流程，开销很高。连接池的作用就是复用连接，减少频繁创建和销毁的成本。&lt;/p&gt;
&lt;p&gt;Spring Boot 3.x 默认使用 HikariCP，这是一款性能和稳定性都很出色的连接池。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-20&quot;&gt;6.2 连接池优化的基本思维&lt;/h3&gt;
&lt;p&gt;连接池调优不是“把最大连接数调到很大”这么简单。连接池参数要和数据库最大连接数、CPU 核数、应用并发、SQL 耗时共同决定。&lt;/p&gt;
&lt;p&gt;连接池太小：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;请求拿不到连接&lt;/li&gt;
&lt;li&gt;应用线程阻塞&lt;/li&gt;
&lt;li&gt;接口响应时间变长&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;连接池太大：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据库压力增大&lt;/li&gt;
&lt;li&gt;争抢严重&lt;/li&gt;
&lt;li&gt;上下文切换增多&lt;/li&gt;
&lt;li&gt;可能出现“连接很多但吞吐没上去”&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-id=&quot;heading-21&quot;&gt;6.3 Spring Boot 3.x 中的 Hikari 配置&lt;/h3&gt;
&lt;p&gt;下面是一个典型配置示例：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-yaml&quot; lang=&quot;yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spring:&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;datasource:&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;url:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;jdbc:mysql://localhost:3306/demo?useSSL=false&amp;amp;serverTimezone=Asia/Shanghai&amp;amp;characterEncoding=utf8&amp;amp;rewriteBatchedStatements=true&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;username:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;root&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;password:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;root&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;driver-class-name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;com.mysql.cj.jdbc.Driver&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;hikari:&lt;/span&gt;
      &lt;span class=&quot;hljs-attr&quot;&gt;maximum-pool-size:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;
      &lt;span class=&quot;hljs-attr&quot;&gt;minimum-idle:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;
      &lt;span class=&quot;hljs-attr&quot;&gt;connection-timeout:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;30000&lt;/span&gt;
      &lt;span class=&quot;hljs-attr&quot;&gt;idle-timeout:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;600000&lt;/span&gt;
      &lt;span class=&quot;hljs-attr&quot;&gt;max-lifetime:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1800000&lt;/span&gt;
      &lt;span class=&quot;hljs-attr&quot;&gt;leak-detection-threshold:&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;2000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-id=&quot;heading-22&quot;&gt;6.4 参数解读&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;maximum-pool-size&lt;/code&gt;：最大连接数，决定峰值时最多多少连接并发访问数据库。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;minimum-idle&lt;/code&gt;：最小空闲连接数，保证预热和快速响应。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;connection-timeout&lt;/code&gt;：拿连接的超时时间，太短会导致正常高峰也失败，太长会掩盖问题。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;idle-timeout&lt;/code&gt;：空闲连接回收时间。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;max-lifetime&lt;/code&gt;：连接最大生命周期，避免连接长期存在导致数据库侧断开。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;leak-detection-threshold&lt;/code&gt;：连接泄漏检测阈值，排查忘记关闭连接非常有帮助。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-id=&quot;heading-23&quot;&gt;6.5 如何判断连接池是否合理&lt;/h3&gt;
&lt;p&gt;你不能只看“连接池跑起来了”，还要看是否出现以下信号：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;等待连接时间偏高&lt;/li&gt;
&lt;li&gt;活跃连接长期接近上限&lt;/li&gt;
&lt;li&gt;数据库 CPU 高但 TPS 没上去&lt;/li&gt;
&lt;li&gt;业务线程被卡在获取连接阶段&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在生产环境里，连接池问题常常不是根因，而是结果。真正根因往往是 SQL 太慢、事务太长、索引不合理。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-24&quot;&gt;7. SQL 优化联动：索引、执行计划、分页、排序、回表&lt;/h2&gt;
&lt;h3 data-id=&quot;heading-25&quot;&gt;7.1 SQL 优化的基本原则&lt;/h3&gt;
&lt;p&gt;SQL 优化不是“改几个关键字”就能解决，它通常与索引策略深度绑定。最有效的原则有以下几个：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;让条件尽量可索引化&lt;/li&gt;
&lt;li&gt;减少全表扫描&lt;/li&gt;
&lt;li&gt;减少返回列数&lt;/li&gt;
&lt;li&gt;避免无意义排序&lt;/li&gt;
&lt;li&gt;控制分页偏移&lt;/li&gt;
&lt;li&gt;减少回表次数&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-id=&quot;heading-26&quot;&gt;7.2 SELECT * 的问题&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;SELECT *&lt;/code&gt; 在开发阶段很方便，但在生产系统中经常带来副作用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;传输冗余字段，浪费网络带宽&lt;/li&gt;
&lt;li&gt;取回不必要的大字段，例如 JSON、TEXT、BLOB&lt;/li&gt;
&lt;li&gt;破坏覆盖索引的可能性&lt;/li&gt;
&lt;li&gt;增加对象映射成本&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;建议只查询需要的字段。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-27&quot;&gt;7.3 大分页问题&lt;/h3&gt;
&lt;p&gt;下面这个分页查询在数据量很大时会越来越慢：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-sql&quot; lang=&quot;sql&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;SELECT&lt;/span&gt; id, user_id, order_no, status, create_time
&lt;span class=&quot;hljs-keyword&quot;&gt;FROM&lt;/span&gt; t_order
&lt;span class=&quot;hljs-keyword&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;BY&lt;/span&gt; create_time &lt;span class=&quot;hljs-keyword&quot;&gt;DESC&lt;/span&gt;
LIMIT &lt;span class=&quot;hljs-number&quot;&gt;100000&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;原因是数据库需要先跳过前 100000 条，再返回 20 条。偏移越大，成本越高。&lt;/p&gt;
&lt;p&gt;更好的方案是基于游标或时间、ID 做“游标翻页”：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-sql&quot; lang=&quot;sql&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;SELECT&lt;/span&gt; id, user_id, order_no, status, create_time
&lt;span class=&quot;hljs-keyword&quot;&gt;FROM&lt;/span&gt; t_order
&lt;span class=&quot;hljs-keyword&quot;&gt;WHERE&lt;/span&gt; create_time &lt;span class=&quot;hljs-operator&quot;&gt;&amp;lt;&lt;/span&gt; ?
&lt;span class=&quot;hljs-keyword&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;BY&lt;/span&gt; create_time &lt;span class=&quot;hljs-keyword&quot;&gt;DESC&lt;/span&gt;
LIMIT &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-id=&quot;heading-28&quot;&gt;7.4 排序问题&lt;/h3&gt;
&lt;p&gt;排序会消耗 CPU 和内存。如果排序字段上没有索引，数据库可能需要额外的 filesort。高频排序字段，特别是和过滤条件一起使用的字段，应该认真设计索引。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-29&quot;&gt;7.5 回表问题&lt;/h3&gt;
&lt;p&gt;当查询列不在索引中时，数据库需要先通过索引找到主键，再回到主表读取完整数据，这就是回表。回表并不总是坏事，但在高频场景下，如果回表次数太多，性能会明显下降。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-30&quot;&gt;7.6 使用 EXPLAIN 观察执行计划&lt;/h3&gt;
&lt;p&gt;以下信息通常很有价值：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;type：访问类型，是否走索引&lt;/li&gt;
&lt;li&gt;key：实际使用的索引&lt;/li&gt;
&lt;li&gt;rows：预估扫描行数&lt;/li&gt;
&lt;li&gt;Extra：是否 Using filesort、Using temporary、Using index&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;你不需要死记硬背所有字段，但至少要会判断：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;有没有走到你想要的索引&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;扫描行数是不是过大&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;有没有排序临时表&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;有没有覆盖索引&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-id=&quot;heading-31&quot;&gt;8. ORM 生成 SQL 的风险点：JPA 为什么会“写出慢 SQL”&lt;/h2&gt;
&lt;h3 data-id=&quot;heading-32&quot;&gt;8.1 ORM 的价值与代价&lt;/h3&gt;
&lt;p&gt;ORM 的价值非常明显：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;提高开发效率&lt;/li&gt;
&lt;li&gt;降低样板代码&lt;/li&gt;
&lt;li&gt;便于领域建模&lt;/li&gt;
&lt;li&gt;统一事务和对象管理&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但代价同样真实：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SQL 透明度下降&lt;/li&gt;
&lt;li&gt;性能问题更隐蔽&lt;/li&gt;
&lt;li&gt;复杂查询表达困难&lt;/li&gt;
&lt;li&gt;容易产生 N+1 问题&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Spring Data JPA 尤其适合简单 CRUD 和中等复杂度查询，但并不意味着它天然适合所有场景。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-33&quot;&gt;8.2 N+1 问题&lt;/h3&gt;
&lt;p&gt;N+1 是 ORM 世界最经典的性能陷阱之一。它的本质是：查询主对象一次，然后为了拿关联对象，逐条发起额外查询。&lt;/p&gt;
&lt;p&gt;比如查询 100 个订单，再逐个查订单详情，就会变成 101 次查询。&lt;/p&gt;
&lt;p&gt;示意图绘制如下，仅供参考：&lt;/p&gt;
&lt;div align=&quot;center&quot;&gt; &lt;img width=&quot;1000&quot; src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/70833de9e4af4b238950cf6268990dcf~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgYnVn6I-M:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780480696&amp;amp;x-signature=Kjk1JxR17zKqml0kk3chp4USHUE%3D&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt; &lt;/div&gt;
&lt;p&gt;这个问题很典型，表面上是代码写得“面向对象”，实际上却在数据库层制造了很多小查询。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-34&quot;&gt;8.3 懒加载与关联查询&lt;/h3&gt;
&lt;p&gt;JPA 的懒加载机制可以减少一些不必要的关联查询，但如果使用场景不当，反而会在循环中触发隐式查询。最好的做法是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;明确查询边界&lt;/li&gt;
&lt;li&gt;需要什么就一次性查出来&lt;/li&gt;
&lt;li&gt;在高频接口里避免不受控的关联展开&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-id=&quot;heading-35&quot;&gt;8.4 JPA 生成 SQL 的风险点&lt;/h3&gt;
&lt;p&gt;常见风险包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;复杂方法名派生查询可读性下降&lt;/li&gt;
&lt;li&gt;难以精确控制 join 方式&lt;/li&gt;
&lt;li&gt;分页和排序组合后 SQL 变重&lt;/li&gt;
&lt;li&gt;批量更新、批量删除能力有限&lt;/li&gt;
&lt;li&gt;对数据库特性利用不足&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-id=&quot;heading-36&quot;&gt;8.5 一个看似优雅、实则危险的查询&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-java&quot; lang=&quot;java&quot;&gt;List&amp;lt;OrderEntity&amp;gt; &lt;span class=&quot;hljs-title function_&quot;&gt;findByUserNameContainingAndStatusOrderByCreateTimeDesc&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String userName, Integer status)&lt;/span&gt;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个方法名本身没有错，但它背后的 SQL 可能会出现：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;模糊查询导致索引失效&lt;/li&gt;
&lt;li&gt;排序字段未命中索引&lt;/li&gt;
&lt;li&gt;返回列过多&lt;/li&gt;
&lt;li&gt;在高并发下产生大量扫描&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以，ORM 的“优雅”必须服从性能与可维护性。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-37&quot;&gt;9. 慢查询如何回溯到代码层：从数据库日志到 Java 方法&lt;/h2&gt;
&lt;h3 data-id=&quot;heading-38&quot;&gt;9.1 慢查询分析的核心目标&lt;/h3&gt;
&lt;p&gt;慢查询分析不是单纯看数据库里哪条 SQL 慢，而是要回答一个更关键的问题：&lt;strong&gt;这条 SQL 是从哪一段代码发出来的，为什么会这样发？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;只有回到代码层，你才能真正修复问题，而不是在数据库侧做一次临时补丁。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-39&quot;&gt;9.2 从数据库日志出发&lt;/h3&gt;
&lt;p&gt;首先你可以借助数据库慢查询日志、执行计划、监控平台，找到耗时较高的 SQL。&lt;/p&gt;
&lt;p&gt;慢查询日志里通常会包含：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SQL 执行时间&lt;/li&gt;
&lt;li&gt;扫描行数&lt;/li&gt;
&lt;li&gt;具体 SQL 文本&lt;/li&gt;
&lt;li&gt;执行时间窗口&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;拿到 SQL 后，下一步是建立“SQL 到代码”的映射。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-40&quot;&gt;9.3 在 Spring Boot 中记录 SQL&lt;/h3&gt;
&lt;p&gt;对于开发和测试环境，开启 SQL 日志非常有帮助。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-yaml&quot; lang=&quot;yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;spring:&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;jpa:&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;show-sql:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;properties:&lt;/span&gt;
      &lt;span class=&quot;hljs-attr&quot;&gt;hibernate:&lt;/span&gt;
        &lt;span class=&quot;hljs-attr&quot;&gt;format_sql:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;
        &lt;span class=&quot;hljs-attr&quot;&gt;highlight_sql:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;logging:&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;level:&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;org.hibernate.SQL:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;debug&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;org.hibernate.orm.jdbc.bind:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;trace&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不过要注意，生产环境不建议无脑开启过详细日志，因为会带来额外性能开销和日志噪音。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-41&quot;&gt;9.4 通过请求链路标识定位&lt;/h3&gt;
&lt;p&gt;更推荐的方式是给请求打上 traceId 或 requestId，把接口请求、业务日志、SQL 日志串起来。&lt;/p&gt;
&lt;p&gt;例如，Controller 接到请求后记录一次关键日志：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-java&quot; lang=&quot;java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.example.demo.web;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; jakarta.servlet.http.HttpServletRequest;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.slf4j.Logger;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.slf4j.LoggerFactory;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.GetMapping;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.RequestMapping;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.web.bind.annotation.RestController;

&lt;span class=&quot;hljs-meta&quot;&gt;@RestController&lt;/span&gt;
&lt;span class=&quot;hljs-meta&quot;&gt;@RequestMapping(&quot;/orders&quot;)&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;OrderController&lt;/span&gt; {

    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;Logger&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;log&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; LoggerFactory.getLogger(OrderController.class);

    &lt;span class=&quot;hljs-meta&quot;&gt;@GetMapping(&quot;/slow&quot;)&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; String &lt;span class=&quot;hljs-title function_&quot;&gt;slowQuery&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(HttpServletRequest request)&lt;/span&gt; {
        &lt;span class=&quot;hljs-comment&quot;&gt;// 记录请求来源，便于排查慢请求对应的入口&lt;/span&gt;
        log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;收到请求：uri={}, remoteAddr={}&quot;&lt;/span&gt;, request.getRequestURI(), request.getRemoteAddr());
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;ok&quot;&lt;/span&gt;;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果你把日志格式统一成包含 traceId，就能在日志平台里按请求串联出整条链路。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-42&quot;&gt;9.5 使用 AOP 记录 Repository 或 Service 耗时&lt;/h3&gt;
&lt;p&gt;你可以在 Service 层加一个简单的耗时统计，快速定位是业务慢还是数据库慢。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-java&quot; lang=&quot;java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.example.demo.aspect;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.aspectj.lang.ProceedingJoinPoint;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.aspectj.lang.annotation.Around;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.aspectj.lang.annotation.Aspect;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.slf4j.Logger;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.slf4j.LoggerFactory;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.stereotype.Component;

&lt;span class=&quot;hljs-meta&quot;&gt;@Aspect&lt;/span&gt;
&lt;span class=&quot;hljs-meta&quot;&gt;@Component&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;CostTimeAspect&lt;/span&gt; {

    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;Logger&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;log&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; LoggerFactory.getLogger(CostTimeAspect.class);

    &lt;span class=&quot;hljs-meta&quot;&gt;@Around(&quot;execution(* com.example.demo.service..*(..))&quot;)&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; Object &lt;span class=&quot;hljs-title function_&quot;&gt;recordCostTime&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(ProceedingJoinPoint joinPoint)&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; Throwable {
        &lt;span class=&quot;hljs-type&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; System.currentTimeMillis();
        &lt;span class=&quot;hljs-keyword&quot;&gt;try&lt;/span&gt; {
            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; joinPoint.proceed();
        } &lt;span class=&quot;hljs-keyword&quot;&gt;finally&lt;/span&gt; {
            &lt;span class=&quot;hljs-type&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;cost&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; System.currentTimeMillis() - start;
            &lt;span class=&quot;hljs-comment&quot;&gt;// 输出方法耗时，帮助判断是否为慢调用入口&lt;/span&gt;
            log.info(&lt;span class=&quot;hljs-string&quot;&gt;&quot;方法耗时：{}#{}，{}ms&quot;&lt;/span&gt;,
                    joinPoint.getSignature().getDeclaringTypeName(),
                    joinPoint.getSignature().getName(),
                    cost);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-id=&quot;heading-43&quot;&gt;9.6 把慢 SQL 反查回 Repository 方法&lt;/h3&gt;
&lt;p&gt;如果你使用 JPA，可以通过以下方式反查：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;看 SQL 文本是否与某个 &lt;code&gt;@Query&lt;/code&gt; 对应&lt;/li&gt;
&lt;li&gt;看 Repository 方法名是否生成了该 SQL&lt;/li&gt;
&lt;li&gt;搜索项目中涉及该表名的所有 Repository&lt;/li&gt;
&lt;li&gt;在业务日志里加入方法级别埋点&lt;/li&gt;
&lt;li&gt;使用性能分析工具定位调用栈&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-id=&quot;heading-44&quot;&gt;9.7 一个实用建议：为复杂查询手写明确的方法名&lt;/h3&gt;
&lt;p&gt;与其让 ORM 自动拼 SQL，不如为高频关键查询写明确的方法接口，例如：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-java&quot; lang=&quot;java&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;@Query(&quot;select new com.example.demo.dto.OrderSummaryDTO(o.id, o.orderNo, o.status, o.createTime) &quot; +
       &quot;from OrderEntity o where o.userId = :userId and o.status = :status order by o.createTime desc&quot;)&lt;/span&gt;
List&amp;lt;OrderSummaryDTO&amp;gt; &lt;span class=&quot;hljs-title function_&quot;&gt;findOrderSummary&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(Long userId, Integer status)&lt;/span&gt;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样做的好处是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;业务含义清晰&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;SQL 边界明确&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;DTO 返回更轻量&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;便于优化索引和执行计划&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-id=&quot;heading-45&quot;&gt;10. Spring Data JPA 与原生 SQL 的选择边界&lt;/h2&gt;
&lt;h3 data-id=&quot;heading-46&quot;&gt;10.1 不要把选择变成信仰之争&lt;/h3&gt;
&lt;p&gt;很多团队会陷入“JPA 好还是 MyBatis 好”的争论。实际上，真正应该讨论的是：&lt;strong&gt;这个场景下哪种方式更适合当前性能目标、团队能力和维护成本。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Spring Data JPA 的优势：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;开发效率高&lt;/li&gt;
&lt;li&gt;对简单 CRUD 非常友好&lt;/li&gt;
&lt;li&gt;领域对象表达自然&lt;/li&gt;
&lt;li&gt;事务与实体状态管理方便&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;原生 SQL 的优势：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对执行计划和语法控制更强&lt;/li&gt;
&lt;li&gt;复杂查询更容易精确表达&lt;/li&gt;
&lt;li&gt;更容易做性能极限优化&lt;/li&gt;
&lt;li&gt;适合报表、统计、复杂联表和批量任务&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-id=&quot;heading-47&quot;&gt;10.2 适合用 JPA 的场景&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;单表 CRUD&lt;/li&gt;
&lt;li&gt;简单条件查询&lt;/li&gt;
&lt;li&gt;中等复杂度分页列表&lt;/li&gt;
&lt;li&gt;以业务建模为中心的领域服务&lt;/li&gt;
&lt;li&gt;不追求极限性能的普通后台系统&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-id=&quot;heading-48&quot;&gt;10.3 适合用原生 SQL 的场景&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;高并发核心接口&lt;/li&gt;
&lt;li&gt;复杂联表查询&lt;/li&gt;
&lt;li&gt;大数据量统计和聚合&lt;/li&gt;
&lt;li&gt;批量写入、批量更新&lt;/li&gt;
&lt;li&gt;需要精确控制索引、Hint、排序、分页方式的场景&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-id=&quot;heading-49&quot;&gt;10.4 选择边界的判断标准&lt;/h3&gt;
&lt;p&gt;你可以用以下四个问题来判断：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;这条查询是否处在核心链路上？&lt;/li&gt;
&lt;li&gt;是否对性能、延迟非常敏感？&lt;/li&gt;
&lt;li&gt;SQL 是否明显复杂到 ORM 表达困难？&lt;/li&gt;
&lt;li&gt;团队是否有能力维护手写 SQL？&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果这四个问题里有两个以上答案偏向“是”，那么原生 SQL 往往更合适。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-50&quot;&gt;10.5 JPA 与原生 SQL 的组合策略&lt;/h3&gt;
&lt;p&gt;更现实的做法不是二选一，而是组合使用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;主流程、简单 CRUD 用 JPA&lt;/li&gt;
&lt;li&gt;核心性能链路用原生 SQL&lt;/li&gt;
&lt;li&gt;批量处理用 JdbcTemplate 或原生批量能力&lt;/li&gt;
&lt;li&gt;报表统计用原生 SQL 或专门的数据访问层&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这才是大多数中大型项目更健康的实践。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-51&quot;&gt;11. 一个完整的性能优化案例：订单查询与批处理改造&lt;/h2&gt;
&lt;p&gt;下面我们用一个贴近业务的案例，把前面讲的索引、SQL、批量、连接池、ORM 风险串起来。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-52&quot;&gt;11.1 场景背景&lt;/h3&gt;
&lt;p&gt;某电商后台有一个“订单查询”和“订单导入”功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;订单查询接口经常超时&lt;/li&gt;
&lt;li&gt;导入接口在批量导入 5 万条数据时非常慢&lt;/li&gt;
&lt;li&gt;数据库 CPU 偶尔飙高&lt;/li&gt;
&lt;li&gt;业务同学感觉“JPA 写起来很方便，但一上线就卡”&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-id=&quot;heading-53&quot;&gt;11.2 初始版本的问题&lt;/h3&gt;
&lt;p&gt;订单表结构大致如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-sql&quot; lang=&quot;sql&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;TABLE&lt;/span&gt; t_order (
    id &lt;span class=&quot;hljs-type&quot;&gt;BIGINT&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;PRIMARY&lt;/span&gt; KEY AUTO_INCREMENT,
    user_id &lt;span class=&quot;hljs-type&quot;&gt;BIGINT&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;NULL&lt;/span&gt;,
    order_no &lt;span class=&quot;hljs-type&quot;&gt;VARCHAR&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;64&lt;/span&gt;) &lt;span class=&quot;hljs-keyword&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;NULL&lt;/span&gt;,
    status &lt;span class=&quot;hljs-type&quot;&gt;INT&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;NULL&lt;/span&gt;,
    total_amount &lt;span class=&quot;hljs-type&quot;&gt;DECIMAL&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;18&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;) &lt;span class=&quot;hljs-keyword&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;NULL&lt;/span&gt;,
    create_time DATETIME &lt;span class=&quot;hljs-keyword&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;NULL&lt;/span&gt;,
    update_time DATETIME &lt;span class=&quot;hljs-keyword&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;NULL&lt;/span&gt;
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;初始查询代码：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-java&quot; lang=&quot;java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.example.demo.service;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.example.demo.entity.OrderEntity;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.example.demo.repository.OrderRepository;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.stereotype.Service;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.List;

&lt;span class=&quot;hljs-meta&quot;&gt;@Service&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;OrderQueryService&lt;/span&gt; {

    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;final&lt;/span&gt; OrderRepository orderRepository;

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;OrderQueryService&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(OrderRepository orderRepository)&lt;/span&gt; {
        &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.orderRepository = orderRepository;
    }

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; List&amp;lt;OrderEntity&amp;gt; &lt;span class=&quot;hljs-title function_&quot;&gt;queryByUserId&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(Long userId)&lt;/span&gt; {
        &lt;span class=&quot;hljs-comment&quot;&gt;// 直接按用户ID查询订单列表&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; orderRepository.findByUserIdOrderByCreateTimeDesc(userId);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Repository：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-java&quot; lang=&quot;java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.example.demo.repository;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.example.demo.entity.OrderEntity;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.data.jpa.repository.JpaRepository;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.List;

&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;OrderRepository&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;JpaRepository&lt;/span&gt;&amp;lt;OrderEntity, Long&amp;gt; {

    &lt;span class=&quot;hljs-comment&quot;&gt;// 根据用户ID查询订单并按时间倒序排列&lt;/span&gt;
    List&amp;lt;OrderEntity&amp;gt; &lt;span class=&quot;hljs-title function_&quot;&gt;findByUserIdOrderByCreateTimeDesc&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(Long userId)&lt;/span&gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-id=&quot;heading-54&quot;&gt;11.3 问题分析&lt;/h3&gt;
&lt;p&gt;表面上看，这段代码很简单，但问题可能有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;create_time&lt;/code&gt; 没有合适索引，排序慢&lt;/li&gt;
&lt;li&gt;返回实体过多，包含不必要字段&lt;/li&gt;
&lt;li&gt;订单列表分页不合理&lt;/li&gt;
&lt;li&gt;查询条件缺少状态过滤，返回数据太多&lt;/li&gt;
&lt;li&gt;JPA 加载关联对象导致额外查询&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-id=&quot;heading-55&quot;&gt;11.4 优化方案一：补充合理索引&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-sql&quot; lang=&quot;sql&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;CREATE&lt;/span&gt; INDEX idx_order_user_time &lt;span class=&quot;hljs-keyword&quot;&gt;ON&lt;/span&gt; t_order(user_id, create_time &lt;span class=&quot;hljs-keyword&quot;&gt;DESC&lt;/span&gt;);
&lt;span class=&quot;hljs-keyword&quot;&gt;CREATE&lt;/span&gt; INDEX idx_order_user_status_time &lt;span class=&quot;hljs-keyword&quot;&gt;ON&lt;/span&gt; t_order(user_id, status, create_time &lt;span class=&quot;hljs-keyword&quot;&gt;DESC&lt;/span&gt;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样，用户维度的时间倒序列表更容易命中索引。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-56&quot;&gt;11.5 优化方案二：使用 DTO 投影减少数据量&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-java&quot; lang=&quot;java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.example.demo.dto;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.math.BigDecimal;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.time.LocalDateTime;

&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;OrderSummaryDTO&lt;/span&gt; {

    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; Long id;
    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; String orderNo;
    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; Integer status;
    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; BigDecimal totalAmount;
    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; LocalDateTime createTime;

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;OrderSummaryDTO&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(Long id, String orderNo, Integer status, BigDecimal totalAmount, LocalDateTime createTime)&lt;/span&gt; {
        &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.id = id;
        &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.orderNo = orderNo;
        &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.status = status;
        &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.totalAmount = totalAmount;
        &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.createTime = createTime;
    }

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; Long &lt;span class=&quot;hljs-title function_&quot;&gt;getId&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt; {
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; id;
    }

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; String &lt;span class=&quot;hljs-title function_&quot;&gt;getOrderNo&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt; {
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; orderNo;
    }

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; Integer &lt;span class=&quot;hljs-title function_&quot;&gt;getStatus&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt; {
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; status;
    }

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; BigDecimal &lt;span class=&quot;hljs-title function_&quot;&gt;getTotalAmount&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt; {
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; totalAmount;
    }

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; LocalDateTime &lt;span class=&quot;hljs-title function_&quot;&gt;getCreateTime&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt; {
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; createTime;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Repository 改造：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-java&quot; lang=&quot;java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.example.demo.repository;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.example.demo.dto.OrderSummaryDTO;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.example.demo.entity.OrderEntity;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.data.jpa.repository.JpaRepository;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.data.jpa.repository.Query;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.data.repository.query.Param;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.List;

&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;OrderRepository&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;JpaRepository&lt;/span&gt;&amp;lt;OrderEntity, Long&amp;gt; {

    &lt;span class=&quot;hljs-meta&quot;&gt;@Query(&quot;select new com.example.demo.dto.OrderSummaryDTO(o.id, o.orderNo, o.status, o.totalAmount, o.createTime) &quot; +
           &quot;from OrderEntity o where o.userId = :userId order by o.createTime desc&quot;)&lt;/span&gt;
    List&amp;lt;OrderSummaryDTO&amp;gt; &lt;span class=&quot;hljs-title function_&quot;&gt;findOrderSummaryByUserId&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-meta&quot;&gt;@Param(&quot;userId&quot;)&lt;/span&gt; Long userId)&lt;/span&gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-id=&quot;heading-57&quot;&gt;11.6 优化方案三：分页改成游标翻页&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-java&quot; lang=&quot;java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.example.demo.repository;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.example.demo.dto.OrderSummaryDTO;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.example.demo.entity.OrderEntity;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.data.jpa.repository.JpaRepository;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.data.jpa.repository.Query;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.data.repository.query.Param;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.time.LocalDateTime;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.List;

&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;OrderRepository&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;JpaRepository&lt;/span&gt;&amp;lt;OrderEntity, Long&amp;gt; {

    &lt;span class=&quot;hljs-meta&quot;&gt;@Query(&quot;select new com.example.demo.dto.OrderSummaryDTO(o.id, o.orderNo, o.status, o.totalAmount, o.createTime) &quot; +
           &quot;from OrderEntity o where o.userId = :userId and o.createTime &amp;lt; :beforeTime order by o.createTime desc&quot;)&lt;/span&gt;
    List&amp;lt;OrderSummaryDTO&amp;gt; &lt;span class=&quot;hljs-title function_&quot;&gt;findOrderSummaryByUserIdAndBeforeTime&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(
            &lt;span class=&quot;hljs-meta&quot;&gt;@Param(&quot;userId&quot;)&lt;/span&gt; Long userId,
            &lt;span class=&quot;hljs-meta&quot;&gt;@Param(&quot;beforeTime&quot;)&lt;/span&gt; LocalDateTime beforeTime,
            org.springframework.data.domain.Pageable pageable)&lt;/span&gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-id=&quot;heading-58&quot;&gt;11.7 批量导入改造&lt;/h3&gt;
&lt;p&gt;初始导入逻辑：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-java&quot; lang=&quot;java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (OrderEntity order : orders) {
    orderRepository.save(order);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;改造成批处理：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-java&quot; lang=&quot;java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;package&lt;/span&gt; com.example.demo.service;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; com.example.demo.entity.OrderEntity;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; jakarta.persistence.EntityManager;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; jakarta.persistence.PersistenceContext;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.stereotype.Service;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; org.springframework.transaction.annotation.Transactional;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.List;

&lt;span class=&quot;hljs-meta&quot;&gt;@Service&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;OrderImportService&lt;/span&gt; {

    &lt;span class=&quot;hljs-meta&quot;&gt;@PersistenceContext&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; EntityManager entityManager;

    &lt;span class=&quot;hljs-meta&quot;&gt;@Transactional&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;importOrders&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(List&amp;lt;OrderEntity&amp;gt; orders)&lt;/span&gt; {
        &lt;span class=&quot;hljs-comment&quot;&gt;// 每批处理的数量，具体值需要压测后确定&lt;/span&gt;
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;batchSize&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;100&lt;/span&gt;;

        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; orders.size(); i++) {
            entityManager.persist(orders.get(i));

            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (i &amp;gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &amp;amp;&amp;amp; i % batchSize == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;) {
                &lt;span class=&quot;hljs-comment&quot;&gt;// 刷新到数据库并清理持久化上下文&lt;/span&gt;
                entityManager.flush();
                entityManager.clear();
            }
        }

        entityManager.flush();
        entityManager.clear();
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-id=&quot;heading-59&quot;&gt;11.8 优化前后的效果预期&lt;/h3&gt;
&lt;p&gt;经过这些改造后，通常可以看到：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;查询耗时下降&lt;/li&gt;
&lt;li&gt;数据库扫描行数减少&lt;/li&gt;
&lt;li&gt;导入吞吐提升&lt;/li&gt;
&lt;li&gt;连接池等待时间下降&lt;/li&gt;
&lt;li&gt;CPU 峰值降低&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;关键不在于“代码看起来更短”，而在于“数据访问路径更合理”。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-60&quot;&gt;12. 常见误区与排查清单&lt;/h2&gt;
&lt;h3 data-id=&quot;heading-61&quot;&gt;12.1 误区一：加索引一定更快&lt;/h3&gt;
&lt;p&gt;不是。索引会提升读性能，但也会增加写成本。是否加索引，取决于查询与写入的平衡。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-62&quot;&gt;12.2 误区二：JPA 一定比手写 SQL 好维护&lt;/h3&gt;
&lt;p&gt;对简单 CRUD 来说，JPA 的确方便；但对复杂查询、高并发链路，手写 SQL 往往更清晰、更高效。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-63&quot;&gt;12.3 误区三：连接池越大越好&lt;/h3&gt;
&lt;p&gt;不是。连接池应该和数据库能力、SQL 耗时、并发模型一起设计。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-64&quot;&gt;12.4 误区四：慢查询只需要改数据库&lt;/h3&gt;
&lt;p&gt;不是。很多慢查询根源是代码层的查询方式不合理，例如循环查询、N+1、DTO 设计不合理、分页方式不当。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-65&quot;&gt;12.5 排查清单&lt;/h3&gt;
&lt;p&gt;你可以按这个顺序排查：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;是否有慢 SQL 日志&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;SQL 是否命中预期索引&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;扫描行数是否过大&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;是否存在 N+1&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;是否存在 &lt;code&gt;SELECT *&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;是否存在大偏移分页&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;是否存在长事务&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;连接池是否耗尽&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ORM 是否生成了意外 SQL&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;是否能用 DTO、原生 SQL 或批量操作改善&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-id=&quot;heading-66&quot;&gt;13. 总结：把性能优化做成工程能力&lt;/h2&gt;
&lt;p&gt;数据库访问优化，不是某一个工具的专属能力，而是贯穿模型设计、SQL 编写、ORM 使用、事务控制、连接池配置、监控排查的系统工程。&lt;/p&gt;
&lt;p&gt;在 Spring Boot 3.x 时代，开发者更应该建立下面这套方法论：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用 JPA 提升开发效率，但不要被 ORM 绑架&lt;/li&gt;
&lt;li&gt;用索引提升查询效率，但不要迷信索引&lt;/li&gt;
&lt;li&gt;用批量处理提升写入吞吐，但要注意事务和内存&lt;/li&gt;
&lt;li&gt;用连接池复用昂贵资源，但要和数据库能力匹配&lt;/li&gt;
&lt;li&gt;用日志、监控、执行计划把慢查询精准定位到代码层&lt;/li&gt;
&lt;li&gt;对核心链路，敢于选择原生 SQL 与 DTO 投影&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;真正高质量的数据库访问优化，不是“把 SQL 调快一点”这么简单，而是把数据访问从“能跑”提升到“稳定、可观测、可扩展”。&lt;/p&gt;
&lt;p&gt;如果你能把本文的思路真正落到项目里，你会发现性能优化并不是玄学，而是一种可以不断复用、持续沉淀的工程能力。&lt;/p&gt;
&lt;p&gt;...&lt;/p&gt;
&lt;p&gt;ok，同学们，本节课就上到这儿，下课~&lt;/p&gt;
&lt;h2 data-id=&quot;heading-67&quot;&gt;🧧 学习福利 · 限时开放 🧧&lt;/h2&gt;
&lt;p&gt;当然，无论你是&lt;strong&gt;计算机专业在读学生&lt;/strong&gt;，还是对编程充满兴趣的入门者，都强烈建议系统学习SpringBoot全体系专栏：👉 &lt;strong&gt;&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fblog.csdn.net%2Fweixin_43970743%2Fcategory_11599389.html&quot; target=&quot;_blank&quot; title=&quot;https://blog.csdn.net/weixin_43970743/category_11599389.html&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;「滚雪球学 Spring Boot」&lt;/a&gt;&lt;/strong&gt;；涵盖SpringBoot所有教学内容。&lt;/p&gt;
&lt;p&gt;该专栏以“&lt;strong&gt;循序渐进 + 实战驱动&lt;/strong&gt;”为核心理念，从基础到进阶到就业到架构师逐层展开，帮助你快速建立完整的 Spring Boot 技术体系，带你玩转SpringBoot框架。&lt;/p&gt;
&lt;p&gt;📌 &lt;strong&gt;学习承诺：&lt;/strong&gt;
通过该专栏，你将能够：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;快速掌握 Spring Boot 核心开发能力&lt;/li&gt;
&lt;li&gt;构建完整的后端项目认知体系&lt;/li&gt;
&lt;li&gt;实现从“入门”到“独立开发”的跃迁&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;就像“滚雪球”一样，知识不断积累、能力持续放大，实现&lt;strong&gt;指数级成长&lt;/strong&gt; 🚀&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;  最后，如果这篇文章对你有所帮助，帮忙给作者来个&lt;strong&gt;一键三连，关注、点赞、收藏&lt;/strong&gt;，您的支持就是我坚持写作最大的动力。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;  同时欢迎大家关注技术号:&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fbbs.csdn.net%2Ftopics%2F612438251&quot; target=&quot;_blank&quot; title=&quot;https://bbs.csdn.net/topics/612438251&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;「猿圈奇妙屋」&lt;/a&gt; ，以便学习更多同类型的技术文章，免费白嫖最新BAT互联网公司面试题、&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fpan.quark.cn%2Fs%2F6b38d03a7298&quot; target=&quot;_blank&quot; title=&quot;https://pan.quark.cn/s/6b38d03a7298&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;4000G PDF编程电子书&lt;/a&gt;、简历模板、技术文章Markdown文档等海量资料。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;ps：本文涉及所有源代码，均已上传至&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fgitee.com%2Fbugjun01%2FSpringBoot-demo&quot; target=&quot;_blank&quot; title=&quot;https://gitee.com/bugjun01/SpringBoot-demo&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;Gitee&lt;/a&gt;开源，供同学们直接对照学习 &lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fgitee.com%2Fbugjun01%2FSpringBoot-demo&quot; target=&quot;_blank&quot; title=&quot;https://gitee.com/bugjun01/SpringBoot-demo&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;Gitee传送门&lt;/a&gt;，同时，原创开源不易，欢迎给个star🌟，想体验下被🌟的感jio，非常感谢❗&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-id=&quot;heading-68&quot;&gt;🫵 Who am I？&lt;/h2&gt;
&lt;p&gt;我是 &lt;strong&gt;bug菌&lt;/strong&gt;，一名深耕 Java 后端领域数十年的一线研发老兵，曾担任独角兽企业后端技术经理、研发架构师等职位，长期专注于 Java 后端、分布式架构、微服务治理、高并发系统、工程效能与研发管理等方向。&lt;/p&gt;
&lt;p&gt;目前活跃于多个主流技术社区，包括：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fblog.csdn.net%2Fweixin_43970743%3Ftype%3Dblog&quot; target=&quot;_blank&quot; title=&quot;https://blog.csdn.net/weixin_43970743?type=blog&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;CSDN&lt;/a&gt;&lt;strong&gt;｜&lt;/strong&gt;&lt;a href=&quot;https://juejin.cn/user/695333581765240&quot; target=&quot;_blank&quot; title=&quot;https://juejin.cn/user/695333581765240&quot;&gt;稀土掘金&lt;/a&gt;&lt;strong&gt;｜&lt;/strong&gt;&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fwww.infoq.cn%2Fprofile%2F4F581734D60B28%2Fpublish&quot; target=&quot;_blank&quot; title=&quot;https://www.infoq.cn/profile/4F581734D60B28/publish&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;InfoQ&lt;/a&gt;&lt;strong&gt;｜&lt;/strong&gt;&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fblog.51cto.com%2Fu_15700751&quot; target=&quot;_blank&quot; title=&quot;https://blog.51cto.com/u_15700751&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;51CTO&lt;/a&gt;&lt;strong&gt;｜&lt;/strong&gt;&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fbbs.huaweicloud.com%2Fcommunity%2Fusersnew%2Fid_1582617489455371&quot; target=&quot;_blank&quot; title=&quot;https://bbs.huaweicloud.com/community/usersnew/id_1582617489455371&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;华为云开发者社区&lt;/a&gt;&lt;strong&gt;｜&lt;/strong&gt;&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fdeveloper.aliyun.com%2Fprofile%2Fuolxikq5k3gke&quot; target=&quot;_blank&quot; title=&quot;https://developer.aliyun.com/profile/uolxikq5k3gke&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;阿里云开发者社区&lt;/a&gt;&lt;strong&gt;｜&lt;/strong&gt;&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fcloud.tencent.com%2Fdeveloper%2Fuser%2F10216480%2Farticles&quot; target=&quot;_blank&quot; title=&quot;https://cloud.tencent.com/developer/user/10216480/articles&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;腾讯云开发者社区&lt;/a&gt;&lt;strong&gt;｜&lt;/strong&gt;&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fmy.oschina.net%2Fu%2F9524856%2F%3Fkey%3Dblog&quot; target=&quot;_blank&quot; title=&quot;https://my.oschina.net/u/9524856/?key=blog&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;开源中国&lt;/a&gt;&lt;strong&gt;｜&lt;/strong&gt;&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fwww.cnblogs.com%2FbugJunNo1&quot; target=&quot;_blank&quot; title=&quot;https://www.cnblogs.com/bugJunNo1&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;博客园&lt;/a&gt;&lt;strong&gt;｜&lt;/strong&gt;&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fwww.modb.pro%2Fu%2F665686&quot; target=&quot;_blank&quot; title=&quot;https://www.modb.pro/u/665686&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;墨天轮&lt;/a&gt;&lt;/strong&gt; 等平台。&lt;/p&gt;
&lt;p&gt;曾获得：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CSDN 博客之星 Top30&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;华为云多年度十佳博主 &amp;amp; 卓越贡献奖&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;掘金多年度人气作者 Top40&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CSDN、掘金、InfoQ、51CTO 等平台签约作者 / 优质作者&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;截至目前，全网技术内容累计影响读者众多，全网粉丝已超过 &lt;strong&gt;30w+&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;如果你也关注 Java 后端、架构设计、技术成长、职场进阶与研发管理，欢迎关注我的技术内容合集入口：👉 &lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fbbs.csdn.net%2Ftopics%2F612438251&quot; target=&quot;_blank&quot; title=&quot;https://bbs.csdn.net/topics/612438251&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;点击查看&lt;/a&gt; 👈️&lt;/p&gt;
&lt;p&gt;硬核技术号 &lt;strong&gt;&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fbbs.csdn.net%2Ftopics%2F612438251&quot; target=&quot;_blank&quot; title=&quot;https://bbs.csdn.net/topics/612438251&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;「猿圈奇妙屋」&lt;/a&gt;&lt;/strong&gt; 期待你的加入。&lt;/p&gt;
&lt;p&gt;这里不仅分享技术干货，也记录一线研发人的成长、踩坑、思考与进阶路径。&lt;/p&gt;
&lt;p&gt;愿我们一起打怪升级，在技术路上持续进阶。&lt;/p&gt;
&lt;div align=&quot;center&quot;&gt; 
    &lt;img width=&quot;900&quot; src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/a75662ee526e42a88ca4b4b326f5a8d9~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgYnVn6I-M:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780480696&amp;amp;x-signature=KWP3yqrJ6a8wV5Kobym018r0q5o%3D&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt; 
&lt;/div&gt;
&lt;p&gt;&lt;em&gt;- End -&lt;/em&gt;&lt;/p&gt;</description><link>https://juejin.cn/post/7644206599271858226</link><guid isPermaLink="false">https://juejin.cn/post/7644206599271858226</guid><pubDate>Wed, 27 May 2026 09:58:16 GMT</pubDate><author>bug菌</author><category>后端</category><category>Spring Boot</category><category>数据库</category></item><item><title>通义灵码不仅改名，还要收费了！！！</title><description>&lt;blockquote&gt;
&lt;p&gt;关注我的公众号：【编程朝花夕拾】，可获取首发内容。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/79d4735d1a124cff821e11c954233789~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgU2ltb25LaW5n:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780448937&amp;amp;x-signature=DvhameS86AfOC15yCfol6FoH4cU%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;h2 data-id=&quot;heading-0&quot;&gt;01 引言&lt;/h2&gt;
&lt;p&gt;在更新IDEA的插件的时候，发现通义灵码竟然改名字了？&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/4110c1c63fe4427db4e153ab069af575~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgU2ltb25LaW5n:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780448937&amp;amp;x-signature=zBOx6iKSWOckSHNJXiT8G5%2BSOCw%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;原以为只是改了名字，详细了解了之后，才发现免费版功能严重阉割，倒逼付费使用！&lt;/p&gt;
&lt;h2 data-id=&quot;heading-1&quot;&gt;02 官方通知&lt;/h2&gt;
&lt;p&gt;从阿里云官网的公告了解到：2026年5月20日，&quot;智能编码助手通义灵码&quot;（&lt;code&gt;Lingma&lt;/code&gt;）正式更名为 &lt;strong&gt;&lt;code&gt;Qoder CN&lt;/code&gt;&lt;/strong&gt;，并同步启用全新订阅定价方案和 Credits 配额机制。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/04472c0455e44729872d69436ef7091a~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgU2ltb25LaW5n:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780448937&amp;amp;x-signature=YXcNRjtjzLxjnk92Mo%2BuMTA8JOw%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;通知地址：&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fwww.aliyun.com%2Fnotice%2Fdetail%3Fnotice-id%3D118234&quot; target=&quot;_blank&quot; title=&quot;https://www.aliyun.com/notice/detail?notice-id=118234&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;www.aliyun.com/notice/deta…&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;官方说明：&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fhelp.aliyun.com%2Fzh%2Flingma%2Fproduct-overview%2Fbilling-description&quot; target=&quot;_blank&quot; title=&quot;https://help.aliyun.com/zh/lingma/product-overview/billing-description&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;help.aliyun.com/zh/lingma/p…&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;更名原本大可不必在意，但是免费版该功能阉割，这样广大使用的用户倍感不爽。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-2&quot;&gt;03 阉割了什么&lt;/h2&gt;
&lt;p&gt;官网表明，原来订阅通义灵码的用户依然保留有基本的权益，我们主要看看免费的版本的功能。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;老版本免费版功能&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/82c0a78ad8244b6d8f256fd5feae26f1~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgU2ltb25LaW5n:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780448937&amp;amp;x-signature=GkZsiR8tUF7fdyaFV9MQlb%2BmfWI%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;新版本&lt;code&gt;Qoder CN&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/ca023bd7ef4f4b39a197ec213594746e~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgU2ltb25LaW5n:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780448937&amp;amp;x-signature=kvVrQKCTnEZ9svb2LJxvm52OlW4%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;现在的个人社区版：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;代码生成：仅&quot;有限的智能补全&quot;&lt;/li&gt;
&lt;li&gt;智能会话：仅 Chat Ask &amp;amp; Chat Agents（&lt;strong&gt;有限额度的模型对话&lt;/strong&gt;）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;免费版从&quot;能用完整功能&quot;变成&quot;功能残血还限额度&quot;，实质上是在&lt;strong&gt;强制推动免费用户转向付费&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-3&quot;&gt;04 存量客户安排&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;定价保护&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2026年5月20日北京时间&lt;code&gt;12:00&lt;/code&gt;前&lt;strong&gt;购买完毕&lt;/strong&gt;的订阅，按&lt;strong&gt;原价格&lt;/strong&gt;执行至合同到期&lt;/li&gt;
&lt;li&gt;存量订阅到期后续费，&lt;strong&gt;按新版价格&lt;/strong&gt;执行&lt;/li&gt;
&lt;li&gt;存量订阅到期后新增席位，按&lt;strong&gt;新版价格&lt;/strong&gt;执行&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;存量订阅切换新定价的代价&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;切换到新定价（启用 Credits 机制）后，可获得：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;新增 &lt;code&gt;GLM 5.1&lt;/code&gt;、&lt;code&gt;DeepSeek V4&lt;/code&gt; 等模型选项&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Quest&lt;/code&gt;、&lt;code&gt;RepoWiki&lt;/code&gt;、&lt;code&gt;Agent 会话&lt;/code&gt;、&lt;code&gt;Subagent&lt;/code&gt; &lt;strong&gt;不再限制次数&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;新增 Experts 专家团能力&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-id=&quot;heading-4&quot;&gt;05 小结&lt;/h2&gt;
&lt;p&gt;免费版实质性阉割，这似乎意味着薅羊毛时代正式终结；阿里从获客工具转向商业变现，企业订阅为核心利润来源。老铁们，你们还在用通义灵码么？&lt;/p&gt;</description><link>https://juejin.cn/post/7644135664520511497</link><guid isPermaLink="false">https://juejin.cn/post/7644135664520511497</guid><pubDate>Wed, 27 May 2026 01:08:57 GMT</pubDate><author>SimonKing</author><category>后端</category><category>Java</category><category>程序员</category></item><item><title>华为抛出“韬定律”：芯片竞争，终于不只盯着几纳米了</title><description>&lt;blockquote&gt;
&lt;p&gt;这不是一句“绕开摩尔定律”的口号，而是把芯片进步的主指标，从“空间里还能塞多少晶体管”，换成“系统里还能少等多少时间”。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/4944ed0f4a3e45229f597a3c5c0b92a1~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5YCU5by655qE55-z5aS0Xw==:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780396894&amp;amp;x-signature=BBFdtEyNbe4z6HYHwcCHicWqK1c%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;图注：华为何庭波在 ISCAS 2026 发表 “New Semiconductor Path in Practice / 半导体新路径探索与实践” 主旨演讲。图源：华为官网新闻稿。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-0&quot;&gt;01 这次刷屏的，不只是一个新名词&lt;/h2&gt;
&lt;p&gt;5月25日，上海，IEEE 国际电路与系统研讨会 ISCAS 2026 上，华为董事、半导体业务部总裁何庭波发表主旨演讲，提出了一个很容易刷屏的新词：&lt;strong&gt;韬(τ)定律&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;我第一眼看到这个名字，也有点职业病式地警惕：技术行业最不缺的就是“新概念”。&lt;/p&gt;
&lt;p&gt;但把华为新闻稿、ISCAS 议程，以及何庭波署名的 ChinaXiv 预印本放在一起看，这件事最值得讨论的地方，反而不是“又一个定律”四个字，而是它背后那个工程判断：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;半导体行业不能再只靠把晶体管做小来讲增长故事了。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;过去几十年，我们习惯用“几纳米”理解芯片。制程越先进，晶体管越小，密度越高，功耗和性能也跟着改善。摩尔定律给产业提供了一个极其清晰的节拍器，登纳德缩放也曾经让功耗、电压、尺寸之间的关系变得顺滑。&lt;/p&gt;
&lt;p&gt;但这套叙事现在越来越贵，也越来越难。&lt;/p&gt;
&lt;p&gt;先进制程的研发和设计成本高到吓人，互连的电阻、电容开始吞掉很多收益。晶体管继续变小，不再自动等于系统体验继续变好。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-1&quot;&gt;02 韬定律到底在讲什么&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/35e7b40689734fcb864b1074d6868eb5~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5YCU5by655qE55-z5aS0Xw==:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780396894&amp;amp;x-signature=uyL4xPPrlNSmHiQL7B2r081PWeY%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
图注：从“几何缩微”到“时间缩微”的理解框架。&lt;/p&gt;
&lt;p&gt;τ，本来就是电路里常见的“时间常数”符号。比如我们经常说 RC 延迟，本质上就是电阻 R 和电容 C 共同决定了信号响应需要多久。&lt;/p&gt;
&lt;p&gt;华为这次把这个概念往上抽象了一层：不只看一个器件、一段导线，而是把器件、电路、芯片、系统里的等待时间，都放进同一个优化目标里。&lt;/p&gt;
&lt;p&gt;换句话说，以前的主线是：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;把空间缩小。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;晶体管更小、线更短、面积更省。&lt;/p&gt;
&lt;p&gt;而韬定律提出的主线是：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;把时间压短。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;信号传播更快，关键路径更短，访存和通信更少绕路，端到端任务更快完成。&lt;/p&gt;
&lt;p&gt;这对互联网从业者其实很好理解。我们做一个复杂系统的性能优化，从来不会只盯一行代码。&lt;/p&gt;
&lt;p&gt;一个接口慢，可能是 SQL 慢，可能是缓存没命中，可能是跨机房链路绕远了，也可能是上游服务的队列把请求堵住了。真正有效的优化，往往是把全链路的等待拆开，找到最主要的那段时间，然后一点点压缩。&lt;/p&gt;
&lt;p&gt;韬定律讲的也是类似的事，只不过它发生在芯片和电子系统里。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-2&quot;&gt;03 它不是单点优化，而是跨层协同&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/cb5afa0da4174ec189de76e0925343d8~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5YCU5by655qE55-z5aS0Xw==:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780396894&amp;amp;x-signature=Nq8YZjUWwbi06ZjADaj22iQd3E4%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;图注：韬定律强调器件、电路、芯片、系统的跨层协同。&lt;/p&gt;
&lt;p&gt;华为公开材料里，把这套方法放在几个层级里讨论。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;器件层&lt;/strong&gt;，继续优化晶体管和互连的电阻、电容，尽量减少底层时间常数。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;电路层&lt;/strong&gt;，引入 LogicFolding，也就是“逻辑折叠”。它的核心不是魔法，而是通过垂直堆叠等三维组织方式，把原本摊在平面上的部分关键路径折起来，缩短走线长度，降低 RC 延迟。何庭波预印本中提到，在移动 SoC 的案例里，LogicFolding 在固定器件节点上带来了晶体管密度和能效的提升。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;芯片层&lt;/strong&gt;，重点变成软件、架构、芯片的协同。很多时候，性能不是算力峰值不够，而是数据流、指令流、访存层级没有配合好。把真实负载拆开看，哪些时间花在计算，哪些花在搬数据，哪些花在同步，才有机会继续往下压。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;系统层&lt;/strong&gt;，华为提到灵衢总线、统一内存编址和原生内存语义。这里的关键词是“少转换、少拷贝、少握手”。AI 计算尤其典型：芯片之间、机柜之间、数据中心之间的通信越来越决定整体效率。单个芯片再强，如果大量时间都在等数据，系统吞吐也会被拉住。&lt;/p&gt;
&lt;p&gt;所以，韬定律真正想强调的不是某一个器件参数，而是&lt;strong&gt;把全栈等待时间变成一个共同优化目标&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-3&quot;&gt;04 它重新定义了什么叫“先进”&lt;/h2&gt;
&lt;p&gt;我觉得这件事真正有意思的地方，是它把“先进”重新定义了一次。&lt;/p&gt;
&lt;p&gt;以前我们问一颗芯片先进不先进，第一反应是制程节点。现在华为想说：如果你能在同样制程下，通过三维电路组织、架构协同、互联协议和系统设计，把关键等待大幅压短，那也是一种先进，而且可能是接下来更现实的一种先进。&lt;/p&gt;
&lt;p&gt;这不是说制程不重要。&lt;/p&gt;
&lt;p&gt;制程仍然重要，材料、光刻、晶体管结构也仍然重要。但它们不再是唯一答案。先进封装、3D 集成、片上网络、内存体系、光互联、系统软件，都会越来越像同一张牌桌上的玩家。&lt;/p&gt;
&lt;p&gt;更直白一点说，后摩尔时代的竞争，不只是“谁能把芯片做得更小”，也会是“谁能把系统里的等待压得更少”。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-4&quot;&gt;05 也要冷静：它还不是被完全验证的自然定律&lt;/h2&gt;
&lt;p&gt;当然，冷静一点看，韬定律今天仍然更像一个产业方法论，而不是已经被全行业验证的自然定律。&lt;/p&gt;
&lt;p&gt;首先，何庭波的论文目前是预印本。按照 ChinaXiv 的说明，预印本不等于已经完成严格同行评审。&lt;/p&gt;
&lt;p&gt;其次，LogicFolding 要真正规模化，绕不开良率、散热、堆叠工艺、EDA 工具链、测试维修、供应链协同这些硬问题。&lt;/p&gt;
&lt;p&gt;再其次，τ 是时间指标，不是能耗指标。一个系统如果跑得更快但耗电也等比例上升，那对手机续航和数据中心电力都不是好消息。&lt;/p&gt;
&lt;p&gt;所以我不太想把它写成“摩尔定律终结，华为重新发明未来”这种标题。那样热闹，但不准确。&lt;/p&gt;
&lt;p&gt;更准确的说法是：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;当几何缩微的红利变薄以后，华为把自己的工程经验总结成了一个新的优化框架，并试图把全栈协同变成后摩尔时代的主线。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 data-id=&quot;heading-5&quot;&gt;06 写在最后&lt;/h2&gt;
&lt;p&gt;这其实很符合今天的技术现实。&lt;/p&gt;
&lt;p&gt;互联网、AI、云计算、芯片都在发生同一件事：单点优化越来越不够用了。真正的效率来自系统工程，来自跨层协同，来自把“看不见的等待”变成可度量、可压缩、可交易的指标。&lt;/p&gt;
&lt;p&gt;韬定律能不能成为行业共识，还要看未来几年更多产品、更公开的数据、更广泛的生态验证。&lt;/p&gt;
&lt;p&gt;但它至少提醒了我们一件事：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;下一代芯片竞争，不只是纳米数的竞争，也会是时间管理能力的竞争。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;谁能让信号少走弯路，让数据少等一会儿，让系统少做一次无谓的转换，谁就有机会在后摩尔时代多赢下一点点确定性。&lt;/p&gt;
&lt;p&gt;而工程世界里，很多大变化，最初都是从这一点点确定性开始的。&lt;/p&gt;</description><link>https://juejin.cn/post/7644060700978970662</link><guid isPermaLink="false">https://juejin.cn/post/7644060700978970662</guid><pubDate>Tue, 26 May 2026 10:41:34 GMT</pubDate><author>倔强的石头_</author><category>人工智能</category><category>芯片</category></item><item><title>零基础用AI写App？兄弟😂 醒醒吧，那只是个玩具罢了！</title><description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;本文要点：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI会替代一部分初中级程序员，但替代不了真正有实力的工程师&lt;/li&gt;
&lt;li&gt;零基础用AI写App只是玩具，真正的编程复杂度远超想象&lt;/li&gt;
&lt;li&gt;程序员要从&quot;写代码的人&quot;升级为&quot;驾驭AI的架构师&quot;&lt;/li&gt;
&lt;li&gt;附具体学习路线和我的IM项目真实案例&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 data-id=&quot;heading-0&quot;&gt;一、一个反直觉的现象&lt;/h2&gt;
&lt;p&gt;最近刷社交媒体，你一定见过这种类型的帖子或者评论：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;不会写代码，用AI一天做了个XX App，震惊！&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;评论区一片&quot;学编程没用了&quot;&quot;会用AI就行了&quot;&quot;未来程序员要被淘汰了&quot;。&lt;/p&gt;
&lt;p&gt;2025年初，OpenAI的联合创始人Andrej Karpathy提出了一个概念叫**&quot;Vibe Coding&quot;**——不写代码，靠感觉和自然语言指挥AI写。这个词迅速火遍全网，成了AI编程的代名词。不过连他自己后来都承认，AI生成的代码&quot;can still be gross&quot;——还是可能很烂。&lt;/p&gt;
&lt;p&gt;听起来很美好，对吧？&lt;/p&gt;
&lt;p&gt;但我想说一个可能让你不太舒服的观点：&lt;strong&gt;AI越强，越需要扎实的技术基础。不是不重要了，是比以往任何时候都重要！&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;AI只是把瓶颈从&quot;写代码&quot;转移到了&quot;审代码&quot;，从&quot;执行&quot;转移到了&quot;决策&quot;。以前你需要会写，现在你需要会&lt;strong&gt;驾驭&lt;/strong&gt;。而驾驭的前提，是你真的懂。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 data-id=&quot;heading-1&quot;&gt;二、&quot;AI会替代程序员&quot;——这句话对了一半&lt;/h2&gt;
&lt;p&gt;先说一个很多人不爱听的真相：&lt;strong&gt;&quot;AI会替代程序员&quot;这句话太笼统了。&lt;/strong&gt; 准确的说法是——&lt;strong&gt;AI会替代一部分初中级程序员，但替代不了真正有实力的工程师。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;什么意思？&lt;/p&gt;
&lt;p&gt;我们先看看AI现在能做什么。一个CRUD接口、一个增删改查页面、一个简单的数据展示列表——这些过去是初级程序员每天干的活。写一个Controller、配一个MyBatis的XML、调一个数据库查询、拼一个前端列表页。这种工作，AI现在干得比初级程序员更快、更准、还不用下班。&lt;/p&gt;
&lt;p&gt;你说，如果一个程序员的核心价值就是&quot;把需求翻译成代码&quot;，那他跟AI有什么区别？区别只有一个——AI更快，不要工资，不请假。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;所以这部分岗位，确实危险了。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;但你要是说&quot;AI要替代所有程序员&quot;，那就是危言耸听了。因为编程这件事，远远不止&quot;把需求翻译成代码&quot;这么简单。&lt;/p&gt;
&lt;p&gt;关于这个问题，业界其实早有共识（&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fwww.reddit.com%2Fr%2FBackend%2Fcomments%2F1qp5izl%2Fif_ai_can_generate_code_now_what_skills_actually%2F&quot; target=&quot;_blank&quot; title=&quot;https://www.reddit.com/r/Backend/comments/1qp5izl/if_ai_can_generate_code_now_what_skills_actually/&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;相关讨论&lt;/a&gt;）：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&quot;Strong engineers are not valuable because they can type syntax. They are valuable because they understand problems, constraints, and trade-offs.&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;翻译过来就是：&lt;strong&gt;强工程师的价值不在于会敲代码，而在于理解问题、约束和权衡。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这些东西，AI目前做不到。&lt;/p&gt;
&lt;p&gt;所以结论很清晰了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;只会写CRUD的初级程序员&lt;/strong&gt;——危险，AI能干你的活&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;只会照搬框架模板的中级程序员&lt;/strong&gt;——危险，AI也能干你的活&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;能做架构决策、能权衡技术选型、能排查疑难杂症的高级工程师&lt;/strong&gt;——安全，AI是你的加速器&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;AI不会替代程序员这个行业，但会重新定义&quot;什么样的程序员有价值&quot;。&lt;/strong&gt; 而这个&quot;有价值&quot;的标准，比以前更高了。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 data-id=&quot;heading-2&quot;&gt;三、AI擅长0→1，但1→100还得靠你&lt;/h2&gt;
&lt;p&gt;AI确实厉害。给它一个Prompt，10分钟它能搭出一个看起来像模像样的应用。前端界面有了，后端接口有了，数据能存能取，点两下还真跑得起来。&lt;/p&gt;
&lt;p&gt;但这只是&lt;strong&gt;0→1&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;从&quot;能跑的原型&quot;到&quot;能上线的真实产品&quot;，中间的距离，比大多数人想象的要远得多。&lt;/p&gt;
&lt;p&gt;AI做出来的东西，也许能跑，但&quot;也许并不是你想要的&quot;。它的理解跟你的意图之间，永远存在偏差——理解偏差、设计偏差、细节偏差。你以为它懂了，它其实只懂了个大概。&lt;/p&gt;
&lt;p&gt;到了1→100的阶段：消息丢了怎么补？并发上来怎么扛？数据一致性怎么保证？跨服务器怎么路由？&lt;/p&gt;
&lt;p&gt;你可能会说：&quot;这些问题我告诉AI，它也能处理啊。&quot;&lt;/p&gt;
&lt;p&gt;没错。&lt;strong&gt;但前提是——你得先知道有这些问题。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我拿一个具体的场景说明。假设你让AI帮你写一个&quot;用户下单&quot;的功能。如果你只是简单地说&quot;帮我写一个下单接口&quot;，AI很快给你生成代码——接收请求、检查库存、扣减库存、创建订单、返回结果。看起来没毛病，跑起来也没问题。&lt;/p&gt;
&lt;p&gt;但如果你懂行，你知道下单远不止这些：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;两个人同时下单，库存只有一件，会不会超卖？——&lt;strong&gt;并发问题&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;扣了库存但订单创建失败了，库存回不回滚？——&lt;strong&gt;事务一致性问题&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;订单创建成功了但消息通知发送失败了怎么办？——&lt;strong&gt;分布式事务问题&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;10000个人同时抢购，数据库能扛住吗？——&lt;strong&gt;性能问题&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;如果有恶意用户用脚本刷单呢？——&lt;strong&gt;安全问题&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;你知道这些问题的存在，你就能跟AI说：&quot;帮我写下单接口，需要处理并发超卖、保证事务一致性、考虑分布式事务、做限流防刷。&quot;AI收到这个指令，大概率能给你一个不错的方案。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;但如果你不知道&quot;并发超卖&quot;这个概念的存在呢？&lt;/strong&gt; 如果你从来没听过&quot;分布式事务&quot;这个词呢？你压根就不会想到要跟AI提这些要求。AI也不会主动提醒你——因为&lt;strong&gt;它不知道你不知道什么&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这就是问题的核心：&lt;strong&gt;不是AI不会，而是你不知道该让它做什么。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;AI的能力没有上限，但你的知识储备决定了你能从AI那里拿到什么质量的输出。你的Prompt写得越精准、考虑得越全面，AI给你的结果就越好。而精准的Prompt，来自扎实的技术功底。&lt;/p&gt;
&lt;p&gt;所以真正可怕的不是&quot;AI写错了&quot;，而是——&lt;strong&gt;你连AI漏了什么都看不出来，因为你自己就不知道那里应该有什么。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 data-id=&quot;heading-3&quot;&gt;四、&quot;我零基础用AI写了3个App&quot;——我想说 兄弟 😂 别闹了&lt;/h2&gt;
&lt;p&gt;现在社交媒体上到处是这种标题：&lt;em&gt;&quot;不会写代码，用AI一天做了个XX&quot;&lt;/em&gt;。&lt;/p&gt;
&lt;p&gt;我直说：&lt;strong&gt;那只是玩具。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;为什么？看下面这张图就明白了。零基础的人只看到水面上那10%——一个能跑的界面、几个功能按钮。而水面下真正的编程复杂度——并发安全、数据一致性、性能扩展、架构决策——他们压根看不到。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/2a165120d6f94d66bf6536f918f2bd6e~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg6J2O5a2Q6I6x6I6x54ix5omT5oCq:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780386203&amp;amp;x-signature=ZEC%2F02vSOhONGQ1%2Beovx6N%2F%2FW9E%3D&quot; alt=&quot;编程复杂度冰山模型&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;先说清楚，AI对普通人确实很有用。帮你整理Excel数据、生成PPT、写工作总结、处理图片、翻译文档、甚至做个简单的网页展示——这些场景AI表现得非常好。&lt;strong&gt;AI对普通人的意义就是提升工作效率，这个毋庸置疑。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;但&quot;提升工作效率&quot;和&quot;开发一个完整的商业化App&quot;，中间的差距是数量级的。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fstackoverflow.blog%2F2026%2F01%2F02%2Fa-new-worst-coder-has-entered-the-chat-vibe-coding-without-code-knowledge%2F&quot; target=&quot;_blank&quot; title=&quot;https://stackoverflow.blog/2026/01/02/a-new-worst-coder-has-entered-the-chat-vibe-coding-without-code-knowledge/&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;Stack Overflow的官方博客&lt;/a&gt;讲过一个真实故事。他们的一位非技术编辑，用Bolt做了一款App。表面上10分钟搭出来了，界面还挺好看。但交给工程师一看——安全漏洞一堆、数据没有任何保护、代码混乱到无法维护、没有单元测试，甚至Redis是什么都不知道就已经在用了。&lt;/p&gt;
&lt;p&gt;66%的开发者在使用AI工具时都遭遇过所谓的&quot;生产力税&quot;——AI生成的代码&quot;几乎对但又不完全对&quot;，你反而要花更多时间去修它。&lt;/p&gt;
&lt;p&gt;你零基础用AI做的那个App，上线试试？用户数据要不要保护？并发扛不扛得住？支付接进去安不安全？&lt;strong&gt;做出来和能用是两回事，能用和能上线又是两回事。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;所以别自嗨了。&lt;strong&gt;零基础用AI做App，发个朋友圈炫耀一下没问题，但别真以为自己会开发了。&lt;/strong&gt; 因为前面说过的那些坑——并发安全、数据一致性、性能扩展、异常处理——你一个都不知道，AI也不会替你操心。&lt;/p&gt;
&lt;p&gt;行外人觉得&quot;AI编程很简单&quot;，因为他们压根看不到水面下的冰山。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 data-id=&quot;heading-4&quot;&gt;五、真实案例：一个IM系统到底有多复杂&lt;/h2&gt;
&lt;p&gt;说这些可能还是太抽象。我拿我自己做的项目举例。&lt;/p&gt;
&lt;p&gt;我花了两年业余时间，一个人做了一个即时通讯系统——XZLL IM。Java微服务后端 + Flutter客户端，从零开始。&lt;/p&gt;
&lt;p&gt;很多人觉得&quot;做个聊天软件能有多难？不就是一个发送按钮一个消息列表吗？&quot;&lt;/p&gt;
&lt;p&gt;来，我列一下一个IM系统&lt;strong&gt;真正要解决的问题&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. 消息可靠性&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;你发出的消息，对方一定要收到。不能丢，不能重复。听起来简单？这需要你理解TCP的三次握手、ACK确认机制、消息去重策略。消息发出去但网络断了怎么办？重试几次？重试期间对方收到了怎么办？幂等性怎么保证？&lt;/p&gt;
&lt;p&gt;如果这些问题你回答不了，那你用AI写的聊天功能，大概率在弱网环境下就出bug了——而你连为什么出bug都不知道。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. 高并发长连接&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;几万人同时在线，每人一个WebSocket长连接。操作系统告诉你：一个进程能开的文件描述符是有限的。怎么突破？需要理解Netty的Reactor线程模型，理解Boss Group和Worker Group怎么分工，理解Epoll和NIO的区别。&lt;/p&gt;
&lt;p&gt;AI可以帮你生成Netty的启动代码，但它不会告诉你&quot;你的线程模型在高并发下可能会阻塞&quot;。&lt;strong&gt;只有你自己懂，才能提前规避。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. 数据存储分层&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;用户和好友关系存MySQL，聊天记录存MongoDB，缓存和未读计数存Redis，消息搜索用Elasticsearch。为什么不用一个数据库搞定？因为每种数据库的特性和适用场景完全不同——这需要对存储引擎、索引原理、CAP理论有理解。&lt;/p&gt;
&lt;p&gt;这个技术选型决策，AI做不了。它不了解你的读写比例、数据量级、查询模式。&lt;strong&gt;选型是架构师的事，不是AI的事。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. 离线消息&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;用户下线了，发给他的消息怎么办？存哪？上线后怎么拉取？拉取的时候怎么保证不漏不重？我用Redis的ZSet按时间戳存储离线消息，上线后按时间范围拉取——这个设计决策，AI能帮你想出来吗？也许能，但前提是你得知道ZSet是什么、为什么用它、它有什么限制。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5. 跨服务器消息路由&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;用户A连接在服务器131上，用户B连接在服务器132上，A给B发消息怎么送达？需要一个gRPC的跨服务器转发机制。如果B同时登录了手机和电脑呢？多端同步怎么办？这些架构决策，不是AI帮你写几行代码就能解决的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;6. 群消息广播&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;一个群500人，一条消息要推给500个设备。500个人里有的在线有的离线，有的在一台服务器上有的分散在十台服务器上。不能一个人一个人地推，需要通过RocketMQ做消息广播，需要设计消息扇出策略——这背后是对消息队列、发布订阅模型的理解。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;这还只是冰山一角。&lt;/strong&gt; 还有Protobuf协议设计、JWT鉴权、API网关路由、MongoDB到Elasticsearch的数据同步、音视频通话的信令设计……&lt;/p&gt;
&lt;p&gt;你说，这些是AI能帮你从0→1搞出来的吗？&lt;/p&gt;
&lt;p&gt;也许它能帮你写出一些框架代码、生成一些CRUD接口。但&lt;strong&gt;每一个环节的设计决策、性能权衡、异常处理&lt;/strong&gt;，都需要人有足够的知识储备。我在开发过程中也大量使用了AI工具（Claude Code、Cursor等）来加速编码，但核心的架构设计、消息流转路径、协议定义，全部基于我对底层技术的理解。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AI帮我写得更快，但不会帮我设计得更好。&lt;/strong&gt; 设计，只能靠我自己。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 data-id=&quot;heading-5&quot;&gt;六、程序员的角色转变：从&quot;开发者&quot;到&quot;架构师&quot;&lt;/h2&gt;
&lt;p&gt;所以结论来了：&lt;strong&gt;AI时代程序员不是要被淘汰，而是要升级。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;什么意思？不是所有人都会失业，但所有人的角色都会变化。以前的程序员和未来的程序员，干的是不一样的事。&lt;/p&gt;
&lt;p&gt;来看看前后的对比：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/f4458c340f7e4118a3097874e90a353b~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg6J2O5a2Q6I6x6I6x54ix5omT5oCq:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780386203&amp;amp;x-signature=XsE7iFG9YHcwJw8UCguC7vdseos%3D&quot; alt=&quot;image-20260526150634981&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;以前一个程序员的工作流：需求 → 设计 → 编码 → 测试 → 部署，大部分时间花在&quot;编码&quot;上。&lt;/p&gt;
&lt;p&gt;现在呢？需求 → 架构设计 → &lt;strong&gt;指挥AI编码&lt;/strong&gt; → 审查验证 → 调优。&lt;/p&gt;
&lt;p&gt;编码的部分被AI加速了，但你的核心能力变成了三样东西：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. 架构能力&lt;/strong&gt;——系统怎么拆？模块怎么分？技术怎么选？用MySQL还是MongoDB？用HTTP还是gRPC？消息同步用推模式还是拉模式？这些决策AI做不了，因为它不理解你的业务、你的用户量、你的约束条件。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. 验证能力&lt;/strong&gt;——AI写的对不对？有没有安全隐患？性能能不能扛住？并发下会不会出问题？代码结构合不合理？你如果连TCP三次握手都说不清楚，怎么验证AI给你的网络方案？&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. 驾驭能力&lt;/strong&gt;——怎么给AI精确的指令？怎么把一个复杂任务拆解成AI能处理的小任务？怎么在AI跑偏时及时纠正？这就像一个导演指挥演员——你不懂表演，你就导不了戏。&lt;/p&gt;
&lt;p&gt;Google的资深工程师Addy Osmani&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fmedium.com%2F%40addyosmani%2Fvibe-coding-is-not-the-same-as-ai-assisted-engineering-3f81088d5b98&quot; target=&quot;_blank&quot; title=&quot;https://medium.com/@addyosmani/vibe-coding-is-not-the-same-as-ai-assisted-engineering-3f81088d5b98&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;说过一句话&lt;/a&gt;：&quot;Vibe Coding不等于AI辅助工程。前者是盲信AI的输出，后者是驾驭AI的能力。&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;而这三种能力——架构能力、验证能力、驾驭能力——全部建立在扎实的技术基础之上。&lt;/strong&gt; 没有基础，你就是个只会说&quot;帮我写个App&quot;的外行，而不是能驾驭AI的工程师。&lt;/p&gt;
&lt;p&gt;打个比方：以前你是驾驶员，自己开车。现在你是&lt;strong&gt;车队策略师&lt;/strong&gt;，AI是你的车手。车手负责执行，但你得比车手更懂赛道——才能制定正确的策略，才能在车手跑偏的时候把他拉回来。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;你不需要亲手换每一个挡，但你必须知道什么时候该换挡。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 data-id=&quot;heading-6&quot;&gt;七、哪些程序员会被淘汰？哪些不会？&lt;/h2&gt;
&lt;p&gt;说到这里，我想更直白地回答一个很多人关心的问题：&lt;strong&gt;到底谁会被淘汰？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;画了一张分界图，一目了然：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/c41172514c374767af724df3e2e4ad1d~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg6J2O5a2Q6I6x6I6x54ix5omT5oCq:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780386203&amp;amp;x-signature=yLMCUPcN25omzI0%2BUkmN%2B7C0wK4%3D&quot; alt=&quot;image-20260526150715953&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;h3 data-id=&quot;heading-7&quot;&gt;先说会被淘汰的&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;1. 只会CRUD的&quot;增删改查工程师&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如果你的日常工作就是：接到需求 → 打开IDE → 写一个Controller → 写一个Service → 写一个Mapper → 测试通过 → 提交代码。这种工作模式，AI现在就能替代80%。不是未来，是现在。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. 不理解原理只会用框架的&quot;调参侠&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;会用Spring Boot，但不知道Spring的IoC容器是怎么工作的；会用Redis，但说不清Redis为什么快、什么场景该用什么数据结构；会用MQ，但不知道消息丢了怎么办。这种人，AI生成的代码跟他写的差不多，但AI快100倍。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. 缺乏系统思维的&quot;单点程序员&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;只会写自己那一块代码，不理解上下游，不理解整个系统怎么运转。出了问题只能靠日志猜，猜不到就找大佬。这种人，AI也替代不了大佬，但能替代他。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-8&quot;&gt;再说不会被淘汰的&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;1. 能做架构决策的人&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;知道一个系统该怎么拆、技术该怎么做选型、性能瓶颈在哪、怎么横向扩展。这种能力不是AI能给的——它需要对业务的深刻理解和对技术的全局把控。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. 能排查疑难杂症的人&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;线上CPU飙到100%怎么排查？消息队列积压了100万条消息怎么办？数据库死锁了怎么分析？这些问题，AI给你一段排查命令容易，但&lt;strong&gt;判断问题出在哪、该怎么做决策&lt;/strong&gt;，需要经验和对底层原理的理解。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. 能驾驭AI的人&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;知道怎么把一个复杂需求拆解成AI能理解的任务，知道AI生成的代码哪里可能有坑，知道什么时候该让AI干活、什么时候该自己动手。这种人，AI是他的倍增器。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;看清这个分界线，就知道自己该往哪个方向努力了。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 data-id=&quot;heading-9&quot;&gt;八、那到底该怎么做？程序员的学习路线&lt;/h2&gt;
&lt;p&gt;不是让你不用AI工具，而是：&lt;strong&gt;先用基础武装自己，再用AI放大能力。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;那具体该学什么？我结合自己做IM项目的经历，按优先级列一个路线：&lt;/p&gt;
&lt;p&gt;我画了一个学习路线金字塔：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/2aad499e38ed496cbdf071bb76ed524c~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg6J2O5a2Q6I6x6I6x54ix5omT5oCq:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780386203&amp;amp;x-signature=48ZPB43QM0rk9hdO76HTU6%2FYXyw%3D&quot; alt=&quot;image-20260526150756974&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;h3 data-id=&quot;heading-10&quot;&gt;第一层：计算机基础（最重要，别跳过）&lt;/h3&gt;
&lt;p&gt;这是所有编程能力的根基。没有这一层，上面盖什么都是空中楼阁。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;网络原理&lt;/strong&gt;（TCP/IP、HTTP、WebSocket）——我设计IM的消息传输方案时，如果不懂TCP的可靠性机制和WebSocket的全双工通信，根本无法做出合理的选择。AI可以帮你写Netty代码，但它不会告诉你&quot;这个场景应该用WebSocket而不是HTTP轮询&quot;。&lt;strong&gt;学了网络原理，你才能判断AI给你的网络方案对不对。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;操作系统&lt;/strong&gt;（进程/线程、内存管理、IO模型、Epoll）——高并发程序的本质是在跟操作系统打交道。你不懂IO多路复用，就理解不了Netty为什么快；不懂线程调度，就不知道线程池参数该怎么配；不懂内存模型，就排查不了内存泄漏。&lt;strong&gt;这些是AI写代码时的&quot;隐形假设&quot;，你不懂就发现不了。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;数据结构与算法&lt;/strong&gt;——不是让你去刷LeetCode应付面试，而是真正理解。知道B+树怎么工作的，才能理解MySQL索引为什么高效；知道哈希表的冲突处理，才能理解Redis的渐进式Rehash；知道图的遍历算法，才能设计消息路由策略。&lt;strong&gt;AI能帮你实现算法，但只有你理解了，才知道该让AI实现哪个算法。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 data-id=&quot;heading-11&quot;&gt;第二层：数据库与存储（吃饭的家伙）&lt;/h3&gt;
&lt;p&gt;几乎所有程序都绕不开数据存储。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;关系型数据库&lt;/strong&gt;（索引原理、事务ACID、锁机制、隔离级别、慢查询优化）——IM系统里用户、好友、群组、会话全部存在MySQL。如果你不理解索引的B+树结构、事务的隔离级别、行锁和表锁的区别，你连AI生成的SQL有没有问题都看不出来。&lt;strong&gt;SQL写错了AI不会提醒你，但你线上数据出问题了那可是真金白银。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NoSQL&lt;/strong&gt;（Redis数据结构与适用场景、MongoDB的文档模型、Elasticsearch的倒排索引）——IM系统用了MongoDB存消息、Redis做缓存和未读计数、Elasticsearch做搜索。每种存储用在哪里、为什么用它、它有什么限制——这些选型决策全是架构层面的，AI做不了。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-12&quot;&gt;第三层：并发与分布式（进阶必备）&lt;/h3&gt;
&lt;p&gt;这一层是区分&quot;会写代码&quot;和&quot;会做工程&quot;的分水岭。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;并发编程&lt;/strong&gt;（线程模型、锁机制、CAS、线程池、volatile）——万人在线的消息推送，如果不懂线程池的参数配置和锁的粒度控制，AI写出来的代码在并发场景下分分钟出bug——而你根本看不出问题在哪。&lt;strong&gt;并发bug是最难调试的bug，因为它不是每次都复现。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;分布式系统&lt;/strong&gt;（消息队列、RPC、服务发现、CAP理论、分布式事务）——IM系统涉及gRPC跨服务器通信、RocketMQ消息广播、Nacos服务注册发现。这些架构决策，AI能帮你写实现代码，但选型决策必须你自己做。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-13&quot;&gt;第四层：架构思维（高级方向）&lt;/h3&gt;
&lt;p&gt;这一层不是学出来的，是在前三层的基础上，通过实战项目&lt;strong&gt;练&lt;/strong&gt;出来的。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;怎么从需求推导出技术架构？&lt;/li&gt;
&lt;li&gt;怎么评估一个方案的性能瓶颈？&lt;/li&gt;
&lt;li&gt;怎么在多种技术方案之间做权衡取舍？&lt;/li&gt;
&lt;li&gt;怎么设计一个可扩展、可维护的系统？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些能力的培养没有捷径，只有一个办法：&lt;strong&gt;做真实项目。&lt;/strong&gt; 不是做一个Todo List，而是做一个真正有复杂度的系统。比如一个IM系统、一个电商系统、一个推荐引擎——任何能让你面对&quot;真实复杂度&quot;的东西。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-14&quot;&gt;同时：学会驾驭AI工具&lt;/h3&gt;
&lt;p&gt;以上四层是基础，同时你要学会使用AI工具（Claude Code、Cursor、Copilot等），它们确实能极大提升效率。但&lt;strong&gt;永远保持对代码的理解和掌控&lt;/strong&gt;——你不是在&quot;让AI帮你写代码&quot;，你是在&quot;用AI加速你的想法落地&quot;。&lt;/p&gt;
&lt;p&gt;一句话：&lt;strong&gt;不懂代码，就无法真正驾驭AI。懂代码，AI就是你的倍增器。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 data-id=&quot;heading-15&quot;&gt;九、一个新概念：Harness Engineering&lt;/h2&gt;
&lt;p&gt;说到这里，我想引出一个2026年正在快速升温的概念——&lt;strong&gt;Harness Engineering&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;Google的资深工程师Addy Osmani在&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Faddyosmani.com%2Fblog%2Fagent-harness-engineering%2F&quot; target=&quot;_blank&quot; title=&quot;https://addyosmani.com/blog/agent-harness-engineering/&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;O&#39;Reilly上发表过一篇文章&lt;/a&gt;，标题就叫《Agent Harness Engineering》。他还专门做了一个&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fbeyond.addy.ie%2F&quot; target=&quot;_blank&quot; title=&quot;https://beyond.addy.ie/&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;AI辅助工程的实践指南&lt;/a&gt;。他说了一句很关键的话：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&quot;一个裸的AI模型不是Agent，Harness（驾驭装置）让它成为了Agent。&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;什么意思？&lt;/p&gt;
&lt;p&gt;就好比一匹千里马，它跑得再快，没有缰绳、马鞍、方向指引，你也骑不了。Harness Engineering就是这个缰绳和马鞍——它指的是&lt;strong&gt;围绕AI Agent设计的那套约束、反馈循环、验证机制和上下文管理&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;具体来说，一个Harness包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;约束设计&lt;/strong&gt;：AI能做什么、不能做什么、边界在哪&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;上下文管理&lt;/strong&gt;：给AI提供正确的项目背景、代码规范、架构约定&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;验证机制&lt;/strong&gt;：AI生成的代码怎么验证对不对、跑测试、过Review&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;反馈循环&lt;/strong&gt;：AI做错了怎么纠正、怎么让它从错误中学习&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;工具接口&lt;/strong&gt;：AI能用哪些工具、怎么调用、权限怎么控制&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;你看出来了吗？&lt;strong&gt;这恰好就是这篇文章一直在说的&quot;驾驭AI&quot;的具体实践。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;前面我说了，AI时代程序员的核心能力是架构能力、验证能力、驾驭能力。Harness Engineering就是这三样能力的工程化落地。它不是一句口号，而是一套可操作的方法论。&lt;/p&gt;
&lt;p&gt;拿我自己做IM项目来说，我并不是简单地跟AI说&quot;帮我写个IM系统&quot;就完事了。我会先告诉它整个系统的架构分层——网关层负责鉴权路由，长连接层用Netty做WebSocket，业务层处理消息存储和好友关系，数据同步层消费MQ写ES。我会规定消息的Protobuf协议格式，约定Chat ID的生成规则，说明离线消息用Redis ZSet存储的策略。我会把一个复杂功能拆成十几步，让AI一步一步来，每一步都验证结果。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;这个过程，本质上就是在给AI搭建一个Harness——告诉它约束是什么、上下文是什么、怎么验证做得对不对。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;而这一切的前提是：我自己先搞懂了Netty的线程模型、Redis的数据结构、消息队列的投递语义、Protobuf的序列化原理。&lt;strong&gt;如果我不懂这些，我连Harness该约束什么都不知道。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;你的基础越扎实，你的Harness就越精密，AI的输出就越可靠。&lt;/p&gt;
&lt;p&gt;关于我是怎么在IM项目中从零搭建Harness、有哪些具体实践和踩过的坑，我会在&lt;strong&gt;下一篇文章&lt;/strong&gt;中详细展开。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 data-id=&quot;heading-16&quot;&gt;十、最后说几句掏心窝的话&lt;/h2&gt;
&lt;p&gt;这篇文章写到这里，我想回到一个最根本的问题：&lt;strong&gt;基础技术到底有多重要？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我用整篇文章在说这件事，但让我再总结一次：&lt;/p&gt;
&lt;p&gt;AI能帮你写代码，但&lt;strong&gt;不能帮你理解代码&lt;/strong&gt;。AI能帮你搭框架，但&lt;strong&gt;不能帮你做架构决策&lt;/strong&gt;。AI能帮你快速出原型，但&lt;strong&gt;不能帮你把原型变成生产级产品&lt;/strong&gt;。这些能力的背后，全部是基础——网络原理、操作系统、数据库、并发、分布式。没有这些，你跟AI之间的对话就只能是&quot;帮我写个XX&quot;，而不是&quot;帮我实现这个架构方案，注意处理并发和事务&quot;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;基础决定了你能从AI那里拿到什么质量的输出。&lt;/strong&gt; 这就是为什么AI越强，越要学基础。&lt;/p&gt;
&lt;p&gt;那程序员到底怎么避免被AI淘汰？&lt;/p&gt;
&lt;p&gt;说难听点，路就两条：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第一条：死磕技术，往上走。&lt;/strong&gt; 把基础打牢，从&quot;写代码的人&quot;升级为&quot;做架构决策的人&quot;。学会驾驭AI，让AI成为你的倍增器。这条路不难理解，但需要时间和汗水——没有捷径。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第二条：认清现实，趁早转行。&lt;/strong&gt; 如果你既不想补基础，又不想升级能力，只想靠AI混日子——那说实话，趁早转行可能是更理性的选择。不是每个人都要当程序员，但如果你想留在这个行业，就必须提供AI提供不了的价值。温水煮青蛙，煮到最后是最惨的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;没有第三条路。&lt;/strong&gt; 指望&quot;AI替代不了我&quot;是自欺欺人，指望&quot;我会用AI就行了&quot;是掩耳盗铃。&lt;/p&gt;
&lt;p&gt;AI是一个放大器——放大高手的能力，也放大菜鸟的无知。基础扎实的人用AI，效率提升10倍；基础不牢的人用AI，只是把错误放大了10倍。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;AI不会淘汰程序员，但会让不懂基础的&quot;程序员&quot;裸泳。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;所以回到标题那句话：&lt;strong&gt;零基础用AI写App？醒醒吧，那只是个玩具罢了。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;真正有价值的，不是你用AI做出了什么，而是&lt;strong&gt;你理解了多少&lt;/strong&gt;。理解得越深，AI能帮你做的就越多。理解得越浅，AI只能帮你做玩具。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;说完了技术和职业，最后我想说点题外话。&lt;/p&gt;
&lt;p&gt;不管你是刚入行的新手，还是干了十几年的&quot;程序大叔&quot;，我想说一句：&lt;strong&gt;保持空杯心态。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;AI这波变化来得太快，快到所有人都有点慌。新手慌&quot;还要不要学&quot;，老手慌&quot;会不会被替代&quot;。但你冷静想想，哪一轮技术革命不是这样？从汇编到高级语言，从单体到微服务，从手工部署到DevOps——每一次都有人喊&quot;要完蛋了&quot;，但每一次挺过来的人，都变得更强了。&lt;/p&gt;
&lt;p&gt;这次也一样。AI不是洪水猛兽，它就是一波新的技术浪潮。你不需要比浪潮跑得快，你只需要&lt;strong&gt;站在对的方向上，别被冲走就行。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;所以尽可能别焦虑。好好学你的基础，好好做你的项目，好好生活，保持一个好心态。技术这条路很长，不是百米冲刺，是马拉松。&lt;strong&gt;能跑到最后的，从来不是跑得最快的，而是心态最稳的。&lt;/strong&gt;&lt;/p&gt;</description><link>https://juejin.cn/post/7644029980892905518</link><guid isPermaLink="false">https://juejin.cn/post/7644029980892905518</guid><pubDate>Tue, 26 May 2026 07:43:23 GMT</pubDate><author>蝎子莱莱爱打怪</author><category>人工智能</category><category>后端</category><category>前端</category></item><item><title>普通程序员有没有必要学习 Agent 开发？</title><description>&lt;p&gt;大家好，我是双越。&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fwww.wangeditor.com%2F&quot; target=&quot;_blank&quot; title=&quot;https://www.wangeditor.com/&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;wangEditor&lt;/a&gt; 作者，前百度 滴滴 资深前端工程师，慕课网金牌讲师，PMP，&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fwww.mianshipai.com%2F&quot; target=&quot;_blank&quot; title=&quot;https://www.mianshipai.com/&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;前端面试派&lt;/a&gt; 作者。&lt;/p&gt;
&lt;p&gt;我正致力于两个项目的开发和升级，感兴趣的可以私信我，加入项目小组。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fwww.huashuiai.com%2F&quot; target=&quot;_blank&quot; title=&quot;https://www.huashuiai.com/&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;【划水AI】&lt;/a&gt; Node 全栈 AIGC 知识库，包括 AI 写作、多人协同编辑。复杂业务，真实上线。&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fzhitalk.chat%2F&quot; target=&quot;_blank&quot; title=&quot;https://zhitalk.chat/&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;【智语】&lt;/a&gt; AI Agent 智能体项目。一个智能面试官，可以优化简历、模拟面试、解答题目等。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;“人人都用 AI ，我们需要更懂 AI 的人” —— 这将是未来所有招聘岗位的要求之一&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/2abea8dc292d4b5e802ae42de9e96583~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5Y-M6LaKQUlfY2x1Yg==:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780365578&amp;amp;x-signature=2%2B4EqPbCB9%2FtFZmZgrPzS%2BKnChE%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;h2 data-id=&quot;heading-0&quot;&gt;开始&lt;/h2&gt;
&lt;p&gt;从 2025 年 agent 就开始流行了，当时是因为 MCP 协议推广，让 agent 扩展第三方能力。&lt;/p&gt;
&lt;p&gt;后来 Skills 推广开来，让大家看到了 AI + skills 就可以成为领域专家，深入到各个垂类。&lt;/p&gt;
&lt;p&gt;再到 2026 年春天，OpenClaw 小龙虾突然火爆网络，再后来 hermes 出现要代替 Openclaw 。&lt;/p&gt;
&lt;p&gt;以及 claude code 源码泄漏，大家了解了它内部的结构，还有现在 codex 正在推广使用。&lt;/p&gt;
&lt;p&gt;2026 年是 agent 最火爆的一年，全世界都在开发用 agent ，也都在开发 agent 。&lt;/p&gt;
&lt;p&gt;问题来了：作为普通程序员，我们肯定都用 agent ，至少 AI 编程吗。&lt;strong&gt;但我们有没有必要深入学习 AI Agent 呢？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;答案当然是肯定的。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-1&quot;&gt;可以更好的使用 Agent&lt;/h2&gt;
&lt;p&gt;无论任何领域，使用任何工具和技术，你知道它的原理和设计，才能更好的使用它。&lt;/p&gt;
&lt;p&gt;例如我知道一位同学，使用 Cursor 编程，一个聊天一直用，他本能的觉得这样有上下文更多信息，AI 可能会回答的更好。但其实这样更容易造成上下文污染，更容易让 AI 产生幻觉？&lt;/p&gt;
&lt;p&gt;这是 Agent 核心模块之一：Context 上下文管理和压缩。&lt;/p&gt;
&lt;p&gt;还有 Claude Code 或者 Cursor 提供了很多高级技巧，例如 subagent hooks 等，你会本能的抗拒它们，因为不熟悉。只会配置一些 skills&lt;/p&gt;
&lt;p&gt;如果你详细学习过 harness 工程的，对这些概念和模块就自然熟悉了，不用也知道它们是干嘛的。&lt;/p&gt;
&lt;p&gt;你担心 AI 写的代码不安全，其实熟悉 agent 设计以后，你就会明白：agent 内部有严格的权限和安全机制。而且你可以设置 prompt 让它来写单元测试，达到某个测试标准。&lt;/p&gt;
&lt;p&gt;这就像当年前端面试考源码一样，Vue React 都会用，但熟悉源码的人会用的更好。虽然你作为候选人抱怨内卷，但如果你是面试官，你也会考源码。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-2&quot;&gt;有机会转型 AI 工程师&lt;/h2&gt;
&lt;p&gt;看看你现在用的所有网站、软件、app ，哪个都有一个 AI 接口，什么 AI 搜索、AI 总结等等。&lt;/p&gt;
&lt;p&gt;应用场景多，肯定会带来专业的开发岗位。现在 AI 工程师的招聘岗位已经很多了，而且会逐步增加。&lt;/p&gt;
&lt;p&gt;当然，不是说所有的人都去转型做 AI 工程师，这毕竟是一部分开发岗位，大部分程序员还是该干啥干啥。&lt;/p&gt;
&lt;p&gt;就像当年的小程序，各个公司都需要开发自己的小程序，就会催生很多招聘需求，但不是所有的人都去做小程序。&lt;/p&gt;
&lt;p&gt;但是，&lt;strong&gt;早期加入的人都会吃到最大的红利&lt;/strong&gt;，会以最低的要求、最高的工资入职，还有最好的晋升机会。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-3&quot;&gt;对于前端开发者&lt;/h2&gt;
&lt;p&gt;虽然 AI 编程的普及和 LLM 的进化，纯前端开发人员一定会慢慢消失。&lt;/p&gt;
&lt;p&gt;因为绝大部分前端界面，AI 编程可以快速实现，后端人员一样能干。而后端的一些逻辑和数据，AI 不一定能完全搞懂。在 AI 编程的加持下，前后端还是有很大区别的。&lt;/p&gt;
&lt;p&gt;所以无论是前端还是后端，大部分都会转型全栈开发。后端好转，前端不好转，有些前端开发者连 HTTP 协议都还没搞明白。&lt;/p&gt;
&lt;p&gt;想要有好的竞争力，除了转型全栈开发，及早去搞 Agent 开发也是一个不错的选择。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-4&quot;&gt;最后&lt;/h2&gt;
&lt;p&gt;不要说我贩卖焦虑，你我都是人在江湖，冷暖自知。焦虑不焦虑的，看自己感觉，别光信我说的。&lt;/p&gt;
&lt;p&gt;“人人都用 AI ，我们需要更懂 AI 的人” —— 这将是未来招聘程序员的要求之一。&lt;/p&gt;</description><link>https://juejin.cn/post/7643757385781936154</link><guid isPermaLink="false">https://juejin.cn/post/7643757385781936154</guid><pubDate>Tue, 26 May 2026 01:59:38 GMT</pubDate><author>双越AI_club</author><category>人工智能</category><category>Agent</category><category>前端</category><category>全栈</category></item><item><title>Codex 把我家烂网给优化后，我 TM 直接原地起飞了。</title><description>&lt;p&gt;昨天看到一个非常有意思的事情，有人研究了一下用 Codex 直接把家里网络修复了一下，修复之后的网络直接原地起飞，实测速度堪比光速。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/f00725dc42b54f029d3345eb9ca800c4~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgY3h1YW5BSQ==:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780310770&amp;amp;x-signature=1z%2B2AXoTzLKFK7xVFHY6Vq%2Fz5lg%3D&quot; alt=&quot;image-20260524111109592&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;这本来没啥可说的。&lt;/p&gt;
&lt;p&gt;但后面有意思的是，另外一个网友直接把原贴扔给了 Codex ，随后附上了自己的 prompt&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-vbnet&quot; lang=&quot;vbnet&quot;&gt;Hey my &lt;span class=&quot;hljs-keyword&quot;&gt;friend&lt;/span&gt; says he improved his internet speed &lt;span class=&quot;hljs-built_in&quot;&gt;and&lt;/span&gt; here &lt;span class=&quot;hljs-built_in&quot;&gt;is&lt;/span&gt; what happened. Can you check &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; there are any improvements we can make &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; our internet? My provider says they&lt;span class=&quot;hljs-comment&quot;&gt;&#39;re sending 1.2k gbps and anything I get is a result of hardware. I&#39;m getting 55mbps right now pls fix make no mistakes.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这句话的意思是说。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我朋友说他的网速提高了，情况是这样的。你能帮我看看我们家的网络有什么可以改进的地方吗？我的网络供应商说他们提供的带宽是 1.2k Gbps，而我实际的网速是硬件问题导致的。我现在只有 55Mbps，请帮我解决这个问题，别出任何差错。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;然后放了一下优化前和优化后的实测对比图。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/4585af9a3a3e4042979c4e667994811c~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgY3h1YW5BSQ==:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780310770&amp;amp;x-signature=WcK7FwJD1xwS6pVbVByULsodp54%3D&quot; alt=&quot;image-20260524070446799&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;这哥们的聪明之处在于，他直接把“别人成功优化的真实案例”当作上下文喂给 Codex，让 Codex 参考那个案例，给自己当前的烂网速做针对性诊断和修复。&lt;/p&gt;
&lt;p&gt;也就是说，只要有人从 0 -&amp;gt; 1 真实跑通一个案例，你发出来之后其他人就可以很方便的裂变，变成 1 -&amp;gt; N。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这里我有个问题，为什么这个人的成功经验不是直接让 LLM 来直接回答呢（手动狗头）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;然后 x 上确实有很多人通过这种方式优化了网络性能。&lt;/p&gt;
&lt;p&gt;我自己也根据这个 prompt 进行了实操，确实网络直接原地起飞了。一条要求 Codex 针对网速改善的对比的请求，工作了 25s 就完成了。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/d81ffc99330c4b5ab80454e73b07c9e1~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgY3h1YW5BSQ==:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780310770&amp;amp;x-signature=lG%2BaF2VVhh0Oyx2406uKbedWn3A%3D&quot; alt=&quot;503bd396-8462-490f-afd7-5279e99964d8&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;然后这是优化之后的直观对比。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/ce1982a203fb42f5b95f33abd277b274~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgY3h1YW5BSQ==:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780310770&amp;amp;x-signature=8IuigqZOX3ru%2BUsqtKhKuyGmiSs%3D&quot; alt=&quot;image-20260524070258122&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;看起来效果提升的并不是特别明显，但我从用户亲身体验的角度来说，确实达到了直接原地起飞的效果。&lt;/p&gt;
&lt;p&gt;要知道，我肉身是在国内。。。。。。&lt;/p&gt;
&lt;p&gt;使用这种方式记得有一点，先评估再进行操作，先让 LLM 做好执行备份。否则容易把你的 xx 给直接 kill 掉。&lt;/p&gt;
&lt;p&gt;比如这个哥们的操作就直接给我笑麻了。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/c17149bd28e54be09af0f1b51c465fe6~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgY3h1YW5BSQ==:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780310770&amp;amp;x-signature=4tHMx3QbB6SCkc07YrD96fZJ%2FcM%3D&quot; alt=&quot;image-20260524102218162&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;我自己实测的过程中也出现过 codex 乱杀的情况，但是幸好我这个影响不太大。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;直接给出大家 prompt 好了，你可以直接去 agent 上（任何 LLM 都可以尝试）进行修复。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-markdown&quot; lang=&quot;markdown&quot;&gt;诊断问题：首先运行了 speedtest-cli。
&lt;span class=&quot;hljs-quote&quot;&gt;&amp;gt; 检查了 DNS 解析时间，&lt;/span&gt;
&lt;span class=&quot;hljs-quote&quot;&gt;&amp;gt; 检查了 MTU、数据包丢失、Wi-Fi 信号/干扰。&lt;/span&gt;
&lt;span class=&quot;hljs-quote&quot;&gt;&amp;gt; 发现了 3 个问题。&lt;/span&gt;
&lt;span class=&quot;hljs-quote&quot;&gt;&amp;gt; 删除了过期的网络位置/配置文件。&lt;/span&gt;
&lt;span class=&quot;hljs-quote&quot;&gt;&amp;gt; 终止或限制了占用带宽的后台进程。&lt;/span&gt;
&lt;span class=&quot;hljs-quote&quot;&gt;&amp;gt; 优化了 mDNS。&lt;/span&gt;
&lt;span class=&quot;hljs-quote&quot;&gt;&amp;gt; 运行了前后速度测试和延迟检查。&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;有人使用 &lt;code&gt;/goal&lt;/code&gt; 命令直接修复，我没有使用 /goal 命令，不过修复的也不错。&lt;/p&gt;
&lt;p&gt;希望大家都能体会到网速起飞的酥麻感，简直太爽了。&lt;/p&gt;</description><link>https://juejin.cn/post/7643639401154756662</link><guid isPermaLink="false">https://juejin.cn/post/7643639401154756662</guid><pubDate>Mon, 25 May 2026 10:46:11 GMT</pubDate><author>cxuanAI</author><category>后端</category><category>人工智能</category><category>程序员</category></item><item><title>3.9元搞定Codex！国内也能畅用~（附教程，超简单）</title><description>&lt;p&gt;大家好，我是袋鼠帝。&lt;br&gt;
&lt;br&gt;
我发现，最近很多朋友貌似都把自己的主力Agent换成了Codex。&lt;br&gt;
&lt;br&gt;
&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/e3ded4cb658e48b88c2653e0245ebc0c~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780297336&amp;amp;x-signature=bzawcgPCboRXeqmgUUARpxhhlLk%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
我也不例外，Codex现在也是我的主力Agent。&lt;br&gt;
&lt;br&gt;
因为最近Codex更新了几个版本之后，干活真的丝滑了很多，布置一个多步骤的复杂任务给它，基本上不用我中途救场，干活嘎嘎好用，稳得一批。&lt;br&gt;
&lt;br&gt;
比如全自动操控浏览器帮我申请YouTube API Key、根据一套Skills完成产品宣传片，基本上都能一次性搞定，而且完成质量还挺高。&lt;br&gt;
&lt;br&gt;
但从评论区，以及一些朋友的私聊中，我发现有个问题是：Codex对国内小伙伴来说，使用门槛还是高了。&lt;br&gt;
&lt;br&gt;
&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/8fee6f2f6d554c77a5092d0807dfe139~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780297336&amp;amp;x-signature=bID%2BR3bNZvdN2Y9mzdmhLWT6Spc%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
魔法上网、注册、跨境支付、短信验证、API配置……一整套从0搞下来，光是门槛就足以把90%的人拦在门外。&lt;br&gt;
&lt;br&gt;
我的评论区和私聊，几乎每周都有人在问这些问题。&lt;br&gt;
&lt;br&gt;
还有一个问题是，我Codex便开了一个月20美元的Plus，额度也是很快就会用完。&lt;br&gt;
&lt;br&gt;
我之前试过猛用一天，额度就没了。后面不得已，直接开了100美元一个月的Pro，还是挺肉疼的💸&lt;br&gt;
&lt;br&gt;
不过最近我发现一个邪修办法，最低3.9元就能畅用Codex一个月。&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
实现原理&lt;br&gt;
&lt;br&gt;
首先Codex是可以配置接入别的模型的，所以这个方案，我们就不用官方的，直接给Codex接入其他模型。&lt;br&gt;
&lt;br&gt;
然后就是找一个便宜的Coding Plan套餐~&lt;br&gt;
&lt;br&gt;
找了一圈，发现讯飞星辰的Coding Plan最便宜。最低只要3.9元/月，而且居然还是不限量。&lt;br&gt;
&lt;br&gt;
&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/e49fd44ad7dc488ab0cdcbc8de6de0fc~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780297336&amp;amp;x-signature=NItzHg%2Fek86yFXX4IyoI0IWl7cc%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
缺点是模型选择有点少，只有5种，但3.9元一个月，一瓶饮料的钱，还要啥自行车🚲&lt;br&gt;
&lt;br&gt;
而且配置好后，还可以在讯飞星辰的控制台随意切换模型，生效时间在2分钟左右。这点还是挺方便的。&lt;br&gt;
&lt;br&gt;
&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/0b7bec95cf03432baa6921dbe0ef876d~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780297336&amp;amp;x-signature=K7LP7AA2jFQpdDDXIKyoiSjxIF8%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
&amp;nbsp;&lt;br&gt;
&lt;br&gt;
怎么配置&lt;br&gt;
&lt;br&gt;
本来我以为，只需要通过CC-Switch配置一下，就能简单搞定了，结果我错了。&lt;br&gt;
&lt;br&gt;
简单配置的结果是Codex疯狂报错。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/404ac14de342447f977a65d64a41bffd~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780297336&amp;amp;x-signature=iWqpgjupqtErFXqtVMFrQ738WdU%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
&amp;nbsp;&lt;br&gt;
然后我就采用了增加一个适配器的方案，折腾一番之后，最终还是跑通了。&lt;br&gt;
&lt;br&gt;
虽然整个过程还是要费点功夫，不过别担心，我已经把所有步骤封装成了一键脚本，傻瓜式操作。&lt;br&gt;
&lt;br&gt;
现在只需要一行命令，就可以完成全部配置。而且随时可以切换回Codex的官方登录，点一下就搞定，巨方便。&lt;br&gt;
&lt;br&gt;
&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/1fccd9a2ae06499aa9e5e7f8d98dde26~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780297336&amp;amp;x-signature=9OUKWk%2Fq%2B19Bk88DNHq8eZft2dk%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
&amp;nbsp;&lt;br&gt;
为什么要用适配器&lt;br&gt;
&lt;br&gt;
讯飞Coding Plan提供的是OpenAI兼容接口，但它当前更稳定可用的是&amp;nbsp;Chat Completions&amp;nbsp;接口。&lt;br&gt;
&lt;br&gt;
而Codex现在主要走&amp;nbsp;OpenAI Responses API&amp;nbsp;。直接把讯飞接口配置进CC-Switch后，可能会出现：&lt;br&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;stream disconnected before completion&lt;/li&gt;
&lt;li&gt;response failed event received&lt;br&gt;
&lt;br&gt;
主要是接口协议不完全匹配。&lt;br&gt;
&lt;br&gt;
所以这里采用一个本地适配器方案：&lt;br&gt;
Codex → 本地适配器 → 讯飞Coding Plan&amp;nbsp;&lt;br&gt;
&lt;br&gt;
适配器负责把Codex发出的Responses API请求，转换成讯飞能稳定处理的Chat Completions请求，再把结果转回Codex能识别的格式。&lt;br&gt;
&lt;br&gt;
期待讯飞能尽快适配Codex啊&lt;br&gt;
当然，它目前也能够，丝滑接入Claude、Cursor、Claude Code、Open Devin等Agent。&lt;br&gt;
&lt;br&gt;
&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/3fd920c95b7247b296ab7bac3a985601~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780297336&amp;amp;x-signature=890TWkBqXbeMTyXdzHeNstKD0FU%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
&amp;nbsp;&lt;br&gt;
&lt;br&gt;
脚本做了什么&lt;br&gt;
&lt;br&gt;
安装脚本会在本机启动一个只监听本地的服务：&amp;nbsp;&lt;a href=&quot;https://link.juejin.cn/?target=http%3A%2F%2F127.0.0.1%3A8666%25C2%25A0&quot; target=&quot;_blank&quot; title=&quot;http://127.0.0.1:8666%C2%A0&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;http://127.0.0.1:8666&amp;nbsp;&lt;/a&gt;&lt;br&gt;
它不会开放公网端口，也不会影响系统代理。&lt;br&gt;
&lt;br&gt;
脚本会自动完成这些事：&lt;br&gt;
&lt;br&gt;
1.&amp;nbsp;安装本地适配器&lt;br&gt;
2.&amp;nbsp;在开机/登录后自动启动适配器&lt;br&gt;
3.&amp;nbsp;在CC-Switch里新增一个独立配置：Xunfei Astron Adapter&lt;br&gt;
4.&amp;nbsp;自动切换Codex到这个配置&lt;br&gt;
5.&amp;nbsp;输入你自己的讯飞Coding Plan API Key&lt;br&gt;
6.&amp;nbsp;保留原来的OpenAI Official配置，方便随时切回&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
使用前准备&lt;br&gt;
&lt;br&gt;
你需要先做好这些准备：&lt;br&gt;
1.&amp;nbsp;已安装CC Switch（Github搜索安装），76k的开源项目
&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/50f0a8fca1ff4186aa4f2f24236c82f5~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780297336&amp;amp;x-signature=XYRGLafj%2FSUXPWfMT2e6EdDM2nk%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
2.&amp;nbsp;已经打开过一次CC Switch&lt;br&gt;
3.&amp;nbsp;已安装Codex&lt;br&gt;
&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/0f0ebd67904f4ca8b3886a3d6db3ac34~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780297336&amp;amp;x-signature=hu4z%2FrLDmN84nSmqTagDJw1rXfg%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
4.&amp;nbsp;已有讯飞星辰的Coding Plan，并拿到API Key&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/f2e23b61e6c94649a23c8cb917627e27~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780297336&amp;amp;x-signature=DmHIUhhrLEkoDpXOpJWMP6CofPU%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
5.&amp;nbsp;Windows用户需要先安装Python 3&lt;/p&gt;
&lt;p&gt;获取API Key的方式很简单，在讯飞星辰的Coding Plan订阅页面，直接复制就好。&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
macOS执行&lt;br&gt;
&lt;br&gt;
国内用户可执行的脚本：&lt;br&gt;
&lt;br&gt;
plaintext&lt;br&gt;
&lt;br&gt;
curl -fsSL &lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fgitee.com%2Fkangarooking%2Fxfun-codex-adapter%2Fraw%2Fmain%2Finstall.sh&quot; target=&quot;_blank&quot; title=&quot;https://gitee.com/kangarooking/xfun-codex-adapter/raw/main/install.sh&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;gitee.com/kangarookin…&lt;/a&gt; | bash&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
执行后，根据提示粘贴你的讯飞API Key。输入时不会显示明文，这是正常的。执行完成后，重启Codex。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/9e57628b438545928fe3284ce208fc2c~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780297336&amp;amp;x-signature=Mq0Idoh3DHYL%2FPP1p3NwMrs9aPA%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
&amp;nbsp;&lt;br&gt;
卸载指令&lt;br&gt;
&lt;br&gt;
plaintext&lt;br&gt;
&lt;br&gt;
curl -fsSL &lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fgitee.com%2Fkangarooking%2Fxfun-codex-adapter%2Fraw%2Fmain%2Funinstall.sh&quot; target=&quot;_blank&quot; title=&quot;https://gitee.com/kangarooking/xfun-codex-adapter/raw/main/uninstall.sh&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;gitee.com/kangarookin…&lt;/a&gt; | bash&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
卸载会移除本地适配器和后台启动项。如果当前Codex仍然指向适配器，脚本会尝试切回CC Switch里的其他Codex配置。&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
Windows执行&lt;br&gt;
&lt;br&gt;
注意：因为我还在出差，手里没有Windows，所以Windows的脚本没有验证过。大家慎用。Mac的版本我亲自验证过，是ok的。&lt;br&gt;
&lt;br&gt;
打开PowerShell，执行：&lt;br&gt;
&lt;br&gt;
plaintext&lt;br&gt;
&lt;br&gt;
powershell -NoProfile -ExecutionPolicy Bypass -Command &quot;irm &lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fgitee.com%2Fkangarooking%2Fxfun-codex-adapter%2Fraw%2Fmain%2Finstall.ps1&quot; target=&quot;_blank&quot; title=&quot;https://gitee.com/kangarooking/xfun-codex-adapter/raw/main/install.ps1&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;gitee.com/kangarookin…&lt;/a&gt; | iex&quot;&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
执行后，根据提示粘贴你的API Key，安装完成后，重启Codex。&lt;br&gt;
&lt;br&gt;
卸载指令&lt;br&gt;
&lt;br&gt;
plaintext&lt;br&gt;
&lt;br&gt;
powershell -NoProfile -ExecutionPolicy Bypass -Command &quot;irm &lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fgitee.com%2Fkangarooking%2Fxfun-codex-adapter%2Fraw%2Fmain%2Funinstall.ps1&quot; target=&quot;_blank&quot; title=&quot;https://gitee.com/kangarooking/xfun-codex-adapter/raw/main/uninstall.ps1&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;gitee.com/kangarookin…&lt;/a&gt; | iex&quot;&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
Codex换上CodingPlan后，干活怎么样&lt;br&gt;
&lt;br&gt;
配置搞完了，最关键的问题来了：换上国内模型之后，Codex干活到底行不行？&lt;br&gt;
&lt;br&gt;
我用它跑了一下我的&amp;nbsp;ai-trend-search Skill&amp;nbsp;，让它帮我去X上搜今天的AI领域热点选题。&lt;br&gt;
&lt;br&gt;
&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/214083958c354cb580bc48503b76b92d~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780297336&amp;amp;x-signature=HXAo%2B7jHElH%2BRHrv6llfWtbpJb8%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
看看这个执行过程：它先读了skill，发现有ai-trend-search skill，然后查看了Skill的详细内容，接着自动运行雷达模式去搜索。&lt;br&gt;
&lt;br&gt;
整个执行过程跟用GPT-5.5的时候几乎一模一样，完全自主。&lt;br&gt;
&lt;br&gt;
最终结果：8个信源全部正常扫描，120条原始信号里精选出4个高价值选题。&lt;br&gt;
&lt;br&gt;
而且思考过程都会展示出来，感觉跟在Codex用GPT-5.5的交互几乎无感切换。&lt;br&gt;
&lt;br&gt;
不过执行更复杂的任务应该还是搭配GPT-5.5更好，毕竟原汤化原食嘛😆&lt;br&gt;
&lt;br&gt;
说实话，我本来以为换成3.9元的国内模型，体验肯定会打折扣。但实际跑下来，日常任务完全够用，而且不太担心额度的问题。&lt;br&gt;
&lt;br&gt;
感兴趣的朋友可以去试试👇&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
套餐档位&lt;br&gt;
&lt;br&gt;
除了3.9元首月套餐外，还有另外两档套餐，可选择的模型更多，也更强：&lt;br&gt;
&lt;br&gt;
&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/60ef6fd2b97d4d39ae3ce2ff92834e44~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780297336&amp;amp;x-signature=K5zCn6rjHy0ZdjihGjlqjDbaXxo%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;专业版 39元/月：模型包含GLM-5.1、MiniMax-M2.5、KIMI-K2.5、DeepSeek-V3.2等&lt;/li&gt;
&lt;li&gt;高效版 199元/月：重度玩家顶配，额度充足&lt;br&gt;
&lt;br&gt;
都是国产顶级模型了。&lt;br&gt;
用量也更充裕，如果是重度玩家可以上199/月的高效版。&lt;br&gt;
如果只是大量处理一些简单任务，用3.9元的最合适。&lt;br&gt;
&lt;br&gt;
提醒一点：3.9元为首月优惠&lt;br&gt;
&lt;br&gt;
如果是用来编程，这里面我最推荐GLM-5.1，编程能力超强。&lt;br&gt;
&lt;br&gt;
&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/8b8a8d77b63b4627af1298ef1b4af11e~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780297336&amp;amp;x-signature=puJYn%2FN6c6UdDZzHpUsVLVzv0mE%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
比如我用Codex + GLM-5.1生成我的世界网页版，一次性就能生成的效果就很棒~&lt;br&gt;
&lt;br&gt;
&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/1cadbe030f5f445bb5d9bc064b15438b~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780297336&amp;amp;x-signature=yC%2BU4aMO8iWlwNH1Nfi0iTz7ytU%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
一般拿到一个模型我都会用这个Case来快速检测它的编程能力。&lt;br&gt;
&lt;br&gt;
这效果，这流畅度，也侧面反映了，CodingPlan里面的GLM-5.1绝对正宗~&lt;br&gt;
&lt;br&gt;
因为就连Deepseek v4都跑不好这个Case，跑出来贼多bug，就直接都穿模了..&lt;br&gt;
&lt;br&gt;
&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/96fff790cc9b48ee8998e0891cd32cf3~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780297336&amp;amp;x-signature=t3LzsXtmuu2%2Fy9Drh5ON1iZlAuM%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
对了，目前讯飞新人还可以获得新礼包卡奖励，双方都有，挺不错的。&lt;br&gt;
&lt;br&gt;
我是袋鼠帝，一个致力于帮你把AI变成生产力的博主。&lt;br&gt;
我们下期见~&lt;br&gt;
&lt;br&gt;
能看到这里的都是凤毛麟角的存在！&lt;br&gt;
如果觉得不错，随手点个赞、在看、转发三连吧✨&lt;br&gt;
如果想第一时间收到推送，也可以给我个星标⭐&lt;br&gt;
&lt;br&gt;
谢谢你耐心看完我的文章～&lt;/li&gt;
&lt;/ul&gt;</description><link>https://juejin.cn/post/7643444734549852223</link><guid isPermaLink="false">https://juejin.cn/post/7643444734549852223</guid><pubDate>Mon, 25 May 2026 07:02:16 GMT</pubDate><author>AI袋鼠帝</author><category></category><category>人工智能</category></item><item><title>体验完阿里首款Design Agent，我开始替UI/前端焦虑了..</title><description>&lt;p&gt;大家好，我是袋鼠帝。&lt;br&gt;
&lt;br&gt;
作为一名后端程序员，我略懂前端，但是对于UI设计是一窍不通。&lt;br&gt;
&lt;br&gt;
还记得以前上班的时候，公司大部分UI设计都是妹子，我连Figma都没打开过。&lt;br&gt;
&lt;br&gt;
自从AI快速发展起来以后，我虽然能做出各种功能复杂的前端的项目，但一直以来有个问题困扰我：做不好看。&lt;br&gt;
&lt;br&gt;
我能分辨什么样的页面是高级的、漂亮的，但我就是很难做出那种高级感、带交互动效的页面。这种感觉很难受😮‍💨&lt;br&gt;
&lt;br&gt;
本来我还想去学一下UI设计和Figma的，但一直没时间。&lt;br&gt;
&lt;br&gt;
然后...我就又一次体会到了什么叫只要你学的慢，就可以不用学。不得不说，这句话还是有一定的道理。&lt;br&gt;
&lt;br&gt;
当然，我不鼓励大家一直不学，毕竟学了，你至少知道这玩意儿是怎么发展的，底层逻辑是什么。&lt;br&gt;
&lt;br&gt;
先给大家看个好玩的，这是我20分钟左右快速做出来的一个产品官网页面。&lt;br&gt;
&lt;br&gt;
&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/ff9a58e568d447a4a0e25ac0e571f440~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780295464&amp;amp;x-signature=x86%2FP7JyslLneo8%2B5gMOP8cKsgQ%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
效果是不是还不错？我感觉这直接比很多产品的官网都要好了吧。&lt;br&gt;
&lt;br&gt;
整个页面的设计就很舒服，然后各种动效，用户可以交互，效果是很炸裂。关键是，这是一个不会UI设计的后端程序员做出来的（正是在下）。&lt;br&gt;
&lt;br&gt;
大家一定很好奇，这个效果，是怎么做到的？&lt;br&gt;
&lt;br&gt;
不卖关子，是**QoderWork的AI Native设计工作台（Design Desk）**帮忙做的，简单来说，它是一个设计Agent。&lt;br&gt;
&lt;br&gt;
&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/46d1335aa5bc43eca7b512364ab30031~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780295464&amp;amp;x-signature=g%2BwZMmAr9CuuGy0skNuLHDeF24w%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
Design Desk还真是让我挺惊艳的，我使用的整个过程非常顺手，即便过程中遇到一些问题，不管是对页面哪部分设计不满意，还是一些细节（颜色、边框、间距），都能在画布上手动快速调整。&lt;br&gt;
&lt;br&gt;
&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/1faf318f69f04c15954a9ba3d30a4a23~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780295464&amp;amp;x-signature=Il1LYeqL%2BJt6dv6nOlhmXlg4mSk%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
而且整个开发流程，对于不熟悉软件开发但是有自己想法想要快速折腾出效果的人非常友好（后面会详说）。&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
做产品官网&lt;br&gt;
&lt;br&gt;
比如开头展示的产品官网，我给了它一个Prompt：&lt;br&gt;
&lt;br&gt;
为一家音响公司打造产品网站。使用React、Tailwind CSS和Framer Motion实现所有动画。产品本身是一件雕塑一样呈现的。声音要通过交互来可视化，而不是单调的虚头。材质和工程设计要通过滚动来展现。即使在静态状态下，网站的使用也应该流畅、滚动丝滑流畅。每个交互元素都要有微交互。网站要完全响应式。参考案例：Transparent Speaker、Bang &amp;amp; Olufsen、Sennos、Tecno、Awwards级别。&lt;br&gt;
&lt;br&gt;
第一版效果就已经很不错了。&lt;br&gt;
&lt;br&gt;
&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/db6a198833e44f339d73349ac197d098~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780295464&amp;amp;x-signature=lmgPvOrbunGpBRFt5dlbIZtZNds%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
然后我给QoderWork加入了图片转3D的Skill：tripo-3d-generation。&lt;br&gt;
&lt;br&gt;
在使用GPT-image2设计好产品图之后，让QoderWork直接转成3D产品，并替换到网页中。&lt;br&gt;
&lt;br&gt;
&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/c471e57dc2034085be27d564b8fa5022~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780295464&amp;amp;x-signature=Y9GKbPFD%2FruDg%2BhQVFQPqg5haJ4%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
最终效果相当nice。&lt;br&gt;
&lt;br&gt;
&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/7e8fe01ebeca42f4b6a20d1ff90a0429~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780295464&amp;amp;x-signature=lCRVr4kdqhGRxVheZP2t2pzM5sU%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
说实话，以前一直做的后端程序员，我从来没想到有一天我能做出看起来这么专业的产品官网（感觉已经比很多产品官网都要高级了）。毕竟我不是前端，更不是设计师。&lt;br&gt;
&lt;br&gt;
而且仅仅只花了20分钟。关键我都没怎么动手，只是做了几道选择题（在一些关键节点做决策就行了）。&lt;br&gt;
&lt;br&gt;
然后我还对比了一下Codex，我用同样的提示词给Codex，它生成的效果虽然也还不错，但也能够明显看出是不如QoderWork Design Desk的。&lt;br&gt;
&lt;br&gt;
&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/b0c509d80d3a4c4daa3523f9f64d2724~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780295464&amp;amp;x-signature=wwqwzYhxo02ObK6%2B2r1dnYyz4%2Fw%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
看来专业的事还得专业Agent来做🤝&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
物理实验3D模型&lt;br&gt;
&lt;br&gt;
最近X上生成教育相关的3D模型网站非常火。&lt;br&gt;
&lt;br&gt;
然后我就顺便用QoderWork做了个高中物理实验3D交互网站。&lt;br&gt;
&lt;br&gt;
顺便看看，对于不熟悉软件开发、但有自己想法的人，QoderWork到底友不友好。&lt;br&gt;
&lt;br&gt;
&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/6bdaa48a188b459ba13c24f986dba1d5~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780295464&amp;amp;x-signature=4qKTPcnW2Zwu8A6EuLjFfBeIsLU%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
我的输入很简单：&lt;br&gt;
&lt;br&gt;
帮我设计一个用于高中教学互动的3D交互实验室的科学App，重点是3D模型可以互动，演示高中物理不同磁学、原子物理部分，展示一些物理的不同原理。然后全局扩展。&lt;br&gt;
&lt;br&gt;
注意，这段话完全没有任何软件开发的术语，不需要你有开发思维，也不需要你给它具体的实现方案。&lt;br&gt;
&lt;br&gt;
然后它做了一件让我觉得聪明的事，没有直接开始干活，先是追问了几个问题，帮我深挖更具体的需求。&lt;br&gt;
&lt;br&gt;
&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/bdf3db0e6650497cbe07207d5b7bff69~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780295464&amp;amp;x-signature=cgUBFcOaDLQNZpZ1%2Fwr6VQ%2Bg9B4%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
问完之后也没有胡乱开始写代码，是生成了一份设计计划让我确认。&lt;br&gt;
&lt;br&gt;
这份计划包含交付的产物、技术方案确认、页面、交互设计以及风险评估。还挺详细的。&lt;br&gt;
&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/78f7b3b9ccf34ea58398196ab8aa1131~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780295464&amp;amp;x-signature=EsbNBPPL1KhXjbUtAkNMGUDSwXw%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
这个流程我觉得是对的。先对齐、再计划、最后执行。&lt;br&gt;
&lt;/p&gt;
&lt;p&gt;方向对齐在前，执行在后，这样一次命中率就高很多，不用反复重来。也是让Agent生成质量更稳的关键。&lt;br&gt;
&lt;br&gt;
最后生成的是带3D交互的完整的React + Vite前端工程文件。&lt;br&gt;
&lt;br&gt;
&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/4782a97c514049e5a525fdf79b3b2a8f~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780295464&amp;amp;x-signature=oFuGi2WkV9Vg0driUgSaesry5PQ%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
这一点跟Claude Design不一样，据我所知Claude目前只能出HTML。&lt;br&gt;
&lt;br&gt;
QoderWork则可以直接输出完整工程文件，这对于一个项目的维护和迭代来说很重要。&lt;br&gt;
&lt;br&gt;
我让我的前端朋友打开了几个文件看了一下，他的评价就是确实不错，确实符合大部分前端工程师的编写习惯。&lt;br&gt;
&lt;br&gt;
所以我觉得QoderWork的design desk对于不懂开发的人来说，也很友好。&lt;br&gt;
&lt;br&gt;
不需要你懂一些技术术语，它会帮你挖需求、出计划。门槛比我预期的低很多。&lt;br&gt;
&lt;br&gt;
当然，它只是拉高了所有人在做UI设计、前端的下限，对于专业的UI设计来说，他们用Design Desk的上限肯定会更高。&lt;br&gt;
&lt;br&gt;
然后在整个体验中，有三个点让我觉得效率提升明显：&lt;br&gt;
&lt;br&gt;
1.&amp;nbsp;画布上直接改：整个工程在无限画布上，基础的宽高、位置、拖拽、调整，不用写代码，实时生效。
&amp;nbsp;  &lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/a1bc2e67a5734ccea02a5a139ebd2ef1~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780295464&amp;amp;x-signature=0%2BfeVuBuhmGsAkJk2lNd8JVG0x0%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
2.框选修改：以前修改页面某块内容，大多要在对话框用文字描述导航栏左上角的那个按钮颜色改一下...&lt;br&gt;
费劲巴拉打一堆字，关键有时候你还真不好描述。现在直接在画布上框选目标内容，告诉它你要怎么改就行。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/b4378e7cceaa42c792326647575a86bc~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780295464&amp;amp;x-signature=E5HTrsdWQYhes4J82EPR%2B8oxaxs%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
3.&amp;nbsp;关键设计决策：做着做着发现需要换主题颜色、换字体这些全局性的东西，正常还是通过对话框改，然后等结果，而且改全局的东西还容易把代码改崩。&lt;br&gt;
QoderWork现在把配色、间距、圆角、字号这些高频微调项直接以可调参数暴露出来，拖拽调整，实时生效，甚至不需要刷新就能看到效果。&lt;br&gt;
&lt;br&gt;
&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/d32793acb6f94a09851862c98447ccb1~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780295464&amp;amp;x-signature=2xD1%2BrrvTiT1DcGLis1Z%2FslAZzs%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
还是那句话，不用等。&lt;br&gt;
&lt;br&gt;
这三个点加起来，解决了同一个核心痛点：别让我等，别让我打字描述，在开发完成之后，需要的是简单，快速，精准的去调整页面。&lt;br&gt;
&lt;br&gt;
不得不说QoderWork跟之前腾讯做的Figma类云端设计工具还是有本质的区别。&lt;br&gt;
&lt;br&gt;
腾讯的核心还是在云端协作的矢量设计上。&lt;br&gt;
&lt;br&gt;
QoderWork的定位是原生的AI驱动设计即代码工具：传统的&quot;纯画图设计师&quot;和&quot;纯写页面前端&quot;的界限正在坍塌，设计文件将不再是不可触碰的黑盒，而是团队所有人都可以共同维护的视觉资产。&lt;br&gt;
&lt;br&gt;
另外QoderWork还内置了150多个高品质风格参考，有模板的好处是风格对人可控，解决了我一直以来的痛：有审美但做不出来。&lt;br&gt;
&lt;br&gt;
&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/ea43ceafe37f4538ae0ad8117f43824d~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780295464&amp;amp;x-signature=zUqpRJgYGrwTFXsLI55pABZnUG8%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
&amp;nbsp;&lt;br&gt;
&lt;br&gt;
极限测试：复刻天花板级网站&lt;br&gt;
&lt;br&gt;
为了测试它的极限，我找了一个动效审美都是天花板的网站&amp;nbsp;lusion.co&amp;nbsp;&lt;br&gt;
&lt;br&gt;
真的，这绝对是我这辈子见过最炫酷的网站，没有之一，可以用震撼来形容。&lt;br&gt;
&lt;br&gt;
&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/db7517260d454532b3adef3c498a0242~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780295464&amp;amp;x-signature=C8xPIeH%2FddBG99pJ%2BRSMaL%2FtHVs%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
这个网站的交互简直就像在看好莱坞大片，每一页翻动都伴随着极其复杂、丝滑又酷炫的3D变换。&lt;br&gt;
&lt;br&gt;
这绝对是极限测试了。我敢说，目前不可能有任何AI能一次性百分百复现这个网站的前端。&lt;br&gt;
&lt;br&gt;
1月份的时候，我丢给过Kimi的Agent，它能复刻出大约30%。&lt;br&gt;
&lt;br&gt;
但是这次QoderWork生成的，很惊艳，我觉得到50%了。&lt;br&gt;
&lt;br&gt;
&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/520105246405482f8b1d42b6e8707a8b~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780295464&amp;amp;x-signature=a5I7egvGyY6RQWTdYcb2qydETOs%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
可惜的是QoderWork目前没有视觉能力，lusion.co的录屏没法给它看，所以在理解上可能有一定偏差。&lt;br&gt;
&lt;br&gt;
另外说下问题，目前Qoderwork在处理特别复杂的3D场景和连续滚动动效时，偶尔会有些卡顿，生成的代码也不是每次都能一跑就通，有时候需要手动调一下。&lt;br&gt;
&lt;br&gt;
不过这才是第一个版本，这个程度还不错了。&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
顺带一提&lt;br&gt;
&lt;br&gt;
QoderWork自定义工作台，除了设计工作台，还有PPT工作台、写作工作台。&lt;br&gt;
&lt;br&gt;
PPT工作台每一页演示稿是独立HTML文件，内置各种中文字体，断网也能渲染。全流程有11个阶段，每个阶段用户都能介入。生成的效果，我试了一下，还挺好的，已经赶上臧师傅开源的PPT skill了。&lt;br&gt;
&lt;br&gt;
&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/85ae04b668844663a8143b1dd31cc708~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgQUnooovpvKDluJ0=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780295464&amp;amp;x-signature=OomCNoxFHQYp7bY%2B2T7H9hIHVK4%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;
写作工作台的选中即批注还挺有意思的，可以像审稿一样圈出某段文字，写下改得更正式、压缩到100字以内，AI就能围绕选中文本定向修改。&lt;br&gt;
&lt;br&gt;
这两个先mark住，如果大家感兴趣的话，后续可以单独聊聊。&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
「最后」&lt;br&gt;
&lt;br&gt;
这次尝试，我觉得我“做不好看”这件事，真的被解决了一大半。&lt;br&gt;
&lt;br&gt;
以及我个人觉得，UI和前端确实越来越危险了，不知道UI和前端们怎么看，欢迎评论区交流。&lt;br&gt;
&lt;br&gt;
我这么说不是没有依据。特别是现在我做OPC，从我个人的角度来说，如果我自己都能做出这样的产品官网，我为什么还要请专业的UI和前端呢？&lt;br&gt;
&lt;br&gt;
因为目前做出来的效果已经比市面上很多产品的官网效果要好了。&lt;br&gt;
&lt;br&gt;
前几天在北京的时候，跟一位老乡朋友吃饭聊天。她是在北京做了很久的资深律师，她主动聊起她焦虑，并问我有没有什么破局的方法。&lt;br&gt;
&lt;br&gt;
我当时给出的破局办法有两种：&lt;br&gt;
&lt;br&gt;
1.&amp;nbsp;打穿并放大：拥抱趋势，拥抱变化，深度使用AI。不仅要是行业的专家，更要成为行业+AI的专家。&lt;br&gt;
2.&amp;nbsp;把自己变成更稀缺的人才：当一个人既能又能的时候，它的稀缺性是指数上升的。比如一个人，既懂AI的关键技术，又懂营销、有网感，还会商务（没模板也干），这样的人是非常稀缺的。所以说你每加一项技能，你的竞争对手就会少非常多，你就越稀缺，越有价值。&lt;br&gt;
&lt;br&gt;
这也是我为什么一直没有找到我公众号的技术编辑的原因——因为适合帮我公众号内容的人太少太少了。&lt;br&gt;
&lt;br&gt;
说真的，从Sketch到Figma，设计与研发格式不同的矛盾还在，原来传统工作页面，设计到代码的还原度平均不足70%，页面交互衔接中往往需要经历3-5轮的标注与返工。懂得都懂，真的太痛了。&lt;br&gt;
&lt;br&gt;
以前的前端开发流程都是产品确定原型图，UI设计师出图，前端再画图。中间有多少沟通成本、多少开发周期。而现在借助design agent可能就是几句的事，输入自然语言，你就能得到可交付的工程文件。&lt;br&gt;
&lt;br&gt;
所以，如果你对网页呈现的效果有一定追求，或者想优化团队现有的开发流程，可以去尝试一下QoderWork Design Desk这样的设计Agent。它确实是能提高审美、提高效率的生产力工具。&lt;br&gt;
&lt;br&gt;
最后，希望评论区不要再说我贩卖焦虑了。因为AI的发展太快了，就连我自己也非常焦虑。&lt;br&gt;
&lt;br&gt;
但焦虑是正常的。关键看你怎么对待它——采取行动，还是放任不管，都在于你自己。&lt;br&gt;
&lt;br&gt;
不过，我家两代人的经历告诉我，人不能一直低头拉车，还得抬头看路。&lt;br&gt;
&lt;br&gt;
能看到这里的都是凤毛麟角的存在！&lt;br&gt;
&lt;br&gt;
如果觉得不错，随手点个赞、在看、转发三连吧✨&lt;br&gt;
&lt;br&gt;
如果想第一时间收到推送，也可以给我个星标⭐&lt;br&gt;
&lt;br&gt;
谢谢你耐心看完我的文章～&lt;/p&gt;</description><link>https://juejin.cn/post/7643116195138781238</link><guid isPermaLink="false">https://juejin.cn/post/7643116195138781238</guid><pubDate>Mon, 25 May 2026 06:31:04 GMT</pubDate><author>AI袋鼠帝</author><category>人工智能</category></item><item><title>面试官：AI生成到90%突然断了，你的解决方案是什么？（万字长文深度剖析）</title><description>&lt;p&gt;最近遇到一个的粉丝，问了一个问题：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/621c9d7ba261451a8840e56951859b3a~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6Q5bCP5aSV:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780293885&amp;amp;x-signature=%2FHHcFQxIPlFWUR7fBFCzIOV52Nc%3D&quot; alt=&quot;图片&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;总结成一句话就是：&lt;/p&gt;
&lt;h5 data-id=&quot;heading-0&quot;&gt;AI生成到90%突然断了，你的恢复方案是什么？&lt;/h5&gt;
&lt;p&gt;这个问题其实在AI技术面试中经常被问到，也是一个“看似简单， 实则深奥”的问题。&lt;/p&gt;
&lt;p&gt;如果大家的AI产品也遇到过以下问题，这篇文章将会非常有帮助：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户网络波动（比如断网，网速时慢时快），WiFi 自动降级导致AI项目的流式输出中断&lt;/li&gt;
&lt;li&gt;浏览器标签页被误关，重新打开后对话记录还在，但刚才那轮生成的内容丢失了&lt;/li&gt;
&lt;li&gt;长任务生成到一半，服务端负载过高触发自动扩容，连接被重置&lt;/li&gt;
&lt;li&gt;用户主动刷新页面，想保存刚才的内容，数据却丢失了&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;流式生成的核心价值是&quot;快&quot;，但如果&quot;快&quot;伴随着不稳定（不可靠），用户体验就会从&quot;惊艳&quot;变成&quot;崩溃&quot;。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;所以作为优秀的产品经理和AI产品开发者，为了打造最好的用户体验，这一“关”，我们必须攻克。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;接下来我就站在面试官的角度，系统的分析这个问题，并提供一个专业，可实操作，可落地的解决方案。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-1&quot;&gt;一个底层的背景：为什么流式生成天生脆弱？&lt;/h2&gt;
&lt;p&gt;要想深度理解“AI生成中断”问题的重要性，我们需要了解传统流式架构的几个痛点：&lt;/p&gt;
&lt;h3 data-id=&quot;heading-2&quot;&gt;1. 纯内存状态：一断全丢&lt;/h3&gt;
&lt;p&gt;标准的&amp;nbsp;SSE（Server-Sent Events）或&amp;nbsp;WebSocket&amp;nbsp;流式架构中，生成状态通常只存在于如下图所示三个位置：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/94553546bab84189be632a3c6b006bd8~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6Q5bCP5aSV:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780293885&amp;amp;x-signature=zhcOz1IByNZIAwwPJrdcKQRTHw0%3D&quot; alt=&quot;图片&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;这三层全是易失性存储。&lt;/strong&gt; &amp;nbsp;任何一层断裂，状态就彻底消失。&lt;/p&gt;
&lt;p&gt;更复杂的问题是，LLM&amp;nbsp;生成具有强烈的&lt;strong&gt;顺序依赖性&lt;/strong&gt;——第100个token的生成依赖前99个token的上下文，你无法像下载文件那样&quot;从中间开始&quot;。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-3&quot;&gt;2. 大模型的&quot;不可重入&quot;性（可以说是痛中之痛了）&lt;/h3&gt;
&lt;p&gt;这里给大家分享一个反直觉的事实：&lt;strong&gt;大多数AI生成请求不是幂等的。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;即使我们把用户的&amp;nbsp;Prompt&amp;nbsp;原封不动再发一次，由于大模型的温度参数和采样的随机性，会导致第二次生成的结果和第一次&lt;strong&gt;完全不同&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这意味着&quot;重新生成&quot;不是&quot;恢复&quot;，而是&quot;替换&quot;。&lt;/p&gt;
&lt;p&gt;对于长文本生成、代码生成、报告撰写这类场景，用户往往对第一次生成的“中间态”已经有了&lt;strong&gt;认知预期（&lt;/strong&gt; 可能已经读了一半，认为AI中断后继续生成， 应该按照中断之前的内容继续生成，如果&lt;strong&gt;替换，等于否定用户的Tokens）&lt;/strong&gt;&lt;/p&gt;
&lt;h3 data-id=&quot;heading-4&quot;&gt;3. 业务成本的损耗&lt;/h3&gt;
&lt;p&gt;从商业角度看，一次中断的代价远不止用户体验，还包含如下成本投入：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;算力浪费&lt;/strong&gt;：生成到90%中断，这90%的token消耗已经产生成本，但用户没看到结果（不过主流的AI产品貌似做了一下平权优化）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;上下文窗口浪费&lt;/strong&gt;：恢复时如果从头重传历史消息，会快速吃掉宝贵的上下文长度&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用户流失&lt;/strong&gt;：我们内部AI产品的数据统计表明，一次&quot;长生成中断&quot;的用户，7日留存率下降约&lt;strong&gt;20%（太痛了）&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;综合上面的分析，其实结论已经很清晰了：流式生成必须像视频播放一样支持&quot;断点续传&quot;。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 data-id=&quot;heading-5&quot;&gt;第一问：宏观思路——如果让你一句话概括解决方案，你会怎么说？&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官&lt;/strong&gt;：&quot;如果让你用一句话概括你的“AI中断恢复”的实现思路，你会怎么做？&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;答&lt;/strong&gt;：&quot;我会让生成过程&lt;strong&gt;像视频播放一样支持断点续传&lt;/strong&gt;——核心是在生成过程中持续&#39;落盘&#39;状态，而不是等到结束才保存。&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;面试官&lt;/strong&gt;：&quot;具体怎么落盘？&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;答&lt;/strong&gt;：&quot;我设计了一个&lt;strong&gt;三层状态恢复模型&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/a443dd679ad844e995a01741fae85476~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6Q5bCP5aSV:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780293885&amp;amp;x-signature=Zr66gDJJcpRntPyOkCjGms1or7Q%3D&quot; alt=&quot;图片&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;客户端缓存层&lt;/strong&gt;：SessionStorage 做热缓存，IndexedDB 做持久缓存，页面刷新后先让用户直接看到上一次已经生成的内容；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;网关缓冲层&lt;/strong&gt;：负责连接状态路由、心跳检测、区分&#39;网络抖动&#39;和&#39;真正中断&#39;；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;服务端持久层&lt;/strong&gt;：Redis 保存热生成状态（包括了 KV Cache），然后数据库做长期归档。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;三层之间通过&amp;nbsp;&lt;code&gt;checkpoint_id&lt;/code&gt;&amp;nbsp;+&amp;nbsp;&lt;code&gt;offset&lt;/code&gt;&amp;nbsp;+&amp;nbsp;&lt;code&gt;hash&amp;nbsp;&lt;/code&gt;三元组串联，确保恢复时的幂等性和数据一致性。&quot;&lt;/p&gt;
&lt;p&gt;同时在实现方案时，需要遵循如下几个实现原则：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. 渐进式持久化&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;不要等到生成结束才保存。每生成一个&quot;逻辑段落&quot;（比如每512个token或每个自然段落结束），就触发一次状态快照。这样的好处是：即使对话中断，丢失的也只是最后一个段落，而不是全部。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. 客户端是第一恢复“数据源”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;建议优先从客户端的缓存中恢复已接收内容，实现&quot;所见即所得&quot;的视觉反馈，服务端只需补充&quot;未接收的部分&quot;。（当然也可以从统一服务端缓存层进行持久化兜底）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. 幂等性设计（面试必备术语，用于“装”那啥）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;通过&amp;nbsp;&lt;code&gt;request_id&lt;/code&gt;&amp;nbsp;+&amp;nbsp;&lt;code&gt;checkpoint_id&lt;/code&gt;&amp;nbsp;+&amp;nbsp;&lt;code&gt;offset&amp;nbsp;&lt;/code&gt;三元组，确保同一恢复请求永远产生确定性的续传结果。&lt;/p&gt;
&lt;p&gt;好啊，下面继续深入技术实现。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-6&quot;&gt;第二问：架构深挖——服务端怎么知道该从哪恢复呢？&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官&lt;/strong&gt;：&quot;用户刷新页面后，客户端发了一个恢复请求过来。服务端如何判断&#39;这个请求是要续传&#39;，而不是&#39;新请求&#39;？&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;答&lt;/strong&gt;：&quot;靠&lt;strong&gt;断点标记协议&lt;/strong&gt;。我在 SSE 的每个数据包里都嵌入了&amp;nbsp;checkpoint&amp;nbsp;元信息，代码案例如下：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/7bd6231c562c484e80e37c8291a6b972~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6Q5bCP5aSV:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780293885&amp;amp;x-signature=5w7QKzYvVh5QmYs5ghZtfGzzy80%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;客户端在每次收到&amp;nbsp;chunk&amp;nbsp;时，都会把这个&amp;nbsp;checkpoint&amp;nbsp;存到本地。恢复时，在请求头（headers）中带上如下信息（标识）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;X-Checkpoint-ID&lt;/code&gt;: 本次生成的唯一标识&lt;/li&gt;
&lt;li&gt;&lt;code&gt;X-Client-Offset&lt;/code&gt;: 客户端最后收到的token数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;X-Content-Hash&lt;/code&gt;: 本地缓存内容的校验和&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;服务端收到&amp;nbsp;Headers&amp;nbsp;中的标识信息后，会先去&amp;nbsp;Redis&amp;nbsp;查这个&amp;nbsp;checkpoint_id。如果存在，说明生成状态还在有效期内，可以进入续传流程。&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;面试官&lt;/strong&gt;：&quot;那如果客户端缓存损坏了，hash 校验不通过，又该怎么处理呢？&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;答&lt;/strong&gt;：&quot;那就退回到上一个可靠的&amp;nbsp;checkpoint&amp;nbsp;重新发送，而不是盲目续传。宁愿多传一点重复内容，也不能让恢复后的内容出现断层或乱码。&quot;&lt;/p&gt;
&lt;h2 data-id=&quot;heading-7&quot;&gt;第三问（状态机设计）：AI生成到一半，突然断了，服务端的状态该怎么处理？&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官&lt;/strong&gt;：&quot;连接断开的那一时刻，LLM&amp;nbsp;可能还在推理，这个时候是直接停止生成，还是有其他更好的方案呢？&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;答&lt;/strong&gt;：&quot;不用停止生成，这正是最容易踩坑的地方。我设计了一个&lt;strong&gt;六状态生成状态机&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/a1faafa2725e4ae194067716b0bf9a2a~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6Q5bCP5aSV:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780293885&amp;amp;x-signature=m3A2G7bf98AHs1skACyFov%2BjsKA%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;状态转换的规则如下：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/d35865b65a924ab9bb033a63fb3f444a~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6Q5bCP5aSV:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780293885&amp;amp;x-signature=6Eb0uOGBLx92ZGAchcWvYDVEDDk%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;具体分享一下我的思路：&lt;/p&gt;
&lt;p&gt;首先，当网关层检测到连接中断（连续3次心跳丢失）时，我们需要做的不是销毁状态，而是把状态机切到&amp;nbsp;&lt;code&gt;PAUSED（暂停）&lt;/code&gt;。此时需要做的是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;冻结生成上下文&lt;/strong&gt;：把当前的&amp;nbsp;&lt;code&gt;messages&lt;/code&gt;、&lt;code&gt;past_key_values&lt;/code&gt;（KV Cache）、已输出token序列做序列化；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;写入Redis&lt;/strong&gt;：&lt;code&gt;SETEX generation:chk_xxx 3600&lt;/code&gt;，TTL设1小时；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;异步归档&lt;/strong&gt;：同时写入数据库（持久化备份， 企业级必备意识），保留3-7天，防止Redis淘汰。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;核心设计价值在于：在&#39;网络抖动&#39;阶段（心跳延迟&amp;gt;2秒）就进入&#39;预暂停&#39;，提前冻结。&lt;/strong&gt; &amp;nbsp;因为 LLM 推理一直在消耗算力，如果等确认断连再冻结，可能已经有大量新生成内容送不到客户端，造成算力浪费。&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;面试官&lt;/strong&gt;：&quot;Redis 挂了又该怎么办？&quot; （可见面试官被企业问题折磨的不轻）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;答&lt;/strong&gt;：&quot;Redis&amp;nbsp;是热存储，挂了就从数据库冷存储恢复。虽然延迟相对高一些（几十毫秒到几百毫秒），但至少不会丢状态。另一方面，我对&amp;nbsp;KV Cache&amp;nbsp;做了&amp;nbsp;INT8&amp;nbsp;量化压缩，能减少 70% 的&amp;nbsp;Redis&amp;nbsp;内存占用，避免高峰期&amp;nbsp;OOM。&quot;&lt;/p&gt;
&lt;p&gt;Good，我们继续下一个刁钻的技术面。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-8&quot;&gt;第四问：客户端策略——页面刷新了，用户凭什么能看到旧内容？&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官&lt;/strong&gt;：&quot;用户刷新页面，浏览器内存全清空了，你凭什么让用户立即看到之前的内容？&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;答&lt;/strong&gt;：&quot;靠&lt;strong&gt;客户端双保险缓存， 具体的实现代码如下&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/701f53dc157d4728acbc0d05f6ff09ca~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6Q5bCP5aSV:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780293885&amp;amp;x-signature=6oQVNxXbtj9PcwhnGnJAIkDRs6o%3D&quot; alt=&quot;image.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;恢复时的优先级顺序是：&lt;strong&gt;内存 &amp;gt; IndexedDB &amp;gt; 服务端冷存储&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;页面打开后，前端先读&amp;nbsp;IndexedDB（浏览器本地存储），立刻把旧内容渲染到对话区域，同时发恢复请求给服务端。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/698c156749b94dc59f1521385746c32e~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6Q5bCP5aSV:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780293885&amp;amp;x-signature=oeJ7xF9lQ9SVroZvPKvaTm1KFfI%3D&quot; alt=&quot;图片&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;用户看到的效果是：内容已经渲染了，光标在文本末尾一直不停地闪烁，新的文字继续流出。用户&lt;strong&gt;根本不知道这是一次恢复，会认为只是&#39;暂停了一下&#39;。这样设计对用户体验来说比较友好～&lt;/strong&gt;&quot;&lt;/p&gt;
&lt;p&gt;更健壮的代码实现如下，大家可以参考一下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-python&quot; lang=&quot;python&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 伪代码示意&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;StreamingCheckpointManager&lt;/span&gt;:
    &lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;__init__&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;self&lt;/span&gt;):
        self.redis = RedisClient()
        self.db = Database()

    &lt;span class=&quot;hljs-keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;freeze_generation&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;self, checkpoint_id: &lt;span class=&quot;hljs-built_in&quot;&gt;str&lt;/span&gt;, context: GenerationContext&lt;/span&gt;):
        &lt;span class=&quot;hljs-comment&quot;&gt;# 1. 序列化生成状态（包含KV Cache和token序列）&lt;/span&gt;
        serialized = self.serialize_context(context)

        &lt;span class=&quot;hljs-comment&quot;&gt;# 2. 写入Redis热存储（1小时TTL）&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;await&lt;/span&gt; self.redis.setex(
            &lt;span class=&quot;hljs-string&quot;&gt;f&quot;generation:&lt;span class=&quot;hljs-subst&quot;&gt;{checkpoint_id}&lt;/span&gt;&quot;&lt;/span&gt;, 
            ttl=&lt;span class=&quot;hljs-number&quot;&gt;3600&lt;/span&gt;, 
            value=serialized
        )

        &lt;span class=&quot;hljs-comment&quot;&gt;# 3. 异步写入数据库冷存储（7天TTL）&lt;/span&gt;
        asyncio.create_task(
            self.db.archive_generation(checkpoint_id, serialized, retain_days=&lt;span class=&quot;hljs-number&quot;&gt;7&lt;/span&gt;)
        )

    &lt;span class=&quot;hljs-keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;resume_generation&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;self, checkpoint_id: &lt;span class=&quot;hljs-built_in&quot;&gt;str&lt;/span&gt;, client_offset: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&lt;/span&gt;):
        &lt;span class=&quot;hljs-comment&quot;&gt;# 1. 先查Redis&lt;/span&gt;
        state = &lt;span class=&quot;hljs-keyword&quot;&gt;await&lt;/span&gt; self.redis.get(&lt;span class=&quot;hljs-string&quot;&gt;f&quot;generation:&lt;span class=&quot;hljs-subst&quot;&gt;{checkpoint_id}&lt;/span&gt;&quot;&lt;/span&gt;)

        &lt;span class=&quot;hljs-comment&quot;&gt;# 2. Redis未命中，查数据库&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; state:
            state = &lt;span class=&quot;hljs-keyword&quot;&gt;await&lt;/span&gt; self.db.get_generation(checkpoint_id)
            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; state:
                &lt;span class=&quot;hljs-keyword&quot;&gt;raise&lt;/span&gt; CheckpointNotFound(&lt;span class=&quot;hljs-string&quot;&gt;&quot;生成记录已过期或不存在&quot;&lt;/span&gt;)

        &lt;span class=&quot;hljs-comment&quot;&gt;# 3. 反序列化上下文&lt;/span&gt;
        context = self.deserialize_context(state)

        &lt;span class=&quot;hljs-comment&quot;&gt;# 4. 如果客户端offset小于服务端已生成量，先补发历史内容&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; client_offset &amp;lt; context.output_length:
            &lt;span class=&quot;hljs-keyword&quot;&gt;await&lt;/span&gt; self.replay_history(client_offset)

        &lt;span class=&quot;hljs-comment&quot;&gt;# 5. 如果生成尚未完成，继续流式输出&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; context.state != GenerationState.COMPLETED:
            &lt;span class=&quot;hljs-keyword&quot;&gt;await&lt;/span&gt; self.continue_generation(context)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;面试官&lt;/strong&gt;：&quot;如果用户换了设备呢？比如手机断了，在电脑上打开同一个页面，如何解决同步？&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;答&lt;/strong&gt;：&quot;这是更业务场景的功能实现了。我们可以把&amp;nbsp;checkpoint&amp;nbsp;与&lt;strong&gt;用户账号&lt;/strong&gt;绑定，而不是设备绑定。电脑端进入同一会话时，检测到该会如果话存在&amp;nbsp;&lt;code&gt;PAUSED&amp;nbsp;&lt;/code&gt;状态的&amp;nbsp;checkpoint，就会提示用户：&#39;检测到您在手机端有未完成的生成，是否继续？&#39; 这对跨设备协作的场景非常有用。&quot;&lt;/p&gt;
&lt;h2 data-id=&quot;heading-9&quot;&gt;第五问：极限边界场景探索（考验求职者的创新和思考能力了）&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官&lt;/strong&gt;：&quot;我问几个边界情况。第一，AI生成恢复时，已生成的内容过长，重新组装&amp;nbsp;Prompt&amp;nbsp;再发给模型，上下文窗口溢出了怎么办？&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;答&lt;/strong&gt;：&quot;可以对已生成内容，做&lt;strong&gt;智能摘要压缩&lt;/strong&gt;，只保留关键结论作为上下文，而不是全文重传。我们可以在&amp;nbsp;Prompt&amp;nbsp;里区分&amp;nbsp;&lt;code&gt;history_summary&amp;nbsp;&lt;/code&gt;和&amp;nbsp;&lt;code&gt;continuing_context&lt;/code&gt;，让模型知道&#39;这是前文摘要，请基于它继续完成&#39;。&quot;&lt;/p&gt;
&lt;p&gt;这是一个非常实用且高频的解决方案，建议大家在AI项目中都采用。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;面试官&lt;/strong&gt;：&quot;第二个问题，LLM&amp;nbsp;有随机性，恢复后续写时，风格变了、人称变了，前后不一致怎么办？&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;答&lt;/strong&gt;：&quot;在恢复&amp;nbsp;Prompt&amp;nbsp;里注入&lt;strong&gt;风格锚点&lt;/strong&gt;（style anchor），明确告知模型&#39;请保持前文的第一人称叙述风格&#39;。同时，checkpoint&amp;nbsp;里记录了生成时的&amp;nbsp;temperature&amp;nbsp;和&amp;nbsp;top_p，恢复时严格复用，最大程度保证一致性。&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;面试官&lt;/strong&gt;：&quot;第三个问题，如果模型版本升级了，旧版&amp;nbsp;KV Cache&amp;nbsp;新版加载不了，如何解决呢？&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;答&lt;/strong&gt;：&quot;可以通过序列化时加入&lt;strong&gt;模型版本标识&lt;/strong&gt;和&lt;strong&gt;序列化协议版本&lt;/strong&gt;。恢复时严格校验兼容性，不兼容时自动降级为&#39;文本级恢复&#39;——从文本断点重新生成，而不是推理状态断点。虽然会多花一点算力，但至少不会崩溃。&quot;&lt;/p&gt;
&lt;p&gt;此时面试官是不是已经急切的想要“招”你了。下面为了挽回自己的颜面，补充一个“加时赛”。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-10&quot;&gt;最后一问：如果让你给团队落地，优先级该怎么设计？&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;面试官&lt;/strong&gt;：&quot;假设你们团队现在资源有限。让你排优先级，你会先做什么，后做什么？&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;答&lt;/strong&gt;：&quot;我会分三步来落地：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第一步&lt;/strong&gt;：先做客户端 IndexedDB 缓存 + 服务端文本级断点续传。不碰 KV Cache 序列化，只记录已生成的文本和 offset。恢复时从文本断点重新调用模型生成。这样投入最小，但能解决80%的用户痛点。用时大概1-3天，当然也需要评估团队目前的技术实力，是否需要配合AI辅助来完成。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第二步&lt;/strong&gt;：引入 Redis 热状态存储，实现KV Cache的序列化与恢复。这是性能拐点，能把恢复后的首 token 延迟从秒级降到毫秒级。如果用AI Coding，不考虑产品UI和交互逻辑，1天内应该可以搞定。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第三步&lt;/strong&gt;：做网关层的心跳检测、多端同步、分级TTL策略。这是稳定性拐点，让方案能扛住生产环境的高峰流量。&quot; 这个需要团队前后端运维多方配合，预计大概3-5天能完整落地。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;面试官&lt;/strong&gt;：&quot;为什么要先做客户端缓存，而不是先做服务端 KV Cache？&quot;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;答&lt;/strong&gt;：&quot;因为我的思路中，&lt;strong&gt;用户体验的永远是第一优先级，比服务端性能优化更直观成本也更低&lt;/strong&gt;。&quot;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 data-id=&quot;heading-11&quot;&gt;最后：给正在准备面试或转型AI的各位粉丝&lt;/h2&gt;
&lt;p&gt;如果大家正在准备AI工程、后端架构或大模型应用相关的面试，&quot;流式生成状态恢复&quot;是一个&lt;strong&gt;非常能体现工程深度&lt;/strong&gt;的面试题。&lt;/p&gt;
&lt;p&gt;给大家分享一个面试回答框架：**&lt;br&gt;
**&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/d02ab251e5dc417eb5c834d4d5fe042b~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6Q5bCP5aSV:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780293885&amp;amp;x-signature=r9d7WrmnegYRCJDmZxkE%2Fxvgr0k%3D&quot; alt=&quot;图片&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;场景痛点 → 架构分层 → 协议设计 → 边界兜底 → 落地优先级&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这个结构能帮大家把自己的技术回答变得既有广度又有深度。&lt;/p&gt;</description><link>https://juejin.cn/post/7643469288817508390</link><guid isPermaLink="false">https://juejin.cn/post/7643469288817508390</guid><pubDate>Mon, 25 May 2026 06:04:45 GMT</pubDate><author>徐小夕</author><category></category><category>前端</category><category>Vue.js</category><category>算法</category></item><item><title>从 15MB 减到 800KB，一行 ffmpeg 解决3D 渲染卡顿问题</title><description>&lt;p&gt;在做跨境电商和独立站（如 &lt;code&gt;Shopify&lt;/code&gt;）的前端架构时，商品详情页经常会遇到一个非常经典的业务需求：&lt;strong&gt;360度商品 3D 交互预览&lt;/strong&gt;。&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/21150e1966684221bf62cac885a19911~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgRXJwYW5PbWVy:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780285921&amp;amp;x-signature=SRhp9MC%2F25hUej2pZPOGD1xWnMA%3D&quot; alt=&quot;20260525-110509.gif&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/4d8af721b06142ad883d061559904bed~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgRXJwYW5PbWVy:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780285921&amp;amp;x-signature=%2Bpg%2FB40KHld2ZCJLQunIopGD%2Bv0%3D&quot; alt=&quot;20260525-110422.gif&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;就是那种允许用户在移动端通过手指滑动，左右旋转商品、放大缩小，多角度查看商品细节的交互组件👆。&lt;/p&gt;
&lt;p&gt;上个月，我们组的产品经理一拍脑袋，也想给新版详情页上这个功能。他兴冲冲地跑来找我：咱们直接用 &lt;code&gt;Three.js&lt;/code&gt;，让 3D 美术给个 &lt;code&gt;glTF&lt;/code&gt; 格式的 3D 模型文件，咱们在网页里用 &lt;code&gt;WebGL&lt;/code&gt; 渲染，多高级！😁&lt;/p&gt;
&lt;p&gt;我看着他，默默泼了一盆冷水：美术导出的高精度 glTF 模型起码 150MB 往上。加载这么大文件，海外用户的首屏白屏时间你来负责？用户稍微划得快一点，低端安卓机直接发热卡死甚至浏览器崩溃，你来写排障报告？&lt;/p&gt;
&lt;p&gt;最终，我毙掉了他的 WebGL 方案，转而采用了一套极其克制、性能极佳的 &lt;strong&gt;视频帧平滑控制（Video Scrubbing）&lt;/strong&gt; 方案。&lt;/p&gt;
&lt;p&gt;今天，我不聊虚的技术趋势，就拿这个真实的开发实战，聊聊前端在处理 3D 视觉交互时的技术选型博弈，以及如何用一行极度硬核的 &lt;code&gt;ffmpeg&lt;/code&gt; 优化命令，彻底榨干移动端 3D 交互的性能🤔。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 data-id=&quot;heading-0&quot;&gt;网页端 3D 交互的三种技术路线&lt;/h3&gt;
&lt;p&gt;在网页端实现 360 度商品预览，行业里目前主要有三条路线，每一条我都踩过深坑：&lt;/p&gt;
&lt;h4 data-id=&quot;heading-1&quot;&gt;路线 1：多帧图片序列拼接（Sprite 拼图）&lt;/h4&gt;
&lt;p&gt;通过在影棚里用 36 个或 72 个角度拍摄商品照片，最后在前端通过鼠标/触摸事件，动态切换 &lt;code&gt;img&lt;/code&gt; 的 &lt;code&gt;src&lt;/code&gt; 或者是控制一张超大雪碧图（Sprite）的 &lt;code&gt;background-position&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;加载极其恶心。72 张高分辨率图片合起来起码有 20MB。如果你不预加载，用户划动时会严重闪烁白屏；如果你预加载，用户的网络带宽会被瞬间吃满，首屏直接卡死。这个方案直接 Pass👋&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/24457b07d4e84a989b92f3cba7237acc~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgRXJwYW5PbWVy:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780285921&amp;amp;x-signature=NH2Q7jNcXkcLsPP2vcX9EDsIOpM%3D&quot; alt=&quot;20260525-104637.gif&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;h4 data-id=&quot;heading-2&quot;&gt;路线 2：&lt;code&gt;Three.js / WebGL&lt;/code&gt; 原生模型渲染&lt;/h4&gt;
&lt;p&gt;直接把 3D 模型文件（&lt;code&gt;glTF、USDZ&lt;/code&gt;）加载到页面中，用 &lt;code&gt;WebGL&lt;/code&gt; 渲染器进行实时光照和渲染。&lt;/p&gt;
&lt;p&gt;这个方案是可行，也是比较主流， 但性能开销是灾难级的。移动端 &lt;code&gt;GPU&lt;/code&gt; 加速会导致手机迅速发烫。更致命的是，为了能在网页端流畅运行，美术必须对模型进行极度残忍的减面和贴图压缩，导致渲染出来的材质有一股极其廉价的塑料感，完全失去了高端商品的质感🤷‍♂️。&lt;/p&gt;
&lt;h4 data-id=&quot;heading-3&quot;&gt;路线 3：3D 离线渲染视频 + 视频帧控制（&lt;code&gt;Video Scrubbing&lt;/code&gt;）&lt;/h4&gt;
&lt;p&gt;让 3D 美术直接在 &lt;code&gt;Blender&lt;/code&gt; 或 &lt;code&gt;C4D&lt;/code&gt; 里，用最顶级的离线光线追踪（Ray Tracing）渲染器，渲染一段商品匀速自转一圈的高保真视频（比如 2 秒，60帧）。
在前端，我们直接使用 &lt;code&gt;video&lt;/code&gt; 标签嵌入这段视频，禁用自动播放。当用户在屏幕上左右滑动时，我们不播放视频，而是&lt;strong&gt;计算滑动的位移量，直接修改 &lt;code&gt;video.currentTime&lt;/code&gt;&lt;/strong&gt;，实现手动拨动商品旋转的效果。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-html&quot; lang=&quot;html&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;video-3d video-3d--inline js-video-3d &quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;data-video-3d-mode&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;inline&quot;&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;data-video-src&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;https://cdn.shopify.com/videos/c/o/v/b34e306cdf7d460881139e3b2820d092.mp4&quot;&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;data-desktop-video-src&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;https://cdn.shopify.com/videos/c/o/v/b34e306cdf7d460881139e3b2820d092.mp4&quot;&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;data-mobile-video-src&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;https://cdn.shopify.com/videos/c/o/v/3e7ca0f840074648943a3ce065ed9f00.mp4&quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;data-poster-src&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;data-preload&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;metadata&quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;data-lazy-load&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;true&quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;data-rotate-sensitivity&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;1&quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;data-duration-fallback&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;3&quot;&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;data-mobile-seek-fps&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;30&quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;data-enable-zoom&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;data-min-zoom&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;1&quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;data-max-zoom&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;2&quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;data-wheel-step&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;0.08&quot;&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;data-trigger-selector&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;style&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;
    --video-3d-bg: #f7f7f7;
    --video-3d-aspect-ratio: 1280 / 880;
    --video-3d-object-fit: contain;
    --video-3d-dialog-width: 1600px;
  &quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;aria-label&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;Interactive 360 degree product video&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;video-3d__viewer js-video-3d-viewer is-metadata-ready is-ready is-interacted is-motion-enabled&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;video-3d__stage js-video-3d-stage&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;video-3d__media js-video-3d-media&quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;style&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;transform: translate3d(0px, 0px, 0px) scale(1);&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;video&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;video-3d__video js-video-3d-video&quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;muted&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;playsinline&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;webkit-playsinline&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;preload&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;auto&quot;&lt;/span&gt;
          &lt;span class=&quot;hljs-attr&quot;&gt;draggable&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;disablepictureinpicture&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;controlslist&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;nodownload noplaybackrate noremoteplayback&quot;&lt;/span&gt;
          &lt;span class=&quot;hljs-attr&quot;&gt;aria-label&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;Interactive 360 degree product video&quot;&lt;/span&gt;
          &lt;span class=&quot;hljs-attr&quot;&gt;src&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;https://cdn.shopify.com/videos/c/o/v/b34e306cdf7d460881139e3b2820d092.mp4&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;video&lt;/span&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;video-3d__loader&quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;aria-hidden&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;true&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;span&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;video-3d__spinner&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;span&lt;/span&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;video-3d__hint js-video-3d-hint&quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;aria-hidden&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;true&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;
        Drag to rotate / 360 view
      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;video-3d__reduced-button js-video-3d-reduced-button&quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;type&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;button&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;
        Enable 360 view
      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;button&lt;/span&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;video-3d__error&quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;role&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;status&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;
        360 video is unavailable.
      &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;渲染质量是电影级的，金属的光泽、皮革的纹理完美保留；视频文件的压缩率极高，一段 &lt;code&gt;1080P&lt;/code&gt; 的自转视频可以被压缩到 1MB 左右，加载极快，且完全不消耗手机 &lt;code&gt;GPU&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/e2df194e6c674266aafa22b2f854d837~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgRXJwYW5PbWVy:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780285921&amp;amp;x-signature=UNpM4yYEsJBAbSEqt2Kh%2FST0ekM%3D&quot; alt=&quot;20260525-103313.gif&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;但这套方案有一个致命的问题：在移动端，当你用手指快速滑动屏幕时，视频画面会产生极其严重的卡顿、抖动和明显的延迟响应。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 data-id=&quot;heading-4&quot;&gt;为什么在移动端，视频拖动会卡顿？&lt;/h3&gt;
&lt;p&gt;在解决这个问题前，我们必须先理解视频编码的底层机制。&lt;/p&gt;
&lt;p&gt;视频之所以能被压缩得这么小，是因为它采用了 &lt;strong&gt;帧间压缩（Temporal Compression）&lt;/strong&gt; 技术。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/c8608163127843c5a067aff64e8b72a8~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgRXJwYW5PbWVy:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780285921&amp;amp;x-signature=5m8y15r77SLa2DkRggrB6jVyxzM%3D&quot; alt=&quot;ChatGPT Image 2026年5月25日 11_37_09.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;视频帧被分为三种类型：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;I 帧（Intra-coded picture，关键帧）：&lt;/strong&gt; 包含完整的单张静态图像，可以独立解码（相当于一张完整的 JPEG 格式图片）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;P 帧（Predicted picture，预测帧）：&lt;/strong&gt; 只记录与前一个帧的差异数据。解码它，必须先解码它前面的帧。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;B 帧（Bi-directional predicted picture，双向预测帧）：&lt;/strong&gt; 记录与前后帧的差异。解码它，需要同时参考前一帧和后一帧。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为了最大化压缩体积，常规视频的 I 帧间隔（也就是常说的 GOP 尺寸）非常大，通常是 250 帧以上。这意味着每隔 250 帧才有一个完整的关键帧。&lt;/p&gt;
&lt;p&gt;当你用手指快速拖拽商品时，浏览器需要将 &lt;code&gt;video.currentTime&lt;/code&gt; 频繁设置到任意时间点（比如从第 10 帧跳转到第 45 帧）。&lt;/p&gt;
&lt;p&gt;这时，浏览器的视频解码器会瞬间崩溃。因为它为了渲染出第 45 帧（P/B帧），&lt;strong&gt;必须强行回溯到第 1 帧（最近的 I 帧），然后一口气在内存中把中间的 44 帧全部计算一遍&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/dbdfa02141e44a089ea99e6473e5b459~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgRXJwYW5PbWVy:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780285921&amp;amp;x-signature=Me5lZYVrq8eesoAFhcfr8Drs7rI%3D&quot; alt=&quot;ChatGPT Image 2026年5月25日 11_32_59.png&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;如果用户在屏幕上快速来回摩擦，解码器的计算量会呈指数级飙升，导致严重的掉帧、卡死和发热。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 data-id=&quot;heading-5&quot;&gt;用ffmpeg 降维打击：一行命令解决移动端 3D 抖动&lt;/h3&gt;
&lt;p&gt;既然找到了病因，解法就非常明确了：&lt;strong&gt;我们需要通过特定的编码参数，彻底摧毁视频的帧间依赖，让浏览器能够以极低的 CPU 开销，进行任意帧的瞬间定位（Scrubbing）。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;经过对 iOS Safari 和各大安卓浏览器内核的反复压测，我最终整理出了下面这行专为移动端交互而生的 &lt;code&gt;ffmpeg&lt;/code&gt; 优化命令：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot; lang=&quot;bash&quot;&gt;ffmpeg -i input.mp4 -an -vf &lt;span class=&quot;hljs-string&quot;&gt;&quot;scale=1280:880,fps=30,format=yuv420p&quot;&lt;/span&gt; \
-c:v libx264 -profile:v main -level:v 4.0 -preset slow -crf 22 \
-g 6 -keyint_min 6 -sc_threshold 0 -bf 0 -movflags +faststart \
product-360-mobile-gop6.mp4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这行命令看起来普通，但每一个参数都是为了榨干移动端 H.264 解码性能而精确调优的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-an&lt;/code&gt;： 彻底剥离音频。商品交互图不需要声音，删掉音频不仅能省带宽，还能防止浏览器因为自动播放/媒体策略而拦截视频。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-g 6 -keyint_min 6&lt;/code&gt;：强行将最大和最小 GOP 长度锁死在 6 帧。在 30fps 的视频里，这意味着每隔 0.2 秒就有一个绝对完整的 I 帧。浏览器在任意定位时，最多只需要解码 5 个中间帧，瞬间降低解码器的内存计算负载。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-sc_threshold 0&lt;/code&gt;： 禁用场景切换检测。防止 &lt;code&gt;ffmpeg&lt;/code&gt; 在画面变动大时擅自插入额外的非等距 I 帧，确保关键帧分布极其均匀，保证滑动时的手感绝对线性。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;-bf 0&lt;/code&gt;：&lt;/strong&gt; &lt;strong&gt;【致命一击】&lt;/strong&gt; 彻底禁用 B 帧（双向预测帧）。B 帧需要向前向后双向查找，在来回摩擦交互时，B 帧是造成卡顿的第一元凶。设置为 0 之后，视频只保留 I 帧和 P 帧，解码器只需单向线性解码，速度发生质的飞跃。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;-movflags +faststart&lt;/code&gt;：&lt;/strong&gt; 将视频的索引信息（moov atom）强行移动到文件的最头部。这样浏览器只要下载了视频开头的几个字节，就能立刻开始响应拖拽定位，无需等待整个视频加载完毕。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;通过这行命令导出的 &lt;code&gt;1280x880&lt;/code&gt; 视频，文件体积控制在 800KB 左右。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 data-id=&quot;heading-6&quot;&gt;将手势映射到视频时间轴&lt;/h3&gt;
&lt;p&gt;底层地基用 &lt;code&gt;ffmpeg&lt;/code&gt; 夯实之后，前端的代码实现变得极其清爽，甚至不需要引入任何第三方库。&lt;/p&gt;
&lt;p&gt;我们只需要监听 &lt;code&gt;touchstart&lt;/code&gt; 和 &lt;code&gt;touchmove&lt;/code&gt; 事件，计算出滑动的距离比例，然后等比映射到视频的 &lt;code&gt;duration&lt;/code&gt; 即可：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot; lang=&quot;javascript&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// 前端 3D 视频控制逻辑&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; video = &lt;span class=&quot;hljs-variable language_&quot;&gt;document&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;getElementById&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&#39;product-360-video&#39;&lt;/span&gt;);
&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; startX = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;
&lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; startProgress = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;

&lt;span class=&quot;hljs-comment&quot;&gt;// 阻止默认的滚屏行为，专心处理左右摩擦&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;handleTouchStart&lt;/span&gt; = (&lt;span class=&quot;hljs-params&quot;&gt;e&lt;/span&gt;) =&amp;gt; {
  startX = e.&lt;span class=&quot;hljs-property&quot;&gt;touches&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;].&lt;span class=&quot;hljs-property&quot;&gt;clientX&lt;/span&gt;;
  &lt;span class=&quot;hljs-comment&quot;&gt;// 记录开始滑动时视频的当前进度比例&lt;/span&gt;
  startProgress = video.&lt;span class=&quot;hljs-property&quot;&gt;currentTime&lt;/span&gt; / video.&lt;span class=&quot;hljs-property&quot;&gt;duration&lt;/span&gt;;
};

&lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;handleTouchMove&lt;/span&gt; = (&lt;span class=&quot;hljs-params&quot;&gt;e&lt;/span&gt;) =&amp;gt; {
  &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (!video.&lt;span class=&quot;hljs-property&quot;&gt;duration&lt;/span&gt;) &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt;;
  
  &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; currentX = e.&lt;span class=&quot;hljs-property&quot;&gt;touches&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;].&lt;span class=&quot;hljs-property&quot;&gt;clientX&lt;/span&gt;;
  &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; deltaX = currentX - startX;
  
  &lt;span class=&quot;hljs-comment&quot;&gt;// 视口宽度对应的最大滑动距离，可以根据手感调整阻尼系数&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; swipeRange = &lt;span class=&quot;hljs-variable language_&quot;&gt;window&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;innerWidth&lt;/span&gt; * &lt;span class=&quot;hljs-number&quot;&gt;1.5&lt;/span&gt;; 
  &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; progressDelta = deltaX / swipeRange;
  
  &lt;span class=&quot;hljs-comment&quot;&gt;// 计算最新的进度，并做好边界处理（首尾循环相连）&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; nextProgress = startProgress - progressDelta;
  &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (nextProgress &amp;lt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;) nextProgress += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;
  &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (nextProgress &amp;gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;) nextProgress -= &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;
  
  &lt;span class=&quot;hljs-comment&quot;&gt;// 精确跳转到目标帧时间，由于 -bf 0 和低 GOP 限制，这次跳转将是 0 延迟的&lt;/span&gt;
  video.&lt;span class=&quot;hljs-property&quot;&gt;currentTime&lt;/span&gt; = nextProgress * video.&lt;span class=&quot;hljs-property&quot;&gt;duration&lt;/span&gt;;
};

video.&lt;span class=&quot;hljs-title function_&quot;&gt;addEventListener&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&#39;touchstart&#39;&lt;/span&gt;, handleTouchStart, { &lt;span class=&quot;hljs-attr&quot;&gt;passive&lt;/span&gt;: &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt; });
video.&lt;span class=&quot;hljs-title function_&quot;&gt;addEventListener&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&#39;touchmove&#39;&lt;/span&gt;, handleTouchMove, { &lt;span class=&quot;hljs-attr&quot;&gt;passive&lt;/span&gt;: &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt; });
&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 data-id=&quot;heading-7&quot;&gt;感受&lt;/h3&gt;
&lt;p&gt;在前端圈，大家很容易陷入一种唯技术论的误区。觉得用上了最新的 &lt;code&gt;WebGL&lt;/code&gt;、写了一大堆复杂的 &lt;code&gt;Shader&lt;/code&gt; 材质、给页面塞了十几兆的 &lt;code&gt;3D&lt;/code&gt; 模型，这才叫技术实力。&lt;/p&gt;
&lt;p&gt;但对于要扛起商业转化率、注重用户体验的真实项目（尤其是跨境独立站）来说，&lt;strong&gt;在保证画质达到电影级的前提下，用最轻量的带宽、最低的硬件功耗，实现绝对丝滑的交互，才是真正的工程品味😁。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;下一次面对类似的 360 度交互需求，别急着去写几百行复杂的 &lt;code&gt;Three.js&lt;/code&gt; 逻辑了。&lt;/p&gt;
&lt;p&gt;试着用 &lt;code&gt;C4D&lt;/code&gt; 导出一款高保真视频，配合这行 &lt;code&gt;ffmpeg&lt;/code&gt; 命令，你只需要用三十行干净的原生 &lt;code&gt;JS&lt;/code&gt; 代码，就能在移动端上，给用户呈现出丝滑无比、极其惊艳的 &lt;code&gt;3D&lt;/code&gt; 视觉体验。&lt;/p&gt;
&lt;p&gt;如果喜欢 点赞 + 收藏😁&lt;/p&gt;
&lt;p align=&quot;center&quot;&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/2a9b17df126744478d631dac2dacb646~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgRXJwYW5PbWVy:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780285921&amp;amp;x-signature=huwCeZPRXFjGPcVb2CZxVb37wUc%3D&quot; alt=&quot;谢谢大家.gif&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;</description><link>https://juejin.cn/post/7643210854389661730</link><guid isPermaLink="false">https://juejin.cn/post/7643210854389661730</guid><pubDate>Mon, 25 May 2026 03:52:02 GMT</pubDate><author>ErpanOmer</author><category></category><category>前端</category><category>JavaScript</category><category>程序员</category></item><item><title>尤雨溪亲自点赞！用 Vue 3 写原生 App，这个框架终于来了！</title><description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;告别 WebView 的卡顿，像写 Vue 3 一样写真正的原生应用&lt;/strong&gt;
这一次，你的 &lt;code&gt;.vue&lt;/code&gt; 文件可以直接跑出 Swift/Kotlin 的性能！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;大家好，我是大鱼。&lt;/p&gt;
&lt;p&gt;在移动端开发的世界里，Vue 开发者似乎总是“低人一等”。&lt;/p&gt;
&lt;p&gt;React 有 &lt;strong&gt;React Native&lt;/strong&gt;，Google 有 &lt;strong&gt;Flutter&lt;/strong&gt;，而 Vue 生态长期缺少一个能与之并肩的“真·原生”跨平台方案。&lt;/p&gt;
&lt;p&gt;直到 &lt;strong&gt;NativeScript-Vue 3&lt;/strong&gt; 的出现，并被 &lt;strong&gt;Vue 之父尤雨溪亲自点赞&lt;/strong&gt;——这一切，终于迎来了改变。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 data-id=&quot;heading-0&quot;&gt;🧐 它是什么？为什么尤大亲自站台？&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;NativeScript-Vue 3&lt;/strong&gt; 是一个基于 Vue 3 核心的&lt;strong&gt;跨平台原生移动开发框架&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;它的核心理念很简单：&lt;strong&gt;没有 WebView，没有 DOM&lt;/strong&gt;——你写的 &lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt; 直接编译成 iOS 的 &lt;code&gt;UIKit&lt;/code&gt; 和 Android 的 &lt;code&gt;AppCompat&lt;/code&gt; &lt;strong&gt;原生组件&lt;/strong&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;一句话总结：&lt;strong&gt;Vue 的自定义渲染器 + NativeScript 原生引擎&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 data-id=&quot;heading-1&quot;&gt;📱 小程序支持？先说清楚！&lt;/h2&gt;
&lt;p&gt;这是很多读者最关心的问题，我直接把结论放在前面：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;❌ NativeScript-Vue 3 不支持微信小程序、支付宝小程序、抖音小程序等任何小程序平台。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;它的定位非常纯粹：&lt;strong&gt;只做 iOS 和 Android 原生 App&lt;/strong&gt;，一套代码，两端运行。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-2&quot;&gt;为什么不做小程序？&lt;/h3&gt;
&lt;p&gt;这是框架的设计哲学决定的：&lt;/p&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;技术特性&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;NativeScript-Vue&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;uni-app / Taro&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;渲染层&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;原生 UIKit/AppCompat&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;WebView / 小程序专用渲染&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;运行环境&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;V8 / JavaScriptCore&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;小程序运行时 / WebView&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;核心目标&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;原生级别性能&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;多端适配能力&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;NativeScript 的底层原理是&lt;strong&gt;直接调用 iOS/Android 的原生 API&lt;/strong&gt;，而小程序的运行环境是完全不同的生态，两者不兼容。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-3&quot;&gt;那我想要小程序怎么办？&lt;/h3&gt;
&lt;p&gt;如果你需要覆盖 &lt;strong&gt;小程序 + App + H5&lt;/strong&gt;，目前主流的选择仍然是 &lt;strong&gt;uni-app&lt;/strong&gt; 或 &lt;strong&gt;Taro&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;但如果你满足以下条件，NativeScript-Vue 3 会是更好的选择：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;✅ 只做 iOS / Android，不需要小程序&lt;/li&gt;
&lt;li&gt;✅ 追求接近原生的性能（重动画、重交互、长列表流畅）&lt;/li&gt;
&lt;li&gt;✅ 团队熟悉 Vue 3 生态，不想学 Swift/Kotlin&lt;/li&gt;
&lt;li&gt;✅ 需要直接调用硬件能力（蓝牙、NFC、传感器等）&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;一句话总结&lt;/strong&gt;：想多端通吃选 uni-app，想做精品原生 App 选 NativeScript-Vue。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 data-id=&quot;heading-4&quot;&gt;💔 为什么是时候说再见了？&lt;/h2&gt;
&lt;p&gt;很多朋友还在用 uni-app 或 Hybrid 方案，但其中的痛点只有开发者自己知道：&lt;/p&gt;






























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;维度&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;传统混合开发&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;NativeScript-Vue 3&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;渲染机制&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;WebView 渲染，启动慢、长列表卡顿&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;原生渲染&lt;/strong&gt;，直接调用系统 UI 组件&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;原生能力&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;需要各种桥接、renderjs，维护成本高&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;直接调用&lt;/strong&gt;原生 API 和 SDK，零延迟&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;开发体验&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;厂商锁仓，Vite/Pinia 支持滞后&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;Vite + TS + Vue 3&lt;/strong&gt; 全家桶，现代前端体验&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;包体积&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;自带 WebView 内核，体积臃肿&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;纯原生二进制包，&lt;strong&gt;平均小 30%&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;有了它，你不仅获得了 React Native 同级别的性能，还保留了 Vue 3 极致的开发体验。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 data-id=&quot;heading-5&quot;&gt;✨ 三大核心特性：Vueer 的“王炸”&lt;/h2&gt;
&lt;h3 data-id=&quot;heading-6&quot;&gt;1. 纯粹的 Vue 3 开发体验&lt;/h3&gt;
&lt;p&gt;完全支持 &lt;code&gt;&amp;lt;script setup&amp;gt;&lt;/code&gt;、Composition API、响应式系统。你甚至可以直接使用 &lt;strong&gt;Pinia&lt;/strong&gt; 作为状态管理，零改动接入！&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-vue&quot; lang=&quot;vue&quot;&gt;&amp;lt;script setup&amp;gt;
import { ref } from &#39;vue&#39;;

const count = ref(0);
const message = ref(&#39;Hello Native!&#39;);
&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
  &amp;lt;Page&amp;gt;
    &amp;lt;ActionBar title=&quot;我的原生App&quot; /&amp;gt;
    &amp;lt;StackLayout class=&quot;p-4&quot;&amp;gt;
      &amp;lt;Label :text=&quot;message&quot; class=&quot;text-2xl&quot; /&amp;gt;
      &amp;lt;Button @tap=&quot;count++&quot; :text=&quot;`点击次数：${count}`&quot; /&amp;gt;
    &amp;lt;/StackLayout&amp;gt;
  &amp;lt;/Page&amp;gt;
&amp;lt;/template&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-id=&quot;heading-7&quot;&gt;2. 超强“外挂”：直接调用原生 API&lt;/h3&gt;
&lt;p&gt;这是它最硬核的地方。它&lt;strong&gt;没有桥接层&lt;/strong&gt;，JS 和原生运行在同一线程，&lt;strong&gt;同步直接调用&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这意味着你可以直接在 Vue 组件里写 Android 的 &lt;code&gt;Intent&lt;/code&gt; 跳转或 iOS 的 &lt;code&gt;CBCentralManager&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-javascript&quot; lang=&quot;javascript&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// 直接在组件中调用原生设备信息&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; { device } &lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&#39;@nativescript/core&#39;&lt;/span&gt;;

&lt;span class=&quot;hljs-variable language_&quot;&gt;console&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;log&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;`系统版本: &lt;span class=&quot;hljs-subst&quot;&gt;${device.osVersion}&lt;/span&gt;`&lt;/span&gt;);
&lt;span class=&quot;hljs-variable language_&quot;&gt;console&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;log&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;`设备型号: &lt;span class=&quot;hljs-subst&quot;&gt;${device.model}&lt;/span&gt;`&lt;/span&gt;);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-id=&quot;heading-8&quot;&gt;3. Vite 加持的极速热重载&lt;/h3&gt;
&lt;p&gt;终于，移动端开发也能享受 Web 端的&lt;strong&gt;毫秒级 HMR&lt;/strong&gt;了！保存代码，模拟器直接更新，无需重新编译。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 data-id=&quot;heading-9&quot;&gt;🛠️ 5 分钟极速上手&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;第一步：安装 NativeScript CLI&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot; lang=&quot;bash&quot;&gt;npm install -g @nativescript/cli
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;第二步：创建 Vue 3 项目&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot; lang=&quot;bash&quot;&gt;ns create my-vue-app --template @nativescript/vue-template
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;第三步：运行起来！&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot; lang=&quot;bash&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 连接手机或打开模拟器&lt;/span&gt;
ns run android   &lt;span class=&quot;hljs-comment&quot;&gt;# 或 ns run ios&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;你会发现，你的第一个纯原生 Vue App 就跑起来了！🚀&lt;/p&gt;
&lt;hr&gt;
&lt;h2 data-id=&quot;heading-10&quot;&gt;⚠️ 避坑指南（必看！）&lt;/h2&gt;
&lt;p&gt;虽然很香，但由于架构不同，&lt;strong&gt;Vue 生态的部分库是无法使用的&lt;/strong&gt;：&lt;/p&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th align=&quot;left&quot;&gt;插件&lt;/th&gt;&lt;th align=&quot;center&quot;&gt;是否可用&lt;/th&gt;&lt;th align=&quot;left&quot;&gt;说明&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;Pinia&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✅&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;零改动，直接使用&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;vue-i18n&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;✅&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;实测正常&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;VueUse&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;⚠️&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;仅无 DOM 的 Utilities 可用&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;Vue Router&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;❌&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;官方推荐用 NativeScript 帧导航 &lt;code&gt;$navigateTo&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td align=&quot;left&quot;&gt;&lt;strong&gt;Vuetify / Element Plus&lt;/strong&gt;&lt;/td&gt;&lt;td align=&quot;center&quot;&gt;❌&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;依赖 CSS &amp;amp; DOM，无法渲染&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;检测小技巧&lt;/strong&gt;：安装包后，&lt;code&gt;grep -r &quot;document\|window&quot; node_modules/xxx&lt;/code&gt;，没输出说明大概率安全！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 data-id=&quot;heading-11&quot;&gt;🗣️ 真实体验：一个月的开发经历告诉你&lt;/h2&gt;
&lt;p&gt;有开发者用 NativeScript-Vue 3 花了一个月时间，做了一个&lt;strong&gt;完整的日程管理+AI助手 App&lt;/strong&gt;（影时间），他的真实感受是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;好的地方：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用 Vue 写原生 UI，Composition API 0 学习成本&lt;/li&gt;
&lt;li&gt;同步调用原生 API 很爽，没有延迟&lt;/li&gt;
&lt;li&gt;包体积小，启动快&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;不太爽的地方：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;社区真的小，问题搜不到，文档写得比较简略&lt;/li&gt;
&lt;li&gt;调试有时候头疼，原生堆栈错误要自己定位&lt;/li&gt;
&lt;li&gt;JS 在主线程运行，耗时计算会阻塞 UI（适合中小项目）&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h2 data-id=&quot;heading-12&quot;&gt;🎯 写在最后&lt;/h2&gt;
&lt;p&gt;Flutter 很强，RN 也很成熟，但如果你是一个 &lt;strong&gt;Vue 3&lt;/strong&gt; 的忠实拥趸，&lt;strong&gt;NativeScript-Vue 3&lt;/strong&gt; 是你涉足原生应用开发最优雅、最低成本的路径。&lt;/p&gt;
&lt;p&gt;它让 Vue 语法第一次 &lt;strong&gt;完整、无损、高性能&lt;/strong&gt; 地跑在 iOS &amp;amp; Android 上。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;但请理性选择：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;需要小程序？👉 &lt;strong&gt;选 uni-app 或者 taro&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;做精品原生 App？👉 &lt;strong&gt;NativeScript-Vue 值得一试&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;</description><link>https://juejin.cn/post/7642933445875007534</link><guid isPermaLink="false">https://juejin.cn/post/7642933445875007534</guid><pubDate>Mon, 25 May 2026 03:42:09 GMT</pubDate><author>大前端历险记</author><category></category><category>前端</category><category>Vue.js</category></item><item><title>IntelliJ IDEA 从卡顿到起飞，只用改这些。。。</title><description>&lt;h2 data-id=&quot;heading-0&quot;&gt;前言&lt;/h2&gt;
&lt;p&gt;今天不聊高并发、不聊架构设计，想和大家聊一个每位Java程序员每天都在用的工具——IntelliJ IDEA。&lt;/p&gt;
&lt;p&gt;说实话，用了多年IDEA，我踩过不少坑。&lt;/p&gt;
&lt;p&gt;今天我把最经典的10个坑整理出来，希望能帮大家少走一些弯路。&lt;/p&gt;
&lt;p&gt;很多小伙伴在工作中肯定也遇到过类似的问题，比如“IDEA突然变卡了”、“代码明明没错就是编译不过”、“Debug的时候断点不生效”等等。&lt;/p&gt;
&lt;p&gt;这篇文章没有高深的理论，全是实战经验，小白也能看懂。&lt;/p&gt;
&lt;p&gt;希望对你会有所帮助。&lt;/p&gt;
&lt;p&gt;更多项目实战在我的技术网站：susan.net.cn/project&lt;/p&gt;
&lt;h2 data-id=&quot;heading-1&quot;&gt;IDEA的优缺点和使用场景&lt;/h2&gt;
&lt;p&gt;在正式开讲之前，我们先来客观地看一下IDEA这款IDE到底好在哪、不好在哪，以及适合什么场景。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-2&quot;&gt;IDEA的优点&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;智能代码提示&lt;/strong&gt;：相比Eclipse，IDEA的代码分析引擎更强大，能根据上下文给出更精准的补全建议。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;重构能力极强&lt;/strong&gt;：重命名、提取方法、改变签名等重构操作非常安全，能自动修复所有引用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内置工具丰富&lt;/strong&gt;：版本控制、数据库客户端、HTTP Client、终端等一应俱全，不用来回切换。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;插件生态完善&lt;/strong&gt;：Lombok、MyBatis、SonarLint等插件几乎覆盖了所有开发场景。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;调试功能强大&lt;/strong&gt;：条件断点、表达式求值、远程调试、内存分析等，排查问题非常高效。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-id=&quot;heading-3&quot;&gt;IDEA的缺点&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;内存占用较高&lt;/strong&gt;：默认配置下轻松吃掉2-4G内存，老机器跑起来比较吃力。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;索引机制耗时&lt;/strong&gt;：每次导入项目或依赖变更，都会触发重新索引，大项目可能要等几分钟。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;配置相对复杂&lt;/strong&gt;：很多优化需要手动调整，新手容易被各种设置搞晕。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;商业软件&lt;/strong&gt;：Ultimate版本收费，虽然可以用Community版，但很多企业级功能（如Spring、JPA、JS等）需要付费。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-id=&quot;heading-4&quot;&gt;适用场景&lt;/h3&gt;








































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;场景&lt;/th&gt;&lt;th&gt;是否推荐&lt;/th&gt;&lt;th&gt;说明&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;大型Java/Spring项目&lt;/td&gt;&lt;td&gt;⭐⭐⭐⭐⭐&lt;/td&gt;&lt;td&gt;IDEA的Spring支持无出其右&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;中小型Web项目&lt;/td&gt;&lt;td&gt;⭐⭐⭐⭐⭐&lt;/td&gt;&lt;td&gt;开发效率远高于Eclipse&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;多语言混合项目（Java+JS+Python）&lt;/td&gt;&lt;td&gt;⭐⭐⭐⭐⭐&lt;/td&gt;&lt;td&gt;Ultimate版支持所有主流语言&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;老旧机器（内存&amp;lt;8G）&lt;/td&gt;&lt;td&gt;⭐⭐&lt;/td&gt;&lt;td&gt;勉强能用，但建议升级配置或换VS Code&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;纯前端项目&lt;/td&gt;&lt;td&gt;⭐⭐&lt;/td&gt;&lt;td&gt;VS Code可能更合适&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;学生/开源学习&lt;/td&gt;&lt;td&gt;⭐⭐⭐⭐&lt;/td&gt;&lt;td&gt;Community版足够用&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;好了，了解这些背景之后，咱们正式进入主题——我踩过的10个坑。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-5&quot;&gt;第1个坑：越用越卡，CPU狂飙&lt;/h2&gt;
&lt;h3 data-id=&quot;heading-6&quot;&gt;现象&lt;/h3&gt;
&lt;p&gt;IDEA打开两三个小时之后，敲个代码都要卡两秒，鼠标转圈圈，CPU动不动就100%。&lt;/p&gt;
&lt;p&gt;重启一下又好一会儿，过一会儿又卡了。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-7&quot;&gt;原因分析&lt;/h3&gt;
&lt;p&gt;IDEA的卡顿通常有两个原因：&lt;strong&gt;内存分配不足&lt;/strong&gt;和&lt;strong&gt;索引被频繁触发&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;先说说内存。&lt;/p&gt;
&lt;p&gt;IDEA默认的堆内存只有512MB-1GB左右，对于现代项目（尤其是微服务项目，一个workspace里有十几个module）来说，这点内存根本不够用。&lt;/p&gt;
&lt;p&gt;JVM频繁进行Full GC，自然就卡了。&lt;/p&gt;
&lt;p&gt;再说说索引。&lt;/p&gt;
&lt;p&gt;IDEA会对项目中的所有文件建立索引，以便实现快速搜索、跳转等功能。&lt;/p&gt;
&lt;p&gt;但是如果你开启了“自动索引外部文件”或者项目中有一个巨大的&lt;code&gt;node_modules&lt;/code&gt;文件夹（前端同学懂得），IDEA就会一直尝试索引这些根本不需要索引的文件，CPU直接拉满。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-8&quot;&gt;解决方案&lt;/h3&gt;
&lt;p&gt;第一步，手动调整IDEA的内存配置。&lt;/p&gt;
&lt;p&gt;找到IDEA安装目录下的&lt;code&gt;idea64.exe.vmoptions&lt;/code&gt;文件（Mac在&lt;code&gt;/Applications/IntelliJ IDEA.app/Contents/bin/idea.vmoptions&lt;/code&gt;），修改以下参数：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-properties&quot; lang=&quot;properties&quot;&gt;# 建议配置（8G内存机器）
-Xms2048m           # 初始堆内存，建议直接给到2G
-Xmx4096m           # 最大堆内存，给到4G
-XX:ReservedCodeCacheSize=512m   # 代码缓存
-XX:+UseG1GC        # 使用G1垃圾回收器，减少停顿
-XX:+UseStringDeduplication  # 去重字符串，节省内存
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第二步，排除不需要索引的目录。&lt;/p&gt;
&lt;p&gt;打开 &lt;code&gt;File -&amp;gt; Settings -&amp;gt; Project Structure -&amp;gt; Modules&lt;/code&gt;，把那些不需要索引的文件夹（如&lt;code&gt;node_modules&lt;/code&gt;、&lt;code&gt;.git&lt;/code&gt;、&lt;code&gt;target&lt;/code&gt;、&lt;code&gt;build&lt;/code&gt;等）标记为&lt;code&gt;Excluded&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;转存失败，建议直接上传图片文件&quot; src=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;做完这两步，IDEA的流畅度会有一个质的飞跃。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-9&quot;&gt;第2个坑：getter/setter报红&lt;/h2&gt;
&lt;h3 data-id=&quot;heading-10&quot;&gt;现象&lt;/h3&gt;
&lt;p&gt;本来好好的项目，更新了IDEA或者改了某个配置之后，所有用&lt;code&gt;@Data&lt;/code&gt;、&lt;code&gt;@Getter&lt;/code&gt;注解的类的调用地方突然飘红，编译失败，提示“找不到getXxx方法”。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-11&quot;&gt;原因分析&lt;/h3&gt;
&lt;p&gt;Lombok的工作原理是在编译期通过注解处理器自动生成getter/setter等代码。&lt;/p&gt;
&lt;p&gt;IDEA需要安装Lombok插件才能识别这些生成的代码，否则就会报红。&lt;/p&gt;
&lt;p&gt;这个坑通常发生在以下几种情况：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;升级IDEA后，旧版Lombok插件不兼容&lt;/li&gt;
&lt;li&gt;项目的Lombok依赖版本和插件版本不一致&lt;/li&gt;
&lt;li&gt;开启了IDEA的“注解处理”但没有正确配置&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-id=&quot;heading-12&quot;&gt;解决方案&lt;/h3&gt;
&lt;p&gt;第一步，检查Lombok插件是否安装并启用。&lt;code&gt;File -&amp;gt; Settings -&amp;gt; Plugins&lt;/code&gt; 搜索Lombok，确保已安装且勾选。&lt;/p&gt;
&lt;p&gt;第二步，打开&lt;code&gt;File -&amp;gt; Settings -&amp;gt; Build, Execution, Deployment -&amp;gt; Compiler -&amp;gt; Annotation Processors&lt;/code&gt;，勾选“Enable annotation processing”。&lt;/p&gt;
&lt;p&gt;第三步，确保项目的pom.xml或build.gradle中引入了Lombok依赖，并且版本不要太老。推荐版本：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-xml&quot; lang=&quot;xml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;&amp;lt;!-- Maven --&amp;gt;&lt;/span&gt;
&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;org.projectlombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;groupId&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;lombok&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;artifactId&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;1.18.30&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;version&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;provided&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;scope&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;dependency&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第四步，如果上面三步都做了还是不行，尝试 &lt;code&gt;File -&amp;gt; Invalidate Caches and Restart&lt;/code&gt;，清空IDEA的缓存并重启。这个操作能解决IDEA里80%的玄学问题。&lt;/p&gt;
&lt;p&gt;有一次我遇到一个特别诡异的情况：同一个项目，同事的IDEA没问题，我的就是报红。&lt;/p&gt;
&lt;p&gt;最后发现是&lt;code&gt;.idea&lt;/code&gt;目录下的配置文件冲突了，删掉&lt;code&gt;.idea&lt;/code&gt;目录让IDEA重新生成就正常了。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-13&quot;&gt;第3个坑：Debug断点死活进不去&lt;/h2&gt;
&lt;h3 data-id=&quot;heading-14&quot;&gt;现象&lt;/h3&gt;
&lt;p&gt;调试的时候，我在一个Service方法的第一行打了个断点，但是跑起来断点根本不生效，代码直接执行过去了。&lt;/p&gt;
&lt;p&gt;更离谱的是，有时候断点上的对勾是灰色的。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-15&quot;&gt;原因分析&lt;/h3&gt;
&lt;p&gt;这个坑有几种可能：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;断点打在不可执行的代码行上&lt;/strong&gt;：比如接口的方法、空行、注释行。IDEA的断点只能打在可执行的字节码行上。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;开启了“静默断点”或“禁用所有断点”&lt;/strong&gt;：断点图标上有一个斜线，表示暂时禁用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;代码被JIT内联优化了&lt;/strong&gt;：在release模式下，热点方法可能被内联，导致断点位置和源码对应不上。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;多线程环境下，断点被其他线程绕过了&lt;/strong&gt;：如果你打了条件断点且条件一直为false，自然不会进去。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-id=&quot;heading-16&quot;&gt;解决方案&lt;/h3&gt;
&lt;p&gt;首先，检查断点图标。正常断点是红色圆点，如果带斜线，点击右键取消“Disable”。&lt;/p&gt;
&lt;p&gt;或者按 &lt;code&gt;Ctrl + Shift + F8&lt;/code&gt; 打开断点管理面板，看看是不是所有断点都被禁用了。&lt;/p&gt;
&lt;p&gt;其次，确保断点打在可执行行上。比如：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-java&quot; lang=&quot;java&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// ❌ 以下位置不能打断点&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;doSomething&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;// 方法签名行&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;// ✅ 这样是可以的&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;doSomething&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt; {
    System.out.println(&lt;span class=&quot;hljs-string&quot;&gt;&quot;这里可以打断点&quot;&lt;/span&gt;);  &lt;span class=&quot;hljs-comment&quot;&gt;// 第一行大括号后的有效代码&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第三，如果是在多线程调试中，检查一下条件断点。IDEA支持在断点上右键设置条件，比如 &lt;code&gt;str == null&lt;/code&gt;。如果条件永远不满足，断点当然不会触发。&lt;/p&gt;
&lt;p&gt;第四，终极方案：使用 &lt;code&gt;Thread.currentThread().getStackTrace()&lt;/code&gt; 打印堆栈来定位问题，或者改用日志输出。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-17&quot;&gt;第4个坑：控制台中文乱码&lt;/h2&gt;
&lt;h3 data-id=&quot;heading-18&quot;&gt;现象&lt;/h3&gt;
&lt;p&gt;运行项目，控制台打印的日志中，中文全部变成了 &lt;code&gt;???&lt;/code&gt; 或者 &lt;code&gt;\uXXXX&lt;/code&gt; 这样的乱码。&lt;/p&gt;
&lt;p&gt;System.out.println(&quot;你好&quot;) 输出的是“???”。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-19&quot;&gt;原因分析&lt;/h3&gt;
&lt;p&gt;乱码的本质是&lt;strong&gt;编码不一致&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;IDEA的控制台、项目的源文件编码、JVM的默认编码、操作系统编码这四个地方只要有一个对不上，就可能出现乱码。&lt;/p&gt;
&lt;p&gt;常见的情况是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;源文件是UTF-8编码，但IDEA控制台用的是GBK&lt;/li&gt;
&lt;li&gt;或者反过来，源文件是GBK，控制台用UTF-8&lt;/li&gt;
&lt;li&gt;JVM的&lt;code&gt;file.encoding&lt;/code&gt;参数没有正确设置&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-id=&quot;heading-20&quot;&gt;解决方案&lt;/h3&gt;
&lt;p&gt;第一步，统一所有地方的编码为UTF-8。&lt;/p&gt;
&lt;p&gt;打开 &lt;code&gt;File -&amp;gt; Settings -&amp;gt; Editor -&amp;gt; File Encodings&lt;/code&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Global Encoding: UTF-8&lt;/li&gt;
&lt;li&gt;Project Encoding: UTF-8&lt;/li&gt;
&lt;li&gt;Default encoding for properties files: UTF-8&lt;/li&gt;
&lt;li&gt;勾选“Transparent native-to-ascii conversion”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;第二步，修改IDEA控制台的编码。在 &lt;code&gt;Help -&amp;gt; Edit Custom VM Options&lt;/code&gt; 中添加：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-properties&quot; lang=&quot;properties&quot;&gt;-Dfile.encoding=UTF-8
-Dconsole.encoding=UTF-8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第三步，对于Maven项目，在pom.xml的&lt;code&gt;maven-surefire-plugin&lt;/code&gt;和&lt;code&gt;maven-compiler-plugin&lt;/code&gt;中也指定编码：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-xml&quot; lang=&quot;xml&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;properties&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;project.build.sourceEncoding&lt;/span&gt;&amp;gt;&lt;/span&gt;UTF-8&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;project.build.sourceEncoding&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;project.reporting.outputEncoding&lt;/span&gt;&amp;gt;&lt;/span&gt;UTF-8&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;project.reporting.outputEncoding&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;properties&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第四步，如果用的是Logback或Log4j，检查日志配置文件的编码，比如Logback：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-xml&quot; lang=&quot;xml&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;appender&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;name&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;CONSOLE&quot;&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;ch.qos.logback.core.ConsoleAppender&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;encoder&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;pattern&lt;/span&gt;&amp;gt;&lt;/span&gt;%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;pattern&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;charset&lt;/span&gt;&amp;gt;&lt;/span&gt;UTF-8&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;charset&lt;/span&gt;&amp;gt;&lt;/span&gt;  &lt;span class=&quot;hljs-comment&quot;&gt;&amp;lt;!-- 关键 --&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;encoder&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;appender&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;做完这些配置之后，重启IDEA，乱码问题一般就能解决了。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-21&quot;&gt;第5个坑：Git提交时多了.idea文件&lt;/h2&gt;
&lt;h3 data-id=&quot;heading-22&quot;&gt;现象&lt;/h3&gt;
&lt;p&gt;用IDEA自带的Git提交代码时，&lt;code&gt;Commit Changes&lt;/code&gt; 窗口里总是出现一些不应该提交的文件，比如&lt;code&gt;.idea/workspace.xml&lt;/code&gt;、&lt;code&gt;target/&lt;/code&gt;目录下的class文件、&lt;code&gt;.iml&lt;/code&gt;文件等。&lt;/p&gt;
&lt;p&gt;有时候一不小心就提交上去了，污染了Git仓库。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-23&quot;&gt;原因分析&lt;/h3&gt;
&lt;p&gt;IDEA默认会把项目的&lt;code&gt;.idea&lt;/code&gt;目录和&lt;code&gt;.iml&lt;/code&gt;文件纳入版本控制，因为这些文件记录了项目的配置信息。&lt;/p&gt;
&lt;p&gt;但问题是，这些文件里可能包含本地路径、个人配置等环境相关的信息，不同机器之间不应该共享。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;target/&lt;/code&gt;目录是编译产物，更不应该提交。&lt;/p&gt;
&lt;p&gt;根本原因是&lt;strong&gt;没有配置&lt;code&gt;.gitignore&lt;/code&gt;文件&lt;/strong&gt;，或者配置了但IDEA没有正确识别。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-24&quot;&gt;解决方案&lt;/h3&gt;
&lt;p&gt;在项目的根目录下创建&lt;code&gt;.gitignore&lt;/code&gt;文件，把以下内容放进去：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-gitignore&quot; lang=&quot;gitignore&quot;&gt;# Compiled class file
*.class
target/
out/

# IntelliJ IDEA
.idea/
*.iml
*.iws
*.ipr
.idea/workspace.xml
.idea/tasks.xml
.idea/gradle.xml
.idea/compiler.xml
.idea/libraries/

# Log file
*.log
*.log.gz

# OS generated files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后在IDEA中，打开 &lt;code&gt;Settings -&amp;gt; Version Control -&amp;gt; Ignored Files&lt;/code&gt;，确保没有任何冲突的规则。&lt;/p&gt;
&lt;p&gt;如果你的&lt;code&gt;.gitignore&lt;/code&gt;文件已经在Git仓库中，并且之前已经错误地提交了&lt;code&gt;.idea&lt;/code&gt;目录，需要先执行命令从Git缓存中移除：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot; lang=&quot;bash&quot;&gt;git &lt;span class=&quot;hljs-built_in&quot;&gt;rm&lt;/span&gt; -r --cached .idea
git commit -m &lt;span class=&quot;hljs-string&quot;&gt;&quot;Remove .idea from git&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;之后再提交，就只会看到需要提交的源码文件了。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-25&quot;&gt;第6个坑：Maven依赖下载巨慢&lt;/h2&gt;
&lt;h3 data-id=&quot;heading-26&quot;&gt;现象&lt;/h3&gt;
&lt;p&gt;在IDEA中刷新Maven项目（Reload All Maven Projects）时，右下角一直在转圈，下载依赖特别慢，有时候直接超时报“Transfer failed”或者“Read timed out”。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-27&quot;&gt;原因分析&lt;/h3&gt;
&lt;p&gt;Maven默认的中央仓库在国外，网络延迟大，下载速度自然慢。&lt;/p&gt;
&lt;p&gt;IDEA虽然内置了Maven，但默认会使用Maven自带的settings.xml，其中没有配置国内镜像。&lt;/p&gt;
&lt;p&gt;另外，IDEA的Maven和命令行Maven可能会共用同一个本地仓库（&lt;code&gt;~/.m2/repository&lt;/code&gt;），如果同时操作，会出现锁文件冲突。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-28&quot;&gt;解决方案&lt;/h3&gt;
&lt;p&gt;第一步，配置国内镜像源。&lt;/p&gt;
&lt;p&gt;在 &lt;code&gt;File -&amp;gt; Settings -&amp;gt; Build, Execution, Deployment -&amp;gt; Build Tools -&amp;gt; Maven&lt;/code&gt; 中，找到 &lt;code&gt;User settings file&lt;/code&gt;，点击“Override”，然后选择或创建一个&lt;code&gt;settings.xml&lt;/code&gt;文件，填入以下内容：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-xml&quot; lang=&quot;xml&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;&amp;lt;?xml version=&lt;span class=&quot;hljs-string&quot;&gt;&quot;1.0&quot;&lt;/span&gt; encoding=&lt;span class=&quot;hljs-string&quot;&gt;&quot;UTF-8&quot;&lt;/span&gt;?&amp;gt;&lt;/span&gt;
&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;settings&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;xmlns&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://maven.apache.org/SETTINGS/1.0.0&quot;&lt;/span&gt;
          &lt;span class=&quot;hljs-attr&quot;&gt;xmlns:xsi&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://www.w3.org/2001/XMLSchema-instance&quot;&lt;/span&gt;
          &lt;span class=&quot;hljs-attr&quot;&gt;xsi:schemaLocation&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;http://maven.apache.org/SETTINGS/1.0.0 
          http://maven.apache.org/xsd/settings-1.0.0.xsd&quot;&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;mirrors&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;hljs-comment&quot;&gt;&amp;lt;!-- 阿里云Maven镜像 --&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;mirror&lt;/span&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;id&lt;/span&gt;&amp;gt;&lt;/span&gt;aliyunmaven&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;id&lt;/span&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;mirrorOf&lt;/span&gt;&amp;gt;&lt;/span&gt;central&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;mirrorOf&lt;/span&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;name&lt;/span&gt;&amp;gt;&lt;/span&gt;阿里云公共仓库&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;name&lt;/span&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;url&lt;/span&gt;&amp;gt;&lt;/span&gt;https://maven.aliyun.com/repository/public&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;url&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;mirror&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;mirrors&lt;/span&gt;&amp;gt;&lt;/span&gt;
    
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;profiles&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;profile&lt;/span&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;id&lt;/span&gt;&amp;gt;&lt;/span&gt;jdk-1.8&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;id&lt;/span&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;activation&lt;/span&gt;&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;activeByDefault&lt;/span&gt;&amp;gt;&lt;/span&gt;true&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;activeByDefault&lt;/span&gt;&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;jdk&lt;/span&gt;&amp;gt;&lt;/span&gt;1.8&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;jdk&lt;/span&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;activation&lt;/span&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;properties&lt;/span&gt;&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;maven.compiler.source&lt;/span&gt;&amp;gt;&lt;/span&gt;1.8&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;maven.compiler.source&lt;/span&gt;&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;maven.compiler.target&lt;/span&gt;&amp;gt;&lt;/span&gt;1.8&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;maven.compiler.target&lt;/span&gt;&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;maven.compiler.compilerVersion&lt;/span&gt;&amp;gt;&lt;/span&gt;1.8&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;maven.compiler.compilerVersion&lt;/span&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;properties&lt;/span&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;profile&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;profiles&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;settings&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第二步，在Maven设置中，把“Work offline”关掉（除非你真的要离线工作），把“Import Maven projects automatically”打开，这样依赖变更时会自动下载。&lt;/p&gt;
&lt;p&gt;第三步，如果你的网络环境特别差，可以尝试配置IDEA的HTTP代理。&lt;code&gt;Settings -&amp;gt; Appearance &amp;amp; Behavior -&amp;gt; System Settings -&amp;gt; HTTP Proxy&lt;/code&gt;，如果公司有内网代理，填进去即可。&lt;/p&gt;
&lt;p&gt;配置完成后，点击Maven面板上的“Reload All Projects”按钮，下载速度应该明显提升。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-29&quot;&gt;第7个坑：代码编译通过，运行却报错&lt;/h2&gt;
&lt;h3 data-id=&quot;heading-30&quot;&gt;现象&lt;/h3&gt;
&lt;p&gt;在IDEA里Maven编译没有任何错误，&lt;code&gt;mvn clean compile&lt;/code&gt;也成功了。&lt;/p&gt;
&lt;p&gt;但是运行main方法或者启动Spring Boot时，控制台报错：&lt;code&gt;java.lang.ClassNotFoundException: com.xxx.SomeClass&lt;/code&gt;。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-31&quot;&gt;原因分析&lt;/h3&gt;
&lt;p&gt;这个坑的原因很隐蔽：&lt;strong&gt;IDEA的编译器和Maven的编译输出目录不一致&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;IDEA默认的编译输出目录是 &lt;code&gt;项目根目录/out/&lt;/code&gt; 或者 &lt;code&gt;target/classes/&lt;/code&gt;，而Maven的编译输出目录是 &lt;code&gt;target/classes/&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;如果你修改过项目结构，或者IDEA的缓存乱了，可能会导致IDEA运行时用的classpath里找不到某些类。&lt;/p&gt;
&lt;p&gt;另一个常见原因是：使用了Lombok，但是IDEA的注解处理器没有生成代码，或者生成的代码路径不对。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-32&quot;&gt;解决方案&lt;/h3&gt;
&lt;p&gt;首先，打开 &lt;code&gt;File -&amp;gt; Settings -&amp;gt; Build, Execution, Deployment -&amp;gt; Compiler&lt;/code&gt;，确保“Build project automatically”是勾选的（但注意这会在你保存文件时自动编译，对性能有影响）。&lt;/p&gt;
&lt;p&gt;然后，检查 &lt;code&gt;File -&amp;gt; Project Structure -&amp;gt; Modules&lt;/code&gt;，看每个module的“Output path”和“Test output path”是否指向了正确的目录。一般来说，Maven项目应该指向&lt;code&gt;target/classes&lt;/code&gt;和&lt;code&gt;target/test-classes&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;转存失败，建议直接上传图片文件&quot; src=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;最暴力的解决方法：点击 &lt;code&gt;Build -&amp;gt; Rebuild Project&lt;/code&gt; 清空所有编译输出，然后重新编译。如果还不行，执行 &lt;code&gt;File -&amp;gt; Invalidate Caches and Restart&lt;/code&gt; 清空缓存。&lt;/p&gt;
&lt;p&gt;还有一个绝招：用Maven命令行先打包，然后手动运行打好的jar包，看是不是同样的问题。&lt;/p&gt;
&lt;p&gt;如果jar包能运行，那就是IDEA的运行配置有问题；如果jar包也报错，那就是代码本身有依赖问题。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-33&quot;&gt;第8个坑：快捷键失灵&lt;/h2&gt;
&lt;h3 data-id=&quot;heading-34&quot;&gt;现象&lt;/h3&gt;
&lt;p&gt;习惯了用 &lt;code&gt;Ctrl+C&lt;/code&gt;、&lt;code&gt;Ctrl+V&lt;/code&gt; 复制粘贴代码，突然有一天发现快捷键不管用了，或者按下去之后出现奇怪的行为（比如弹出某个面板、删除文字等）。&lt;/p&gt;
&lt;p&gt;更离谱的是，&lt;code&gt;Ctrl+Alt+L&lt;/code&gt; 格式化代码也无效。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-35&quot;&gt;原因分析&lt;/h3&gt;
&lt;p&gt;IDEA的快捷键冲突通常有两种情况：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;与其他软件的快捷键冲突&lt;/strong&gt;：比如微信PC版的截图快捷键是&lt;code&gt;Ctrl+Alt+A&lt;/code&gt;，和IDEA的一些插件快捷键重复；搜狗输入法的&lt;code&gt;Ctrl+Shift+F&lt;/code&gt;会切换简繁体。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IDEA的keymap被无意中修改了&lt;/strong&gt;：可能是不小心按到了“切换keymap”的快捷键，或者某个插件改动了设置。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-id=&quot;heading-36&quot;&gt;解决方案&lt;/h3&gt;
&lt;p&gt;第一步，检查是否切换了keymap。&lt;/p&gt;
&lt;p&gt;打开 &lt;code&gt;File -&amp;gt; Settings -&amp;gt; Keymap&lt;/code&gt;，看看当前选中的keymap是不是你常用的（比如Windows默认是&lt;code&gt;Default&lt;/code&gt;，Mac是&lt;code&gt;Mac OS X&lt;/code&gt;）。如果显示&lt;code&gt;Default copy&lt;/code&gt;或者别的，说明被改过了。可以点击“Restore Defaults”恢复默认。&lt;/p&gt;
&lt;p&gt;第二步，排查外部软件冲突。&lt;/p&gt;
&lt;p&gt;常见的冲突有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;微信：&lt;code&gt;Ctrl+Alt+W&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;搜狗/微软拼音：&lt;code&gt;Ctrl+Shift+F&lt;/code&gt;（简繁体切换）、&lt;code&gt;Ctrl+Shift+E&lt;/code&gt;（表情）&lt;/li&gt;
&lt;li&gt;QQ：&lt;code&gt;Ctrl+Alt+A&lt;/code&gt;（截图）&lt;/li&gt;
&lt;li&gt;网易云音乐：&lt;code&gt;Ctrl+Alt+上/下&lt;/code&gt;（音量）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;解决方法是去这些软件里修改快捷键，或者直接关闭它们。我个人的习惯是写代码的时候把聊天软件退了，清净。&lt;/p&gt;
&lt;p&gt;第三步，如果只有某个特定快捷键失效，可以在Keymap里搜索这个快捷键的动作，看看是不是被占用了。&lt;/p&gt;
&lt;p&gt;比如搜索&lt;code&gt;Reformat Code&lt;/code&gt;（格式化代码），默认是&lt;code&gt;Ctrl+Alt+L&lt;/code&gt;，如果显示多个动作，说明有冲突，可以右键移除一个。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-37&quot;&gt;第9个坑：连不上MySQL&lt;/h2&gt;
&lt;h3 data-id=&quot;heading-38&quot;&gt;现象&lt;/h3&gt;
&lt;p&gt;IDEA自带的Database工具（很好用，很多小伙伴可能不知道）连接MySQL时，报错：&lt;code&gt;The server time zone value &#39;???ú±ê×??±??&#39; is unrecognized&lt;/code&gt; 或者 &lt;code&gt;Could not create connection to database server.&lt;/code&gt;&lt;/p&gt;
&lt;h3 data-id=&quot;heading-39&quot;&gt;原因分析&lt;/h3&gt;
&lt;p&gt;MySQL 8.0以上版本要求明确指定时区参数&lt;code&gt;serverTimezone&lt;/code&gt;。IDEA的Database连接配置默认不包含这个参数，导致了错误。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-40&quot;&gt;解决方案&lt;/h3&gt;
&lt;p&gt;在IDEA的Database面板中，点击数据源设置，进入“Advanced”选项卡，手动添加一个参数：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Name&lt;/code&gt;: &lt;code&gt;serverTimezone&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Value&lt;/code&gt;: &lt;code&gt;Asia/Shanghai&lt;/code&gt; 或者 &lt;code&gt;UTC&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果还不行，在“General”页面的URL后面直接加上：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot; lang=&quot;bash&quot;&gt;jdbc:mysql://localhost:3306/test?useSSL=&lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;&amp;amp;serverTimezone=Asia/Shanghai&amp;amp;characterEncoding=utf-8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;另外，如果是用Spring Boot项目的数据源配置，也建议在连接池的URL中加入这些参数，防止运行时报同样的错。&lt;/p&gt;
&lt;p&gt;最后，检查一下MySQL驱动版本。IDEA默认会下载最新的驱动，但如果你的MySQL是5.7版本，用8.x的驱动可能会不兼容。&lt;/p&gt;
&lt;p&gt;可以在数据源的“Driver”下拉菜单中选择旧版本。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-41&quot;&gt;第10个坑：提交代码时自动格式化&lt;/h2&gt;
&lt;h3 data-id=&quot;heading-42&quot;&gt;现象&lt;/h3&gt;
&lt;p&gt;团队协作时，你提交代码前IDEA自动帮你格式化了代码（&lt;code&gt;Ctrl+Alt+L&lt;/code&gt;）。&lt;/p&gt;
&lt;p&gt;结果提交上去之后，整个文件的缩进、换行、空行全变了。&lt;/p&gt;
&lt;p&gt;你的改动可能只有一行，但是git diff里却显示了整个文件几百行的变更。&lt;/p&gt;
&lt;p&gt;代码Review的时候，同事根本看不出你到底改了啥。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-43&quot;&gt;原因分析&lt;/h3&gt;
&lt;p&gt;这是IDEA的“崇高”功能——在提交代码时自动执行代码格式化、优化导入等操作。&lt;/p&gt;
&lt;p&gt;初衷是好的，希望保持代码风格统一。&lt;/p&gt;
&lt;p&gt;但是，如果团队成员没有使用统一的代码格式化规则（比如每个人的缩进设置不同：有的用4空格、有的用2空格、有的用Tab），就会导致互相覆盖、diff爆炸。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-44&quot;&gt;解决方案&lt;/h3&gt;
&lt;p&gt;有两种解决思路：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;方案一：统一团队代码格式（推荐）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在项目根目录下放置一个&lt;code&gt;.editorconfig&lt;/code&gt;文件，这是各大IDE和编辑器共同遵守的格式规范：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ini&quot; lang=&quot;ini&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# .editorconfig&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;root&lt;/span&gt; = &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;

&lt;span class=&quot;hljs-section&quot;&gt;[*]&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;charset&lt;/span&gt; = utf-&lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;indent_style&lt;/span&gt; = space
&lt;span class=&quot;hljs-attr&quot;&gt;indent_size&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;end_of_line&lt;/span&gt; = lf
&lt;span class=&quot;hljs-attr&quot;&gt;insert_final_newline&lt;/span&gt; = &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;trim_trailing_whitespace&lt;/span&gt; = &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;

&lt;span class=&quot;hljs-section&quot;&gt;[*.java]&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;indent_size&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;

&lt;span class=&quot;hljs-section&quot;&gt;[*.xml]&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;indent_size&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;IDEA会自动识别&lt;code&gt;.editorconfig&lt;/code&gt;，并提示是否采用。这样所有人都用同一套规则。&lt;/p&gt;
&lt;p&gt;同时，在IDEA中导出代码格式化规则（&lt;code&gt;File -&amp;gt; Settings -&amp;gt; Editor -&amp;gt; Code Style -&amp;gt; Java -&amp;gt; Manage -&amp;gt; Export&lt;/code&gt;），把文件放进项目版本控制，让同事导入。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;方案二：关闭自动格式化功能&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如果你不想自动格式化，可以关掉。打开 &lt;code&gt;File -&amp;gt; Settings -&amp;gt; Version Control -&amp;gt; Commit&lt;/code&gt;，把“Reformat code”、“Optimize imports”、“Rearrange code”前面的勾全部取消。&lt;/p&gt;
&lt;p&gt;这样一来，提交的时候就只会提交你手动改动的部分，不会动其他代码。当然，你需要自己保证代码格式是OK的。&lt;/p&gt;
&lt;p&gt;个人建议采用方案一，这样既保持了代码整洁，又不会引起格式冲突。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-45&quot;&gt;总结&lt;/h2&gt;
&lt;p&gt;好了，10个坑终于讲完了。&lt;/p&gt;
&lt;p&gt;我来帮大家快速回顾一下：&lt;/p&gt;




























































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;序号&lt;/th&gt;&lt;th&gt;坑&lt;/th&gt;&lt;th&gt;一句话解决方案&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;IDEA越来越卡&lt;/td&gt;&lt;td&gt;调大内存 + 排除无需索引的目录&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Lombok失效&lt;/td&gt;&lt;td&gt;装插件 + 开启注解处理&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;断点进不去&lt;/td&gt;&lt;td&gt;打在有效行 + 检查禁用状态&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;控制台中文乱码&lt;/td&gt;&lt;td&gt;统一UTF-8 + JVM参数&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;Git提交了不该提交的文件&lt;/td&gt;&lt;td&gt;配置.gitignore + 移除已提交的&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;Maven依赖下载慢&lt;/td&gt;&lt;td&gt;配置阿里云镜像&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;7&lt;/td&gt;&lt;td&gt;ClassNotFoundException&lt;/td&gt;&lt;td&gt;检查编译输出目录 + Rebuild&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;8&lt;/td&gt;&lt;td&gt;快捷键失灵&lt;/td&gt;&lt;td&gt;检查keymap + 关闭冲突软件&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;9&lt;/td&gt;&lt;td&gt;数据库时区错误&lt;/td&gt;&lt;td&gt;添加serverTimezone参数&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;10&lt;/td&gt;&lt;td&gt;提交时自动改格式&lt;/td&gt;&lt;td&gt;统一.editorconfig或关闭自动格式化&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;最后用一张图来总结一下这些坑的应对思路：&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;转存失败，建议直接上传图片文件&quot; src=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;写这篇文章，一方面是帮大家避坑，另一方面也是对自己这些年IDEA使用经验的一个总结。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;工欲善其事，必先利其器&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;IDEA确实是一个非常强大的工具，但再强大的工具，如果不会用、用不对，也会变成绊脚石。&lt;/p&gt;
&lt;p&gt;希望这篇文章能给大家带来实实在在的帮助。&lt;/p&gt;
&lt;p&gt;如果你也踩过其他“奇葩”的坑，欢迎在评论区留言分享。&lt;/p&gt;
&lt;p&gt;咱们互相学习、共同进步！&lt;/p&gt;
&lt;p&gt;更多项目实战在我的技术网站：susan.net.cn/project&lt;/p&gt;</description><link>https://juejin.cn/post/7643355476503347254</link><guid isPermaLink="false">https://juejin.cn/post/7643355476503347254</guid><pubDate>Sun, 24 May 2026 09:44:29 GMT</pubDate><author>苏三说技术</author><category>后端</category></item><item><title>SenseNova-U1 实战体验：从网页版生成，到 Mac 踩坑，再到 CUDA 服务器跑通本地部署</title><description>&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/5cc2e44f23d74877a98cd8f2b0c125a1~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5YCU5by655qE55-z5aS0Xw==:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780105106&amp;amp;x-signature=Tc1qsEPqUMPBINp9UMLtUCk1Fok%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;最近试了一轮商汤开源的 &lt;code&gt;SenseNova-U1&lt;/code&gt;。我一开始不是奔着“跑分”去的，而是想确认一件更实际的事：它到底能不能从在线体验过渡到本地部署，尤其是像我这种日常主力是 Mac 的开发环境，最后能不能把流程真实跑通。&lt;/p&gt;
&lt;p&gt;这篇文章按我的实际操作顺序写：先看网页版效果，再记录 Mac 本地尝试，最后切到 CUDA 服务器完成部署和生成测试。中间有成功，也有失败。我尽量把命令、报错和判断都放出来，因为这些比只贴一张最终效果图更有参考价值。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-0&quot;&gt;先理解 SenseNova-U1：它不是单纯的文生图模型&lt;/h2&gt;
&lt;p&gt;官方介绍里，SenseNova-U1 的关键词是 &lt;code&gt;NEO-Unify&lt;/code&gt;，定位是“原生统一多模态理解与生成”。这点和传统多模态方案不太一样：很多模型是一个视觉编码器接一个语言模型，生成任务再接另一个图像生成模块；而 SenseNova-U1 强调把理解、生成、图像编辑、图文交错等能力放进统一架构里。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/9734e826db064f84837ddb20f6ccdafb~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5YCU5by655qE55-z5aS0Xw==:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780105106&amp;amp;x-signature=0ANBSCUx11qp%2FvjtYuAP6qblcgc%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;从架构图看，它同时覆盖左侧的理解类任务和右侧的生成类任务。理解侧包括文本理解、视觉语言理解、知识推理、Agent 决策、空间智能；生成侧包括图像生成、图像编辑、信息图生成、交错图文生成、统一推理。&lt;/p&gt;
&lt;p&gt;这个定位也决定了我后面的测试方向：不只看它能不能出图，还要看它在部署链路里是否能稳定加载、是否吃显存、是否对分辨率有约束。&lt;/p&gt;
&lt;p&gt;官方还放了不少 benchmark 对比，能看到 &lt;code&gt;SenseNova-U1-A3B-MoT&lt;/code&gt; 和 &lt;code&gt;SenseNova-U1-8B-MoT&lt;/code&gt; 在多个理解、编辑、生成任务上和其他模型对比。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/a1bde8dcec8745a5b3edbc5529938297~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5YCU5by655qE55-z5aS0Xw==:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780105106&amp;amp;x-signature=9u43gmCjDCt4%2FnKqDS4wAZNE7u4%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;我这次实际部署用的是 &lt;code&gt;sensenova/SenseNova-U1-8B-MoT&lt;/code&gt;。原因很简单：A3B-MoT 更大，本地和普通云 GPU 都更容易遇到资源问题；8B-MoT 更适合做个人实测。&lt;/p&gt;
&lt;p&gt;官方资料：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-plain&quot; lang=&quot;plain&quot;&gt;GitHub: https://github.com/OpenSenseNova/SenseNova-U1
Hugging Face: https://huggingface.co/sensenova/SenseNova-U1-8B-MoT
SenseNova Skills: https://github.com/OpenSenseNova/SenseNova-Skills
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-id=&quot;heading-1&quot;&gt;网页版体验：先看模型能做什么&lt;/h2&gt;
&lt;p&gt;在本地部署前，我先用了网页版体验。这个阶段的目的不是研究环境，而是判断模型能力是否值得继续折腾本地部署。&lt;/p&gt;
&lt;p&gt;第一个测试是信息图生成。我给的方向是“人生四个十年的 2x2 网格”，要求用物件、材质和年代数字表达不同人生阶段。返回结果是一个四象限信息图：10 岁、20 岁、30 岁、40 岁分别用玩具、耳机、书本、工具、药瓶、植物等物件表达阶段感。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/b5dd085224d74b2ea19ccb553b698ed7~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5YCU5by655qE55-z5aS0Xw==:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780105106&amp;amp;x-signature=h4ILx5TWEVAfj5MUM1cv%2BkHWMKU%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;这张图最让我意外的是，它不是简单把文字贴到画面上，而是尝试用“物化”的方式表达年龄。10 岁是积木和拼图质感，20 岁有耳机和金属数字，30 岁是书本和钟表，40 岁是工具、药瓶和植物。它生成的效果还是很符合我们的prompt的&lt;/p&gt;
&lt;p&gt;第二个测试是 2D 卡通贴纸。我要求从同一男性角色出发，生成六张贴纸，并保留人物标志性特征，比如眼镜、笑容、发型，同时让每张贴纸有不同表情和文字。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/e967dfe286344d6091540c05e4fae6b3~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5YCU5by655qE55-z5aS0Xw==:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780105106&amp;amp;x-signature=kvzyjHsrxaN%2B1YcEm42tH0oGhbA%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;这张更偏社交媒体素材。它保留了统一角色，六张贴纸分别表达“教师模式开启”“我需要咖啡……”“订阅！”“自拍时间到！”“让我来评分。”“太容易了”。从结果看，网页版已经能支撑不少轻量内容创作场景，尤其适合先做创意验证。&lt;/p&gt;
&lt;p&gt;也正是因为网页版效果还可以，我才继续往本地部署走。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-2&quot;&gt;Mac 本地部署：可以搭环境，但不适合硬跑完整推理&lt;/h2&gt;
&lt;p&gt;我的主力机器是 MacBook Pro，配置是 Apple M1 Pro，8 核 CPU（6 个性能核心 + 2 个能效核心），16GB 内存，系统是 macOS 15.4.1，arm64 架构。第一反应当然是先在本机跑一遍。但虽然SenseNova-U1 官方环境默认是 Linux + CUDA，但还是想试一下。&lt;/p&gt;
&lt;p&gt;官方项目的 &lt;code&gt;pyproject.toml&lt;/code&gt; 要求 Python 版本是：&lt;/p&gt;
&lt;p&gt;requires-python = &quot;&amp;gt;=3.11,&amp;lt;3.12&quot;&lt;/p&gt;
&lt;p&gt;我一开始用 Python 3.12，直接被拒绝：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/0ad77e9a1d9d44c8aa801dac59d3518f~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5YCU5by655qE55-z5aS0Xw==:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780105106&amp;amp;x-signature=Ljk%2FgniaHFplkancNyLlF6w9g1E%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;这一步说明了一个细节：不要看到本机 Python 新就直接用。SenseNova-U1 当前明确要求 Python 3.11，3.12 不行。&lt;/p&gt;
&lt;p&gt;Mac 上正确的环境方向是：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-plain&quot; lang=&quot;plain&quot;&gt;brew install python@3.11
/opt/homebrew/opt/python@3.11/bin/python3.11 -m venv .venv
source .venv/bin/activate
python -m pip install -U pip wheel setuptools
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后安装 macOS 版 PyTorch，而不是 CUDA 版 PyTorch：&lt;/p&gt;
&lt;p&gt;pip install torch torchvision&lt;/p&gt;
&lt;p&gt;项目依赖我没有直接 &lt;code&gt;uv sync&lt;/code&gt;，因为官方 &lt;code&gt;uv&lt;/code&gt; 配置会拉取 CUDA 12.8 的 PyTorch wheel，Mac arm64 不能安装这个包。我的方式是手动安装核心依赖：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-plain&quot; lang=&quot;plain&quot;&gt;pip install transformers==4.57.1 tokenizers==0.22.1 accelerate==1.10.1 \
  huggingface-hub==0.36.2 safetensors==0.6.2 sentencepiece==0.2.1 \
  &quot;numpy&amp;gt;=1.24,&amp;lt;3&quot; pillow==12.0.0 tqdm==4.67.1 packaging==25.0 httpx

pip install -e . --no-deps
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;pip install -e . --no-deps&lt;/code&gt; 的作用是把当前项目注册到 Python 环境里，否则运行示例脚本会出现：&lt;/p&gt;
&lt;p&gt;ModuleNotFoundError: No module named &#39;sensenova_u1&#39;&lt;/p&gt;
&lt;p&gt;到这里，Mac 上的项目环境是能起来的。模型也能开始下载和加载。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/3954e6f9b2214439a98d1cbc5c572aaf~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5YCU5by655qE55-z5aS0Xw==:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780105106&amp;amp;x-signature=uCGPbfpfzx%2BikQVc5F%2BWIndubfE%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;但真正进入 MPS 推理时，问题来了。即使我只跑 &lt;code&gt;512x512&lt;/code&gt;、&lt;code&gt;4 steps&lt;/code&gt; 的最小文生图测试，模型加载到 MPS 时仍然触发了内存不足：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/486497ff22a74b778cea4d52a47d8422~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5YCU5by655qE55-z5aS0Xw==:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780105106&amp;amp;x-signature=ZIBg6EfZEPhG6x4ybmezriCWMPo%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;报错里最关键的是：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-plain&quot; lang=&quot;plain&quot;&gt;RuntimeError: MPS backend out of memory
MPS allocated: 18.04 GiB
max allowed: 18.13 GiB
Tried to allocate 96.00 MiB
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这说明它还没真正开始生成图，就已经把 MPS 可用内存顶满了。&lt;/p&gt;
&lt;p&gt;我又尝试了官方低显存模式：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-plain&quot; lang=&quot;plain&quot;&gt;python examples/t2i/inference.py \
  --model_path sensenova/SenseNova-U1-8B-MoT \
  --prompt &quot;一张极简中文卡片，标题是 SenseNova-U1 Mac 本地部署测试，白底，科技感。&quot; \
  --width 512 \
  --height 512 \
  --num_steps 4 \
  --cfg_scale 1.0 \
  --device mps \
  --dtype float16 \
  --attn_backend sdpa \
  --vram_mode low \
  --output outputs/mac_mps_low_test.png
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;结果不是 OOM，而是另一个更明确的问题：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/f82dd92034a54649b71f62d59433e04b~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5YCU5by655qE55-z5aS0Xw==:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780105106&amp;amp;x-signature=4cPZFFGP9cqVNTD1Dxw1Kqo9mFM%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;核心报错是：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-plain&quot; lang=&quot;plain&quot;&gt;NotImplementedError: Inference requires a CUDA or XPU device (got device(type=&#39;mps&#39;)).
CPU / MPS lack the pinned-memory and stream primitives used here.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个结论很清楚：Mac 可以完成环境适配和模型下载验证，但当前不适合作为 SenseNova-U1-8B-MoT 的完整本地推理主力环境。&lt;code&gt;--vram_mode low&lt;/code&gt; 这类 offload 机制依赖 CUDA/XPU 的 pinned memory 和 stream，MPS 不支持。&lt;/p&gt;
&lt;p&gt;这一段我反而觉得值得写进文章。&lt;strong&gt;因为很多时候“本地部署失败”不是无意义失败，它能帮助判断什么环境才是合理投入。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 data-id=&quot;heading-3&quot;&gt;切到 CUDA 服务器：部署路线变得顺畅&lt;/h2&gt;
&lt;p&gt;Mac 这条路走不通后，我换到了云端 GPU Notebook。最终我拿到的环境是 NVIDIA GPU，实际验证里 PyTorch 能识别到：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-plain&quot; lang=&quot;plain&quot;&gt;torch: 2.8.0+cu128
cuda: 12.8
cuda available: True
gpu: NVIDIA GeForce RTX 3090
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;服务器环境截图如下：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/e95247211dad441ebe6abd8f98afa003~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5YCU5by655qE55-z5aS0Xw==:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780105106&amp;amp;x-signature=wSFkFcBn2YV6d3noeJ1aYj4EVH0%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;CUDA 和 PyTorch 验证是本地部署里很重要的一步，建议不要跳过。我用的是：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-plain&quot; lang=&quot;plain&quot;&gt;python -c &quot;import torch; print(torch.__version__); print(torch.version.cuda); print(torch.cuda.is_available()); print(torch.cuda.get_device_name(0))&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输出确认 CUDA 可用：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/591803c66de149119df1cf8583480d11~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5YCU5by655qE55-z5aS0Xw==:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780105106&amp;amp;x-signature=cR7%2ByQgWfZ5GvTbS7QGRHCndi1A%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;安装好 PyTorch 后，我再安装 SenseNova-U1 的核心依赖：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-plain&quot; lang=&quot;plain&quot;&gt;pip install transformers==4.57.1 tokenizers==0.22.1 accelerate==1.10.1 \
  huggingface-hub==0.36.2 safetensors==0.6.2 sentencepiece==0.2.1 \
  &quot;numpy&amp;gt;=1.24,&amp;lt;3&quot; pillow==12.0.0 tqdm==4.67.1 packaging==25.0 httpx

pip install -e . --no-deps
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/220ebb8c57044c67bdedb61c44fc344a~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5YCU5by655qE55-z5aS0Xw==:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780105106&amp;amp;x-signature=umQ%2FOm%2FTHN4ihYZ%2F2ny%2B9ONFjYE%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;这里我还是没有直接让依赖工具自动处理 PyTorch。原因是前面已经验证了 &lt;code&gt;torch==2.8.0+cu128&lt;/code&gt; 和 GPU 可用，后续安装项目依赖时不希望 pip 或 uv 把 torch 版本改掉。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/883845d3e8304a8faee62ef635d4690a~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5YCU5by655qE55-z5aS0Xw==:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780105106&amp;amp;x-signature=cf5%2Bu68JYt8wLfhWq%2BVkMZYGDH8%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;接着克隆项目：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-plain&quot; lang=&quot;plain&quot;&gt;cd /root/autodl-tmp
git clone https://github.com/OpenSenseNova/SenseNova-U1.git
cd SenseNova-U1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/26e421d830d448da9d2e4d7bbc8e2389~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5YCU5by655qE55-z5aS0Xw==:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780105106&amp;amp;x-signature=h9782OLNcdkJg3XE7QVZvAgNfVs%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;h2 data-id=&quot;heading-4&quot;&gt;Hugging Face 下载问题：切镜像源并保存到数据盘&lt;/h2&gt;
&lt;p&gt;服务器默认访问 Hugging Face 不稳定，一开始直接加载：&lt;/p&gt;
&lt;p&gt;--model_path sensenova/SenseNova-U1-8B-MoT&lt;/p&gt;
&lt;p&gt;会报：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-plain&quot; lang=&quot;plain&quot;&gt;Network is unreachable
HTTPSConnectionPool(host=&#39;huggingface.co&#39;, port=443)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;所以我改成先把模型下载到数据盘，再用本地路径加载。这里用国内镜像：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-plain&quot; lang=&quot;plain&quot;&gt;HF_ENDPOINT=https://hf-mirror.com huggingface-cli download sensenova/SenseNova-U1-8B-MoT \
  --local-dir /root/autodl-tmp/models/SenseNova-U1-8B-MoT \
  --resume-download \
  --max-workers 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;几个参数解释一下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-plain&quot; lang=&quot;plain&quot;&gt;HF_ENDPOINT=https://hf-mirror.com：切到 Hugging Face 镜像源
--local-dir：把模型放到数据盘，避免占系统盘
--resume-download：支持断点续传
--max-workers 1：降低并发，提高弱网络下的稳定性
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当然下面这种先export 然后验证也是可以的。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/9bdb973bae4e4ba1a4163cd294db1bab~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5YCU5by655qE55-z5aS0Xw==:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780105106&amp;amp;x-signature=taYBqKHMMXKCxo2Nz%2BrOJB4zNx8%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;中途我确实遇到过 &lt;code&gt;Broken pipe&lt;/code&gt;，重新执行同一条命令后会续传。最终下载完成时显示 214 个文件全部获取成功：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/ab536b7fa8134f21b6fa6caf9d444ecc~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5YCU5by655qE55-z5aS0Xw==:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780105106&amp;amp;x-signature=0Ut1rfYEhsiATtnjcozLVM75l6w%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;这很重要，因为它证明后续不是在线拉模型，而是从本地路径加载。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-5&quot;&gt;第一次生成：用 1024x1024 验证 CUDA 推理闭环&lt;/h2&gt;
&lt;p&gt;模型下载完成后，我没有继续走在线模型名，而是直接使用本地模型目录作为 &lt;code&gt;--model_path&lt;/code&gt;。第一次成功生成用的是 &lt;code&gt;1024x1024&lt;/code&gt;、&lt;code&gt;30 steps&lt;/code&gt;、&lt;code&gt;cfg_scale 4.0&lt;/code&gt;，这比单纯的连通性测试更接近实际可用效果。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-plain&quot; lang=&quot;plain&quot;&gt;cd /root/autodl-tmp/SenseNova-U1
mkdir -p outputs

python examples/t2i/inference.py \
  --model_path /root/autodl-tmp/models/SenseNova-U1-8B-MoT \
  --prompt &quot;一张中文科技风信息图，标题为 SenseNova-U1 本地部署成功，画面包含 GPU 环境、模型下载、推理测试三个步骤，白色背景，蓝色科技感，清晰排版，中文文字清晰。&quot; \
  --width 1024 \
  --height 1024 \
  --num_steps 30 \
  --cfg_scale 4.0 \
  --device cuda \
  --dtype bfloat16 \
  --attn_backend sdpa \
  --vram_mode balanced \
  --output outputs/sensenova_u1_cuda_quality_test.png
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/809d1e3d489c46d9a2d120238f9bf764~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5YCU5by655qE55-z5aS0Xw==:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780105106&amp;amp;x-signature=j99Wmidt5iSq8n4Jmm5Q%2FAK7tOo%3D&quot; alt=&quot;在这里插入图片描述&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;这张图里能看到三个关键信息：命令行已经从本地模型路径加载，checkpoint shards 正常加载完成，最终图片保存到了 &lt;code&gt;outputs/sensenova_u1_cuda_quality_test.png&lt;/code&gt;。生成结果本身也符合提示词要求，包含“GPU 环境、模型下载、推理测试”三个步骤，说明 CUDA 服务器上的文生图链路已经跑通。&lt;/p&gt;
&lt;p&gt;需要注意的是，脚本会提示 &lt;code&gt;1024x1024&lt;/code&gt; 不在官方训练分辨率 bucket 中。这个警告不影响本次生成成功，也提醒我后面可以继续按官方 bucket 再跑一次更规范的 16:9 测试。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-6&quot;&gt;分辨率也有坑：不要随便填 1360x768&lt;/h2&gt;
&lt;p&gt;我随后尝试 16:9，但一开始用了 &lt;code&gt;1360x768&lt;/code&gt;，结果脚本提示它不在官方训练 bucket 里，并在 patchify 阶段报 shape 错误。&lt;/p&gt;
&lt;p&gt;官方支持的 bucket 里，16:9 对应的是：&lt;/p&gt;
&lt;p&gt;2720x1536&lt;/p&gt;
&lt;p&gt;所以后面我改成官方 bucket。这个细节很容易踩坑：SenseNova-U1 的图像生成不是任意分辨率都稳定，最好按官方支持的 bucket 来。&lt;/p&gt;
&lt;p&gt;我最终使用的 16:9 测试命令是：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-plain&quot; lang=&quot;plain&quot;&gt;python examples/t2i/inference.py \
  --model_path /root/autodl-tmp/models/SenseNova-U1-8B-MoT \
  --prompt &quot;生成一张中文信息图，标题为 SenseNova-U1 本地部署流程。内容包含四个步骤：创建 Python 3.11 环境、安装 PyTorch CUDA 12.8、下载 SenseNova-U1 模型、运行文生图测试。白底蓝色科技风，16:9 横版，排版清晰，文字尽量清楚。&quot; \
  --width 2720 \
  --height 1536 \
  --num_steps 30 \
  --cfg_scale 4.0 \
  --device cuda \
  --dtype bfloat16 \
  --attn_backend sdpa \
  --vram_mode balanced \
  --output outputs/sensenova_u1_deploy_flow_2720x1536.png
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;生成结果如下：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/b74db879c34d410daa87613b2ef8513a~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5YCU5by655qE55-z5aS0Xw==:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780105106&amp;amp;x-signature=%2FI8BS7kglno2CKxk44qyXZNODKw%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;这一版使用官方 16:9 bucket，比前面的 1024x1024 测试更符合模型推荐分辨率。它也进一步证明：在 CUDA 环境下，只要分辨率和参数设置合理，SenseNova-U1 的文生图流程可以完整跑通。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-7&quot;&gt;用 SenseNova-U1 生成文章封面&lt;/h2&gt;
&lt;p&gt;最后我又让它生成了一张文章封面。提示词里我明确要求主题是“SenseNova-U1 本地部署实战”，画面包含 GPU 服务器、MacBook、Python 3.11、CUDA 12.8、PyTorch 2.8、Hugging Face、MPS OOM、vGPU 等关键词。&lt;/p&gt;
&lt;p&gt;命令如下：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-plain&quot; lang=&quot;plain&quot;&gt;python examples/t2i/inference.py \
  --model_path /root/autodl-tmp/models/SenseNova-U1-8B-MoT \
  --prompt &quot;生成一张中文技术博客封面图，主题是 SenseNova-U1 本地部署实战。画面主体是一台发光的 GPU 服务器和一台 MacBook，通过蓝色数据流连接，背景是深色科技空间，漂浮着 Python 3.11、CUDA 12.8、PyTorch 2.8、Hugging Face、MPS OOM、vGPU 这些关键词。标题文字：SenseNova-U1 本地部署实战。副标题文字：从 Mac 尝试到 CUDA GPU 跑通。整体风格高级、清晰、科技感强、信息图海报感、16:9 横版、构图有冲击力、中文标题尽量清晰。&quot; \
  --width 2720 \
  --height 1536 \
  --num_steps 40 \
  --cfg_scale 4.0 \
  --device cuda \
  --dtype bfloat16 \
  --attn_backend sdpa \
  --vram_mode balanced \
  --output outputs/sensenova_u1_article_cover.png
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;终端生成过程：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/f503188c529649009aba70e5cf56caee~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5YCU5by655qE55-z5aS0Xw==:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780105106&amp;amp;x-signature=pHbJ3UeljvgUeCI8w%2FOhkjcLWDg%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;最终封面图我放在文章开头，也再贴一次：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/d07d3d0e8d17436e8be2ad626634ca92~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5YCU5by655qE55-z5aS0Xw==:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780105106&amp;amp;x-signature=84voKBM0lMjjivyHMUSZ0BHrBA0%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;这张封面图的整体完成度比我预期更好：主题明确，GPU 服务器、Mac、本地部署这些元素都能和文章内容对应起来，中文标题也足够醒目。对我来说，它已经不只是“跑通模型”的证明，而是可以直接服务文章表达的结果图。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-8&quot;&gt;这次部署我得到的几个结论&lt;/h2&gt;
&lt;p&gt;第一，网页版适合快速验证创意。本地部署前，我先用网页版生成了信息图和贴纸。如果这个阶段效果不值得继续投入，本地部署其实没有必要。&lt;/p&gt;
&lt;p&gt;第二，Mac 可以做环境验证，但不适合当前 8B-MoT 完整生成推理。我的 Mac 上完成了 Python 3.11 环境、依赖安装、模型下载和脚本启动，但 MPS 在加载模型阶段就接近 18GB 上限并 OOM。&lt;code&gt;--vram_mode low&lt;/code&gt; 又依赖 CUDA/XPU，不支持 MPS。&lt;/p&gt;
&lt;p&gt;第三，CUDA 服务器是当前最稳路线。只要 PyTorch 版本、CUDA 版本、Python 版本对齐，部署体验明显顺畅。我的环境里 &lt;code&gt;torch==2.8.0+cu128&lt;/code&gt;、CUDA 12.8、RTX 3090 能跑通本地推理。&lt;/p&gt;
&lt;p&gt;第四，模型下载要提前规划。SenseNova-U1-8B-MoT 文件不少，直接在线加载容易受网络影响。我更推荐先用 &lt;code&gt;huggingface-cli download&lt;/code&gt; 下载到数据盘，再用本地路径加载。&lt;/p&gt;
&lt;p&gt;第五，分辨率要尊重官方 bucket。像 &lt;code&gt;1360x768&lt;/code&gt; 这种看起来标准的 16:9，并不一定适合模型内部 patch 逻辑。官方 16:9 bucket 是 &lt;code&gt;2720x1536&lt;/code&gt;，使用非 bucket 分辨率可能会在 patchify 阶段报错。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-9&quot;&gt;最后总结&lt;/h2&gt;
&lt;p&gt;这次折腾下来，我最大的感受不是“终于生成了一张图”，而是对 SenseNova-U1 的部署边界有了更清楚的判断。&lt;/p&gt;
&lt;p&gt;我认为 SenseNova-U1 最有价值的点不是单张图是否完美，而是它把理解、生成、编辑、交错图文这些任务放在统一模型路线里。对于开发者来说，这意味着后续不一定要为每个多模态任务拼不同模型和不同服务，而是有机会围绕一个统一模型做应用层封装。&lt;/p&gt;
&lt;p&gt;当然，从这次实测看，它也不是“无脑本地跑”的模型。Python 版本、CUDA 版本、模型下载、显存、分辨率 bucket，每一项都可能成为部署门槛。我的建议是：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-plain&quot; lang=&quot;plain&quot;&gt;如果只是体验能力，先用网页版。
如果是 Mac 用户，先把它当成环境适配和失败分析样本，不要期待轻松跑满。
如果要真正复现本地推理，优先选择 Linux + NVIDIA CUDA。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这条路线最终是跑通的，而且中间踩到的问题也比较有代表性。对我来说，这比单纯贴一个“成功生成”的结果更有意义。&lt;/p&gt;</description><link>https://juejin.cn/post/7642555314736136227</link><guid isPermaLink="false">https://juejin.cn/post/7642555314736136227</guid><pubDate>Sat, 23 May 2026 01:38:26 GMT</pubDate><author>倔强的石头_</author><category>人工智能</category><category>开源</category></item><item><title>看我你就不焦虑了,程序员！失踪人口回归，我去干嘛了！！！！</title><description>&lt;p&gt;看了一下我掘金最后一篇文章更新时间，已经是在两年前了，很久没有在掘金上去更新了，我加入掘金社区是在2019年，中间断断续续有更新一些文章和学习内容。断更很久了，&lt;strong&gt;因为我失业了很久&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;记得上一份工作还是在北京工作，一个很偶然机会得到工作机会然后从成都去了北京，这份工作依稀记得在2024年11月出初结束，没错我是被&lt;strong&gt;裁员了&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在外漂泊有7到8年吧，我后面选择了会老家，于是我会武汉了，距离现在2026年5月22号，已经过去一年半了，&lt;/p&gt;
&lt;p&gt;我还没有找到工作，因为需要定居，于是我在武汉买了房子（ps本来我不想买，可是爸妈说租房子不如买房子，我确实也没地方住），存款也已经不多了。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;当然中间是有摆烂一段时间，再加上AI不断爆火更新 我陆续开始找，可是好像一直没有勇气迈出哪一步，
我一直觉得我没有准备好，中间自己也有接一些私活，但是只能说维持生活，可是也越来越难了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我歇息久了，我就感觉我就不想上班了，每天除了吃就睡，晚上睡不着，白天睡不醒，一天饿了才会吃，偶然发疯，
本来说想趁着这段时间，学习一下AI相关的东西的，可是断断续续也没有学进去什么，&lt;/p&gt;
&lt;p&gt;但我意识到我不能再这么颓废下去了，我一直拿准备好再去面试当借口一天拖拉一天，我知道这样我可能永远都准备不好，永远不可能迈出那一步。&lt;/p&gt;
&lt;p&gt;我是JAVA后端开发，可以给我一些建议，AI方面 AI agent 开发可以吗，还是其他工作岗位和编程相关性的，或者JAVA后端在武汉好找工作吗，有什么经验吗，在武汉工作伙伴们，我今年30了，学历大专，在线急急急。。。。。&lt;/p&gt;</description><link>https://juejin.cn/post/7642513525504737334</link><guid isPermaLink="false">https://juejin.cn/post/7642513525504737334</guid><pubDate>Fri, 22 May 2026 16:07:38 GMT</pubDate><author>程序员三时</author><category></category><category>程序员</category><category>AI编程</category></item><item><title>Gemini3.5Flash前端是真的强！</title><description>&lt;p&gt;Gemini 前端厉害，是公认的！但是没想到 3.5 Flash 这么厉害！（抱歉~有点冒犯到前端和设计师了）&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/b7175a5bc3784da2bfb2c918b486d413~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55Sy57u05pav:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780047342&amp;amp;x-signature=p1fMWr6t4ymly3obYNIyPbs0YqA%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;“桃花影落飞神剑，碧海潮生按玉箫。” ——黄药师《射雕英雄传》&lt;/p&gt;
&lt;p&gt;最近我有点“复古”，在研究“武侠”！&lt;/p&gt;
&lt;p&gt;然后就想着让 AI 帮我做一个网页，可以整理出金庸、古龙的武侠作品，以及其中的人物、武功、兵器、战役、图谱。&lt;/p&gt;
&lt;p&gt;因为这几天在高强度测试 Gemini 3.5 Flash，所以这个任务自然是交给它了。&lt;/p&gt;
&lt;p&gt;它第一个版本就惊艳到我了！&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/cf1c293374784942bf88a32a31d0dfbe~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55Sy57u05pav:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780047342&amp;amp;x-signature=GNfZBZs5sWpXrbTbsz0KOA36cDM%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;风格设计相当出色，而且贴合主题，内容规划也非常到位，字体选得也很赞，配色也不错！&lt;/strong&gt;* &lt;em&gt;制作过程也极快。&lt;/em&gt;*&lt;/p&gt;
&lt;p&gt;就几句话的事情，整个前端设计已经做得八九不离十了！&lt;/p&gt;
&lt;p&gt;根本不用费心和设计师沟通，规划不同页面，然后搜集各种数据，然后反复调整，反复改稿，然后再找一个前端工程师把设计稿变成网页。&lt;/p&gt;
&lt;p&gt;现在就一个 Gemini，几分钟功夫，全部搞完！&lt;/p&gt;
&lt;p&gt;它的页面构思是非常全面的，基本的内容展示逻辑都考虑到了。&lt;/p&gt;
&lt;p&gt;下面我就来展示一下细节，最后说一下，我是如何指挥 Gemini 3.5 Flash 生成这个网页的！&lt;/p&gt;
&lt;h2 data-id=&quot;heading-0&quot;&gt;首页&lt;/h2&gt;
&lt;p&gt;一个红色的特殊字体的“江湖百晓生”点明网站主题。&lt;/p&gt;
&lt;p&gt;然后下面金色文字：“&lt;strong&gt;知天下人 + 悉天下兵 + 辨天下武 + 记天下事&lt;/strong&gt;”！&lt;/p&gt;
&lt;p&gt;非常形象地概括了主要内容。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/626097c2417d46958ce0c6f0b39dcbb0~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55Sy57u05pav:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780047342&amp;amp;x-signature=XXCqVhBRog9ypVtVVAe9HBSW%2BM0%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;接下来是武侠世界的名人名言。看到这些熟悉的对白，脑海里立马就会复习哪些我们耳熟能详的片段。&lt;/p&gt;
&lt;p&gt;底部还有一个搜索框。可以搜寻侠客、绝技、兵器、宝典。&lt;/p&gt;
&lt;p&gt;然后还做了分卷二、分卷三，可以分屏展示！&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/988bbd9ca8ef4913a1902446ac5911a3~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55Sy57u05pav:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780047342&amp;amp;x-signature=JLfFjd1r04lkNTqk1qmSOSM01Lo%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;这个整体感觉太好了，这绝对不是简单的排列组合。&lt;/p&gt;
&lt;p&gt;而是充分理解了中国武侠，融会贯通之后，才会有的设计。&lt;/p&gt;
&lt;p&gt;你看这些文字描述，全是那透着古味儿的武侠专有名词。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-1&quot;&gt;藏经秘阁&lt;/h2&gt;
&lt;p&gt;这一部分主要展示金庸和古龙的武侠作品。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/4894a6758b2a4554aa8dbe8e08bedeaa~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55Sy57u05pav:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780047342&amp;amp;x-signature=7DviFGU7aiQ6sCYtBHOut82OvN0%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;顶部做了金庸作品集和古龙系列集的分类。下面是一本书一个卡片。卡片设计也很有古风韵味，看起来就很像一本书。右侧竖屏的书名，左边的书线。然后每本书上有一句话和书的概要。&lt;/p&gt;
&lt;p&gt;比如射雕英雄传的：“侠之大者，为国为民”；&lt;/p&gt;
&lt;p&gt;神雕侠侣的：“问世间情为何物，直教人生死相许”！&lt;/p&gt;
&lt;p&gt;天龙八部这个：“飞雪连天射白露，笑书神侠倚碧鸳” 好像是错乱了，这是金庸的书名集合！&lt;/p&gt;
&lt;p&gt;点击书本还可以展开：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/ff515e0719754f519d7bbbd2c490f730~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55Sy57u05pav:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780047342&amp;amp;x-signature=ZwPY%2BLSh2%2B2k114sfRr7rYV5NC4%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;展开之后可以看到：&lt;/p&gt;
&lt;ol start=&quot;0&quot;&gt;
&lt;li&gt;书里面有哪些角色&lt;/li&gt;
&lt;li&gt;出场的神兵是什么&lt;/li&gt;
&lt;li&gt;经典武学有哪些&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-id=&quot;heading-2&quot;&gt;群侠风云&lt;/h2&gt;
&lt;p&gt;这一部分主要就是小说中出现的人物。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/ddad448b639a4109aa41d1e5cfec6d03~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55Sy57u05pav:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780047342&amp;amp;x-signature=UWDpUjVRNwdN5fa7a9ruUKQlAEA%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;下面可以看到我们熟悉的：&lt;/p&gt;
&lt;ol start=&quot;0&quot;&gt;
&lt;li&gt;丐帮：萧峰&lt;/li&gt;
&lt;li&gt;大理段氏：段誉&lt;/li&gt;
&lt;li&gt;逍遥派：虚竹&lt;/li&gt;
&lt;li&gt;丐帮：郭靖&lt;/li&gt;
&lt;li&gt;桃花岛岛主：黄蓉&lt;/li&gt;
&lt;li&gt;古墓派：杨过&lt;/li&gt;
&lt;li&gt;古墓派：小龙女&lt;/li&gt;
&lt;li&gt;明教：张无忌&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;等等等等。&lt;/p&gt;
&lt;p&gt;每一个人物一张卡片，卡片里面包含了以下内容：作者来源、所属派别、相关标签。&lt;/p&gt;
&lt;p&gt;点开每个人物之后，就可以看到他的详细信息。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/cdeb8dde76a740ca9e42bdfcf23651dd~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55Sy57u05pav:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780047342&amp;amp;x-signature=FKQD7R4kx2CZf%2BMmS5eNaSc2NO0%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;比如我们的萧峰，降龙大侠北乔峰！&lt;/p&gt;
&lt;p&gt;侠客生平：&lt;/p&gt;
&lt;p&gt;他曾任丐帮帮主，为人豪迈飒爽，智勇双全，世人尊称为“北乔峰”。&lt;/p&gt;
&lt;p&gt;江湖语录：&lt;/p&gt;
&lt;p&gt;我萧峰大好头颅在此，谁来取之？阿朱就是阿朱，四海列国，千秋万载，就只有一个阿朱。&lt;/p&gt;
&lt;p&gt;人物纠葛：&lt;/p&gt;
&lt;p&gt;结拜兄弟：段誉、虚竹，挚爱：阿朱&lt;/p&gt;
&lt;p&gt;右边还有一个人物雷达图，哈哈！&lt;/p&gt;
&lt;h2 data-id=&quot;heading-3&quot;&gt;兵器谱&lt;/h2&gt;
&lt;p&gt;这部分主要展现小说中的兵器。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/37cb3d88015947ae9ef1e58f0830d03a~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55Sy57u05pav:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780047342&amp;amp;x-signature=8e4C3bN7RQy2O30VNKCh4oaUFE8%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;因为百晓生这个角色主要源于古龙的小说，所以这部分首先放的是“百晓生兵器谱”。在古龙的小说中：&lt;/p&gt;
&lt;ol start=&quot;0&quot;&gt;
&lt;li&gt;天机棒（排名第一）&lt;/li&gt;
&lt;li&gt;子母龙凤环（排名第二）&lt;/li&gt;
&lt;li&gt;小李飞刀（排名第三）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;继续往下翻就可以看到其他的兵器了。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/04cc1fd552404ce8b32000a9af508ceb~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55Sy57u05pav:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780047342&amp;amp;x-signature=D3wRLWEztBUY68p8HlPBCzAhZgQ%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;这个兵器也进行了分类，可以选金庸还是古龙，甚至还细分为：剑、刀、暗器、奇门、防具等！每件武器都有介绍以及锋芒值。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-4&quot;&gt;奇功奥义&lt;/h2&gt;
&lt;p&gt;这一部分就介绍小说中的武功秘籍吧。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/de10ceb932f044e2a3554acc43924f9c~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55Sy57u05pav:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780047342&amp;amp;x-signature=%2BZjL2rykWfB%2B6b496edM5nbSyS8%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;武功秘籍也是卡片形式的，可以展开和收起，同时也做了分类和筛选。&lt;/p&gt;
&lt;p&gt;比如第一个是金庸掌法类的降龙十八掌，里面说到源自历代丐帮帮主的传承。经典招式：&lt;/p&gt;
&lt;ol start=&quot;0&quot;&gt;
&lt;li&gt;亢龙有悔&lt;/li&gt;
&lt;li&gt;飞龙在天&lt;/li&gt;
&lt;li&gt;见龙在田&lt;/li&gt;
&lt;li&gt;神龙摆尾&lt;/li&gt;
&lt;li&gt;潜龙勿用&lt;/li&gt;
&lt;li&gt;双龙取水&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;牛牛牛～～学会了！&lt;/p&gt;
&lt;h2 data-id=&quot;heading-5&quot;&gt;风云战役&lt;/h2&gt;
&lt;p&gt;这部分显示的就是小说中的名场面。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/b466b288e8d84495b09897bb690e7009~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55Sy57u05pav:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780047342&amp;amp;x-signature=10y3yZ8RP5sVzby%2BPoOFvl4rOpY%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;这里面的布局还挺有特色的，采用那种类似时间线和节点的方式，左边一个、右边一个交叉显示。&lt;/p&gt;
&lt;p&gt;这里放在第一个的是金庸的华山论剑。 对这个事件做了说明，然后列出了参战的风云人物。&lt;/p&gt;
&lt;p&gt;这里提到参与的人有：王重阳、黄药师、欧阳锋、段智兴、洪七公、郭靖、杨过。&lt;/p&gt;
&lt;p&gt;这个细节应该是对的吧？&lt;/p&gt;
&lt;p&gt;除了这个之外，还有很多名场面，比如“决战紫禁之巅”。&lt;/p&gt;
&lt;p&gt;参战人物有：西门吹雪、叶孤城、陆小凤等。&lt;/p&gt;
&lt;p&gt;还有“决战光明顶”。&lt;/p&gt;
&lt;p&gt;六大正道门派围攻明教总部光明顶，参战人物有：张无忌、灭绝师太等。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-6&quot;&gt;江湖图谱&lt;/h2&gt;
&lt;p&gt;这部分主要就是说人物关系。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/d31c6414a2a34f10b9e7b38e7f266796~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55Sy57u05pav:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780047342&amp;amp;x-signature=Si3UAtsg6s5Y9%2FSbnbwjlDEtaSk%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;比如我们的丐帮帮主萧峰，他的人物关系包括：&lt;/p&gt;
&lt;ol start=&quot;0&quot;&gt;
&lt;li&gt;结拜兄弟：段誉、虚竹&lt;/li&gt;
&lt;li&gt;挚爱：阿朱&lt;/li&gt;
&lt;li&gt;另外还有一些灰色的部分，好像是一些推荐的人物。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;点击某个人物之后，这个图就会立马切换成新的人物关系图。&lt;/p&gt;
&lt;p&gt;除了上面各种功能之外，还包含了两个主题，以及右下角的背景音切换功能。&lt;/p&gt;
&lt;p&gt;整体看下来，项目已经非常完善了：&lt;/p&gt;
&lt;ol start=&quot;0&quot;&gt;
&lt;li&gt;每个功能模块都已经具备&lt;/li&gt;
&lt;li&gt;每个页面设计都已完成&lt;/li&gt;
&lt;li&gt;相关的内容填充也都很到位&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;接下来只要稍微完善一下，把数据补充完整就 OK 了。&lt;/p&gt;
&lt;p&gt;我是只抽了一次卡，直接就抽到了比较满意效果，所以就没有再继续抽了。&lt;/p&gt;
&lt;p&gt;感觉多抽抽还能抽出很多宝藏！&lt;/p&gt;
&lt;h2 data-id=&quot;heading-7&quot;&gt;制作过程&lt;/h2&gt;
&lt;p&gt;光分享结果不是我的风格，所以下面带大家来体验一下，我是怎么制作的。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/6bea7a52b9a1471ab39368ed32630eb5~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55Sy57u05pav:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780047342&amp;amp;x-signature=afyf8ERAvqm7yKCin8QwBj6VhYc%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;我使用的工具就是谷歌最近发布的 Antigravity 2.0。&lt;/p&gt;
&lt;p&gt;操作很简单：打开软件，创建一个文件夹，开始提出自己的想法。&lt;/p&gt;
&lt;p&gt;然后，Gemini 就帮我做了一些设计，提供了一些方案供我选择。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;我为“江湖百晓生”网站制定了一份详细的实施计划。

它涵盖了技术选型（Vite + React + CSS）、视觉风格规范（水墨风、自定义雷达图、落叶动效）以及详尽的金庸与古龙小说/人物/神兵/武功数据结构。

请您查看实施计划，并在继续之前协助确认以下几个关键点：

视觉风格倾向：您更喜欢水墨暗黑风（黑/深灰色背景、朱砂红与金色点缀，极具武侠神秘感）还是古风宣纸风（淡黄/米色宣纸质感背景、墨黑与棕色线条，偏向传统古朴画卷）？

门派可视化：对于各大门派（少林、武当、移花宫、丐帮等）的关系和信息展现，您希望是一个图形化的关系网，还是常规的分类卡片？

音乐与音效：我们计划加入优雅的武侠古筝/竹笛背景音乐（默认静音，提供浮动开关），以及按钮悬停/点击时的刀剑出鞘音效，您是否喜欢这种设计？

期待您的反馈！收到您的批准和意见后，我将立刻开始搭建项目并编写数据与界面。

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其实你看到它的这个描述时，就知道它已经 get 到你的点了。它已经选择好了技术方案、视觉风格以及内容的排列等。&lt;/p&gt;
&lt;p&gt;下面提出了三个问题：&lt;/p&gt;
&lt;ol start=&quot;0&quot;&gt;
&lt;li&gt;视觉风格：是要选水墨暗黑风，还是古风宣纸风？&lt;/li&gt;
&lt;li&gt;门派可视化：你是需要分类卡片，还是关系网？&lt;/li&gt;
&lt;li&gt;音乐与音效：计划加入古筝主题背景，并提供浮动开关；此外，按钮选中、点击时会加入刀剑出鞘的音效。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;它既然问了，你说我该怎么选呢？&lt;strong&gt;我的世界里没有二选一，肯定是全要。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;然后它就会自己制作实现方案、任务列表以及总结文档。你只要点执行就好了。&lt;/p&gt;
&lt;p&gt;执行完成之后会自动启动服务器，然后你打开这个网址：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-arduino&quot; lang=&quot;arduino&quot;&gt;http:&lt;span class=&quot;hljs-comment&quot;&gt;//localhost:5173&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样就可以在浏览器中看到效果了。&lt;/p&gt;
&lt;p&gt;当然这个过程也不完全是说全自动完成。&lt;/p&gt;
&lt;p&gt;因为你做一个东西的关键在于，它生成的内容和你需要的内容是否能够对齐。当不对齐的时候，你就需要纠正它。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;第一阶段计划：
文件：
implementation_plan_phase1.md
内容：初始化 Vite 骨架，建立水墨风视觉设计，构建基础武侠数据库与 Lobby、Characters 等核心组件。

第二阶段计划：
文件：
implementation_plan_phase2.md
内容：实现“宣纸古风”亮色主题与飘落桃花瓣粒子，构建交互式 SVG 江湖人物人际关系网图谱（江湖图谱）。

第三阶段计划：
文件：
implementation_plan_phase3.md
内容：大幅扩充并完善本地数据库（新增 7 位侠客、3 件神兵、6 门武功、4 场战役），打通跳转流转的一致性关系。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;所以其实我中间也调整了几轮， 它创建了三个计划，然后每个计划里面有一些细节调整。&lt;/p&gt;
&lt;p&gt;Gemini 是会把所有的相关文件保存在它自己的目录里面的，然后我就比较喜欢存在我的项目目录里。&lt;/p&gt;
&lt;p&gt;所以我让它把所有过程中的相关内容全都保存到我的文档目录存档，这样方便后期的迭代，以及迁移到其他工具或者做后续的回顾。&lt;/p&gt;
&lt;p&gt;现在的模型已经很厉害，所以我也没有太多其他可以介绍的。&lt;/p&gt;
&lt;p&gt;就是选择一个文件夹，打开一个对话窗口，然后凭借你对业务的理解能力以及想象力，尽情地对话、反馈，然后再对话、再反馈就可以了。具体实施的部分，你是一点都不要去碰，就是让它完成。&lt;/p&gt;
&lt;p&gt;我刚才主要是展示了它的设计效果。其实从这次的体验来说，它的逻辑能力（即写代码的工程能力）是比之前的版本有明显的提升的。因为之前的版本很容易写着写着就出错，而这一次基本上写完就没有错误， 让它修改的时候时候也是指哪打哪，跟随感比较好。&lt;/p&gt;
&lt;p&gt;现在好像配额也多了！&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/0292f7bce45f44daa1d06708c0bae616~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55Sy57u05pav:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780047342&amp;amp;x-signature=We4UlUf%2Fp9wINK70ukPsqCDRtdA%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;收集大量资料，改了这么多页面内容，写了好几个文档，居然只消耗了 2/5，马上又可以重置了！&lt;/p&gt;
&lt;p&gt;哎，既然如此，是不是要续一波？至少前端很强，后端还行，速度很快，是吧！&lt;/p&gt;</description><link>https://juejin.cn/post/7642514614770008116</link><guid isPermaLink="false">https://juejin.cn/post/7642514614770008116</guid><pubDate>Fri, 22 May 2026 09:35:42 GMT</pubDate><author>甲维斯</author><category></category><category>人工智能</category><category>前端</category></item><item><title>手把手教你写一个 AI Skill，让 AI 真正学会你的工作流</title><description>&lt;p&gt;&lt;code&gt;Skill&lt;/code&gt; 可以理解成 AI 的“专业能力模块”。&lt;/p&gt;
&lt;p&gt;它不是临时 prompt，也不一定要联网调用外部工具。
更准确地说，它是一个文件夹，把某类任务里的经验、规则、操作流程和注意事项都收进去，后面反复用。&lt;/p&gt;
&lt;p&gt;比如你经常让 AI 写周报，每次都要提醒它：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-text&quot; lang=&quot;text&quot;&gt;不要写得太空。
不要虚构数据。
要先整理工作内容。
要写成果、问题和下周计划。
语言正式一点。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;像这种每次都会重复提醒、又很容易沉淀成规则的东西，就适合做成 Skill。&lt;/p&gt;
&lt;p&gt;下面我用“工作总结写作”举例，创建一个叫 &lt;code&gt;work-summary-writing&lt;/code&gt; 的 Skill。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-0&quot;&gt;一个 Skill 长什么样？&lt;/h2&gt;
&lt;p&gt;一个最简单的 Skill，其实只需要一个 &lt;code&gt;SKILL.md&lt;/code&gt; 文件：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-text&quot; lang=&quot;text&quot;&gt;work-summary-writing/
└── SKILL.md
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更完整的 Skill 还可以包含这些目录：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-text&quot; lang=&quot;text&quot;&gt;work-summary-writing/
├── SKILL.md
├── scripts/
├── references/
└── assets/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;不同目录的作用不一样：&lt;/p&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;目录&lt;/th&gt;&lt;th&gt;作用&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;SKILL.md&lt;/code&gt;&lt;/td&gt;&lt;td&gt;必需文件，描述 Skill 什么时候触发，以及触发后怎么做&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;scripts/&lt;/code&gt;&lt;/td&gt;&lt;td&gt;放可重复执行的脚本&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;references/&lt;/code&gt;&lt;/td&gt;&lt;td&gt;放较长的规则、规范、接口文档或业务资料&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;assets/&lt;/code&gt;&lt;/td&gt;&lt;td&gt;放模板、图片、字体、示例文件等输出素材&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;刚开始不用急着把目录搭得很完整。
先把 &lt;code&gt;SKILL.md&lt;/code&gt; 写清楚，让它能触发、能稳定完成任务，第一版就够用了。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-1&quot;&gt;第 1 步：确定这个 Skill 解决什么问题&lt;/h2&gt;
&lt;p&gt;别一上来就写“万能写作 Skill”。&lt;/p&gt;
&lt;p&gt;Skill 越泛，越容易失控。比如：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-yaml&quot; lang=&quot;yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;description:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;帮助用户写东西&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个描述太宽。
写文章、写邮件、写代码注释、写广告文案、写产品需求文档，都可能触发它。
模型最后反而不知道该按哪套规则走。&lt;/p&gt;
&lt;p&gt;我们这次只解决一个具体场景：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;当用户需要写工作总结、周报、月报、季度总结、年度总结、项目复盘或阶段性汇报时，帮助用户把零散信息整理成一篇总结。
这篇总结要结构清晰、重点明确、表达正式自然。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;边界说得越清楚，Skill 越稳定。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-2&quot;&gt;第 2 步：创建 Skill 目录&lt;/h2&gt;
&lt;p&gt;不同 AI 工具放 Skill 的位置不一样。&lt;/p&gt;
&lt;p&gt;以 Codex 为例，个人全局 Skill 通常放在：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-text&quot; lang=&quot;text&quot;&gt;~/.codex/skills/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果我们要创建 &lt;code&gt;work-summary-writing&lt;/code&gt;，目录结构就是：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-text&quot; lang=&quot;text&quot;&gt;~/.codex/skills/work-summary-writing/
└── SKILL.md
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以用命令创建目录：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot; lang=&quot;bash&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;mkdir&lt;/span&gt; -p ~/.codex/skills/work-summary-writing
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果你使用的是 Claude Code，目录可能是：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-text&quot; lang=&quot;text&quot;&gt;~/.claude/skills/work-summary-writing/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;关键不是路径本身，而是要放进对应 Agent 能识别的 Skill 目录。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-3&quot;&gt;第 3 步：写 FrontMatter&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;SKILL.md&lt;/code&gt; 开头需要一段 YAML FrontMatter：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-yaml&quot; lang=&quot;yaml&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;work-summary-writing&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;description:&lt;/span&gt;  &lt;span class=&quot;hljs-string&quot;&gt;撰写、润色或整理中文工作总结类文档时使用，包括周报、双周报、月报、季度总结、半年/年度总结、项目复盘、阶段性汇报、述职报告、工作小结等。当用户说&quot;帮我写个周报&quot;、&quot;整理一份月度工作&quot;、&quot;年终总结&quot;、&quot;项目复盘&quot;、&quot;做汇报材料&quot;、&quot;述职&quot;，或扔过来一堆零散工作记录要求&quot;总结一下&quot;、&quot;整理成报告&quot;时，都要主动启用。该技能用于帮助用户把零散工作内容整理成结构清晰、重点明确、表达正式自然的总结文本。&lt;/span&gt;
&lt;span class=&quot;hljs-meta&quot;&gt;---

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里最重要的是两个字段：&lt;/p&gt;

















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;字段&lt;/th&gt;&lt;th&gt;作用&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;name&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Skill 的名字，建议使用小写英文、数字和连字符&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;description&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Skill 的触发条件和能力说明&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;很多人会低估 &lt;code&gt;description&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;它不是写给人看的简介，而是给 AI 判断“什么时候该加载这个 Skill”的依据。
只有 Skill 被触发后，AI 才会继续读正文。
触发条件如果只写在正文里，模型可能根本看不到。&lt;/p&gt;
&lt;p&gt;所以 &lt;code&gt;description&lt;/code&gt; 里至少要说清楚三件事：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;这个 Skill 能做什么。&lt;/li&gt;
&lt;li&gt;适合什么场景。&lt;/li&gt;
&lt;li&gt;用户说哪些话时应该触发。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不要写成：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-yaml&quot; lang=&quot;yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;description:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;帮助写总结&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这太短，也太模糊。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-4&quot;&gt;第 4 步：把流程写成可执行步骤&lt;/h2&gt;
&lt;p&gt;Skill 更像操作手册，不是理念宣言。&lt;/p&gt;
&lt;p&gt;不要只写：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-text&quot; lang=&quot;text&quot;&gt;写得专业、自然、有逻辑。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这类话方向没错，但模型不好执行。更稳的写法，是把任务拆成一步一步的动作。&lt;/p&gt;
&lt;p&gt;下面是一个完整的 &lt;code&gt;SKILL.md&lt;/code&gt; 示例：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-markdown&quot; lang=&quot;markdown&quot;&gt;---
name: work-summary-writing
&lt;span class=&quot;hljs-section&quot;&gt;description:  撰写、润色或整理中文工作总结类文档时使用，包括周报、双周报、月报、季度总结、半年/年度总结、项目复盘、阶段性汇报、述职报告、工作小结等。当用户说&quot;帮我写个周报&quot;、&quot;整理一份月度工作&quot;、&quot;年终总结&quot;、&quot;项目复盘&quot;、&quot;做汇报材料&quot;、&quot;述职&quot;，或扔过来一堆零散工作记录要求&quot;总结一下&quot;、&quot;整理成报告&quot;时，都要主动启用。该技能用于帮助用户把零散工作内容整理成结构清晰、重点明确、表达正式自然的总结文本。
---&lt;/span&gt;

&lt;span class=&quot;hljs-section&quot;&gt;# 工作总结写作&lt;/span&gt;

&lt;span class=&quot;hljs-section&quot;&gt;## 写作步骤&lt;/span&gt;

&lt;span class=&quot;hljs-section&quot;&gt;### 1. 明确总结范围&lt;/span&gt;

先判断总结的时间范围、使用场景和目标字数，例如：

&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 周报
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 月报
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 季度总结
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 年度总结
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 项目阶段总结
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 个人工作复盘

如果用户没有说明时间范围，可使用“本阶段”作为默认表述。

如果用户没有说明字数，默认生成 800-1200 字左右的工作总结。

&lt;span class=&quot;hljs-section&quot;&gt;### 2. 提炼核心工作&lt;/span&gt;

从用户提供的信息中提取主要工作内容。

优先识别：

&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 负责了什么任务
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 推进了哪些项目
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 解决了哪些问题
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 参与了哪些协作
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 完成了哪些交付

&lt;span class=&quot;hljs-section&quot;&gt;### 3. 整理工作成果&lt;/span&gt;

将工作内容转化为结果表达。

尽量补充：

&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 完成情况
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 进展状态
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 产生的价值
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 效率提升
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 问题解决效果
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 可量化数据

如果用户没有提供数据，不要编造，可使用“提升了工作效率”“推动了项目进展”等稳妥表达。

&lt;span class=&quot;hljs-section&quot;&gt;### 4. 分析问题与不足&lt;/span&gt;

客观总结工作中存在的问题。

可以从以下角度整理：

&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 进度是否受阻
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 沟通是否充分
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 流程是否顺畅
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 方案是否还有优化空间
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 个人能力是否需要提升

表达要克制，不夸大问题，也不回避问题。

&lt;span class=&quot;hljs-section&quot;&gt;### 5. 提炼经验与反思&lt;/span&gt;

总结本阶段获得的经验。

重点写：

&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 哪些方法有效
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 哪些流程可以复用
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 哪些协作方式值得保留
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 后续可以如何改进

&lt;span class=&quot;hljs-section&quot;&gt;### 6. 制定下一步计划&lt;/span&gt;

根据前文内容，提出后续计划。

计划应具体、可执行，例如：

&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 继续推进某项任务
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 优化某个流程
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 提升某项能力
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 完成某个交付
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 加强沟通协作

&lt;span class=&quot;hljs-section&quot;&gt;## 字数要求&lt;/span&gt;

&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 优先遵循用户明确提出的字数要求。
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 如果用户没有提出字数要求，默认生成 800-1200 字。
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 如果用户要求“简短”“简单”“概括”，控制在 300-600 字。
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 如果用户要求“详细”“完整”“正式”，控制在 1200-2000 字。
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 不要为了凑字数重复表达。
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 不要为了压缩字数删掉关键事实。

&lt;span class=&quot;hljs-section&quot;&gt;## 推荐结构&lt;/span&gt;

&lt;span class=&quot;hljs-code&quot;&gt;```text
一、总体情况
简要说明本阶段的工作重点和整体完成情况。

二、主要工作
分条说明完成的重点事项。

三、工作成果
总结取得的结果、进展或价值。

四、问题与不足
客观说明存在的问题和改进空间。

五、经验总结
提炼本阶段的收获和方法。

六、下一步计划
说明后续重点工作安排。
```&lt;/span&gt;

&lt;span class=&quot;hljs-section&quot;&gt;## 注意事项&lt;/span&gt;

&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 不要虚构关键事实、数据、项目名称或成果。
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 用户提供的信息不足时，可以使用通用表达，但应避免写得过满。
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 表达要正式、自然、简洁，避免口号式语言。
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 多写具体行动和实际结果，少写空泛态度。
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 总结个人工作时，突出职责和贡献，但不要过度夸大。
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 总结团队工作时，注意使用“我们”“团队”等表述。
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 问题与不足要真实可改进，不要写成严重失误。
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 下一步计划要和前文问题、成果形成呼应。

&lt;span class=&quot;hljs-section&quot;&gt;## 输出要求&lt;/span&gt;

默认输出一篇完整工作总结。

如果用户只要求框架，则只输出结构和要点。

如果用户提供了原始素材，应优先基于素材改写，不随意扩展事实。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;写到这里，一个最小可用的 Skill 就完成了。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-5&quot;&gt;第 5 步：测试 Skill 是否能触发&lt;/h2&gt;
&lt;p&gt;保存后，可以用接近真实场景的提示词测试：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-text&quot; lang=&quot;text&quot;&gt;帮我写一份本周工作总结。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-text&quot; lang=&quot;text&quot;&gt;把下面这些工作记录整理成月报，正式一点，控制在 1000 字左右。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;测试时我一般看三件事：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;是否会按工作总结场景响应。&lt;/li&gt;
&lt;li&gt;是否遵守结构、字数和注意事项。&lt;/li&gt;
&lt;li&gt;是否在信息不足时乱编数据。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;经常不触发，就先改 &lt;code&gt;description&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;能触发，但输出不稳定，就改正文里的“写作步骤”“注意事项”和“输出要求”。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-6&quot;&gt;第 6 步：什么时候需要 scripts、references 和 assets？&lt;/h2&gt;
&lt;p&gt;不是每个 Skill 都需要额外目录。&lt;/p&gt;
&lt;p&gt;像“工作总结写作”这种偏写作和判断的 Skill，通常一个 &lt;code&gt;SKILL.md&lt;/code&gt; 就够。&lt;/p&gt;
&lt;p&gt;任务变复杂之后，再考虑拆资源。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-7&quot;&gt;需要 scripts 的情况&lt;/h3&gt;
&lt;p&gt;如果某个操作需要稳定执行，就别让 AI 每次重新想办法。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-text&quot; lang=&quot;text&quot;&gt;markdown-mermaid-to-images/
├── SKILL.md
└── scripts/
    └── convert_mermaid.py
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这类任务涉及文件扫描、图片导出、路径替换。交给脚本，比写一堆自然语言规则可靠。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-8&quot;&gt;需要 references 的情况&lt;/h3&gt;
&lt;p&gt;如果有大量规则、规范、接口文档或业务知识，就放到 &lt;code&gt;references/&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-text&quot; lang=&quot;text&quot;&gt;contract-review/
├── SKILL.md
└── references/
    └── clause-checklist.md
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;SKILL.md&lt;/code&gt; 只写核心流程，并说明什么时候读取参考资料。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-9&quot;&gt;需要 assets 的情况&lt;/h3&gt;
&lt;p&gt;如果最终产物需要模板或素材，就放到 &lt;code&gt;assets/&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;例如：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-text&quot; lang=&quot;text&quot;&gt;slides-builder/
├── SKILL.md
└── assets/
    └── company-template.pptx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样 AI 不用每次重新创建模板，也更容易保持统一样式。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-10&quot;&gt;手写 Skill 的常见问题&lt;/h2&gt;
&lt;p&gt;手写 Skill 很适合理解原理，但也容易踩坑。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-11&quot;&gt;1. description 太宽泛&lt;/h3&gt;
&lt;p&gt;错误示例：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-yaml&quot; lang=&quot;yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;description:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;写作助手&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个描述几乎什么都能触发，边界太宽。&lt;/p&gt;
&lt;p&gt;更好的写法：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-yaml&quot; lang=&quot;yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;description:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;撰写、润色或整理中文工作总结类文档时使用，包括周报、双周报、月报、季度总结、半年/年度总结、项目复盘、阶段性汇报、述职报告、工作小结等。当用户说&quot;帮我写个周报&quot;、&quot;整理一份月度工作&quot;、&quot;年终总结&quot;、&quot;项目复盘&quot;、&quot;做汇报材料&quot;、&quot;述职&quot;，或扔过来一堆零散工作记录要求&quot;总结一下&quot;、&quot;整理成报告&quot;时，都要主动启用。该技能用于帮助用户把零散工作内容整理成结构清晰、重点明确、表达正式自然的总结文本。&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-id=&quot;heading-12&quot;&gt;2. 只写原则，不写步骤&lt;/h3&gt;
&lt;p&gt;错误示例：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-markdown&quot; lang=&quot;markdown&quot;&gt;&lt;span class=&quot;hljs-section&quot;&gt;## 要求&lt;/span&gt;

写得专业、自然、有深度。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更好的写法，是把“专业”拆成动作：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;先判断总结范围。&lt;/li&gt;
&lt;li&gt;再提炼核心工作。&lt;/li&gt;
&lt;li&gt;然后整理成果。&lt;/li&gt;
&lt;li&gt;接着写问题与不足。&lt;/li&gt;
&lt;li&gt;最后写经验和计划。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-id=&quot;heading-13&quot;&gt;3. 把所有东西都塞进 SKILL.md&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;SKILL.md&lt;/code&gt; 最好保持精简。&lt;/p&gt;
&lt;p&gt;内容越来越长时，通常就该拆了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;长规范放 &lt;code&gt;references/&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;重复操作放 &lt;code&gt;scripts/&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;模板素材放 &lt;code&gt;assets/&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-id=&quot;heading-14&quot;&gt;4. 没有写反例和禁区&lt;/h3&gt;
&lt;p&gt;很多输出问题，不是 AI 不知道该做什么，而是不知道什么不能做。&lt;/p&gt;
&lt;p&gt;例如工作总结里必须明确：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不要虚构数据。&lt;/li&gt;
&lt;li&gt;不要写口号。&lt;/li&gt;
&lt;li&gt;不要把小问题写成严重事故。&lt;/li&gt;
&lt;li&gt;不要为了凑字数重复表达。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;限制写得越清楚，输出越稳定。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-15&quot;&gt;接下来：用 skill-creator 自动创建&lt;/h2&gt;
&lt;p&gt;手写过一遍之后，再看 &lt;code&gt;skill-creator&lt;/code&gt; 就顺很多。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;skill-creator&lt;/code&gt; 也是一个 Skill，只是它专门负责创建和更新 Skill。
目录结构、FrontMatter、资源该不该拆，它会帮你一起处理。
你不用每次都从空白文件开始。&lt;/p&gt;
&lt;p&gt;github地址：&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2Fanthropics%2Fskills%2Ftree%2Fmain%2Fskills%2Fskill-creator&quot; target=&quot;_blank&quot; title=&quot;https://github.com/anthropics/skills/tree/main/skills/skill-creator&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;github.com/anthropics/…&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;安装 skill-creator：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot; lang=&quot;bash&quot;&gt;npx skills add https://github.com/anthropics/skills --skill skill-creator
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;你可以直接这样要求 claude code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-text&quot; lang=&quot;text&quot;&gt;使用 skill-creator，帮我创建一个 work-summary-writing skill。

目标：
当用户需要写工作总结、周报、月报、季度总结、年度总结、项目复盘或阶段性汇报时触发。

能力：
1. 判断总结范围和字数要求。
2. 从零散工作记录中提炼核心工作。
3. 整理工作成果、问题不足、经验总结和下一步计划。
4. 输出正式、自然、结构清晰的工作总结。

注意事项：
1. 不要虚构关键事实、数据、项目名称或成果。
2. 信息不足时使用稳妥表达。
3. 避免口号式语言。
4. 下一步计划要具体可执行。

位置：
安装到全局 Claude skills 目录。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这种请求比“帮我创建一个写周报 Skill”稳定得多。
边界给清楚了，&lt;code&gt;skill-creator&lt;/code&gt; 才知道该往哪里收、哪里不能展开。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-16&quot;&gt;skill-creator 会帮你做什么？&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;skill-creator&lt;/code&gt; 不只是生成一个空文件夹。&lt;/p&gt;
&lt;p&gt;它会从“另一个 AI 以后怎么用这个 Skill”的角度，帮你把这些事情过一遍：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;理解这个 Skill 要解决什么问题。&lt;/li&gt;
&lt;li&gt;整理触发条件和真实使用场景。&lt;/li&gt;
&lt;li&gt;规划是否需要 &lt;code&gt;scripts/&lt;/code&gt;、&lt;code&gt;references/&lt;/code&gt;、&lt;code&gt;assets/&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;创建 Skill 目录和 &lt;code&gt;SKILL.md&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;写好 &lt;code&gt;name&lt;/code&gt;、&lt;code&gt;description&lt;/code&gt; 和正文流程。&lt;/li&gt;
&lt;li&gt;必要时补充资源文件。&lt;/li&gt;
&lt;li&gt;检查 Skill 结构是否完整。&lt;/li&gt;
&lt;li&gt;根据真实使用结果继续迭代。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;换句话说，手写时你要自己操心的细节，&lt;code&gt;skill-creator&lt;/code&gt; 会替你检查一轮。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-17&quot;&gt;为什么要用 skill-creator？&lt;/h2&gt;
&lt;p&gt;手写适合学习原理。真要长期用，我更建议交给 &lt;code&gt;skill-creator&lt;/code&gt; 起草和迭代。&lt;/p&gt;
&lt;p&gt;原因主要有四个。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-18&quot;&gt;1. 它更懂 Skill 的结构&lt;/h3&gt;
&lt;p&gt;一个 Skill 不只是写一段 prompt。&lt;/p&gt;
&lt;p&gt;它需要考虑：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;name&lt;/code&gt; 是否规范。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;description&lt;/code&gt; 是否能准确触发。&lt;/li&gt;
&lt;li&gt;正文是否是可执行流程。&lt;/li&gt;
&lt;li&gt;是否缺少注意事项。&lt;/li&gt;
&lt;li&gt;是否应该拆分资源目录。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些细节手写时很容易漏掉。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-19&quot;&gt;2. 它能减少触发错误&lt;/h3&gt;
&lt;p&gt;低质量 Skill 最常见的问题，就是 &lt;code&gt;description&lt;/code&gt; 写得太宽，或者太窄。&lt;/p&gt;
&lt;p&gt;太宽会误触发，太窄会不触发。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;skill-creator&lt;/code&gt; 会提醒你把能力、场景和触发词写清楚。
比如别只写“处理合同”，要写成“当用户要求检查合同、总结合同风险或整理关键条款时使用”。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-20&quot;&gt;3. 它会帮你判断资源怎么拆&lt;/h3&gt;
&lt;p&gt;很多人第一次写 Skill，会把所有规则都塞进 &lt;code&gt;SKILL.md&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;短期能用，时间一长就会臃肿。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;skill-creator&lt;/code&gt; 会根据任务判断：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;是否需要脚本保证稳定执行。&lt;/li&gt;
&lt;li&gt;是否需要参考资料保存长规则。&lt;/li&gt;
&lt;li&gt;是否需要模板或素材支持最终输出。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这就是渐进加载：常用规则放正文，长资料按需读取，重复操作交给脚本。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-21&quot;&gt;4. 它适合持续迭代&lt;/h3&gt;
&lt;p&gt;好的 Skill 通常不是一次写完的。&lt;/p&gt;
&lt;p&gt;真实使用后，你会发现它可能有这些问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;某些提示词没有触发。&lt;/li&gt;
&lt;li&gt;输出格式不稳定。&lt;/li&gt;
&lt;li&gt;经常编造不存在的数据。&lt;/li&gt;
&lt;li&gt;处理复杂输入时漏步骤。&lt;/li&gt;
&lt;li&gt;和其他 Skill 的边界冲突。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这时可以继续让 &lt;code&gt;skill-creator&lt;/code&gt; 检查和更新：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-text&quot; lang=&quot;text&quot;&gt;使用 skill-creator 检查这个 skill 是否合格：
~/.claude/skills/work-summary-writing

重点检查：
1. description 是否能准确触发。
2. SKILL.md 是否过长。
3. 写作步骤是否可执行。
4. 注意事项是否覆盖常见错误。
5. 是否需要拆分 references 或 assets。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这比临时修一句 prompt 稳得多。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-22&quot;&gt;手写和 skill-creator 怎么选？&lt;/h2&gt;
&lt;p&gt;可以按这个规则判断：&lt;/p&gt;

































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;场景&lt;/th&gt;&lt;th&gt;建议&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;第一次学习 Skill&lt;/td&gt;&lt;td&gt;手写一遍&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;只需要一个很小的个人规则&lt;/td&gt;&lt;td&gt;手写也可以&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;要创建长期复用的 Skill&lt;/td&gt;&lt;td&gt;用 &lt;code&gt;skill-creator&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Skill 涉及脚本、模板、参考资料&lt;/td&gt;&lt;td&gt;用 &lt;code&gt;skill-creator&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;需要检查触发条件和目录结构&lt;/td&gt;&lt;td&gt;用 &lt;code&gt;skill-creator&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;需要迭代已有 Skill&lt;/td&gt;&lt;td&gt;用 &lt;code&gt;skill-creator&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;我的建议是：先手写一个最小版本，搞清楚 &lt;code&gt;name&lt;/code&gt;、&lt;code&gt;description&lt;/code&gt;、正文流程和注意事项分别在干什么。
之后要创建正式 Skill，再交给 &lt;code&gt;skill-creator&lt;/code&gt;。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-23&quot;&gt;小结&lt;/h2&gt;
&lt;p&gt;写 Skill 的重点，不是把 prompt 写长。
真正要做的，是把高频任务沉淀成一套能触发、能执行、后面还能维护的工作流。&lt;/p&gt;
&lt;p&gt;一个好 Skill，至少要回答四个问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;什么时候触发？&lt;/li&gt;
&lt;li&gt;触发后按什么步骤做？&lt;/li&gt;
&lt;li&gt;输出应该长什么样？&lt;/li&gt;
&lt;li&gt;哪些事情不能做？&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;手写能帮你理解底层结构。&lt;code&gt;skill-creator&lt;/code&gt; 则适合把这套结构做完整，并且在后续使用中持续修。&lt;/p&gt;
&lt;p&gt;第一版 Skill 不需要完美。
先让它在真实任务里跑起来。
哪里触发错了，就补触发条件；哪里输出跑偏了，就补规则和反例；哪里靠文字说不稳，就拆资源、加脚本。
Skill 是这样一点点变强的。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/f29406ed80704d208c7b8e3568299ce5~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg56iL5bqP5ZGY5bCP5a-S:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780014974&amp;amp;x-signature=M%2BhQS%2BVuaUguPnl8PYnLFeGJBi4%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;h2 data-id=&quot;heading-24&quot;&gt;往期回顾&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fmp.weixin.qq.com%2Fs%2FAj7mOtgJd2xxlNJg464wow&quot; target=&quot;_blank&quot; title=&quot;https://mp.weixin.qq.com/s/Aj7mOtgJd2xxlNJg464wow&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;AI Skill 是什么？一篇讲清楚它和 Prompt、MCP 的区别&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fmp.weixin.qq.com%2Fs%2FlgKiloZ83TbB2iYaa-EX5g&quot; target=&quot;_blank&quot; title=&quot;https://mp.weixin.qq.com/s/lgKiloZ83TbB2iYaa-EX5g&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;如何寻找、安装和管理 AI Skill？&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><link>https://juejin.cn/post/7642171057679859775</link><guid isPermaLink="false">https://juejin.cn/post/7642171057679859775</guid><pubDate>Fri, 22 May 2026 00:36:14 GMT</pubDate><author>程序员小寒</author><category>人工智能</category><category>AI编程</category><category>Claude</category></item><item><title>AI Harness 企业级落地实践（一）</title><description>&lt;h2 data-id=&quot;heading-0&quot;&gt;一、前言&lt;/h2&gt;
&lt;p&gt;今年 AI 圈是非常躁动的，除了全民养龙虾，Harness 也在技术圈掀起了不小的波澜。&lt;/p&gt;
&lt;p&gt;与open claw不同的是，Harness 不是一个服务大众的产品。通俗来说，Harness 是将工程学的思维，落地成范式束缚于Agent上，让Agent能够更规范、更稳定的工作。&lt;/p&gt;
&lt;h4 data-id=&quot;heading-1&quot;&gt;Harness是什么？&lt;/h4&gt;
&lt;p&gt;想象一下在广袤的草原上，一群骏马飞快的驰骋着，它们就是 AI，有时候难免会跑偏。此时一位猛男，拿着马具跳到马背上，三下五除二就让骏马一直沿着正确的道路飞奔！&lt;/p&gt;
&lt;p&gt;这个马具就是 Harness！👉 套马的汉子，你威武雄壮~&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/fe431e0473974f6b8e24960f1c48b165~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgS2FybF93ZWk=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779956735&amp;amp;x-signature=InFhECepRskC%2BsGae8lt6JwAi74%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;关于Harness更具体的定义可以参考以下文献:&amp;nbsp;&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fopenai.com%2Fzh-Hans-CN%2Findex%2Fharness-engineering%2F&quot; target=&quot;_blank&quot; title=&quot;https://openai.com/zh-Hans-CN/index/harness-engineering/&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;OpenAI Harness 深度长文&lt;/a&gt;、&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzI2NDU4OTExOQ%3D%3D%26mid%3D2247695294%26idx%3D1%26sn%3D63a246504edde73b337f15ad72bed3b1%26chksm%3Deb3d6d799f4f8af600a467047daec90cafc55d6eb0c020d84cf42af4ff201a171b089c48ae9e%23rd&quot; target=&quot;_blank&quot; title=&quot;https://mp.weixin.qq.com/s?__biz=MzI2NDU4OTExOQ==&amp;amp;mid=2247695294&amp;amp;idx=1&amp;amp;sn=63a246504edde73b337f15ad72bed3b1&amp;amp;chksm=eb3d6d799f4f8af600a467047daec90cafc55d6eb0c020d84cf42af4ff201a171b089c48ae9e#rd&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;Harness Engineering即控制论&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;今天笔者的核心：详细拆解 Harness 工程的设计和落地&lt;/p&gt;
&lt;p&gt;同时，也会把这套实践开源，让每个开发者都能快速用上 Harness，&lt;strong&gt;解决“万事开头难”的哲学难题&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;快速、低成本给自己的项目加上Harness范式&lt;/li&gt;
&lt;li&gt;享受 openSpec +oh my xcode带来的高质量方案设计和代码交付&lt;/li&gt;
&lt;li&gt;轻易定制建设更适合自己团队的Harness项目工程&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;开源项目地址：&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2FWxqKb%2Fcow-harness&quot; target=&quot;_blank&quot; title=&quot;https://github.com/WxqKb/cow-harness&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;github.com/WxqKb/cow-h…&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;你的&amp;nbsp; &lt;strong&gt;[Star]&lt;/strong&gt; &amp;nbsp;将是我的核动力✨&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-id=&quot;heading-2&quot;&gt;二、基础软件工程理念&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Software Process Improvement（SPI）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;前面我们讲到，Harness 简单理解就是让AI 大模型能严格按照软件工程的体系，执行方案分析设计、代码开发、测试验证等流程，从而高效完整的完成工作。&lt;/p&gt;
&lt;p&gt;这次 Harness 的搭建，使用软件工程中一个比较标准的体系： &lt;strong&gt;《软件过程改进闭环》&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;立项决策 → 需求规划 → 评审规范 → 实施验证 →复盘改进&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在整个工程中，我们把复杂的需求拆解为以下环节，从而契合CMMI 与 敏捷Scrum 的迭代研发标准框架：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Decisions → Plans → Reviews → Specs → Verifications → Retros&lt;/p&gt;
&lt;/blockquote&gt;








































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;软件工程标准专业名词&lt;/th&gt;&lt;th&gt;所属体系&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;decisions&lt;/td&gt;&lt;td&gt;基线决策 / 变更决议 / 技术决策&lt;/td&gt;&lt;td&gt;CMMI、敏捷&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;plans&lt;/td&gt;&lt;td&gt;迭代规划 / 项目计划 / 里程碑计划&amp;nbsp;&lt;/td&gt;&lt;td&gt;敏捷Scrum、软件工程&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;specs&lt;/td&gt;&lt;td&gt;需求规格说明(SRS) / 技术规范 / 基线规范&lt;/td&gt;&lt;td&gt;软件工程、CMMI&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;reviews&lt;/td&gt;&lt;td&gt;同行评审 / 阶段评审 / 质量门禁评审&amp;nbsp;&lt;/td&gt;&lt;td&gt;CMMI、ISO软件工程&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;verifications&lt;/td&gt;&lt;td&gt;验证 Verification (V)&lt;/td&gt;&lt;td&gt;CMMI&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;retros&lt;/td&gt;&lt;td&gt;过程复盘 / 迭代回顾 / 流程改进回顾&lt;/td&gt;&lt;td&gt;Scrum、SPI&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 data-id=&quot;heading-3&quot;&gt;三、框架选型和落地&lt;/h2&gt;
&lt;h4 data-id=&quot;heading-4&quot;&gt;1. 技术选型&lt;/h4&gt;
&lt;p&gt;Harness 的搭建，需要把这些软件流程落成约束范式，把每一个环节都拆细，比如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;需求理解阶段：用头脑风暴（&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fwww.skills.sh%2Fobra%2Fsuperpowers%2Fbrainstorming&quot; target=&quot;_blank&quot; title=&quot;https://www.skills.sh/obra/superpowers/brainstorming&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;brainstorming&lt;/a&gt;）的模式，让AI 覆盖更多的边界场景思考出来&lt;/li&gt;
&lt;li&gt;技术方案设计：我们会用 superpower（&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fwww.skills.sh%2Fobra%2Fsuperpowers%2Fbrainstorming&quot; target=&quot;_blank&quot; title=&quot;https://www.skills.sh/obra/superpowers/brainstorming&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;brainstorming&lt;/a&gt;、&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fwww.skills.sh%2Fobra%2Fsuperpowers%2Fwriting-plans&quot; target=&quot;_blank&quot; title=&quot;https://www.skills.sh/obra/superpowers/writing-plans&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;writing-plans&lt;/a&gt;），通过不断的追问，从顶层设计、全栈链路、风险前置等维度，与研发人员进行确认，边界场景覆盖完整&lt;/li&gt;
&lt;li&gt;方案评审：严格的过程，指定 superpower 对应的技能，来进行智能评审，对方案进行评分。同时设定门禁，必须由研发人员同意才能继续往下实施&lt;/li&gt;
&lt;li&gt;任务实施：拆分完的 Task，我们通过 omx、&lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fwww.skills.sh%2Fobra%2Fsuperpowers%2Fusing-git-worktrees&quot; target=&quot;_blank&quot; title=&quot;https://www.skills.sh/obra/superpowers/using-git-worktrees&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;using-git-worktrees&lt;/a&gt;&amp;nbsp;进行编排。它会自动把具体的任务分配给合适的 Agent，达到更高效的编排和更完美的实施&lt;/li&gt;
&lt;li&gt;等等……&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-id=&quot;heading-5&quot;&gt;2. 脚手架设计&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-csharp&quot; lang=&quot;csharp&quot;&gt;cow-harness/
├── README.md                  
├── project.profile.md         &lt;span class=&quot;hljs-meta&quot;&gt;# AI 生成的项目基础信息画像&lt;/span&gt;
├── context-map.md             &lt;span class=&quot;hljs-meta&quot;&gt;# AI 生成的项目模块/上下文边界地图&lt;/span&gt;
├── project.verification.md    &lt;span class=&quot;hljs-meta&quot;&gt;# AI 生成的项目级验证规则&lt;/span&gt;
│
├── core/                      &lt;span class=&quot;hljs-meta&quot;&gt;# 通用 Harness 规则（核心约束）&lt;/span&gt;
│   ├── harness.md             &lt;span class=&quot;hljs-meta&quot;&gt;# Harness 核心理念与总体约束&lt;/span&gt;
│   ├── routing.md             &lt;span class=&quot;hljs-meta&quot;&gt;# 任务路由表与分发规则&lt;/span&gt;
│   ├── artifacts.md           &lt;span class=&quot;hljs-meta&quot;&gt;# 过程产物格式与存放规范&lt;/span&gt;
│   ├── verification.md        &lt;span class=&quot;hljs-meta&quot;&gt;# 验证门禁与完成标准&lt;/span&gt;
│   └── runbooks.md            &lt;span class=&quot;hljs-meta&quot;&gt;# 各类任务的标准操作手册&lt;/span&gt;
│
├── &lt;span class=&quot;hljs-keyword&quot;&gt;init&lt;/span&gt;/                      &lt;span class=&quot;hljs-meta&quot;&gt;# 新项目初始化&lt;/span&gt;
├── entrypoints/               &lt;span class=&quot;hljs-meta&quot;&gt;# AI 入口文件模板（CLAUDE.md 等）&lt;/span&gt;
├── adapters/                  &lt;span class=&quot;hljs-meta&quot;&gt;# 各编程工具适配模板（.cursor/ 等）&lt;/span&gt;
├── scripts/                   &lt;span class=&quot;hljs-meta&quot;&gt;# 内部脚本，初始化会调用&lt;/span&gt;
└── artifact-templates/        &lt;span class=&quot;hljs-meta&quot;&gt;# 过程产物模板&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;core层是核心的约束&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;routing 路由表会&lt;strong&gt;判定用户的任务属于 SPI 的哪个流程&lt;/strong&gt;，进而决定使用什么工具和流程
&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/36d2e2dfa0044a2caeed6192615037da~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgS2FybF93ZWk=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779956735&amp;amp;x-signature=ncW7pzjFmcEltx%2B8VqjpclJLFN8%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/li&gt;
&lt;li&gt;runBooks 执行手册会说明哪些环节使用什么技能
&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/a7a73db5e0324219a4c73d8bda949434~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgS2FybF93ZWk=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779956735&amp;amp;x-signature=Rr8R2DHPQa9Fmh0xweWSeNH55D0%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/li&gt;
&lt;li&gt;artifacts 会&lt;strong&gt;约束过程产物的规范&lt;/strong&gt;，并且沉淀成项目级别的知识库；&lt;/li&gt;
&lt;li&gt;verification 会规定验证和准入标准&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;init 层，&lt;strong&gt;支持一句话，让 AI 在你的项目中部署 Harness&lt;/strong&gt;，将工具适配层、入口文件等投射到你的项目根目录中。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;nbsp;&amp;nbsp;同时阅读你的项目，&lt;strong&gt;生成属于你项目的信息画像&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&amp;nbsp;&amp;nbsp;&lt;strong&gt;这一步非常重要，完成初始化后，你在让 AI Agent 工作的时候，自然就会按照Harness 的约束去执行任务了&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;entrypoints，&lt;strong&gt;AI 执行指令时是会先找到项目目录下的入口文件&lt;/strong&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;nbsp;&amp;nbsp;比如 gpt 会加载 AGENT.md，Claude 会加载 CLAUDE.md&lt;/li&gt;
&lt;li&gt;&amp;nbsp;&amp;nbsp;init 的时候，会把入口文件投射到项目中，重新启动 AI Agent，查看默认上下文，你就会发现对应的入口文件都被加载进去了&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/bdd58807822943e6912329bcf20b7673~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgS2FybF93ZWk=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779956735&amp;amp;x-signature=tQdiD7QHrnILmxRBtCdRwjAK7pQ%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;adapters：&lt;strong&gt;AI 编码工具的适配层&lt;/strong&gt;，需要指定主流工具严格进入入口文件，进入 Harness 约束&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/5e978e7b3e7144288590449510ecaae4~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgS2FybF93ZWk=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779956735&amp;amp;x-signature=Ec0%2FI05Cn%2B4r5PQl781nRWg1MTE%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;h4 data-id=&quot;heading-6&quot;&gt;3. 一些粗浅的设计理念&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Harness 其实也是&lt;strong&gt;软约束&lt;/strong&gt;，init 做好最基础的工作，达到可用状态&lt;/li&gt;
&lt;li&gt;文件投射到项目本地，最大的好处是**&lt;code&gt;你完全可以根据自己的实现，去修改 Harness 约束&lt;/code&gt;**&lt;/li&gt;
&lt;li&gt;没有提供 sdk、npm 包等接入方式，最直接把cow-harness 拷贝到你的项目中，自由度完全开放给开发者。我们希望，每个人都能深度参与到对 AI 的管控，直到成为你团队内完全可复用的 AI 规范&lt;/li&gt;
&lt;li&gt;长期来看，大模型的能力提升会弱化 Harness 的作用。但**&lt;code&gt;约束的设计思维，必然与时俱进&lt;/code&gt;**&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-id=&quot;heading-7&quot;&gt;四、接入步骤&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;项目拷贝&lt;br&gt;
把cow-harness 项目 fork/ download 下来，通过 git submodule 引导你的项目中（或者直接把cow-harness 文件夹放在项目中）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;阅读 README，执行 init，这一步 AI 会：&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;安装相关的 skills&lt;/li&gt;
&lt;li&gt;生成项目画像&lt;/li&gt;
&lt;li&gt;投射必要的文件到本地&lt;/li&gt;
&lt;li&gt;创建产物结构目录&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不要手工阅读和执行每一步，&lt;strong&gt;请务必相信 AI 比我们做的好&lt;/strong&gt;。直接把下面这段话发给 AI：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot; lang=&quot;bash&quot;&gt;请先读取 cow-harness/README.md 和 cow-harness/init/bootstrap.prompt.md。
这是一个新项目刚接入 Agent Harness，请按 Harness 初始化流程处理：
1. 从 cow-harness/entrypoints/ 投影根目录 AI 入口文件。
2. 从 cow-harness/adapters/ 投影工具适配目录。
3. 创建 .ai-runtime-artifacts/ 及其子目录。
4. 如需安装或检查 AI runtime，请先说明会修改哪些本机环境，然后由你执行 cow-harness/scripts/install-ai-skills.sh。
5. 读取 cow-harness/init/project-profiler.prompt.md。
6. 扫描当前项目，生成或更新 cow-harness/project.profile.md、cow-harness/context-map.md、cow-harness/project.verification.md。
7. 由你运行 cow-harness/scripts/harness-check.sh。
8. 汇总推断项、待确认项和验证结果。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;3.  开始执行任务&lt;br&gt;
重启 AI 终端，开启你的 cow-harness 之旅
&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/7cd9e7cab6f44635843607b3ea2d9f3c~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgS2FybF93ZWk=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779956735&amp;amp;x-signature=uO66YUrncQ2aKWBOhFjdiEvCh5w%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;h2 data-id=&quot;heading-8&quot;&gt;五、自我 QA 环节&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;接入之后，是不是所有任务都必然会走到 harness 约束中？&lt;br&gt;
答：理论上是的，但是我们会判断这个任务的量级，小任务会直接放行
&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/e715f6db9db442e4a7622fc15e780b29~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgS2FybF93ZWk=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779956735&amp;amp;x-signature=lBM5J6bskJeuOS8Qf5GPuOI%2BOfw%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;harness 的约束能否达到 100%？&lt;br&gt;
答：否！harness 也是软约束，你甚至可以理解成是 prompt 超集，在实践中我们正常的提问都可以命中，同时我们在产物中明确说明了推理过程中使用了那些技能&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;这个项目的目的是？&lt;br&gt;
答：核心只有一个：帮助部分同学解决 Harness “万事开头难”的问题。这是个非常简单的基础建设，你开始之后可以轻松随意植入自己想法，去约束 AI，加入新的技能包&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如何加自己的技能包？&lt;br&gt;
答：&lt;strong&gt;能用开源的尽量用开源的&lt;/strong&gt;，社区的 Star 和实践踩坑，能让你少走很多弯路。内部自定义的 Skills，请用 skills-create 这个官方技能包去创建&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果用了 Harness 还是不理想怎么办？&lt;br&gt;
答：如果有更好的，那么换了cow-harness。&lt;code&gt;这终归是一个软约束，模型能力的提升能让我们当下的约束被取代。&lt;/code&gt;然而往下探究，当 prompt 约束不够了，就需要干涉到更底层，比如 Agent 内部的编排逻辑，比如构建你公司项目的知识库，等等&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-id=&quot;heading-9&quot;&gt;六、下一步计划&lt;/h2&gt;
&lt;p&gt;在实践过程中，笔者会不断优化cow-harness的建设，核心目标是更向一人公司靠拢：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;方案输出更精准，接入类似 &lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2FFission-AI%2FOpenSpec%2F&quot; target=&quot;_blank&quot; title=&quot;https://github.com/Fission-AI/OpenSpec/&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;openspec&lt;/a&gt; 的优秀实践，让 specs 的设计更加完整&lt;/li&gt;
&lt;li&gt;构建更完整的软件研发全流程：产品 prd 解析、全栈开发流程、AI 测试、监控链路建设等等&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Harness 之后，也许我们会再往知识图谱、RAG 向量化、垂类模型训练、Agent 编排逻辑和执行拓扑等方向去学习，分享。&lt;/p&gt;</description><link>https://juejin.cn/post/7641912628643528738</link><guid isPermaLink="false">https://juejin.cn/post/7641912628643528738</guid><pubDate>Thu, 21 May 2026 07:43:06 GMT</pubDate><author>Karl_wei</author><category></category><category>AI编程</category><category>OpenAI</category><category>Agent</category></item><item><title>Claude Code Harness 工程：数仓侧落地方案｜得物技术</title><description>&lt;h2 data-id=&quot;heading-0&quot;&gt;一、AI Coding 现状与痛点：为什么需要 Harness&lt;/h2&gt;
&lt;h3 data-id=&quot;heading-1&quot;&gt;当前使用情况&lt;/h3&gt;
&lt;p&gt;得物离线数仓各小组已基本完成 AI Coding 工具的覆盖，主力工具为 Claude Code，辅以数据平台的 IDE 插件，应对重复性工作时效率提升明显。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-2&quot;&gt;核心痛点&lt;/h3&gt;
&lt;p&gt;尽管整体提效已显现，但团队在实际使用中暴露出三类结构性痛点。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;痛点一&lt;/strong&gt;：AI 不记得上下文约束，开发过程中反复&quot;失忆&quot;。会话开始时告知了&quot;金额字段单位是千元&quot;，对话进行到一半后 AI 忘了，生成的 SQL 把千元当元用，导致数据差了 1000 倍。这不是偶发问题，而是 Claude Code 的 context compact 机制（上下文压缩）的系统性限制：当对话 token 接近上限（约 95%）时，历史内容被自动压缩为摘要，临时口头说的约束全部丢失。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;痛点二&lt;/strong&gt;：规范执行不稳定，靠记忆兜底的部分最容易出问题。OneData 命名规范、注释三段式、INSERT 必须带 PARTITION 子句......这些规范大家都知道。在项目工期紧张时，人工规范遵守率降至 60%~70%，AI 靠 prompt 记忆的规范遵守率也只有 70%~80%。真正需要的是：把规范从&quot;LLM 记忆中的指导性内容&quot;变成&quot;每次执行时强制检查的护栏&quot;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;痛点三&lt;/strong&gt;：大型需求开发中，context 很快被撑满，越到后期 AI 越不可靠。复杂需求（大型宽表、大量下游血缘）的典型开发过程：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-objectivec&quot; lang=&quot;objectivec&quot;&gt;血缘查询结果（&lt;span class=&quot;hljs-number&quot;&gt;500&lt;/span&gt;~&lt;span class=&quot;hljs-number&quot;&gt;3000&lt;/span&gt; tokens） 自测 &lt;span class=&quot;hljs-number&quot;&gt;23&lt;/span&gt; 条 SQL 执行结果（&lt;span class=&quot;hljs-number&quot;&gt;5000&lt;/span&gt;~&lt;span class=&quot;hljs-number&quot;&gt;15000&lt;/span&gt; tokens） &lt;span class=&quot;hljs-built_in&quot;&gt;SKILL&lt;/span&gt; 规范文件内容（~&lt;span class=&quot;hljs-number&quot;&gt;10000&lt;/span&gt; tokens） 数据比对两表样本（大量行）= context 迅速膨胀 → compact 触发 → 关键约束遗忘 → AI 开始犯低级错误
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;核心矛盾：越是复杂的需求，越依赖 AI；但越复杂的需求，context 越容易撑满，AI 越容易&quot;失忆&quot;。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-3&quot;&gt;从&quot;随手问 AI&quot;到&quot;把能力封装起来&quot;&lt;/h3&gt;
&lt;p&gt;针对上述痛点，我们沿用了一条反复验证的结论：规范执行是人的短板、AI 的长板；业务判断是 AI 的短板、人的长板。Harness 工程的目标，就是把&quot;执行层&quot;的不稳定因素系统性地消掉：把规范写进 hooks，不再靠 AI 记忆，每次写 SQL 文件后自动触发检查；把迭代约束写进持久化文件，compact 后自动重新注入，不再靠临时口头说；把高 token 操作隔离到 subagent，主 context 只接收摘要，不被过程数据撑满。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-4&quot;&gt;二、先搞清楚&quot;Harness&quot;是什么&lt;/h2&gt;
&lt;p&gt;在 Claude Code 的 update-config skill 描述中有一句话：&quot;Automated behaviors require hooks configured in settings.json --- the harness executes these, not Claude&quot;。&lt;/p&gt;
&lt;p&gt;Harness = Claude Code 的宿主运行框架，即 Claude Code 客户端本身这个&quot;工具链容器&quot;。它：管理 context window 生命周期；在 LLM 推理循环之外确定性地执行 hooks；协调 subagents 的生命周期；不依赖模型判断，直接执行配置的自动化行为。区别总结：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/109ec8947c374029923ea8d5aa05f6bb~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6X54mp5oqA5pyv:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779934891&amp;amp;x-signature=HxnoSYIase0tFBQZv3E7FR7SSUE%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;h2 data-id=&quot;heading-5&quot;&gt;三、核心问题：compact 到底丢掉什么？&lt;/h2&gt;
&lt;p&gt;每次数仓开发 context 接近满时，auto-compact 触发（默认 95% 时触发），会把整个对话历史替换为一份摘要，token 缩减到原来的约 12%。哪些内容 compact 后丢失：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/ce870b7e788c4495ae68ceb72d110956~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6X54mp5oqA5pyv:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779934891&amp;amp;x-signature=9dyX7AN5mjFhyjT6IZT4zMIF3qg%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;数仓场景最痛的点：对话中说的&quot;这次用 OVERWRITE 模式&quot;、&quot;先忽略 field_a 字段&quot; → compact 后全忘；SKILL 文件读了一半，compact 后前几个 step 的内容没了 → Claude 重复询问；自测跑出来 50 行结果，加上血缘查询的几十行表结构 → context 很快膨胀到 compact 阈值。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-6&quot;&gt;四、五层防御体系（从简单到复杂）&lt;/h2&gt;
&lt;h3 data-id=&quot;heading-7&quot;&gt;第一层：写死进 CLAUDE.md（立即可用）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;机制&lt;/strong&gt;：项目根目录 .claude/CLAUDE.md 每次 compact 后从磁盘重新注入，是最可靠的持久化位置。将当前迭代的关键信息写入，格式建议：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-sql&quot; lang=&quot;sql&quot;&gt;# 当前迭代状态（每次迭代手动更新）## 正在开发&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt; 表：db_a.dws_table_a
 版本：V1&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt;
 node_id：&lt;span class=&quot;hljs-number&quot;&gt;1000000001&lt;/span&gt;
 状态：ETL开发阶段（Step &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;）

## 本次迭代约束&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt; 禁止修改：dwd_table_b（已上线，只读）
 分区字段：partition_dt（格式 yyyyMMdd，不是 dt）
 amount 字段单位：千元（不是元）

## 数仓全局规范
 建表：分区字段必须是 partition_dt string
 禁止：&lt;span class=&quot;hljs-keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;*&lt;/span&gt;，&lt;span class=&quot;hljs-keyword&quot;&gt;UPDATE&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;DELETE&lt;/span&gt; 无 &lt;span class=&quot;hljs-keyword&quot;&gt;WHERE&lt;/span&gt;
 金额字段用 &lt;span class=&quot;hljs-type&quot;&gt;DECIMAL&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;)，不用 &lt;span class=&quot;hljs-keyword&quot;&gt;DOUBLE&lt;/span&gt;
 &lt;span class=&quot;hljs-keyword&quot;&gt;INSERT&lt;/span&gt; 必须带 &lt;span class=&quot;hljs-keyword&quot;&gt;PARTITION&lt;/span&gt; 子句
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;操作规则&lt;/strong&gt;：进入新迭代时，更新&quot;正在开发&quot;和&quot;本次迭代约束&quot;两节；上线后清空&quot;本次迭代约束&quot;；全局规范长期保留，控制在 100 行以内。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-8&quot;&gt;第二层：Auto Memory 自动积累（已在运行）&lt;/h3&gt;
&lt;p&gt;机制：Claude 自动将跨会话发现写入 ~/.claude/projects//memory/MEMORY.md，每次 compact 后重新注入。数仓场景下主动触发 Claude 写记忆的时机：&quot;这张表的 amount 字段单位是千元，请记住&quot;；&quot;field_a 在特定场景下会为空，请记住这个踩坑&quot;；&quot;本次 V1.0 的关键变更是 field_b 逻辑调整，请记住&quot;。Claude 会自动写入 MEMORY.md，下次会话或 compact 后自动恢复。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-9&quot;&gt;第三层：hooks 自动验证（核心防御，解决&quot;忘了检查&quot;的问题）&lt;/h3&gt;
&lt;p&gt;这是解决&quot;每次写完 SQL 自动检查&quot;的关键机制。&lt;/p&gt;
&lt;h4 data-id=&quot;heading-10&quot;&gt;配置文件位置&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-markdown&quot; lang=&quot;markdown&quot;&gt;数仓项目根目录/
└── .claude/
&lt;span class=&quot;hljs-code&quot;&gt;    ├── settings.json          ← hooks 在这里配置
    ├── CLAUDE.md              ← 数仓规范上下文
    └── hooks/
        ├── validate_sql.sh          ← SQL 规范自动检查
        ├── block_dangerous_ddl.sh   ← 危险 DDL 拦截
        └── inject_context.sh        ← compact 后重注入上下文
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-id=&quot;heading-11&quot;&gt;settings.json 完整配置&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-swift&quot; lang=&quot;swift&quot;&gt;{&lt;span class=&quot;hljs-string&quot;&gt;&quot;hooks&quot;&lt;/span&gt;: {&lt;span class=&quot;hljs-string&quot;&gt;&quot;PostToolUse&quot;&lt;/span&gt;: [{&lt;span class=&quot;hljs-string&quot;&gt;&quot;matcher&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;Write|Edit&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;hooks&quot;&lt;/span&gt;: [{&lt;span class=&quot;hljs-string&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;command&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;command&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-subst&quot;&gt;\&quot;&lt;/span&gt;$CLAUDE_PROJECT_DIR&lt;span class=&quot;hljs-subst&quot;&gt;\&quot;&lt;/span&gt;/.claude/hooks/validate_sql.sh&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;timeout&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;60&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;statusMessage&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;检查 SQL 规范...&quot;&lt;/span&gt;}]}],&lt;span class=&quot;hljs-string&quot;&gt;&quot;PreToolUse&quot;&lt;/span&gt;: [{&lt;span class=&quot;hljs-string&quot;&gt;&quot;matcher&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;Bash&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;hooks&quot;&lt;/span&gt;: [{&lt;span class=&quot;hljs-string&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;command&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;command&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-subst&quot;&gt;\&quot;&lt;/span&gt;$CLAUDE_PROJECT_DIR&lt;span class=&quot;hljs-subst&quot;&gt;\&quot;&lt;/span&gt;/.claude/hooks/block_dangerous_ddl.sh&quot;&lt;/span&gt;}]}],&lt;span class=&quot;hljs-string&quot;&gt;&quot;SessionStart&quot;&lt;/span&gt;: [{&lt;span class=&quot;hljs-string&quot;&gt;&quot;matcher&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;compact&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;hooks&quot;&lt;/span&gt;: [{&lt;span class=&quot;hljs-string&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;command&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;command&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;cat &lt;span class=&quot;hljs-subst&quot;&gt;\&quot;&lt;/span&gt;$CLAUDE_PROJECT_DIR&lt;span class=&quot;hljs-subst&quot;&gt;\&quot;&lt;/span&gt;/.claude/context/dw_conventions.md&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;statusMessage&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;重注入数仓规范...&quot;&lt;/span&gt;}]}],&lt;span class=&quot;hljs-string&quot;&gt;&quot;Stop&quot;&lt;/span&gt;: [{&lt;span class=&quot;hljs-string&quot;&gt;&quot;hooks&quot;&lt;/span&gt;: [{&lt;span class=&quot;hljs-string&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;prompt&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;prompt&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;检查用户要求的所有任务是否都已完成。如果还有未完成项，返回提示但不要重新开始。检查 stop_hook_active 是否为 true，如是则直接 exit。&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;model&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;claude-haiku-4-5-20251001&quot;&lt;/span&gt;}]}]}}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-id=&quot;heading-12&quot;&gt;SQL 规范自动检查脚本&lt;/h4&gt;
&lt;p&gt;.claude/hooks/validate_sql.sh：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot; lang=&quot;bash&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;#!/bin/bash&lt;/span&gt;
INPUT=$(&lt;span class=&quot;hljs-built_in&quot;&gt;cat&lt;/span&gt;)
FILE_PATH=$(&lt;span class=&quot;hljs-built_in&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-variable&quot;&gt;$INPUT&lt;/span&gt;&quot;&lt;/span&gt; | python3 -c &lt;span class=&quot;hljs-string&quot;&gt;&quot;import sys,json; d=json.load(sys.stdin); print(d.get(&#39;tool_input&#39;,{}).get(&#39;file_path&#39;,&#39;&#39;))&quot;&lt;/span&gt; 2&amp;gt;/dev/null)

&lt;span class=&quot;hljs-comment&quot;&gt;# 只处理 .sql 文件&lt;/span&gt;
[[ &lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-variable&quot;&gt;$FILE_PATH&lt;/span&gt;&quot;&lt;/span&gt; != *.sql ]] &amp;amp;&amp;amp; &lt;span class=&quot;hljs-built_in&quot;&gt;exit&lt;/span&gt; 0
[[ -z &lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-variable&quot;&gt;$FILE_PATH&lt;/span&gt;&quot;&lt;/span&gt; ]] &amp;amp;&amp;amp; &lt;span class=&quot;hljs-built_in&quot;&gt;exit&lt;/span&gt; 0

SQL=$(&lt;span class=&quot;hljs-built_in&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-variable&quot;&gt;$FILE_PATH&lt;/span&gt;&quot;&lt;/span&gt; 2&amp;gt;/dev/null)
[[ -z &lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-variable&quot;&gt;$SQL&lt;/span&gt;&quot;&lt;/span&gt; ]] &amp;amp;&amp;amp; &lt;span class=&quot;hljs-built_in&quot;&gt;exit&lt;/span&gt; 0

ERRORS=()

&lt;span class=&quot;hljs-comment&quot;&gt;# 规范1：禁止 SELECT *echo &quot;$SQL&quot; | grep -iqE &#39;SELECT\s+\*&#39; &amp;amp;&amp;amp; ERRORS+=(&quot;CRITICAL: 发现 SELECT *，必须明确列名&quot;)&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# 规范2：INSERT 必须带 PARTITIONif echo &quot;$SQL&quot; | grep -iqE &#39;INSERT\s+(INTO|OVERWRITE)&#39;; thenecho &quot;$SQL&quot; | grep -iqE &#39;PARTITION\s*\(&#39; || ERRORS+=(&quot;CRITICAL: INSERT 缺少 PARTITION 子句&quot;)&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;fi&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 规范3：DOUBLE 类型金额echo &quot;$SQL&quot; | grep -iqE &#39;\bDOUBLE\b&#39; &amp;amp;&amp;amp; ERRORS+=(&quot;WARNING: 金额字段建议用 DECIMAL(20,4)，不用 DOUBLE&quot;)&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# 规范4：UPDATE/DELETE 必须有 WHEREif echo &quot;$SQL&quot; | grep -iqE &#39;\b(UPDATE|DELETE)\b&#39;; thenecho &quot;$SQL&quot; | grep -iqE &#39;\bWHERE\b&#39; || ERRORS+=(&quot;CRITICAL: UPDATE/DELETE 缺少 WHERE 条件&quot;)&lt;/span&gt;
fiif [ &lt;span class=&quot;hljs-variable&quot;&gt;${#ERRORS[@]}&lt;/span&gt; -gt 0 ]; thenecho &lt;span class=&quot;hljs-string&quot;&gt;&quot;=== SQL 规范检查失败：&lt;span class=&quot;hljs-variable&quot;&gt;$FILE_PATH&lt;/span&gt; ===&quot;&lt;/span&gt; &amp;gt;&amp;amp;2
  &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; err &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-variable&quot;&gt;${ERRORS[@]}&lt;/span&gt;&quot;&lt;/span&gt;; doecho &lt;span class=&quot;hljs-string&quot;&gt;&quot;  &lt;span class=&quot;hljs-variable&quot;&gt;$err&lt;/span&gt;&quot;&lt;/span&gt; &amp;gt;&amp;amp;2
  doneexit 2
fiecho &lt;span class=&quot;hljs-string&quot;&gt;&quot;SQL 规范检查通过: &lt;span class=&quot;hljs-subst&quot;&gt;$(basename $FILE_PATH)&lt;/span&gt;&quot;&lt;/span&gt; &amp;gt;&amp;amp;2
&lt;span class=&quot;hljs-built_in&quot;&gt;exit&lt;/span&gt; 0
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-id=&quot;heading-13&quot;&gt;危险 DDL 拦截脚本&lt;/h3&gt;
&lt;p&gt;.claude/hooks/block_dangerous_ddl.sh：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot; lang=&quot;bash&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;#!/bin/bash&lt;/span&gt;
INPUT=$(&lt;span class=&quot;hljs-built_in&quot;&gt;cat&lt;/span&gt;)
CMD=$(&lt;span class=&quot;hljs-built_in&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-variable&quot;&gt;$INPUT&lt;/span&gt;&quot;&lt;/span&gt; | python3 -c &lt;span class=&quot;hljs-string&quot;&gt;&quot;import sys,json; d=json.load(sys.stdin); print(d.get(&#39;tool_input&#39;,{}).get(&#39;command&#39;,&#39;&#39;))&quot;&lt;/span&gt; 2&amp;gt;/dev/null)

&lt;span class=&quot;hljs-comment&quot;&gt;# 拦截生产表 DROP/TRUNCATE（放行 _dev/_test/_stg 后缀）if echo &quot;$CMD&quot; | grep -iqE &#39;\b(DROP\s+TABLE|TRUNCATE\s+TABLE)\b&#39;; thenif ! echo &quot;$CMD&quot; | grep -qiE &#39;(_dev|_test|_stg)\b&#39;; thenecho &quot;BLOCKED: 检测到生产表 DROP/TRUNCATE 操作，请确认表名是否正确&quot; &amp;gt;&amp;amp;2&lt;/span&gt;
    &lt;span class=&quot;hljs-built_in&quot;&gt;exit&lt;/span&gt; 2
  fifiexit 0
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-id=&quot;heading-14&quot;&gt;hook 通信协议关键规则&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/712b4ce07bb14cae82281f926a91eb15~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6X54mp5oqA5pyv:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779934891&amp;amp;x-signature=MWQFQFrfwdeath8Q8VrfAk9UXmM%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;关键陷阱：阻断必须用 exit 2，用 exit 1 不会阻止 Claude 继续执行。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-15&quot;&gt;第四层：subagents 做上下文隔离（防 context 膨胀）&lt;/h3&gt;
&lt;p&gt;核心原则：把&quot;高 token 消耗但结果只需要摘要&quot;的操作放到 subagent 的独立 context 中执行。&lt;/p&gt;
&lt;p&gt;数仓场景适合下放 subagent 的操作&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/5a7b694691b04009b56eaa8758260e63~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6X54mp5oqA5pyv:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779934891&amp;amp;x-signature=TaWLqCQx1SCwXuqvp7%2BYnHvsZZY%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;h4 data-id=&quot;heading-16&quot;&gt;创建 subagent 文件&lt;/h4&gt;
&lt;p&gt;.claude/agents/sql-validator.md（SQL 语法验证）：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-yaml&quot; lang=&quot;yaml&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;sql-validator&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;description:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ODPS/MaxCompute&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;SQL&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;语法验证与规范检查专用&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;agent。当用户生成或修改&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;SQL&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;文件后需要验证时调用。在独立&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;运行，防止大量验证日志污染主对话。&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;tools:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Read,&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Bash,&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Grep,&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Glob&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;model:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;haiku&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;permissionMode:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;dontAsk&lt;/span&gt;
&lt;span class=&quot;hljs-meta&quot;&gt;---
&lt;/span&gt;
&lt;span class=&quot;hljs-string&quot;&gt;你是数仓&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;SQL&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;规范专家，只做验证，不修改文件。&lt;/span&gt;

&lt;span class=&quot;hljs-string&quot;&gt;验证项（按优先级）：&lt;/span&gt;
&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;禁止&lt;/span&gt;
&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;必须带&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;PARTITION&lt;/span&gt;
&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;字段用&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;snake_case&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;命名&lt;/span&gt;
&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;金额字段用&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;DECIMAL&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;不用&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;DOUBLE&lt;/span&gt;
&lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;多表&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;JOIN&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;必须有&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;条件&lt;/span&gt;
&lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;笛卡尔积风险检测&lt;/span&gt;

&lt;span class=&quot;hljs-string&quot;&gt;输出格式：&lt;/span&gt;
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;状态：PASS&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;FAIL&lt;/span&gt;
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;问题列表（CRITICAL&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;WARNING&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;INFO）&lt;/span&gt;
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;修改建议（具体到行号）&lt;/span&gt;

&lt;span class=&quot;hljs-string&quot;&gt;不超过&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;50&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;行，只返回结构化报告。&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;.claude/agents/dw-explorer.md（防止血缘查询撑爆主 context）：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-yaml&quot; lang=&quot;yaml&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;dw-explorer&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;description:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;数仓结构探索&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;agent。当需要大量读取表结构、DDL、字段信息、血缘关系时自动调用，避免大量文件内容污染主&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;context。只读，不修改任何文件。&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;tools:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Read,&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Glob,&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Grep,&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Bash&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;model:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;haiku&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;permissionMode:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;dontAsk&lt;/span&gt;
&lt;span class=&quot;hljs-meta&quot;&gt;---
&lt;/span&gt;
&lt;span class=&quot;hljs-string&quot;&gt;你是数仓探索专家，只读操作。&lt;/span&gt;

&lt;span class=&quot;hljs-string&quot;&gt;当被调用时：&lt;/span&gt;
&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;读取指定表的&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;DDL、字段信息、分区策略&lt;/span&gt;
&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;分析上下游血缘（一层）&lt;/span&gt;
&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;识别关键字段口径（金额、日期、状态类字段）&lt;/span&gt;

&lt;span class=&quot;hljs-string&quot;&gt;输出：不超过&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;行的结构化摘要，包含：&lt;/span&gt;
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;表基本信息（层级、粒度、分区策略）&lt;/span&gt;
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;核心字段定义（含口径说明）&lt;/span&gt;
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;上下游血缘（只列表名，不展开内容）&lt;/span&gt;
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;发现的特殊口径或踩坑点&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-id=&quot;heading-17&quot;&gt;使用方式&lt;/h4&gt;
&lt;p&gt;在主对话中自然触发：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-sql&quot; lang=&quot;sql&quot;&gt;用 dw&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt;explorer 分析 db_a.dwd_table_a 的结构

对刚生成的 insert_dws_table_a.sql 用 &lt;span class=&quot;hljs-keyword&quot;&gt;sql&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt;validator 验证
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或强制指定（避免 Claude 自行判断）：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-lua&quot; lang=&quot;lua&quot;&gt;@&lt;span class=&quot;hljs-string&quot;&gt;&quot;sql-validator (agent)&quot;&lt;/span&gt; 验证 &lt;span class=&quot;hljs-built_in&quot;&gt;path&lt;/span&gt;/to/&lt;span class=&quot;hljs-built_in&quot;&gt;insert&lt;/span&gt;.sql
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-id=&quot;heading-18&quot;&gt;第五层：SKILL 文件改造（减少 context 消耗）&lt;/h3&gt;
&lt;p&gt;当前的问题：每次调用 SKILL 文件（01~08.md），内容全部加载进主 context，加速 compact 触发。&lt;strong&gt;改造方向&lt;/strong&gt;：把 SKILL 文件的&quot;执行步骤&quot;提炼成 subagent 指令，subagent 内部读完整 SKILL 文件，主 context 只接收结果摘要；用 path-scoped rules 替代 SKILL 文件中的规范章节，按需加载：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-yaml&quot; lang=&quot;yaml&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;# .claude/rules/etl-rules.md&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;paths:&lt;/span&gt;
  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;**/*insert*.sql&quot;&lt;/span&gt;
  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;**/*_di.sql&quot;&lt;/span&gt;
  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;**/*_df.sql&quot;&lt;/span&gt;
&lt;span class=&quot;hljs-meta&quot;&gt;---
&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;# ETL 开发规范（按文件路径自动加载）&lt;/span&gt;
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;必须有&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;partition_dt&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;分区&lt;/span&gt;
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;OVERWRITE&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;前检查分区是否已存在&lt;/span&gt;
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;不允许跨库&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;JOIN&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;SKILL 文件保持现状，但改变调用方式：不要在主对话中直接触发，而是启动一个 subagent 来读 SKILL 文件执行 ETL，主对话只接收最终产出的 SQL 文件路径。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-19&quot;&gt;五、可行落地方案：数仓 Harness 架构&lt;/h2&gt;
&lt;p&gt;先让我们看一下整体的架构设计（整体架构图）：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/d5487158cdc44428b895bffb746c07ea~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6X54mp5oqA5pyv:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779934891&amp;amp;x-signature=7NePBZabEdZkdr6lLGwUTu3r8i0%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;这张架构图的核心逻辑是&lt;strong&gt;职责分层&lt;/strong&gt;：不同类型的工作交给最合适的机制去做，而不是全部压在 Claude 的推理循环里。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;持久化层&lt;/strong&gt;解决的是&quot;失忆&quot;问题，任何临时口头说的约束，compact 后都会消失；但写进 .claude/CLAUDE.md 的内容，每次会话启动和 compact 后都会从磁盘重新注入------这是整套方案里最简单也最可靠的一层。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Harness 层（Hooks）&lt;/strong&gt; 解决的是&quot;规范靠记忆&quot;的问题，PostToolUse hook 在每次写 .sql 文件后确定性触发，不依赖 Claude 有没有记住规范要求；违规时 exit 2 强制阻断，Claude 必须修正后才能继续，规范遵守率从 70%80% 提升到 95%+。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Subagent 层&lt;/strong&gt;解决的是&quot;context 被撑满&quot;的问题，血缘查询、23 项自测、数据比对这类操作会产生大量 token，放到独立 context 的 subagent 里执行，主会话只接收一份摘要，compact 触发频率预计降低 50%70%。&lt;/p&gt;
&lt;p&gt;三层机制分工明确，互不干扰：Hooks 处理&quot;写动作触发的规范检查&quot;，subagent 处理&quot;读操作的 context 隔离&quot;，CLAUDE.md 处理&quot;跨会话状态持久化&quot;。为了配合这套架构落地，数仓的研发流程可以拆解为 8 个大的步骤，流程图如下：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/7857d974748c4b6382a127ccf2ad1252~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6X54mp5oqA5pyv:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779934891&amp;amp;x-signature=ovSMzxkkZsHpO1A%2Bw3PMhquykUQ%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;从 Harness 架构的视角来看，8 个步骤可以按&quot;对 context 的影响&quot;分成两类：一类是&lt;strong&gt;直接在主会话处理&lt;/strong&gt; （内容量有限，context 压力低）：需求分析（读 PRD）、技术设计（写规范说明）、SR 导入（生成配置）、SLA/DQC（生成规则）。另一类&lt;strong&gt;必须通过 Harness 机制处理&lt;/strong&gt;（否则会加速 compact 或规范失控）：ETL 开发每次写 .sql 文件，PostToolUse hook 自动触发规范检查，不依赖人工提醒；自测时 23 条 SQL 的执行结果体量大，交给 data-quality-checker subagent 隔离，主会话只收 PASS/FAIL 摘要；数据比对时两表样本数据量大，交给 data-comparator subagent 隔离；性能优化时血缘 + 多层 DDL 每次 500~3000 tokens，交给 dw-explorer subagent 隔离。这种分工不是把步骤拆开独立执行，而是在同一个工作流里，让每个步骤以最合适的方式运行------context 压力小的步骤留在主会话保持流畅，context 压力大的步骤通过 subagent 隔离保持干净，规范检查通过 hook 自动执行不需要人工干预。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-20&quot;&gt;六、基于 SKILL 规范的数仓工作流设计&lt;/h2&gt;
&lt;p&gt;数仓 8 步 SKILL 规范（需求分析→技术设计→ETL→自测→数据比对→SR 导入→性能优化→SLA/DQC）天然对应 Harness 的三层机制。核心思路是：SKILL 文件不变，改变调用方式------主对话只读规范结论，实际执行由 subagent 或 hook 完成。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/6941dbd0f33d4fd8a58f169fe2087971~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6X54mp5oqA5pyv:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779934891&amp;amp;x-signature=AkVaX2vZB%2Fipq4kyhmkVeDwPZhY%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;h3 data-id=&quot;heading-21&quot;&gt;各步骤推荐提示词与工作流&lt;/h3&gt;
&lt;h4 data-id=&quot;heading-22&quot;&gt;Step 1：需求分析&lt;/h4&gt;
&lt;p&gt;推荐提示词：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-markdown&quot; lang=&quot;markdown&quot;&gt;用 dw-explorer subagent 先读取上游表结构（只返回摘要），
然后按需求分析规范生成：
&lt;span class=&quot;hljs-bullet&quot;&gt;1.&lt;/span&gt; 需求摘要（≤5行）
&lt;span class=&quot;hljs-bullet&quot;&gt;2.&lt;/span&gt; 表字段口径草稿
&lt;span class=&quot;hljs-bullet&quot;&gt;3.&lt;/span&gt; 待确认问题清单（按优先级排序）
需求文档 URL：[粘贴PRD链接]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hook 配合：SessionStart 注入当前迭代约束（版本号/表名/禁止修改的表）。&lt;/p&gt;
&lt;h4 data-id=&quot;heading-23&quot;&gt;Step 2：技术设计&lt;/h4&gt;
&lt;p&gt;推荐提示词：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-css&quot; lang=&quot;css&quot;&gt;基于上一步确认的需求，按 OneData 规范完成技术设计：
 表名：&lt;span class=&quot;hljs-selector-attr&quot;&gt;[按 层级_域_主题_粒度_周期 格式命名]&lt;/span&gt;
 粒度：&lt;span class=&quot;hljs-selector-attr&quot;&gt;[描述]&lt;/span&gt;
 分区：partition_dt string（格式 yyyyMMdd）
 禁止：任何与上游不一致的字段命名
输出 OneData 建模说明，不超过 &lt;span class=&quot;hljs-number&quot;&gt;60&lt;/span&gt; 行
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;CLAUDE.md 写入（设计完成后手动更新）：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-diff&quot; lang=&quot;diff&quot;&gt;## 当前迭代技术设计决策- 表名：db_a.dws_table_a
&lt;span class=&quot;hljs-deletion&quot;&gt;- 主键：order_no + partition_dt&lt;/span&gt;
&lt;span class=&quot;hljs-deletion&quot;&gt;- 特殊约束：amount 字段继承上游千元单位，不做转换&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-id=&quot;heading-24&quot;&gt;Step 3：ETL 开发&lt;/h4&gt;
&lt;p&gt;这是 Harness 工程价值最高的步骤，PostToolUse hook 在每次 SQL 文件保存时自动触发。&lt;/p&gt;
&lt;p&gt;推荐提示词：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-sql&quot; lang=&quot;sql&quot;&gt;按 ETL 开发规范生成建表 DDL &lt;span class=&quot;hljs-operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Insert&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;SQL&lt;/span&gt;：
&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt; 建表文件：ddl_[表名].&lt;span class=&quot;hljs-keyword&quot;&gt;sql&lt;/span&gt;
&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt; 插入文件：insert_[表名].&lt;span class=&quot;hljs-keyword&quot;&gt;sql&lt;/span&gt;
&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt; 要求：&lt;span class=&quot;hljs-keyword&quot;&gt;INSERT&lt;/span&gt; 用 OVERWRITE 模式，&lt;span class=&quot;hljs-keyword&quot;&gt;PARTITION&lt;/span&gt; 子句必须包含 partition_dt
&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt; 金额字段：&lt;span class=&quot;hljs-type&quot;&gt;DECIMAL&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;)，单位继承上游（千元）
生成完毕后，用 &lt;span class=&quot;hljs-keyword&quot;&gt;sql&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt;validator subagent 验证两个文件
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hook 自动执行（无需手动触发）：每次写入 .sql 文件 → PostToolUse hook 自动运行规范检查。若发现 SELECT * 或缺少 PARTITION → 返回 exit 2，Claude 收到错误自动修正。&lt;/p&gt;
&lt;h4 data-id=&quot;heading-25&quot;&gt;Step 4：自测&lt;/h4&gt;
&lt;p&gt;推荐提示词（防止自测结果撑爆主 context）：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-css&quot; lang=&quot;css&quot;&gt;用 data-quality-checker subagent 对 &lt;span class=&quot;hljs-selector-attr&quot;&gt;[表名]&lt;/span&gt; 执行 &lt;span class=&quot;hljs-number&quot;&gt;23&lt;/span&gt; 项标准自测，
bizdate = &lt;span class=&quot;hljs-selector-attr&quot;&gt;[日期]&lt;/span&gt;
补充口径约束：&lt;span class=&quot;hljs-selector-attr&quot;&gt;[如&lt;span class=&quot;hljs-string&quot;&gt;&quot;is_perform=1 只取履约订单&quot;&lt;/span&gt;]&lt;/span&gt;
只返回：PASS/FAIL 汇总 + FAIL 项详情（≤&lt;span class=&quot;hljs-number&quot;&gt;50&lt;/span&gt;行），不返回原始 SQL 执行结果
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;效果：23 条 SQL 的执行结果全在 subagent context 里，主对话只收到一份摘要报告。&lt;/p&gt;
&lt;h4 data-id=&quot;heading-26&quot;&gt;Step 5：数据比对&lt;/h4&gt;
&lt;p&gt;推荐提示词：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ini&quot; lang=&quot;ini&quot;&gt;用 data-comparator subagent 对比：
 新表：&lt;span class=&quot;hljs-section&quot;&gt;[新表名]&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;partition_dt&lt;/span&gt; = [日期]
 参考表：&lt;span class=&quot;hljs-section&quot;&gt;[旧表名/线上表]&lt;/span&gt;
 比对字段：&lt;span class=&quot;hljs-section&quot;&gt;[核心金额字段列表]&lt;/span&gt;
 容差：≤ 0.01%（金额类）
只返回：差异超过容差的字段列表 + 差值，不返回全量对比数据
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-id=&quot;heading-27&quot;&gt;Step 6：SR数据库导入&lt;/h4&gt;
&lt;p&gt;推荐提示词（自动生成最优数据库建表参数）：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-markdown&quot; lang=&quot;markdown&quot;&gt;用 dw-sr SKILL生成建表任务， 先查以下表的 DDL 和一层上下游血缘（只返回摘要）：
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 源表：[ODPS表名]
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 目标表：[SR表名]

然后基于 DDL 摘要，分析当前 SR 同步任务的配置风险：
&lt;span class=&quot;hljs-bullet&quot;&gt;1.&lt;/span&gt; 字段类型是否有精度丢失风险（DECIMAL/DOUBLE → DECIMAL(38,18)）
&lt;span class=&quot;hljs-bullet&quot;&gt;2.&lt;/span&gt; Key 字段选择是否合理（重复率是否过高导致 DUPLICATE KEY 膨胀）
&lt;span class=&quot;hljs-bullet&quot;&gt;3.&lt;/span&gt; 分区数量是否合理（partition&lt;span class=&quot;hljs-emphasis&quot;&gt;_live_&lt;/span&gt;number 与下游查询窗口是否匹配）
&lt;span class=&quot;hljs-bullet&quot;&gt;4.&lt;/span&gt; DISTRIBUTED BY HASH 的 bucket 数与数据量是否匹配
&lt;span class=&quot;hljs-bullet&quot;&gt;5.&lt;/span&gt; 是否有 DATETIME 字段在 SR 侧用了 VARCHAR 存储（会导致时间过滤走全表扫描）

输出同步任务配置建议（按风险高低排序），不超过 20 行。
每条格式：[风险等级 高/中/低] 问题描述 → 建议修改方式
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-id=&quot;heading-28&quot;&gt;Step 7：性能优化&lt;/h4&gt;
&lt;p&gt;推荐提示词（防止血缘查询撑爆主 context）：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-sql&quot; lang=&quot;sql&quot;&gt;用 dw&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt;explorer subagent 先查 [表名] 的一层上下游血缘和 DDL（只返回摘要），
然后分析当前 &lt;span class=&quot;hljs-keyword&quot;&gt;Insert&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;SQL&lt;/span&gt; 的性能瓶颈：
&lt;span class=&quot;hljs-number&quot;&gt;1.&lt;/span&gt; 是否有全表扫描
&lt;span class=&quot;hljs-number&quot;&gt;2.&lt;/span&gt; 是否有笛卡尔积风险
&lt;span class=&quot;hljs-number&quot;&gt;3.&lt;/span&gt; 是否可以用 MAP &lt;span class=&quot;hljs-keyword&quot;&gt;JOIN&lt;/span&gt; 替代 HASH &lt;span class=&quot;hljs-keyword&quot;&gt;JOIN&lt;/span&gt;
输出优化建议（按收益排序），不超过 &lt;span class=&quot;hljs-number&quot;&gt;30&lt;/span&gt; 行
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-id=&quot;heading-29&quot;&gt;Step 8：SLA/DQC&lt;/h4&gt;
&lt;p&gt;推荐提示词：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-css&quot; lang=&quot;css&quot;&gt;按 SLA/DQC 规范为 &lt;span class=&quot;hljs-selector-attr&quot;&gt;[表名]&lt;/span&gt; 生成 &lt;span class=&quot;hljs-number&quot;&gt;9&lt;/span&gt; 类 DQC 规则：
 完整性：主键非空、分区数据量
 准确性：核心金额字段与上游比对（容差 &lt;span class=&quot;hljs-number&quot;&gt;0.01%&lt;/span&gt;）
 一致性：is_perform 与 perform_flag 联动逻辑
 时效性：产出时间 SLA ≤ 次日 &lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;00&lt;/span&gt;
输出 DQC 配置 JSON，可直接使用
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-id=&quot;heading-30&quot;&gt;SKILL 调用方式改造（减少主 context 消耗）&lt;/h3&gt;
&lt;p&gt;当前问题：触发 SKILL 时，SKILL 文件全文（约 10KB）加载进主 context，加速 compact。改造方向：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/75b6d9298f5f4d3c927dfae0b37e9862~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6X54mp5oqA5pyv:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779934891&amp;amp;x-signature=zzUvhKgYbfmq5QO5GzUTcVMIG7w%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;核心原则：主对话只接收决策级信息（PASS/FAIL、差异字段、优化方案），不接收过程数据（SQL 执行结果、原始血缘列表、完整 DDL 内容）。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-31&quot;&gt;精准对话流设计：控制AI思考的艺术&lt;/h3&gt;
&lt;p&gt;文章中多次提到 /dw-etl、/dw-自测 等命令，这是数仓研发全流程 SKILL 套件的核心触发词，每个命令对应一个封装了规范、产出格式和工具调用的标准化执行单元。核心理念：把每次都要重复讲的要求写进 SKILL，把每次都怕忘的检查点写进 SKILL，把每次都需要的结构化输出也写进 SKILL------这样谁来做需求都行，底座是一致的。&lt;/p&gt;
&lt;h4 data-id=&quot;heading-32&quot;&gt;8 个 SKILL 命令一览&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/388a0580a14d43fca10ac8f009119f61~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6X54mp5oqA5pyv:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779934891&amp;amp;x-signature=jbeq2MEddExYjLxfReeOgNRv1%2Fs%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;以 /dw-etl 为例：一条命令封装了什么？ETL 开发（Step 3）是 Harness 工程价值最高的步骤，SKILL 文件内封装了：① 规范内容（写死，不靠记忆）：建表规范：分区字段必须是 partition_dt STRING（格式 YYYYMMDD）；金额字段：DECIMAL(26,4)，不用 DOUBLE；INSERT 模式：必须使用 INSERT OVERWRITE，必须带 PARTITION 子句；禁止：SELECT *、跨库 JOIN（非血缘关系）。② 产出格式（结构化，不走样）：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-sql&quot; lang=&quot;sql&quot;&gt;输出文件：
├── ddl_[表名].&lt;span class=&quot;hljs-keyword&quot;&gt;sql&lt;/span&gt;      ← ODPS 建表语句（含注释三段式、生命周期配置）
├── insert_[表名].&lt;span class=&quot;hljs-keyword&quot;&gt;sql&lt;/span&gt;   ← ODPS &lt;span class=&quot;hljs-keyword&quot;&gt;Insert&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;SQL&lt;/span&gt;（含分区裁剪、&lt;span class=&quot;hljs-keyword&quot;&gt;JOIN&lt;/span&gt; 规范）
└── ddl_sr_[表名].&lt;span class=&quot;hljs-keyword&quot;&gt;sql&lt;/span&gt;   ← SR 建表语句（Key 列顺序、&lt;span class=&quot;hljs-type&quot;&gt;DECIMAL&lt;/span&gt; 精度）
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;③ 自动护栏（Hook 配合）：每次 .sql 文件写入后，PostToolUse hook 自动执行 validate_sql.sh；发现 SELECT * 或缺少 PARTITION → exit 2 阻断，Claude 强制修正。④ subagent 卸载（防 context 膨胀）：&quot;生成完毕后，用 sql-validator subagent 验证两个文件&quot;；验证结果全在 subagent context 里，主对话只收到&quot;PASS/FAIL + 问题列表&quot;。综合效益数据：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/6b1673037a1f42a6bb4875aba7d58aa7~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6X54mp5oqA5pyv:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779934891&amp;amp;x-signature=7zV3sLzKM5%2FHdN6GpdEzSQXVkeo%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;h2 data-id=&quot;heading-33&quot;&gt;七、落地步骤&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;步骤一&lt;/strong&gt;：项目级上下文持久化。在数仓项目目录下创建 .claude/CLAUDE.md，写入当前迭代状态。每次新迭代开始时更新&quot;正在开发&quot;和&quot;本次迭代约束&quot;两节，上线后清空约束节。全局规范永久保留，控制在 100 行以内。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;步骤二&lt;/strong&gt;：配置 hooks 自动验证。创建 .claude/settings.json + hooks/ 目录，配置 PostToolUse hook（每次写 .sql 后自动规范检查）和 PreToolUse hook（拦截危险 DDL）。效果：不需要每次手动说&quot;帮我检查 SQL 规范&quot;，hook 在 Harness 层自动触发，不占用 Claude 推理资源。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;步骤三&lt;/strong&gt;：创建 subagents 隔离高 token 操作。创建三个核心 subagent 文件：sql-validator.md、dw-explorer.md、data-quality-checker.md。将 Step 4/5/7 的执行全部下放，预计主 context compact 频率降低 50%~70%。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-34&quot;&gt;八、Harness 工程能解决的核心问题&lt;/h2&gt;
&lt;p&gt;这一节是整个方案的出发点，也是对&quot;为什么要这么做&quot;的直接回答。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-35&quot;&gt;数仓 AI 开发当前的本质瓶颈：语义理解&lt;/h3&gt;
&lt;p&gt;在实际数仓 AI 开发中，技术能力不是瓶颈，语义理解才是。需求理解偏差占总返工的 40%～60%，大约 40%～50% 的工作时间花在理解需求和与业务核对口径上。精准血缘探查：准确率提升显著，远超传统方式。这两个观察揭示了同一个问题：AI 在数仓场景的不准确，根本原因不是&quot;不会写 SQL&quot;，而是&quot;不理解业务语义&quot;------不知道这张表的 amount 单位是千元还是元，不知道 is_perform=1 在这个版本里意味着什么，不知道某字段在特定场景下会为空。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-36&quot;&gt;语义 × 数据 = 准确率&lt;/h3&gt;
&lt;p&gt;数仓 AI 开发的准确率，可以用一个公式来理解：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;准确率 = 语义理解深度 × 数据规范覆盖度
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/34ae82922fb44d33bffcfe743ad0ee49~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6X54mp5oqA5pyv:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779934891&amp;amp;x-signature=QSEueslKE4%2FD5hEP8eyVVRqsJoo%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;结论：Harness 工程的本质，是把&quot;语义&quot;和&quot;规范&quot;从不可靠的 LLM 记忆中，迁移到确定性的 hooks + 持久化文件里，从而让 语义 × 规范 = 准确率 这个等式两边的变量都变得稳定。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-37&quot;&gt;具体能解决的四类问题&lt;/h3&gt;
&lt;h4 data-id=&quot;heading-38&quot;&gt;问题一：字段口径遗忘导致的计算错误&lt;/h4&gt;
&lt;p&gt;现状：对话开始时告知了&quot;amount 字段单位是千元&quot;，compact 后 Claude 忘了，生成的 SQL 把千元当元用，导致数据差 1000 倍。&lt;strong&gt;Harness 解法&lt;/strong&gt;：字段口径写进 .claude/CLAUDE.md（compact 后重新注入）；踩坑经验写进 Auto Memory（跨会话持久化）；结果：这类错误从&quot;时常发生&quot;降到&quot;基本不出现&quot;。&lt;/p&gt;
&lt;h4 data-id=&quot;heading-39&quot;&gt;问题二：需求理解偏差导致的返工&lt;/h4&gt;
&lt;p&gt;现状：需求文档描述的是&quot;用户视角的 GMV&quot;，但 AI 生成了&quot;交易视角的 GMV&quot;，两者口径不同，数据对不上，需要返工。&lt;strong&gt;Harness 解法&lt;/strong&gt;：需求分析的产出（口径草稿 + 待确认问题清单）写进 CLAUDE.md 的迭代约束节；Stop hook 检查任务完整性，确认待确认问题清单已全部明确后才放行；结果：需求一次交付通过率从约 50% 提升到 90%。&lt;/p&gt;
&lt;h4 data-id=&quot;heading-40&quot;&gt;问题三：SQL 规范执行不一致&lt;/h4&gt;
&lt;p&gt;现状：规范文档写了&quot;INSERT 必须带 PARTITION&quot;，但 Claude 有时会忘，或在 compact 后规范内容被清除后生成不合规的 SQL。&lt;strong&gt;Harness 解法&lt;/strong&gt;：PostToolUse hook 在每次写 .sql 文件后自动执行规范检查，不依赖 Claude 记忆；违规时 exit 2 返回错误，Claude 强制修正后才能继续；结果：规范执行率从&quot;依赖 LLM 记忆的 70%~80%&quot;提升到&quot;hook 强制的 95%+&quot;。&lt;/p&gt;
&lt;h4 data-id=&quot;heading-41&quot;&gt;问题四：大型需求开发中的 context 耗尽&lt;/h4&gt;
&lt;p&gt;现状：复杂需求（大型宽表、大量下游血缘）开发过程中，血缘查询 + 自测结果 + SKILL 文件内容堆满 context，compact 触发后丢失关键约束，Claude 开始犯低级错误。&lt;strong&gt;Harness 解法&lt;/strong&gt;：血缘查询 → dw-explorer subagent（独立 context，只返回摘要）；23 项自测 → data-quality-checker subagent（独立 context，只返回 PASS/FAIL 报告）；SKILL 文件内容 → subagent 内部读取，主 context 只接收产出的 SQL 文件路径；结果：主 context compact 频率预计降低 50%~70%。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-42&quot;&gt;与传统数仓 AI 开发方式的对比&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/4813c7ef8b6b47a1bcb3b78c2703af6c~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6X54mp5oqA5pyv:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779934891&amp;amp;x-signature=05kGQTxmWM7R3jTh760QH8gJrNE%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;h3 data-id=&quot;heading-43&quot;&gt;从&quot;AI 帮我写代码&quot;到&quot;AI 嵌入研发流水线&quot;&lt;/h3&gt;
&lt;p&gt;Harness 工程的最终目标，不是让 Claude 更聪明，而是让整个研发流水线更可靠。Claude（LLM）负责：理解需求、设计方案、生成代码------这些需要语义理解的事；Harness（hooks）负责：规范检查、危险拦截、任务完整性验证------这些需要确定性执行的事；Subagents 负责：大量文件读取、血缘查询、自测执行------这些会消耗大量 context 的事；CLAUDE.md + Memory 负责：字段口径、迭代约束、踩坑经验------这些需要跨会话持久化的事。这四层分工，让数仓 AI 开发从&quot;对话驱动的一次性辅助&quot;升级为&quot;规则嵌入的流水线自动化&quot;。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-44&quot;&gt;往期回顾&lt;/h2&gt;
&lt;p&gt;1.[BP Claw 破解 AI 编码输入难题 ------FlinkSpec 需求智能化实践｜得物技术](# 一、AI Coding 现状与痛点：为什么需要 Harness&lt;/p&gt;
&lt;h3 data-id=&quot;heading-45&quot;&gt;当前使用情况&lt;/h3&gt;
&lt;p&gt;得物离线数仓各小组已基本完成 AI Coding 工具的覆盖，主力工具为 Claude Code，辅以数据平台的 IDE 插件，应对重复性工作时效率提升明显。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-46&quot;&gt;核心痛点&lt;/h3&gt;
&lt;p&gt;尽管整体提效已显现，但团队在实际使用中暴露出三类结构性痛点。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;痛点一&lt;/strong&gt;：AI 不记得上下文约束，开发过程中反复&quot;失忆&quot;。会话开始时告知了&quot;金额字段单位是千元&quot;，对话进行到一半后 AI 忘了，生成的 SQL 把千元当元用，导致数据差了 1000 倍。这不是偶发问题，而是 Claude Code 的 context compact 机制（上下文压缩）的系统性限制：当对话 token 接近上限（约 95%）时，历史内容被自动压缩为摘要，临时口头说的约束全部丢失。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;痛点二&lt;/strong&gt;：规范执行不稳定，靠记忆兜底的部分最容易出问题。OneData 命名规范、注释三段式、INSERT 必须带 PARTITION 子句......这些规范大家都知道。在项目工期紧张时，人工规范遵守率降至 60%~70%，AI 靠 prompt 记忆的规范遵守率也只有 70%~80%。真正需要的是：把规范从&quot;LLM 记忆中的指导性内容&quot;变成&quot;每次执行时强制检查的护栏&quot;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;痛点三&lt;/strong&gt;：大型需求开发中，context 很快被撑满，越到后期 AI 越不可靠。复杂需求（大型宽表、大量下游血缘）的典型开发过程：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-objectivec&quot; lang=&quot;objectivec&quot;&gt;血缘查询结果（&lt;span class=&quot;hljs-number&quot;&gt;500&lt;/span&gt;~&lt;span class=&quot;hljs-number&quot;&gt;3000&lt;/span&gt; tokens） 自测 &lt;span class=&quot;hljs-number&quot;&gt;23&lt;/span&gt; 条 SQL 执行结果（&lt;span class=&quot;hljs-number&quot;&gt;5000&lt;/span&gt;~&lt;span class=&quot;hljs-number&quot;&gt;15000&lt;/span&gt; tokens） &lt;span class=&quot;hljs-built_in&quot;&gt;SKILL&lt;/span&gt; 规范文件内容（~&lt;span class=&quot;hljs-number&quot;&gt;10000&lt;/span&gt; tokens） 数据比对两表样本（大量行）= context 迅速膨胀 → compact 触发 → 关键约束遗忘 → AI 开始犯低级错误
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;核心矛盾：越是复杂的需求，越依赖 AI；但越复杂的需求，context 越容易撑满，AI 越容易&quot;失忆&quot;。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-47&quot;&gt;从&quot;随手问 AI&quot;到&quot;把能力封装起来&quot;&lt;/h3&gt;
&lt;p&gt;针对上述痛点，我们沿用了一条反复验证的结论：规范执行是人的短板、AI 的长板；业务判断是 AI 的短板、人的长板。Harness 工程的目标，就是把&quot;执行层&quot;的不稳定因素系统性地消掉：把规范写进 hooks，不再靠 AI 记忆，每次写 SQL 文件后自动触发检查；把迭代约束写进持久化文件，compact 后自动重新注入，不再靠临时口头说；把高 token 操作隔离到 subagent，主 context 只接收摘要，不被过程数据撑满。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-48&quot;&gt;二、先搞清楚&quot;Harness&quot;是什么&lt;/h2&gt;
&lt;p&gt;在 Claude Code 的 update-config skill 描述中有一句话：&quot;Automated behaviors require hooks configured in settings.json --- the harness executes these, not Claude&quot;。&lt;/p&gt;
&lt;p&gt;Harness = Claude Code 的宿主运行框架，即 Claude Code 客户端本身这个&quot;工具链容器&quot;。它：管理 context window 生命周期；在 LLM 推理循环之外确定性地执行 hooks；协调 subagents 的生命周期；不依赖模型判断，直接执行配置的自动化行为。区别总结：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/109ec8947c374029923ea8d5aa05f6bb~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6X54mp5oqA5pyv:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779934891&amp;amp;x-signature=HxnoSYIase0tFBQZv3E7FR7SSUE%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;h2 data-id=&quot;heading-49&quot;&gt;三、核心问题：compact 到底丢掉什么？&lt;/h2&gt;
&lt;p&gt;每次数仓开发 context 接近满时，auto-compact 触发（默认 95% 时触发），会把整个对话历史替换为一份摘要，token 缩减到原来的约 12%。哪些内容 compact 后丢失：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/ce870b7e788c4495ae68ceb72d110956~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6X54mp5oqA5pyv:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779934891&amp;amp;x-signature=9dyX7AN5mjFhyjT6IZT4zMIF3qg%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;数仓场景最痛的点：对话中说的&quot;这次用 OVERWRITE 模式&quot;、&quot;先忽略 field_a 字段&quot; → compact 后全忘；SKILL 文件读了一半，compact 后前几个 step 的内容没了 → Claude 重复询问；自测跑出来 50 行结果，加上血缘查询的几十行表结构 → context 很快膨胀到 compact 阈值。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-50&quot;&gt;四、五层防御体系（从简单到复杂）&lt;/h2&gt;
&lt;h3 data-id=&quot;heading-51&quot;&gt;第一层：写死进 CLAUDE.md（立即可用）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;机制&lt;/strong&gt;：项目根目录 .claude/CLAUDE.md 每次 compact 后从磁盘重新注入，是最可靠的持久化位置。将当前迭代的关键信息写入，格式建议：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-sql&quot; lang=&quot;sql&quot;&gt;# 当前迭代状态（每次迭代手动更新）## 正在开发&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt; 表：db_a.dws_table_a
 版本：V1&lt;span class=&quot;hljs-number&quot;&gt;.0&lt;/span&gt;
 node_id：&lt;span class=&quot;hljs-number&quot;&gt;1000000001&lt;/span&gt;
 状态：ETL开发阶段（Step &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;）

## 本次迭代约束&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt; 禁止修改：dwd_table_b（已上线，只读）
 分区字段：partition_dt（格式 yyyyMMdd，不是 dt）
 amount 字段单位：千元（不是元）

## 数仓全局规范
 建表：分区字段必须是 partition_dt string
 禁止：&lt;span class=&quot;hljs-keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;*&lt;/span&gt;，&lt;span class=&quot;hljs-keyword&quot;&gt;UPDATE&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;DELETE&lt;/span&gt; 无 &lt;span class=&quot;hljs-keyword&quot;&gt;WHERE&lt;/span&gt;
 金额字段用 &lt;span class=&quot;hljs-type&quot;&gt;DECIMAL&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;)，不用 &lt;span class=&quot;hljs-keyword&quot;&gt;DOUBLE&lt;/span&gt;
 &lt;span class=&quot;hljs-keyword&quot;&gt;INSERT&lt;/span&gt; 必须带 &lt;span class=&quot;hljs-keyword&quot;&gt;PARTITION&lt;/span&gt; 子句
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;操作规则&lt;/strong&gt;：进入新迭代时，更新&quot;正在开发&quot;和&quot;本次迭代约束&quot;两节；上线后清空&quot;本次迭代约束&quot;；全局规范长期保留，控制在 100 行以内。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-52&quot;&gt;第二层：Auto Memory 自动积累（已在运行）&lt;/h3&gt;
&lt;p&gt;机制：Claude 自动将跨会话发现写入 ~/.claude/projects//memory/MEMORY.md，每次 compact 后重新注入。数仓场景下主动触发 Claude 写记忆的时机：&quot;这张表的 amount 字段单位是千元，请记住&quot;；&quot;field_a 在特定场景下会为空，请记住这个踩坑&quot;；&quot;本次 V1.0 的关键变更是 field_b 逻辑调整，请记住&quot;。Claude 会自动写入 MEMORY.md，下次会话或 compact 后自动恢复。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-53&quot;&gt;第三层：hooks 自动验证（核心防御，解决&quot;忘了检查&quot;的问题）&lt;/h3&gt;
&lt;p&gt;这是解决&quot;每次写完 SQL 自动检查&quot;的关键机制。&lt;/p&gt;
&lt;h4 data-id=&quot;heading-54&quot;&gt;配置文件位置&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-markdown&quot; lang=&quot;markdown&quot;&gt;数仓项目根目录/
└── .claude/
&lt;span class=&quot;hljs-code&quot;&gt;    ├── settings.json          ← hooks 在这里配置
    ├── CLAUDE.md              ← 数仓规范上下文
    └── hooks/
        ├── validate_sql.sh          ← SQL 规范自动检查
        ├── block_dangerous_ddl.sh   ← 危险 DDL 拦截
        └── inject_context.sh        ← compact 后重注入上下文
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-id=&quot;heading-55&quot;&gt;settings.json 完整配置&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-swift&quot; lang=&quot;swift&quot;&gt;{&lt;span class=&quot;hljs-string&quot;&gt;&quot;hooks&quot;&lt;/span&gt;: {&lt;span class=&quot;hljs-string&quot;&gt;&quot;PostToolUse&quot;&lt;/span&gt;: [{&lt;span class=&quot;hljs-string&quot;&gt;&quot;matcher&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;Write|Edit&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;hooks&quot;&lt;/span&gt;: [{&lt;span class=&quot;hljs-string&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;command&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;command&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-subst&quot;&gt;\&quot;&lt;/span&gt;$CLAUDE_PROJECT_DIR&lt;span class=&quot;hljs-subst&quot;&gt;\&quot;&lt;/span&gt;/.claude/hooks/validate_sql.sh&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;timeout&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-number&quot;&gt;60&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;statusMessage&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;检查 SQL 规范...&quot;&lt;/span&gt;}]}],&lt;span class=&quot;hljs-string&quot;&gt;&quot;PreToolUse&quot;&lt;/span&gt;: [{&lt;span class=&quot;hljs-string&quot;&gt;&quot;matcher&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;Bash&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;hooks&quot;&lt;/span&gt;: [{&lt;span class=&quot;hljs-string&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;command&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;command&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-subst&quot;&gt;\&quot;&lt;/span&gt;$CLAUDE_PROJECT_DIR&lt;span class=&quot;hljs-subst&quot;&gt;\&quot;&lt;/span&gt;/.claude/hooks/block_dangerous_ddl.sh&quot;&lt;/span&gt;}]}],&lt;span class=&quot;hljs-string&quot;&gt;&quot;SessionStart&quot;&lt;/span&gt;: [{&lt;span class=&quot;hljs-string&quot;&gt;&quot;matcher&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;compact&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;hooks&quot;&lt;/span&gt;: [{&lt;span class=&quot;hljs-string&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;command&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;command&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;cat &lt;span class=&quot;hljs-subst&quot;&gt;\&quot;&lt;/span&gt;$CLAUDE_PROJECT_DIR&lt;span class=&quot;hljs-subst&quot;&gt;\&quot;&lt;/span&gt;/.claude/context/dw_conventions.md&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;statusMessage&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;重注入数仓规范...&quot;&lt;/span&gt;}]}],&lt;span class=&quot;hljs-string&quot;&gt;&quot;Stop&quot;&lt;/span&gt;: [{&lt;span class=&quot;hljs-string&quot;&gt;&quot;hooks&quot;&lt;/span&gt;: [{&lt;span class=&quot;hljs-string&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;prompt&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;prompt&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;检查用户要求的所有任务是否都已完成。如果还有未完成项，返回提示但不要重新开始。检查 stop_hook_active 是否为 true，如是则直接 exit。&quot;&lt;/span&gt;,&lt;span class=&quot;hljs-string&quot;&gt;&quot;model&quot;&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&quot;claude-haiku-4-5-20251001&quot;&lt;/span&gt;}]}]}}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-id=&quot;heading-56&quot;&gt;SQL 规范自动检查脚本&lt;/h4&gt;
&lt;p&gt;.claude/hooks/validate_sql.sh：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot; lang=&quot;bash&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;#!/bin/bash&lt;/span&gt;
INPUT=$(&lt;span class=&quot;hljs-built_in&quot;&gt;cat&lt;/span&gt;)
FILE_PATH=$(&lt;span class=&quot;hljs-built_in&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-variable&quot;&gt;$INPUT&lt;/span&gt;&quot;&lt;/span&gt; | python3 -c &lt;span class=&quot;hljs-string&quot;&gt;&quot;import sys,json; d=json.load(sys.stdin); print(d.get(&#39;tool_input&#39;,{}).get(&#39;file_path&#39;,&#39;&#39;))&quot;&lt;/span&gt; 2&amp;gt;/dev/null)

&lt;span class=&quot;hljs-comment&quot;&gt;# 只处理 .sql 文件&lt;/span&gt;
[[ &lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-variable&quot;&gt;$FILE_PATH&lt;/span&gt;&quot;&lt;/span&gt; != *.sql ]] &amp;amp;&amp;amp; &lt;span class=&quot;hljs-built_in&quot;&gt;exit&lt;/span&gt; 0
[[ -z &lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-variable&quot;&gt;$FILE_PATH&lt;/span&gt;&quot;&lt;/span&gt; ]] &amp;amp;&amp;amp; &lt;span class=&quot;hljs-built_in&quot;&gt;exit&lt;/span&gt; 0

SQL=$(&lt;span class=&quot;hljs-built_in&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-variable&quot;&gt;$FILE_PATH&lt;/span&gt;&quot;&lt;/span&gt; 2&amp;gt;/dev/null)
[[ -z &lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-variable&quot;&gt;$SQL&lt;/span&gt;&quot;&lt;/span&gt; ]] &amp;amp;&amp;amp; &lt;span class=&quot;hljs-built_in&quot;&gt;exit&lt;/span&gt; 0

ERRORS=()

&lt;span class=&quot;hljs-comment&quot;&gt;# 规范1：禁止 SELECT *echo &quot;$SQL&quot; | grep -iqE &#39;SELECT\s+\*&#39; &amp;amp;&amp;amp; ERRORS+=(&quot;CRITICAL: 发现 SELECT *，必须明确列名&quot;)&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# 规范2：INSERT 必须带 PARTITIONif echo &quot;$SQL&quot; | grep -iqE &#39;INSERT\s+(INTO|OVERWRITE)&#39;; thenecho &quot;$SQL&quot; | grep -iqE &#39;PARTITION\s*\(&#39; || ERRORS+=(&quot;CRITICAL: INSERT 缺少 PARTITION 子句&quot;)&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;fi&lt;/span&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 规范3：DOUBLE 类型金额echo &quot;$SQL&quot; | grep -iqE &#39;\bDOUBLE\b&#39; &amp;amp;&amp;amp; ERRORS+=(&quot;WARNING: 金额字段建议用 DECIMAL(20,4)，不用 DOUBLE&quot;)&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# 规范4：UPDATE/DELETE 必须有 WHEREif echo &quot;$SQL&quot; | grep -iqE &#39;\b(UPDATE|DELETE)\b&#39;; thenecho &quot;$SQL&quot; | grep -iqE &#39;\bWHERE\b&#39; || ERRORS+=(&quot;CRITICAL: UPDATE/DELETE 缺少 WHERE 条件&quot;)&lt;/span&gt;
fiif [ &lt;span class=&quot;hljs-variable&quot;&gt;${#ERRORS[@]}&lt;/span&gt; -gt 0 ]; thenecho &lt;span class=&quot;hljs-string&quot;&gt;&quot;=== SQL 规范检查失败：&lt;span class=&quot;hljs-variable&quot;&gt;$FILE_PATH&lt;/span&gt; ===&quot;&lt;/span&gt; &amp;gt;&amp;amp;2
  &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; err &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-variable&quot;&gt;${ERRORS[@]}&lt;/span&gt;&quot;&lt;/span&gt;; doecho &lt;span class=&quot;hljs-string&quot;&gt;&quot;  &lt;span class=&quot;hljs-variable&quot;&gt;$err&lt;/span&gt;&quot;&lt;/span&gt; &amp;gt;&amp;amp;2
  doneexit 2
fiecho &lt;span class=&quot;hljs-string&quot;&gt;&quot;SQL 规范检查通过: &lt;span class=&quot;hljs-subst&quot;&gt;$(basename $FILE_PATH)&lt;/span&gt;&quot;&lt;/span&gt; &amp;gt;&amp;amp;2
&lt;span class=&quot;hljs-built_in&quot;&gt;exit&lt;/span&gt; 0
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-id=&quot;heading-57&quot;&gt;危险 DDL 拦截脚本&lt;/h3&gt;
&lt;p&gt;.claude/hooks/block_dangerous_ddl.sh：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-bash&quot; lang=&quot;bash&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;#!/bin/bash&lt;/span&gt;
INPUT=$(&lt;span class=&quot;hljs-built_in&quot;&gt;cat&lt;/span&gt;)
CMD=$(&lt;span class=&quot;hljs-built_in&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;&quot;&lt;span class=&quot;hljs-variable&quot;&gt;$INPUT&lt;/span&gt;&quot;&lt;/span&gt; | python3 -c &lt;span class=&quot;hljs-string&quot;&gt;&quot;import sys,json; d=json.load(sys.stdin); print(d.get(&#39;tool_input&#39;,{}).get(&#39;command&#39;,&#39;&#39;))&quot;&lt;/span&gt; 2&amp;gt;/dev/null)

&lt;span class=&quot;hljs-comment&quot;&gt;# 拦截生产表 DROP/TRUNCATE（放行 _dev/_test/_stg 后缀）if echo &quot;$CMD&quot; | grep -iqE &#39;\b(DROP\s+TABLE|TRUNCATE\s+TABLE)\b&#39;; thenif ! echo &quot;$CMD&quot; | grep -qiE &#39;(_dev|_test|_stg)\b&#39;; thenecho &quot;BLOCKED: 检测到生产表 DROP/TRUNCATE 操作，请确认表名是否正确&quot; &amp;gt;&amp;amp;2&lt;/span&gt;
    &lt;span class=&quot;hljs-built_in&quot;&gt;exit&lt;/span&gt; 2
  fifiexit 0
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-id=&quot;heading-58&quot;&gt;hook 通信协议关键规则&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/712b4ce07bb14cae82281f926a91eb15~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6X54mp5oqA5pyv:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779934891&amp;amp;x-signature=MWQFQFrfwdeath8Q8VrfAk9UXmM%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;关键陷阱：阻断必须用 exit 2，用 exit 1 不会阻止 Claude 继续执行。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-59&quot;&gt;第四层：subagents 做上下文隔离（防 context 膨胀）&lt;/h3&gt;
&lt;p&gt;核心原则：把&quot;高 token 消耗但结果只需要摘要&quot;的操作放到 subagent 的独立 context 中执行。&lt;/p&gt;
&lt;p&gt;数仓场景适合下放 subagent 的操作&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/5a7b694691b04009b56eaa8758260e63~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6X54mp5oqA5pyv:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779934891&amp;amp;x-signature=TaWLqCQx1SCwXuqvp7%2BYnHvsZZY%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;h4 data-id=&quot;heading-60&quot;&gt;创建 subagent 文件&lt;/h4&gt;
&lt;p&gt;.claude/agents/sql-validator.md（SQL 语法验证）：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-yaml&quot; lang=&quot;yaml&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;sql-validator&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;description:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ODPS/MaxCompute&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;SQL&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;语法验证与规范检查专用&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;agent。当用户生成或修改&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;SQL&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;文件后需要验证时调用。在独立&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;运行，防止大量验证日志污染主对话。&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;tools:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Read,&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Bash,&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Grep,&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Glob&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;model:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;haiku&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;permissionMode:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;dontAsk&lt;/span&gt;
&lt;span class=&quot;hljs-meta&quot;&gt;---
&lt;/span&gt;
&lt;span class=&quot;hljs-string&quot;&gt;你是数仓&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;SQL&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;规范专家，只做验证，不修改文件。&lt;/span&gt;

&lt;span class=&quot;hljs-string&quot;&gt;验证项（按优先级）：&lt;/span&gt;
&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;禁止&lt;/span&gt;
&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;必须带&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;PARTITION&lt;/span&gt;
&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;字段用&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;snake_case&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;命名&lt;/span&gt;
&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;金额字段用&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;DECIMAL&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;不用&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;DOUBLE&lt;/span&gt;
&lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;多表&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;JOIN&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;必须有&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;条件&lt;/span&gt;
&lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;笛卡尔积风险检测&lt;/span&gt;

&lt;span class=&quot;hljs-string&quot;&gt;输出格式：&lt;/span&gt;
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;状态：PASS&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;FAIL&lt;/span&gt;
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;问题列表（CRITICAL&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;WARNING&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;INFO）&lt;/span&gt;
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;修改建议（具体到行号）&lt;/span&gt;

&lt;span class=&quot;hljs-string&quot;&gt;不超过&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;50&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;行，只返回结构化报告。&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;.claude/agents/dw-explorer.md（防止血缘查询撑爆主 context）：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-yaml&quot; lang=&quot;yaml&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;dw-explorer&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;description:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;数仓结构探索&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;agent。当需要大量读取表结构、DDL、字段信息、血缘关系时自动调用，避免大量文件内容污染主&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;context。只读，不修改任何文件。&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;tools:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Read,&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Glob,&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Grep,&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;Bash&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;model:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;haiku&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;permissionMode:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;dontAsk&lt;/span&gt;
&lt;span class=&quot;hljs-meta&quot;&gt;---
&lt;/span&gt;
&lt;span class=&quot;hljs-string&quot;&gt;你是数仓探索专家，只读操作。&lt;/span&gt;

&lt;span class=&quot;hljs-string&quot;&gt;当被调用时：&lt;/span&gt;
&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;读取指定表的&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;DDL、字段信息、分区策略&lt;/span&gt;
&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;分析上下游血缘（一层）&lt;/span&gt;
&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;识别关键字段口径（金额、日期、状态类字段）&lt;/span&gt;

&lt;span class=&quot;hljs-string&quot;&gt;输出：不超过&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;行的结构化摘要，包含：&lt;/span&gt;
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;表基本信息（层级、粒度、分区策略）&lt;/span&gt;
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;核心字段定义（含口径说明）&lt;/span&gt;
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;上下游血缘（只列表名，不展开内容）&lt;/span&gt;
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;发现的特殊口径或踩坑点&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-id=&quot;heading-61&quot;&gt;使用方式&lt;/h4&gt;
&lt;p&gt;在主对话中自然触发：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-sql&quot; lang=&quot;sql&quot;&gt;用 dw&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt;explorer 分析 db_a.dwd_table_a 的结构

对刚生成的 insert_dws_table_a.sql 用 &lt;span class=&quot;hljs-keyword&quot;&gt;sql&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt;validator 验证
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或强制指定（避免 Claude 自行判断）：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-lua&quot; lang=&quot;lua&quot;&gt;@&lt;span class=&quot;hljs-string&quot;&gt;&quot;sql-validator (agent)&quot;&lt;/span&gt; 验证 &lt;span class=&quot;hljs-built_in&quot;&gt;path&lt;/span&gt;/to/&lt;span class=&quot;hljs-built_in&quot;&gt;insert&lt;/span&gt;.sql
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-id=&quot;heading-62&quot;&gt;第五层：SKILL 文件改造（减少 context 消耗）&lt;/h3&gt;
&lt;p&gt;当前的问题：每次调用 SKILL 文件（01~08.md），内容全部加载进主 context，加速 compact 触发。&lt;strong&gt;改造方向&lt;/strong&gt;：把 SKILL 文件的&quot;执行步骤&quot;提炼成 subagent 指令，subagent 内部读完整 SKILL 文件，主 context 只接收结果摘要；用 path-scoped rules 替代 SKILL 文件中的规范章节，按需加载：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-yaml&quot; lang=&quot;yaml&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;# .claude/rules/etl-rules.md&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;paths:&lt;/span&gt;
  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;**/*insert*.sql&quot;&lt;/span&gt;
  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;**/*_di.sql&quot;&lt;/span&gt;
  &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&quot;**/*_df.sql&quot;&lt;/span&gt;
&lt;span class=&quot;hljs-meta&quot;&gt;---
&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;# ETL 开发规范（按文件路径自动加载）&lt;/span&gt;
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;必须有&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;partition_dt&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;分区&lt;/span&gt;
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;OVERWRITE&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;前检查分区是否已存在&lt;/span&gt;
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;不允许跨库&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;JOIN&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;SKILL 文件保持现状，但改变调用方式：不要在主对话中直接触发，而是启动一个 subagent 来读 SKILL 文件执行 ETL，主对话只接收最终产出的 SQL 文件路径。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-63&quot;&gt;五、可行落地方案：数仓 Harness 架构&lt;/h2&gt;
&lt;p&gt;先让我们看一下整体的架构设计（整体架构图）：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/d5487158cdc44428b895bffb746c07ea~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6X54mp5oqA5pyv:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779934891&amp;amp;x-signature=7NePBZabEdZkdr6lLGwUTu3r8i0%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;这张架构图的核心逻辑是&lt;strong&gt;职责分层&lt;/strong&gt;：不同类型的工作交给最合适的机制去做，而不是全部压在 Claude 的推理循环里。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;持久化层&lt;/strong&gt;解决的是&quot;失忆&quot;问题，任何临时口头说的约束，compact 后都会消失；但写进 .claude/CLAUDE.md 的内容，每次会话启动和 compact 后都会从磁盘重新注入------这是整套方案里最简单也最可靠的一层。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Harness 层（Hooks）&lt;/strong&gt; 解决的是&quot;规范靠记忆&quot;的问题，PostToolUse hook 在每次写 .sql 文件后确定性触发，不依赖 Claude 有没有记住规范要求；违规时 exit 2 强制阻断，Claude 必须修正后才能继续，规范遵守率从 70%80% 提升到 95%+。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Subagent 层&lt;/strong&gt;解决的是&quot;context 被撑满&quot;的问题，血缘查询、23 项自测、数据比对这类操作会产生大量 token，放到独立 context 的 subagent 里执行，主会话只接收一份摘要，compact 触发频率预计降低 50%70%。&lt;/p&gt;
&lt;p&gt;三层机制分工明确，互不干扰：Hooks 处理&quot;写动作触发的规范检查&quot;，subagent 处理&quot;读操作的 context 隔离&quot;，CLAUDE.md 处理&quot;跨会话状态持久化&quot;。为了配合这套架构落地，数仓的研发流程可以拆解为 8 个大的步骤，流程图如下：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/7857d974748c4b6382a127ccf2ad1252~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6X54mp5oqA5pyv:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779934891&amp;amp;x-signature=ovSMzxkkZsHpO1A%2Bw3PMhquykUQ%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;从 Harness 架构的视角来看，8 个步骤可以按&quot;对 context 的影响&quot;分成两类：一类是&lt;strong&gt;直接在主会话处理&lt;/strong&gt; （内容量有限，context 压力低）：需求分析（读 PRD）、技术设计（写规范说明）、SR 导入（生成配置）、SLA/DQC（生成规则）。另一类&lt;strong&gt;必须通过 Harness 机制处理&lt;/strong&gt;（否则会加速 compact 或规范失控）：ETL 开发每次写 .sql 文件，PostToolUse hook 自动触发规范检查，不依赖人工提醒；自测时 23 条 SQL 的执行结果体量大，交给 data-quality-checker subagent 隔离，主会话只收 PASS/FAIL 摘要；数据比对时两表样本数据量大，交给 data-comparator subagent 隔离；性能优化时血缘 + 多层 DDL 每次 500~3000 tokens，交给 dw-explorer subagent 隔离。这种分工不是把步骤拆开独立执行，而是在同一个工作流里，让每个步骤以最合适的方式运行------context 压力小的步骤留在主会话保持流畅，context 压力大的步骤通过 subagent 隔离保持干净，规范检查通过 hook 自动执行不需要人工干预。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-64&quot;&gt;六、基于 SKILL 规范的数仓工作流设计&lt;/h2&gt;
&lt;p&gt;数仓 8 步 SKILL 规范（需求分析→技术设计→ETL→自测→数据比对→SR 导入→性能优化→SLA/DQC）天然对应 Harness 的三层机制。核心思路是：SKILL 文件不变，改变调用方式------主对话只读规范结论，实际执行由 subagent 或 hook 完成。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/6941dbd0f33d4fd8a58f169fe2087971~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6X54mp5oqA5pyv:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779934891&amp;amp;x-signature=AkVaX2vZB%2Fipq4kyhmkVeDwPZhY%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;h3 data-id=&quot;heading-65&quot;&gt;各步骤推荐提示词与工作流&lt;/h3&gt;
&lt;h4 data-id=&quot;heading-66&quot;&gt;Step 1：需求分析&lt;/h4&gt;
&lt;p&gt;推荐提示词：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-markdown&quot; lang=&quot;markdown&quot;&gt;用 dw-explorer subagent 先读取上游表结构（只返回摘要），
然后按需求分析规范生成：
&lt;span class=&quot;hljs-bullet&quot;&gt;1.&lt;/span&gt; 需求摘要（≤5行）
&lt;span class=&quot;hljs-bullet&quot;&gt;2.&lt;/span&gt; 表字段口径草稿
&lt;span class=&quot;hljs-bullet&quot;&gt;3.&lt;/span&gt; 待确认问题清单（按优先级排序）
需求文档 URL：[粘贴PRD链接]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hook 配合：SessionStart 注入当前迭代约束（版本号/表名/禁止修改的表）。&lt;/p&gt;
&lt;h4 data-id=&quot;heading-67&quot;&gt;Step 2：技术设计&lt;/h4&gt;
&lt;p&gt;推荐提示词：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-css&quot; lang=&quot;css&quot;&gt;基于上一步确认的需求，按 OneData 规范完成技术设计：
 表名：&lt;span class=&quot;hljs-selector-attr&quot;&gt;[按 层级_域_主题_粒度_周期 格式命名]&lt;/span&gt;
 粒度：&lt;span class=&quot;hljs-selector-attr&quot;&gt;[描述]&lt;/span&gt;
 分区：partition_dt string（格式 yyyyMMdd）
 禁止：任何与上游不一致的字段命名
输出 OneData 建模说明，不超过 &lt;span class=&quot;hljs-number&quot;&gt;60&lt;/span&gt; 行
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;CLAUDE.md 写入（设计完成后手动更新）：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-diff&quot; lang=&quot;diff&quot;&gt;## 当前迭代技术设计决策- 表名：db_a.dws_table_a
&lt;span class=&quot;hljs-deletion&quot;&gt;- 主键：order_no + partition_dt&lt;/span&gt;
&lt;span class=&quot;hljs-deletion&quot;&gt;- 特殊约束：amount 字段继承上游千元单位，不做转换&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-id=&quot;heading-68&quot;&gt;Step 3：ETL 开发&lt;/h4&gt;
&lt;p&gt;这是 Harness 工程价值最高的步骤，PostToolUse hook 在每次 SQL 文件保存时自动触发。&lt;/p&gt;
&lt;p&gt;推荐提示词：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-sql&quot; lang=&quot;sql&quot;&gt;按 ETL 开发规范生成建表 DDL &lt;span class=&quot;hljs-operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;Insert&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;SQL&lt;/span&gt;：
&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt; 建表文件：ddl_[表名].&lt;span class=&quot;hljs-keyword&quot;&gt;sql&lt;/span&gt;
&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt; 插入文件：insert_[表名].&lt;span class=&quot;hljs-keyword&quot;&gt;sql&lt;/span&gt;
&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt; 要求：&lt;span class=&quot;hljs-keyword&quot;&gt;INSERT&lt;/span&gt; 用 OVERWRITE 模式，&lt;span class=&quot;hljs-keyword&quot;&gt;PARTITION&lt;/span&gt; 子句必须包含 partition_dt
&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt; 金额字段：&lt;span class=&quot;hljs-type&quot;&gt;DECIMAL&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;,&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;)，单位继承上游（千元）
生成完毕后，用 &lt;span class=&quot;hljs-keyword&quot;&gt;sql&lt;/span&gt;&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt;validator subagent 验证两个文件
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hook 自动执行（无需手动触发）：每次写入 .sql 文件 → PostToolUse hook 自动运行规范检查。若发现 SELECT * 或缺少 PARTITION → 返回 exit 2，Claude 收到错误自动修正。&lt;/p&gt;
&lt;h4 data-id=&quot;heading-69&quot;&gt;Step 4：自测&lt;/h4&gt;
&lt;p&gt;推荐提示词（防止自测结果撑爆主 context）：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-css&quot; lang=&quot;css&quot;&gt;用 data-quality-checker subagent 对 &lt;span class=&quot;hljs-selector-attr&quot;&gt;[表名]&lt;/span&gt; 执行 &lt;span class=&quot;hljs-number&quot;&gt;23&lt;/span&gt; 项标准自测，
bizdate = &lt;span class=&quot;hljs-selector-attr&quot;&gt;[日期]&lt;/span&gt;
补充口径约束：&lt;span class=&quot;hljs-selector-attr&quot;&gt;[如&lt;span class=&quot;hljs-string&quot;&gt;&quot;is_perform=1 只取履约订单&quot;&lt;/span&gt;]&lt;/span&gt;
只返回：PASS/FAIL 汇总 + FAIL 项详情（≤&lt;span class=&quot;hljs-number&quot;&gt;50&lt;/span&gt;行），不返回原始 SQL 执行结果
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;效果：23 条 SQL 的执行结果全在 subagent context 里，主对话只收到一份摘要报告。&lt;/p&gt;
&lt;h4 data-id=&quot;heading-70&quot;&gt;Step 5：数据比对&lt;/h4&gt;
&lt;p&gt;推荐提示词：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ini&quot; lang=&quot;ini&quot;&gt;用 data-comparator subagent 对比：
 新表：&lt;span class=&quot;hljs-section&quot;&gt;[新表名]&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;partition_dt&lt;/span&gt; = [日期]
 参考表：&lt;span class=&quot;hljs-section&quot;&gt;[旧表名/线上表]&lt;/span&gt;
 比对字段：&lt;span class=&quot;hljs-section&quot;&gt;[核心金额字段列表]&lt;/span&gt;
 容差：≤ 0.01%（金额类）
只返回：差异超过容差的字段列表 + 差值，不返回全量对比数据
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-id=&quot;heading-71&quot;&gt;Step 6：SR数据库导入&lt;/h4&gt;
&lt;p&gt;推荐提示词（自动生成最优数据库建表参数）：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-markdown&quot; lang=&quot;markdown&quot;&gt;用 dw-sr SKILL生成建表任务， 先查以下表的 DDL 和一层上下游血缘（只返回摘要）：
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 源表：[ODPS表名]
&lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; 目标表：[SR表名]

然后基于 DDL 摘要，分析当前 SR 同步任务的配置风险：
&lt;span class=&quot;hljs-bullet&quot;&gt;1.&lt;/span&gt; 字段类型是否有精度丢失风险（DECIMAL/DOUBLE → DECIMAL(38,18)）
&lt;span class=&quot;hljs-bullet&quot;&gt;2.&lt;/span&gt; Key 字段选择是否合理（重复率是否过高导致 DUPLICATE KEY 膨胀）
&lt;span class=&quot;hljs-bullet&quot;&gt;3.&lt;/span&gt; 分区数量是否合理（partition&lt;span class=&quot;hljs-emphasis&quot;&gt;_live_&lt;/span&gt;number 与下游查询窗口是否匹配）
&lt;span class=&quot;hljs-bullet&quot;&gt;4.&lt;/span&gt; DISTRIBUTED BY HASH 的 bucket 数与数据量是否匹配
&lt;span class=&quot;hljs-bullet&quot;&gt;5.&lt;/span&gt; 是否有 DATETIME 字段在 SR 侧用了 VARCHAR 存储（会导致时间过滤走全表扫描）

输出同步任务配置建议（按风险高低排序），不超过 20 行。
每条格式：[风险等级 高/中/低] 问题描述 → 建议修改方式
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-id=&quot;heading-72&quot;&gt;Step 7：性能优化&lt;/h4&gt;
&lt;p&gt;推荐提示词（防止血缘查询撑爆主 context）：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-sql&quot; lang=&quot;sql&quot;&gt;用 dw&lt;span class=&quot;hljs-operator&quot;&gt;-&lt;/span&gt;explorer subagent 先查 [表名] 的一层上下游血缘和 DDL（只返回摘要），
然后分析当前 &lt;span class=&quot;hljs-keyword&quot;&gt;Insert&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;SQL&lt;/span&gt; 的性能瓶颈：
&lt;span class=&quot;hljs-number&quot;&gt;1.&lt;/span&gt; 是否有全表扫描
&lt;span class=&quot;hljs-number&quot;&gt;2.&lt;/span&gt; 是否有笛卡尔积风险
&lt;span class=&quot;hljs-number&quot;&gt;3.&lt;/span&gt; 是否可以用 MAP &lt;span class=&quot;hljs-keyword&quot;&gt;JOIN&lt;/span&gt; 替代 HASH &lt;span class=&quot;hljs-keyword&quot;&gt;JOIN&lt;/span&gt;
输出优化建议（按收益排序），不超过 &lt;span class=&quot;hljs-number&quot;&gt;30&lt;/span&gt; 行
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-id=&quot;heading-73&quot;&gt;Step 8：SLA/DQC&lt;/h4&gt;
&lt;p&gt;推荐提示词：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-css&quot; lang=&quot;css&quot;&gt;按 SLA/DQC 规范为 &lt;span class=&quot;hljs-selector-attr&quot;&gt;[表名]&lt;/span&gt; 生成 &lt;span class=&quot;hljs-number&quot;&gt;9&lt;/span&gt; 类 DQC 规则：
 完整性：主键非空、分区数据量
 准确性：核心金额字段与上游比对（容差 &lt;span class=&quot;hljs-number&quot;&gt;0.01%&lt;/span&gt;）
 一致性：is_perform 与 perform_flag 联动逻辑
 时效性：产出时间 SLA ≤ 次日 &lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;:&lt;span class=&quot;hljs-number&quot;&gt;00&lt;/span&gt;
输出 DQC 配置 JSON，可直接使用
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-id=&quot;heading-74&quot;&gt;SKILL 调用方式改造（减少主 context 消耗）&lt;/h3&gt;
&lt;p&gt;当前问题：触发 SKILL 时，SKILL 文件全文（约 10KB）加载进主 context，加速 compact。改造方向：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/75b6d9298f5f4d3c927dfae0b37e9862~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6X54mp5oqA5pyv:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779934891&amp;amp;x-signature=zzUvhKgYbfmq5QO5GzUTcVMIG7w%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;核心原则：主对话只接收决策级信息（PASS/FAIL、差异字段、优化方案），不接收过程数据（SQL 执行结果、原始血缘列表、完整 DDL 内容）。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-75&quot;&gt;精准对话流设计：控制AI思考的艺术&lt;/h3&gt;
&lt;p&gt;文章中多次提到 /dw-etl、/dw-自测 等命令，这是数仓研发全流程 SKILL 套件的核心触发词，每个命令对应一个封装了规范、产出格式和工具调用的标准化执行单元。核心理念：把每次都要重复讲的要求写进 SKILL，把每次都怕忘的检查点写进 SKILL，把每次都需要的结构化输出也写进 SKILL------这样谁来做需求都行，底座是一致的。&lt;/p&gt;
&lt;h4 data-id=&quot;heading-76&quot;&gt;8 个 SKILL 命令一览&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/388a0580a14d43fca10ac8f009119f61~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6X54mp5oqA5pyv:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779934891&amp;amp;x-signature=jbeq2MEddExYjLxfReeOgNRv1%2Fs%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;以 /dw-etl 为例：一条命令封装了什么？ETL 开发（Step 3）是 Harness 工程价值最高的步骤，SKILL 文件内封装了：① 规范内容（写死，不靠记忆）：建表规范：分区字段必须是 partition_dt STRING（格式 YYYYMMDD）；金额字段：DECIMAL(26,4)，不用 DOUBLE；INSERT 模式：必须使用 INSERT OVERWRITE，必须带 PARTITION 子句；禁止：SELECT *、跨库 JOIN（非血缘关系）。② 产出格式（结构化，不走样）：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-sql&quot; lang=&quot;sql&quot;&gt;输出文件：
├── ddl_[表名].&lt;span class=&quot;hljs-keyword&quot;&gt;sql&lt;/span&gt;      ← ODPS 建表语句（含注释三段式、生命周期配置）
├── insert_[表名].&lt;span class=&quot;hljs-keyword&quot;&gt;sql&lt;/span&gt;   ← ODPS &lt;span class=&quot;hljs-keyword&quot;&gt;Insert&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;SQL&lt;/span&gt;（含分区裁剪、&lt;span class=&quot;hljs-keyword&quot;&gt;JOIN&lt;/span&gt; 规范）
└── ddl_sr_[表名].&lt;span class=&quot;hljs-keyword&quot;&gt;sql&lt;/span&gt;   ← SR 建表语句（Key 列顺序、&lt;span class=&quot;hljs-type&quot;&gt;DECIMAL&lt;/span&gt; 精度）
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;③ 自动护栏（Hook 配合）：每次 .sql 文件写入后，PostToolUse hook 自动执行 validate_sql.sh；发现 SELECT * 或缺少 PARTITION → exit 2 阻断，Claude 强制修正。④ subagent 卸载（防 context 膨胀）：&quot;生成完毕后，用 sql-validator subagent 验证两个文件&quot;；验证结果全在 subagent context 里，主对话只收到&quot;PASS/FAIL + 问题列表&quot;。综合效益数据：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/6b1673037a1f42a6bb4875aba7d58aa7~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6X54mp5oqA5pyv:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779934891&amp;amp;x-signature=7zV3sLzKM5%2FHdN6GpdEzSQXVkeo%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;h2 data-id=&quot;heading-77&quot;&gt;七、落地步骤&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;步骤一&lt;/strong&gt;：项目级上下文持久化。在数仓项目目录下创建 .claude/CLAUDE.md，写入当前迭代状态。每次新迭代开始时更新&quot;正在开发&quot;和&quot;本次迭代约束&quot;两节，上线后清空约束节。全局规范永久保留，控制在 100 行以内。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;步骤二&lt;/strong&gt;：配置 hooks 自动验证。创建 .claude/settings.json + hooks/ 目录，配置 PostToolUse hook（每次写 .sql 后自动规范检查）和 PreToolUse hook（拦截危险 DDL）。效果：不需要每次手动说&quot;帮我检查 SQL 规范&quot;，hook 在 Harness 层自动触发，不占用 Claude 推理资源。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;步骤三&lt;/strong&gt;：创建 subagents 隔离高 token 操作。创建三个核心 subagent 文件：sql-validator.md、dw-explorer.md、data-quality-checker.md。将 Step 4/5/7 的执行全部下放，预计主 context compact 频率降低 50%~70%。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-78&quot;&gt;八、Harness 工程能解决的核心问题&lt;/h2&gt;
&lt;p&gt;这一节是整个方案的出发点，也是对&quot;为什么要这么做&quot;的直接回答。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-79&quot;&gt;数仓 AI 开发当前的本质瓶颈：语义理解&lt;/h3&gt;
&lt;p&gt;在实际数仓 AI 开发中，技术能力不是瓶颈，语义理解才是。需求理解偏差占总返工的 40%～60%，大约 40%～50% 的工作时间花在理解需求和与业务核对口径上。精准血缘探查：准确率提升显著，远超传统方式。这两个观察揭示了同一个问题：AI 在数仓场景的不准确，根本原因不是&quot;不会写 SQL&quot;，而是&quot;不理解业务语义&quot;------不知道这张表的 amount 单位是千元还是元，不知道 is_perform=1 在这个版本里意味着什么，不知道某字段在特定场景下会为空。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-80&quot;&gt;语义 × 数据 = 准确率&lt;/h3&gt;
&lt;p&gt;数仓 AI 开发的准确率，可以用一个公式来理解：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;准确率 = 语义理解深度 × 数据规范覆盖度
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/34ae82922fb44d33bffcfe743ad0ee49~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6X54mp5oqA5pyv:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779934891&amp;amp;x-signature=QSEueslKE4%2FD5hEP8eyVVRqsJoo%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;结论：Harness 工程的本质，是把&quot;语义&quot;和&quot;规范&quot;从不可靠的 LLM 记忆中，迁移到确定性的 hooks + 持久化文件里，从而让 语义 × 规范 = 准确率 这个等式两边的变量都变得稳定。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-81&quot;&gt;具体能解决的四类问题&lt;/h3&gt;
&lt;h4 data-id=&quot;heading-82&quot;&gt;问题一：字段口径遗忘导致的计算错误&lt;/h4&gt;
&lt;p&gt;现状：对话开始时告知了&quot;amount 字段单位是千元&quot;，compact 后 Claude 忘了，生成的 SQL 把千元当元用，导致数据差 1000 倍。&lt;strong&gt;Harness 解法&lt;/strong&gt;：字段口径写进 .claude/CLAUDE.md（compact 后重新注入）；踩坑经验写进 Auto Memory（跨会话持久化）；结果：这类错误从&quot;时常发生&quot;降到&quot;基本不出现&quot;。&lt;/p&gt;
&lt;h4 data-id=&quot;heading-83&quot;&gt;问题二：需求理解偏差导致的返工&lt;/h4&gt;
&lt;p&gt;现状：需求文档描述的是&quot;用户视角的 GMV&quot;，但 AI 生成了&quot;交易视角的 GMV&quot;，两者口径不同，数据对不上，需要返工。&lt;strong&gt;Harness 解法&lt;/strong&gt;：需求分析的产出（口径草稿 + 待确认问题清单）写进 CLAUDE.md 的迭代约束节；Stop hook 检查任务完整性，确认待确认问题清单已全部明确后才放行；结果：需求一次交付通过率从约 50% 提升到 90%。&lt;/p&gt;
&lt;h4 data-id=&quot;heading-84&quot;&gt;问题三：SQL 规范执行不一致&lt;/h4&gt;
&lt;p&gt;现状：规范文档写了&quot;INSERT 必须带 PARTITION&quot;，但 Claude 有时会忘，或在 compact 后规范内容被清除后生成不合规的 SQL。&lt;strong&gt;Harness 解法&lt;/strong&gt;：PostToolUse hook 在每次写 .sql 文件后自动执行规范检查，不依赖 Claude 记忆；违规时 exit 2 返回错误，Claude 强制修正后才能继续；结果：规范执行率从&quot;依赖 LLM 记忆的 70%~80%&quot;提升到&quot;hook 强制的 95%+&quot;。&lt;/p&gt;
&lt;h4 data-id=&quot;heading-85&quot;&gt;问题四：大型需求开发中的 context 耗尽&lt;/h4&gt;
&lt;p&gt;现状：复杂需求（大型宽表、大量下游血缘）开发过程中，血缘查询 + 自测结果 + SKILL 文件内容堆满 context，compact 触发后丢失关键约束，Claude 开始犯低级错误。&lt;strong&gt;Harness 解法&lt;/strong&gt;：血缘查询 → dw-explorer subagent（独立 context，只返回摘要）；23 项自测 → data-quality-checker subagent（独立 context，只返回 PASS/FAIL 报告）；SKILL 文件内容 → subagent 内部读取，主 context 只接收产出的 SQL 文件路径；结果：主 context compact 频率预计降低 50%~70%。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-86&quot;&gt;与传统数仓 AI 开发方式的对比&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://p3-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/4813c7ef8b6b47a1bcb3b78c2703af6c~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5b6X54mp5oqA5pyv:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779934891&amp;amp;x-signature=05kGQTxmWM7R3jTh760QH8gJrNE%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;h3 data-id=&quot;heading-87&quot;&gt;从&quot;AI 帮我写代码&quot;到&quot;AI 嵌入研发流水线&quot;&lt;/h3&gt;
&lt;p&gt;Harness 工程的最终目标，不是让 Claude 更聪明，而是让整个研发流水线更可靠。Claude（LLM）负责：理解需求、设计方案、生成代码------这些需要语义理解的事；Harness（hooks）负责：规范检查、危险拦截、任务完整性验证------这些需要确定性执行的事；Subagents 负责：大量文件读取、血缘查询、自测执行------这些会消耗大量 context 的事；CLAUDE.md + Memory 负责：字段口径、迭代约束、踩坑经验------这些需要跨会话持久化的事。这四层分工，让数仓 AI 开发从&quot;对话驱动的一次性辅助&quot;升级为&quot;规则嵌入的流水线自动化&quot;。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-88&quot;&gt;往期回顾&lt;/h2&gt;
&lt;p&gt;1.&lt;a href=&quot;https://juejin.cn/post/7639261453330874410&quot; target=&quot;_blank&quot; title=&quot;https://juejin.cn/post/7639261453330874410&quot;&gt;BP Claw 破解 AI 编码输入难题 ------FlinkSpec 需求智能化实践｜得物技术&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;2.&lt;a href=&quot;https://juejin.cn/post/7636724456984428607&quot; target=&quot;_blank&quot; title=&quot;https://juejin.cn/post/7636724456984428607&quot;&gt;基于 Harness + SDD + 多仓管理模式的 AI 全栈开发实践｜得物技术&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;3.&lt;a href=&quot;https://juejin.cn/post/7634073298897125439&quot; target=&quot;_blank&quot; title=&quot;https://juejin.cn/post/7634073298897125439&quot;&gt;通用 AI Agent 驱动网关路由安全审计实践｜得物技术&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;4.&lt;a href=&quot;https://juejin.cn/post/7631495035478589450&quot; target=&quot;_blank&quot; title=&quot;https://juejin.cn/post/7631495035478589450&quot;&gt;AI驱动：从运营行为到自动化用例的智能化实践｜得物技术&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;5.&lt;a href=&quot;https://juejin.cn/post/7628888137545859081&quot; target=&quot;_blank&quot; title=&quot;https://juejin.cn/post/7628888137545859081&quot;&gt;生成式召回在得物的落地技术分享与思考&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-id=&quot;heading-89&quot;&gt;文 /丹克&lt;/h2&gt;
&lt;p&gt;关注得物技术，每周更新技术干货&lt;/p&gt;
&lt;p&gt;要是觉得文章对你有帮助的话，欢迎评论转发点赞～&lt;/p&gt;
&lt;p&gt;未经得物技术许可严禁转载，否则依法追究法律责任。
)&lt;/p&gt;
&lt;p&gt;2.基于 Harness + SDD + 多仓管理模式的 AI 全栈开发实践｜得物技术&lt;/p&gt;
&lt;p&gt;3.通用 AI Agent 驱动网关路由安全审计实践｜得物技术&lt;/p&gt;
&lt;p&gt;4.AI驱动：从运营行为到自动化用例的智能化实践｜得物技术&lt;/p&gt;
&lt;p&gt;5.生成式召回在得物的落地技术分享与思考&lt;/p&gt;
&lt;h2 data-id=&quot;heading-90&quot;&gt;文 /丹克&lt;/h2&gt;
&lt;p&gt;关注得物技术，每周更新技术干货&lt;/p&gt;
&lt;p&gt;要是觉得文章对你有帮助的话，欢迎评论转发点赞～&lt;/p&gt;
&lt;p&gt;未经得物技术许可严禁转载，否则依法追究法律责任。&lt;/p&gt;</description><link>https://juejin.cn/post/7641896054783639571</link><guid isPermaLink="false">https://juejin.cn/post/7641896054783639571</guid><pubDate>Thu, 21 May 2026 02:21:32 GMT</pubDate><author>得物技术</author><category>人工智能</category><category>数据库</category><category>AI编程</category><category>大数据</category></item><item><title>Flutter 3.44 发布啦，超级大版本更新！！！</title><description>&lt;p&gt;虽然 Flutter 3.44 的版本已经发布两天了，但是今天才是真正的官宣 Flutter 3.44 发布哦，3.44 虽然看起来版本号不大，但是这确实是一个超级大版本更新。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;也不知道为什么 Flutter 对于 3.x 这个版本号这么热爱，就和 RN 热爱 0.x 一样。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这次 3.44 核心包括 &lt;strong&gt;Android HC++ 功能落地、iOS/MacOS 默认使用 Swift PM、多窗口功能落地、Material 和 Cupertino 解耦、各种 AI 场景支持、Widget Previewer 更新和各种功能优化&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/0e044262372c40d38b908121e5d12558~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779930330&amp;amp;x-signature=3PCSXwaHtfTw6u0Gg9wZrjzcWso%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;首先还是按照惯例，Flutter 先公布了近期的一些数据情况，其中 &lt;strong&gt;pub.dev  在过去 30 天内， Package 下载量超过 13 亿次  ，Flutter 两大应用商店下月活开发者超过 150 万 ，一年内增长了 50%&lt;/strong&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这算是惯例对于 「Flutter 凉了没」的回覆。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-id=&quot;heading-0&quot;&gt;工具更新&lt;/h2&gt;
&lt;h3 data-id=&quot;heading-1&quot;&gt;Widget Previewer&lt;/h3&gt;
&lt;p&gt;虽然我基本没怎么用过，但是 Flutter 官方一直很热衷 Widget Previewer 的优化，这次主要有两个内容：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;预览检测的逻辑重写了，使用 analysis server 做 widget preview detection，&lt;strong&gt;降低了 Flutter 工具的内存占用，对于 IDE 用户而言，整体内存占用最多可降低 50%&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自定义 preview annotation 支持 collections 和 records&lt;/strong&gt;，现在可以按组、名称、脚本和包 URI 筛选预览&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/035d197d338649c892fde36df84dc64e~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779930330&amp;amp;x-signature=yNMvfbIlDu01yNjKxb%2BsOCAr1EY%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;3.44 的 Previewer 其实就是接入了更底层的 analysis server 检测链路，主要涉及：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;IDE 能准确知道哪些函数、构造器、静态方法可以 preview&lt;/li&gt;
&lt;li&gt;Previewer 要能处理真实项目里的 wrapper、theme、localization、状态注入&lt;/li&gt;
&lt;li&gt;依赖真实 analyzer 级别的语义信息&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;可以看出来官方对于 Widget Previewer 很重视，大概在 AI 时代，Widget Previewer 可以在开发过程中，有不错的事实预览效果。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-id=&quot;heading-2&quot;&gt;不需要 Rosetta&lt;/h3&gt;
&lt;p&gt;这个我们提前聊过，在之前的 &lt;a href=&quot;https://juejin.cn/post/7637433660883714090&quot; target=&quot;_blank&quot; title=&quot;https://juejin.cn/post/7637433660883714090&quot;&gt;《Flutter iOS 又修复了一个构建问题》&lt;/a&gt; 就提到过，以前 Flutter 本身的构建工具还是需要 Rosetta 进行适配支持，这次所有的 macOS 命令行工具都已经通过 &lt;strong&gt;Fat Binary，从而同时支持 &lt;code&gt;x86_64&lt;/code&gt; 和 &lt;code&gt;arm64&lt;/code&gt; 两种架构&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;因为下个版本 Rosetta 就要开始推出历史舞台了，所以这也算事一个重要的跟进升级，当然，&lt;em&gt;这个能力的 PR 的过程很抽象，没看过的可以了解下，是真的草台&lt;/em&gt;。。。。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/ed0e18c777c14a94ba834c12b1ca26af~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779930330&amp;amp;x-signature=8mpidTXtECTaCs%2FP9mBR5bejjhA%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;h2 data-id=&quot;heading-3&quot;&gt;AI&lt;/h2&gt;
&lt;p&gt;Flutter 官方真的很热衷跟进各种 AI 能力，而且跟进的贼快。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-4&quot;&gt;Agentic Hot Reload&lt;/h3&gt;
&lt;p&gt;3.44 官方推出了全新的 Agentic Hot Reload 功能，Flutter 在 AI 支持能力上一直很热衷，这次的  Agentic Hot Reload 也是。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/47feca1959a0490e9dfdc96f3f6b804b~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779930330&amp;amp;x-signature=G9VgjZx%2BV1jV%2BjXB%2BoAKdca9F7A%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;从 3.44 开始，&lt;strong&gt;一些 MCP 服务器和 Coding Agnet 支持自动查找并连接到正在运行的 Flutter App&lt;/strong&gt; ，也就是类似 Antigravity 这样的 Coding Agnet  可以支持使用 Hot Reload， 同时还有配置前面的 Previewer ，整体 AI 开发体验会更好。&lt;/p&gt;
&lt;p&gt;另外，Agent 现在可以通过服务，直接读取本地 pub 包依赖，不需要去取搜索本地 pub 缓存，同时 MCP 相关的 Tools 也得到了更新。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;实际上这个能力以前也能做到，AI 通过命令行的 &lt;code&gt;r&lt;/code&gt; 输入也可以，但是这次的是让 agent 有官方路径去发现运行中的 Flutter session，agent 可以知道是哪个 App 正在运行，因为是一整套的 MCP 协议支持。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-id=&quot;heading-5&quot;&gt;Skills&lt;/h3&gt;
&lt;p&gt;关于 skills 在不久前我们也刚聊过，&lt;a href=&quot;https://juejin.cn/post/7637046499474538559&quot; target=&quot;_blank&quot; title=&quot;https://juejin.cn/post/7637046499474538559&quot;&gt;《新 Flutter &amp;amp; Dart Agent Skills 深度解读》&lt;/a&gt; ，现在官方的 skills 都是**“任务导向型”的 Skills**，每个 Skill 都不是在描述一个功能或者说明一个文档，而是在提供一套决策逻辑，让 AI 可以通过明确指令来解决问题，并且提供对应的 反馈循环（Feedback Loop）。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/fc0f53412fbf421092a894c7badcdc51~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779930330&amp;amp;x-signature=AfnnIylDsvZGQq420VVJGAnM7lk%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;每个技 Skill 的结果都需要做检验&lt;/strong&gt;，类似  &lt;code&gt;flutter-fix-layout-issues&lt;/code&gt;、&lt;code&gt;flutter-add-widget-test&lt;/code&gt; 、&lt;code&gt;flutter-add-integration-test&lt;/code&gt; 、&lt;code&gt;flutter-build-responsive-layout&lt;/code&gt;、&lt;code&gt;flutter-setup-localization&lt;/code&gt; 、&lt;code&gt;flutter-implement-json-serialization&lt;/code&gt; 、&lt;code&gt;flutter-add-widget-preview&lt;/code&gt; 、&lt;code&gt;dart-fix-runtime-errors&lt;/code&gt; 、&lt;code&gt;dart-use-pattern-matching&lt;/code&gt; 都是很实用的技能。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-6&quot;&gt;Genkit Dart&lt;/h3&gt;
&lt;p&gt;关于 GenKit 我们之前也一样在 &lt;a href=&quot;https://juejin.cn/post/7615551904538755114&quot; target=&quot;_blank&quot; title=&quot;https://juejin.cn/post/7615551904538755114&quot;&gt;《谷歌 Genkit Dart 正式发布》&lt;/a&gt; 聊过，基于Genkit 可以构建全栈式 AI 驱动的智能体应用：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Flutter 使用 Dart 可以直接原生实现 AI 编排框架，支持不同模型和本地场景，提供 agent workflow / tool calling / RAG 等能力&lt;/strong&gt; 。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;通过 Genkit Dart 你可以实现一整套的 Agent 的服务端和客户端能力，支持 Google、Anthropic 、 OpenAI 甚至本地模型的能力，包括类型安全的结构化输出、工具调用、多轮对话和内置的可观测性能力等等。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-dart&quot; lang=&quot;dart&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&#39;package:genkit/genkit.dart&#39;&lt;/span&gt;;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&#39;package:genkit_google_genai/genkit_google_genai.dart&#39;&lt;/span&gt;;

&lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; main() &lt;span class=&quot;hljs-keyword&quot;&gt;async&lt;/span&gt; {
 &lt;span class=&quot;hljs-keyword&quot;&gt;final&lt;/span&gt; ai = Genkit(plugins: [googleAI()]);

 &lt;span class=&quot;hljs-keyword&quot;&gt;final&lt;/span&gt; response = &lt;span class=&quot;hljs-keyword&quot;&gt;await&lt;/span&gt; ai.generate(
   model: googleAI.gemini(&lt;span class=&quot;hljs-string&quot;&gt;&#39;gemini-flash-latest&#39;&lt;/span&gt;),
   prompt: &lt;span class=&quot;hljs-string&quot;&gt;&#39;Why is Dart a great language for AI
            applications?&#39;&lt;/span&gt;,
 );

 &lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(response.text);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-id=&quot;heading-7&quot;&gt;Gemma 4&lt;/h3&gt;
&lt;p&gt;Flutter 也支持直接跑 Gemma 4  本地模型，通过 &lt;code&gt;flutter_gemma&lt;/code&gt;  插件，App 可以和 Gemma 深度集成，插件底层支持 LiteRT-LM ，支持 GPU 和 NPU 加速，最重要是支持全平台 ：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/3437f7cf2190482ab1647fa421f197ac~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779930330&amp;amp;x-signature=scPElPU5lrjW%2F%2BrhrZHF3KmsmV0%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;h3 data-id=&quot;heading-8&quot;&gt;GenUI&lt;/h3&gt;
&lt;p&gt;这个大家应该也不陌生吧，我们在 &lt;a href=&quot;https://juejin.cn/post/7640409934489010230&quot; target=&quot;_blank&quot; title=&quot;https://juejin.cn/post/7640409934489010230&quot;&gt;《Flutter GenUI 0.9 和 A2UI 0.9 发布》&lt;/a&gt; 才刚刚聊过，官方表示：&lt;code&gt;Flutter + A2UI = GenUI&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/139589c087a24ffb88bbd44dca74f14d~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779930330&amp;amp;x-signature=YePgwghBc3iA%2F8%2BCQjPL%2FWfBUBU%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;作为基于 AI 的生成式  UI 支持，Flutter 算是在 A2UI 领域最早的支持项目之一，它提供了一套完整的协议实现，&lt;strong&gt;可以让 Agent 在 App 运行中动态生成控件，客户端不需要开发一个完整的页面功能，开发者只需要维护组建库&lt;/strong&gt;，剩下的都交给 AI 。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;官方统计，自从推出 Flutter GenUI SDK 以来，软件包下载量自年初以来增长了 500%。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;官方特别提到了 &lt;em&gt;Catagay Ulusoy&lt;/em&gt; 开发的 &lt;em&gt;Finnish it&lt;/em&gt; （ 可在 Google Play 商店和 Apple Store 下载 ）例子，这款应用不仅能为用户创建定制化的课程计划来学习芬兰语，还能根据每节课的需要动态生成完美的界面：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/1709217d07bf48d3a003055d06d64582~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779930330&amp;amp;x-signature=LJNZDPFfvb3%2FkW2z2NnP9i7B4PA%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;另外还有官方提供的 Demo ，也分享了 DeepMind 使用 Flutter 构建 Gemini App “可视化布局”的效果 ：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/94499288dc354a6f95aebd43124a50e6~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779930330&amp;amp;x-signature=w4Q5vhjjYysTv9nQPXjh4JqJMdk%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;h2 data-id=&quot;heading-9&quot;&gt;Android&lt;/h2&gt;
&lt;p&gt;首先就是 Googlebook 支持，&lt;strong&gt;我都还没用上，Flutter 就宣布了 Googlebook 已经适配完成&lt;/strong&gt;，核心是适配了 Gemini 处理器的全新 Googlebook 笔记本电脑，不过具体支持的如何，还需要看真的发布后才知道。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;另外还有 Android 17 的适配&lt;/strong&gt;， Flutter 3.44 也正在完成 Android 17 的适配，包括本地网络保护和安全动态代码加载等场景 。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-10&quot;&gt;Hybrid Composition++&lt;/h3&gt;
&lt;p&gt;另外还有一个重点就是 Hybrid Composition++ 终于落地了，这个我们再去年的 &lt;a href=&quot;https://juejin.cn/post/7471979172115152932&quot; target=&quot;_blank&quot; title=&quot;https://juejin.cn/post/7471979172115152932&quot;&gt;《Flutter 正在推进全新 PlatformView 实现 HCPP》&lt;/a&gt; 就提到过，这是一套全新的 PlatformView 实现，可以提供更好的 PlatformView 新能：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/d115b34ab1b04d5886cd30eaebbbb3e8~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779930330&amp;amp;x-signature=zm7o80qf7baChahfpfkY9bk9V%2F4%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HCPP 不再依赖屏幕外缓冲区或强制 Flutter 引擎处理原生视图&lt;/strong&gt;，而是将图层合成直接委托给 Android 本地，然后利用 Vulkan 图形库的底层访问能力，通过硬件缓冲区交换链和 &lt;code&gt;SurfaceControl&lt;/code&gt; 事务将 Flutter UI 与原生 Android 视图同步。&lt;/p&gt;
&lt;p&gt;简单来说就是，&lt;strong&gt;HCPP 主要就是通过 &lt;code&gt;SurfaceControl&lt;/code&gt; 来构造一个高层级的 &lt;code&gt;Surface&lt;/code&gt; 从而实现最终绘制时混合覆盖的问题&lt;/strong&gt;，这和 &lt;a href=&quot;https://juejin.cn/post/7461597205342928936&quot; target=&quot;_blank&quot; title=&quot;https://juejin.cn/post/7461597205342928936&quot;&gt;《深入 Flutter 和 Compose 的 PlatformView 实现对比》&lt;/a&gt; 里 Compose 可以在 PlatformView 里直接使用 &lt;code&gt;SurfaceView&lt;/code&gt; 的道理类似，都是 &lt;code&gt;SurfaceFlinger&lt;/code&gt; 合成时的层级操作。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;只是&lt;strong&gt;需要 Vulkan 和 API 34 的环境才支持使用&lt;/strong&gt; 。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;所以 HCPP 对 &lt;a href=&quot;https://link.juejin.cn/?target=https%3A%2F%2Fdocs.flutter.dev%2Fplatform-integration%2Fandroid%2Fplatform-views%23hcpp&quot; target=&quot;_blank&quot; title=&quot;https://docs.flutter.dev/platform-integration/android/platform-views#hcpp&quot; ref=&quot;nofollow noopener noreferrer&quot;&gt;Android API 和硬件有一定要求 &lt;/a&gt;，可以通过在 &lt;code&gt;run&lt;/code&gt; 中添加 &lt;code&gt;--enable-hcpp&lt;/code&gt;  或者在 &lt;code&gt;AndroidManifest.xml&lt;/code&gt; 文件中添加相应的配置标志来启用：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-xml&quot; lang=&quot;xml&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;meta-data&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;android:name&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;io.flutter.embedding.android.EnableHcpp&quot;&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;android:value&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&quot;true&quot;&lt;/span&gt; /&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-id=&quot;heading-11&quot;&gt;Android 显示屏圆角&lt;/h3&gt;
&lt;p&gt;Android 设备圆角支持，&lt;code&gt;PredictiveBackPageTransitionsBuilder&lt;/code&gt; 新增对 &lt;code&gt;MediaQuery.displayCornerRadiiOf(context)&lt;/code&gt; 的使用。&lt;/p&gt;
&lt;p&gt;简单说，Android 设备真实屏幕圆角可以参与页面返回转场的裁剪效果，让转场更贴合物理设备边界。&lt;/p&gt;
&lt;p&gt;如果你的应用自己覆盖了 Android 页面转场，可以显式使用这个 builder；设备圆角会由 &lt;code&gt;MediaQuery.displayCornerRadiiOf(context)&lt;/code&gt; 自动参与裁剪，拿不到设备圆角时走 fallback：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-dart&quot; lang=&quot;dart&quot;&gt;MaterialApp(
  theme: ThemeData(
    pageTransitionsTheme: &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; PageTransitionsTheme(
      builders: &amp;lt;TargetPlatform, PageTransitionsBuilder&amp;gt;{
        TargetPlatform.android: PredictiveBackPageTransitionsBuilder(
          fallbackColor: Colors.black,
        ),
      },
    ),
  ),
  home: &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; HomePage(),
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-id=&quot;heading-12&quot;&gt;AGP 9 和 built-in Kotlin&lt;/h3&gt;
&lt;p&gt;在 AGP 9 版本之前，Android 应用和插件需要手动将 Kotlin Gradle 插件 (KGP) 添加到构建文件，系统才能识别并编译 Kotlin 代码。&lt;/p&gt;
&lt;p&gt;从 AGP 9.0 开始，Android 构建系统已原生支持 Kotlin，由于构建系统已经处理了 Kotlin，&lt;strong&gt;手动添加单独的 KGP 会导致冲突并造成构建失败&lt;/strong&gt;，所以这个情况需要 Flutter 进行适配，所以：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果你是开发 Flutter App，这里需要更新 Android 构建文件，删除单独的 Kotlin Gradle 插件 (KGP)&lt;/li&gt;
&lt;li&gt;如果是插件的话，就需要对 Gradle 进行修改兼容&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;设置   AGP 9.0 的插件必须  &lt;code&gt;pubspec.yaml&lt;/code&gt;  里将 Flutter 的最低版本限制设置为 3.44 。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这个问题主要还是 AGP 和 Kotlin 的破坏性更新带来的，以前 Flutter Android 项目里常见的是：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-groovy&quot; lang=&quot;groovy&quot;&gt;plugins {
    id &quot;com.android.application&quot;
    id &quot;kotlin-android&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或者老写法：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-groovy&quot; lang=&quot;groovy&quot;&gt;apply plugin: &#39;com.android.application&#39;
apply plugin: &#39;kotlin-android&#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;而到了 AGP 9.0，Android Gradle Plugin 自己内置了 Kotlin 支持同时默认启用，也就是说普通 Android app/library 模块里不再需要显式 apply &lt;code&gt;org.jetbrains.kotlin.android&lt;/code&gt; 或 &lt;code&gt;kotlin-android&lt;/code&gt; 插件。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Google 官方说法是：AGP 9.0 introduces built-in Kotlin support and enables it by default，不再需要 apply &lt;code&gt;org.jetbrains.kotlin.android&lt;/code&gt; / &lt;code&gt;kotlin-android&lt;/code&gt; 来编译 Kotlin 源码。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;所以迁移后的 Flutter Android app 大致会从：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-groovy&quot; lang=&quot;groovy&quot;&gt;plugins {
    id &quot;com.android.application&quot;
    id &quot;kotlin-android&quot;
    id &quot;dev.flutter.flutter-gradle-plugin&quot;
}

android {
    kotlinOptions {
        jvmTarget = JavaVersion.VERSION_17.toString()
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;变成：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-groovy&quot; lang=&quot;groovy&quot;&gt;plugins {
    id &quot;com.android.application&quot;
    id &quot;dev.flutter.flutter-gradle-plugin&quot;
}

android {
    // ...
}

kotlin {
    compilerOptions {
        jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;也就是 &lt;strong&gt;删掉 &lt;code&gt;kotlin-android&lt;/code&gt;，删掉 &lt;code&gt;android { kotlinOptions {} }&lt;/code&gt;，改用顶层 &lt;code&gt;kotlin { compilerOptions {} }&lt;/code&gt;。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Flutter 3.44 也不是强行让所有项目马上完全迁到 AGP 9 + built-in Kotlin，所以也加了两个 flag 做缓冲：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-ini&quot; lang=&quot;ini&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;android.newDsl&lt;/span&gt;=&lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;android.builtInKotlin&lt;/span&gt;=&lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;而为了支持还没迁移的项目，Flutter 默认使用 legacy Kotlin Gradle Plugin 和 old AGP DSL types，Flutter migrator 会自动把这两个 flag 加到 &lt;code&gt;gradle.properties&lt;/code&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-id=&quot;heading-13&quot;&gt;ABI&lt;/h3&gt;
&lt;p&gt;Flutter 之前的做法是帮你按构建类型动态塞 ABI 过滤器，现在改成「在 &lt;code&gt;defaultConfig&lt;/code&gt; 里统一塞一次」，这个变化也是遇到 AGP 9 的合并规则后。&lt;/p&gt;
&lt;p&gt;以前一般是 &lt;code&gt;flutter build apk --target-platform android-arm64&lt;/code&gt; 或者 &lt;code&gt;flutter build apk --split-per-abi&lt;/code&gt; ，而现在为了 AGP9 ， Flutter 把 ABI filter 放到了 &lt;code&gt;defaultConfig&lt;/code&gt; ：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-groovy&quot; lang=&quot;groovy&quot;&gt;android {
    defaultConfig {
        ndk {
            abiFilters ...
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;所以，如果在特定构建类型或产品风格中使用自定义 &lt;code&gt;abiFilters&lt;/code&gt; ，现在需要在构建或运行应用时传递 &lt;code&gt;-Pdisable-abi-filtering=true&lt;/code&gt; 标志。&lt;/p&gt;
&lt;h2 data-id=&quot;heading-14&quot;&gt;iOS&lt;/h2&gt;
&lt;h3 data-id=&quot;heading-15&quot;&gt;Swift PM 默认&lt;/h3&gt;
&lt;p&gt;这个我们其实也已经在 &lt;a href=&quot;https://juejin.cn/post/7635969457790648383&quot; target=&quot;_blank&quot; title=&quot;https://juejin.cn/post/7635969457790648383&quot;&gt;《Flutter 3.44 发布前夕，官方宣布 SwiftPM 将完全取代 CocoaPods》&lt;/a&gt; 聊过，从  Flutter 3.44 开始，&lt;strong&gt;Swift Package Manager 成为是 iOS/macOS 的默认包管理器 ，同时这个包含了大量SwiftPM 的修复&lt;/strong&gt;，例如：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;CocoaPods 与 SwiftPM 冲突提示、SwiftPM 最低平台版本诊断、SwiftPM 下载太慢的慢提示、SwiftPM cache 集中化处理、SwiftPM Add-to-App 工具等&lt;/em&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;现在 Flutter CLI 会自动处理迁移。构建或运行应用时，CLI 会将 Xcode 项目更新为使用 SwiftPM，如果依赖暂时不支持 SwiftPM，Flutter 会 fallback 到 CocoaPods，同时发出警告。&lt;/p&gt;
&lt;p&gt;如果在 add-to-app 场景下，新的 &lt;code&gt;flutter build swift-package&lt;/code&gt;  也会支持对应命令，如果 SwiftPM 是在无法兼容，页可以通过在 &lt;code&gt;pubspec.yaml&lt;/code&gt; 文件中设置 &lt;code&gt;--enable-swift-package-manager: false&lt;/code&gt; 来回退禁用。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://juejin.cn/Users/guoshuyu/Library/Containers/com.tencent.xinWeChat/Data/Documents/xwechat_files/wxid_ori7u1g616jx22_9a0f/temp/InputTemp/881580a2-1a33-40bd-b4d3-0e81464ee33a.png&quot; alt=&quot;转存失败，建议直接上传图片文件&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;h3 data-id=&quot;heading-16&quot;&gt;UIScene&lt;/h3&gt;
&lt;p&gt;由于 Apple 已经强制了 UIScene 要求， &lt;strong&gt;所以这里是想提醒你，如果还么迁移适配，那就要抓紧了&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 data-id=&quot;heading-17&quot;&gt;predictive text&lt;/h3&gt;
&lt;p&gt;这是 iOS 上一个新的实验性支持，&lt;code&gt;TextField&lt;/code&gt;、&lt;code&gt;CupertinoTextField&lt;/code&gt;、&lt;code&gt;EditableText&lt;/code&gt; 和 &lt;code&gt;TextInputConfiguration&lt;/code&gt; 增加了 &lt;code&gt;enableInlinePrediction&lt;/code&gt; 相关配置。&lt;/p&gt;
&lt;p&gt;也就是  iOS 文本输入接入 inline prediction 提供了 opt-in 配置，并把配置从高层 &lt;code&gt;TextField&lt;/code&gt; 传到底层 text input channel，Material 风格输入框可以这样显式打开：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-dart&quot; lang=&quot;dart&quot;&gt;TextField(
  controller: titleController,
  enableInlinePrediction: &lt;span class=&quot;hljs-keyword&quot;&gt;true&lt;/span&gt;,
  textInputAction: TextInputAction.done,
  decoration: &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; InputDecoration(
    labelText: &lt;span class=&quot;hljs-string&quot;&gt;&#39;标题&#39;&lt;/span&gt;,
  ),
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Cupertino 风格输入框也有同名参数：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-dart&quot; lang=&quot;dart&quot;&gt;CupertinoTextField(
  controller: titleController,
  enableInlinePrediction: &lt;span class=&quot;hljs-keyword&quot;&gt;true&lt;/span&gt;,
  placeholder: &lt;span class=&quot;hljs-string&quot;&gt;&#39;标题&#39;&lt;/span&gt;,
  textInputAction: TextInputAction.done,
)
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;默认功能是关闭的，它目前只对 iOS 17 及以上的 inline predictive text 有用。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-id=&quot;heading-18&quot;&gt;Web&lt;/h2&gt;
&lt;p&gt;这个版本主要都是一个简单优化，例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;支持  &lt;code&gt;prefers-reduced-motion&lt;/code&gt; ，也就是现在浏览器/系统说要“少动画”，Flutter Web 能够适配，然后 Web 还把这个偏好同步到 Flutter engine 的 accessibility 配置里，让 Flutter 侧的 &lt;code&gt;disableAnimations&lt;/code&gt; / &lt;code&gt;reduceMotion&lt;/code&gt; 生效。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;另外现在 Flutter Web 表单错误能更快被屏幕阅读器读到，也算是无障碍的一个优化。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;支持  iOS 26 Safari autofill ，Flutter Web 在 iOS 26 Safari 上不会再频繁销毁/重建用于 autofill 的隐藏 DOM form，而是尽量复用同一个 form，这样 Safari/密码管理器才能识别“这是一组连续的登录/注册表单字段”，从而正常自动填充。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-id=&quot;heading-19&quot;&gt;Desktop&lt;/h2&gt;
&lt;p&gt;Flutter 这次不装了，直接宣布 &lt;strong&gt;Canonical 将成为 Flutter Desktop 的主要维护者和战略合作伙伴&lt;/strong&gt;  ，这是什么意思？就是 Desktop 完全交给 Canonical 维护和主导了。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/5902db19d7c048878c52984e91e91d49~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779930330&amp;amp;x-signature=vRzoDxD4ZI2IWK68VmoL6NmXHrs%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;结果这次还是失望了， &lt;strong&gt;虽然新增加了功能，但是多窗口功能还是只仅在 master 可以用&lt;/strong&gt;，依然没有合并到 stable 。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/52ef38ab72ba49209e67843b229b56a9~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779930330&amp;amp;x-signature=Du0nNkyhMAz3eoNcN3Q4jpHIQik%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;这次多窗口新增加了  Tooltips 、Popups 和  Dialogs 的落地，同时 Linux 现在也支持了 content-sized 视图，可以根据窗口内容动态调整窗口大小。&lt;/p&gt;
&lt;p&gt;另外这次更新里 showRawDialog / showDialog 可以走原生 dialog window ，如果通过 &lt;code&gt;flutter config --enable-windowing&lt;/code&gt; 启用了 windowing，那么 dialog 会通过 windowing system 显示在自己的窗口中，而不是当前窗口内的 modal overlay，平台不支持时，会 fallback 到普通 dialog route。&lt;/p&gt;
&lt;p&gt;其他还有 &lt;code&gt;_window.dart&lt;/code&gt; 有了多类 controller 和 widget：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;RegularWindowController&lt;/code&gt; / &lt;code&gt;RegularWindow&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DialogWindowController&lt;/code&gt; / &lt;code&gt;DialogWindow&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TooltipWindowController&lt;/code&gt; / &lt;code&gt;TooltipWindow&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PopupWindowController&lt;/code&gt; / &lt;code&gt;PopupWindow&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SatelliteWindowController&lt;/code&gt; / &lt;code&gt;SatelliteWindow&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-id=&quot;heading-20&quot;&gt;嵌入式&lt;/h2&gt;
&lt;p&gt;这里官方主要介绍了一些案件，例如丰田的车机， RAV4 在 2025 年是全球最畅销的车型 ，而 &lt;strong&gt;2026 款 RAV4 正在使用 Flutter 构建车机系统&lt;/strong&gt; ：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/bf9b0e13bb4d49c5bab60c85e6cee7d1~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779930330&amp;amp;x-signature=uMZAKucLJy2ta%2FYu6oNQ%2Bu9Fe%2BA%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;LG 的基于 Flutter 的 WebOS SDK 页要更新发布了，webOS SDK 将包含对 Firebase、视频播放器、游戏手柄等插件的支持。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/f0721483b0f94da8aac7f9fae9736c8c~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779930330&amp;amp;x-signature=RKX%2BRU5Wl9rUiphNZq0YR8Qy45s%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;h2 data-id=&quot;heading-21&quot;&gt;Impeller&lt;/h2&gt;
&lt;p&gt;3.44 版本包含多个 Vulkan 优化，包括「更好的缓存内存管理」，还有在丢帧情况下更高效的 GPU/CPU 同步，&lt;strong&gt;使用 SDF 可以实现更清晰的圆圈&lt;/strong&gt; ：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/07e1831fc976424fba425318186763ee~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779930330&amp;amp;x-signature=riWZlzahgfEs45LnMAecLUDKGsY%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这个圈我看了是真头晕。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;同时也改进了 Impeller 处理透视矩阵的方式，修正了阴影和透视投影变换的渲染行为，支持  &lt;em&gt;Get Uniform by Name API&lt;/em&gt;  ，可以在着色器中按名称绑定 uniform 变量：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-c&quot; lang=&quot;c&quot;&gt;    &lt;span class=&quot;hljs-type&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;setUp&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(ui.FragmentShader shader)&lt;/span&gt; {
      shader.getUniformFloat(&lt;span class=&quot;hljs-string&quot;&gt;&#39;foobar&#39;&lt;/span&gt;).&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;1.234&lt;/span&gt;);
    }
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-id=&quot;heading-22&quot;&gt;Framework&lt;/h2&gt;
&lt;h3 data-id=&quot;heading-23&quot;&gt;解耦&lt;/h3&gt;
&lt;p&gt;3.44 开始，&lt;strong&gt;Material 和 Cupertino  就是独立的  &lt;code&gt;material_ui&lt;/code&gt; 和 &lt;code&gt;cupertino_ui&lt;/code&gt;  了，而下个版本发布的时候，框架内当前兼容的样式框就会被完全弃用兼容&lt;/strong&gt;，整整 60 多万行代码的 PR ：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/1f31a42826ba4a8a99e521755754a154~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779930330&amp;amp;x-signature=tm%2FXGY89rPGWi6ebBxAy%2FMCJ3bI%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;h3 data-id=&quot;heading-24&quot;&gt;弹框&lt;/h3&gt;
&lt;p&gt;这次新增的 &lt;code&gt;CupertinoMenuAnchor&lt;/code&gt; / &lt;code&gt;CupertinoMenuItem&lt;/code&gt;  就是基于 widgets 层的 &lt;code&gt;RawMenuAnchor&lt;/code&gt; 实现， Flutter 正在把“菜单锚点、打开/关闭、overlay、焦点和手势”这类共性逻辑放在更低层，让 Material 和 Cupertino 分别负责自己的视觉和交互风格。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/d8503c42d9a047389b21956542e140b7~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779930330&amp;amp;x-signature=nCWDLYp1g6XXJtOHr17v4TZKCgg%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;3.44 新增 &lt;code&gt;CupertinoMenuAnchor&lt;/code&gt; 和 &lt;code&gt;CupertinoMenuItem&lt;/code&gt;，它们提供 Cupertino 风格的菜单 popup，支持 controller、open/close 回调、动画状态、overlay padding、长按打开、swipe 选择、focus/hover、destructive action 等能力：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-dart&quot; lang=&quot;dart&quot;&gt;CupertinoMenuAnchor(
  menuChildren: &amp;lt;Widget&amp;gt;[
    CupertinoMenuItem(
      leading: &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; Icon(CupertinoIcons.doc_on_doc),
      subtitle: &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; Text(&lt;span class=&quot;hljs-string&quot;&gt;&#39;创建一个副本&#39;&lt;/span&gt;),
      trailing: &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; Icon(CupertinoIcons.right_chevron),
      onPressed: duplicateItem,
      child: &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; Text(&lt;span class=&quot;hljs-string&quot;&gt;&#39;复制&#39;&lt;/span&gt;),
    ),
    &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; CupertinoMenuDivider(),
    CupertinoMenuItem(
      leading: &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; Icon(CupertinoIcons.delete),
      isDestructiveAction: &lt;span class=&quot;hljs-keyword&quot;&gt;true&lt;/span&gt;,
      onPressed: deleteItem,
      child: &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; Text(&lt;span class=&quot;hljs-string&quot;&gt;&#39;删除&#39;&lt;/span&gt;),
    ),
  ],
  builder: (BuildContext context, MenuController controller, Widget? child) {
    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; CupertinoButton(
      padding: EdgeInsets.zero,
      onPressed: () {
        controller.isOpen ? controller.close() : controller.open();
      },
      child: &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; Icon(CupertinoIcons.ellipsis_circle),
    );
  },
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果你不需要自己控制打开/关闭，也可以传 &lt;code&gt;child&lt;/code&gt; 并配合外部 &lt;code&gt;MenuController&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-dart&quot; lang=&quot;dart&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;final&lt;/span&gt; MenuController controller = MenuController();

CupertinoMenuAnchor(
  controller: controller,
  menuChildren: &amp;lt;Widget&amp;gt;[
    CupertinoMenuItem(
      onPressed: () =&amp;gt; controller.close(),
      child: &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; Text(&lt;span class=&quot;hljs-string&quot;&gt;&#39;完成&#39;&lt;/span&gt;),
    ),
  ],
  child: CupertinoButton(
    onPressed: controller.open,
    child: &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; Text(&lt;span class=&quot;hljs-string&quot;&gt;&#39;更多&#39;&lt;/span&gt;),
  ),
)
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;这里和 &lt;code&gt;PlatformMenuBar&lt;/code&gt; 不一样：&lt;code&gt;CupertinoMenuAnchor&lt;/code&gt; 是 Flutter 自己绘制的 Cupertino-style popup menu，适合控件附近的上下文菜单；&lt;code&gt;PlatformMenuBar&lt;/code&gt; 则是交给宿主平台渲染的顶层菜单栏。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Material 的 &lt;code&gt;MenuAnchor&lt;/code&gt;  也新增了 Material 3 动画， &lt;code&gt;SubmenuButton&lt;/code&gt; 上的新 &lt;code&gt;hoverOpenDelay&lt;/code&gt; 参数可以控制子菜单的交互，默认动画处于禁用状态，可以通过 animated 设置为 true 来启用 ：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/267d94389119467eba273974d5ec0369~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779930330&amp;amp;x-signature=gkum5H22wRqxyw0zSkXHQXSoUrs%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;另外， &lt;code&gt;CupertinoSheetRoute&lt;/code&gt;  里面的可滚动内容现在可以和拖拽动画无缝协作，对于需要自定义拖拽区域的开发者来说，新的 &lt;code&gt;scrollableBuilder&lt;/code&gt; 支持将托管的 &lt;code&gt;ScrollController&lt;/code&gt; 传递给 body 的可滚动区域：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/a9a1aa099866468898131f5992975ed8~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779930330&amp;amp;x-signature=N3I1Y2uifFcgU%2F6RztQ7JSBhpS4%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;h3 data-id=&quot;heading-25&quot;&gt;CarouselView 支持 infinite&lt;/h3&gt;
&lt;p&gt;CarouselView 这也也进行了大调整，最重要就是支持了 infinite：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/6276bff9c72e43fca2d7d34443116694~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1779930330&amp;amp;x-signature=SwV01RlAd2j3iDv%2FxFemf9GvBHw%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;Material &lt;code&gt;CarouselView&lt;/code&gt; 新增 &lt;code&gt;infinite&lt;/code&gt; 参数，开启后 Carousel 可以在两个方向连续循环滚动。&lt;/p&gt;
&lt;p&gt;这个能力覆盖普通 &lt;code&gt;CarouselView&lt;/code&gt;、&lt;code&gt;CarouselView.weighted&lt;/code&gt; 和 lazy builder 场景，当 &lt;code&gt;infinite&lt;/code&gt; 为 true 时，carousel 支持无限循环，双向连续滚动：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-dart&quot; lang=&quot;dart&quot;&gt;CarouselView(
  itemExtent: &lt;span class=&quot;hljs-number&quot;&gt;280&lt;/span&gt;,
  infinite: &lt;span class=&quot;hljs-keyword&quot;&gt;true&lt;/span&gt;,
  children: &lt;span class=&quot;hljs-built_in&quot;&gt;List&lt;/span&gt;&amp;lt;Widget&amp;gt;.generate(&lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;, (&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; index) {
    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; Card.filled(
      child: Center(child: Text(&lt;span class=&quot;hljs-string&quot;&gt;&#39;推荐内容 &lt;span class=&quot;hljs-subst&quot;&gt;$index&lt;/span&gt;&#39;&lt;/span&gt;)),
    );
  }),
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-id=&quot;heading-26&quot;&gt;SelectableRegion&lt;/h3&gt;
&lt;p&gt;不得不说，这个玩意一直都没完全支持好，这次 3.44 主要解决了两个问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Web 布局约束保留 ： 之前  &lt;code&gt;SelectableRegion&lt;/code&gt; 在网页上渲染时可能会导致对应子元素意外缩小，现在它会将所有布局约束原封不动地传递给子元素，从而确保一致的尺寸行为&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;多行复制精度，现在 &lt;code&gt;SelectableRegion&lt;/code&gt; 中的文本选择更加精确，当用户选择并复制跨越多行的文本时，复制的输出中会正确保留换行符，不会丢失换行符&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-id=&quot;heading-27&quot;&gt;Superellipse&lt;/h3&gt;
&lt;p&gt;另外，Superellipse 现在覆盖更多 iOS 风格形状：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CupertinoFocusHalo.withRoundedSuperellipse&lt;/code&gt; 用 &lt;code&gt;RoundedSuperellipseBorder&lt;/code&gt; 绘制更接近 iOS 的平滑圆角 focus halo&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ShapedInputBorder&lt;/code&gt; 可一配合 &lt;code&gt;RoundedSuperellipseBorder&lt;/code&gt; 做 iOS-style shape&lt;/li&gt;
&lt;li&gt;Cupertino 的 dialog、context menu、sheet、list section、picker、segmented control 等路径已经基本采用 &lt;code&gt;ClipRSuperellipse&lt;/code&gt; / &lt;code&gt;RoundedSuperellipseBorder&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-dart&quot; lang=&quot;dart&quot;&gt;ClipRSuperellipse(
  borderRadius: BorderRadius.circular(&lt;span class=&quot;hljs-number&quot;&gt;28&lt;/span&gt;),
  child: Image.asset(
    &lt;span class=&quot;hljs-string&quot;&gt;&#39;assets/cover.jpg&#39;&lt;/span&gt;,
    width: &lt;span class=&quot;hljs-number&quot;&gt;160&lt;/span&gt;,
    height: &lt;span class=&quot;hljs-number&quot;&gt;160&lt;/span&gt;,
    fit: BoxFit.cover,
  ),
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-id=&quot;heading-28&quot;&gt;ExpansionTile&lt;/h3&gt;
&lt;p&gt;最后， &lt;code&gt;ExpansionTileController&lt;/code&gt;  页做了优化，作为 Material 组件 &lt;code&gt;ExpansionTile&lt;/code&gt; 底层基础的 &lt;code&gt;Expansible&lt;/code&gt; 组件， &lt;code&gt;ExpansibleController&lt;/code&gt; 和 &lt;code&gt;ExpansibleController&lt;/code&gt; 都新增了切换方法，Material 的列表图块 &lt;code&gt;RadioListTile&lt;/code&gt; 、 &lt;code&gt;CheckboxListTile&lt;/code&gt; 和 &lt;code&gt;SwitchListTile&lt;/code&gt;  也支持了 &lt;code&gt;WidgetStatesController&lt;/code&gt; 。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-dart&quot; lang=&quot;dart&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&#39;package:flutter/material.dart&#39;&lt;/span&gt;;

&lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;ExpansibleControllerDemo&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;StatefulWidget&lt;/span&gt; &lt;/span&gt;{
  &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; ExpansibleControllerDemo({&lt;span class=&quot;hljs-keyword&quot;&gt;super&lt;/span&gt;.key});

  &lt;span class=&quot;hljs-meta&quot;&gt;@override&lt;/span&gt;
  State&amp;lt;ExpansibleControllerDemo&amp;gt; createState() =&amp;gt;
      _ExpansibleControllerDemoState();
}

&lt;span class=&quot;hljs-class&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;_ExpansibleControllerDemoState&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;State&lt;/span&gt;&amp;lt;&lt;span class=&quot;hljs-title&quot;&gt;ExpansibleControllerDemo&lt;/span&gt;&amp;gt; &lt;/span&gt;{
  &lt;span class=&quot;hljs-keyword&quot;&gt;final&lt;/span&gt; ExpansibleController _controller = ExpansibleController();

  &lt;span class=&quot;hljs-meta&quot;&gt;@override&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; dispose() {
    _controller.dispose();
    &lt;span class=&quot;hljs-keyword&quot;&gt;super&lt;/span&gt;.dispose();
  }

  &lt;span class=&quot;hljs-meta&quot;&gt;@override&lt;/span&gt;
  Widget build(BuildContext context) {
    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; Scaffold(
      appBar: AppBar(
        title: &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; Text(&lt;span class=&quot;hljs-string&quot;&gt;&#39;ExpansibleController.toggle&#39;&lt;/span&gt;),
      ),
      body: Padding(
        padding: &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; EdgeInsets.all(&lt;span class=&quot;hljs-number&quot;&gt;16&lt;/span&gt;),
        child: Expansible(
          controller: _controller,
          headerBuilder: (context, animation) {
            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; Card(
              child: ListTile(
                title: &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; Text(&lt;span class=&quot;hljs-string&quot;&gt;&#39;自定义 Expansible Header&#39;&lt;/span&gt;),
                subtitle: &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; Text(&lt;span class=&quot;hljs-string&quot;&gt;&#39;底层展开组件，不限制 Material 样式&#39;&lt;/span&gt;),
                trailing: RotationTransition(
                  turns: Tween&amp;lt;&lt;span class=&quot;hljs-built_in&quot;&gt;double&lt;/span&gt;&amp;gt;(
                    begin: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;,
                    end: &lt;span class=&quot;hljs-number&quot;&gt;0.5&lt;/span&gt;,
                  ).animate(animation),
                  child: &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; Icon(Icons.expand_more),
                ),
                onTap: () {
                  _controller.toggle();
                },
              ),
            );
          },
          bodyBuilder: (context, animation) {
            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; SizeTransition(
              sizeFactor: animation,
              child: &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; Card(
                child: Padding(
                  padding: EdgeInsets.all(&lt;span class=&quot;hljs-number&quot;&gt;16&lt;/span&gt;),
                  child: Text(
                    &lt;span class=&quot;hljs-string&quot;&gt;&#39;这里是展开内容。&#39;&lt;/span&gt;
                    &lt;span class=&quot;hljs-string&quot;&gt;&#39;Expansible 更适合做完全自定义 UI，&#39;&lt;/span&gt;
                    &lt;span class=&quot;hljs-string&quot;&gt;&#39;而 ExpansionTile 是 Material 风格的封装。&#39;&lt;/span&gt;,
                  ),
                ),
              ),
            );
          },
        ),
      ),
      floatingActionButton: FloatingActionButton.extended(
        onPressed: () {
          _controller.toggle();
        },
        label: &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; Text(&lt;span class=&quot;hljs-string&quot;&gt;&#39;toggle&#39;&lt;/span&gt;),
        icon: &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; Icon(Icons.swap_vert),
      ),
    );
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-id=&quot;heading-29&quot;&gt;无障碍&lt;/h2&gt;
&lt;h3 data-id=&quot;heading-30&quot;&gt;ProgressIndicator&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ProgressIndicator&lt;/code&gt; 的 &lt;code&gt;semanticsValue&lt;/code&gt; 现在支持类似 &lt;code&gt;50%&lt;/code&gt; 的百分比字符串，之前 progress bar 语义检查更偏向数值区间，现在对百分比文本有了明确支持：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-dart&quot; lang=&quot;dart&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; LinearProgressIndicator(
  value: &lt;span class=&quot;hljs-number&quot;&gt;0.5&lt;/span&gt;,
  semanticsLabel: &lt;span class=&quot;hljs-string&quot;&gt;&#39;文件上传进度&#39;&lt;/span&gt;,
  semanticsValue: &lt;span class=&quot;hljs-string&quot;&gt;&#39;50%&#39;&lt;/span&gt;,
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同样适用于 &lt;code&gt;CircularProgressIndicator&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-dart&quot; lang=&quot;dart&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; CircularProgressIndicator(
  value: &lt;span class=&quot;hljs-number&quot;&gt;0.75&lt;/span&gt;,
  semanticsLabel: &lt;span class=&quot;hljs-string&quot;&gt;&#39;同步进度&#39;&lt;/span&gt;,
  semanticsValue: &lt;span class=&quot;hljs-string&quot;&gt;&#39;75%&#39;&lt;/span&gt;,
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-id=&quot;heading-31&quot;&gt;Slider&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Slider&lt;/code&gt; 修复了语义节点尺寸问题， &lt;code&gt;_RenderSlider.assembleSemanticsNode&lt;/code&gt; 会把语义 rect 设置为以 thumb center 为中心、大小为 &lt;code&gt;kMinInteractiveDimension&lt;/code&gt; 的区域：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-dart&quot; lang=&quot;dart&quot;&gt;Slider(
  value: volume,
  min: &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;,
  max: &lt;span class=&quot;hljs-number&quot;&gt;100&lt;/span&gt;,
  divisions: &lt;span class=&quot;hljs-number&quot;&gt;20&lt;/span&gt;,
  label: &lt;span class=&quot;hljs-string&quot;&gt;&#39;&lt;span class=&quot;hljs-subst&quot;&gt;${volume.round()}&lt;/span&gt;&#39;&lt;/span&gt;,
  onChanged: (&lt;span class=&quot;hljs-built_in&quot;&gt;double&lt;/span&gt; value) {
    setState(() =&amp;gt; volume = value);
  },
  semanticFormatterCallback: (&lt;span class=&quot;hljs-built_in&quot;&gt;double&lt;/span&gt; value) {
    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&#39;音量 &lt;span class=&quot;hljs-subst&quot;&gt;${value.round()}&lt;/span&gt;%&#39;&lt;/span&gt;;
  },
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其他还有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;PopupMenuButton&lt;/code&gt; 和 &lt;code&gt;DropdownButton&lt;/code&gt; 的 expanded state 语义更新修复，避免展开状态没有正确同步&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PinnedHeaderSliver&lt;/code&gt; 修复语义焦点捕获问题&lt;/li&gt;
&lt;li&gt;不可见 semantics 节点从语义树中移除时的崩溃被修复&lt;/li&gt;
&lt;li&gt;自动播放视频预览：通知用户是否已禁用视频预览的自动播放&lt;/li&gt;
&lt;li&gt;优先使用不闪烁光标：允许 App 为那些觉得闪烁光标分散注意力或难以跟踪的用户提供稳定的、不闪烁的文本指示器&lt;/li&gt;
&lt;li&gt;自动播放动画图像 ：检测用户何时选择暂停自动播放 GIF 或其他动画内容&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-id=&quot;heading-32&quot;&gt;最后&lt;/h2&gt;
&lt;p&gt;可以看出来，这个版本更新了很多，最核心就是样式库已经完成初步解耦落地，后续样式跟进和液态玻璃效果就能快很多了，同时这也是一个充满 AI Coidng 场景的更新，当然最可惜的还是桌面的依然不合并到 Stable ，虽然我已经用了一段时间了。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;貌似关注过我的，基本已经提前看到大半的 3.44 更新了吧？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;那么，更新吧骚年，是时候勇敢的吃螃蟹了。&lt;/p&gt;</description><link>https://juejin.cn/post/7641896054782672915</link><guid isPermaLink="false">https://juejin.cn/post/7641896054782672915</guid><pubDate>Thu, 21 May 2026 01:05:30 GMT</pubDate><author>恋猫de小郭</author><category></category><category>Flutter</category><category>Android</category><category>iOS</category></item><item><title>2026 Google I/O ，意料之外的 Antigravity 2.0 和消失的 Gemini CLI</title><description>&lt;p&gt;在刚刚过去的 Goolge I/O，其实我觉得最有意思的就是 Antigravity 2.0，虽然大家过去一年的时间里都在吐槽 Antigravity，但是现在它被扶正了，&lt;strong&gt;直接干掉了 Gemini CLI  这个绝对是大多数人意想不到的&lt;/strong&gt;，果然青梅足马敌不过天降。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/fb0c85033b204c78907697e6adec9d76~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780445583&amp;amp;x-signature=DOARF4ec0jBPepPzAu4EqMwCwCI%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;看来谷歌也知道 Gemini CLI 太垃圾了，所以把战略都转向 Antigravity&lt;/strong&gt; ，这次 Antigravity 的定位是 &lt;strong&gt;agent-first development platform&lt;/strong&gt;，这也是头部 AI Coding 产品里，最后一个 AI IDE 正式宣布放弃 IDEA 入口，转向 agent 管理入口了：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/a6466b46999c4408b7609abe2bcd0f8d~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780445583&amp;amp;x-signature=QeCMKgm3NWnxQzM75lLhDjOuwKo%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Codex App，Copilot App，Cursor 3，Trae Solo 都转向了 Agent 管理 UI ，这次 Antigravity 2.0 也是最后一个完成调整的了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;这一次 Antigravity 2.0 的核心是多个 agent 可以并行执行任务、生成代码、测试、验证、部署，同时跨 Google AI Studio、Android、Firebase 等开发场景协作&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;说人话就是，以前的 Antigravity 是 「带 Agent Manager 的 IDE」，&lt;strong&gt;而现在 Antigravity 2.0 则是 「Agent 工作台 + CLI + SDK + 云端托管 Agent 的基础设施」。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/efab9898ce5d4e4db693939cb44f7fd4~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780445583&amp;amp;x-signature=2FHnkA3pW9bgmVqPAGvRkBn4lqQ%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;现在的 Antigravity 2.0 不再强调说明代码补全，而是 &lt;strong&gt;standalone desktop application&lt;/strong&gt;，核心在于「集中管理、定制和编排 coding agents」，你可以让 agent 进行代码重构、生成单元测试、按 spec 搭建服务组件，甚至从一个 prompt 派生 subagents，让多个任务并行运行。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这也是熟悉的场景了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/3f0510fd696540dbb1f95fb27d1ea956~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780445583&amp;amp;x-signature=sy4M9Pg6bRJygsTvwGlxYM8rwS4%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;另外，2.0 支持 &lt;strong&gt;dynamic subagents for parallelized workflows&lt;/strong&gt; ，也就是你发出一个复杂任务后，主 agent 自己会拆分出多个子 agent 并行处理不同部分，比如一个负责改后端，一个负责改前端，一个负责写测试，一个负责跑浏览器验证：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/08fb14888ad74d03b4ecf51a2e695dc7~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780445583&amp;amp;x-signature=JDFsgA4a0K%2F5cyS%2BMh094uh%2BdmI%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;另外，&lt;strong&gt;这次还新增加了 Scheduled Tasks，也就是 Agent 可以后台自动跑任务&lt;/strong&gt;，这就有点像 OpenClaw 场景了。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/2755a81081964f749229ccdd268f09b5~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780445583&amp;amp;x-signature=wswGF%2F7xSSIo%2B6DZnOnwXuW0wrA%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;这次 2.0 支持的 &lt;strong&gt;scheduled tasks for background automation&lt;/strong&gt;，就是可以让它按计划跑一些任务，例如定期检查 issue、跑测试、更新依赖、生成报告、重构某个模块、补测试覆盖。&lt;/p&gt;
&lt;p&gt;这个方向其实和 Gemini Spark 的个人 agent 思路是同一条线，&lt;strong&gt;因为 Google 这次把 Spark 做成 24/7 后台 agent，而 Antigravity  则是提供 coding agent 平台能力，这两者都是属于「长期运行、可调度、可授权、可观察」的 agent 产品思想&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/f15f04763d69418f97b09191749bc8ac~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780445583&amp;amp;x-signature=x6lzyqznM34PqcNSStZECrl4U7c%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;这页算是它和 Cursor / Copilot 目前最大区别之一，「The agent team in action, starting to build the OS」，例如官方展示的在构建自定义 Doom 操作系统的超大规模演示中（93 个子代理、15,000+ 次模型请求）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sentinel 子代理通过 Scheduled Tasks（后台 cron）持续监控其他子代理的进度文件&lt;/li&gt;
&lt;li&gt;一旦某个子代理卡住（无限循环、编译卡死、I/O 阻塞），自动终止并重启，实现&lt;strong&gt;自我修复的多代理团队&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/83a5d5ce31384a97a70a83059584ecae~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780445583&amp;amp;x-signature=tMmvO38k7ld3kaLiePtgGZp%2BkL8%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;在对话中输入 /schedule ，可设置一次性定时器 或 recurring cron 计划，任务在后台异步运行（支持长期自主执行）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;另外一个核心就是 Antigravity CLI，是的， Gemini CLI 凉了&lt;/strong&gt;，现在是全新的  Antigravity CLI ，谷歌终于是发现自己的 Gemini CLI 不行了，而现在 Antigravity CLI  等于是把完整 Antigravity  能力下放到命令行：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;same harness, same agent, same quality of intelligence as Antigravity 2.0&lt;/strong&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;另外它和 Claude 场景类似，能和桌面 app 深度集成，共享认证、上下文、skills 和配置，等于是 &lt;strong&gt;CLI 是 agent 的执行器，而 GUI 是 agent 的调度和审查的 GUI 场景&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/41f04648c43f49058a118e40b0d9f472~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780445583&amp;amp;x-signature=oNQufuomC9iUeDSQJK4%2BsZHHI%2F4%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;同时你可以在 CLI 里启动、执行、快速交互， 在桌面 app 里看任务、并行状态、artifact、审批，最后在 IDE 里做细节编辑，&lt;strong&gt;另外还可以用 SDK 把 agent 能力嵌入自己的平台&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/bab00eac93094ca1bb8c82656dc1225c~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780445583&amp;amp;x-signature=34flNeC%2BONLFTLAU79eWOxvn4Gc%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;需要注意的是，2026 年 6 月 18 日，&lt;strong&gt;Gemini CLI 和 Gemini Code Assist IDE 将停止使用&lt;/strong&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;另外，&lt;strong&gt;这次发布的还有 Antigravity SDK&lt;/strong&gt;，Antigravity SDK  提供对 Google agent harness 的程序化访问，它可以让开发者定义 custom agent behaviors，并把它部署到自己选择的基础设施上。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs language-python&quot; lang=&quot;python&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; asyncio
&lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt; google.antigravity &lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; Agent, LocalAgentConfig

&lt;span class=&quot;hljs-keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;main&lt;/span&gt;():
    config = LocalAgentConfig()
    &lt;span class=&quot;hljs-keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;with&lt;/span&gt; Agent(config) &lt;span class=&quot;hljs-keyword&quot;&gt;as&lt;/span&gt; agent:
        response = &lt;span class=&quot;hljs-keyword&quot;&gt;await&lt;/span&gt; agent.chat(&lt;span class=&quot;hljs-string&quot;&gt;&quot;What files are in the current directory?&quot;&lt;/span&gt;)
        &lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;await&lt;/span&gt; response.text())

&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; __name__ == &lt;span class=&quot;hljs-string&quot;&gt;&quot;__main__&quot;&lt;/span&gt;:
    asyncio.run(main())
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;所以这次发布的 Antigravity SDK，目的是为了让开发者基于 Google coding tool 构建 custom agents / custom workflows，这场景也和 Claude SDK 提供的如出一辙。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/c32816cde2bd41eb909c0488bcc46a11~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780445583&amp;amp;x-signature=kdL%2BBb7%2BH1zeKtGq5uWsEOy%2FbMk%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;另外，这次还有 Managed Agents in Gemini API&lt;/strong&gt;，Antigravity Agent 被云端 API 化，也就是说现在 Gemini API 支持 managed agents，开发者可以用一个 API call 启动一个能 reasoning、用工具、执行代码的 agent，它基于 Antigravity agent 驱动，基于 Gemini 3.5 Flash，可通过 Interactions API 和 Google AI Studio 使用。&lt;/p&gt;
&lt;p&gt;官方目前列出的能力包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;reason、plan、call tools&lt;/li&gt;
&lt;li&gt;在 isolated Linux sandbox 里执行代码和管理文件&lt;/li&gt;
&lt;li&gt;浏览 web 获取和处理实时数据&lt;/li&gt;
&lt;li&gt;每次 interaction 可以创建或接收一个 environment&lt;/li&gt;
&lt;li&gt;follow-up calls 可以恢复 session，保留文件和状态&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这其实也很像「云端 Codex sandbox / Claude Code remote runner / OpenClaw-like agent runtime」 的 Google 版本，区别是 Google 把它做进了 Gemini API，支持你用 &lt;strong&gt;AGENTS.md 和 SKILL.md&lt;/strong&gt; 定义自己的 agent instruction、skills、data，并注册成 managed agent。&lt;/p&gt;
&lt;p&gt;另外一个有意思的就是，这次 Google 给 AI Studio 加了 Antigravity export tool，&lt;strong&gt;也就是开发者可以把现有项目导出到本地 Antigravity&lt;/strong&gt;，这次的产品思路很直观：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI Studio：快速试想法 / prompt 原型 / Android vibe coding&lt;/li&gt;
&lt;li&gt;Antigravity：接管工程化开发 / 多 agent 修改 / 测试验证&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最后就是价格，这次谷歌新增加了 **Google AI Ultra &lt;span class=&quot;math math-inline&quot;&gt;&lt;span class=&quot;katex&quot;&gt;&lt;span class=&quot;katex-mathml&quot;&gt;&lt;math xmlns=&quot;http://www.w3.org/1998/Math/MathML&quot;&gt;&lt;semantics&gt;&lt;mrow&gt;&lt;mn&gt;100&lt;/mn&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;/&lt;/mi&gt;&lt;mtext&gt;月&lt;/mtext&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mo&gt;∗&lt;/mo&gt;&lt;mtext&gt;，方案会给&lt;/mtext&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;n&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;v&lt;/mi&gt;&lt;mi&gt;i&lt;/mi&gt;&lt;mi&gt;t&lt;/mi&gt;&lt;mi&gt;y&lt;/mi&gt;&lt;mtext&gt;比&lt;/mtext&gt;&lt;mi&gt;G&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mi&gt;g&lt;/mi&gt;&lt;mi&gt;l&lt;/mi&gt;&lt;mi&gt;e&lt;/mi&gt;&lt;mi&gt;A&lt;/mi&gt;&lt;mi&gt;I&lt;/mi&gt;&lt;mi&gt;P&lt;/mi&gt;&lt;mi&gt;r&lt;/mi&gt;&lt;mi&gt;o&lt;/mi&gt;&lt;mtext&gt;高&lt;/mtext&gt;&lt;mn&gt;5&lt;/mn&gt;&lt;mi&gt;X&lt;/mi&gt;&lt;mtext&gt;的使用限制，并且限时提供&lt;/mtext&gt;&lt;/mrow&gt;&lt;annotation encoding=&quot;application/x-tex&quot;&gt;100/月** ，方案会给 Antigravity 比 Google AI Pro 高 5X 的使用限制，并且限时提供 &lt;/annotation&gt;&lt;/semantics&gt;&lt;/math&gt;&lt;/span&gt;&lt;span class=&quot;katex-html&quot; aria-hidden=&quot;true&quot;&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:1em;vertical-align:-0.25em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;100/&lt;/span&gt;&lt;span class=&quot;mord cjk_fallback&quot;&gt;月&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mbin&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mspace&quot; style=&quot;margin-right:0.2222em;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;base&quot;&gt;&lt;span class=&quot;strut&quot; style=&quot;height:0.8889em;vertical-align:-0.1944em;&quot;&gt;&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;∗&lt;/span&gt;&lt;span class=&quot;mord cjk_fallback&quot;&gt;，方案会给&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.02778em;&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;mord cjk_fallback&quot;&gt;比&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;G&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;oo&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.03588em;&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.01968em;&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.07847em;&quot;&gt;I&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.13889em;&quot;&gt;P&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot;&gt;ro&lt;/span&gt;&lt;span class=&quot;mord cjk_fallback&quot;&gt;高&lt;/span&gt;&lt;span class=&quot;mord&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;mord mathnormal&quot; style=&quot;margin-right:0.07847em;&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;mord cjk_fallback&quot;&gt;的使用限制，并且限时提供&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;100 Antigravity bonus credits ：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/2d66500b3b334152b7558f7ec52b9743~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780445583&amp;amp;x-signature=4%2FnxEZdUj2tIMgcuanumvREY9Gw%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;对应的 Ultra 现在是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;AI Ultra $100&lt;/strong&gt;：面向开发者/高级用户，Antigravity 额度比 Pro 高 5X&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;AI Ultra $200&lt;/strong&gt;：顶级方案，Gemini app 和 Antigravity 额度比 Pro 高 20X&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;比如这次的 Gemini Spark 就需要 AI Ultra ：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/f2176aa2dbb94125991e57181223c1fc~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780445583&amp;amp;x-signature=q7L%2FVxICtpTY5aiwgUndptnjvZk%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;p&gt;整体的方案价格如下所示：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/82c500e02cc24c10ba8e06eaf62254c9~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5oGL54yrZGXlsI_pg60=:q75.awebp?rk3s=f64ab15b&amp;amp;x-expires=1780445583&amp;amp;x-signature=5mxnl9OB9fwZsaAcl1coOgwTvd4%3D&quot; alt=&quot;&quot; loading=&quot;lazy&quot; referrerpolicy=&quot;no-referrer&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Pro / Ultra 用户会有 priority access，额度每 &lt;strong&gt;5 小时刷新&lt;/strong&gt;，而免费用户则改成更大的 weekly-based rate limit。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;不过有点难以接受的是，这次官方强调 &lt;strong&gt;Antigravity 的用量不是按请求数或代码行数算&lt;/strong&gt;，而是和 agent 做了多少“work”相关，简单任务消耗少，复杂推理任务消耗多，所以额度消耗还是一个迷之统计情况。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;当然，Pro 肯定没事生产力就是了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;总的来说，这次 Google Antigravity  主要就是围绕了  Antigravity CLI、Antigravity SDK、Antigravity IDE 这个几个场景展开，当然也没什么太多新东西，更多是跟上了主流的节奏，不得不说谷歌的反应还是一如既往的慢，不过至少是跟上了，也算是憋了个大的。&lt;/p&gt;
&lt;p&gt;那么，你更新了 Antigravity 2.0 了吗？？？&lt;/p&gt;</description><link>https://juejin.cn/post/7641409122263285766</link><guid isPermaLink="false">https://juejin.cn/post/7641409122263285766</guid><pubDate>Wed, 20 May 2026 00:17:06 GMT</pubDate><author>恋猫de小郭</author><category>人工智能</category><category>前端</category><category>AI编程</category></item></channel></rss>