<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Performance | Francis Du</title>
    <link>https://francisdu.com/tags/performance/</link>
      <atom:link href="https://francisdu.com/tags/performance/index.xml" rel="self" type="application/rss+xml" />
    <description>💻Data Engineer | 🦀 Rustacean | 📷 Photographer | 🤖Vibe Coder</description>
    <generator>Hugo 0.166.0</generator><language>zh-CN</language><copyright>© Francis Du</copyright><lastBuildDate>Sat, 12 Sep 2026 05:32:00 +0800</lastBuildDate>
    <item>
      <title>wcode v0.6.2：我不再拿 SLOTS 当性能了</title>
      <link>https://francisdu.com/blog/wcode-v0-6-2/</link>
      <pubDate>Sat, 12 Sep 2026 05:32:00 +0800</pubDate>
      <guid>https://francisdu.com/blog/wcode-v0-6-2/</guid>
      <description>&lt;p&gt;前几天我一直盯着 wcode 的并发面板看。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SLOTS&lt;/code&gt; 32，&lt;code&gt;PEAK&lt;/code&gt; 看起来也不低，但实际跑起来还是有一种很奇怪的感觉：数字挺忙，任务不一定真快。&lt;/p&gt;
&lt;p&gt;我把执行链拆开看了一遍，问题就清楚了。&lt;/p&gt;
&lt;p&gt;外层 Tool Slot 只表示请求已经准入。CPU、文件 I/O、&lt;code&gt;cargo&lt;/code&gt;、&lt;code&gt;git&lt;/code&gt;、Language Server 还有各自的线程池或队列，外面 32 个槽位全亮，并不代表里面 32 份工作都在向前跑。&lt;/p&gt;
&lt;p&gt;0.6.2 先把这些资源分开计量和限制。&lt;/p&gt;
&lt;figure class=&#34;content-image&#34;&gt;&lt;img src=&#34;https://francisdu.com/img/wcode/wcode-observatory-full_hu_2e0fc54b6ad597b6.webp&#34; alt=&#34;wcode Project Observatory&#34;loading=&#34;lazy&#34; decoding=&#34;async&#34; srcset=&#34;https://francisdu.com/img/wcode/wcode-observatory-full_hu_2e0fc54b6ad597b6.webp 960w, https://francisdu.com/img/wcode/wcode-observatory-full_hu_77a4ca195d4c7462.webp 1600w&#34; sizes=&#34;(max-width: 900px) calc(100vw - 32px), 900px&#34; width=&#34;1600&#34; height=&#34;5017&#34;&gt;&lt;/figure&gt;&lt;h2 id=&#34;slotscpuio子进程是四件事&#34;&gt;SLOTS、CPU、I/O、子进程是四件事&lt;a class=&#34;heading-anchor&#34; href=&#34;#slotscpuio%e5%ad%90%e8%bf%9b%e7%a8%8b%e6%98%af%e5%9b%9b%e4%bb%b6%e4%ba%8b&#34; aria-label=&#34;章节链接：SLOTS、CPU、I/O、子进程是四件事&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;现在我更愿意把执行路径看成：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Tool admission
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ↓
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Foreground CPU budget
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ↓
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Bounded file I/O pool
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ↓
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Child process / Git probe queues
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;它们有不同的瓶颈。&lt;/p&gt;
&lt;p&gt;前台 CPU 工作线程会取硬件并行度、8 个线程、内存推导上限和请求并行度的最小值。阻塞线程池上限提高到 64，是为了不让大量独立阻塞请求被隐藏的较小线程上限卡住。&lt;/p&gt;
&lt;p&gt;独立文件修改走共享、有界的 I/O Pool；固定形式的 Git 状态和差异检查走独立 Probe Queue，不再和重型编译器进程抢同一组名额。&lt;/p&gt;
&lt;p&gt;默认资源预算下，重型子进程仍然是很小的并发数。因为同时启动 20 个 &lt;code&gt;cargo&lt;/code&gt; 不会 magically 变快，只会把机器打爆。&lt;/p&gt;
&lt;h2 id=&#34;我专门撤回过一个看起来更并行的优化&#34;&gt;我专门撤回过一个“看起来更并行”的优化&lt;a class=&#34;heading-anchor&#34; href=&#34;#%e6%88%91%e4%b8%93%e9%97%a8%e6%92%a4%e5%9b%9e%e8%bf%87%e4%b8%80%e4%b8%aa%e7%9c%8b%e8%b5%b7%e6%9d%a5%e6%9b%b4%e5%b9%b6%e8%a1%8c%e7%9a%84%e4%bc%98%e5%8c%96&#34; aria-label=&#34;章节链接：我专门撤回过一个“看起来更并行”的优化&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;这轮有一件事我觉得挺重要：我试过把热读取也放进更宽的线程池，结果本地配对实验更慢。&lt;/p&gt;
&lt;p&gt;所以撤回了。&lt;/p&gt;
&lt;p&gt;做 Agent Runtime 很容易有一种冲动：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;线程更多 = 更快
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;队列更深 = 吞吐更高
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;并发数更大 = Agent 更强
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;配对结果不好看就撤回。0.6.2 后面的资源调整也基本按这个标准做：先把不同类型的工作隔开，别靠调大一个统一并发值解决所有问题。&lt;/p&gt;
&lt;h2 id=&#34;32-个命令排队时我还希望-read-能进去&#34;&gt;32 个命令排队时，我还希望 Read 能进去&lt;a class=&#34;heading-anchor&#34; href=&#34;#32-%e4%b8%aa%e5%91%bd%e4%bb%a4%e6%8e%92%e9%98%9f%e6%97%b6%e6%88%91%e8%bf%98%e5%b8%8c%e6%9c%9b-read-%e8%83%bd%e8%bf%9b%e5%8e%bb&#34; aria-label=&#34;章节链接：32 个命令排队时，我还希望 Read 能进去&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;如果所有 Tool Slot 都被执行进程占满，Agent 连 &lt;code&gt;read_file&lt;/code&gt;、状态查询这种轻操作都进不来，系统就会出现另一种死锁感。&lt;/p&gt;
&lt;p&gt;所以执行进程类工具在拿总 Tool Slot 前，还要先拿一层 Execution Admission。&lt;/p&gt;
&lt;p&gt;总量是 32 时，执行类请求最多占 28 个槽位，给非执行工具留四个受控余量。单槽位配置则保留一个可用名额，不会把自己完全饿死。&lt;/p&gt;
&lt;p&gt;它不保证固定延迟，但编译队列再长，&lt;code&gt;read_file&lt;/code&gt; 和状态查询至少还有机会进来。&lt;/p&gt;
&lt;h2 id=&#34;明确的错误位置不应该先全仓搜索&#34;&gt;明确的错误位置，不应该先全仓搜索&lt;a class=&#34;heading-anchor&#34; href=&#34;#%e6%98%8e%e7%a1%ae%e7%9a%84%e9%94%99%e8%af%af%e4%bd%8d%e7%bd%ae%e4%b8%8d%e5%ba%94%e8%af%a5%e5%85%88%e5%85%a8%e4%bb%93%e6%90%9c%e7%b4%a2&#34; aria-label=&#34;章节链接：明确的错误位置，不应该先全仓搜索&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;性能不只在 Scheduler。&lt;/p&gt;
&lt;p&gt;我调真实任务时发现另一个很浪费的路径：模型已经拿到了这种信息：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;error[E0308] at src/runtime/harness/context_budget.rs:33:9
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;结果 &lt;code&gt;agent_context&lt;/code&gt; 还先做一遍广域符号检索，再回来读这个明确位置。&lt;/p&gt;
&lt;p&gt;这顺序反了。&lt;/p&gt;
&lt;p&gt;现在带文件和行号的诊断会先经过 Workspace 保护解析，然后直接保留对应源码原文、行范围和 SHA 编辑前置条件。简单位置查询可以暂缓 Repo Graph 扩展；调用方、Impact、架构或显式 Scope 查询仍然走深入路径。&lt;/p&gt;
&lt;p&gt;缺失位置也不会先把一堆无关文件索引起来再告诉我“没找到”。&lt;/p&gt;
&lt;p&gt;这类任务现在先吃掉已有的精确位置，只有问题真的需要跨文件关系时才继续扩图。&lt;/p&gt;
&lt;h2 id=&#34;同一个冷索引也不应该被重复建-10-次&#34;&gt;同一个冷索引也不应该被重复建 10 次&lt;a class=&#34;heading-anchor&#34; href=&#34;#%e5%90%8c%e4%b8%80%e4%b8%aa%e5%86%b7%e7%b4%a2%e5%bc%95%e4%b9%9f%e4%b8%8d%e5%ba%94%e8%af%a5%e8%a2%ab%e9%87%8d%e5%a4%8d%e5%bb%ba-10-%e6%ac%a1&#34; aria-label=&#34;章节链接：同一个冷索引也不应该被重复建 10 次&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;并发 Agent 很容易同时问同一个文件。&lt;/p&gt;
&lt;p&gt;以前多个冷查询可能一起发现“没有索引”，然后各自开始建。&lt;/p&gt;
&lt;p&gt;现在同一 Workspace、同一文件的冷查询会共享正在进行的索引构建。不同文件仍然可以独立执行；失效和版本变化会阻止旧构建结果晚到后重新污染缓存。&lt;/p&gt;
&lt;p&gt;这里没有做增量 Tree-sitter，也没有引入全仓快照，只是把同一份冷索引的重复构建合掉。&lt;/p&gt;
&lt;h2 id=&#34;symbol_context-开始对自己返回的版本负责&#34;&gt;&lt;code&gt;symbol_context&lt;/code&gt; 开始对自己返回的版本负责&lt;a class=&#34;heading-anchor&#34; href=&#34;#symbol_context-%e5%bc%80%e5%a7%8b%e5%af%b9%e8%87%aa%e5%b7%b1%e8%bf%94%e5%9b%9e%e7%9a%84%e7%89%88%e6%9c%ac%e8%b4%9f%e8%b4%a3&#34; aria-label=&#34;章节链接：symbol_context 开始对自己返回的版本负责&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;另一个一致性问题是：索引说 Symbol 在 A，但真正读正文时文件已经变了。&lt;/p&gt;
&lt;p&gt;如果这时还把旧签名和新正文拼成一个结果，Agent 会拿到一个内部自相矛盾的 Context。&lt;/p&gt;
&lt;p&gt;现在 &lt;code&gt;symbol_context&lt;/code&gt; 会核对符号信息和正文是不是同一文件版本。发现旧索引最多重新获取一次；文件持续变化、拿不到稳定版本时，就明确失败。&lt;/p&gt;
&lt;p&gt;我宁愿返回“现在无法稳定读取”，也不想返回一个看起来完整的 Frankenstein Context。&lt;/p&gt;
&lt;h2 id=&#34;验证计划不能静默只跑前八项&#34;&gt;验证计划不能静默只跑前八项&lt;a class=&#34;heading-anchor&#34; href=&#34;#%e9%aa%8c%e8%af%81%e8%ae%a1%e5%88%92%e4%b8%8d%e8%83%bd%e9%9d%99%e9%bb%98%e5%8f%aa%e8%b7%91%e5%89%8d%e5%85%ab%e9%a1%b9&#34; aria-label=&#34;章节链接：验证计划不能静默只跑前八项&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;0.6.2 还修了一个更严重的问题。&lt;/p&gt;
&lt;p&gt;混合语言仓库里，完整验证可能推导出十几项检查。旧路径有一处会静默只取前八项。&lt;/p&gt;
&lt;p&gt;这类优化最危险的地方不是少跑了几个命令，而是上层可能还把已经执行的前缀描述成“完整验证”。&lt;/p&gt;
&lt;p&gt;现在先构造完整计划，整体上限是 32。超限就&lt;strong&gt;在派发前失败&lt;/strong&gt;，明确告诉调用者没有执行检查，而不是偷偷截断。&lt;/p&gt;
&lt;p&gt;验证历史也会在一次请求里共享代码 Revision 和 Evidence Snapshot，减少重复扫描；结果要同时匹配 Code 和 Design State 才能展示为当前有效。&lt;/p&gt;
&lt;p&gt;窄范围检查不能把宽范围失败抹掉，时间戳冲突按失败关闭。Evidence 缺失或扫描截断，也不能被解释成通过。&lt;/p&gt;
&lt;h2 id=&#34;verify_project-可以断线以后再查&#34;&gt;&lt;code&gt;verify_project&lt;/code&gt; 可以断线以后再查&lt;a class=&#34;heading-anchor&#34; href=&#34;#verify_project-%e5%8f%af%e4%bb%a5%e6%96%ad%e7%ba%bf%e4%bb%a5%e5%90%8e%e5%86%8d%e6%9f%a5&#34; aria-label=&#34;章节链接：verify_project 可以断线以后再查&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;项目验证现在还复用了 MCP Tasks 扩展。&lt;/p&gt;
&lt;p&gt;客户端支持 Tasks 时，服务端可以先持久化任务并返回 &lt;code&gt;taskId&lt;/code&gt;，验证继续由 Runtime 管理。客户端断线后，可以拿同一个 ID 查询状态。&lt;/p&gt;
&lt;p&gt;这里我刻意没有加一个模型可见的 &lt;code&gt;async=true&lt;/code&gt; 参数，也没有把断线等同于自动重试。&lt;/p&gt;
&lt;p&gt;因为对带副作用的系统来说，最危险的一句话就是：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;没收到响应，那再执行一遍吧。
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;完成状态只表示底层工具返回了结果，不等于检查通过；调用者还必须读真正的 &lt;code&gt;passed&lt;/code&gt; / error 状态。&lt;/p&gt;
&lt;h2 id=&#34;配置终于开始收敛&#34;&gt;配置终于开始收敛&lt;a class=&#34;heading-anchor&#34; href=&#34;#%e9%85%8d%e7%bd%ae%e7%bb%88%e4%ba%8e%e5%bc%80%e5%a7%8b%e6%94%b6%e6%95%9b&#34; aria-label=&#34;章节链接：配置终于开始收敛&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;wcode 可调参数越来越多以后，另一个问题也很明显：高级参数是给调试和特殊机器用的，不应该逼所有人启动时手写一排数字。&lt;/p&gt;
&lt;p&gt;所以现在有三档常用性能配置：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;balanced
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fast
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;light
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;也可以先预览：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wcode setup --performance fast --dry-run
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wcode --show-config
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;真的执行 Setup 才会保存审核过的启动选项。&lt;/p&gt;
&lt;p&gt;同时新增了：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wcode help-all
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wcode help-all setup
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wcode help-all --json
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;它直接从真实 CLI Parser 生成完整命令和参数目录，包括隐藏高级选项、短参数、别名、默认值和枚举值。&lt;/p&gt;
&lt;p&gt;普通 &lt;code&gt;--help&lt;/code&gt; 继续保持短。我不想为了“可发现性”把日常帮助页重新塞成说明书。&lt;/p&gt;
&lt;h2 id=&#34;webui-首屏也一起收了&#34;&gt;WebUI 首屏也一起收了&lt;a class=&#34;heading-anchor&#34; href=&#34;#webui-%e9%a6%96%e5%b1%8f%e4%b9%9f%e4%b8%80%e8%b5%b7%e6%94%b6%e4%ba%86&#34; aria-label=&#34;章节链接：WebUI 首屏也一起收了&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Observatory 这轮主要改首屏信息层级。&lt;/p&gt;
&lt;p&gt;现在执行活动、待批准请求、工作树变更、当前有效验证结果分开显示。Architecture 入口改成可搜索组件卡片和详情 Inspector，Design / Implementation / Overlay 图仍然保留，但不再要求用户先读一张很大的图才能知道项目现在发生了什么。&lt;/p&gt;
&lt;p&gt;活动刷新也和慢项目刷新拆开。页面隐藏时停止轮询；共享进程资源和当前项目任务分开标记；“没有采样”不再画成“0”。&lt;/p&gt;
&lt;p&gt;我主要想避免一件事：没有数据时别画成一个看起来很健康的数字。&lt;/p&gt;
&lt;h2 id=&#34;做完以后我给自己留了几条检查项&#34;&gt;做完以后，我给自己留了几条检查项&lt;a class=&#34;heading-anchor&#34; href=&#34;#%e5%81%9a%e5%ae%8c%e4%bb%a5%e5%90%8e%e6%88%91%e7%bb%99%e8%87%aa%e5%b7%b1%e7%95%99%e4%ba%86%e5%87%a0%e6%9d%a1%e6%a3%80%e6%9f%a5%e9%a1%b9&#34; aria-label=&#34;章节链接：做完以后，我给自己留了几条检查项&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;我最后给自己留下几条明确的检查项：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Slot 数不等于吞吐；&lt;/li&gt;
&lt;li&gt;拿到文件和行号，先读明确位置；&lt;/li&gt;
&lt;li&gt;Verification mapped 和 executed 分开；&lt;/li&gt;
&lt;li&gt;Task completed 和 checks passed 分开；&lt;/li&gt;
&lt;li&gt;断线不自动重放；&lt;/li&gt;
&lt;li&gt;没有采样就显示 unknown。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;0.6.2 没有一个单独的大功能，更多是在把这些边界钉死。对我来说，这比再加一批 Tool 更实际。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>我把 wcode 写代码这条链又压快了一轮</title>
      <link>https://francisdu.com/blog/wcode-performance/</link>
      <pubDate>Wed, 26 Aug 2026 23:40:00 +0800</pubDate>
      <guid>https://francisdu.com/blog/wcode-performance/</guid>
      <description>&lt;p&gt;最近我拿 wcode 去几个别的项目里实际写代码，最明显的感受不是“功能还缺什么”，而是还不够快。&lt;/p&gt;
