..

管道不死,也不凋零

2026 年春天,技术圈忽然开始怀旧。钉钉和飞书先后放出官方 CLI 工具,Gemini CLI 开源,开发者们围着命令行讨论得热火朝天。社交媒体上到处是「CLI 才是 Agent 的终局」之类的标题。

命令行回来了。或者说,它从未离开。

但 CLI 本身——那个黑底白字的终端窗口、那些 --flag 和子命令——只是表象。CLI 不过是管道的入口。真正值钱的,是管道。

为什么又轮到 CLI 了

先回答一个朴素的问题:2026 年了,为什么是命令行,而不是更现代的东西。

两年前,AI Agent 的工具调用还在走 MCP(Model Context Protocol)路线。Anthropic 推出这套协议,OpenAI 和其他厂商都迅速跟进。思路很清晰:给每个外部工具写一个标准化的 JSON-RPC 接口,模型通过结构化请求来调用。像极了二十年前 SOAP 和 WSDL 的故事1——先定义契约,再按契约办事。

MCP 的问题不是它不对,而是它太重了。你想让 Agent 查一下日志里有多少条报错,得先有人写一个 MCP Server,定义好 Schema,部署好鉴权。等这些都搞完,你手动敲一行 grep "ERROR" app.log | wc -l 早就拿到答案了。

开发者们发现,世界上已经存在几十万个现成的 CLI 工具。Git、Docker、FFmpeg、SQLite、curl——它们覆盖了你能想到的几乎所有操作,而且每一个都经过了几十年的打磨。不需要写 Server,不需要定义 Schema,安装完就能用。

更要命的是,大模型天然就会用这些东西。训练语料里有数以亿计的 Shell 脚本、Stack Overflow 问答、Linux 手册。对模型来说,grep -r "TODO" src/ 不是需要学习的新知识,是肌肉记忆2。你不用花几千个 Token 去解释一个 API 的参数含义,模型自己就知道 -i 是忽略大小写,-E 是正则。

所以 CLI 的回归不是怀旧,是经济学。现成的生态加上模型的内化知识——CLI 是 Agent 拿到外部能力最便宜的路。

还有一层更根本的原因:CLI 天然适配管道,GUI 不行。

GUI 的输出是像素。一个按钮点下去,屏幕上变了一块颜色,这块颜色没有标准的方式传给下一个程序。你没法把 Photoshop 的导出结果「接」到 Slack 的发送动作上——除非有人专门写一个插件。协作靠剪贴板、拖拽、或开发者预先埋好的集成入口,每一条路径都是特制的。

CLI 的输出是文本流。文本流有一个极好的特性:它不关心上游是谁。grep 不在乎它处理的文本来自 catcurl 还是 docker logs。任何程序只要往 stdout 吐文本,就能被管道接走。组合是默认行为,不需要额外开发。

对 Agent 来说,这意味着一件事:它不需要为每个工具的输出学一套特殊的处理方式。所有东西都是文本,所有文本都能进管道,所有管道都能串起来。

管道才是本体

但 CLI 只是前台。后台的主角是管道。

Doug McIlroy 在 1964 年写了一份备忘录3,建议 Unix 系统增加一种机制,让程序的输出可以直接接入另一个程序的输入。Ken Thompson 在 1973 年用 | 符号实现了它。这个看上去毫不起眼的竖线,可能是计算机史上投入产出比最高的发明之一。 mcilroy-memo

管道做了一件极简的事:让数据在进程之间流动,不落地、不暂存、不需要中间人。

这件事在 LLM 时代格外重要。原因只有一个:上下文窗口是有限资源。

假设你要从一个十万行的日志文件里找出最近的五条报错。在 MCP 模式下,你得先有人把「日志查询」「排序」「截取」分别封装成三个 MCP 工具,定义好各自的 Schema,部署好服务。模型可以依次调用它们,逻辑上并不复杂——但前提是这三个工具已经存在。瓶颈不在调用,在接入。每个新场景都需要开发者提前预设工具。

