ARTICLE · 1186082
AI 已经会写代码了,为什么还需要软件架构?
AI 已经会写代码了,为什么还需要软件架构?
—— 从GitHub Copilot编程智能体看软件总体设计
01|从代码补全到能够独立执行任务的AI智能体
很多程序员使用AI编程工具,是为了提高编写代码的效率。开发人员输入一段注释,AI补全一个函数;遇到不熟悉的API,AI给出使用示例;编写重复性代码时,AI帮助减少机械劳动。在这样的工作方式中,开发人员仍然需要亲自组织开发过程,决定修改哪些文件、执行哪些命令,以及怎样检查最终结果。
随着AI编程技术的发展,GitHub Copilot开始支持更加自主的编程智能体。开发人员不再只能让AI补全某一段代码,还可以直接向智能体分配开发任务。例如,在GitHub仓库中创建一个Issue,描述需要修复的缺陷或增加的功能,再将任务交给Copilot编程智能体。
接到任务后,智能体可以分析仓库中的代码,修改相关文件,运行测试,并创建Pull Request(PR,拉取请求),供开发人员审查和合并。这意味着,AI不再只是代码编辑器中的辅助工具,而开始承担一部分原本需要开发人员连续完成的工作。GitHub官方将这种能力称为Copilot coding agent。
但如果仔细分析这一过程,就会发现一个值得思考的问题:
一个能够完成编程任务的AI智能体,究竟需要怎样的软件系统来支撑?
表面上看,核心能力似乎来自大语言模型。但实际完成一次软件修改,远不只是生成一段代码。智能体需要理解用户任务、读取项目文件、选择修改位置、调用开发工具、运行测试、处理执行结果,并将修改提交给开发人员。整个过程涉及多个具有不同职责的组成部分,而且其中一些操作还可能影响文件、运行环境和软件安全。

这正是软件总体设计需要解决的问题。
02|总体设计:不是先写代码,而是先决定系统怎样组织
在软件工程中,总体设计通常发生在需求分析之后、详细设计之前。需求分析回答的是系统需要解决什么问题、满足哪些要求;总体设计则需要进一步确定系统的整体结构,包括主要模块、模块之间的关系、接口、数据流以及关键的架构决策。
假设现在让你开发一个简化版的AI编程智能体。用户提出的需求很直接:输入一项编程任务,AI能够自动修改项目代码,并检查修改是否正确。
如果只从功能出发,最简单的想法可能是:调用一个大语言模型,把用户的任务和项目代码发送给它,再把模型生成的代码写回文件。
这样的方案也许能够完成简单演示,但真正投入使用以后,很快就会遇到一系列问题。
首先,项目可能包含数百甚至数千个文件,不可能每次都把所有内容完整发送给模型。系统需要决定如何读取项目、搜索相关代码,以及怎样组织提供给模型的信息。
其次,模型生成的结果可能需要执行命令、安装依赖或者运行测试,这些操作涉及实际的计算机资源,并不只是文本生成。
此外,模型可能产生错误的修改,测试也可能失败,因此系统需要保存执行状态、处理异常,并把结果反馈给用户。
更重要的是,如果允许AI直接访问用户计算机上的所有文件和工具,一次错误的操作就可能造成超出当前任务范围的影响。
这些问题说明,大语言模型虽然可能是系统的重要组成部分,但它并不等于整个软件系统。
开发人员必须决定哪些工作由模型完成,哪些工作由其他模块承担,模块之间怎样交换信息,以及哪些操作必须受到限制。
这些决定—— 就是总体设计的重要内容。
03|案例:GitHub Copilot为什么需要隔离执行环境?
GitHub Copilot的云端编程智能体提供了一个很有代表性的总体设计案例。
按照GitHub官方说明,Copilot云端智能体可以根据开发任务创建分支、编写代码并提出Pull Request。它在临时的、受到网络访问限制的执行环境中工作,而不是默认直接在开发人员的日常工作环境里执行全部操作。GitHub还提供权限控制、安全扫描和人工审查等机制,降低自动化操作带来的风险。[1]
为什么需要这样设计?
假设一个开发人员要求Copilot修复某个登录功能。为了完成任务,智能体可能需要读取认证模块的源代码、修改相关文件、安装依赖并运行测试。表面上看,这些都是正常的开发活动。但如果测试脚本包含危险操作,或者AI错误地选择了文件路径,就可能影响当前任务之外的资源。
如果系统把AI模型和文件操作工具直接连接起来,且没有适当的执行边界,那么模型一旦作出错误判断,后果就可能超出一次代码修改的范围。
GitHub采用隔离执行环境,正是为了在架构层面控制这类风险。
沙箱(Sandbox)可以理解为一个受到访问限制的执行空间。 系统允许程序在其中运行,但会对它能够访问的文件、网络资源和系统能力施加约束。这样,即使执行过程中出现问题,也有机会限制影响范围。
不过,沙箱并不意味着绝对安全。不同运行方式的隔离能力并不相同。GitHub官方文档明确区分云端沙箱和本地沙箱:云端沙箱在远程隔离环境中运行,本地沙箱则在用户计算机上通过权限策略限制访问。对于某些本地运行方式,如果没有启用沙箱,命令可能仍然拥有当前用户账户的访问权限。[2]
这说明沙箱不是给AI附加的一项普通功能,而是系统整体架构中的重要设计选择。

