文章探讨了AI编程中"上下文腐烂"的问题,分析了三大根源(注意力衰减、代码异味传播、沟通问题),提出用Unix管道架构作为解决方案,通过进程隔离、标准IO和组合能力来构建AI友好的编程范式。

提到AI编程呢,真的是让人欢喜让人优。爱得不行又恨得不行。 写出来的东西前期是好得不得了,后期就垃圾遍地,错觉横飞。 因为他的能力强大,对于研发和产品来说很难割舍不用,但他不受控制,也给后期维护带来的极大地麻烦。

经常行走江湖的朋友都知道,一旦被毒蛇咬了,不要怕,不要慌,剧毒之物,五步之内必有解药。

那问题来了,对于AI编程的这种困境,五步之内是否有解药呢?

我们梳理了一下这些年来的软件工程的编程模型,a~~~,还真的有一个软件的设计架构,刚好可以补足AI编程的短板。只是这个架构太古老了,估计很多人都没有听说过。 这个架构就是命令行Pipeline架构(不记得有没人定义过明确的名称,大概是这个意思)。

1 AI编程的三大绝症

要解决问题,第一步就是要识别问题,找出他的根本原因 1

AI编程前面一开始很厉害,但是越到后期越糟糕,而且是指数级的下降。这种现象被业内人士称为”上下文腐烂”。

它不仅会导致代码质量下降,处处埋伏隐患,而且还无法维护。给实际生成应用带来了很大的挑战。 最新的OpenAI的访谈 2里就提到一个数据就是说目前主流应用AI编程的公司,其工作量100个小时有80个小时都花在AI编码后的验证和确认上。

问题在哪儿呢?

  • 金鱼记忆:上下文窗口的诅咒 大语言模型在长上下文中的注意力衰减问题。简单来说就是AI的记忆力非常有限。 就跟鱼一样只有7秒的记忆。 注意,这不是说他能力不行,相反能力是很强大的。怎么说呢,就像是一条鲸鱼,随便拍拍尾巴就能掀起巨浪,但他的记忆就只有7秒。 他能一下子把人拍飞,也百分百听你的话,但你让他干点复杂的事情,不好意思,拍一下能解决的他能干的很好,拍两下能解决的他能弄得鸡飞狗跳, 拍第二下的时候忘了第一下,连目标都可能丢失了,还顺带造成附加损伤。

  • 代码瘟疫:训练数据的技术债传染 AI模型在训练过程中需要大量的数据训练,比如说来自github的代码库。问题是不是所有的代码都是大师级别的规范设计的,就是经过筛选,也难免其中混杂一些奇怪的思路和做法,这些都会在训练过程中被AI吸收,然后在某个不知道什么时机的点传播到生成结果中。如果仅仅是思路和逻辑弱一点倒也罢了,但如果是存在严重的安全隐患和漏洞,那后果就麻烦了。

  • 沟通深渊:听话的AI是好AI么? AI编码能力是从程序员学来的,当然毛病也有点一样,就是都喜欢写新的代码,不愿意修改现有代码。AI编码在修改现有代码时,尤其容易出现顾此失彼的问题。并且当开发者给出指示后,AI很大部分程度上是对指示100%遵循的。包括你对他说这块颜色不对要黑色中带点五彩斑斓的感觉。或者是这块能不能让他调小一些,但是内容显示的更大。这些要求如果是对人当面沟通,多半就会掀桌子。但AI仍会回复你说:你说的有道理,我立刻按你的要求来改, 然后大肆发挥,你就等着看结果就行,反正你要对结果负责,AI不对结果负责。

2 命令行架构模式, 四十年前的解药

针对AI编码的问题和根源,不难发现,古老的命令行Pipeline架构正恰恰好弥补了AI编码的短板。

命令行Pipeline架构是一种非常实用的古老的软件设计架构。他是如此的简洁、清晰,以至于并没有人为他专门定义过什么理论或者专有名词(我印象中是没有的)。这里我称呼为命令行Pipeline架构,可能不大准,但意思是没问题的。

命令行Pipeline架构的核心思想是 一个工具只做一件事,然后遵循标准的输入和输出。在命令行环境中,多个工具通过管道(|)符号串联,形成一个工作流。前一个工具的标准输出成为下一个工具的标准输入,数据在进程间通过内存缓冲区传递,无需落地为临时文件。

