如果你用过 OpenAI 的 Codex CLI,你大概有过这样的体验:装一个 codex 需要先搞定 Node.js 运行时,然后 npm install 拉下来几百个依赖包,node_modules 动不动就几百 MB。每次启动,V8 引擎先预热,模块再加载,你好不容易等到提示符出现,已经过去了十几秒。

这不是 Codex 的问题,这是整个 JavaScript 工具链的通病。但当你的日常工作是靠编程 Agent 来提高效率时,这个"启动税"就开始让人难受了。

最近,一位名叫 Paolo Anzani 的开发者做了一个大胆的尝试:用 C++23 重写整个 Codex CLI,编译出来的二进制不到 1MB。项目叫 MicroCodex,上周在 Hacker News 上获得不少关注。

这不仅仅是"用 C++ 重写"的技术练习。MicroCodex 的设计背后,折射出对 AI 编程工具本质的一些有趣思考。

1MB 的野心:从 Node.js 到原生二进制#

先看一组对比。Codex CLI 的安装流程是:确保 Node.js ≥ 18 → npm install → 等待几百个包下载 → 完成。而 MicroCodex 的安装是:

curl -fsSL https://github.com/paoloanzn/microcodex/releases/latest/download/install.sh | sh

一条命令,下载一个预编译的静态链接二进制,放到 $PATH 里,结束。没有运行时依赖(Linux 上需要 libcurl 和 OpenSSL,这几乎是任何系统的标配),不需要包管理器,不需要任何语言生态。

MicroCodex 的 main.cpp 只有 388 行。整个项目使用了一个简洁的 Makefile,依赖的第三方库只有两个:libcurl 做 HTTP 请求,md4c 做 Markdown 渲染(用于终端内的富文本显示),以及 termbox2 做终端 UI。没有异步框架,没有 ORM,没有构建系统的那一套 webpack + babel + tsc 全家桶。

二进制大小的意义不在于节省磁盘空间,而在于它代表了一种哲学:一个编程 Agent 的核心价值是"理解任务并执行工具调用",所有跟这个核心不直接相关的东西都是噪音。MicroCodex 证明了,把噪音全部去掉之后,这个核心可以非常小。

一模一样的 API,完全不同的实现#

MicroCodex 并非另起炉灶定义一套新协议。它复用了 OpenAI Codex 的同一套后端 API:https://chatgpt.com/backend-api/codex/responses。认证也是同样的 OAuth 流程,用你的 ChatGPT 订阅账号登录。

这意味着什么?MicroCodex 是一个 drop-in 替代品。 你用 microcodex 命令的体验,和用 codex 几乎一样:

# 一键式提问
microcodex "Find the failing test, fix it, and run the relevant test suite"

# 交互式会话
microcodex

# 恢复历史会话
microcodex resume abc123

# 列出所有历史对话
microcodex list

甚至连 $CODEX_HOME/skills 目录下的 skills 文件都是兼容的。MicroCodex 会自动扫描 ~/.codex/skills/,读取每个 skill 的 SKILL.md 元数据,在会话启动时注入 agent 的 system prompt 中。

但实现层面完全是另一回事。我们来看看几个关键子系统。

工具系统:类型安全的 C++ 模板#

MicroCodex 的工具系统是整个项目中最精巧的设计之一。它用 C++ 模板实现了一套类型安全的工具注册和执行框架:

// 在 tool.h 中,Tool 是一个模板类
template <typename T, typename ... S>
class Tool final : public ToolBase {
    // T 是返回值类型,S... 是参数类型包
    // 通过 JsonExecutionAdapter 将 JSON 参数映射到 C++ 函数调用
};

每个工具(read、write、edit、bash、glob)都是一个 Tool 实例,注册时提供 JSON Schema 描述参数格式,执行时 adapter 自动完成 JSON 到 C++ 类型的转换。这种设计的优雅之处在于:编译期类型检查保证了工具调用的正确性,不会像动态语言那样在运行时才发现参数类型不匹配。

MicroCodex 内置了五个核心工具:

工具功能备注
read读取文件内容支持分页读取大文件
write创建新文件只允许新建,不允许覆盖
edit精确替换文件内容基于 fuzzy matching 的查找替换
bash执行 shell 命令带安全守卫,阻止危险操作
glob文件模式匹配rg --files 的等价实现

这个工具集精简到了极致。Codex CLI 有十几个工具(包括 web_search、notebook 等),MicroCodex 只保留了编程 Agent 最核心的五个。少即是多。

安全守卫:简单但有效#

编程 Agent 执行 shell 命令时的安全性是一个经典难题。OpenAI 的 Codex 采用了基于沙盒的隔离方案,而 MicroCodex 走了一条更轻量的路:词法黑名单

// 在 bash-safety.cpp 中,一个简单的拒绝列表
// 阻止 rm -rf、git reset --hard、磁盘格式化等危险命令

打开 bash-safety.cpp,你会看到它拦截的模式包括:

  • rm -f / rm -rf:强制删除
  • git reset --hard:强制重置
  • git checkout --:丢弃修改
  • mkfs.*dd if=:磁盘操作
  • shutdownreboot:系统命令

