<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>AI 编程 on Trevor's Blog</title><link>http://hitrevor.com/tags/ai-%E7%BC%96%E7%A8%8B/</link><description>Recent content in AI 编程 on Trevor's Blog</description><generator>Hugo</generator><language>zh-CN</language><lastBuildDate>Thu, 12 Nov 2026 09:20:00 +0800</lastBuildDate><atom:link href="http://hitrevor.com/tags/ai-%E7%BC%96%E7%A8%8B/index.xml" rel="self" type="application/rss+xml"/><item><title>DeepSeek Harness 的代码审阅：瓶颈根本不在 git</title><link>http://hitrevor.com/posts/dsh-worktree-review/</link><pubDate>Thu, 12 Nov 2026 09:20:00 +0800</pubDate><guid>http://hitrevor.com/posts/dsh-worktree-review/</guid><description>DeepSeek Harness 0.2.2-rc.2 加了按分支、提交、文件类型审阅。我在 21,711 个文件的仓库上把每一环量了一遍：建工作树 1.5 秒，28,458 行 diff 只要 75 毫秒，真正装不下的是三十万 token 的上下文。</description><content:encoded><![CDATA[<p>DeepSeek Harness 发了 0.2.2-rc.2，其中一条写着「Git Worktree 支持按分支、提交和文件类型审阅改动」。</p>
<p>我当晚就去升，结果 npm 上根本没有这个版本。</p>
<h2 id="三个地方三个版本号">三个地方三个版本号</h2>
<p>GitHub Releases 上是 dsh-v0.2.2-rc.2，11 日 11:33 发的。我去装，npm 报 notarget。</p>
<p>查了一下 dist-tags，latest 和 next 都还指着 0.2.2-rc.1。</p>
<p><img alt="三个位置，三个版本号" loading="lazy" src="/images/dsh-worktree-review/fig1.png"></p>
<p>桌面端更早，还停在 0.2.1-rc.2。也就是说我机器上同时躺着三个版本号，一个都没到 rc.2。</p>
<p>这不是 DeepSeek Harness 的毛病，发版流程都这样。但它决定了你什么时候能真的用上新功能：要么等 npm 追上，要么去桌面端切开发版渠道，而那个渠道本身就是 rc.2 里新加的。</p>
<h2 id="换个路子自己测">换个路子自己测</h2>
<p>装不上，我就把 DeepSeek Harness 这次要做的事在本机复刻一遍。</p>
<p>工作树、按分支比、按文件类型切，这些底层动作全是 git 命令，跟客户端无关。我用自己那个 21,711 个文件、60,037 次提交的仓库当靶子，旁边配一个 50 个文件的小仓库做对照。</p>
<p>先测最费时间的那一步：建工作树。</p>
<p><img alt="建工作树的耗时" loading="lazy" src="/images/dsh-worktree-review/fig2.png"></p>
<p>小仓库 32 毫秒，跑三次是 31、32、32。</p>
<p>大仓库 1.5 秒，三次 1.47、1.49、1.51，很稳。差了 46 倍。</p>
<p>工作树 checkout 出来占 275 MB，但 .git 是共享的，840 MB 那个仓库没被复制一遍。这点设计省了不少磁盘。</p>
<p>1.5 秒不算长，可如果 agent 每改一次代码就建一个工作树，中间还夹着网络往返、磁盘抖动和一堆看不见的等待，这个 1.5 秒就会变成一个随时可能超时的赌注。release notes 写道「放宽大型仓库创建工作树的等待时间」，说的就是这个 1.5 秒。</p>
<h2 id="三种审阅维度全是毫秒">三种审阅维度，全是毫秒</h2>
<p>我在工作树里造了两轮改动，模拟 agent 干活：40 个文件一轮，240 个文件一轮，累计对主分支 311 个文件、28,458 行。</p>
<p>然后按它说的三个维度各比一遍。</p>
<p><img alt="三种审阅维度的耗时" loading="lazy" src="/images/dsh-worktree-review/fig3.png"></p>
<p>按分支看统计，65 毫秒。全量正文，75 毫秒。按文件类型聚合，29 毫秒。按提交看日志，26 毫秒。</p>
<p>四个维度全在百毫秒以内，git 层面没有一处是慢的。</p>
<p>这里有个反直觉的地方。28,458 行、1.27 MB 的 diff，git 算出来只要 75 毫秒，我原本以为它会是大头，结果它是全场最快的那个。</p>
<h2 id="基线选错审的是空气">基线选错，审的是空气</h2>
<p>这里我踩了个坑，值得写出来。</p>
<p>第一次跑对比，我用的是 <code>git diff main...HEAD</code>。三个点，意思是拿两个分支的共同祖先比。结果输出 0 个文件。</p>
<p>原因很简单：我那个仓库的本地 main 早就落后，HEAD 本身就是 main 的一个祖先。共同祖先算出来是 HEAD 自己，自己跟自己比，当然是空的。</p>
<p>换成 <code>origin/main...HEAD</code>，立刻变成 311 个文件。</p>
<p>同一个仓库，同一个分支，只换基线，从 0 变成 311 个文件。</p>
<p>所以「按分支审阅」这件事，真正需要小心的不是 diff 慢不慢，是它到底在跟谁比。agent 的分支如果是从一个旧基线上拉出来的，你审出来的东西会少一大截，而且不会有任何提示。</p>
<p>三个点比共同祖先，两个点比两个端点。这个区别平时不重要，一旦交给 agent 自动审阅，就变成了能不能看见改动的分水岭。</p>
<h2 id="那-28458-行怎么读">那 28,458 行怎么读</h2>
<p>既然 git 不慢，慢的必然是别处。把 diff 按扩展名拆开，答案就浮出来了。</p>
<p><img alt="改动按文件类型的分布" loading="lazy" src="/images/dsh-worktree-review/fig4.png"></p>
<p>Python 187 个文件、12,468 行，占 43%。JSON 52 个文件、5,690 行，占 20%。TypeScript 46 个文件、2,647 行。TSX 12 个文件、1,526 行。</p>
<p>有意思的是 JSON 那 5,690 行。锁文件、契约快照、配置导出，占了五分之一的行数，但真正要逐行读的不到百分之五。</p>
<p>按文件类型审阅这件事，价值不在于分类好看，在于它让你有理由跳过一整个 5,690 行的文件夹。</p>
<h2 id="工作树省的不是磁盘">工作树省的不是磁盘</h2>
<p>我原本以为工作树会占很多盘，实测下来这个担心多余。</p>
<p>21,711 个文件、840 MB 的 .git，建出来的工作树只占 275 MB。因为 .git 是共享的，复制出去的只有工作区文件。</p>
<p>这 275 MB 买到的是一份隔离：同一个仓库里可以有多个工作树，各自挂在不同的分支上，互不干扰。agent A 在 feat-a 上改代码，agent B 在 feat-b 上改另一处，两边的工作区和索引都是各自独立的。</p>
<p>换成沙盒或者整个仓库副本，你要付的是 840 MB 的磁盘加几十秒的拷贝时间，而工作树付的只是 1.5 秒，还顺带把分支隔离这件事免费送给了你。</p>
<p>这也是它把审阅做在工作树上的原因。分支在那儿，提交在那儿，文件也在那儿，按哪个维度切都是现成的原料。</p>
<h2 id="瓶颈在上下文不在工具">瓶颈在上下文，不在工具</h2>
<p>把每一环的数字摆在一起，结论就很清楚。</p>
<p><img alt="每一环的量级" loading="lazy" src="/images/dsh-worktree-review/fig5.png"></p>
<p>建工作树 1.5 秒。产出 diff 75 毫秒。</p>
<p>把这份 diff 交给模型，1,268,059 个字符，粗算三十万 token。</p>
<p>三十万 token 是什么概念？现在主流模型的上下文窗口在二十万上下，这一个改动的 diff 就装不下，还没算上仓库结构、任务描述和你的提问。</p>
<p>所以 rc.2 那句「减少查看大型改动时的卡顿」，官方描述指出卡的不是 git，是把这堆东西渲染出来、送进模型、再让人读的那一层。前面几个毫秒级的数字再怎么优化都没用，因为真正的天花板在这里。</p>
<p>按文件类型、按提交、按分支，这三条路径本质上是三种切法。切得动，模型才读得完。</p>
<h2 id="另一条我还没试的">另一条我还没试的</h2>
<p>rc.2 还加了两件事：SubAgent 支持具名与多层协作，AgentTeam 可以按会话开启，共用成员和任务面板。</p>
<p>这个我没法在本机复刻，因为它不是 git 层面的事，是编排层的事。而且 npm 上装不到 rc.2，我手上只有 rc.1，跑出来也不是 rc.2 的行为。</p>
<p>所以我只写我验过的部分。这条留给能用上的人。</p>
<h2 id="你现在可以做的">你现在可以做的</h2>
<p>如果你的 agent 已经开始在分支上干活，有两件事现在就能改。一是给工作树准备一块快的盘，1.5 秒里大半是磁盘 IO，放在机械盘或者网络盘上会更慢。</p>
<p>二是先看统计再看正文。312 行和 28,458 行之间差 90 倍，先读前者，能过滤掉一半不需要看的文件。</p>
<p>至于 DeepSeek Harness 的 rc.2，等 npm 追上就行。装上之后第一件事建议是拿自己最大的那个仓库跑一遍建工作树，看看你那台机器上是 1.5 秒还是 15 秒。</p>
<p>这个数字决定了你以后要不要让它频繁开分支，也决定了你的流水线里能不能跑多个 agent 并行改同一份代码。一台机器上 1.5 秒和 15 秒的差别，最终会变成流水线里「三个 agent 一起跑」还是「老实一个一个来」这样两种完全不同的架构选择。</p>
]]></content:encoded></item><item><title>交完 25 美元才知道，Google Play 给自己装应用不要钱</title><link>http://hitrevor.com/posts/gplay-personal/</link><pubDate>Mon, 26 Oct 2026 09:31:22 +0800</pubDate><guid>http://hitrevor.com/posts/gplay-personal/</guid><description>10 月谷歌给 Google Play 开了个新入口：对着 AI 说句话生成的应用，不用开发者账号、不用 25 美元、不过审核，扫码就装。代价是只有你自己能装。</description><content:encoded><![CDATA[<p>十月我为了一个开发者账号忙了小半个月。25 美元报名费，身份验证要政府签发的证件，付款资料的地址必须和证件上一字不差，新注册的个人号还得先找 12 个测试人员连续挂满 14 天，中途账号还被封过一次，重新走了一遍流程。这三件事我都写过。</p>
<p>就在我跑这些流程的时候，10 月 13 日，谷歌在 Play 的产品博客上发了一篇更新，标题是 New on Google Play: More ways to create, discover, and play。</p>
<p>里面有这么一句。</p>
<blockquote>
<p>Using Google AI Studio, you can vibe code a custom Android app. Since many of these apps start out as personal projects, through Google Play you can now launch these personal apps on your own device. This means your creations stay private, secure, and separate from the public store catalog. You only need your standard Google account to do so — no developer account required.</p>
</blockquote>
<p>用大白话说，对着 AI 说几句话生成一个安卓应用，点一下发布，扫个二维码，应用就装到你手机上了。不用开发者账号，不用 25 美元，不用审核。</p>
<p>同一个 Google Play，两套门槛。</p>
<p><img alt="开发者账号和个人库，同一个 Google Play 上的两套门槛" loading="lazy" src="/images/gplay-personal/gplay-two-doors.png"></p>
<h2 id="这条路具体怎么走">这条路具体怎么走</h2>
<p>Play Console 的帮助中心新开了一页，标题叫 Personal library apps in Google Play，把步骤写得很细。</p>
<p>在电脑浏览器打开 Google AI Studio，用你的个人 Google 账号登录。点 New app，选 Build an Android app，输入你想做什么。生成预览之后，右上角点 Publish。第一次用要连一下 Google 账号，然后点 Create app。</p>
<p>几分钟后，屏幕上出现一个二维码。</p>
<p>手机用同一个 Google 账号登录过 Play 商店，扫这个码，装。</p>
<p>不想扫码也行，路径是 Play 商店应用里点个人资料，管理应用和设备，找到 Your personal library，里面就是你自己做的应用，点安装。更新也一样，回 AI Studio 改 prompt，点 Update app，手机上自动更新。</p>
<p>整个过程我最想确认的是那句 no developer account required。官方帮助页写得更死。</p>
<blockquote>
<p>You only need a Google Account to get started.</p>
</blockquote>
<p>一句话，一个账号，一个二维码。</p>
<p><img alt="从一句 prompt 到装进手机，官方帮助页写的五步" loading="lazy" src="/images/gplay-personal/gplay-flow.png"></p>
<h2 id="有开发者账号的人反而用不了">有开发者账号的人反而用不了</h2>
<p>这是我读到最意外的一条，官方帮助页单列了一个问答。</p>
<blockquote>
<p>Owners of Google Play Console developer accounts will need to use a different Google Account to use this feature.</p>
</blockquote>
<p>意思是，如果你已经有 Play Console 开发者账号，想用这个功能，得换一个 Google 账号。</p>
<p>谷歌没解释原因。我的理解是账户体系要隔离，个人库里的东西不能和你在 Play Console 里以开发者身份提交的应用混在一起，否则你用一个号既能提交公开应用又能绕过审核装私人应用，边界就糊了。这是我的推断，官方没写。</p>
<p>但对开发者来说这个体验挺怪的。你为了正经发布交过 25 美元，现在想顺手给自己做个小工具，反而要再注册一个账号。</p>
<h2 id="私人这两个字要打个引号">「私人」这两个字要打个引号</h2>
<p>官方反复强调私人这两个字。不进公开目录，不出现在搜索结果、榜单和推荐里，只能你自己装。</p>
<p>但它不等于谷歌看不见。</p>
<p>帮助页末尾那段写得很清楚，当你在 AI Studio 里创建、修改或发布应用时，工具会把这些东西传给 Google Play：应用的包、创建过程的元数据（包括 prompt）、AI 生成标记、软件依赖和 SDK、用户可见的字符串，还有源代码。</p>
<p>拿去干什么？官方列了四项：安全扫描、滥用防护、政策合规，以及训练和改进自动化的应用安全分类器。</p>
<p>所以你写的每一句 prompt，AI 生成的每一行 Kotlin，都在谷歌的扫描管道里过了一遍。免的是人工审核和上架流程，不是数据采集。</p>
<p>这条我建议大家读原文，因为「私人」在中文语境里容易被读成「没人管」。</p>
<h2 id="审核是免了但不是没规矩">审核是免了，但不是没规矩</h2>
<p>同一页列了明确的内容禁区，个人应用一样不能碰。</p>
<p>不能做银行、贷款、加密货币、真钱赌博、政府服务这几类高风险业务。不能申请无障碍服务、短信和通话记录、绑定通知、请求安装应用这类敏感权限。不能侵犯第三方知识产权，不能冒充已有品牌、政府机构或个人。不能含恶意软件、间谍软件、钓鱼、未授权的数据采集，也不能有仇恨言论、色情内容和暴力。</p>
<p>违规的后果是应用从 AI Studio 里被移除，屡次违规会终止你对 AI Studio 的访问权限。</p>
<p>免审只是省掉了排队和人工核对，该守的线一条没少。区别在于以前是谷歌在上架前拦，现在是你自己撞上去才处理。</p>
<h2 id="它生成的是个什么工程">它生成的是个什么工程</h2>
<p>这部分我对写代码的人有用。</p>
<p>AI Studio 生成的是一套标准 Gradle 项目，构建脚本用 build.gradle.kts 的 Kotlin DSL，界面层是 Jetpack Compose 配 Material 3，架构是单 Activity 加 ViewModel 和数据类，还带 AndroidManifest、drawable、strings 这些资源文件。</p>
<p>开了 Firebase 的话会多出 google-services.json、firebase_applet_config.xml 和 firestore.rules。依赖由 agent 自己从 Maven 和谷歌仓库里加。</p>
<p>你可以下载成 ZIP，导进 Android Studio 接着改。</p>
<p>限制也写得很直白，四条。</p>
<p>只有客户端，没有服务端组件，涉及密钥管理、多人协作、Google Workspace 接口的功能都做不了。单 Activity 单 module，结构超过这个规模就不行。只认 Kotlin 和 Jetpack Compose，Java 和 XML 布局不支持。没有 NDK，C 和 C++ 进不来。可穿戴和 Android TV 也不支持，只有手机和平板。</p>
<p>还有个细节挺有意思，浏览器里的模拟器是跑在云端的，你不需要装 Android SDK、Android Studio 或者本地模拟器。但它不支持相机、NFC、蓝牙，GPS 是模拟的，而且没有 Google Play services，谷歌登录和地图在模拟器里用不了，得装到真机才正常。</p>
<p>这套工程的上限很清楚，适合做个人工具、小应用、原型，不适合往上叠大工程。</p>
<p><img alt="AI Studio 生成的安卓工程结构，以及官方列出的四条硬限制" loading="lazy" src="/images/gplay-personal/gplay-limits.png"></p>
<h2 id="同一个按钮两条路">同一个按钮，两条路</h2>
<p>写到这里我发现最值得讲的是 AI Studio 里那个 Publish 按钮的解释。</p>
<p>它有两条出口。一条通向个人库，零门槛，只有你能装。另一条通向 Play Console 的内测轨道，需要 25 美元的开发者账号和完整开发者资料，最多能给 100 个测试人员装。</p>
<p>同一个界面，同一次生成，两套规则差别这么大。</p>
<p>谷歌在博客里把后续路径也铺好了。未来几个月，你可以把个人应用分享给一小圈朋友和家人，那时候应用要先过一遍 Trust &amp; Safety 审核。如果你想让全世界都能用，可以升级成完整开发者账号，个人库里的所有应用会迁移到 Play Console，变成内测轨道上的草稿应用。</p>
<p>我读这段的感觉是，谷歌在把「做个小工具自己用」和「做一个产品给人用」拆成了两个完全不同的入口，中间留了一条升级通道。</p>
<p>以前只有后者，你想给自己手机装个 AI 刚生成的东西，得先变成开发者。现在前者单独开了门，代价是你得先承认自己不是开发者。</p>
<p><img alt="谷歌铺好的三级台阶：个人库、分享给朋友家人、升级开发者账号" loading="lazy" src="/images/gplay-personal/gplay-stairs.png"></p>
<h2 id="这功能现在中国用不了">这功能现在中国用不了</h2>
<p>这个功能现在是 beta，只对美国地区的 18 岁以上用户开放，未来几周内逐步铺开。Play 商店应用要 53.5 以上版本。其他国家「near future」，官方没给时间表。</p>
<p>我这边不在支持的地区，功能没摸到。上面这些流程、限制、原文，全部来自三份官方文档：10 月 13 日的 Play 产品博客、Play Console 帮助页的 Personal library apps in Google Play、以及 AI Studio 的安卓构建文档。哪句话是官方原文，哪句是我的推测，正文里都标了。</p>
<p>那问题来了。</p>
<p>如果以后你在美国的朋友对着 AI 说几句话就把应用装上了，而你还在为 12 个测试人员连挂 14 天发愁，你会去注册一个普通 Google 账号绕过去吗？还是说，这 25 美元和那五道关，本来买的就是「能给别人装」这个资格？</p>
<p>再想一层。谷歌这次拆的其实只是「给自己用」这半堵墙，另一半一动不动。等到哪天 vibe coding 出来的人都想分享给朋友了，这道 Trust &amp; Safety 审核会不会又变成新的五道关？</p>
<p>你手上有没有那种「就我自己用，但一直懒得为它开账号」的小工具？如果现在只要一句 prompt 就能装上手机，你会先做一个什么？</p>
]]></content:encoded></item></channel></rss>