最初,人们在 Coding Agent 上发现了这样一个现象:只要把 Bash 工具暴露给它,它似乎就能完成所有事——从基础的代码编写,到 agentic 的上下文查找,再到 Git 工作流的执行。
于是,我们开始看到万物 CLI 化。CLI 似乎成为了将复杂软件暴露给 Agent 的标准答案。你一定听过这句话:
“CLI is all you need.”
但在这股热潮背后,我们也观察到一个问题:Agent 往往像人类使用终端一样,执行一条短命令、读取结果,再决定下一步。任务越复杂,模型与工具之间的往返越多,也就意味着更多的模型调用、上下文开销和等待时间。
与其让 Agent 编写复杂的 Shell 脚本,我们更希望它使用自己熟悉的编程语言来组织任务。基于这一观察和后续实验,我们提出了一种优化方案:仍以 CLI 作为统一入口,但以代码作为实际的软件操作接口。
Agent 一次写入一段代码,将原本分散在多轮交互中的操作、判断和数据处理,交给代码执行环境完成。ego-browser 正是这种思路的一次实践:CLI 负责启动可编程环境,软件将能力暴露为少量函数,Agent 则使用已有的编程能力完成组合与编排。
在这篇博客中,我们将比较 Heredoc 与 REPL 两种 CLI 中的代码执行方式,并分享 ego-browser 的实验结果:相对于 REPL ,Heredoc 将 Agent 的平均执行轮数、工具调用次数和成本降低了约 40%。
CLI Is All You Need ,然后呢?
“CLI Is All You Need”成立的前提,是模型已经良好掌握这个 CLI 的使用。
对于 Git 、Docker 、FFmpeg 等常见工具,这通常不是问题。模型在训练过程中见过大量命令、教程、脚本和报错,已经熟悉它们的参数和组合方式。
但当我们在为 Agent 开发一个全新的 CLI 时,情况就不同了。每个 CLI 都有自己的子命令、参数、输出格式和错误语义。对模型来说,这相当于一门新的微型语言。即使我们提供完整文档,它仍然需要先理解这些规则,再通过多次调用摸索不同命令该如何组合。
如果把同样的能力暴露为 JavaScript 或其他语言的 API ,模型仍然需要学习新的领域概念,但不必重新学习控制流、数据结构和组合方式。循环、条件、异常处理和数据加工,都可以继续使用它已经熟悉的编程语言。
以“打开网页并读取主标题”为例。假设 ego-browser 采用传统的命令式接口,Agent 可能需要分几步完成任务:
# 第一次调用:打开网页
ego-browser open https://example.com
# 工具返回:页面已经打开
# 第二次调用:查找主标题
ego-browser find --role heading
# 工具返回:找到一个标题元素
# 第三次调用:读取标题文字
ego-browser read --role heading
每执行一步,Agent 都要等待工具返回结果,再根据结果决定下一步。
ego-browser 实际采用的代码接口,是让 Agent 将整个过程写成一段 JavaScript ,一次执行:
await taskSpaces.useOrCreate("读取示例页面");
await browser.openOrReuseTab("https://example.com", { wait: true });
const heading = await page.getByRole("heading").textContent();
console.log(heading);
两种方式完成同一件事。命令式接口把过程拆成多轮模型与工具的交互;代码接口则让 Agent 一次写出完整过程,再交给本地执行环境完成。
这正是前文提到的设计思路:以 CLI 作为统一入口,但以代码作为实际的软件操作接口。 它保留了 CLI 易于调用和集成的优势,同时让模型使用自己更熟悉的编程能力完成组合与编排。
当 CLI 成为代码的入口
当 CLI 开始接收代码,下一个问题是:Agent 应该怎样把代码交给执行环境?
严格来说,Heredoc 是 Shell 的输入语法,REPL 是解释器的运行模式,二者并不处在同一个抽象层。本文实际比较的,是 ego-browser 中以 Heredoc 为入口的一次性代码执行,与基于 REPL 的持久交互会话。为了行文简洁,后文分别简称为 Heredoc 和 REPL 。
一种方式是 Heredoc 。以 ego-browser 为例,Agent 可以一次提交整段 JavaScript:
ego-browser nodejs <<'EOF'
await taskSpaces.useOrCreate("读取示例页面");
await browser.openOrReuseTab("https://example.com", { wait: true });
const heading = await page.getByRole("heading").textContent();
console.log(heading);
EOF
Shell 将其中的代码交给 ego-browser ,执行完成后返回结果并退出。对 Agent 来说,这是一次普通的工具调用。
另一种方式是 REPL 。解释器持续运行,Agent 可以多次输入代码,并在会话中保留变量和状态:
> await browser.openOrReuseTab("https://example.com", { wait: true })
< Tab {...}
> await page.getByRole("heading").textContent()
< "Example Domain"
从表达能力上看,两种方式没有本质区别。REPL 可以一次执行包含循环、条件和异常处理的完整代码,Heredoc 也可以只提交一行。
明确的差别在于进程生命周期。Heredoc 的代码执行完毕后,进程随即退出; REPL 则需要长期维护解释器进程,等待后续输入。这也意味着它们对 Agent 工具的要求不同。Heredoc 可以直接运行在常见的请求—响应模型上:
提交命令 → 等待进程退出 → 返回结果
REPL 则要求工具进一步支持持久进程、会话管理、持续写入、中断和恢复。这是很多 agent 自带 bash 工具所不具备的能力(目前主流产品只有 Codex 支持较为完备)。并且工具支持只是使用 REPL 的必要条件,并不能决定模型会怎样使用它。即使两种环境都能运行相同的代码,模型生成代码的方式仍可能不同。
模型在两种环境下会怎样写代码?
理论上,模型在 Heredoc 和 REPL 中拥有相同的编程能力。但我们观察到,模型在 REPL 中更倾向于逐步输入代码,而在 Heredoc 中更倾向于一次生成完整程序。
就像为人类设计软件时需要考虑人体工程学,为 Agent 设计软件时,我们也需要考虑「模型体验工程学」:接口要顺应模型在训练中形成的行为倾向。
Heredoc 与 REPL 的差异,正与模型的训练数据分布有关。
训练数据中的 REPL 内容,通常来自教程、调试过程和问答记录,常见形态是输入一个表达式、查看结果,再继续尝试:
> 获取页面
< 返回页面信息
> 查找元素
< 返回元素信息
> 读取内容
< 返回文本
而 Heredoc 的代码块在形式上更接近脚本或源文件。模型需要在明确的开始和结束边界内完成任务,因此更容易一次写出连续的操作过程:
const page = await openPage();
const element = await findElement(page);
const text = await readText(element);
console.log(text);
这并不意味着 REPL 不能这样写。模型完全可以把同样的完整代码一次提交给 REPL 。区别在于,REPL 的交互语境鼓励“先执行、再观察”,而 Heredoc 的代码块语境鼓励“先组织、再执行”。
这种倾向会进一步影响控制流的位置。在 REPL 中,模型更容易把任务拆成多步,由自己根据每次结果决定下一步;在 Heredoc 中,模型更容易把循环、判断和数据处理直接写进代码,交给本地运行时完成。
实验数据对照
在我们能够稳定接入的主流 Agent 工具中,Codex 提供了运行持久 REPL 所需的执行能力。因此,我们基于 Codex SDK 构建了一套自动化测试,让同一个 Agent 分别通过 REPL 和 Heredoc 完成 4 类真实浏览器任务,并将多次重复运行的结果汇总对比。
这 4 个任务分别是:
- X 热门帖统计:抓取 OpenAI 最近 7 天的主帖,排除置顶、转帖和回复,按 Views 排出前 5 名,并计算互动率与整体平均值。
- OpenAI 招聘申请:准确找到旧金山的 Cloud Infrastructure 岗位,上传简历并填写完整申请表,但停在最终提交之前。
- Redfin 房贷测算:在 Austin 按房型和价格筛选房源,进入排序后的第一套房,将首付改为 20%,读取新的预估月供。
- Expedia 航班筛选:搜索 JFK 到 MIA 的单程直飞航班,选择最便宜的指定航司,填写乘机人信息,并在进入支付流程前停止。
除了基础的打开网页、读取文字,还包含了结构化信息提取、条件筛选、跨页面导航、文件上传、表单填写、页面状态修改和结果计算,基本覆盖了 Browser Agent 最常见的几类操作。

