EN
在未完的书里寻找

输入关键词,寻找已经公开的文章。

← 返回文章
技术与社会 · 人与 AI

为 Agent 写 CLI 后,我开始在“输出”里做设计

CLI 向系统交付行动,也向 Agent 交付下一步所需的上下文。

CLI 是 Command-Line Interface 的缩写,中文通常译作命令行界面。对不熟悉开发工具的人来说,可以把它理解成一种用文字操作软件的方式:图形界面让人点击按钮,CLI 则让人在终端里输入命令,让软件查询信息、修改文件或执行某项操作。

在传统开发语境中,CLI 最鲜明的价值是执行。它直接、可重复,可以写进脚本,也能够与其他工具组合。Agent 开始进入终端以后,CLI 又成为它调用软件能力的一种高效入口。

围绕 Agent 与 CLI,现在已经有不少新的讨论:工具接口的调用效率、输出格式带来的 Token 成本、机器可读的帮助信息和结构化错误。最近,我更常看到 Agent 工程的讨论使用 Harness Engineering 和 Loop Engineering 这样的说法,把注意力放在运行环境与行动循环上;Context Engineering 反而很少再被单独拿出来谈。

我今天还是想从上下文出发,讲一讲最近在 CLI 设计中的一些新思路:当 CLI 开始被 Agent 使用,一条命令执行完以后,Agent 接下来会看到什么,本身就成了一项需要被设计的工作。

一、命令结束,不是 CLI 作用的终点

CLI 向系统交付行动,也向 Agent 交付上下文

大多数时候设计 CLI,首先考虑的是命令能否被正确调用:帮助信息是否清楚,参数是否明确,执行结果是否正确,错误有没有合适的退出码。

开始为 Agent 设计 CLI 以后,我会在这些熟悉的问题之外多看一步。同一段 CLI 输出,对不同调用者有不同作用:人会阅读并理解它,脚本会按照预设逻辑解析和处理它;在常见的 Agent 工作流中,CLI 输出则会先被 Harness 接收,其中被保留下来的部分会作为观察结果(Observation)进入下一轮推理。中间可能经过筛选、截断或重新组织,但 CLI 已经决定了这条链路最初能够获得哪些信息。对 Agent 来说,CLI 输出既是当前命令的执行结果,也是下一次行动的输入。

当命令由 Agent 调用时,CLI 返回的内容已经在参与生产下一轮上下文。当前对象、执行状态、失败原因和可用的后续动作,往往要等命令运行后才能确定。CLI 设计者能够决定的是返回哪些状态、错误、完整性信息和后续入口,以及怎样组织它们,让 Agent 足以据此完成下一步判断。

传统 CLI 的输出设计,大体围绕前两种使用方式展开:让人读懂,以及让脚本解析。以 AWS CLI 为例,它默认返回 JSON,也支持 YAML、Text 和 Table。

例如,AWS CLI 的 list-users 会返回这样的 JSON:

{
  "Users": [
    {
      "Path": "/",
      "UserName": "Admin",
      "UserId": "AIDA...",
      "Arn": "arn:aws:iam::...:user/Admin"
    }
  ]
}

这是一个合格的机器输出。字段稳定,可以继续交给 --queryjq 或另一段脚本处理。它优先保证调用者获得稳定、可解析的数据。

但“用稳定结构返回结果”与“为 Agent 组织下一步所需的上下文”并不是同一个设计目标。JSON 告诉 Agent 系统里有哪些字段和数据;至于当前任务最需要关注什么、结果是否足以支持下一步、接下来有哪些合适的动作,通常仍由 Agent 自己重新判断。

这个区别改变了我设计 CLI 时所问的问题。除了“这条命令应该返回什么结果”,我还会继续追问:“Agent 看完这个结果以后,需要什么才能完成下一步?”

在我的 CLI 设计里,工作流只有一个自然的后续动作时,可以通过 Next 直接给出下一步;存在几个合理方向时,可以通过 Recommendations 给出一组推荐项,并说明它们各自适合什么状态。这里的“下一步”也不一定是另一条命令,它还可能是 Agent 接下来应该怎样向用户回复。

我最近遇到的一个场景,是让 Agent 按照特定模板交付结果。通常,模板会保存在一个独立文件中,再由 AGENTS.md 或其他长期指令要求 Agent 在回复前读取它。问题在于,这条要求往往出现在任务开始的位置;真正需要读取模板,则是在许多轮推理和工具调用之后。模板文件虽然一直存在,它的内容却只有在 Agent 实际读取以后,才会进入当前上下文。

经过多轮推理和工具调用以后,长期指令的遵从可能下降。长上下文实验和 Agent 任务轨迹都观察到了这类现象;研究也发现,在后续轮次重新给出持续指令,可以改善模型的遵从表现。

当前 Agent 所使用的主流通用大语言模型,绝大多数采用自回归的 Transformer 架构。这种架构决定了模型的每一步生成,都是根据此前的 Token 预测下一个 Token。上下文中的 Token 都可以参与预测,但它们的影响并不相同。2026 年,研究者在 Pythia 和 Qwen2.5 上直接测量了较早 Token 对下一 Token 预测分数的影响;跨大量文本位置统计后的中位影响力会随着距离增加而衰减。

