fx:把 coding agent 做成一把瑞士军刀
摘要
fx 是一个用 Zig 写的原生 coding agent,二进制只有 6MB 出头。它能当终端 agent 用,也能作为 WASM 内核嵌进浏览器和 Node 应用。这篇文章拆解它的工具、权限、子 agent、上下文和嵌入设计,以及它和主流 coding agent 的差别。
主流的 coding agent 多数基于 Node 或 Python,安装后依赖通常有几十上百 MB,交互集中在一个全屏 TUI 里。fx 选了另一条路:用 Zig 写成,编译出来是一个 6MB 出头的原生二进制。
仓库在 vercel-labs/fx,Apache-2.0 开源,目前标注为实验状态。我翻它源码时的第一感觉是,它更像一把瑞士军刀 - 体积小巧,能力却很全。
fx 是什么
fx 对自己的描述是 “Tiny, open, embeddable, native coding agent”,这四个词基本概括了它的取舍。
技术底座是看起来偏小众的 Zig 0.16+,没有 Node 运行时,根目录也没有 package.json。当前源码版本 0.0.10,src/ 下有 591 个 Zig 文件、约 68 万行代码。这里的“小”指的是产物,不是代码量 - 大量代码花在接口约定、校验、权限和测试上。
它有两种用法:既是一个终端里的命令行工具,也是一个可以被别的系统嵌进去的 agent 运行时。
命令行与内核
先说命令行。fx 的顶层命令不是只有进入交互界面一个入口,而是一整套可以单独调用的子命令:
fx # 进入交互式 shell
fx ask "解释这个仓库最近的改动"
fx status --json # 结构化状态,方便脚本消费
fx pr # 在 git 仓库里起草 PR
fx issue
fx replay bug.fxtape # 回放录制的终端 tape
顶层命令还包括 login、setup、permissions、mcp、models、provider、doctor、session、sessions、resume、credits、usage、upgrade、workspace 等。进入交互界面后,还有一组斜杠命令:
/compact/permissions/model/skills/mcp- 等等
这种设计让 fx 可以被脚本和 CI 直接调用,而不是只能由人在终端里手动敲。
此外,fx 可以作为 ACP(Agent Client Protocol)服务器,也可以编译成 WebAssembly,作为内核被 JS 宿主使用:
import { createFxAgent } from "libfx";
const agent = await createFxAgent({
apiKey: process.env.AI_GATEWAY_API_KEY,
model: "google/gemini-2.5-flash-lite",
});
const turn = agent.prompt("Explain this project.");
for await (const event of turn) {
if (event.type === "text_delta") process.stdout.write(event.delta);
}
libfx 的对外接口很精简:一个 agent 实例就是一次对话,全部状态都在内存中,没有独立的进程或服务,只提供 prompt、checkpoint、close 三个操作。宿主负责网络、凭证、会话存储和终端 I/O。导入 libfx 时不会连接 MCP、不会扫描 skill、不会起进程、不会读文件系统。
官方还配了 Node.js、浏览器、Next.js、Nuxt 四个可运行示例。主流 coding agent 的 SDK 大多是包一层子进程,fx 是把内核本身交出去。
内置工具集
fx 的内置工具集中在 src/builtins/tools.zig,一共十七个:
| 工具 | 作用 |
|---|---|
shell | run / interact / stop,支持持久 TTY |
read_file | 带行号的分段读取 |
write_file | 覆盖式写入 |
edit_file | 精确字符串替换 |
glob_files | 按路径模式查找,支持 count |
grep_files | 精确文本匹配(不支持正则),支持分页和上下文行 |
web_fetch | 抓取指定 URL 的文本 |
web_search | 网络搜索,支持域名白名单 / 黑名单 |
capability_search | 按关键词检索可用能力 |
subagent | 委派临时或常驻 subagent |
skill / install_skill | 加载和安装技能 |
mcp_select_tool / mcp_features | MCP 工具选择和能力发现 |
ask_user_question | 结构化提问,带 2 到 6 个选项 |
vision | 图片输入 |
read_tool_result | 读取历史工具结果 |
shell 不是一次性执行
列表里最特别的是 shell。它不是“跑一条命令拿一次输出”,而是一套跨轮次的会话协议:
shell.run执行命令。如果命令在yield_time_ms内没结束,会返回一个session_id。shell.interact用这个session_id发送输入(chars)并观察输出,可以跨轮次反复调用。shell.stop终止会话。
也就是说,一个长期运行的进程可以被 agent 持续交互,而不是每条命令都重新起一个 shell。工具说明里还明确禁止用 &、nohup、setsid 或双重 fork 把进程放到后台。tty=true 会走真正的 PTY,底层是 src/core/terminal/ 里的终端引擎。
这一点和大多数 agent 的 bash 工具差别很大:后者通常只提供一次性执行,交互式程序基本没法用。
结果一直可读
上下文压缩之后,旧的工具结果不会直接消失。较近的完整工具调用会留在上下文里,更早的结果可以通过工具 read_tool_result 重新取出。这样模型需要回溯某个历史输出时,不需要重新跑一遍命令。
权限
fx 的权限基线有三档:ask、auto、full-access(yolo 作为别名保留)。
真正有意思的是 auto 模式下发生的事。每一个没有被配置规则或会话规则明确放行的操作,都会先经过一次针对性的安全审查。审查器拿到的输入包括:操作的原始文本和目标、来源和调用身份、可选的分支证据,以及当前轮次里较早工具结果的有限摘录。
它返回 caution 的唯一理由是发现了具体的 prompt injection 或者恶意行为。如果一个操作只是破坏性、有风险、涉及外部或远程,但不带恶意,它会放行。文本匹配到之前的工具输出只是“值得查看的证据”,不等于恶意。
而且 clear 只授权那一个未改变的操作。操作一旦变化,就要重新审查。caution、证据不足或审查不可用,都只会按住当前这一个操作,把判断交回给 agent,不会弹人工审批界面,也不会禁用工具或结束轮次。
审查还有预算控制:同一个操作在每一轮里最多消耗一次“审查不可用”的机会,caution 和确定性证据不足的结果只在当前轮次内复用。每次审查接受一个合法结构化决定,允许在原来的 30 秒期限内对格式不合规的响应重试一次。
这套设计的目标很具体:不是判断任务做得好不好,也不是替用户做授权决定,而是识别注入和恶意。它和主流的 allow / deny / always 加一个 yolo 开关,是两种不同的问题。
会话自己管理上下文
fx 会在模型可用输入容量的 80% 处自动压缩上下文,也可以手动 /compact。
压缩有几个约束值得注意:
- 压缩完成后先校验上下文,只有 checkpoint 提交成功才切换。失败或取消的压缩会保留上一个已提交的上下文,已保存的会话可以从那个 checkpoint 恢复。
- 已保存的会话里,较早的助手内容会被摘要,原始用户文本在放得下时保持不改动、保持时间顺序。
- 达到容量时才会摘要较早的用户消息。
会话本身存在 ~/.fx/sessions/<session-id>/ 下,是全局的,可以跨工作区携带。每个会话记录自己的 workspace_root,在别的工作区恢复时更新。项目里的 .fx.json 只能放可以安全提交的默认值,像 provider、模型、权限模式、凭证这些属于个人配置的键会被忽略,不会从项目配置里被读进来。
能持续对话的 subagent
fx 的 subagent 有两种形态。
subagent.run 起一个临时 subagent,执行一个完整任务,不接受后续消息,可以单独指定模型和推理强度,不指定就继承父级。
subagent.message 走的是另一种模式:给它一个名字。第一次用这个名字会创建常驻 subagent,之后再调用就是继续对话。如果 subagent 正在工作,消息会排队作为反馈,不会打断它当前的工具调用。可选的 instructions 只替换 subagent 自己的系统覆盖层,而且不能替换 fx 的信任基础提示,也不能扩大权限。
父子关系上,父会话维护一份有界的 subagent/children.json 注册表,子会话只带一个不可变的归属标记。子会话不进入普通会话发现,也不能被直接恢复。
这套结构对应一种具体的工作方式:用前沿模型做规划和过程引导,把实现交给更便宜的模型,过程中还能插话调整。
不绑定任何一家模型
fx 支持内置的几种登录方式:fx login 走 Vercel AI Gateway,fx login codex 走 ChatGPT 订阅的 OAuth,fx login grok 走 xAI 的 OAuth,fx setup 配 Gateway 的 API key。
同时它也支持自定义的 OpenAI Chat Completions 端点,比如本地的 Ollama 或者 OpenRouter:
{
"provider": "local",
"providers": {
"local": {
"protocol": "openai-chat-completions",
"base_url": "http://localhost:11434/v1",
"auth": { "type": "none" }
}
},
"models": {
"local": "qwen2.5:7b"
}
}
然后用 fx provider local 保存偏好,或者用环境变量单次覆盖:
FX_PROVIDER=openrouter FX_MODEL=openai/gpt-4.1 fx ask "review this change"
自定义连接有明确的边界:远程端点必须 HTTPS,本机回环地址可以用 HTTP;匿名连接不发 Authorization 头;bearer 连接只读它自己指定的环境变量。它也有一些还没做的能力,比如自定义适配器暂时不支持原生图片输入,也不支持 Responses API 和供应商特定的推理控制。自动权限审查会用同一个连接上的模型,也可以用 reviewer_model 指定另一个。
需要注意的是,fx 不会在模型审查失败时回退到云端审查器,也不会改动权限模式 - 无法审查就不放行。
把体积和启动耗时当成产品约束
这是 fx 和大多数 coding agent 最不一样的地方之一:它把性能和体积写进了 CI。
- 启动延迟有预算。Linux CI 上每个命令的实测耗时预算是 2ms,由
benchmarks/startup.sh和bench.yml执行。FX_BENCH=1会在参数解析和 CLI 分发之后直接退出,不进 TTY 初始化。 - 二进制体积有门禁。
binary-size.yml会在四个平台上对比 PR 和 base 的 stripped ReleaseSafe 二进制,报告精确字节和 section 变化。单个平台增长到 52,429 字节(0.05 MiB)会告警并保留该平台的二进制用于排查。macOS arm64 的 PGSO 发布门禁则守着 7.800 MiB 的上限。 - 有 PGSO 语料分类。每个根级
tests/e2e/*.test.ts都必须在scripts/pgso/corpus.json里归为 Training、Verification-only 或 Intentional exclusion 之一,PR CI 会拒绝缺失、重复、过期或未分类的文件。
渲染也按同样思路对待。fx 默认走 inline 渲染,只输出一个很小的 ANSI 子集,只有三类所有者可以占用备用屏:交互式权限审查、完整 transcript 界面、目录菜单。为了复现渲染问题,它提供 FX_DEBUG_RECORD=1 录制二进制 tape,再用 fx replay 在没有 TTY 的情况下确定性回放,甚至可以 --golden 生成回归基线。
一个 agent 项目把启动耗时、二进制体积和渲染可复现性都当成约束,这不算常见。
上手
安装脚本一行:
curl -fsSL https://fx.sh/setup.sh | bash
或者从源码构建(需要 Zig 0.16+):
git clone https://github.com/vercel-labs/fx.git
cd fx
zig build -Doptimize=ReleaseSafe
./zig-out/bin/fx
然后是登录和第一次运行:
cd your_project
fx # 交互式 shell
fx ask "explain this repository" # 一次性问答
如果想把它嵌进自己的应用,可以先用 fx acp 接编辑器,或者在 Node / 浏览器项目里 npm install libfx。
相关文章
2026年9月15日
一天多了 1,796 颗星,阿里把代码审查里的 Agent 关进了确定性流程
OpenCodeReview 在 GitHub Today 获得 +1,796 stars,并于同日发布 v1.12.1。它不是让 Agent 自由浏览代码,而是把文件选择、规则匹配、分组和评论校验交给确定性程序,再把真正需要判断的部分留给模型。
2026年9月12日
一天多了 545 颗星,PI-Desktop 想把 Coding Agent 从终端搬进可控的桌面
PI-Desktop 在 GitHub Today 拿到 +545 stars,当天又发布 v0.14.7-beta.1。它把多模型、技能、MCP、子 Agent 和权限确认收进本地桌面,但仍是一款需要审慎安装的早期预览软件。
2026年9月7日
我又给 Pi Agent 做了个 zvec-grep 扩展
承接 dsh-zvec-grep 的开发,聊聊 pi-zvec-grep 如何在命令行 Agent 中自动建立和更新代码索引,以及它与 DSH 插件在运行机制上的差别。
最近一封 · Sample
OpenRig 冲上 Trending:把 Claude Code 和 Codex 编成一支队伍
“OpenRig 在 GitHub Trending Today 获得 622 个 stars 的窗口信号。它用可恢复的队列、席位与权限记录,把 Claude Code 和 Codex 放进同一套多 Agent 工程流程。”
—— william
来信
里面装的是
- 新文章 — 写完一篇就寄一封,不攒货
- 这周读到的、看到的、好用的工具
- 正在折腾的实验,附带翻车记录
约莫 1–2 周一封 · 随时退订
合作伙伴
CompeteMap — 英国及爱尔兰学生竞赛一站式搜索
数学、编程、科学、写作等各类竞赛信息汇总,支持按年龄和科目筛选,再也不错过报名截止日。