&lt;p&gt;这个“慢”很容易全甩给模型。&lt;/p&gt;
&lt;p&gt;但我看了一轮调用链以后，发现里面有不少完全是 Runtime 自己造成的等待。&lt;/p&gt;
&lt;p&gt;模型可能已经知道要改哪几个文件了，结果后面还在重复遍历、重复强制落盘、串行扫描，或者一个一个发 Tool Call。&lt;/p&gt;
&lt;p&gt;这些东西单次看都不大，Agent 连续改几十个文件时就很明显。&lt;/p&gt;
&lt;p&gt;所以这一轮我没有继续加新的 Intelligence 能力，先把写代码的热路径压了一遍。&lt;/p&gt;
&lt;figure class=&#34;content-image&#34;&gt;&lt;img src=&#34;https://francisdu.com/img/wcode/wcode-tui_hu_13e59e78ee0ce797.webp&#34; alt=&#34;wcode 最新终端实时面板&#34;loading=&#34;lazy&#34; decoding=&#34;async&#34; srcset=&#34;https://francisdu.com/img/wcode/wcode-tui_hu_13e59e78ee0ce797.webp 960w, https://francisdu.com/img/wcode/wcode-tui_hu_6437a17a51f06ca3.webp 1800w&#34; sizes=&#34;(max-width: 900px) calc(100vw - 32px), 900px&#34; width=&#34;3420&#34; height=&#34;2146&#34;&gt;&lt;/figure&gt;&lt;h2 id=&#34;第一处每个小编辑都-fsync-太贵了&#34;&gt;第一处：每个小编辑都 &lt;code&gt;fsync&lt;/code&gt; 太贵了&lt;a class=&#34;heading-anchor&#34; href=&#34;#%e7%ac%ac%e4%b8%80%e5%a4%84%e6%af%8f%e4%b8%aa%e5%b0%8f%e7%bc%96%e8%be%91%e9%83%bd-fsync-%e5%a4%aa%e8%b4%b5%e4%ba%86&#34; aria-label=&#34;章节链接：第一处：每个小编辑都 fsync 太贵了&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;wcode 的文件写入一直比较保守。&lt;/p&gt;
&lt;p&gt;已有文件不是原地 &lt;code&gt;truncate&lt;/code&gt;，而是：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;read + verify SHA
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ↓
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;create temp file in same directory
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ↓
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;write content
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ↓
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;atomic replace
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个设计我不准备改。&lt;/p&gt;
&lt;p&gt;真正拖速度的是之前为了追求磁盘级耐久性，还会做：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;temp file sync_all
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rename
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;parent directory sync_all
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;也就是说，一个很小的 &lt;code&gt;apply_edits&lt;/code&gt; 也可能触发两次强制刷盘。&lt;/p&gt;
&lt;p&gt;在本地 SSD 上偶尔看不明显，但到了 macOS APFS、虚拟机、网络盘或者 Windows，一连串小 edit 的 latency 会直接堆起来。&lt;/p&gt;
&lt;p&gt;这里我重新看了 Design State 的约束。&lt;/p&gt;
&lt;p&gt;wcode 真正必须保证的是：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SHA stale-write protection
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;same-directory atomic replacement
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;create-new cannot overwrite raced target
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;path / symlink / hardlink safety
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;它不是数据库，也没有承诺“每一个 Agent 小编辑在机器突然断电后都必须已经物理落盘”。&lt;/p&gt;
&lt;p&gt;所以现在交互式 Coding Path 去掉了每个小写入的强制 data + directory fsync。&lt;/p&gt;
&lt;p&gt;Atomic Replace 还在。&lt;/p&gt;
&lt;p&gt;这两个概念不要混在一起：&lt;strong&gt;原子性保留了，强制持久化延迟拿掉了。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;第二处project_context-原来有两个串行全仓库扫描&#34;&gt;第二处：&lt;code&gt;project_context&lt;/code&gt; 原来有两个串行全仓库扫描&lt;a class=&#34;heading-anchor&#34; href=&#34;#%e7%ac%ac%e4%ba%8c%e5%a4%84project_context-%e5%8e%9f%e6%9d%a5%e6%9c%89%e4%b8%a4%e4%b8%aa%e4%b8%b2%e8%a1%8c%e5%85%a8%e4%bb%93%e5%ba%93%e6%89%ab%e6%8f%8f&#34; aria-label=&#34;章节链接：第二处：project_context 原来有两个串行全仓库扫描&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Agent 进入一个新项目以后，我通常希望它先跑 &lt;code&gt;project_context&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;这里会做不少事情：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;找 Manifest；&lt;/li&gt;
&lt;li&gt;读 Repository Guidance；&lt;/li&gt;
&lt;li&gt;推导 Verification Checks；&lt;/li&gt;
&lt;li&gt;跑 Convention；&lt;/li&gt;
&lt;li&gt;跑 Language Quality Matrix。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Profile 本身已经有 Cache。&lt;/p&gt;
&lt;p&gt;但 Convention 和 Language Quality 之前还是串行执行。&lt;/p&gt;
&lt;p&gt;这两个操作都可能扫一遍仓库。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Convention Scan
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ↓
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Language Quality Scan
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其实它们之间没有数据依赖。&lt;/p&gt;
&lt;p&gt;现在直接 &lt;code&gt;rayon::join&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        ┌─ Convention Scan
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;context ┤
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        └─ Language Quality Scan
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;结果语义不变，但大仓库第一次进入时的 wall-clock 更合理。&lt;/p&gt;
&lt;h2 id=&#34;第三处搜索不应该先收集完整文件列表&#34;&gt;第三处：搜索不应该先收集完整文件列表&lt;a class=&#34;heading-anchor&#34; href=&#34;#%e7%ac%ac%e4%b8%89%e5%a4%84%e6%90%9c%e7%b4%a2%e4%b8%8d%e5%ba%94%e8%af%a5%e5%85%88%e6%94%b6%e9%9b%86%e5%ae%8c%e6%95%b4%e6%96%87%e4%bb%b6%e5%88%97%e8%a1%a8&#34; aria-label=&#34;章节链接：第三处：搜索不应该先收集完整文件列表&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;以前 &lt;code&gt;search_code/search_many&lt;/code&gt; 的逻辑大致是：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WalkDir 整个目录
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ↓
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;收集 Vec&amp;lt;PathBuf&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ↓
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Rayon 并行读文件
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ↓
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;搜索
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这意味着哪怕我要的前几十条结果很快就能找到，也要先把目录完整走完并分配一个 Path Vec。&lt;/p&gt;
&lt;p&gt;现在改成了边遍历边送给 Rayon Worker：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WalkDir → par_bridge → read/search
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一旦结果数量够了，后续 Worker 可以尽早退出。&lt;/p&gt;
&lt;p&gt;大仓库里这类改动比在小 Fixture 上测出来的数字更有意义。&lt;/p&gt;
&lt;h2 id=&#34;第四处同文件多个-edit-不应该重复建-line-index&#34;&gt;第四处：同文件多个 Edit 不应该重复建 Line Index&lt;a class=&#34;heading-anchor&#34; href=&#34;#%e7%ac%ac%e5%9b%9b%e5%a4%84%e5%90%8c%e6%96%87%e4%bb%b6%e5%a4%9a%e4%b8%aa-edit-%e4%b8%8d%e5%ba%94%e8%af%a5%e9%87%8d%e5%a4%8d%e5%bb%ba-line-index&#34; aria-label=&#34;章节链接：第四处：同文件多个 Edit 不应该重复建 Line Index&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;apply_edits&lt;/code&gt; 支持一次对同一个原始 SHA 做多处编辑。&lt;/p&gt;
&lt;p&gt;如果每个 Edit 都带 &lt;code&gt;start_line/end_line&lt;/code&gt;，以前每一条都会重新遍历整份内容去算行首 Byte Offset。&lt;/p&gt;
&lt;p&gt;也就是 N 个 Edit，可能做 N 次 Line Scan。&lt;/p&gt;
&lt;p&gt;现在只要这一批里有人用了 Line Bound，就先建一次 Line Start Index，所有 Edit 共享。&lt;/p&gt;
&lt;p&gt;对于几千行文件一次改很多位置，这属于很便宜但应该做的优化。&lt;/p&gt;
&lt;h2 id=&#34;第五处read_file-不需要为整份文件保存-vecstr&#34;&gt;第五处：&lt;code&gt;read_file&lt;/code&gt; 不需要为整份文件保存 &lt;code&gt;Vec&amp;lt;&amp;amp;str&amp;gt;&lt;/code&gt;&lt;a class=&#34;heading-anchor&#34; href=&#34;#%e7%ac%ac%e4%ba%94%e5%a4%84read_file-%e4%b8%8d%e9%9c%80%e8%a6%81%e4%b8%ba%e6%95%b4%e4%bb%bd%e6%96%87%e4%bb%b6%e4%bf%9d%e5%ad%98-vecstr&#34; aria-label=&#34;章节链接：第五处：read_file 不需要为整份文件保存 Vec&amp;lt;&amp;amp;str&amp;gt;&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;读取工具有 1 MiB 上限，所以以前直接：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;let&lt;/span&gt; lines: Vec&amp;lt;&amp;amp;&lt;span style=&#34;color:#2b91af&#34;&gt;str&lt;/span&gt;&amp;gt; = content.lines().collect();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;功能完全没问题。&lt;/p&gt;
&lt;p&gt;但 Agent 大多数时候只拿 100～500 行。&lt;/p&gt;
&lt;p&gt;现在先算总行数，再只对需要返回的 Range 做 &lt;code&gt;skip/take&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;不是一个惊人的 Benchmark，但这是典型的 Runtime Hot Path：每一次都跑，能少一次完整分配就少一次。&lt;/p&gt;
&lt;h2 id=&#34;第六处默认并行度再往上提&#34;&gt;第六处：默认并行度再往上提&lt;a class=&#34;heading-anchor&#34; href=&#34;#%e7%ac%ac%e5%85%ad%e5%a4%84%e9%bb%98%e8%ae%a4%e5%b9%b6%e8%a1%8c%e5%ba%a6%e5%86%8d%e5%be%80%e4%b8%8a%e6%8f%90&#34; aria-label=&#34;章节链接：第六处：默认并行度再往上提&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;之前默认值是：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;logical CPU × 8
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;clamp 64..128
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;现在改成：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;logical CPU × 12
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;clamp 96..192
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Harness 的硬上限仍然是 256，CLI 还是可以显式：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wcode -j 256
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;为什么不直接默认 256？&lt;/p&gt;
&lt;p&gt;因为这个 Semaphore 不只有小文件 IO，还会承载一部分 CPU 和外部进程任务。&lt;/p&gt;
&lt;p&gt;我希望默认更激进，但不是把所有机器都当成 32 核工作站。&lt;/p&gt;
&lt;p&gt;8 核现在默认 96，10 核 120，16 核及以上最多到 192。&lt;/p&gt;
&lt;p&gt;这个档位更适合 Agent 一次并行导航和修改多个文件。&lt;/p&gt;
&lt;h2 id=&#34;第七处连统计响应有多大也不该复制整份-json&#34;&gt;第七处：连“统计响应有多大”也不该复制整份 JSON&lt;a class=&#34;heading-anchor&#34; href=&#34;#%e7%ac%ac%e4%b8%83%e5%a4%84%e8%bf%9e%e7%bb%9f%e8%ae%a1%e5%93%8d%e5%ba%94%e6%9c%89%e5%a4%9a%e5%a4%a7%e4%b9%9f%e4%b8%8d%e8%af%a5%e5%a4%8d%e5%88%b6%e6%95%b4%e4%bb%bd-json&#34; aria-label=&#34;章节链接：第七处：连“统计响应有多大”也不该复制整份 JSON&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;TUI 会展示请求、响应和 Token Economy，所以 Tool Runtime 要知道每次调用大概传了多少字节。&lt;/p&gt;
&lt;p&gt;以前这个指标是这样算的：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Value
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ↓
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;serde_json::to_vec
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ↓
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;拿 Vec.len()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ↓
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Vec 丢掉
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;也就是说，真正响应以后，为了统计长度又临时分配并序列化了一份 JSON。&lt;/p&gt;
&lt;p&gt;小结果没什么感觉，但 &lt;code&gt;parallel_tools&lt;/code&gt;、Graph、Project Context 这类 &lt;code&gt;structuredContent&lt;/code&gt; 大时，这就是纯粹的额外内存和 CPU。&lt;/p&gt;
&lt;p&gt;现在改成一个只实现 &lt;code&gt;Write&lt;/code&gt; 的 Byte Counter，让 &lt;code&gt;serde_json::to_writer&lt;/code&gt; 流过去，只累加字节数，不保存第二份 Buffer。&lt;/p&gt;
&lt;p&gt;协议内容完全不变，Monitor 指标也不变，但每个 Tool Call 少一次只为计数存在的临时分配。&lt;/p&gt;
&lt;h2 id=&#34;单个函数快了还不够&#34;&gt;单个函数快了还不够&lt;a class=&#34;heading-anchor&#34; href=&#34;#%e5%8d%95%e4%b8%aa%e5%87%bd%e6%95%b0%e5%bf%ab%e4%ba%86%e8%bf%98%e4%b8%8d%e5%a4%9f&#34; aria-label=&#34;章节链接：单个函数快了还不够&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Runtime 再快，如果 Agent 还是：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;read A
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;edit A
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;read B
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;edit B
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;read C
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;edit C
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;MCP Round Trip 一样会浪费很多时间。&lt;/p&gt;
&lt;p&gt;所以 Project Context 的 Workflow 现在会明确提示：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;同文件多个修改 → apply_edits
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;多个已知现有文件 → apply_file_edits
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;多个新文件 → create_files
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;已知互不依赖的任务 → parallel_tools
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;一次遍历能解决 → search_many / read_files
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我越来越觉得 Tool Harness 的性能不是单个函数跑多快。&lt;/p&gt;
&lt;p&gt;它至少有三层：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;模型要不要一次提出足够完整的操作
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            ↓
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Tool Runtime 能不能批量/并行调度
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            ↓
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;底层文件和索引操作有没有多余工作
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;只优化最后一层，体感还是会卡。&lt;/p&gt;
&lt;h2 id=&#34;安全检查没有为了速度删掉&#34;&gt;安全检查没有为了速度删掉&lt;a class=&#34;heading-anchor&#34; href=&#34;#%e5%ae%89%e5%85%a8%e6%a3%80%e6%9f%a5%e6%b2%a1%e6%9c%89%e4%b8%ba%e4%ba%86%e9%80%9f%e5%ba%a6%e5%88%a0%e6%8e%89&#34; aria-label=&#34;章节链接：安全检查没有为了速度删掉&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;性能优化最容易走到另一个极端：觉得 &lt;code&gt;canonicalize&lt;/code&gt;、SHA、Symlink Check、Lock 都贵，干脆少查一点。&lt;/p&gt;
&lt;p&gt;这轮我没有这么做。&lt;/p&gt;
&lt;p&gt;保留的边界包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Workspace Root；&lt;/li&gt;
&lt;li&gt;Protected Path；&lt;/li&gt;
&lt;li&gt;Parent Traversal；&lt;/li&gt;
&lt;li&gt;Symlink Component；&lt;/li&gt;
&lt;li&gt;Unix Hard Link Write；&lt;/li&gt;
&lt;li&gt;SHA-256 stale revision；&lt;/li&gt;
&lt;li&gt;写锁后的路径重新解析；&lt;/li&gt;
&lt;li&gt;Atomic Replace；&lt;/li&gt;
&lt;li&gt;No-shell Command；&lt;/li&gt;
&lt;li&gt;Pending Authorization。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我拿掉的是重复工作和不必要的同步，不是安全模型。&lt;/p&gt;
&lt;h2 id=&#34;现在还剩什么可以继续优化&#34;&gt;现在还剩什么可以继续优化&lt;a class=&#34;heading-anchor&#34; href=&#34;#%e7%8e%b0%e5%9c%a8%e8%bf%98%e5%89%a9%e4%bb%80%e4%b9%88%e5%8f%af%e4%bb%a5%e7%bb%a7%e7%bb%ad%e4%bc%98%e5%8c%96&#34; aria-label=&#34;章节链接：现在还剩什么可以继续优化&#34;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;这一轮之后，我觉得还有几块值得继续盯：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;project_context&lt;/code&gt; 的两个仓库扫描虽然并行了，但未来最好共享一次 File Inventory，而不是各走一遍目录。&lt;/li&gt;
&lt;li&gt;MCP Tool Result 为兼容 &lt;code&gt;content + structuredContent&lt;/code&gt; 本身仍会保留两种表示；这和已经去掉的“仅为统计字节数再序列化一次”不是一回事，大结果仍有进一步优化空间。&lt;/li&gt;
&lt;li&gt;Software Graph 第一次建立时，Language/Tree-sitter Parser 初始化和目录候选选择还可以继续做更细的缓存。&lt;/li&gt;
&lt;li&gt;Monitor 的指标必须保持便宜，不能为了展示吞吐量反过来拖 Tool Call。&lt;/li&gt;
&lt;li&gt;多 Workspace 同时工作时，需要继续观察 Rayon、Tokio &lt;code&gt;spawn_blocking&lt;/code&gt; 和全局 Semaphore 三层调度会不会互相争资源。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;我不准备为了追一个漂亮 Benchmark 把这些全部一次性复杂化。&lt;/p&gt;
&lt;p&gt;我现在还是拿真实项目当标准：哪一步明显在等，就把那一步拆出来。&lt;/p&gt;
&lt;p&gt;这也是我现在优化 wcode 的方式。&lt;/p&gt;
&lt;p&gt;v0.3 的整体变化见 &lt;a href=&#34;https://francisdu.com/blog/wcode-v0-3/&#34;&gt;wcode v0.3：从本地代码桥到 Software Intelligence Runtime&lt;/a&gt;。&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>