这为前面的行为现象提供了一条机制线索:同样一条规则在 Agent 做出决定之前再次出现,通常比只在任务开始时出现一次,更容易影响接下来的生成。命令、工具调用和最终回复虽然由多个 Token 构成,也都从第一个 Token 开始逐步生成;动作开始生成后,已经生成的 Token 又会成为后续预测的新上下文。

于是,我让相关的 CLI 动作在完成以后,通过 Suggestions 返回一组提示:

Suggestions:
- Before responding, read templates/task-result.md.
- Format the final response using that template.

CLI 不需要重复模板的全部内容,只需要在 Agent 即将回复时,再次指出此刻应该读取哪份文件。Agent 随后读取模板,它的内容才会在生成回复之前进入最新的上下文。如果输出格式是不可违反的机器契约,仍然需要 Schema 校验或其他程序化约束;Suggestions 解决的是如何让一条需要 Agent 理解和执行的规则,在相关节点再次出现。

Suggestions 提高了一条规则在当前节点被使用的机会,但不改变系统状态。有些步骤不能只靠提示:程序还需要把一次显式确认绑定到状态转换。此时可以采用另一种设计:有意不在帮助信息中提前展示一项关键参数,等 Agent 真正走到相关节点时,再让程序把这项要求显露出来。

假设 Agent 必须在完成任务前处理一份文档。系统通过 task finish 结束任务,但帮助信息中没有提前展示 --verify-docs 这个参数。

Agent 第一次调用:

task finish

命令不会完成任务,而是返回:

Task not finished: documentation review required.

Review:
- docs/final-check.md
- Update the document if the current task changed its contents.

Retry after review:
- task finish --verify-docs=true

Agent 由此进入一个新的步骤:打开文档,检查内容,需要时完成修改,然后带着 --verify-docs=true 重新调用 task finish

这次失败是有意设计的。它没有把参数遗漏当作普通输入错误,而是利用一次无法完成的调用,把检查要求、待审文档和重试方式送进 Agent 最新一轮的上下文;程序同时拒绝结束任务,让任务不能在没有显式确认的情况下完成。

--verify-docs=true 不是一张验证凭证,而是一次显式确认。程序确保的是:结束任务以前,检查要求会再次明确出现,Agent 必须给出确认;文档是否需要修改、应该怎样修改,仍然由 Agent 根据任务本身决定。

系统规定结束任务前必须给出显式确认,但不替 Agent 规定判断的结果。

普通、稳定、可预见的参数,仍然应该在帮助信息中清楚呈现。但对于需要在特定节点被显式判断、不能在没有确认的情况下完成的关键步骤,帮助信息只负责可发现性;运行时拒绝则把检查要求绑定到任务结束这个状态转换节点。我把这种设计称为“决策时点显影”。

Next 指明自然的后续动作,Recommendations 呈现几个值得考虑的方向,Suggestions 在当前节点触发对长期规则的读取;决策时点显影则进一步把显式确认绑定到状态转换。它们的机制和约束强度并不相同,回答的却是同一个问题:Agent 执行完当前命令以后,CLI 还应该交付什么,才能让它更好地完成下一步?

CLI 不只是执行工具,也是一层为下一步服务的上下文界面(Context Surface)。

二、我把这些经验整理成了一个 Skill

这些认识来自一次次设计帮助信息、输出、错误和下一步提示时遇到的具体问题。后来,我把它们整理成了一个叫 ai-friendly-cli-design 的 Skill。

Skill 地址:https://github.com/Biaoo/skills/blob/main/skills/agent-systems/ai-friendly-cli-design/SKILL.md

它最核心的判断是:

A CLI command is not only an execution surface. It is a context delivery surface for the next Agent step.

Karpathy 曾把软件分成三种正在并存的范式:Software 1.0 是人写下的明确指令,Software 2.0 是通过数据和训练得到的神经网络权重;到了 Software 3.0,程序开始由自然语言构成,大语言模型也成为一种可以通过自然语言编程的新型计算机。

沿着 Software 3.0 的框架再往运行时推进一步,自然语言对 Agent 行为的塑造并不只发生在初始提示词里。Agent 在运行过程中不断获得的上下文,也在持续塑造它的下一步行为。CLI 返回的帮助信息、执行结果、错误提示和后续行动建议,不再只是软件的说明或输出,也成为软件行为设计的一部分。

以后让 Codex 或其他 Agent 帮我设计 CLI 时,我会用这个 Skill 让它们同时设计两件事:一条命令应该完成什么,以及命令结束以后,调用它的 Agent 应该看到什么。

过去,我把 CLI 看作 Agent 操作软件的入口。现在,它也是软件世界进入 Agent 下一次判断的入口。

WECHAT · 微信公众号仓颉的未完书公众号二维码仓颉的未完书

微信扫码关注,继续阅读。