Conductor重写揭秘:如何提升性能
速览
本文深入探讨了Conductor重写过程中的关键变化。这些改动旨在显著提升系统的运行效率。对于关注AI基础设施优化的开发者而言,这是一份极具价值的参考。
AI 深度解读
Conductor 重构深度解析:他们做了什么让产品变得更快?
背景
近期,X(原 Twitter)上出现了一条由 Charlie Holtz 发布的帖子,声称:“我们从头重写了 Conductor,使其速度提升了两倍。”这一消息立即引起了广泛关注。为了探究其性能提升背后的具体技术决策,笔者与 Conductor 的联合创始人 Jackson de Campos 进行了深入交流。
Conductor 是一个面向开发者的 AI 编码助手工具。在初创初期,团队对 React 框架并不熟悉,但他们凭借敏锐的产品直觉,迅速实现了产品与市场需求的契合(Product-Market Fit)。然而,随着用户量的增长,核心功能(如聊天、工作树 worktrees 和代码查看)的性能瓶颈日益凸显,操作延迟成为了阻碍用户体验的最大痛点。
为了解决这一问题,Conductor 决定进行彻底的重构。本文旨在梳理这次重构的技术细节、架构选择以及背后的思考逻辑,特别是他们如何在保持“本地优先(Local-first)”架构优势的同时,通过精细的性能优化消除 UI 层面的摩擦。
核心内容
1. 核心理念:为自己构建产品
Conductor 团队最成功的决策之一是“Dogfooding”(吃自己的狗粮)。正如他们在官网所述:“我们使用 Conductor 来构建 Conductor。”
这种策略带来了显著优势:
- 痛点即时感知:团队与用户共享相同的工作流、挫折感和边缘案例。当开发者自己在日常工作中遇到卡顿或逻辑缺陷时,这些问题不再是待办事项列表中的普通 Ticket,而是必须在当天下午就修复的紧急任务。
- 高频迭代:Conductor 的更新日志(Changelog)更新极其频繁,充满了细微的修复和优化。这种节奏是深度使用产品的直接回报,确保了产品始终围绕真实的使用场景进行打磨。
2. 技术栈概览
在深入重构细节之前,了解 Conductor 当前的技术栈至关重要。其架构保持了“本地优先”的一致性,但在前端渲染和状态管理上进行了精细化选型。
前端(Frontend):
- 核心框架:React 19 + react-dom,TypeScript 作为开发语言。
- 构建工具:Vite,采用按包内容哈希的分块策略。
- 路由与状态:@tanstack/react-router(类型安全路由)、TanStack Query(主要数据层)、Zustand(内存状态存储)。
- 虚拟化与渲染:react-virtuoso 和 @tanstack/react-virtual 用于聊天列表和长列表的虚拟化,防止大量 DOM 节点导致的性能问题。
- 编辑器与交互:Tiptap + ProseMirror(富文本编辑器)、Shiki(代码高亮)、xterm.js + anser(终端渲染)。
- UI 组件:Radix UI primitives、Floating UI、cmdk(命令面板)、Tailwind CSS(无 CSS-in-JS 运行时,减少开销)。
数据与原生外壳(Data + Native Shell):
- 本地数据库:SQLite 作为单一事实来源(Source of Truth),存储工作区、聊天记录、检查点和设置。
- 原生外壳:Tauri 2.6.2,结合 Rust 核心和原生 WebKit 网页视图(macOS 上即 Safari 引擎)。
- Agent 进程:Rust 核心负责生成和监督 Agent 进程,Agent CLI(如 Claude Code)作为子进程运行,使用 Bun 作为运行时(早期为 Node.js)。
3. 重构前的性能基石:本地优先与 Tauri
在重构之前,Conductor 已经具备了一些高性能基因,这主要归功于两个关键架构选择:
A. 真正的本地优先架构 与 Linear 等应用将远程 Postgres 缓存到 IndexedDB 不同,Conductor 没有远程数据库需要缓存。SQLite 就是数据库本身,所有数据(工作区、聊天记录、设置)均存储在本地。
- 优势:彻底消除了网络请求带来的延迟。UI 永远不会等待服务器响应,实现了“零网络延迟”的数据读取体验。
B. 选择 Tauri 而非 Electron 虽然 Tauri 和 Electron 的性能之争常被简化为“谁更快”,但核心在于架构契合度。
- Tauri 的优势:Conductor 的架构涉及 Rust 核心生成 Agent CLI,且 UI 运行在高性能的原生 WebKit 中。Tauri 提供了更小的打包体积、更快的冷启动速度和更灵敏的 UI 渲染。
- 对比:如果应用是 TypeScript 客户端-服务器设计且依赖 Node 运行时(如 OpenCode 后来的选择),Electron 可能更合适。但 Conductor 的 Rust 核心与 WebKit 视图组合,使得 Tauri 成为更优解。
4. 重构的核心挑战:调试困境
当网络瓶颈被移除后,性能问题转移到了 UI 渲染层面。此时,Conductor 团队面临了一个严峻的工程挑战:如何调试 React 性能问题?
- Electron 的优势:Electron 内置 Chromium,可以直接使用 Chrome 的性能分析器、内存工具以及 React DevTools 扩展。
- Tauri 的劣势:Tauri 不捆绑浏览器,而是使用操作系统的原生 Webview(macOS 上是 WKWebView)。这意味着开发者只能使用 Safari 的 Web Inspector。
- 痛点:Safari 的 Web Inspector 只能分析 JavaScript 代码的执行时间(例如某个函数运行了 12ms),但无法分析 React 组件的重渲染情况(例如
WorkspaceView因为某个 prop 引用在每次导航时都变化,导致重渲染了 400 次)。React DevTools 扩展无法在 WKWebView 中加载,而这是定位 React 性能瓶颈的关键工具。
5. 解决方案:桥接模拟与 Chrome 调试
为了在不放弃 Tauri 优势的前提下获得强大的调试能力,Conductor 团队采取了一种巧妙的开发策略:在开发环境中,将 Tauri 的桥接层(Bridge)模拟掉,使应用能在标准 Chrome 浏览器中运行。
技术实现逻辑:
- 前端本质:Conductor 的前端本质上是一个 Vite 构建的单页应用(SPA)。聊天消息或文件树的渲染逻辑并不依赖原生外壳。
- 通信机制:UI 与 Rust 核心的通信通过 Tauri 的
invoke()桥接函数进行。 - 开发环境 Shim:在开发模式下,团队拦截了
invoke()调用。如果检测到__TAURI_INTERNALS__不存在(即在 Chrome 中运行),则通过fetch请求将命令代理到本地运行的开发服务器,或者直接返回模拟数据。
代码示意:
// Conductor 的 UI 通过 Tauri 的 invoke() 桥接访问 Rust 核心。
// 在普通浏览器中没有 Tauri 运行时:__TAURI_INTERNALS__ 为 undefined,
// 每次 invoke() 都会抛出异常。因此在开发环境中,我们 shim 这个唯一的入口点,
// 并在 Chrome 中启动完全相同的前端,从而同时启用 Chrome 分析器和 React DevTools。
import { invoke as tauriInvoke } from "@tauri-apps/api/core";
export function invoke<T>(cmd: string, args?: Record<string, unknown>): Promise<T> {
// 打包应用:使用原生桥接
if ("__TAURI_INTERNALS__" in window) return tauriInvoke<T>(cmd, args);
// Chrome 开发环境:替代 Rust 后端。
// 代理到运行真实命令的开发服务器,或返回用于分析表面的模拟数据。
return fetch(`/__backend__/${cmd}`, {
method: "POST",
body: JSON.stringify(args ?? {}),
}).then((r) => r.json());
}
通过这种“桥接模拟”,团队得以在拥有 Chrome 强大调试生态(React DevTools Profiler)的环境中开发,精准定位并修复了不必要的重渲染、卡顿的滚动和掉帧问题,最终实现了整体性能的大幅提升。
关键要点
- 本地优先是性能基石:通过 SQLite 作为唯一数据源,Conductor 消除了网络延迟,这是其