从结果看,两种方式都能完成大部分任务:Heredoc 的 77.5%成功率比 REPL 75.0% 略微高一点。这组实验更值得关注的是两种交互方式在完成同类任务时呈现出的效率差异。
与 REPL 相比,Heredoc 的平均耗时降低了 35.0%,中位耗时降低了 30.7%;工具调用次数减少了 35.5%,Token 消耗减少了 29.8%,平均成本降低了 21.6%。尽管 REPL 支持复用运行状态,但这一能力并未带来更少的交互;实际结果显示,Heredoc 的工具调用次数更少。
这一结果与前文的分析一致。进入 REPL 后,Agent 往往先运行一小段代码,读取结果,再据此决定下一步。原本可以集中在一段程序中完成的循环、筛选与判断,因而被拆成模型与工具之间的多轮往返。
两种执行环境具备相近的表达能力,效率差异主要源于交互形式对 Agent 行为的引导。至少在这 4 类 Browser Agent 任务中,Heredoc 更容易促使模型一次组织出相对完整的程序,将循环、筛选和判断交给代码执行,从而减少逐步决策带来的多轮往返。
为了观察这一趋势在更大样本中是否依然成立,我们又在 Odysseys 数据集上,将 ego-browser 与一款基于 REPL 的同类浏览器自动化产品进行了对比。与前面的同模型实验不同,这里比较的是两套完整方案,因此更适合观察整体效率,不能将全部差异直接归因于 Heredoc 或 REPL 。

这不是 Heredoc 对 REPL 的永久胜利
最后,我们并不认为 Heredoc 天然优于 REPL 。本博客的结论,建立在 2026 年的模型能力、训练数据分布和 Agent 工具形态之上。
今天,大多数 Agent 更擅长一次生成完整代码,它们拥有的 Shell 工具也更适合“提交命令、等待退出、返回结果”的执行方式。因此,Heredoc 更容易减少交互轮次,把控制流交给本地代码完成。
但这些条件可能很快发生变化。随着工具进步,Agent 可能获得可靠的持久会话、结构化输出和状态恢复能力,不再需要自己处理提示符、进程状态和会话中断。针对性的模型训练,也可能让模型在 REPL 中主动提交完整代码,并减少不必要的逐步交互。
到那时,REPL 可以同时保留状态复用和即时反馈的优势,也不一定带来更多的模型调用。在初始化成本较高、需要长期保存状态,或者任务本身具有较强探索性的场景中,它甚至可能成为更好的选择。
这也是标题强调“2026 年”的原因:我们不想说我们发现了什么永久定律,只是和各位分享基于当前模型和工具能力的阶段性工程判断。