命令行Pipeline架构的核心优势在于其清晰的定义、简单的结构和各步骤间的低耦合性。这种架构直接对抗了AI编程腐烂的三大根源:

  • 进程隔离:让AI编码只敢简单的同时逻辑性强的事 命令行Pipeline将整个任务拆分为多个独立进程,每个进程专注于单一功能。这种设计使得AI生成的代码即使存在缺陷,也不会污染整个工作流。例如,如果数据清洗步骤中的AI生成代码出现错误,后续的特征工程步骤将不会受到影响,开发者可以快速定位问题并进行修复。 同时最核心的一点,就是拆分成的子任务(独立程序)通常是用途单一且明确的,而且范围也不大,其复杂度还可以控制在刚好能在AI腐烂前能解决。这样子AI能一次或简单的几次迭代就能搞定,质量还高。

  • 标准IO协议:用最常见最普通的规则代替混乱 命令行Pipeline强制使用标准输入输出进行数据传递,减少了硬编码和隐式依赖。完全一致的输入输出处理,而且也都是很成熟简单的参数传递机制,使得AI无需额外的过多约束规格定义就能很好的满足整体架构设计的的代码。有点像遵循Restful规范,逻辑上似乎意义不大,但在整体架构上,能提供简单清晰一致的理解和思路,从而简化问题,避免一碗面条式的逻辑。例如,在数据预处理阶段,AI生成的代码必须将处理后的数据输出到标准输出,而后续步骤只需读取标准输入,无需关心具体实现细节。

  • 组合起来威力无边:最为重要的是,每个子任务(独立程序)都可以独立运行,单独工作,简单的测试和验证,独立升级维护。 这使得系统的开发调试运行维护都极为简便,同时组合起来功能强大。

命令行模式是所有模式中难得见到的可以将系统实现简化,操作简化,但是功能却超越预设的强大的一种。所有的按部就班设计的系统,最好的结果就是按照设计的工作。 而命令行模式的各种组合,其形式几乎可以是无穷无尽的。

由于每个子任务(独立程序)都可以单独运行并完整的完成自己的任务,因此多个子任务可以任意的前后组合起来,形成复杂的工作流。 而这一步,只需要简单的shell,bash, cmd脚本批处理就可以做到了。

假设你有10个可独立运行的子任务,一个5层的工作流,理论上来说,就有100000种不同的使用场景。而unix/linux,mac,windows/dos的命令行,通常只有几十到百来个命令。 而这些命令的组合,基本就能满足日常整个操作系统维护的需求。

所以依靠命令行pipeline架构的简单设计,就能实现非常庞大复杂的系统能力。 这是一种化繁为简的神兵利器。

3 命令行架构在AI编程中的实践

命令行架构这么强大,那么,要到哪里才能买…啊不对,要怎么才能用起来呢?

首先,顾名思义,命令行架构,如果你的系统是后端的,不需要UI界面的,基本都可以直接套用。而且思路和设计也极为简单,就是将整个大的系统,尽可能的拆分成可以独立运行的子任务(子系统)。拆的越细越好,越多越好。 每个子任务(子系统)因为是独立运行,因此也可以独立设计,独立开发,如果是多人协作的话,还可以分给不同的人,甚至是外包。

当然这些的前提是子任务的功能足够的清晰,明确,单一;所以要拆的足够的细。举例来说,文件操作很多,也很复杂。单个子任务来维护文件操作就过于庞大了,就可以继续拆分。像是 stat命令,就只做一件事情,返回文件的修改时间访问时间创建时间等几个属性。

基本上,只要能拆到这么细的程度,整个系统架构就算是完成了。

拆的足够细是保证系统能够非常简单的构建。 但要做到想命令行架构一样的强大的组合能力,还需要遵循标准输入输出模式。 这样子才可以将任意的子任务任意的组合起来,形成复杂的工作流。

这里举个简单的例子:

在某电商平台的用户数据分析项目中,开发团队采用了命令行Pipeline架构来处理海量用户数据。整个管道包含数据采集、清洗、特征工程、验证和存储五个步骤:

python collect_data.py --start_date 2025-01-01 | python clean_data.py | python extract_features.py | python validate_features.py | python store_data.py

上面的例子是最简单的直接输入输出重定向,管道串联的例子。 实际使用上,还可以借助shell bash或cmd bat的脚本批处理做粘合剂,实现条件判断,流程跳转,函数调用等等复杂的逻辑。

那是不是仅仅只有后台无界面应用才适合命令行架构模式呢?

也不是的。即便是UI界面丰富的应用,一些情况下也是可以采用或部分采用命令行架构模式的。

在经典的设计模式中,就有一种命令模式的,它的基本思想是将请求封装成一个对象,从而使你可以用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。 其思路也是跟命令行架构非常相似的。每个菜单项单独配置一个Action,每个Action都可以独立运行和测试。

另一种思路也是部分软件系统在采用的,就是将整个系统都设计成后端服务模式,一些必要的UI界面功能,单独通过提供一个网页的形式来操作。 这样子不仅简化了实现,UI界面的调整也变得非常简单。

还有哪些可以应用命令行架构模式的场景呢?欢迎各位分析师来分享和补充。