管道不死,也不凋零
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 不在乎它处理的文本来自 cat、curl 还是 docker logs。任何程序只要往 stdout 吐文本,就能被管道接走。组合是默认行为,不需要额外开发。
对 Agent 来说,这意味着一件事:它不需要为每个工具的输出学一套特殊的处理方式。所有东西都是文本,所有文本都能进管道,所有管道都能串起来。
管道才是本体
但 CLI 只是前台。后台的主角是管道。
Doug McIlroy 在 1964 年写了一份备忘录3,建议 Unix 系统增加一种机制,让程序的输出可以直接接入另一个程序的输入。Ken Thompson 在 1973 年用 | 符号实现了它。这个看上去毫不起眼的竖线,可能是计算机史上投入产出比最高的发明之一。

管道做了一件极简的事:让数据在进程之间流动,不落地、不暂存、不需要中间人。
这件事在 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 还是自定义格式,过一遍 jq 或 awk,就变成模型能直接理解的东西。
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 时间戳),下游的 sort 和 awk 可能静默地产出错误结果。没有 Schema 做契约检查,这种错误很难被发现。管道越长,累积出沉默 bug 的概率越大。
跨平台一致性仍是老问题。 macOS 的 sed 和 GNU sed 参数不同,BSD grep 没有 -P 选项。模型训练集里的 Shell 范例大多来自 Linux,在 macOS 或 Alpine 上跑起来未必顺畅。这是五十年来 Unix 世界一直没解决干净的碎片化问题。
所以准确的说法是:管道适合做 Agent 与外部世界交互的「默认模式」,不适合做「唯一模式」。对于探索性任务、个人自动化、快速原型,管道的灵活性和效率无可匹敌。对于高并发、高安全、强审计的生产环境,结构化协议仍然是更安全的选择。
两者不是替代关系,是分层关系。底层操作用管道,高层集成用协议。让操作系统处理数据流,让模型处理语义流,让协议处理信任流。
一根竖线
1973 年,Ken Thompson 在 Unix 第三版里加入了管道符 |。五十三年后,这根竖线成了 AI Agent 与外部世界之间最短的路径。
管道的本质从未改变:让数据流过去,只留下你需要的。五十年前,这省的是程序员的时间。今天,省的是模型的上下文窗口——而上下文窗口,就是 Agent 的工作记忆,是它思考的全部空间。
CLI 的兴起不过是表象。管道才是那个安静、古老、一直在场的东西。它不声张,不定义协议,不要求你注册应用。它只做一件事:把输出接到输入上。
-
SOAP(Simple Object Access Protocol)和 WSDL(Web Services Description Language)是 2000 年代企业级 Web 服务的标准协议。为了调用一个远程方法,你得先写一份几百行的 XML 契约来描述接口。它们后来被更轻量的 REST 风格几乎全面取代。参见 W3C SOAP Specification. ↩
-
这也解释了为什么钉钉、飞书开放 CLI 而非仅靠 API——虽然这些专有命令本身没有被模型内化,但 Unix 风格的命令语法(
--flag、子命令、管道组合)是内化的。模型不认识lark-cli,但它精通这门「语言」的语法。 ↩ -
麦克罗伊的原始表述见 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.” ↩
-
这个 bug 的 commit 和随之而来的 issue #123 成了开源社区的十年名梗。一个空格,毁掉整个系统。BTW,Qwen 系列模型会在英文和中文之间加空格,即使是文件路径也会,排版指南看多了到处炫技么。🤷 ↩