用管道的做法是:

grep "ERROR" app.log | sort -t' ' -k1 | tail -5

三个进程,在操作系统的内核缓冲区里依次处理文本流。grep 滤掉了 99% 的无关行,sort 按时间排列,tail 只留最后五条。中间产生过多少行数据?模型不知道,也不需要知道。进入上下文的只有最终的五行结果。

这就是管道的核心价值:中间结果不进入上下文。

过滤、排序、截断——这些确定性计算,MCP 模式也能做。区别不在于模型能不能调用,而在于工具是否已经存在。MCP 的每一种组合都依赖开发者预先封装的方法;而管道的组合是即席的。模型现场用 | 拼接命令,不需要任何人提前定义接口。操作系统的内核缓冲区替你搬运数据,不需要解析中间格式。管道把工具接入的门槛降到最低,把模型的注意力留给需要语义理解的活。

用公式说:如果一条管道有 \(n\) 个阶段,每个阶段将数据量压缩为前一阶段的 \(r\)(\(0 < r < 1\)),那么最终返回给模型的结果只有原始数据量的 \(r^n\)。三个阶段,每个阶段保留十分之一,最终只剩千分之一。其余的数据从未离开过操作系统的内核缓冲区。

Unix 哲学和它的反面

管道不是孤立的发明。它是 Unix 哲学的核心表达。

这套哲学的要点很简单4:每个程序只做一件事,做好它;程序之间通过文本流协作;万物皆文件。Doug McIlroy 还补充了一条:期望每个程序的输出成为另一个程序的输入——所以不要在输出里加多余的装饰。

Bash 是这套哲学最忠实的执行者。它本身几乎不做事,只负责把小工具串起来。grep 只搜索,sort 只排序,awk 只做列提取。每个工具沉默寡言,只吐结果,不废话。McIlroy 五十年前就说了:如果你往标准输出里塞装饰性文字,下游的管道就没法接。

PowerShell 走了相反的路。它传递的不是文本流,而是 .NET 对象。Get-Process | Sort-Object CPU | Select-Object -First 5 看起来和 Bash 管道很像,但管道里流动的是有类型的结构化对象。每个对象带着属性、方法、类型信息。这和 MCP 的思路其实是一样的:用强类型契约来保证数据在组件之间传递时不会出错。

这个设计在传统编程中有明显的优势。你不需要解析文本,不需要担心列对不齐,不需要猜某个字段是字符串还是数字。类型系统替你做了这些事。

但在 LLM 时代,这个优势变成了包袱。

LLM 的训练集——维基百科、GitHub、arXiv、Common Crawl——绝大多数是行式的自然语言和代码。.NET 对象对模型来说是异物,需要先序列化才能处理。而 Bash 管道里的文本流,格式上和模型见过最多的 Shell 交互记录一模一样,天然就在它的舒适区里。

PowerShell 的对象管道是封闭的。对象必须符合特定的类型定义,跨系统传递时需要序列化和反序列化。而 Bash 的文本管道是开放的。任何东西,只要能输出一行一行的文本,就能接入管道。这种「弱类型」的特征,在需要精确性的场合是缺陷,在需要灵活性的场合却是巨大的优势。

Agent 操作的世界恰好是后者。它要跟几十个不同厂商的工具打交道,每个工具的数据格式都不一样。纯文本是它们的最大公约数。管道把所有工具拉到同一个平面上。不管你原来输出 JSON、CSV 还是自定义格式,过一遍 jqawk,就变成模型能直接理解的东西。

Bash 选择的是粗粝的自由。PowerShell 选择的是精致的秩序。老兵不死——也没凋零,只是在终端里安静地等了五十年,等到 LLM 来了,把自由变成了生产力。

辩证地看

说了这么多管道的好话,该说说它不行的地方。