从总体设计角度看,它回答的是:当系统必须执行可能产生风险的操作时,应该把这些操作放在哪里执行,又应该通过什么边界限制它们?
这类问题并不能仅靠提高大语言模型的回答准确率来解决。
04|从真实产品中理解模块划分与模块接口
现在,我们尝试站在软件设计人员的角度,分析一个AI编程智能体可能需要怎样的总体结构。
可以把系统抽象为任务管理、智能体决策、代码与工具操作、隔离执行、结果验证以及用户审查等几个部分。这是一种依据产品功能建立的教学概念模型,并不是GitHub公开的完整内部架构图。

任务管理部分负责接收开发任务、维护任务状态,并把用户要求传递给智能体。智能体根据任务内容分析需要完成的工作,决定读取哪些文件、修改哪些代码以及调用哪些工具。工具接口负责把智能体提出的操作转换为具体的文件访问、命令执行或测试调用。执行环境则负责承载这些操作,并限制其资源访问范围。任务完成以后,系统还需要整理修改结果、运行必要的检查,并把变更提交给开发人员审查。
这种划分并不意味着每个部分都必须成为一个独立部署的服务。总体设计中的模块首先是一种职责划分,它可以对应同一应用内部的不同组件,也可以根据实际需要分布在不同进程或服务中。
这里涉及软件设计中的两个重要概念:模块内聚与模块耦合。
内聚关注一个模块内部的职责是否集中。例如,任务管理模块主要负责管理任务状态,而不是同时承担代码执行、网络权限管理和用户界面渲染等所有工作。耦合关注模块之间的依赖程度。如果智能体模块必须直接了解执行环境的所有内部细节,那么一旦更换执行环境,就可能需要大范围修改智能体代码。
相反,如果模块之间通过相对稳定的接口协作,系统就有机会在不大幅修改其他部分的情况下替换某项实现。
例如,假设原来的AI编程智能体使用模型A,后来开发团队希望改用模型B。如果模型调用能力被封装在适当的接口之后,任务管理、工具执行和结果展示等部分就不一定需要随之修改。
类似地,如果系统原来只支持在本地执行任务,后来希望增加云端隔离执行能力,那么是否能够在不重写整个智能体的情况下扩展新的执行方式,也取决于原有模块划分和接口设计是否合理。

