从 Raycast 重构看 AI 时代的产品架构
Raycast 最近发了一篇技术博客,讲他们把整个应用从零重写了一遍。标题很低调,《A Technical Deep Dive Into the New Raycast》。但如果你认真读完就会发现,这篇文章表面在讲跨平台重构的架构选型,底子里藏着一个更锋利的问题:
如果你的产品将来要被 AI Agent 调用,而不只是被人点击,这个架构应该是什么样?

这个问题比"要不要给现在的产品加一个 AI 功能"大得多。它决定了你未来五年是轻松应对变革,还是每次 AI 浪潮一来就要重新打补丁。
Raycast 团队给出的答案可以浓缩成一句话:让 UI 和 Agent 成为平等的调用者。
旧架构的尽头
先看看背景。
Raycast v1 是纯 macOS 原生应用,Swift + AppKit,代码绑得很紧。启动快,占用低,体验流畅。2020 年上线至今,用户口碑一直很好。
按传统标准,这样的产品没有理由重写。
但产品本身其实已经升级了很多次:
最初它只是一个启动器,后来增加了 AI Chat、Notes、Extension Store、云同步、文件搜索。每一次扩展,都是在为一个启动器设计的骨架上接骨。编译时间越来越长,改一个功能要跨好几个模块,团队发现找深度 AppKit 人才越来越难。
这个持续开发的过程中还有一个更根本的矛盾:
旧架构里的业务逻辑和 UI 是缠在一起的。
你想让扩展调用某个能力,扩展必须通过 UI 层的 API。你想让脚本操作数据,得模拟用户操作。
换句话说,这个应用只有一个入口:图形界面。所有的用户操作都必须经过它。
这在 2020 年没问题,但在 2026 年的今天,问题开始越来越大了。
四层架构的隐含前提
Raycast v2 的新架构分成四层,每层之间通过类型化 IPC 通信:
- Host App(macOS 用 Swift/AppKit,Windows 用 C#/WPF):只做窗口管理、全局热键、托盘图标、加载 WebView。没有任何业务逻辑。
- Web 前端(React + TypeScript):渲染全部 UI,双端共享。每个窗口独立入口。
- Node 后端(单例长驻进程):全部业务逻辑、数据库、扩展运行时、各类服务。
- Rust 核心:数据层、云同步 schema、自定义文件索引器。
这个拆法的关键在于:业务逻辑不在 UI 层。它在一个独立的、可以通过 IPC 访问的进程里。 UI 只是这个进程的消费者之一,不是唯一的入口。
这听起来像微服务架构的老生常谈,但在桌面应用里做到这一层拆分的团队很少。大多数桌面应用仍然把逻辑写在 ViewController 里、埋在 onClick 回调里。UI 拆不出来,因为当初就没想过除了人点按钮之外,还有谁会调用这些能力。
Raycast 的新架构给出了一个明确答案:任何能力都通过类型安全的 IPC 暴露,UI 用这个 IPC,扩展用这个 IPC,外部进程也可以用这个 IPC。 谁是调用者不重要。人和 Agent 在这个架构里没有本质区别。
大部分 AI 功能是粘上去的
现在市面上给应用加 AI 的套路很固定:在 UI 上加一个对话框,对话框后面接一个大模型,大模型再调几个写死的 intent 映射。用户说帮我找文件,intent 路由到文件搜索;用户说创建提醒,intent 路由到提醒模块。
每加一个 AI 能力,都需要改对话层的代码。intent 映射表越来越长,边界情况越来越多。模型输出不可靠的时候,错误处理分散在各个地方。很多用户真正想做的事经常跨多个模块。比如"帮我整理上周的会议笔记,提取待办事项,加到日历里"。这种组合操作在硬编码的 intent 路由下几乎没法优雅处理。
这个问题不是 AI 本身的问题,因为你的应用没有给 AI 一个干净的接口。
Raycast 2.0的扩展系统提供了一个完全不同的思路。扩展运行在 Node 进程中,有明确的输入 schema 和输出类型,不依赖 UI。如果你已经有了这样一个类型安全的、可组合的命令系统,给 Agent 加一个工具就是在扩展列表里多注册一项。 Agent 不需要理解 UI 布局,不需要模拟点击,不需要等待动画完成。它只需要发一个类型正确的 IPC 消息。
这就是"平等的调用者"的真正含义:Agent 调用的和用户点击触发的,是同一条命令。只是触发方式不同。
文件索引器不是做给人用的
这篇文章还花了很大篇幅讲他们的 Rust 索引器。在 Windows 上直接读 NTFS 主文件表,把全盘扫描从分钟压到秒。技术含量很高,但很容易被读者当成"Rust 性能崇拜"翻过去。
别翻过去。这个索引器的设计哲学比实现细节重要十倍。
传统桌面搜索(Spotlight、Windows Search)给人类用户设计:用户敲文件名,搜索返回用户结果。但如果你想让 Agent 帮你处理文件,比如找出最近一周修改过的所有 PDF,提取其中的合同条款,汇总到表格里,传统索引就不够了,它缺结构化信息,缺上下文,缺跨应用的数据关联。
Raycast 2.0的索引器现在可以做到:任何扩展都可以往这个数据层注册自己的 schema。联系人、便签、日历、剪贴板历史、代码片段,结构不同,但都进同一个索引,然后被同一个查询引擎检索。
这可以让用户更快地找到东西。对 Agent 来说,这是一个结构化 memory。它不需要知道数据分别存在哪个应用、哪个格式、哪个目录。它只需要查这个统一的数据层。
我们花了很多时间讨论怎么给 Agent 做 RAG、怎么搭知识库、怎么管上下文窗口。但很少人从产品架构层面问:
如果我们从一开始就把数据层设计成对机器友好的形态,情况会有什么不同?
Raycast 的索引器至少在这个方向上迈了一步。它是否足够好另说,但方向是清楚的。
150MB 内存买的是什么
文章最后非常老实地交代了内存数据:v2 大约 350-450MB,v1 是 200-300MB。多了 150。
正常的性能评估会判定这是退化。用户会因为多占 150MB 而高兴吗?不会。
但如果你把"可被 Agent 调用"当做一项核心产品能力而非锦上添花,评估框架就变了。那 150MB 买的不是跨平台,买的是未来五年不需要再推倒重来。 它是一个跨进程类型安全的 IPC 通道、一个独立运行的 Node 运行时、一个从零构建的 Rust 数据层、以及一整套扩展运行时。这些都是"可编程性"的物理代价。
传统的性能基准没有"可被外部程序调用"和"Agent 可操作性"这两个维度。不是因为它们不重要,而是因为大多数应用从来没有认真对待过这些需求。当 AI Agent 还没有大规模渗透桌面操作系统之前,这些维度在评分卡上是隐形的。
Raycast 在这个时间点做这件事,说明他们不是在响应用户当下的抱怨,而是在为一个还没完全到来的场景付首付。
什么时候重构
整个故事里最容易被低估的部分不是技术选型,是时机判断。
Raycast 并不是已经被逼到墙角了才重写。产品增长健康,用户满意度高,指标一切正常。按以往常规的产品逻辑,这时候最不该做的就是推倒重来。
但他们做了。核心理由不是"旧架构坏了",是"旧架构的极限已经看得见了"。
这个决定并不容易。大多数团队在技术债堆到影响交付速度的时候才开始重构,但那时候时间窗已经极窄,只能做折中方案:改一部分,保留大部分,妥协堆妥协。
AI Agent 的渗透不会等到所有人准备好。它已经在发生。如果你的应用架构等到用户开始问"为什么 ChatGPT 不能直接操作你的应用"时才去改,你能做的只剩在外面裹一层脆弱的 glue,通过无障碍 API、屏幕识别、坐标点击这些权宜之计来"操作"一个本来不是设计给机器调用的界面。
那不是解决方案,是补丁。补丁会越打越厚,直到下一次不得不推倒重来。
Raycast 的判断是:AI Agent 不是功能需求,是架构需求。 面向功能的团队加一个聊天框就觉得"做了 AI 了"。面向架构的团队思考的是:这个应用的每一个能力,是否都暴露为了可发现、可组合、类型安全的命令。
前者在短期更快。后者在长期更活。
往哪里走
读完这篇文章,有三件事让我印象深刻。
第一,Raycast 没有选择给旧架构嫁接 AI。他们选择了把架构本身变成对 AI 友好的形态。这是一次为 AI 时代准备基础设施的努力。
第二,他们没有回避代价。多占 150MB 怎么了?"我们正在优化中"——写了,但没道歉,也没辩解。这在今天的技术博客里很少见。
第三,整个方案的逻辑是自洽的:如果要让扩展系统继续繁荣,如果要让 AI Agent 能真正调用应用,那业务逻辑就必须和 UI 解耦,数据层就必须对机器友好,IPC 就必须类型安全。这四点互相咬合,少一个都不成立。
对于在 AI 时代做产品开发的团队,这篇文章提供了一个难得的参照。
现实中,所有东西都在变化,没有谁的实践可以称为最佳。它提供的是一套清晰的思维框架:你怎么判断一场技术浪潮对你的产品是功能需求还是架构需求?你愿意为可编程性付多少成本?你打算什么时候动手?
这三个问题比用什么框架、用哪个模型重要得多。
2026 年 5 月