作者在 README 中坦诚地说明了这一点:

MicroCodex is not a sandbox. This guard is not a shell parser and is not a complete security boundary.

它不是沙盒,也不假装自己是。它只是一个快速过滤层,防止最常见的事故。这种诚实的"够用就好"态度,反而比很多过度设计的安全方案更让人放心,因为你清楚它的边界在哪里。

上下文压缩:让长对话活得更久#

LLM 的上下文窗口终究有限。当对话持续多轮后,token 消耗会逼近上限。Codex 的做法是由后端自动管理上下文摘要,而 MicroCodex 把这个逻辑搬到了客户端。

context-compaction.h 可以看到压缩策略的核心参数:

struct CompactionConfig {
    std::size_t context_limit_tokens = 258'400;   // 模型总容量
    std::size_t compact_at_tokens = 244'800;       // 触发压缩的阈值
    std::size_t retained_context_tokens = 20'480;  // 保留的最近上下文
    std::size_t maximum_summary_bytes = 32'768;    // 摘要的最大字节数
};

工作流程是:当对话 token 数接近 compact_at_tokens(约 245K)时,MicroCodex 会请求模型对历史对话生成摘要,然后保留最近 20K token 的原始上下文,其余部分用摘要替代。这样既保留了近期细节,又不会丢失前文的脉络。

这个设计有一个值得注意的细节:它是确定性的、可预测的。压缩的触发条件、保留比例、摘要大小都是明确定义的常量,不会像某些黑盒方案那样在你不注意的时候突然丢掉了关键上下文。

API 层的深思熟虑#

MicroCodex 的 CodexApi 类封装了与 OpenAI 后端通信的全部逻辑。它的设计有几个精心考虑的决策:

同步 API,异步由调用者管理。 sendUserMessage() 是同步阻塞的,在内部完成完整的 model-tool 循环(模型生成 → 工具调用 → 结果返回 → 模型继续生成)。这意味着 UI 线程需要自行管理工作线程,但也意味着核心逻辑完全不受异步框架的束缚。

中断支持。 interrupt() 方法可以从另一个线程安全地中断正在进行的请求。这在交互式场景中非常重要,比如用户在 Agent 执行到一半时按了 Ctrl+C

会话持久化。 对话历史以 JSONL 格式保存在 ~/.codex/conversations/ 目录下,每次 turn 都会增量写入。这意味着即使进程崩溃,对话进度也不会全部丢失。

最让我印象深刻的是 CodexApiConfig 中的这个字段:

std::size_t maximum_tool_rounds = 128;
std::size_t maximum_parallel_tool_calls = 32;
std::size_t maximum_tool_output_bytes = 64 * 1024;

这些看似"拍脑袋"的常量,实际上构成了一个 Agent 的行为边界。128 轮工具调用是上限,超过就停止;单次工具输出不超过 64KB;最多 32 个工具可以并行执行。这些限制不是来自 API,而是来自 MicroCodex 的自我约束。它们存在的意义是:防止失控。一个没有天花板的 Agent 可能会在一个死循环里烧掉你几百美元的 API 费用。

边界与未来#

MicroCodex 当然不完美。目前已知的限制包括:

  • 不支持 MCP(Model Context Protocol),这意味着无法连接到第三方工具服务器
  • 终端内文本无法复制,这是 termbox2 库的已知问题
  • 安全守卫只是词法过滤,不是真正的沙盒
  • 目前只有 32 颗 GitHub Star,社区还很早期

但这些限制恰恰说明了项目的定位:它不试图成为"万能 Agent 平台",而是一个聚焦核心体验的编程助手。作者 Paolo 显然很清楚自己在做什么:把 Codex 最本质的功能(理解代码、执行工具、保持对话)提炼出来,用最少的代码实现,让它在任何地方都能零摩擦启动。

启示:AI 工具的"轻量化"趋势#

MicroCodex 的出现不是孤例。回顾过去一年,AI 编程工具领域有一个明显的趋势:从重型平台向轻量工具回归

  • OpenAI 自己的 Codex CLI 本身就是对 IDE 插件的简化(不需要 VS Code,终端就够了)
  • Aider 的成功证明了纯命令行 Agent 的吸引力
  • 各种 “Agent in X lines of Y” 的项目层出不穷(9 行 Python、400 行 Shell)
  • Hoplite 等 YC 项目在解决"Agent 部署"问题,本质上也是让重型基础设施隐形

MicroCodex 把这个趋势推到了极致。它告诉我们:当你把问题定义清楚之后,实现可以比想象中小得多。 1MB 的二进制里包含了 Agent 循环、工具执行、上下文管理、OAuth 认证、终端 UI、Markdown 渲染,以及完整的测试套件。

对于正在构建 AI 工具的团队来说,这是一个值得思考的信号。我们是不是过度设计了?是不是在还不清楚用户真正需要什么的时候,就先搭了一个沉重的技术栈?

当然,我不是说要所有人去用 C++ 重写自己的 Agent。我想说的是:MicroCodex 证明了"小"是一种美德。在 AI 工具的设计中,知道自己不需要什么,比知道自己需要什么更难。


参考来源: