
一、这门课为什么现在出现
这节课从一个现实问题开始:计算机正在经历新一轮能力普及,而大学教育、学习方式和工作方式还没有完全适应这种变化。
计算机历史上的多次变革,都可以理解为同一件事的反复发生:原本昂贵、稀缺、只有少数人能够使用的能力,逐渐变成普通人可以直接使用的日用品。个人计算机让计算能力进入个人生活,互联网把人连接起来,移动互联网又把支付、通信和服务带到了每个人的手机上。生成式 AI 则把文字生成、图像生成、代码编写、信息处理和软件操作进一步压缩成自然语言交互。
课堂用 ICQ、OICQ 和 QQ 的演变说明互联网早期的连接感:一个人可以随机联系到世界另一端的人,即使双方语言和经验完全不同。移动支付的普及则展示了另一种变化:二维码在很短的时间里进入菜市场等日常场景,改变了人们完成交易的方式。生成式 AI 的普及速度更快,已经开始重新定义学习、工作和创作。
“AI 替我上大学”的困境
当老师使用 AI 出题、学生使用 AI 做作业时,课程仍然可能完成考核,但学生未必得到训练。整个教学闭环看似正常,真正缺失的是学生本人从问题中获得能力的过程。
这种变化带来了几种具体焦虑:
- 成绩可以很好,但毕业时发现自己没有真正掌握解决问题的能力;
- 认真学会的许多技能,AI 也已经能够完成;
- 大量简历都在堆叠实习、奖项、论文和竞赛,人与人之间越来越难以区分;
- 如果简历没有 GitHub、个人主页、预印本、可运行项目或其他可验证作品,纸面上的经历很难说明真实能力。
课堂举了一个“看起来非常完美”的简历例子:简历中有论文和经历,但缺少代码仓库、个人主页以及可供进一步验证的材料。问题不在排版是否漂亮,而在于简历没有留下足够多的真实工作证据。生成式 AI 让文本包装变得更容易,也让“看起来很优秀”变得更不稀缺。
因此,课程的目标不是简单地教大家多写代码,而是让大家在 AI 时代重新获得两种东西:一是使用 AI 做出真实作品的能力,二是理解软件工程、判断结果质量并留下可验证成果的能力。
二、课程定位:生成式软件工程
课程名称是“生成式软件工程”。它仍然是一门软件工程课,只是软件的生产过程中加入了生成式 AI 和 Agent。
软件工程不等于把代码写出来。更基础的问题是:如何让软件不失败,如何把一个需求转化为可以交付、可以验证、可以继续维护的软件。
课程采用案例为主、讨论较松散、实践优先的方式。课堂中的案例包括配置操作系统、处理邮件、阅读论文、分析视频、操作浏览器、制作 Excel 工具以及设计可维护的软件架构。传统的“古法编程”不再是课程的中心,重点转向如何描述问题、调用 Agent、验证产物并把一次性的成功沉淀成长期可复用的系统。
课程中还讨论了几个现实约束:
- Token 成本需要被纳入工作流;演示可以优先选择价格较低、速度较快但能力足够的模型;
- 模型不应被当成绝对可靠的黑盒,重要结果仍然需要检查;
- 课程设计上倾向使用“通过 / 不通过”的方式评价项目,但具体评判标准仍在形成;
- 一个可执行的项目方向是实现个人 email 管理系统,使其能够收发邮件、处理回复,并长期运行在一台小型电脑上;
- 项目的价值不只体现在分数上,更体现在最终能否形成一个可访问、可解释、可复现的作品。
内容即代码
课堂展示的课件本身就是生成式软件工程的案例。Markdown 讲义被视为 source of truth,Agent 根据讲义扩展出幻灯片和图像资源,再由浏览器渲染成最终课件。课件中的许多图片和页面元素由 AI 生成,内容则通过多轮提示、不同 Agent 和盲评继续调整。
这种方式把一次授课拆成了几个可以继续处理的对象:
- 预先写下的 Markdown 讲义;
- 课堂现场的讲解与即兴交流;
- 录制下来的完整课程;
- 经过切片、复盘和重组后的知识片段;
- 可以被后续维护、定制和共享的数字课程。
“content as code”或者“everything is code”的含义,不是把所有内容机械地变成程序,而是让内容拥有明确的来源、结构、生成过程和可维护形式。课程可以像软件一样被修订、组合、复用,甚至由不同的人继续维护。
三、从大语言模型到 Agent
课堂没有从训练模型的工程细节开始,而是先建立一个使用者能够掌握的直觉。
大语言模型可以被理解为从大量数据中学习得到的概率分布。给定一段上下文后,它会不断预测后续 token;输出看起来像连续的文章、代码或回答,本质上是许多次预测的组合。模型可以处理很长的文本,也可以处理图像等不同形式的输入,但它并不天然等于一个可靠的软件工程师。
当模型拥有更长的上下文、更强的推理能力和工具调用能力后,Agent 就出现了。Agent 不再只是生成一段回答,而是可以:
- 读取任务和当前环境;
- 调用 bash、浏览器或计算机操作工具;
- 观察工具返回的结果;
- 判断当前路径是否合理;
- 修改方案并继续执行;
- 在验证通过后结束任务。
这就是课堂反复展示的 ReAct 式循环。模型的输出可以触发程序,程序的结果又会被送回模型上下文,模型据此继续行动。一个复杂任务因此不再是“一次生成”,而是由多个观察、行动和修正步骤组成。
使用 Agent 的第一步并不是学习如何训练一个模型,而是直接给它一个清晰的任务,并让它开始工作。项目中的 AGENTS.md 等配置文件可以提供持续的背景、角色和约束;人可以通过追问、检查和反馈逐步了解 Agent 的能力边界。课堂给出的判断是:想象力、需求描述能力和验证能力,决定了 Agent 能够被用到什么程度。
四、Agent 能做什么:从个人环境到知识工作流
4.1 用自然语言配置本地系统
课堂展示了一套由 Agent 协助完成的本地工作环境。可启动的 Linux 系统被放在 USB 设备上,窗口管理器、终端、NeoVim 和命令行工具经过定制,界面和操作方式围绕课堂展示进行了优化。
过去,配置这类环境需要查阅大量文档、理解配置文件、反复试错,并逐项处理兼容性问题。现在可以先用自然语言描述目标,让 Agent 检查系统状态、安装组件、修改配置并验证结果。Agent 还可以把普通命令替换成更适合日常使用的工具,对终端输出、窗口布局和快捷键进行统一调整。
这里真正发生的变化不是“人类不再需要任何知识”,而是知识的使用方式发生变化。人需要知道想要什么样的系统,知道哪些结果值得接受,能够发现错误并要求 Agent 重新检查;具体配置细节则可以交给 Agent 处理。
4.2 把日常事务交给个人 Agent
另一个案例是个人邮件工作流。系统中保存了过去处理过的邮件和回复记录,因此收到新邮件后,Agent 可以执行一组连续动作:
- 自动标记邮件状态;
- 根据既有语气生成回复草稿;
- 识别附件中的发票等材料;
- 把重要附件保存到指定的归档位置;
- 接收来自 Reminder 的任务;
- 调用打印机完成打印;
- 完成后把通知推送到手表。
这类流程的关键不是单个动作有多复杂,而是多个工具被组合成了一个持续运行的工作流。邮件、数据库、文件归档、Reminder、打印机和通知设备之间形成了一个个人自动化系统。
课堂同时强调了边界:日常事务可以交给 Agent,但前提是任务足够可信、风险可接受,重要结果仍然应该经过确认。Agent 能够操作电脑,不代表所有操作都应该被无条件授权。
4.3 用多 Agent 加速读书、读论文和看视频
Agent 不只用于写代码,也可以改变知识获取方式。
阅读论文时,可以让不同的 Agent 分别承担不同任务:回看人类已有的知识和历史案例,寻找相关工作,使用第一性原理分析问题,或者从不同立场提出质疑。多个 Agent 形成不同观点后进行讨论,主 Agent 再把分歧重新交给它们处理,直到得到相对稳定的结论。
这种阅读方式的核心不是让 AI 替代原文,而是先剥离已经熟悉的部分,把真正新的内容提取出来,再带着原文、分层总结和问题继续对话。对于一篇很长的论文,已知背景和形式化铺垫被压缩后,剩下的关键贡献、假设和限制会更容易被定位。
看视频也可以采用类似流程:
- 获取完整内容并整理为可处理的素材;
- 生成转写文本和图文时间轴;
- 在必要位置保留截图作为 ground truth;
- 让 Agent 识别已经熟悉的内容;
- 只保留新的观点、案例和方法;
- 带着摘要回到原视频进行核对。
这样做的价值不只是“看得更快”,而是把视频从一次性消费的媒体变成可检索、可复盘、可重新组织的知识材料。
4.4 浏览器和计算机使用能力
浏览器是一个极其复杂的软件工程产品。Chrome DevTools 提供了网页结构、网络请求、脚本执行和状态观察等开发接口。过去,只有开发者会系统地使用这些能力;Agent 可以把其中一部分能力交给普通用户。
课堂提到的典型操作包括打开开发者工具、观察页面和网络请求、读取请求头与 Cookie、把浏览器中的请求复制成 cURL 命令,以及在保留当前状态的前提下继续处理数据。课堂还展示了在浏览器中运行 Android 界面的思路:应用的界面元素、文本和坐标被提取出来后,可以通过浏览器完成显示和交互。
当 Agent 操作网页时,它可能先尝试一种方式,发现直接注入事件无效,再改用真实点击或其他可行路径。失败并不一定意味着任务结束;Agent 可以观察失败结果、重新选择工具并继续尝试。
更重要的是,一条成功的操作路径可以被保存为脚本或记忆。一次探索性的操作由 Agent 完成后,后续重复任务就可能变成确定性的自动化流程。浏览器操作、页面状态、脚本和记忆因此可以组合成更大的个人工作流。
4.5 能力越强,安全边界越重要
课堂中的受限环境案例说明了 Agent 能力的双重用途:一台机器可以允许文件进入,却禁止文件直接离开;如果把合法的输入、显示和交互通道组合起来,仍然可能形成数据外传路径。
二维码动画和 Excel 公式的演示重点不在于提供一种攻击教程,而在于说明安全边界不能只依赖“禁止安装程序”或“禁止复制文件”。当 Agent 可以操作浏览器、桌面、表格、打印机和其他设备时,原本彼此分离的通道可能被重新组合。软件工程设计必须同时考虑功能、权限、可观察性和滥用风险。
4.6 从 bits 到 atoms
课堂最后把视野从屏幕上的数字内容扩展到现实世界:自然语言可以驱动 Python 程序,Python 程序又可以生成 3D 打印对象。视频、论文、幻灯片、代码和实体物品都可以被纳入同一条“内容—代码—执行”链路。
“从 bits 到 atoms”并不是一句关于未来的口号。只要数字对象能够被代码描述,Agent 就可能参与从意图到实体的转换。
五、软件工程真正要解决的是“空隙”
AI 可以完成很多局部任务,但一个可用产品不是局部任务的简单相加。
例如,一个外卖系统同时包含前端、后端、交互、数据、部署和运营。AI 可以分别帮助设计页面、编写接口、生成数据库 schema 或提出运营方案,但只要其中一个环节与其他环节不匹配,整个产品就可能无法使用。产品开发因此是系统性工程,组织这些局部能力比生成一段代码更重要。
5.1 三个空间
课堂用三个空间描述软件从想法到产品的转换过程:
| 空间 | 核心问题 | 典型内容 |
|---|---|---|
| Intention | 到底想解决什么问题 | 做一个教务系统、改善点外卖体验、处理个人邮件 |
| Specification | 软件需要满足什么要求 | 功能、界面、数据 schema、架构、约束、正确性标准 |
| Implementation | 具体怎样把它做出来 | 代码、数据库、脚本、可运行系统和部署环境 |
同一个 Intention 可以对应许多种 Specification;同一个 Specification 也可以由许多种 Implementation 实现。客户、产品经理、分析人员和程序员对同一个需求产生不同理解时,空隙就会被放大。
软件工程的核心工作,就是不断补上 Intention、Specification 和 Implementation 之间的 gap。软件失败通常不是因为某一行代码语法写错,而是因为最终实现的东西从一开始就不是想要的东西,或者虽然实现了目标,却没有满足规格中的正确性、可靠性和可维护性要求。
5.2 QR / Excel 案例:能完成不等于做得对
课堂用 QR / Excel 工具说明了 Agent 的局限。任务看起来很明确:输入任意字符串,经过编码后生成二维码动画,并且使用旧版本 Excel 也能兼容的公式。
在没有明确架构时,Agent 容易把需求扩大,尝试追求“对所有输入都成立”的通用方案。结果可能包括把 Base64 内容硬编码到公式中、生成不可维护的代码,或者在长时间反复修补后才勉强完成。即使最后得到一个能运行的结果,也不代表它满足真正的 Specification,更不代表它适合继续演化。
更可靠的方法是先限制问题范围,再把系统拆成可以分别验证的层次:
- 先定义最小、不会失败的输入和输出;
- 设计一个中间语言或 DSL;
- 让中间语言既可以执行为 Python,也可以翻译为 Excel 公式;
- 单独验证 Base64 编码是否正确;
- 单独验证二维码每个像素的生成是否正确;
- 单独验证中间语言到 Python 和 Excel 的翻译;
- 用测试、运行结果和人工 review 组成闭环。
这种设计把“让 AI 直接写完整程序”变成了“让 AI 参与构造基础设施,再分别验证每个转换”。代码可能并不更短,但边界清楚、错误容易定位,也更容易维护。
5.3 失败项目不能只靠继续堆资源
《人月神话》中的经典判断是:一个已经陷入失败的项目,继续加入更多人,可能只会让项目更失败。课堂把这个判断延伸到了 Agent:当生成结果已经产生 slop,继续投入更多 Token 不一定能改变方向,甚至可能让错误结构被进一步固化。
因此,遇到失败时,首先需要判断问题属于哪一层:
- 需求是否被正确理解;
- Specification 是否足够明确;
- 架构是否允许后续变化;
- 实现是否满足规格;
- 测试是否能够发现错误;
- 当前的修补是在解决问题,还是在掩盖结构性问题。
软件工程的目标不是让一次演示看起来成功,而是让系统能够在需求变化、人员变化、模型变化和环境变化之后继续工作。可靠性、演化能力、可维护性和长期成本,都属于“软件做得对不对”的一部分。
六、AI 时代仍然需要人的能力
传统计算机教育通常先从 C 语言、数据结构和具体实现开始,再逐步学习软件工程。学生先熟悉实现空间中的工具,再学习如何把需求落实为程序。考试题则往往要求在很短时间内得到一个明确答案。
这种训练方式对基础学习仍然有价值,但 AI 在短程任务上已经拥有更多数据、更强的记忆和更明确的反馈信号。只要问题可以被快速定义、快速测试、快速评分,Agent 往往比人更快完成。
学习方式因此需要变化:可以先让 Agent 把一个东西做出来,再回头复盘它为什么能工作、哪些地方不可靠、边界在哪里。这样做的效率可能高于从零开始手写每一个细节,但它有一个明显风险:得到的理解可能只是“能运行的理解”,并不等于正确、完整和可迁移的理解。
人的稀缺价值
在课堂给出的框架中,人的价值不再主要是比 AI 更快地完成一个局部实现,而是承担以下工作:
- 发现值得解决的问题,而不是只等待一个明确任务;
- 把模糊意图整理成可讨论、可验证的 Specification;
- 选择合适的架构和中间表示,减少不同空间之间的误差;
- 判断什么结果算成功,什么结果只是暂时通过;
- 对模型的输出进行测试、审查和事实核验;
- 把一次成功的探索沉淀为脚本、Skill、文档或可复用系统;
- 用便宜的实验验证方向,用证据及时停止坏方向;
- 对系统的长期结果、风险和责任负责。
好奇心、自我驱动、工程品位和对真实世界的理解,决定了一个人能否把 AI 带到更大的问题上。会用 Agent 只是起点;知道它能做什么、不能做什么,以及如何把它组织进可靠流程,才是生成式软件工程的核心能力。
七、第一节课留下的结论
这节课并没有把 AI 描绘成一个已经完成的终极工具。Agent 在单个任务、局部代码和浏览器操作上越来越强,但它仍然会误解需求、急于开始、追逐“通过测试”的短期奖励,并生成难以维护的实现。模型可能很快进一步学会工程设计和品位,课程中的方法也可能因为模型能力变化而迅速过时。
但这并不意味着软件工程失去意义。恰恰相反,当局部执行越来越便宜,方向、结构、验证和长期结果就越重要。
“古法编程”正在失去主导地位,软件工程却没有消失。一个人能否被招募、被信任,不能只看他是否能写出一段 AI 也能写出的代码,而要看他能否回答一个更困难的问题:
为什么要招一个人,而不是购买一个 200 美元的 Claude Max?
课堂给出的答案可以归纳为四件事:
- 找到真正值得解决的问题;
- 把问题拆成成本可控的实验;
- 用证据让错误方向及时停止;
- 对系统的长期结果负责。
Agent 放大的是执行力。生成式软件工程要解决的,则是如何确定方向、补上意图与实现之间的空隙、建立验证闭环,并把一次性的生成结果变成能够持续演化的系统。