安全性是管道模式最大的隐患。 给 Agent 一个 Shell,等于给了它一把万能钥匙。风险有两层:一是命令注入——一个恶意构造的文件名里藏着 ; rm -rf /,经过管道接入 Shell 时可能被直接执行。这不是假想场景:2011 年 Bumblebee 开源显卡驱动的安装脚本里,/usr 后面多了一个空格,rm -rf /usr /lib/nvidia-current/xorg/xorg 变成了 rm -rf /usr /lib/...——直接删掉了用户的整个 /usr 目录5。Shell 不会替你检查意图,它只忠实地执行字面命令。二是提示词注入——管道返回的文本里藏着精心构造的指令,诱导模型执行非预期操作(这一点 MCP 返回的 JSON 里一样可能发生,但管道的攻击面更宽,因为 Shell 本身就是一个完整的执行环境)。MCP 的 Schema 定义了「合法行为的边界」,相当于一道前置防火墙;纯文本管道没有这道墙。

语义过滤是管道的盲区。 grep 只做关键词匹配,sort 只做字典序或数值排序。如果你需要「找出那些语气愤怒的用户评论」,这一步必须交给模型,管道帮不了忙。确定性的过滤交给 CPU,语义的过滤交给 GPU——这条分界线在实际操作中并不总是清晰的。

长链条的误差累积不可忽视。 如果管道中某个环节的输出格式发生了细微变化(比如日志的时间戳从 ISO 格式变成了 Unix 时间戳),下游的 sortawk 可能静默地产出错误结果。没有 Schema 做契约检查,这种错误很难被发现。管道越长,累积出沉默 bug 的概率越大。

跨平台一致性仍是老问题。 macOS 的 sed 和 GNU sed 参数不同,BSD grep 没有 -P 选项。模型训练集里的 Shell 范例大多来自 Linux,在 macOS 或 Alpine 上跑起来未必顺畅。这是五十年来 Unix 世界一直没解决干净的碎片化问题。

所以准确的说法是:管道适合做 Agent 与外部世界交互的「默认模式」,不适合做「唯一模式」。对于探索性任务、个人自动化、快速原型,管道的灵活性和效率无可匹敌。对于高并发、高安全、强审计的生产环境,结构化协议仍然是更安全的选择。

两者不是替代关系,是分层关系。底层操作用管道,高层集成用协议。让操作系统处理数据流,让模型处理语义流,让协议处理信任流。

一根竖线

1973 年,Ken Thompson 在 Unix 第三版里加入了管道符 |。五十三年后,这根竖线成了 AI Agent 与外部世界之间最短的路径。

管道的本质从未改变:让数据流过去,只留下你需要的。五十年前,这省的是程序员的时间。今天,省的是模型的上下文窗口——而上下文窗口,就是 Agent 的工作记忆,是它思考的全部空间。

CLI 的兴起不过是表象。管道才是那个安静、古老、一直在场的东西。它不声张,不定义协议,不要求你注册应用。它只做一件事:把输出接到输入上。


  1. SOAP(Simple Object Access Protocol)和 WSDL(Web Services Description Language)是 2000 年代企业级 Web 服务的标准协议。为了调用一个远程方法,你得先写一份几百行的 XML 契约来描述接口。它们后来被更轻量的 REST 风格几乎全面取代。参见 W3C SOAP Specification

  2. 这也解释了为什么钉钉、飞书开放 CLI 而非仅靠 API——虽然这些专有命令本身没有被模型内化,但 Unix 风格的命令语法(--flag、子命令、管道组合)是内化的。模型不认识 lark-cli,但它精通这门「语言」的语法。 

  3. The Origin of Unix Pipes - Doug McIlroy’s memo, 1964 

  4. 麦克罗伊的原始表述见 Bell System Technical Journal, 1978:“Make each program do one thing well. To do a new job, build afresh rather than complicate old programs by adding new features. Expect the output of every program to become the input to another, as yet unknown, program.” 

  5. 这个 bug 的 commit 和随之而来的 issue #123 成了开源社区的十年名梗。一个空格,毁掉整个系统。BTW,Qwen 系列模型会在英文和中文之间加空格,即使是文件路径也会,排版指南看多了到处炫技么。🤷 

EOF 🤞