当然,低耦合并不意味着模块之间完全没有联系。软件系统需要各个部分协作才能完成任务,关键在于让必要的依赖保持清晰、稳定,并尽量避免不必要的相互影响。
这也是总体设计为什么不能停留在一张模块名称列表上。设计人员不仅要决定系统由哪些部分组成,还需要明确各部分的职责、接口和协作关系。
05|为什么“能够运行”不等于“总体设计合理”?
假设现在有两套AI编程智能体系统,它们都能够根据用户要求修改代码并运行测试。
第一套系统把任务管理、模型调用、文件操作、命令执行和结果展示集中在一个大型模块中。开发人员只需要维护一个主要程序,初期实现可能比较直接。
第二套系统则把不同职责划分为相对独立的模块,通过接口协作,并为可能产生风险的操作设置执行边界。
如果只演示一次简单的代码修改任务,两套系统可能都能够正常工作,甚至第一套系统的开发速度更快。
那么,哪一种总体设计更合理?
仅凭这个演示,其实无法得出结论。
如果系统只是一个短期实验项目,功能简单、使用人数很少,那么过度复杂的模块划分可能增加不必要的开发成本。相反,如果系统需要长期维护,支持多种AI模型、多种开发工具以及不同执行环境,那么模块职责不清、依赖关系复杂的问题就可能逐渐显现。
例如,当系统需要支持多个用户同时提交任务时,是否能够隔离不同用户的执行环境?当某个测试任务长时间无法结束时,是否能够限制资源消耗并终止任务?当AI生成错误代码时,系统能否保留原有版本并恢复修改?当开发团队希望增加新的模型或者工具时,是否需要修改大量原有代码?
这些问题体现了软件总体设计中另一项重要工作:考虑系统的质量属性。
功能需求描述系统需要完成什么任务,而安全性、可靠性、可维护性、可扩展性等质量属性,则影响系统应该采用怎样的组织方式。
GitHub Copilot采用隔离执行环境,就是一个典型的例子。隔离环境本身并不是用户最直接关心的编程功能,却与系统的安全性和可靠性密切相关。
同样,任务状态管理、权限控制、执行记录、代码审查等机制,也可能影响系统能否在真实开发环境中长期使用。
因此,总体设计并不是简单地选择一种流行的软件架构,也不是模块越多、系统越复杂就越先进。它需要在功能要求、质量目标、开发成本、运行环境和未来变化之间作出权衡。
架构设计没有脱离具体条件的唯一最优解。
思考1|如果让你设计一个简化版AI编程智能体,你会怎样划分模块?
假设系统需要完成三个基本任务:接收用户提出的代码修改要求、自动修改指定项目中的代码、运行测试并返回结果。
请尝试设计它的总体结构,说明你认为需要哪些主要模块、各模块承担什么职责,以及它们之间怎样协作。
不要求画出详细类图,也不要求给出具体代码。可以使用简单的模块结构图表达你的设计。
06|AI能够生成架构图,是否意味着总体设计可以交给AI?
随着生成式AI的发展,开发人员已经可以让AI根据需求描述生成软件架构图、模块设计方案,甚至直接生成一套可以运行的应用程序。
对于总体设计而言,这显然是一种有价值的变化。
过去,设计人员需要自己整理需求、识别模块、比较技术方案,再逐步形成系统结构。现在,AI可以辅助分析需求,提出多种架构候选方案,生成接口草案,并帮助设计人员比较不同方案可能存在的优缺点。
但是,AI生成一张看起来完整的架构图,并不意味着总体设计已经完成。
假设我们要求AI设计一个编程智能体,它可能生成一个包含十几个模块的系统架构,使用消息队列、微服务、容器、数据库以及多个AI智能体协作。这样的设计在技术上未必不可行,但对于一个只有几名开发人员、主要面向小规模使用场景的项目来说,可能带来过高的开发和维护成本。
另一方面,如果系统需要同时服务大量用户、执行不可信代码,并满足严格的安全要求,那么一个过于简单的架构又可能无法满足实际需求。
这意味着,评价一个架构方案,不能只看它是否采用了先进技术、是否具有完整的模块图,或者AI是否能够据此生成可运行代码。
更重要的是,设计人员需要说明为什么采用这种模块划分,为什么选择这种执行环境,哪些质量目标最重要,以及这种设计在什么条件下可能不再适用。
GitHub Copilot的案例恰好说明了这一点。对于一个能够自主修改代码和执行命令的智能体系统,隔离执行环境、权限控制和审查机制并不是可有可无的装饰,而是与其实际使用场景密切相关的架构考虑。
AI能够帮助提出这些设计,但是否采用、怎样组合以及如何验证,仍然需要结合具体项目作出判断。
思考2|如果AI生成的软件已经能够运行,还需要检查它的总体设计吗?
假设你让AI生成了一套完整的编程智能体系统。它能够接收任务、修改代码、运行测试,演示效果也很好。
现在准备让更多用户使用这套系统。你认为是否还需要对总体设计进行审查?
请结合案例,选择你认为最重要的几个方面进行分析,并说明如果忽视这些问题,系统在后续运行和维护中可能出现什么情况。
思考3|当AI能够自动生成多套架构方案,软件工程师在总体设计阶段还需要做什么?
假设未来AI可以在很短时间内生成多套满足相同功能需求的架构方案,并自动实现其中任何一套。
在这种情况下,软件工程师是否还需要学习模块划分、模块接口、内聚与耦合以及软件架构设计?
请进一步思考:当生成设计方案的成本不断降低时,怎样评价和选择设计方案,是否会成为更加重要的能力?
结语|总体设计的价值,不只是画出一张架构图
从GitHub Copilot编程智能体的案例可以看到,一个软件系统能否完成某项功能,与它是否具有合理的总体设计,是两个相关但并不相同的问题。
大语言模型能够生成代码,但真正的软件产品还需要组织任务、管理状态、调用工具、控制权限、执行测试,并处理可能出现的异常。不同模块应该承担什么职责,模块之间怎样协作,以及系统如何满足安全性、可靠性和可维护性等要求,都需要在总体设计阶段认真考虑。
AI的发展正在降低生成代码和设计方案的成本,却没有消除架构决策所面临的约束与权衡。相反,当一个可以运行的软件越来越容易被生成时,判断它为什么这样设计、是否适合真实使用环境,以及未来能否持续维护和演化,可能会变得更加重要。
AI可以更快地生成软件架构,但不能仅凭架构图的完整程度,证明一个设计就是合理的。
课堂投票
主要参考资料
本文关于GitHub Copilot的产品能力、云端执行环境和安全控制的事实,主要依据GitHub官方文档。文中用于解释模块划分的结构是教学抽象,不代表GitHub完整的内部实现。
GitHub:Copilot智能体的负责任使用说明 GitHub:Copilot云端与本地沙箱 GitHub:Copilot开发环境配置 Visual Studio Code:AI辅助开发中的安全机制















































































