本篇回答四个问题:它到底是个什么东西?它有几种露面方式?它靠什么技术跑起来?它的几千个文件是怎么摆放的?
1.1 它到底是个什么东西:一个住在终端里、会自己动手改代码的 AI
先说一个最常见的误解:很多人以为 AI 编程助手就是"一个更聪明的聊天机器人,你问它代码怎么写,它把代码贴给你,你自己复制过去"。
不是。它更像一个坐在你电脑前的实习生,只不过这个实习生:
- 能听懂你说的话("帮我把这个 bug 修了");
- 自己会去看文件、搜代码、跑命令(不用你把代码喂给它);
- 看完之后直接动手改,改完还能自己跑测试验证;
- 遇到拿不准的事(比如要删文件),会回头问你一句。
所以它和"聊天机器人"有一个本质区别:聊天机器人只会输出文字,它能输出"动作"。
打个比方。普通聊天机器人像一个顾问 :你问,他答,动嘴不动手。而它像一个有钥匙的钟点工:你说"把厨房收拾一下",他会自己打开柜门、找到脏碗、洗掉、放回原处------你只需要在他要动你保险柜的时候喊停。
那"动手"这件事在程序里是怎么实现的?答案很朴素:它能做的每一个动作,都被写成了一个工具(你可以理解成一个函数):读文件是一个工具、改文件是一个工具、跑终端命令是一个工具。AI 每次想做事,就说一句"我要调用'读文件'工具,参数是这个路径",程序收到后真的去读,再把结果喂回给 AI。
bash
你说:帮我看看这个报错
↓
AI:我要调用「跑命令」工具,执行 npm test
↓
程序真的跑了 npm test,把报错文字拿回来
↓
AI:我要调用「读文件」工具,读 src/auth.ts
↓
程序真的读了文件,把内容拿回来
↓
AI:我要调用「改文件」工具,把第 42 行的 == 改成 ===
↓
程序真的改了
↓
AI:修好了,原因是......(你看到的回答)
这个"AI 说要做什么 → 程序真的去做 → 把结果还回去"的转圈,就是整个产品最核心的机制,第 3 篇会专门拆开讲。
还有一个关键点:AI 本身是"远程的" 。真正在思考的那个大模型,运行在别人家公司的服务器上(通过网络调用)。你电脑上运行的这个程序,本质上是一个大管家:负责把你的话、你的文件、你的环境信息打包发给远端的大脑,再把大脑的"指令"翻译成本地动作。这个大管家做得好不好,决定了产品好不好用------大脑各家都差不多,管家才是分水岭。
1.2 它的四种露面方式:终端对话、被程序调用、被编辑器调用、被手机远程指挥
同一个"大管家"内核,穿了四件不同的外套,应付四种场合。
第一种:终端里的对话窗口(最主要的形态)
你在命令行敲一个命令,进入一个全屏的对话界面:上面是聊天记录,下面是输入框,能显示彩色的代码改动、待办清单、转圈的加载动画。这是给"人直接用"的形态,也是功能最全的形态。本书大部分篇幅讲的都是它。
第二种:被别的程序调用
它不只是给人用的,也可以被别的程序当成零件装进去。比如你写了一个自动化脚本,想让 AI 在脚本里帮你分析日志,你可以用代码的方式调用它:传入一句话,它返回结果,全程不出现任何界面。
打个比方:第一种形态像"去饭店堂食",你和服务员面对面;第二种像"外卖中央厨房",别的 App 下单,厨房做好递出去,顾客根本看不到厨房。
第三种:被编辑器调用
像 Zed、Cursor 这类代码编辑器,可以通过一套标准的"对话规矩"(一套双方都遵守的消息格式)来指挥它。编辑器负责显示界面、处理你的点击,它负责思考和干活。好处是:编辑器厂商不用自己造一个 AI 助手,只要按规矩发消息就行;而它也不用为每个编辑器单独做适配。
这就像电器和插座的关系:不管是台灯还是电脑,只要插头符合标准,插上就能用电。它是"电",编辑器是"电器",那套对话规矩就是"插座标准"。
第四种:被手机远程指挥
你出门在外,用手机发一句话"帮我把 CI 挂了的那个测试修一下",家里电脑上的它收到后真的开始干活,过程和结果实时传回手机;遇到要删文件这种事,手机上会弹个确认框,你点"同意"它才敢动手。
技术上这是在本地跑了一个小小的"收发室"程序,手机连着它,它再指挥本地的管家内核。
四种形态看起来差别很大,但内核是同一套:都是"收到一句话 → 转圈思考和干活 → 把结果回传"。区别只在于"这句话从哪来、结果送到哪去、确认弹窗弹给谁"。把同一套内核塞进不同外壳,是这个项目架构上最重要的一个决定------后面讲到第 3 篇和第 7 篇时你会反复体会到它的好处。
1.3 它靠什么跑起来:为什么选了这几门技术
一个程序用什么语言、什么框架写,本来是私事,但这个项目的选型很有特点,而且每个选择都直接影响了它"为什么长这样",所以值得花一章讲。
运行时:Bun(一个又快又新的 JavaScript 运行环境)
写这个程序用的是 JavaScript/TypeScript 这门语言。JavaScript traditionally 是跑在浏览器里的,后来有人把它搬到服务器上跑(Node.js),Bun 就是这类"让 JavaScript 跑出浏览器"的环境里最新、最快的一个。
为什么选它?三个现实原因:
- AI 生态几乎都在 JavaScript 这边。大模型的官方开发工具包、终端界面库、各种插件,JavaScript 版本最全最成熟。
- 启动快。这种工具是"敲一次命令、用一次、退出"的程序,每次启动都要重新加载自己。启动慢 0.5 秒,用户每天就会多等几十秒。Bun 启动特别快。
- 自带打包能力。它能直接把几千个源码文件打成可发布的产物,还支持"打包时就把用不到的代码删掉",这个能力对第 11 篇要讲的"功能开关"机制至关重要。
界面:React(做网页的那套技术)+ 一个自研的终端界面库
这是最有意思的选择。终端本来只能显示文字,做界面 traditionally 是"往屏幕上打印字符"这种很原始的方式,界面一复杂就很难维护。
这个项目的做法是:用做网页的思路做终端界面 。React 是做网页界面最流行的框架,它的核心思想是"你只管用代码描述界面应该长什么样,数据一变,框架自动帮你把界面更新成新样子,不用你手动去改屏幕上的字"。
但 React 默认只会渲染到网页上,不认识终端。所以项目自己造了一个"翻译层":把 React 描述的界面,翻译成终端能懂的字符和控制指令(光标移到哪、用什么颜色、清掉哪一行)。这个翻译层是整个项目里技术难度最高的部分之一,第 6 篇会专门讲。
打个比方:普通终端程序像"手绘黑板报",改一个字都要自己擦自己画;用 React 的方式像"做幻灯片",你只管写内容和排版规则,换内容时幻灯片自动重排。
语言:TypeScript(带类型的 JavaScript)
JavaScript 写小程序很爽,写几万行的大项目就容易乱:你不知道一个变量里装的是字符串还是对象,传错了要等运行起来才报错。TypeScript 给 JavaScript 加了"类型",相当于给每个数据贴标签("这个是字符串""这个是包含 name 和 age 两个字段的对象"),写错了在写代码的时候就提醒你。
这种几十万个文件的大项目,没有类型约束根本不敢改。
一句话总结这一节:Bun 负责"跑得快、启动快",TypeScript 负责"大项目不出错",React 负责"复杂界面好维护",自研翻译层负责"把网页界面搬进终端"。
1.4 代码仓库导览:几千个文件是怎么分门别类的
最后带你在门口看一眼这栋大楼的平面图,后面每一篇都会说"这在大楼的哪个房间"。
整个项目分两大块:主程序 和独立小包。
主程序的 src/ 目录(可以理解为"主楼"),最重要的几个房间:
css
src/
├── entrypoints/ ← 大门:程序从这里启动
├── main.tsx ← 总服务台:所有命令行参数在这里登记
├── query.ts ← 核心车间:一问一答的转圈就在这
├── QueryEngine.ts ← 车间调度:安排一场长对话怎么跑
├── Tool.ts ← 工具说明书:一个"工具"长什么样的规定
├── tools.ts ← 工具库房登记处:一共发了哪些工具
├── screens/ ← 门面:终端里你看到的那些画面
├── components/ ← 门面零件:消息气泡、输入框、加载动画
├── commands/ ← 服务区:四十多个 / 开头的斜杠命令
├── services/ ← 外联部:对接大模型、对接外部工具等
│ ├── api/ ← 对接各家 AI 模型
│ ├── mcp/ ← 对接外部能力(GitHub、数据库之类)
│ └── acp/ ← 对接编辑器
├── bridge/ ← 收发室:手机远程控制走这里
├── memdir/ ← 档案室:AI 的长期记忆
├── daemon/ ← 值夜班的门房:关掉终端还在后台干活
├── buddy/、modes/ ← 小角色:陪伴助手、各种工作模式
└── utils/ ← 杂物间:几百个各干各的小工具函数
独立小包的 packages/ 目录(可以理解为"院子里的独立车间")。这些是可以单独拿出去用的零件,各自有独立的"身份证"(各自的 package.json):
perl
packages/
├── @ant/ink/ ← 那个自研的终端界面库(第 6 篇的主角)
├── @ant/model-provider/ ← 对接各家 AI 模型的适配层(第 7 篇讲)
├── builtin-tools/ ← 六十多个内置工具的实现(第 4 篇讲)
├── acp-link/ ← 编辑器对接的代理程序
└── (还有音频采集、电脑控制等十几个小包)
为什么要把有些东西拆成独立小包?两个好处:一是边界清楚 ,比如终端界面库完全不知道"AI""对话"这些概念,它只管"把界面画到终端上",可以单独测试、单独复用;二是按需加载,用不到的小包(比如电脑控制)平时根本不会被搬进内存。
还有一个贯穿全书的词你先记住:功能开关(feature flag)。项目里有很多实验性功能,它们的代码虽然写在仓库里,但发布时可以被"一键摘掉",普通用户拿到的程序里根本没有这些代码。就像杂志排版时,编辑可以决定某篇文章这期发不发------不发的话印刷厂直接不印,而不是印了再涂黑。第 11 篇会讲它怎么做到的。
本篇小结
- 它不是聊天机器人,是一个能动手的管家:AI 出脑子,程序出手,"工具"就是手。
- 同一套内核有四种外套:终端对话、被程序调用、被编辑器调用、被手机远程指挥。
- 技术选型各有任务:Bun 快、TypeScript 稳、React 让界面好维护、自研库把网页界面搬进终端。
- 代码分主楼(
src/)和独立车间(packages/),记住几个关键房间的名字,后面会反复回来。
下一篇我们走到大门口,看看你敲下启动命令的那一瞬间,程序内部到底发生了什么。