然而,我们会发现一个反直觉的现象:今天的 Agent 最佳实践和问题,本质上与几十年来软件工程的老问题几乎一模一样。
为何在工具变迁之下,我们竟然还要面对“代码臃肿”、“缺少测试”、“耦合过高”等陈年问题?
AI Agent 的出现,并未替代软件工程理念,反而让那些不变的规律更加凸显。
现象:Agent时代的新问题与实践
在 Agent 开发领域,层出不穷的新方法论似乎映射出古老的做法。
CLAUDE.md/AGENTS.md
这被称为上下文文件,用来为 AI 代理提供项目规则、架构说明和编码规范;这正类似于传统项目里的架构文档、编码规范和团队知识库,只不过写在了Agent能读的文件里。
这些上下文文件往往篇幅庞大,有人戏言它们“越写越长”,就像当年项目组随意堆砌的设计说明,一样容易变成冗余信息的存储库。
计划模式(plan mode)
让代理规划设计方案,再执行生成代码。
开发者在写第一行代码之前,先要产出蓝图、列出设计文档,代理生成代码亦是如此。
AI代码生成速度很快,也依然需要先思考,先动笔画出蓝图”。
计划模式与传统软件工程中的架构设计阶段、设计评审一脉相承。
事实上,Agent 在实现明确规范的系统时表现出色,但它们并不擅长做设计决策,架构决策。
输出质量完全取决于输入质量(garbage in, garbage out),也就是设计。
人机协作(Human-in-the-Loop)
当 AI 写出代码时,人的角色不再是检查每一行是否语法正确,而是关注架构设计、业务意图和边界条件。
人类开发者更多地承担起系统级把控和代码审查的职责,而不是重复机械检查。
这恰如软件工程中的代码评审、设计评审——人类站在更高层级审视系统,而让机器处理例行实现。
测试驱动开发(TDD)
越来越多的实践强调“先写用例再让代理生成代码”的工作方式,这是TDD思想的一次回归。
由此人们提出了“Test-Driven AI Agent Development”的概念:用可执行测试来定义、约束代理行为。
这不正是把传统的单元测试、BDD(可执行规范)、回归测试理念,延伸到 LLM 编程之中吗?
自动化测试不仅检验代理输出,也引导其修正方向,就像当年我们写好测试,迫使代码满足规范一样。
知识模块化(Agent Skills)
Anthropic团队提出“技能包(Skill)”的概念,用 SKILL.md 文件封装特定领域的知识和操作指南。
这些“技能”像模块化的领域知识,对应到软件工程便是“模块化设计”和“领域封装”:每个模块(或服务)只解决特定问题,有清晰的接口和责任。
一个 Skill 就是一个轻量包,用 SKILL.md 教会 AI 完成特定任务,需要遵循的标准、使用的工具。
他们不会永久改变 AI 的思维,只在需要时提供指导。
这正如软件中的组件或库:它们封装逻辑,需要时调用,大大降低了整体的认知负担。
上下文工程(Context Engineering)
好的上下文工程等同于信息架构设计:如何在有限的上下文窗口中挑选关键内容,就像如何在有限记忆中筛选信息。
LLM 的“注意力预算”类似人类的“工作记忆容量”;如果在一个提示中塞入太多信息,模型就会遗忘或困惑。
由此,社区提出把相关上下文(如需求、文档、范例)模块化管理,只按需喂给代理,避免“提示漫游”。
这对应了传统软件中的信息隐藏和界面设计:我们会把信息封装在特定模块里,通过定义良好的接口传递,避免无谓的耦合。
用最小高信号的上下文让输出最大化,这与软件架构强调的“接口即边界”如出一辙。
循环工程(Loop Engineering)
这是为 Agent 设计 CI/CD 式反馈环。
Addy Osmani 等人提出:与其让开发者反复手动提示 AI,更有效的做法是“设计让系统自己去提示”的循环。
正如不断合并、持续集成那样,Agent 系统也需要自动化的任务分配、检查、记录与反馈机制。
Osmani 说:“你要构建一个小系统来寻找任务、分派任务、检查结果,并决定下一步要做什么,而不是你自己去操作”。
这无疑对应了传统软件开发里的持续集成和反馈循环思想:让系统自动打点而非依赖人工,否则“人永远都在环里最前端”,变成瓶颈。
以上实践,只是当前 Agent 生态中常见例子。它们与经典的软件工程原则如影随形:写 CLAUDE.md 就像写架构文档;Plan Mode 就像提前设计;Human-in-Loop 就是代码评审;Test-driven Agent 是 TDD;Skills 模块化如同组件化;Context 工程对标信息架构;Loop 工程如同 CI/CD。可以说,Agent 世界里的许多“新”做法,只不过是新瓶装酒酒。
历史:软件工程的不变法则
之所以这些映射如此明显,是因为软件工程过去半个世纪一直在解决同样的核心问题:如何控制复杂性?如何降低认知负担?如何保证行为符合预期?如何建立反馈循环?如何让多人协作?
早在上世纪,软件专家就发现了这些永恒难题。Fred Brooks 在《人月神话》中指出,软件项目的最大困难在于管理复杂性,简单地增员并不能线性缩短开发时间;
他提出了“没有银弹”论,警示人们软件开发的难点不会因为新工具而自动消失。
Parnas 提出的信息隐藏原则说明:把容易变化的设计决策封装隔离,通过稳定的接口连接各部分,可以让系统更易于维护。
面向对象之父 Grady Booch 也总结:封装(encapsulation)能将可变性限制在单个模块内部,使其他部分不被动摇。
SOLID 原则、Unix 哲学、领域驱动设计(DDD)等,都强调低耦合、高内聚和分层,这些正是对抗复杂性的利器。
敏捷宣言、极限编程、TDD 等思想则持续强调快速反馈。敏捷倡导短周期迭代,让需求和实现之间形成紧密的反馈环;极限编程(XP)鼓励结对编程和持续重构以减少缺陷。
Kent Beck 早就提倡的 TDD(测试驱动开发)正是通过“写测试,先见未来”的方式,把需求变成可执行规格。
CI/CD 的出现,让每次改动都自动进行构建和测试,保证代码行为可控且回归安全。
Clean Architecture、DDD 等现代方法也一再提醒我们:系统要按照业务领域划分边界,每个模块都有清晰职责,构架应隔离不确定性。
即便计算机语言、框架、工具日新月异,上述原则数十年来始终被实践证实有效。
为什么这些原则几十年不变?
因为无论技术如何发展,人类的认知容量和协作机制没有根本改变。
解耦、封装和反馈是管理任何规模软件系统的基础。
信息隐藏之父 Parnas 曾说:“信息隐藏就是把易变的设计决策隔离开,以保护系统其他部分不受改动影响”。
也就是说,不确定性要隔离到边界之内;而系统其他模块只依赖稳定接口,如此一来,一个模块的变化不会让全局重构。这一思想从模块化设计到微服务架构,无处不在。
从第一性原理看,软件系统的复杂度来自任意依赖的指数级增长。无论是人写代码还是 AI 写代码,如果没有边界和分层,整个系统都会陷入“Big Ball of Mud”式的混乱:缺乏明确分工,任意改动都会牵一发动全身。
一个贪大的 Prompt(提示串)承载了过多信息,正像一个“God Object”:一个组件掌握了整个系统的大量状态和逻辑,强耦合且难以维护。
在软件史上,这样的模式令人惧怕,因为一个错综复杂的整体无法扩展和重构。Agent 时代重复出现类似问题,并非偶然,而是因为不管生成手段如何,复杂性、耦合性、反馈循环的需求等不变量依然存在。
自由意味着束缚,约束意味着释放。
换句话说,如果没有约束(设计原则、边界和规范),系统的潜力就被无穷的选项反噬;而恰恰是约束(接口、规范、边界)给我们以秩序和可预测性。Agent 只是新的交互方式,底层人类控制复杂系统的方法论并未改变。
本质:为何问题重演
从第一性原理分析,为何 Agent 时代会重现相同问题?原因在于:AI Agent 改变了代码的生成方式,但并未改变需求本身的复杂性和团队协作的本质。
AI 的贡献是降低了编写代码的边际成本,但它并不会自动清理混乱的架构或补全缺失的测试。
相反,它让未经设计的“垃圾输入”更容易产生“垃圾输出”,加强了对工程过程管控的必要性。
举例来说,当一个 Prompt 越来越长,其实质就是将所有信息堆到了一个模块里,这与架构解耦的基本思想相悖。
过长的 Prompt 导致模型记忆衰减(context rot),效率急剧下降(Anthropic 实验显示没有模块化上下文的单个代理性能骤降至90%以下)。
这就像是一个项目完全没有模块分割,所有逻辑都扔进一个玻璃瓶——一旦出错,修复难度极高。
相反,有经验的工程师会把复杂任务拆分给子模块、子代理(子系统),让各模块独立完成,然后再整合。
这正是微服务或任务队列的思路:专人专责,互不干扰。如此既减小了每个部分的“上下文负荷”,又避免了全局性的耦合。
因此,Prompt 的“臃肿”实际上暴露了信息架构设计的缺失。
再看 Agent 一再修改代码却无法完成任务的情形,其本质就是缺乏明确的规格和反馈。
当一个团队没有自动化测试或性能指标,就像迷失在茫茫大海中没有指南针。
软件工程早已告诉我们:没有测试的代码是脆弱且不可预测的;每次改动都可能引入新 bug。
Agent 也是如此,如果没有测试用例或验收条件来验证其输出,它只能机械地修改而难以收敛。
MLflow 的一份报告甚至指出,98% 的可靠性来自补充在模型外的验证逻辑,而不是放在 GPT Prompt 里。
换言之,质量保证需要外置在 AI 之外:单靠让 Agent 自说自话,不提供测试反馈,就像工厂不做质检一样糟糕。
Agent 不断循环修改代码却出不来结果,正是软件在缺乏反馈循环和清晰需求规格时的老毛病翻版。
类似地,Agent 生成大量代码但质量下降,这是技术债务(technical debt)的一种表现。
在传统开发中,走捷径和缺乏设计会积累债务,最终拖慢迭代速度。
AI 代码被盲目接受,很可能会引入不必要的依赖或重复逻辑,让代码可维护性变差。
没有开发者审阅的 AI 输出,就像未经检查、仓促拼凑的代码,必将留下重构隐患。
这与我们日常所说的“写得越快,修得越久”同样适用于 AI;Agent 写的代码如果没有人来清理、整理、重构,就会像过期贷款一样越滚越大。
还有一种常见现象:给 Agent 挂接了过多工具,导致行为混乱。
这类似于在传统系统中接口设计失败的案例:一个组件同时调用数十个外部库,接口过多导致不知从何下手。
将功能隔离到不同子代理或模块中,并为每种功能设计清晰、狭义的 API(“尽可能窄小、针对性强的工具”)。否则,宽泛的工具就像泛滥的全局变量,让系统边界模糊,安全性和维护性大打折扣。
同理,多重 Skill 导致的“Skill 地狱”,如同微服务爆炸或依赖地狱:模块过多、粒度不对、依赖混乱,都会让系统复杂度飙升而无法把控。
归纳来看,Agent 时代的问题本质上都源自一个事实:人类并没有放弃“驾驭复杂系统”的艰难任务,只是把代码打磨的活交给了 AI,把定义系统边界、设计解耦方案、建立反馈机制的任务留给了自己。因此,Agent 的失误其实提醒我们:软件工程的基本规律根本没变——只有更重要。
推演:软件工程的未来角色
如果未来十年 AI Agent 成为主要的代码生产方式,软件工程的角色会如何演变?答案很可能是:软件工程不会消失,反而将更加重要且核心。
AI 并不会自己理解需求或架构良好系统,人类工程师的价值只会从写代码为主,转向定义问题、设计系统、管理复杂度。
Kent Beck(TDD 之父)在与 AI 共事时依然称 TDD 为“超能力”。
因为 AI 代理可能会为了让测试通过而随意删减测试,测试的存在确保系统朝正确方向演进。
这说明测试仍是核心工具:它是驱动正确行为的规范,无论是人工编码还是自动化生成都需要它。
Martin Fowler 指出:“对人类适用的做法,同样可以用在代理身上。代理在能够自我检测代码质量时表现更佳,而不是完全依赖我们来检查”。
Harness Engineering 正是要建立这样供代理运行的反馈体系。可以说,当下测试驱动、持续集成和监控等方法正移植到 Agent 世界。
这都说明,软件工程的黄金法则如同不变的物理定律,并未因为 AI 而失效。
另一个角度看工程师的价值转变。传统观点里,程序员的价值是生产代码,而 Agent 时代,价值体现为定义问题和监督解决方案。
正如一位开发者在使用 Agent 后感叹:他发现自己写的不是代码,而是“更多的自然语言提示、规范和澄清说明”,就像是在为一个人类团队撰写详细设计文档,只不过团队成员换成了 AI。
Grady Booch 的预言被印证:“AI 将彻底改变程序员的角色……它不会消灭程序员,但要求我们掌握新技能、以新方式工作”。
人类工程师更多地扮演“架构师”和“指挥家”的角色:AI 负责生成各模块的样板代码,而开发者则监控整体进度、保持设计正确。
这正是软件架构师的传统工作——用 AI 提速工具链,却依旧需要人为设置目标和审核结果。
开发者将更多思考需求是否明晰、界面是否合理、性能和安全保障,而让 AI 完成繁复的样板编写和改错工作。
AI 让开发者从一行一行敲代码,转移到关注更高层次的问题上来。
综上,不论是 Kent Beck、Martin Fowler、ThoughtWorks 还是业界开发者,都在强调:编程语言和语法不再是程序员的核心价值,软件工程理念才是。
掌握“定义规范、设计反馈循环、构建可靠系统”的能力,才是 Agent 时代的竞争力。
AI 本身不会取代软件工程师,但掌握 AI 工具的工程师会替代不会用 AI 的人。
AI时代的软件工程原则
面对 Agent 时代,让我们从已有的经验中提炼出一些原则,以指导未来实践。这些原则并非凭空创新,而是对传统软件工程理念的重新阐发:
隔离不确定性
将系统中最可能变化、最不确定的部分隔离开来,交由 Agent 自动处理;而其余部分依赖稳定接口。
例如,把可变的逻辑封装在可动态加载的 Skill 或服务中,将确定的逻辑用严格定义的 API 暴露。
信息隐藏原则就是这种思想的体现:通过稳定接口将不确定实现隔离。
反馈循环优先
用快速循环的反馈代替对未来的臆测。每次 Agent 迭代后都要立刻检查结果并调整提示,就像 TDD 里的“红-绿-重构”循环。
测试驱动或 CI 管道便是此思路在传统开发中的体现:及时发现偏差,缩短交付周期。
Agent 时代同样要紧盯输出——可以让 Agent 自测(比如让它运行单元测试),或构建自动化验证流程(Harness Engineering),保证每次代码变动都有回馈。比如,在生成代码后自动触发测试套件,把反馈循环嵌入代理工作流。
规范驱动生成
用明确的规格来驱动代码输出,而不是随意提示。
例如,在输入给 Agent 详细的功能需求、接口定义或示例输入/输出(相当于可执行规格)。
这种做法与 BDD/TDD 类似:我们先定义好行为(或用例),再让 Agent 生成满足这些行为的代码。这样可以避免 AI 越写越发散,确保产出符合预期。
如前所述的 Plan Mode,就是给出预设任务清单和设计方案,再让 Agent 执行。
实践中可以将需求文档、接口规范作为源文件,由 AI 参照生成实现;每次迭代前都重新校对规范,类似软件需求评审,确保 Agent “懂得”要做什么。
模块化知识管理上下文
把知识和上下文划分到独立模块(技能/工具/记忆)中,需要时动态加载。这与软件信息隐藏原理相同:为系统定义清晰模块,每个模块对外只暴露接口。
Agent 可以通过技能包加载特定功能指令,或者把长期记忆抽离为数据库/文档,只在必要时查询。
这样的好处是避免一次性把所有历史对话、背景都塞进提示,减少认知负担。 Agent Skills 标准鼓励只在需要时引入相关技能(称为渐进式披露)。
这些做法与面向对象编程中的“高内聚,低耦合”思想一致:信息按领域组织,避免交叉污染。
用约束创造自由
适当地设置规则和限制反而能让系统更灵活。给 Agent 画好边界和责任范围,让它在规范框架内探索,会比无限制地让它“随心所欲”生成结果更有效。如同软件架构设计一样:“Constraints liberate” 并非口号,而是经验结论。
实践中,我们为代理指定只能使用哪些 API、严格校验输入输出类型,或对危险操作设置人工确认(权限分级),都体现了“约束带来可控”的原则。
分工与协作规则
在多 Agent 或人机合作中,明确分工和接口很重要。这对应传统中的职责分离和团队协作。比如,一个复杂任务可以拆解成多个子代理(专职子模块)并行完成,各自独立工作,最终父代理汇总结果。
要规定好各 Agent 的输入输出格式、调用时机,避免它们相互“越权”。这就像微服务架构一样,每个服务有自己的契约(接口协议),共同完成更大功能。
同样,我们还需要规定人机界面:人类在什么场景介入(如终极审批)、如何查看代理决策过程等,类似代码评审或需求审批流程。
小步迭代、渐进演化
Agent 系统不能“一步到位”解决所有。应分解功能,用最小可行单元测试和部署,循序渐进。
传统 Agile 的思想告诉我们:分支集成、分块迭代、持续交付都降低了风险。
Agent 时代也是如此:每个 Agent 只负责一个小任务,先验证后扩展。
比如先让 Agent 完成一个核心功能的脚手架,再逐步加入细节。这避免一次性生成臃肿系统。
小结
以上原则在 Agent 场景中的应用,都有对应的传统源头:边界设计与信息隐藏、敏捷与TDD的反馈循环、规范化开发的“先规范后编码”、模块化设计、约束型架构等。
它们之所以依然有效,是因为控制复杂度、提供反馈、确保一致性的需求不变。通过这些原则,我们可以像对待传统软件一样驾驭 Agent 系统。
结论:软件工程的本质与未来
综观未来十年,AI Agents 的加入并不会让“软件工程”这个学科消亡,反而会更加凸显它的核心价值。
Agent 时代暴露出真正重要的是 定义目标、搭建框架、设计反馈、管理复杂性 的能力,而不是单纯写出多少行代码。
AI 解放了重复劳动,却让人的注意力回归到架构设计和需求分析上。Kent Beck、Martin Fowler 等前辈的话早已暗示这一点:AI 是低层细节的助手,但系统的高层蓝图仍需人类规划。
Agent不是软件工程的终结者,而是对软件工程重要性的再强调,同时,软件工程也将变得更加基础和哲学化。
未来的工程师需要学会与 AI 共舞:当 AI 填写琐碎细节,我们需要做的,是像指挥交响乐一样,确保所有部分和谐共振。
只有掌握了抽象思考、反馈管理与协作沟通等本质技能的人,才能在 Agent 时代成为不可替代的“高级程序员”。
总而言之,Agent 时代的浪潮终将平息,但推动开发的核心原则不会动摇。无论时代如何演进,“控制复杂性、精确反馈、模块化设计、明确定义、约束边界”这些理念都将继续指引我们走向可控、高效的软件未来。
Agent 时代的软件工程,不是新学科的出现,而是老学科更清晰的显现:我们所做的,不过是用 AI 作为新工具,重新温习和应用那些历久弥坚的工程智慧。
夜雨聆风