你的CLI有了新用户,它不是人类

你向你的AI副驾驶要求捕获一个窗口。副驾驶写下peek app "Xcode"。工具尝试寻找一个精确名称为Xcode的窗口,但没有找到,因为实际的进程名是Xcode-16.3。工具打印出Error: application not found。这位情感记忆如金鱼般的副驾驶尝试peek app "Xcode-16.3",成功了。但浪费了一次对话轮次、输入和输出的令牌,还有支付账单的用户的耐心。 现在想象另一种场景:副驾驶写下peek app xcode。工具会自动标准化名称,进行模糊匹配,找到Xcode-16.3,捕获窗口,并返回/tmp/peek/Xcode-16.3-1712524800.png。一个输出令牌。零次无效尝试。 这两种情况的差别不是一个bug,而是一个设计决策。 那些不会看你--help的用户 2025年初,Netlify的CEO Mathias Biilmann创造了术语“智能代理体验”(Agent Experience,即AX),用来描述AI代理在与一款产品互动时所拥有的体验。正如用户体验(UX)关注的是人类用户,开发者体验(DX)面向的是开发者,智能代理体验(AX)则专注于LLM。 这个概念听起来很抽象,直到你把它应用到某些具体的东西上。例如,命令行工具(CLI)。CLI已有40年的历史,其设计一直是为了与人类用户交互:描述性的信息、颜色、高度可视化的进度条以及--help页面。这些对于LLM来说全是“噪音”。一个LLM不会查看帮助信息——它会根据命令名称推断出标志。它不会欣赏绿色的“成功”提示——它只处理纯文本。它也不会观察进度条——它只等待过程完成。 传统CLI的设计旨在让人类用户理解发生了什么,而AX则优化CLI工具,以便智能代理能用最少的令牌和轮次来完成操作。 五项原则,三款工具 在过去的几个月里,我创建了三款秉持同一理念的CLI工具:peek(用于macOS窗口捕获)、lql(用于Linear问题管理)和driftkit(用于智能代理的行为审核工具)。它们都设计成即使没有说明文档,LLM也可以使用。从这些经验中总结出了五项原则。 1. 输出是契约,不是对话 传统的CLI用于窗口捕获时可能会输出类似以下的信息: ✅ Screenshot saved successfully! File: /tmp/peek/Xcode-1712524800.png Size: 1920x1080 Format: PNG 这看起来很漂亮,也很有信息量。但对于需要将路径传递到另一工具的LLM来说完全没用。它不得不解析这个输出,忽略掉表情符号,找到以File:开头的那行,并提取路径。浪费了令牌。 peek只输出一个内容: /tmp/peek/Xcode-1712524800.png 一个路径,没有其他多余信息。LLM直接读取、使用并继续。stdout的输出是一种契约:始终是一个容易解析的路径,始终保持稳定。如果更改格式,就破坏了契约,也会让所有依赖该工具的代理出错。 也就是说:你的stdout是API,而不是用来“装饰”的。 2. 容忍幻觉——不要惩罚它们 LLM会产生幻觉命名。这是一种自然现象,就像地心引力或wifi总是在你赶时间时信号变差。如果你的工具需要准确名称,那就是在向一种基于概率的机器要求精确。这是行不通的。 peek有三种搜索模式以找到应用程序: 精确匹配(不区分大小写):xcode → Xcode 标准化匹配(去除空格和短横线):thinklocal → ThinkLocal 部分匹配:xcode → Xcode-16.3 LLM并不需要知道进程的确切名称。它只需给出一个大致的名字,工具会处理剩下的事情。lql也采取类似的方法来匹配项目和团队的名字——它会根据部分内容将tokamak解析为Tokamak,而无需使用UUID。 原则很简单:如果监督代理的那个人类能够推测出它的意思,那么工具也应该能够做到。 3. 错误信息应该告诉用户怎么做,而不是发生了什么 对比一下以下两个错误消息: Error: application not found in window list Error: "Xcode" is not running. Start it with: open -a "Xcode" 第一个描述了问题所在。第二个则提供了解决问题的方法。人类读了第一个会想“哦,没打开啊。”LLM读到第一个后会……用其他名字试试,或者去Google搜索,又或者发明一个--force标志。而对于第二个,LLM会直接执行open -a "Xcode",等待,然后再试一次。问题在一个轮次内得以解决。 ...

2026年4月7日 · Fernando