[00:00:00] 我们上周讲了一点版本管理 [00:00:03] 我们这周继续讲版本管理 [00:00:04] 然后我发布了一个作业 [00:00:07] 然后按照之前的说法 [00:00:08] 就是这门课所有的作业大家都是选做自愿完成 [00:00:13] 然后最后当然肯定会验收 [00:00:15] 因为最终也许学校会让我们提交一个成绩 [00:00:19] 那么大家就会教一些链接 [00:00:23] 然后由我的机器人来给大家评分 [00:00:26] 然后我们的第一个lab [00:00:29] 算是一个比较时髦的需求 [00:00:32] 叫会成长的 [00:00:35] 个人助手 [00:00:36] 然后他现在对大家的要求都是不限 [00:00:39] 你们想怎么做就怎么做 [00:00:41] 然后最好还是可以vibe code一个 [00:00:42] 而且我今天应该会课上会留的时间 [00:00:45] 我自己就来vibe code一个 [00:00:47] 然后我会告诉大家 [00:00:48] 如果你直接让他vibe code的时候 [00:00:50] 你会遇到什么样的小坑 [00:00:52] 然后除了今天以外 [00:00:53] 我下一周 [00:00:54] 而不是下一周 [00:00:55] 是这周日要调休 [00:00:57] 周二的课 [00:00:58] 所以这周日还有课 [00:00:59] 然后会讲软件的架构 [00:01:01] 然后会把它会把它连起来 [00:01:03] 然后这个例例子就是你们特别特别 [00:01:06] 每个同学都会需要的 [00:01:07] 我自己自己也有的 [00:01:08] 就是一个能够持续为你工作的个人助手 [00:01:12] 然后你可以这些需求是供你参考的 [00:01:14] 当然如果你实现它的话 [00:01:15] 会有一点点成就感 [00:01:17] 比如说你的学习的数据库 [00:01:18] 你 [00:01:19] 你们这个学期可能会在上一些专业必修课 [00:01:23] 可能计算机网络或者数概率之类 [00:01:27] 比较困难的 [00:01:28] 专业课 [00:01:28] 然后你可以把你的专业课的资料 [00:01:31] 放到你的个人数据库里 [00:01:32] 或者你参与了研究组的课题的时候 [00:01:35] 你可以把你们研究组的论文相关的文献 [00:01:38] 教科书这些整理成你的个人的数据库 [00:01:41] 这是一种形式的数据库不限 [00:01:42] 你也可以把你自己的个人信息 [00:01:45] 我不知道大家是不是已经填表 [00:01:47] 已经填的很烦了 [00:01:48] 每次你填表的时候 [00:01:50] 都是给你一个DOC的表格 [00:01:51] 然后在那个表格里要填姓名名 [00:01:53] 学号 [00:01:54] 身份证号 [00:01:54] 然后有时候是个人简历这个那个 [00:01:57] 然后我现在已经把这些所有的事情都交给agent了 [00:01:59] 就是好把这个东西填了 [00:02:01] 啊这 [00:02:02] 觉觉得从往以往到今年 [00:02:05] 有一个非常大的效率进步 [00:02:07] 今年我记得我大概在疫情的时候 [00:02:10] 我招过一个学生 [00:02:12] 然后研究生研究生就在我这里做了3年 [00:02:15] 做了一个什么 [00:02:15] 就是自动填表系统 [00:02:17] 就我们就填 [00:02:17] 觉得填表很烦 [00:02:18] 然后等到他毕业的时候 [00:02:20] 突然有个ChatGPT [00:02:21] 然后又很慌 [00:02:22] 他做他觉得他做的事情马上就要被替代了 [00:02:25] 我说不要紧 [00:02:26] 你赶快答辩 [00:02:26] 然后就可以毕业毕业了 [00:02:29] 然后这世界就是发展的 [00:02:31] 这么快 [00:02:32] 然后在个人数据库的基础上 [00:02:33] 你可以把数据库和你的email的邮箱 [00:02:37] 关联关联起来 [00:02:39] 如果有也就有可能的话 [00:02:41] 比如说我在两周以后会在半夜给大家发邮件 [00:02:44] 然后你的agent呢可能会把邮件回回给我 [00:02:46] 就实现一个always on的一个在后台 [00:02:49] 你们也许买一个很小的那种嵌入式的小设备 [00:02:52] 一两百块钱 [00:02:53] 你就可以在你的宿舍里面 [00:02:54] 持续的跑你的agent loop [00:02:57] 这样然后 [00:02:59] 以及用你的信息可以办理一卡通的事务 [00:03:01] 就像我上课的时候对 [00:03:02] 这就是一句话 [00:03:04] 你直接一个像agent的子进程的调用就可以 [00:03:09] 然后如果你们有兴趣的话 [00:03:11] 可以做一个手机端的联动 [00:03:12] 也许是一个网页 [00:03:13] 也许是一个别的 [00:03:15] 就甚至是一个苹果的app或者是一个android的app [00:03:18] 就你只要让agent的去做 [00:03:19] 他会自自自己去帮你下好所有需要的东西 [00:03:22] 然后把你要的东西给啊给出给做出来了对 [00:03:29] 然后为什么要布置这样的实验 [00:03:31] 就看起来就所有的任务都在AI的能力范围之内 [00:03:35] 但是如果你直接我今天会试的 [00:03:38] 我没有试过 [00:03:39] 直接把这个实验要求直接让AI去做 [00:03:42] 他在一开始就会做出很多 [00:03:45] 可能他认为看起来也合理的决定 [00:03:48] 但是这些决定会让你那项目的维护 [00:03:51] 变得越来越困难 [00:03:52] 越来越困难 [00:03:52] 最后直到陷入啊焦油坑 [00:03:54] 所以我觉得是每个同学都有 [00:03:57] 都有必要体验一下软件工程里面的焦油坑 [00:04:01] 也就是你当你的AI slop [00:04:03] 开始不断的消耗你的token的时候 [00:04:05] 你终于会有一天会下定决心好 [00:04:08] 我要把这个项目删掉 [00:04:09] 从头重做 [00:04:10] 或者就回退到从某一个很早期的版本开始 [00:04:14] 从头做 [00:04:15] 那这是我们这个实验可能想要 [00:04:18] 告诉大家的事情好 [00:04:21] 当然我 [00:04:21] 我相信这个项目对每个同学来说都是有用的 [00:04:24] 这是我也是我设计实验的初衷 [00:04:27] 我大概会这样 [00:04:29] 我可以提前预告一下 [00:04:31] 我的下一个lab会和这个lab有非常大的关联 [00:04:35] 而且你们暂时猜不到 [00:04:38] 然后呢你会发现你就你现在lab1 [00:04:42] 比如说那些实验要求你都做好了 [00:04:44] 然后他成为一个非常非常舒适的个人助手 [00:04:47] 然后我怕给你加一个需求 [00:04:48] 然后这个需求和前面所有都是关联 [00:04:51] 并且有一定的冲突 [00:04:52] 然后你的一点就去改 [00:04:54] 然后越改越崩溃 [00:04:55] 越改越崩溃 [00:04:56] 就有一个这样的这样的体验 [00:04:58] 所以大家可以期待一下这个 [00:05:00] 这个后面的后面的lab [00:05:01] 所以如果你不做 [00:05:02] 比如说你现在lab1选择躺倒 [00:05:05] 或或者就不管它 [00:05:07] 让AI直接就做 [00:05:07] 下一次再把这个做的直接删掉 [00:05:09] 那可能就没有这个软件工程的体验了 [00:05:13] 大概是我想要做这样的一个啊lab好 [00:05:17] 我们回顾一下 [00:05:18] 我们上节课讲的是软件的项目管理 [00:05:21] 项目我们说项目是各种文件的集合 [00:05:23] 你的intent [00:05:25] 一些设计文档 [00:05:25] 你的README都在 [00:05:28] 都在你的项项目里 [00:05:29] 所以所以其实我不喜欢那种AI写出来 [00:05:32] 那个非常非常长的这个README [00:05:35] 我喜欢的是对我来说 [00:05:37] 我觉得README应该 [00:05:38] 就写一下你在设计这个项目的时候 [00:05:40] 的最初的初衷 [00:05:42] 你想做一个什么样的产品 [00:05:44] 然后这个产品能达到什么样的效果 [00:05:46] 可能可以两个screenshots [00:05:48] 以及你最重要的那些设计 [00:05:50] 有点什么感觉 [00:05:52] 有一天你突然想了一个非常好的点子 [00:05:56] 然后你真的想用它去挣一个亿 [00:05:58] 然后你想挣一个亿的时候 [00:05:59] 你要组建一个额创业团队 [00:06:02] 你要说服你那个computer science里面 [00:06:04] 比如你要说服我出来干 [00:06:06] 然后你就只其实只需要一个比较短的 [00:06:09] README [00:06:09] 这是你的INTE能想做这个东西 [00:06:11] 那剩下比如说我有架构的能力 [00:06:12] 我有写代码能力的 [00:06:13] 我可以把剩下的东西的给你给你补出来 [00:06:16] 你不需要知道这个软件系统是怎么样 [00:06:19] 它的specification是什么 [00:06:20] 他用什么样的数据库 [00:06:21] 怎么样支持这个用户 [00:06:23] 从1~10到100到100万到1亿 [00:06:27] 这个架构你可能没有 [00:06:29] 这个computer science的知识 [00:06:30] 但是你不需要有你只要有那个最原始的设计 [00:06:33] 那intent [00:06:34] 然后再到spec [00:06:35] 就有我刚才说的一些 [00:06:36] 我要选什么样的数据库 [00:06:38] 我甚至要选什么样的编程语言 [00:06:40] 然后我的项目的结构是什么啊等 [00:06:42] 各种各样的 [00:06:43] 小到比如说每个模块的接口都属于spec [00:06:46] 然后再到code implementation [00:06:47] 它现在都在都在这个项目里 [00:06:49] 那有这样的项目以后 [00:06:51] 很自然的你就你就需要一个容器 [00:06:55] 把这些各种各样的文件给管理出来 [00:06:58] 那我们说大家用文件系统来管理项目 [00:07:02] 其实真的就是图方便 [00:07:03] 因为你回到1950年 [00:07:04] 1960年的时候 [00:07:06] 操作系统给你的存储功能就只有文件 [00:07:10] 他没有别的 [00:07:11] 就那个时候数据库还关系型 [00:07:13] 数据库还没有发明出来 [00:07:14] 所以所以所有的程序员他别无他法 [00:07:17] 只能把你的项目以文件的形式存存进来 [00:07:21] 所以所以这更多时候是一个历史的 [00:07:24] 有历史是不停的往后涨 [00:07:25] 往后涨往后涨 [00:07:26] 导致的原因 [00:07:27] 我自己是觉得文件系统可能不是 [00:07:30] 组织项目的正确的方式 [00:07:32] 因为文件系统其实丢失了很多文件 [00:07:35] 不适合表达的信息 [00:07:36] 就有些有些信息其实是比较容易表达的 [00:07:40] 比如说我的intent spec这种 [00:07:43] 就我一一条文档这个地方我是怎么想的 [00:07:45] 或者这个测试用例是什么 [00:07:47] 我输入是什么 [00:07:48] 输出是什么 [00:07:49] 然后我要assert在程序的运行过程中 [00:07:51] 什么东西不能被违反 [00:07:52] 但是你马上就会发现有很多隐藏的关联 [00:07:58] 在项目里面是没有的 [00:08:00] 我举个例子 [00:08:01] 你们你经常会在AI就是AI在写代码的时候 [00:08:07] 现现在agent的会稍微好一点 [00:08:08] 有时候也不会 [00:08:10] 你让他说哎把这个实现的什么方法从 [00:08:14] 比如说你要把link list换成是一个更高效的 [00:08:17] tree的结构去优化性能 [00:08:20] 这是一个很常见 [00:08:21] 你突然发现这个性能不够了 [00:08:22] 然后你让AI去做 [00:08:23] AI就啪啪啪给你代码给改了 [00:08:25] 但是你没有想到的是 [00:08:27] 你可能在其中的某一个文件里写了一个文档里 [00:08:31] markdown里写了一个 [00:08:32] 我这个项目是用这个数据 [00:08:35] 是用link list管理的 [00:08:37] 然后在项目当中 [00:08:39] 其实你的这个文档和你的代码和测试之间 [00:08:44] 就形成了一个关联 [00:08:47] 它就形成了一个你在写的时候 [00:08:52] 你写文档的时候可能还没有代码 [00:08:53] 所以你就先写了那个文档 [00:08:54] 你随手一写 [00:08:55] 这是个link list [00:08:56] 但是一旦你的代码实现了这个关联 [00:09:00] 又没有强行的联系上 [00:09:02] 这就是一个技术债 [00:09:04] technical debt [00:09:05] 因为以后随着文档和代码的不断的向前推演 [00:09:11] 他们的不一致只会越来越多 [00:09:13] 不会越来越少 [00:09:14] 然后这个软件就陷入一个维护的泥潭了 [00:09:16] 因为后面你拿出一个代码 [00:09:18] 甚至AI拿出看到一份代码 [00:09:19] 那到底是文档说的对还是代码说的对 [00:09:23] 你跟他聊天的那个历史没有了 [00:09:26] 你那个chat已经已经消失了 [00:09:28] 你换了一台电脑 [00:09:30] 然后你那个git repo里面 [00:09:32] 可能还有一些这个这个change的日志 [00:09:34] 但是你当你到最后的时候 [00:09:37] 你真的就不知道到底是代码对还是文档对 [00:09:41] 然后其实在软件工程里面 [00:09:43] 这是一个研究了非常非常长时间的 [00:09:46] 问题叫叫traceability [00:09:48] 你看这是这已经是2014年的时候 [00:09:50] 他review的一些更老的时候的文章 [00:09:54] 他就叫software traceability [00:09:56] 可可可追踪性 [00:09:58] 所谓的追踪啧 [00:10:01] 就是你的 [00:10:02] 就他发现我们文件真的只是图 [00:10:05] 保存在文件系统里方便 [00:10:07] 那么在一个软件项目当中的 [00:10:11] 各种各样的测试用例文档 [00:10:15] 哪怕就文档中间一行代码 [00:10:17] 它之间的这个关联是什么 [00:10:19] 我们能不能在这个软件系统的演进过程中 [00:10:22] 仍仍然维持它 [00:10:23] 这其实是一个非常软件工程的 [00:10:26] 软软件工程的问题 [00:10:28] 所以很多时候我们觉得蛮有意思的 [00:10:31] 文件系统将错就错了 [00:10:32] 那我们大家最后总有一天会发现 [00:10:35] 你用文件系统来管理代码 [00:10:37] 你受不了了 [00:10:38] 打个压缩包发布 [00:10:40] 打压缩包发布 [00:10:41] 然后打压缩包发给你的合作者 [00:10:43] 这件事情啊已经维护不下去了 [00:10:46] 维护不下去了 [00:10:46] 所以所以就有了SVN [00:10:48] 有了git [00:10:51] 那下一个是什么 [00:10:53] 大家有没有没有想过下一个是什么 [00:10:56] 我今天一会讲那个 [00:10:58] jj他的下一另外一个 [00:11:01] 可能甚至比git要好一些 [00:11:02] 更好用的一个版版本控制工具 [00:11:04] 但我同时也觉得就刚才说到 [00:11:07] traceability [00:11:08] 其实如果以后我们再也都不要写代码了 [00:11:11] 那软件他就不应该是一个 [00:11:14] 就是像像现在现在我们在git [00:11:17] git repo里面管管理 [00:11:18] 这样 [00:11:19] 我们有好多文件 [00:11:22] 什么什么README.md [00:11:26] 然后是什么hello [00:11:28] 点C [00:11:30] 还有一个什么DOS下的什么什么什么文档 [00:11:33] 然后其实如果如果所有的这些东西 [00:11:38] 我们人都不几乎不管了 [00:11:41] 那我们有没有可能我一直在想 [00:11:43] 就等这件这件这个未来到来 [00:11:46] 我们把这里面软软件或者说部件之间 [00:11:50] 就也许我们还是需要文档 [00:11:51] 但我们的文档可能是好多个切片 [00:11:53] 好多切片就把他们变成好多的对象 [00:11:56] object或者是entity [00:12:00] 然后 [00:12:01] 那比如说这个文档和文 [00:12:04] 这个实现之间就有一个关系 [00:12:06] 它实现了这个这个代码 [00:12:08] 实现了这个文档 [00:12:09] 然后我可能有个测试用例 [00:12:13] 然后这个测试用例也有这个文档 [00:12:16] 那这个文档和测试用例又关联起来了 [00:12:19] 然后这个测试用例是和这个代码的这部分实现 [00:12:21] 是关联起来的 [00:12:22] 然后这个文档又和这个文档是关联起来的 [00:12:24] 然后你看这是一个完全结构化的东西 [00:12:27] 没有办法在文件系统里以一个树状的形式表达 [00:12:29] 这是一个就随便连接的一个图 [00:12:31] 有cycle的图graph [00:12:33] 那这个东西 [00:12:35] 比如说我可以把它放到一个数据库里 [00:12:37] 叫这个就叫repo.db [00:12:41] 那显然人类就没有办法用现在的这个UNIX的世界 [00:12:45] 里面的工具去维护这样的一个repository了 [00:12:47] 但不要紧 [00:12:48] 我们应该怎么 [00:12:50] 或者说我们应该应该怎么解决 [00:12:52] 用魔法打败魔法 [00:12:54] 人类理解不了的东西 [00:12:55] 我们只要训练AI [00:12:56] 就他只要有强化学习的反馈信号 [00:12:58] 我们就可以训练AI [00:12:59] AI能够理解这个repo [00:13:01] 所以我们要干的是什么 [00:13:03] 这就是一个非常大的项目 [00:13:04] 什么LINUX内核数据库 [00:13:06] 或者你们想做的一个价值一个亿的产品好 [00:13:09] 那每次你就说好AI [00:13:11] 因为你也不太可能说一下子就说 [00:13:14] 我要把这个产品直接变成另外一个产品了 [00:13:16] 一当你比如说这个软件系统已经在工作了 [00:13:19] 那你一般来说就是要给它增加一个功能 [00:13:22] 修改一个功能 [00:13:23] 然就跟git的理philosophy很像 [00:13:27] git管理了文件目录 [00:13:29] 快照和快照之间的关系 [00:13:30] 你的你的git [00:13:32] 希望我们能够小步前进 [00:13:34] 我每做一件事情 [00:13:35] 我fix一个bug [00:13:36] 我改一个文档 [00:13:37] 我都产生一个commit [00:13:39] 然后这样我就可以在多个人之间协作 [00:13:41] 每个人可以自己产生自己的commit [00:13:43] 然后我们可以用像rebase merge [00:13:45] 这个fast forward的 [00:13:47] 这些 [00:13:47] 就或者是普通的这种merge来 [00:13:50] 创建一个可追踪的 [00:13:52] 成整个项目的修改历史 [00:13:54] 那如果我们以后也不要文件 [00:13:58] 就也不是用 [00:14:00] 也许也许还可以用文件系统来管理 [00:14:02] 那我们要的就是 [00:14:03] 我们可以让AI自动维护 [00:14:07] 所有的这个artifacts软件 [00:14:09] artifacts之间的一致性 [00:14:11] 这个artifacts之间一致性 [00:14:12] 就比如说代码和文档必须要一致 [00:14:14] 我文档说这是link list [00:14:15] 我的实现里面必须是link list [00:14:17] 然后我的这个test case测试用例 [00:14:20] 我文档里面说 [00:14:21] 我要有ABC3个方面的测试 [00:14:23] 那我这个test case就必须要有ABC [00:14:26] 它都是关联起来的 [00:14:27] 然后呢你想从git里面 [00:14:29] 我们知道我们希望小步前进 [00:14:33] 我们希望小步前进 [00:14:34] 那同样的 [00:14:36] 当我们谈要做一小步的时候 [00:14:38] 其实我们知道这一小步是干什么的 [00:14:40] 所以你可以chat [00:14:41] 你可以跟AI chat说 [00:14:43] 我现在要哎 [00:14:44] 我现在发现他有个bug [00:14:45] 或者我做了一个产品 [00:14:47] 比如说我现在今天对这个幻灯片样式不满意 [00:14:50] 那这就其实就是一个小步 [00:14:52] 然后呢这个时候一个大型的软件系统里面 [00:14:55] 绝大部分的内容跟这个小步都是没有关系的 [00:15:00] 比如说我当当我谈说哎 [00:15:02] 我对这个幻灯片的样式不感兴趣的时候 [00:15:04] 我比如说大家可以看直接看我的 [00:15:07] 看我这个repo [00:15:09] 看下顶层的结构 [00:15:10] 我有 [00:15:11] 我有些assets [00:15:13] 然后甚至还有这个点cache [00:15:15] 有缓存的系统 [00:15:17] 然后有这个P1P2P3P4P5 [00:15:19] 然后有一些脚本等 [00:15:22] 那任何一个软件系统 [00:15:24] 当你只做一小步的时候 [00:15:26] 你就只需要看到这个软件系统的一小部分 [00:15:29] 大部分东西应该是无关的好那既然是无关的 [00:15:32] 我们就可以让AI根据我们的chat [00:15:35] 把和我相关的东西给摘出来 [00:15:38] 他可以他可以知道 [00:15:40] 我现在需要需要的是这个文件 [00:15:43] 这个test case和这个文档 [00:15:44] 其是其他的东西都不需要了 [00:15:47] 然后你想AI有什么能力 [00:15:50] AI有动态生成任何内容的能力 [00:15:54] everything is code [00:15:56] content as code code可以表达任何东西 [00:15:59] 所以AI可以根据我的chat [00:16:01] 生成一个和我要改的这一小步相关的view [00:16:06] 一个视图诶 [00:16:08] 在这你看你们学到的这个各种系统里面的概念 [00:16:11] 还是有用的 [00:16:12] 就因为不是所有的同学都学过数据库 [00:16:15] 数据库里面有一个叫view的概念 [00:16:17] 他说我们我们的数据数据数据就在这了 [00:16:20] 但我可以创建一个不一样的查询 [00:16:22] 可以把它以另一个形式展示出来 [00:16:25] 这就是这个很简单的想法 [00:16:26] 我希望把这个这些数据 [00:16:29] 以另外一个形式给展现出来 [00:16:32] 但比如说当我看到的时候 [00:16:33] 我就看到的不是这些代码文档DF这些 [00:16:36] 而是一个可视化的一个看板 [00:16:39] 然后这个看板上面大概说了 [00:16:40] 列出了和我这个小步相关的一些东西 [00:16:43] 然后问我要改什么 [00:16:44] 然后我一把改完了以后 [00:16:46] 我同样的还是从一个 [00:16:49] 从一个V0到V1 [00:16:53] 他还是一个repo.db [00:16:56] 但是这一小步就会把这些相关联的东西 [00:16:58] 比如说我要增加一种类型的测试用例 [00:17:01] 那他就会在这个测试用例里面 [00:17:02] 比如说我还是画一个这样的结构 [00:17:05] 对吧啊好 [00:17:06] 那他可能就会在这些地方加一些测试用例 [00:17:09] 这个地方加一些测试用例 [00:17:11] 这个地方加一些测试用 [00:17:12] 例 [00:17:12] 然有些地方可能要改掉 [00:17:14] 他就从一个一致的状态 [00:17:16] 就是各种复错综复杂的关系 [00:17:18] 然后做一次小步的修改到这个啊下一个版本 [00:17:24] 然后这样我们就好像 [00:17:26] 就软件工程就又变了彻底变了 [00:17:28] 然后我觉得这是一个未来有可能发生的 [00:17:30] 就是在AI内部 [00:17:32] 它是这样生产软件 [00:17:33] 然后然后从此以后我们也就再也不要看代码了 [00:17:36] 就我觉得你们看到现在的这种现代IDE [00:17:38] 比如说cursor [00:17:39] 我其实还蛮讨厌的 [00:17:40] 就是他现在就打开默认就是agent mode [00:17:43] 然后agent mode [00:17:44] 就是原来的那个我们熟悉的那个IDE [00:17:46] 它就没有没有了 [00:17:48] 然后强迫你用一个像像chat [00:17:50] 类似于chat的方式去跟他沟通 [00:17:52] 但因为我还是相对来说比较精通 [00:17:56] 古法编程的 [00:17:57] 这个有时候我还是对代码有一些掌控欲 [00:18:00] 可能是不好的 [00:18:01] 这个可能是不对的 [00:18:02] 但是就未来可能会是这是这可能是一个途径 [00:18:07] 然后你们当然我觉得同学们肯定也会焦虑的 [00:18:10] 那如果未来 [00:18:12] 这件事情真的有可能发生 [00:18:13] 而且就可能一两年以后 [00:18:15] 大家就真的有一个公司把这东西做出来了 [00:18:17] 那我们学那么多多东西还怎么办 [00:18:21] 然后其实你发现在我们思考 [00:18:23] 就在创造这些东西的过程当中 [00:18:26] 我们用的都是你们学习的这些经典集大成的 [00:18:30] computer science的课程 [00:18:31] 我刚才说的数据库里的视图 [00:18:34] 数据库我用的是借用了数据库的概念 [00:18:36] 实体和关系 [00:18:37] 然后我借用了git [00:18:39] 我用git就这个模型没有变 [00:18:41] git长期的开发经验说 [00:18:43] 我们要一步一步向向前 [00:18:46] 如果在这个模型底下 [00:18:47] 我们是大步向前 [00:18:48] 那就惨了 [00:18:49] 那当然也有可能发生 [00:18:50] 就是模型面非常非常强 [00:18:52] 一个非常大型的项目 [00:18:53] 而且一步啪就变成变成下一个了 [00:18:56] 这个这个怎么做 [00:18:57] 我们现在还不知道 [00:18:58] 但是至少在初期 [00:19:02] 我们可能还是要沿用这个过去的这个 [00:19:05] 大家积累的软件工程智慧去小步向前 [00:19:08] 然后通往那个极乐的世界 [00:19:10] 但我还是相信这个极乐世界有可能 [00:19:13] 确实有可能是能是能到的对 [00:19:16] 所以这就这就引发了一个我觉得 [00:19:20] 在大学里面 [00:19:23] 我觉得蛮有意思的这个一个评论吧 [00:19:26] 这个这个同学应该是已经毕业了 [00:19:29] 已经毕业 [00:19:30] 因为我上上节课说我问那个同学们git rebase [00:19:34] 然后大家都不知道什么是git rebase [00:19:36] 然后他raise了一个valid point [00:19:38] 就是说他说学生时代 [00:19:40] 大多数人是不会和他人共同合作的 [00:19:42] 也就是做作业 [00:19:43] 所以rebase merge用的场景就很少正确 [00:19:47] 这个point是对的 [00:19:49] 就你们做作业的时候确实确实不会 [00:19:51] 然后我的回应是大概是这样的 [00:19:52] 但是 [00:19:53] 如果你真的去往这个外面的世界去走一走的话 [00:19:56] 这个互联网开发者社区铺天盖地都是文档 [00:20:00] 所以你一定会在有一天你会留意过别人的项目 [00:20:03] 会看到过叫contributing.md [00:20:05] 然后一般来说这个肯你马上就问这个 [00:20:08] 你们有没有同学问过 [00:20:16] rebase [00:20:17] 没关系 [00:20:17] 错了就错了 [00:20:19] 哎我没有 [00:20:21] 我没有 [00:20:21] 他还 [00:20:27] 仓库根目录下的一份贡献者指南 [00:20:30] 通常回答我怎么参与这个项目 [00:20:32] 然后你看它里面就有这些就项目的总体的结构 [00:20:36] 然后分支提交信息 [00:20:38] pr的规范和流程 [00:20:40] 那你如果看过 [00:20:42] 就这如果你看过很多的项目的contributing.md [00:20:45] 你比如说你就随手打开看一眼 [00:20:48] 然后如果你发现里面东西都知道了 [00:20:50] 那你就知道了 [00:20:51] 如果你不知道 [00:20:51] 比如说有一天 [00:20:52] 你一定会看到一个项目里面有一个说 [00:20:54] 我们你必须要在你自己的分支上REBASE [00:20:57] 你禁止你 [00:20:58] 你这种就我们要保持线性历史 [00:21:00] 禁止你直接创建那种分叉的merge [00:21:03] 你就会知道REBASE是干什么的 [00:21:06] 然后它现在是什么 [00:21:08] 现在我们的社会变得太快了 [00:21:11] 所以有一种学生其实不是批评 [00:21:15] 批评大家就是因为你们你们上高中的时候 [00:21:16] 就是这样的 [00:21:17] 在高中时候老师不教的 [00:21:19] 就是你不需要会的 [00:21:20] 考试不考 [00:21:21] 就是你不用学的 [00:21:22] 非常明显的一个你们为了升学的利益最大化 [00:21:26] 这个是正确的 [00:21:26] 没有 [00:21:28] 没有没有错 [00:21:30] 然后在你们到大学以后 [00:21:31] 你们如果还带着这个思维的话 [00:21:33] 你就你就会有这样的 [00:21:36] 就是这样的gap [00:21:37] 就是你一种新人类和旧人类之间的这个gap [00:21:41] 当然但我相信每一个同学也还是可以成为 [00:21:44] 成为成为新人类的 [00:21:45] 然后那你只需要去有一些注意力 [00:21:48] 去注意到这个更多的东西 [00:21:51] 因为因为现在我有一个危机 [00:21:54] 就是AI时代的斩杀线以下的价值就全部归零 [00:21:58] 当然我觉得现在斩杀线可能还斩不到 [00:22:01] 这个各位 [00:22:02] 985同大学这个computer science专业的同学 [00:22:05] 但是可能比如说那些低级的那种 [00:22:08] 低级智力劳动 [00:22:10] 比如说会计从业者 [00:22:12] 好像我看过一个报道 [00:22:14] 说中国可能是不是有1000万 [00:22:15] 还是有多少这个会计从业者 [00:22:17] 那这个行业里面顶端的人 [00:22:20] 肯定暂时还是没有威胁的 [00:22:22] 但是在底下的这个大量的人都面临 [00:22:25] 这个被agent的替代斩杀的啊危险 [00:22:27] 所以你们需要在这些经典的课程上 [00:22:30] 不管是什么操作系统 [00:22:32] 编译器这些 [00:22:34] 然后还是软件工程 [00:22:35] 这里面有些软件工程的智慧 [00:22:37] 你们学到一些经典的东西 [00:22:39] 然后最终形成你们自己的啊自己的理解 [00:22:42] 对这是这是一些啊评论和复习复习 [00:22:46] git好 [00:22:47] 那我们继续回到软件工程 [00:22:53] 不管是这个模型 [00:22:54] 就是我说我畅想一下 [00:22:56] 未未来会发生什么 [00:22:58] 还是我们就是就是git [00:23:01] git git [00:23:02] 他管理的是快照 [00:23:06] 也就是一个目录 [00:23:10] 整个一个可能是也就是这样的一个东西 [00:23:12] 的一个快照好 [00:23:14] 那我可以在快照上面做一个开发 [00:23:18] 做一个开发他要求小步 [00:23:20] 那我现在现在有一两个开发者 [00:23:22] 一个是A一个是B [00:23:23] 我们就可以独立的在这两个上面啊做开发 [00:23:27] 然后好 [00:23:30] 那这个东西是commit [00:23:34] 然后如果你要做这个时候 [00:23:37] 如果你要想把它合起来 [00:23:39] 那在git里面 [00:23:40] 在git的这个原始的模型里面 [00:23:44] 它REBASE相对来说是不那么提倡使用的 [00:23:47] 它是说好 [00:23:48] 你会创建一个就是两路的merge [00:23:51] 他有222个parent [00:23:53] 继承了这两个的这个修改 [00:23:56] 但是但是这又带来一些问题 [00:24:00] 比如说这个merge完 [00:24:01] 比如说merge是由AA来A来干的 [00:24:04] 那这个merge里面的这个一些内容 [00:24:08] 就由B写的这些内容 [00:24:11] 他就它就变他作者就变成A了 [00:24:14] 他其实有一个隐藏的作者修改 [00:24:17] 比如说B在这儿加了一行 [00:24:20] 在这个可能还能还能追溯到B [00:24:22] 就如果发生冲突 [00:24:23] 比如说发生冲突时候 [00:24:24] 在resolve的时候 [00:24:26] 那冲突完了以后 [00:24:27] 这个称职就是由这是由A完成的 [00:24:29] 这是A完成的 [00:24:30] 那这个这B改的代码 [00:24:33] 最后ownership又归到了A [00:24:35] 所以这会带来一些 [00:24:37] 相对来说有一点小小的小麻烦 [00:24:39] 然后rebase解决了这个问题 [00:24:41] rebase哎 [00:24:42] 我还是横过来画 [00:24:43] 这个是不是第一排的同学有点看不到 [00:24:48] 如果我现在有两个历史 [00:24:50] 那比如说我现在我现我现在改了 [00:24:55] 这是这是A同学A同学改了 [00:24:58] 改了两份 [00:24:59] 做了两次的提交 [00:25:00] 得到两个两个快照 [00:25:02] OK德尔塔一德尔塔二好 [00:25:04] 然后我这个时候另外一个同学开始改好 [00:25:09] 那rebase做了一件什么事 [00:25:12] rebase说的是 [00:25:15] 比如说A先先改了文档 [00:25:18] 然后再加了测试 [00:25:22] 然后然后我B加了一个feature [00:25:25] 然后又加了一个 [00:25:27] 加了一个测试 [00:25:28] 那这个时候我不是直接把他们两个东西 [00:25:33] 创合成一个 [00:25:35] 说把这两条线路并起来的提交 [00:25:38] 而是我试图先把这个feature能不能在 [00:25:44] 我先要试一试 [00:25:45] 有没有可能在这个A的这个后面 [00:25:49] 把这个feature加上 [00:25:52] 如果加上了 [00:25:53] OK那就成功了 [00:25:54] 这就成功了好但是这是有一个很大的风险的 [00:25:59] 就是因为我可能在这个里面 [00:26:02] 加入了一个测试用例 [00:26:04] 然后这个测试用例和这个feature就是不兼容的 [00:26:08] 这是这是有可能的 [00:26:09] 或者甚至就是他们就改了同一个地方 [00:26:10] 我就做了两个完全不兼容的东西 [00:26:12] 那这个时候他是有可能可能失败的 [00:26:15] 如果成功 [00:26:16] 这就比较好 [00:26:17] 那我再把test放过来 [00:26:20] 如果成功 [00:26:21] 那么他就一路相当于 [00:26:23] 如果就也就是说这两条线上那边的修改 [00:26:26] 完全没有任何冲突 [00:26:27] 那我就可以一路把它合并过去 [00:26:29] 变成一个线性的历史 [00:26:30] 但是一旦发生冲突 [00:26:32] 这是非常危险了 [00:26:33] 为什么 [00:26:34] 一旦冲突 [00:26:35] 你就需要resolve [00:26:37] 你会进入一个REBASE的模式 [00:26:38] 你们如果如果进入过这个模式 [00:26:40] 你会发现瞬间自己就不知道应该怎么办了 [00:26:43] 然后这时候你就打开你的agent的说 [00:26:45] 哎我现在在我先我发生了什么 [00:26:49] 然后然后然后然后agent会细心的解释 [00:26:52] 解释给你 [00:26:53] 更麻烦的是 [00:26:54] 你就算是把这个东西搬过来了 [00:26:56] feature搬过来了 [00:26:58] 你可能搬test的时候又要失败 [00:27:02] 然后你还需要再把test这个再搬过来 [00:27:06] 而且每一次你都会创建一个新的提交 [00:27:08] 也就是说这是一个这是一个commit [00:27:11] 他有一个id [00:27:12] 这commit有id [00:27:13] 每个commit都有id [00:27:15] 那如果你是一个这样的两路的merge [00:27:19] 那所有的这些id都保留了 [00:27:21] 你会创建一个新的id [00:27:23] 但是因为你是REBASE的REBASE [00:27:26] 每次这样的rebase就会创建一个新的commit [00:27:29] 因为他这个快照 [00:27:31] 本来这个快照的base在这个 [00:27:35] 这个commit的base在这所谓的rebase你就知道 [00:27:38] REBASEREBASE它的base要改掉 [00:27:43] 要把这个base改到这里来 [00:27:45] REBASE那你会创建一个新的id [00:27:50] 每次会创建一个新的id [00:27:51] 然后然后这个历史就变了 [00:27:54] 然后你会感觉到这里有一点点轻微的 [00:28:00] 不一致 [00:28:01] 就觉得你好像不想 [00:28:03] 不是完全要想这样去 [00:28:06] 管理软件 [00:28:07] 因为我们关心的是修改 [00:28:11] 也就是我希望的是把这个修改搬过来 [00:28:15] 把这个修改搬过来 [00:28:17] 然后在git里面修改是用commit来替代的 [00:28:20] 说好我现在有一个commit [00:28:22] 然后这个commit和他的parent之间的关系 [00:28:25] 就叫一个修改 [00:28:27] 他没有一个专门的叫change的这个对象 [00:28:31] 所以它这用commit it来代替修改 [00:28:33] 那可能绝大部分的情况都还能满足 [00:28:36] 但是如果我们把change也变成first class citizen [00:28:42] 会发生什么 [00:28:44] 你就发明了这个下一代更好用的 [00:28:48] 版本版本控制系统 [00:28:51] 就是说你我不仅可以有这个 [00:28:55] 有commit的ID [00:28:57] 甚至甚至这个机器组 [00:28:59] 它是和git底层完全兼容的 [00:29:02] 你可以直接把当git用 [00:29:05] 然后但是在它增加了 [00:29:07] 增加了一个叫做change的概念 [00:29:10] 也就是每一个这个东西 [00:29:13] 每一个这样的东西change [00:29:18] 他都可以sin一个这个一个change [00:29:22] 然后他可以把好多的change [00:29:26] 比如REBASE的时候 [00:29:27] 他会把change直接把change搬过来 [00:29:29] 然后change还是有可能就冲突是冲突是解决不了的 [00:29:33] 就如果我在REBASE的时候 [00:29:34] 我要我要冲冲突 [00:29:36] 这是解决不了的 [00:29:37] 但是因为它有这个change的object [00:29:39] 就change这个概念 [00:29:40] 所以他可以把这些change值一路带下来 [00:29:43] 生成一个直接REBASE到这里 [00:29:45] 但是里面引入了好多冲突 [00:29:47] 就你他还是运用了git的那个冲突 [00:29:49] 冲突那个记录 [00:29:50] 但你看他的里面有一套自己的记录方式 [00:29:52] 把所有这些change的冲突也都塞进去 [00:29:56] 然后你可以在这里相当于把它们搬过来 [00:29:58] 然后在这里再resolve它的底层的模型没有变 [00:30:01] 但是你用起来会舒服很多 [00:30:05] 然后他有一个很好的特点 [00:30:08] 它不需要staging area [00:30:10] 就是你在你在git里面 [00:30:16] 最讨厌的是什么 [00:30:18] 啊我上我上操讯课的时候会讲 [00:30:21] 会讲这个例子 [00:30:22] 最讨厌的是你现在有个工作区 [00:30:25] 你现在有个你现在有个repo [00:30:27] 然后你现在改了 [00:30:28] 比如说你有一个hello点C [00:30:30] 然后现在把它改了改改改改改到一半 [00:30:34] 然后这个时候项目还不能编译 [00:30:37] 也不能运行 [00:30:38] 测试也通不过 [00:30:38] 就你改到一半 [00:30:39] 突然导师给你打电话 [00:30:42] 哎呀我现在有一个很高很高优先级的项目 [00:30:46] 这个你就有个bug [00:30:48] 马上客户就这个项目就要交不了差了 [00:30:50] 这个赶快把这个bug给我一分钟修了好 [00:30:53] 那你怎么办 [00:30:55] 你不应该commit [00:30:57] 就是你需要你需要的是你 [00:31:00] 你现在把它加到你的这个index里 [00:31:01] 然后git stash [00:31:02] 然后他会压栈压栈 [00:31:04] 然后这其实是一个比较讨厌的操作 [00:31:08] 因为你stash是一个东西 [00:31:10] stash是一个东西 [00:31:11] 然后stash一个东西 [00:31:12] 你去把原来那个bug开始修 [00:31:14] 你刚修了一半 [00:31:16] 你的导师又给你打电话 [00:31:18] 哎呀你这个bug别修了 [00:31:19] 这个我还有一个更优先级更高的bug [00:31:21] 你去把它修了好 [00:31:23] 你这时候要再把它stash [00:31:24] 然后那git stash是一个栈 [00:31:25] 然后它里面就会有好访问 [00:31:27] 好多好多个提交 [00:31:28] 然后你去你需要去管理那个那个stack [00:31:32] 然后如果你想象 [00:31:36] 如如果你想象在任何时候 [00:31:38] 也就是你随时随地都在编辑这个repo [00:31:41] 这不就是一个change吗 [00:31:45] 这就是一个change [00:31:47] 你现在把hello点C改一改 [00:31:49] 加一行减一行 [00:31:51] 他都是change [00:31:52] 所以你 [00:31:53] 所以这个jj他好像是在干一件什么事 [00:31:56] 好像是你但凡改了一个字节 [00:32:00] 他都会立即做一个git commit [00:32:02] 当然这个commit不会产生这个好多 [00:32:05] 这个线性的历史 [00:32:06] 而是先把上一次的那个就上一次 [00:32:09] 那肯定得给抹掉 [00:32:11] 然后他上一次的commit就你改了一个字节 [00:32:14] 那上一次的那个提交就被抹掉了 [00:32:16] 抹掉了 [00:32:17] 然后你重新用当前这个修改去替代这个提交 [00:32:20] 也就是说你永远是把因为现在有个change [00:32:25] 这现在有个当前的snapshot [00:32:28] 它永远是提处于一个提交的状态 [00:32:30] 一个change提交的状态 [00:32:32] 那你就很舒服了 [00:32:33] 你 [00:32:34] 你连这个这个staging area也不需要了 [00:32:39] 这就是一个非常好的 [00:32:41] 它几个你从 [00:32:45] 你从我要把change作为first class citizen开始 [00:32:48] 你再往后推 [00:32:49] 你就可以发明自己的版版本管理系统 [00:32:52] 当然这个不是它的全部 [00:32:53] 然后它还有一些这个别的 [00:32:56] 有别的路线可以可以推导出来 [00:32:58] 但是你们适当的时候可以质疑一下 [00:33:02] 比如说git [00:33:04] 就git有没有哪里做的不够好 [00:33:06] git哪里做的不够好 [00:33:07] 然后如果如果可以做的更好的话 [00:33:09] 还能做怎么样的设计 [00:33:12] 所以我觉得这是这是很有趣的 [00:33:13] 一些非常有趣的设计 [00:33:15] 你们可以在agent的带领下 [00:33:17] 或者说我开了一个头 [00:33:19] 我说我给你们一些motivation [00:33:20] 你们可以把这些最重要的prompt交给agent [00:33:24] 说我如果要学Jujutsu [00:33:25] 然后我想我想我想从change开始理解 [00:33:29] 然后如果如果你看他的tutorial的话 [00:33:30] 他其实也是一上来就会告诉你 [00:33:32] 他没有没有staging [00:33:35] area啊等 [00:33:37] 这样的 [00:33:38] 你管你管理这个版本是更自然 [00:33:40] 它对人类首先对人类更友好 [00:33:43] 然后实际上它可能会对agent也稍微更友好一点 [00:33:46] 友友好一点 [00:33:48] 对友好一点 [00:33:49] 所以这我觉得为什么你们作为AI native的人类 [00:33:52] 能够淘汰掉这个我们这一代人 [00:33:55] 就是因为我已经形成了git的肌肉记忆了 [00:33:58] 然后比我更老的一代人 [00:34:00] 他已经形成SVN的肌肉记忆了 [00:34:02] 然后当一旦人形成一个肌肉记忆以后 [00:34:05] 要把这个习惯掰过来就很困难了 [00:34:08] 就比如说我现在对git是有肌肉记忆的 [00:34:09] 但是我即便是能够理解这个jj的概念 [00:34:13] 甚至我可能理解的会比会比你们 [00:34:15] 可能作为初学者还要更更好一些 [00:34:18] 我还是可以从我的first principle去思考它 [00:34:21] 自己相当于virtually reimplement这个系统 [00:34:24] 但是我即便能够理解 [00:34:25] 我也没有足够的时间再去训练另外一个 [00:34:29] 肌肉记忆 [00:34:30] 所以所以你们你们是反过来的 [00:34:32] 你们这跟我正好是反过来的 [00:34:33] 你们应该在你们现在还没有形成记忆 [00:34:36] 有记忆的时候就直接去用那个对的东西 [00:34:39] 就人类历史都是积累的 [00:34:41] 他SVN大实际用不下去了才用才用git [00:34:45] 然后git他发现了git的缺点以后有了jj [00:34:49] 所以你们可以的是先用肌肉记忆 [00:34:53] 记住一个最正确的设计 [00:34:55] 然后再去理解这个设计是怎么样 [00:34:57] 就你再回去想的时候 [00:34:58] 原来git这么蠢 [00:35:00] 在git出现的时候 [00:35:01] 你大家会想 [00:35:02] git这么先进 [00:35:03] 它是一个persistent data structure [00:35:05] 这是SVN就是SVN [00:35:07] 从一开始他从走从纯纯DF那条线就走错了 [00:35:11] 到git的时候 [00:35:12] 大家觉得很先进 [00:35:12] 然后到到现在的时候 [00:35:13] 你再回去看的时候 [00:35:14] 原来git也犯了一个 [00:35:16] 犯了一些 [00:35:18] 设计上 [00:35:18] 它当然这是这是因为他最早的时候他没有 [00:35:22] 没有想过rebase会有这么大的Impact [00:35:25] 他有merge就已经很好了 [00:35:28] 就能解决他手上的问题了 [00:35:30] 所以他可能没有把这个概念模型想的 [00:35:32] 想得更加更加的清楚 [00:35:34] 这个这是一些有意思的 [00:35:37] 这个 [00:35:38] 这个comments也是你们学习 [00:35:40] 可以告告诉你们一些学习的建议 [00:35:42] 你们在学东西的时候 [00:35:45] 其实尤其在AI的辅助下 [00:35:47] 可以不断的往前走往前走往前走 [00:35:50] 这是这个对好 [00:35:54] 但这门课不是软件工程 [00:35:57] 这门课是生成式软件工程 [00:35:59] 所以我们要真正要做的事是 [00:36:02] 在agent的时代再次重新设计版本管理管理系统 [00:36:06] 也就是说你当然可以让这个agent的去用git [00:36:10] 然后让agent的去用jj [00:36:11] 那啊这对人类来说 [00:36:14] jj是一个很大的进步 [00:36:16] 但对agent来说可能可能进步来说相对会小一些 [00:36:19] 因为他好像很会很会REBASE这些 [00:36:23] 那这个时候你看我们一路走过来 [00:36:27] SVN有局限 [00:36:28] git有局限 [00:36:30] 那在agent的时代 [00:36:33] 我们的局限和我们要做的破掉的改进是什么 [00:36:37] 刚才所有的这个version control system它都有一个假设 [00:36:42] 这个假设就是这version control system的使用者是人类人 [00:36:47] 人类有什么特点 [00:36:48] 人类是这个single-threaded的生物 [00:36:51] 我一直上上操作系统课的时候讲并发程序 [00:36:54] 然后并发程序我打什么 [00:36:55] 比方 [00:36:56] 你就把线程想象成是一个人 [00:36:58] 然后你的线程可以访问共享内存 [00:37:00] 那访问共享内存的时候 [00:37:02] 两个基本的操作是load和store [00:37:04] 或者说read和write [00:37:06] 我可以从一个变量里读一个值 [00:37:08] 我把X读到我的临时变量里 [00:37:10] 或者我可以写X等于一 [00:37:12] 然后这个操作是不能同时进行的 [00:37:15] 就是我不能说既读一个又写一个 [00:37:17] 你这样就需要一个原子指令了 [00:37:19] 然后绝大部分的这个share memory access [00:37:21] 你能想象成人是什么 [00:37:22] 我如果想要观察这个世界 [00:37:24] 想要观察这个世界 [00:37:26] 那我对不起 [00:37:26] 我手要抱抱在抱在后面 [00:37:28] 我只能看 [00:37:29] 然后等我看完了 [00:37:30] 比如说我看到这个同学在这 [00:37:32] 我想要对他施加一个效果 [00:37:33] 比如说我想用这个粉笔导弹射击他 [00:37:36] 那当我想要真正要write就写一个变量的时候 [00:37:40] 我必须要把眼睛闭起来 [00:37:42] 而我把眼睛闭起来扔的时候 [00:37:45] 注意我读到的那个值其实已经失效了 [00:37:48] 那个值已经是旧的值 [00:37:49] 就是我上一个时刻读的 [00:37:51] 那在上一个时刻到这个时刻之间 [00:37:52] 可能经历了很多的事情 [00:37:54] 可能我被换CPU换下去了 [00:37:57] 我被中断打断了 [00:37:58] 然后换了另外一个线程上来执行 [00:38:00] 然后执行了 [00:38:01] 可能执行了一秒钟以后我才恢复过来 [00:38:04] 但我恢复过来以后 [00:38:05] 我看到的我在寄存器里面看到那个X值 [00:38:07] 我上次读X等于一 [00:38:08] 然后这个时候我就把那个粉笔扔出去了 [00:38:10] 那很有可能就扔的就是就是错的 [00:38:13] 就是single-threaded [00:38:14] 然后当多线程的时候 [00:38:15] 带来带来这多线程共享内存 [00:38:17] 就带来了无穷的问题 [00:38:20] 其实人类也是的 [00:38:21] 人类 [00:38:21] 人和人之间是有这个无法逾越的物理屏障的 [00:38:27] 你不能理解我的思想 [00:38:28] 我也不能理解我的思想 [00:38:30] 我就是一个独立的个体 [00:38:32] 由分子 [00:38:33] 把我很强的连在一起 [00:38:37] OK所以我们只有一份IO设备 [00:38:39] 我们就一双一一双手 [00:38:41] 一张嘴 [00:38:41] 一对眼睛 [00:38:42] 然后那么我们我们在 [00:38:45] 比如说在编辑这个代码库的时候 [00:38:47] 以这种方式编辑代码库产生change [00:38:50] 那就是以小时为单位的 [00:38:54] 小时为单位的 [00:38:55] 然后 [00:38:56] 一个软件公司可能比如说负责一个模块的开发 [00:39:00] 可能多也就十几个人 [00:39:01] 十几个人已经是一个不小的团队了 [00:39:03] 那十几个人每个人以小时为单位开发 [00:39:07] 那最多这个也就是以10分钟这样的 [00:39:11] 10分钟这样的单位产生一个提交 [00:39:16] 好那10分钟为单位产生一个提交 [00:39:20] 意味着这个速度会比人和人之间沟通的速度 [00:39:24] 要慢很多 [00:39:25] 因为尤其是一个team [00:39:26] 他工位都在一起 [00:39:27] 你们你们研究生的工位都在一起 [00:39:29] 你马上 [00:39:30] 你再写 [00:39:31] 你要写一个东西要一两个小时 [00:39:33] 你在写之前你肯定跟师兄说一声 [00:39:35] 哎师兄我要干个这个行不行 [00:39:38] 十二十秒钟 [00:39:39] 30秒钟 [00:39:40] 师兄说行 [00:39:41] 你去你去改吧 [00:39:41] 我们现在不再改 [00:39:43] 或者你们你们如果去厂里面打工了 [00:39:46] 厂里面可能每天早上都要开会 [00:39:48] 每天早上的leader都会把任务分享出来 [00:39:51] 今天我们要干什么事情 [00:39:52] 然后你做什么 [00:39:53] 你做什么 [00:39:53] 你做什么 [00:39:54] 你就提前在 [00:39:55] 什么半小时的时间里 [00:39:57] 你就划分了一个scope [00:39:59] 你就把这个项目切开了 [00:40:00] 你领了其中一部分走 [00:40:01] 然后你就去产生垂直 [00:40:03] 当然这是古法 [00:40:05] 古法编程 [00:40:06] 古法编程 [00:40:07] 那在古法编程的时代 [00:40:09] 你就看到比如说stash是一个合理的 [00:40:14] 是一个合理的设计 [00:40:15] 因为你不你我刚才说的那个情况 [00:40:18] 你导师给你打电话 [00:40:20] 导师给你打电话 [00:40:21] 这件事情是可能发生的 [00:40:23] 但是在你修到一半的时候 [00:40:26] 导师再给你打电话 [00:40:27] 这件事情是不太可能发生的 [00:40:29] 发生概率是很低的 [00:40:30] 绝大部分时候你的这个stash也就是stash stack [00:40:34] 里面就一层 [00:40:34] 如果你有好多层 [00:40:35] 你管起来其实其实挺麻烦的对 [00:40:37] 还有一点麻烦 [00:40:38] 你还你就需要去rebase stash [00:40:41] 所以你会你会尽可能的保证这个stash [00:40:44] 不要太深 [00:40:45] 因为你可以拒绝一个工作 [00:40:46] 或者你会说我手上有一个更高优先级的工作 [00:40:48] 我现在对不起 [00:40:49] 我不能干这个事 [00:40:50] 然后等你干完了以后 [00:40:51] 你自己可以可以排一个开 [00:40:53] 排一个队列 [00:40:54] 所以git是给人用的 [00:40:56] 但是在agent的时代 [00:40:58] 这件事情变了 [00:41:02] 如果是一个agent team [00:41:04] 单个agent [00:41:05] 它首先生产这个AI slop的速度就远远快于人 [00:41:09] 它 [00:41:10] 它生成AI slop就以分钟级为单位 [00:41:12] 甚至更快 [00:41:13] 它有时候你让他fix一个东西 [00:41:15] 它在上下文是热的时候可能就极几十秒钟对 [00:41:19] 讲DeepSeek V4 Flash [00:41:20] 他干活的时候就几秒钟就做了 [00:41:23] 那以秒级当agent工作时候 [00:41:26] 以秒即可以产生一个原子提交 [00:41:29] 并且你可以轻易的得到一个十倍100倍的agent [00:41:33] team的时候 [00:41:34] git或者jj是这样的 [00:41:36] 他举起来是跟git兼容的 [00:41:38] 这样的一个为人设计的模型 [00:41:40] 就有点跟不上 [00:41:42] 确实是有一点 [00:41:45] 跟不上这个这个速度 [00:41:46] 就算是可能大型的项目 [00:41:48] 它有一些门控 [00:41:49] 就是你当我写完了以后 [00:41:51] 改完这个部分以后 [00:41:52] 他必须要经历一个测试的流水线 [00:41:53] 那这个测试可能本身就要运行几分钟 [00:41:56] 那可以放缓agent的提交的速度 [00:41:59] 但是毫无疑问的 [00:42:02] agent加速了这个软件开发的过程 [00:42:05] 那如果agent加速的软件开发的过程 [00:42:07] 我们应该怎么样为agent的设计这个版本管理的 [00:42:12] 系统 [00:42:14] 那首先我们可以让agent沿用人的模型 [00:42:18] 每个agent你就想 [00:42:20] 每个agent都有一个自己的开发计算机 [00:42:24] A这有个自己的开发计算机 [00:42:25] 那就你就把single-threaded的人类和agent [00:42:29] 就做一个严格一一对应的类比 [00:42:31] 你就让它有一个独立的电脑 [00:42:33] 可能是个容器 [00:42:34] 然后你就把它放到什么git点NJU [00:42:37] 点EDU点CN上 [00:42:38] 然后你就跟你就直接instruct agent [00:42:40] 说好 [00:42:40] 我的这个remote仓库是在git的 [00:42:43] 你现在就是一个单人开发者 [00:42:45] 然后你现在可以从tmux里面收到命令 [00:42:50] 然后如果你收到命令就可以开干 [00:42:53] 所以这件事情其实是其实是非常容易实现的 [00:42:57] 比如说啊比如说fancy project [00:43:02] 好U [00:43:08] 我可以这样 [00:43:15] 嘶啊这样也可以 [00:43:23] 好我就直接让agent在开干 [00:43:26] 然后我现在就是就agent时代有点什么好 [00:43:32] 每个人都是领导 [00:43:34] 你就是这个领导好 [00:43:38] 工头 [00:43:38] 然后现在有两个tmux session [00:43:44] 你可以想象就是 [00:43:45] 我实际在你们实际开发的时候 [00:43:48] 这两个tmux session都是位于两台不同的机器 [00:43:50] 或者不同的容器 [00:43:51] 他物理上隔离开的 [00:43:52] 他看不到 [00:43:52] 看不到世界上面其他其其他的人 [00:44:01] 还故故意用一个这个可能在中国现在还能用的 [00:44:04] 用的词 [00:44:05] Master [00:44:06] 然后我现在就是就是master [00:44:09] 好 [00:44:10] 哎你看你这个名字改过来了 [00:44:12] slave [00:44:12] 好好 [00:44:15] 好我可以给他每一个都起一个派 [00:44:20] 哎好 [00:44:26] 啊coding agent好 [00:44:29] 那我可以让他干什么 [00:44:48] Okay [00:44:49] It doesn't matter [00:44:52] Uh [00:44:58] 啊你看他们两个就开始工作了 [00:45:01] 开始工作了 [00:45:02] 好好他们 [00:45:06] 啊这个A [00:45:15] 我让我让他 [00:45:16] 所以你看当AI agent变快的时候 [00:45:21] 这个好他开始写斯拉夫克的 [00:45:30] 当当AI开始变快的时候 [00:45:32] 你想一想 [00:45:36] 如果你的指挥发生一点点差错 [00:45:39] 或者哪怕甚就甚至指挥 [00:45:41] 就是就现在一个流行的paradigm [00:45:43] 就是你有一个监工的agent [00:45:45] 然后你有好多个这个subagent [00:45:47] 有些比如说 [00:45:50] 比如说为了最大化模型的智力 [00:45:53] 防止AI生成你不想要的东西 [00:45:56] 你会放两个比较强的模型 [00:45:58] 比如说由这个codex来设计 [00:46:00] 然后让Claude来review [00:46:02] 然后让他们互相打架 [00:46:03] 然后达成达成一致 [00:46:04] 你只要开两个tmux就行了 [00:46:06] 然后你的主座位呢就负责协调 [00:46:09] 就观看他们的输出和或者总结报告 [00:46:12] 然后往里面inject prompt [00:46:14] 然后这个一个多agent就这样转起来了 [00:46:20] 然后我看一下这个repo status [00:46:29] 哎然后你就发现 [00:46:31] 如果大家工作在同一个git仓库上 [00:46:34] 就会有一些麻烦 [00:46:36] 但如果他们工作在不同的repo上 [00:46:37] 就是完全完全可以的 [00:46:40] 他们可以合到 [00:46:41] 他们可以合去远端拉取别人的提交 [00:46:45] 然后冲突了 [00:46:46] 如果冲突了就会自己修复 [00:46:48] 然后在必要的时候 [00:46:49] 他甚至还可以给这个master agent [00:46:52] 发消息 [00:46:53] 你们立即就可以构建出一个这样多agent的系统 [00:46:58] 那么相应的这个我们今天也有一些work around的 [00:47:02] 比如说git就有worktree这样的功能 [00:47:05] 所以所以你看我可以问他 [00:47:08] 我的老师说 [00:47:10] git worktree可以改进这样并行的啊工作方式 [00:47:15] 那么能为让这两个tmux sessions都工 [00:47:22] 都工作在worktree 上吗 [00:47:28] 提问其实是关键的 [00:47:30] 你们可以在各种信息 [00:47:32] 就你们甚至比如说你今天早上走到教室的时候 [00:47:35] 在看微信公众号 [00:47:37] 然后这个微信公众号上面说来也git worktree [00:47:39] 或者他提了一个什么样的sandbox container [00:47:42] 你就可以立即让agent来帮你帮你试一试 [00:47:46] 然后我来看一看他在做什么 [00:47:53] 诶这不是一个相对来说比较容易的任务吗 [00:47:57] OK他确实是在写 [00:48:00] 写脚本哎 [00:48:01] 你看他把pad退出来了 [00:48:05] 哦应该OK了 [00:48:24] 这是当前的 [00:48:28] git worktree [00:48:29] 我们的git允许我们创建一个工作树 [00:48:33] 然后这个工作树就是一个 [00:48:35] 你可以想象成就是连接到了一个remote [00:48:38] 就是一个git repo [00:48:39] 然后我可以在这里面做独立的提交 [00:48:42] 在一个隔离的环境里面做独立的提交 [00:48:44] 然后大家都知道点git是什么 [00:48:46] .git是一个目录 [00:48:49] 点git [00:48:50] 比如说我现在我的JS1 [00:49:03] 大家都知道我的.git的是一个目录 [00:49:05] 然后他有里面有一些 [00:49:06] 比如说啊这个logs [00:49:10] 还有objects [00:49:11] 三种类型的对象 [00:49:13] 那worktree里面的.git的是什么 [00:49:18] 点开就是一个普通的文件 [00:49:23] 是一个文本文件 [00:49:26] 然后你如果如果你继续追问agent的话 [00:49:30] agent会告诉你 [00:49:31] 这个也是我才知道的 [00:49:32] 就是除了git [00:49:35] 除了点git [00:49:36] 除了是可以是一个目录以外 [00:49:39] 它还可以是一个这样的 [00:49:41] 只有只有这个格式的文件 [00:49:44] 然后这个文件说gitdir: [00:49:46] 然后好 [00:49:47] 你看它指向了一个worktrees [00:49:49] 然后这个是什么 [00:49:50] 这就是文件系统里面的一个啊文件 [00:49:54] 所以你看到 [00:49:55] git [00:49:56] 最大程度上 [00:50:03] git最大程度上复用了操作系统里面的机制 [00:50:07] 这个tree就是一个这样的 [00:50:10] 它是一个小型的git目录 [00:50:13] 他是个小型的点 [00:50:15] git它依然有是head index locks这些 [00:50:18] 一个微型的git的目录 [00:50:20] 但是它还是依附于原有的那个git目录 [00:50:24] 而而而生的这样一个一个一个特性 [00:50:28] 这个特性就在AI时代突然间变得诶好像 [00:50:34] 有点有用 [00:50:34] 我们可以在在这个提交 [00:50:37] 直接在本地互相可见 [00:50:39] 不需要互相的pull和push [00:50:40] 就如果你像刚才我说的 [00:50:42] 我开了好几台虚拟机 [00:50:43] 然后在每台虚拟机里面放一个agent [00:50:45] 然后我直接往那个tmux里面注入 [00:50:47] 那当然是可以的 [00:50:49] 这是完全可以完成的 [00:50:50] 但是worktree提供了一个更轻量的这个 [00:50:54] 合作的合作的方式 [00:50:55] 但是但是就是如果有比如说有冲突的修改 [00:50:59] 它仍然需要merge和REBASE才能才能合 [00:51:01] 才能合并 [00:51:02] 这样啊性能性 [00:51:04] 性能会更高一点好那我们回到这个agent team [00:51:09] 如果我们有agent team或者agent [00:51:11] Swarm [00:51:12] 除了今天的workaround [00:51:13] 比如说worktree这样的机制以外 [00:51:17] 还要回头来想 [00:51:18] 为什么我们需要版本控制 [00:51:20] 为什么需要版本管理 [00:51:23] 也就是说我们人类的限制 [00:51:25] 就是人类对这个 [00:51:27] 就我刚才说10分钟 [00:51:29] 一个小的team [00:51:30] 哪怕是一个团队都要10分钟产生一个一个commit [00:51:35] 所以是因为人的限制塑造了这个这个工具 [00:51:38] 人之间的这个communication [00:51:42] 导致了你每天早上都要开一次会议 [00:51:45] 同步一下各各个人的进展 [00:51:47] 然后再把这个任务给分下去 [00:51:48] 而而且就算是人做了这样的沟通 [00:51:52] 你也都知道 [00:51:53] 你有的时候你想就你的你的室友 [00:51:57] 向你请教一个数学问题 [00:51:58] 明明你会做 [00:52:00] 你就怎么都没办法给他讲明白 [00:52:03] 你除非你是一个很好的老师 [00:52:04] 能够共情别人就共情 [00:52:07] 别人在哪里会能站站在别人的角度去思考 [00:52:11] 就是沟通的成本就是很高的 [00:52:13] 所以也是大厂和小厂对 [00:52:16] 尤其是初创初创公司 [00:52:17] 初创团队为什么效率可以更高 [00:52:19] 就是当软件系统大了以后 [00:52:21] 人多了以后 [00:52:21] 他沟通的效率变低了以后 [00:52:24] 它产出的速度也就也就降下来了 [00:52:27] 所以可能你一个100个人的团队 [00:52:30] 他不可能达到一个十人团队效率的十十倍 [00:52:34] 可能有两倍 [00:52:35] 三倍就已经就已经挺挺不错了 [00:52:37] 所以团队没有办法变大 [00:52:39] 没有办法变大 [00:52:40] 所以我们需要git的各种各样的best practice [00:52:43] 快照 [00:52:45] 快照 [00:52:45] 然后小步的前进 [00:52:47] 你改一个title也要做一个commit [00:52:49] 然后你做一个什么也要一个commit [00:52:51] 一个commit [00:52:51] 然后都可以 [00:52:52] 然后这些小的commit每个都可以追溯 [00:52:54] 因为一旦出问题了以后 [00:52:56] 你需要回溯到那个人做事commit那个时间 [00:53:00] 然后然后那个人是有记忆的 [00:53:02] 开发者会回想起来 [00:53:04] 那天我们当天早上开了一个会 [00:53:07] 然后我收到要做这个需求 [00:53:08] 然后呢做这个需求时候沟通发生了一个问题 [00:53:10] 大家找到那个时候的沟通记录文档 [00:53:12] 然后再说 [00:53:13] 我们这个地方应该应该怎么修正 [00:53:15] 所以你看有了git bisect的 [00:53:16] git blame这些 [00:53:18] 专门为人来这个设计的特性 [00:53:22] 但是你想一想 [00:53:24] 如果是由agent team或者agent swarm来实现你的项目 [00:53:28] 我们还需要git blame吗 [00:53:32] 就是因为人可以blame [00:53:34] 就是你这个事情我blame你多了 [00:53:36] 你就该被开掉了 [00:53:38] 实习生你就背锅了 [00:53:41] 但如果agent没有坐牢的 [00:53:43] 被坐牢的 [00:53:44] 被开除的能力的时候 [00:53:48] 这个这个模型就变了 [00:53:50] 我们再也不需要blame了 [00:53:51] 我们的项目只要前进就可以了 [00:53:55] 然后我们前进 [00:53:56] 有的时候也不需要知道到底是哪一个 [00:53:58] 提交引入这个错误 [00:53:59] 我只要知道这个地方错了 [00:54:01] 我也不要再也不要管他 [00:54:02] 历史上是怎么造成这个错误的 [00:54:04] 我只要把这个错误修了就行了 [00:54:06] 因为agent之间的communication [00:54:09] 而且尤其尤其现在更好玩的是 [00:54:11] 我们的每个agent都是相同的模型 [00:54:14] 这也就是说它们是完全相同的克隆体 [00:54:17] 同一个事情让他们来做 [00:54:19] 他们大概率会收敛到 [00:54:20] 就虽然模型还是有不确定性 [00:54:23] 还是会收敛到相同的结果 [00:54:25] 同样的prompt做同一件事 [00:54:27] 可能有点细微的差别 [00:54:28] 但是最终的那个方向性的东西 [00:54:30] 可能收敛到相同的结果 [00:54:32] 所以我们再也不要blame了 [00:54:34] 那我们的git永远就是一个 [00:54:36] 就或者说我们的项目 [00:54:37] 就永远就是一个向前进的过程 [00:54:39] 每次哈我现在在就快照肯定还是需要的 [00:54:42] 因为因比如说这个方向走错了 [00:54:44] 我们 [00:54:45] 你如果没有保留历史的上的某一个snapshot [00:54:49] 那一下子往前走了好多以后再回去 [00:54:51] 可能他的代价比你一点一点在再往前修 [00:54:55] 要修要好 [00:54:55] 所以保留快照肯定还是还是需要的 [00:54:58] 那我们就是不断的大步向前 [00:55:00] 也永远几乎永远不要看过去 [00:55:03] git的这个committer里面只是留了一些lessons [00:55:06] 或者我们大部 [00:55:07] 我们这个项目到底经历了什么样的 [00:55:09] 什么样的演化 [00:55:10] 然后不停的就往前走 [00:55:11] 往前走往前走 [00:55:12] 合并 [00:55:13] 合并合并合并 [00:55:14] 所以就说历史的价值可以从谁写错了 [00:55:18] 变成我怎么把它修好 [00:55:20] 只要保存 [00:55:21] 我只要能知道我从现在开始怎么样能够往前进 [00:55:24] 往前进这件事情就可以了 [00:55:26] 所以你再想再想 [00:55:28] 这个时候 [00:55:29] 你在计算机学科学到的那些知识又起作用了 [00:55:34] 我又回到讲操作系统的时候 [00:55:36] 讲并发 [00:55:36] 讲并发 [00:55:37] 那数据库就是就现在的这个git的模型 [00:55:43] 更像是数据库里面的并发控制 [00:55:46] 也就比如说我们有两条SQL [00:55:50] 然后这个SQL它都是一个transaction [00:55:54] 它是一个很大的SQL [00:55:57] 都是一个很大的传 [00:55:58] 在坑中间可以混任何代码 [00:56:00] 然后你可以先比如说你先一个select select一个什么 [00:56:03] 你先读一下 [00:56:04] 那我这里也可以select select [00:56:08] 然后那我先读完以后 [00:56:09] 我可以做代码的计算 [00:56:12] 比如说我就是Python代码或JAVASCRIPT代码 [00:56:15] 然后这个代码是图灵完备的 [00:56:16] 你永远不知道他会根据我看到的结果算出什么 [00:56:19] 我甚至也可以从外面 [00:56:20] 比如说根据我当前的时间再算一个什么东西 [00:56:22] 然后算完以后我再update [00:56:27] Update [00:56:28] 然后update的时候就会产生冲突 [00:56:30] 这也就是说这个就可能产生死锁 [00:56:32] 也可能产生冲突 [00:56:33] 就是说这个update可能可能 [00:56:36] 这个这个如果这个update读它 [00:56:38] 这个update要读它 [00:56:40] 那就会产生一个循环依赖 [00:56:43] 有可能是产生这种数据的依赖 [00:56:45] 也可能是产生就是我要锁你 [00:56:48] 我要锁你的对象 [00:56:49] 你要锁我对象产生死锁 [00:56:50] 然后这个时候就会导致这个transaction 的abort [00:56:53] 可能比如说这个transaction SQL [00:56:56] 说这个就不能进行下去了 [00:56:57] 对不起 [00:56:58] 因为我检测到一个循环的依赖 [00:57:00] 所以对不起我 [00:57:01] 我这个这个就不能做了 [00:57:03] 我要回滚 [00:57:04] 相当于他要roll back [00:57:05] Roll back [00:57:06] 然后其实git的模型有一点 [00:57:09] 像这种这种乐观的并发控制 [00:57:11] Of of of mist optimistic [00:57:13] 为什么他是乐观的 [00:57:15] 他就说我假设这两个transaction不会冲突 [00:57:19] 我在执行的时候 [00:57:20] 我会假设厂家是不会冲突 [00:57:22] 这个假设在数据库系统当中是大概率是成立的 [00:57:25] 为什么 [00:57:26] 我们想教务系统 [00:57:28] 你们每一个同学他读的都是你读 [00:57:33] 写的都是你自己那块数据 [00:57:36] 你就说我选课选的是我的课 [00:57:38] 我查看课表 [00:57:39] 查看的是我的课表 [00:57:40] 那所以所以说这个一个全局的这个冲突 [00:57:44] 是不太可能有的 [00:57:45] 我两个同学哪怕同时开始选课 [00:57:47] 我也是读我的 [00:57:48] 写我的这两个就可以就过学知道 [00:57:51] 哦mistake的 [00:57:54] 那of of git也是这样 [00:57:56] 就说我假设这个我这样开发 [00:57:59] 我们已经事先开过会了 [00:58:00] 今天早上开过会了 [00:58:01] 所以我可以顺着这条路先做这个 [00:58:03] 另一个人做这个 [00:58:04] 然后我合并的时候大概率不会产生冲突 [00:58:06] 不管是merge也好 [00:58:07] 还是REBASE也好 [00:58:08] 这个都能都能顺利的顺利的完成 [00:58:12] 但是但是啊这就这是这是就古法编程时代的 [00:58:19] 就像我用SQL来做一个比方 [00:58:21] 但是如果我们agent的快了1000倍 [00:58:25] agent的快了1000倍 [00:58:26] 那如果我们的这个主 agent呢又没有 [00:58:32] 可能协调的时候就一下子又分了好多任务出去 [00:58:35] 他们就真的有可能会更频繁的触发这个 [00:58:40] transaction的abort [00:58:41] 然后触发这种abort在AI时代也不是什么大问题 [00:58:46] 就是agent的 [00:58:47] 反正出错了 [00:58:47] 或者出了conflict [00:58:49] 他就修 [00:58:49] 他能修好 [00:58:51] 但是不是在agent的时代 [00:58:53] 我们可以换一种并发控制的方式 [00:58:55] 你想我们在操作系统里面 [00:58:57] 这是在数据库里面做的 [00:58:59] 我们在操作系统里面学的并发控制 [00:59:01] 你们是用什么做并发控制 [00:59:03] 上锁锁和这个数据库里面的这个transaction [00:59:08] 是有点不一样的 [00:59:10] 你是你是lock一个 [00:59:13] 我上课时经常说一把大锁保平安 [00:59:17] 做实验你们就知道做过实验 [00:59:19] 你们就知道了 [00:59:22] 当我想要访问资源可能冲突的资源的时候 [00:59:26] 我会先把它锁住 [00:59:29] 说我先要acquire了一把锁 [00:59:30] 然后这把锁一旦acquire时候 [00:59:32] 别人想要再lock的时候 [00:59:34] 那对不起 [00:59:35] 这个这个上锁的就必须要等到等到快以后 [00:59:39] 一个release的快啊的关系建立起来 [00:59:42] 就必须是先一后二 [00:59:45] 而不是这种optimistic的 [00:59:46] 大家先先往前跑跑了再说 [00:59:49] 我必须是我先要知道我 [00:59:51] 我必须在使用这个资源之前 [00:59:54] 我要declare [00:59:57] 我要declare [00:59:58] 对这个资源的使用上锁的方式 [01:00:02] 所以你看这是就是只有你在这个操作系统课 [01:00:05] 数据库 [01:00:06] 数据数据库课 [01:00:07] 你真的把这些东西学会了 [01:00:09] 你回来想的时候 [01:00:10] 软件工程里面 [01:00:11] 这些概念又再做一次 [01:00:14] 所以所以想现在如果agent他的动作非常快 [01:00:19] 我们其实应该用更加偏向这种 [01:00:23] 悲观的并发控制 [01:00:25] 也就是说我今天要做什么事 [01:00:28] 或者我有个主agent [01:00:30] 我规划 [01:00:30] 然后规划完了以后 [01:00:31] 我就立马把这个项目的某一个部分给锁上 [01:00:35] 我可以把这个git [01:00:36] 就说我应该在一个git repo [01:00:39] 或者一个快照上 [01:00:40] 我支持一个锁的操作 [01:00:41] 把这些scope说好 [01:00:43] 我现在锁住了 [01:00:44] 我要我要我要我现在做一件事 [01:00:46] 需要这些他先上锁 [01:00:48] 然后上锁以后做完以后commit [01:00:50] 然后另外一边也可以上锁 [01:00:53] 但是如果一旦他想要干的事情 [01:00:55] 被另外一一个人锁上了 [01:00:57] 他就必须等到这个锁前面人释放了 [01:01:00] 他才能才能才能再上锁 [01:01:03] 这样不就几乎避免了所有的冲突 [01:01:05] 在文就比如说打个比方 [01:01:06] 我可以在文件级上锁 [01:01:09] 我就避免了两个agent它会同时写同一个测试 [01:01:13] 往同一个 [01:01:13] 比如说测试或者一个配置里面里面做更改 [01:01:16] 然后但是又因为agent数量足够多 [01:01:19] 这个速度足够快 [01:01:21] 我还是可以保证整体项目的进度可以往前推 [01:01:23] 因为也许还有别的agent可以继续运行 [01:01:26] 这也就跟操作系统里面 [01:01:28] 我们其实现并发程序 [01:01:29] 我经常说 [01:01:32] 如果你一把大锁保平安了 [01:01:34] 或者你哪怕是锁锁拆拆桥了 [01:01:37] 我们互斥锁 [01:01:38] 它的本质是不要并行 [01:01:42] 不要并发 [01:01:43] 他和这个多处理器并行是根有根本矛盾的 [01:01:46] 他不就要把一个并行能并发的程序退回 [01:01:49] 退回一个串行程序 [01:01:51] 但是当这个系统里面有好多独立的 [01:01:54] 不冲突的线程在运行的时候 [01:01:56] 我即便每一个线程都持有了一把锁 [01:01:58] 他还是可以继续高效的 [01:02:00] 即便是悲观的 [01:02:01] 他依然可以是 [01:02:03] 可以是高效的 [01:02:04] 就是这些知识关联关联起来让你看清楚 [01:02:07] 可能 [01:02:08] 我觉得在agent的时代 [01:02:10] 我们又可以重新设计一个版本控制的系统 [01:02:13] 所以我觉得这就在在agent时代 [01:02:15] 软件工程肯定是要发生很大的变化的 [01:02:18] 你从这first principle出发 [01:02:19] 我们要管理快照 [01:02:20] 我们要管理版本 [01:02:21] 我们要管理change [01:02:22] 我们还要管理飞快的change [01:02:26] 那答案是什么 [01:02:27] 可能 [01:02:28] git可能是一条线 [01:02:30] 如果我们用一种像这样的方式来管理软件 [01:02:32] 那可能又是另外啊另外一条线 [01:02:36] 所以你发现这个学操作系统 [01:02:38] 学数据库这些东西有用 [01:02:40] 你还是虽然痛苦 [01:02:42] 你怀怀疑在AI时代我学这种东西 [01:02:44] AI都会写了数据库 [01:02:46] 这个是SQL 查询 [01:02:48] 我早就早就不写任何SQL查询了 [01:02:51] 那我们还有没有可能学数据库是有用的 [01:02:56] 答案是有用的 [01:02:57] 你还是去好好学习 [01:02:59] 当然数据库里面也有这种advisory lock这样的 [01:03:02] 这个机制也是为什么我喜欢上课的原因 [01:03:06] 就是我如果我不来上操作系统课 [01:03:10] 我不上这个生成式软件工程课 [01:03:12] 可能就不会让我去对 [01:03:14] 我在备课的时候会把这些事情在脑袋里面 [01:03:17] 再过一遍 [01:03:18] 是不是地球上所有人都错了 [01:03:20] 因为因为我要讲给你们的时候 [01:03:22] 我必须要共情 [01:03:23] 我的听众要考虑到你们是一个 [01:03:26] 只能只能接受这个比较平实朴实逻辑的 [01:03:30] 听众不能直接就说哎 [01:03:31] 这个什么事故系统是怎么设计的等的 [01:03:33] 我必须要把那个那个最顶层的idea啊提炼出来 [01:03:38] 然后试图让大家共情 [01:03:40] 当然这可能我做的也不够好 [01:03:41] 这个哼你们可以在AI的帮助下 [01:03:44] 再来再来重新理解一下 [01:03:48] OK好 [01:03:52] 版本控制 [01:03:53] 那版本管理 [01:03:53] 基本上其实我就我就我就讲完了 [01:03:55] 从历史动机到过去git讲到现在 [01:04:01] 这次再讲到未来可能发生的事情 [01:04:04] 但是但是版本控制本质上还是一个工具 [01:04:07] 不管 [01:04:08] 哪怕是我刚才那种 [01:04:09] 比如说基于乐一种乐观或者悲观锁的版本控制 [01:04:12] 真正困难的实际上是在进度 [01:04:16] 也就是团队的管理 [01:04:20] 我们为什么现在觉得还需要软件工程 [01:04:23] 就是因为我们现在没有办法做到一句话 [01:04:26] 就直出一个高质量的产品 [01:04:28] 如果斩杀线到了到了这个就老板 [01:04:31] 老板有一个想法就说 [01:04:35] 就说我要做一个agent用的微信 [01:04:40] 我随随口说一说一个 [01:04:42] 或者说做一个AI时代的微信 [01:04:44] 然后这个微信是一个社交爆款 [01:04:46] 然后以后以后这些人社交 [01:04:48] 可能也就不要用微信了 [01:04:49] 就用我 [01:04:50] 当然你可能有个更具体的想法 [01:04:52] 比如说为什么你有一些思考 [01:04:54] 然后如果这时候AI直接就能出那个 [01:04:57] 微信级的产品 [01:04:58] 那软件工程就已经死了 [01:04:59] 那我们就都死了 [01:05:02] 但是呢现在这个斩杀线暂时还没有到 [01:05:05] 所以至少没有到这个团队管理 [01:05:09] 这一层面 [01:05:12] 所以我们可能还要学 [01:05:17] 但是我觉得可能也许有一天 [01:05:21] 真的我也要被拆掉 [01:05:23] 因为摩尔定律本质上也是用scaling law它 [01:05:26] 它现在还是成立的 [01:05:28] 模型 [01:05:28] 肯定会更强更小更快 [01:05:30] 然后也许算力就有一天能够唤出我们的我 [01:05:36] 我们的智能 [01:05:37] 但今天至少AI还不知道怎么做团队的管理 [01:05:42] 因为每当你多一个人的时候 [01:05:44] 这个沟通的关系都是平方级的上升的 [01:05:48] 因此现在软件工程团队里面 [01:05:51] 最难招的其实不是码农 [01:05:53] 是那个能把任务分解的那个team leader [01:05:58] 也就最难招的是那种 [01:06:01] 能把那种国民级的应用的那种 [01:06:03] 他说我要我要去造一个微信 [01:06:05] 然后那个微信他还能够分出对 [01:06:08] 我就一个100人的团队 [01:06:09] 能分出十个小团队 [01:06:11] 然后十个人十个team leader干 [01:06:13] 最后加起来我拼起来还能成为一个一个团队 [01:06:16] 这个人人最稀缺 [01:06:17] 然后接下来那个能够带领小团队的人 [01:06:20] 其实也很也很稀缺 [01:06:22] 这个人月神话里面那里面就是人之人 [01:06:25] 人之间两两之间就是平方级的沟通沟通关系 [01:06:31] 然后就算是你能把你份内的事情做好 [01:06:36] 就因为这个平方级的沟通关系 [01:06:37] 别人也在做他的事 [01:06:39] 你不百分之百知道别人在做什么事的时候 [01:06:41] 或者你对这个整体的团队了解不是很好的时候 [01:06:46] 你还是就这样 [01:06:47] 最后就会各种冲突 [01:06:49] 然后你写的测试我过不了 [01:06:51] 就经常会发生 [01:06:53] 发生发生这样的事情 [01:06:55] 那么如果我们想要管一个团队的话 [01:07:04] 或者说你们在今天在想要在毕业的时候 [01:07:08] 能够具有一定的团队管理能力 [01:07:10] 你现在就可以当成是那个主agent的 [01:07:13] 就像我刚才那样 [01:07:14] 刚刚才当然刚才我给了一个不好的示范 [01:07:17] 我说我说我今天创了两个slave [01:07:19] 你现你现在 [01:07:20] 你现在也可以立即拥有这个 [01:07:22] DeepSeek V4的这个slave [01:07:24] 然后然后你可以去想 [01:07:26] 如果你要尽可能最大化两个或者 [01:07:29] 三个或者更多agent [01:07:30] 你应该怎么把这个任务给分解 [01:07:36] 然后你应该怎么样确定一个提交的策略 [01:07:41] 什么时候你的agent应该提交 [01:07:43] 什么时候他应该合并 [01:07:45] 然后你就可以把刚才我们讲的 [01:07:48] 所有的版本控制的概念带到你的开发流程里 [01:07:51] 所以重要是这句话 [01:07:54] 版本控制是工具 [01:07:56] 它是由蒸馏了人类过去软件工程很多年的经验 [01:08:02] 得到的是我们要人类要这样开发 [01:08:05] 然后在这个工具上 [01:08:06] 你可以开发出属于你自己的 [01:08:08] 软件工程的直觉和经验啊来做 [01:08:13] 然后这里面就有好多比如说学东西还是有用的 [01:08:15] 一些意外 [01:08:18] 除了比如说我 [01:08:19] 我可能后面后面再讲 [01:08:20] 怎么怎么来做这个软件管理 [01:08:25] 最近我看到一个蛮有意思的题目 [01:08:29] 啊大概就是这样的 [01:08:31] 这样的我又带了这个模型 [01:08:33] 但淘宝好脑游很喜欢的 [01:08:35] 淘宝好友好多游 [01:08:36] 作为一个面试题 [01:08:38] 这好像是应该是 [01:08:41] 因为我不知道为什么就在网上刷到了 [01:08:43] 是小一般是小学生考级的题目 [01:08:46] 汉诺塔都会低V的 [01:08:49] 会好会现有个额外的要求 [01:08:52] 就是你的所有的盘子的移动只能往一个方向 [01:08:56] 就比如说我现在我现在两简单一点 [01:08:59] 两两个盘子 [01:08:59] 两个盘子 [01:09:00] 我现在移移过来 [01:09:03] 这个方向移是可以的 [01:09:05] 是可以的 [01:09:07] 这个方向移是可以的 [01:09:10] 这个方向移也是可以的 [01:09:13] 这个方向移也是可以的 [01:09:14] 就是我要啧往只能往一个方向移动 [01:09:19] 当然折过折过来就折回去 [01:09:21] 我不允许的事 [01:09:23] 就是你三个盘子的时候 [01:09:24] 你就能看出 [01:09:26] 哦三个盘子的时候就可以看出问题了 [01:09:29] 如果我要移三个盘子的话 [01:09:31] 我希望的是先把两个移到中间 [01:09:36] 假设两个已经移到中间了 [01:09:38] 那这时候这时候我下一个就是从 [01:09:40] 把这个盘子从这里移到这里就对了 [01:09:43] 这是汉诺塔的正常的移法 [01:09:46] 但是在这个限制下 [01:09:48] 你是做不到的 [01:09:51] 在这个限制下 [01:09:52] 你不能把它移到这儿 [01:09:54] 就你只能往一个方向 [01:09:55] 比如说往那个方向方向移动好 [01:09:58] 你很难想象小学生要做这样的题 [01:10:01] 然后他要输出这个真想 [01:10:04] 如果现在是你们 [01:10:05] 你们就在保研的这个机制或者是 [01:10:10] 保研机制就是小学生难度 [01:10:12] 这个你就碰到这个题了 [01:10:15] 你要输出方案或者输出这个数数字 [01:10:19] 反正N也不是很大 [01:10:20] 但是你确实需要一个额 [01:10:23] 需要一个方需要理解这个问题 [01:10:26] 诶 [01:10:31] 那当然我 [01:10:32] 我讲的不是这个这个汉诺塔的故事 [01:10:34] 我讲的不是这个汉诺塔的故事 [01:10:35] 这个这个汉诺塔的故事是 [01:10:37] 你递归的时候 [01:10:40] 你现在要把它移过来 [01:10:42] 你为了移过来 [01:10:44] 你只能你还是先还是一样的 [01:10:47] 你先要把它移到这个 [01:10:51] 你需要的是先把它移到这里 [01:10:53] 然后让这个最大的盘子向右移一个 [01:10:56] 然后再把它移到这里 [01:10:59] 再让向右的盘子移到这 [01:11:01] 再把它移到这里 [01:11:04] 所以就相当于是你考虑这个考虑最大的盘子 [01:11:08] 那个最优解 [01:11:09] 他考虑最大的盘子总是向右移一个 [01:11:12] 再向右右移一个的好 [01:11:15] 那当然我这个拆开拆开来讲 [01:11:17] 是因为 [01:11:21] 我能用这个吗 [01:11:22] 在这 [01:11:25] 我准备了一个小例子 [01:11:38] 我准备这个例子 [01:11:40] 我写了一个啊这样的这个程序好 [01:11:45] 没问题 [01:11:46] 就他就是就是我刚才说的说的那个 [01:11:48] 就是我得把 [01:11:50] 如果我的下一个目标不是目标的话 [01:11:53] 我只有最大的盘子 [01:11:54] 我总是向右移一个 [01:11:56] 再向右移一个 [01:11:56] 所以它是它是最优的 [01:11:58] 就是我最大的盘子的那个移动是最最最少的 [01:12:02] 最就是这是不可避免的 [01:12:04] 然后剩下的也就基于inductive就归纳法 [01:12:09] 我这个也是也是也是也是最优的 [01:12:11] 有点难 [01:12:12] 你很难想象小学生那样可以做这样的题 [01:12:15] 但这不重要 [01:12:16] 重要的是我们现在要推出这个产品 [01:12:21] 比如说我现在要把这个东西卖给小学生 [01:12:24] 那我怎我 [01:12:25] 我怎么样才能最好的把这个产品卖给小学生 [01:12:28] 当然是提供付费的增值服务 [01:12:31] 比如说这个小学生在这个 [01:12:35] 他可以在这里写代码 [01:12:37] 我这个代码是可以可以随时编辑的 [01:12:39] 比如说我可以再写一个 [01:12:41] 他就错了对 [01:12:43] 我的可视化是随随代码来运动的 [01:12:48] 比如说错了 [01:12:48] 他就我就可以找到 [01:12:50] 比如说对找到找到我这条语句 [01:12:55] 试图把一个蓝色的移到就小的 [01:12:58] 移到啊移到大的上 [01:12:59] 然后然后同学们就能找到bug [01:13:01] 那如果我要挣钱的话 [01:13:03] 我要提供增值服务 [01:13:05] 就现在现在还只是一个就是就是一个纯粹的你 [01:13:11] 你可以这个playground [01:13:12] 然后你可以可以可以写代码 [01:13:14] 然后可以可以可以运行它 [01:13:16] 然后到这个时候我就要提供一个AI助教 [01:13:20] 比如说这个小朋友 [01:13:22] 当然这个是不是不太好 [01:13:23] 这个开玩笑的 [01:13:25] 这个我们还是尽可能以一个便宜的成本 [01:13:27] 提供给小朋友们 [01:13:29] 这个 [01:13:32] 当你实在做不下去的时候 [01:13:35] 你就可以点一个这个叫我要助教 [01:13:38] 然后这个时候DeepSeek的token就开始燃烧 [01:13:41] 然后这样我可以收取 [01:13:42] 比你比这个DeepSeek原价更贵的token费 [01:13:46] 然后然后记在你的你的你的账户上 [01:13:50] 这样 [01:13:50] 然后因为因为我的prompt是我独门的 [01:13:53] 我作为一个有经验的老教师 [01:13:55] 我可以把我自己蒸馏成prompt [01:13:57] 然后然后然后然后我可以敏锐的知道 [01:13:59] 这个小朋友的问题在哪里 [01:14:01] 然后给他提供一个个性化的指导 [01:14:05] 我就这个时候我就涉及到要做一个信息系统了 [01:14:09] 要做一个信息系统 [01:14:10] 那做这个信息系统 [01:14:13] 因因为我有我 [01:14:15] 我让学生来做这个事 [01:14:17] 我自己没有时间 [01:14:18] 我竟然有这么大的这个市场的钱 [01:14:21] 我竟然都不想挣这个 [01:14:23] 然后然后学生学生在设计 [01:14:25] 然后我看了那个学生和AI聊完那一版设计 [01:14:27] 然后我也让那个GPT 也 [01:14:30] 来 [01:14:30] 就是大概梳理了一下下需求 [01:14:33] 这个是GP的 [01:14:34] 原话他说叫一个API应用 [01:14:36] 一个关系数据库 [01:14:37] 一个对象存储 [01:14:38] 然后需要异步点点评时再加后台任务进程 [01:14:42] 数据库关系和记录 [01:14:44] 大课程包与完整轨迹存放对象存储 [01:14:47] 任务量小时 [01:14:48] 数据库任务表就够用 [01:14:49] 这是一个非常正常的 [01:14:51] 就是就如果如果是你们上软件工程课 [01:14:54] 那太正常了 [01:14:55] 你看GPT [01:14:56] 它是一个语言模型 [01:14:58] 但我不喜欢这个设计 [01:15:02] 我不喜欢这个设计 [01:15:03] 为什么 [01:15:04] 因为 [01:15:08] 我不知道你们有没有用过overleaf [01:15:09] 就跟别人协作过文档 [01:15:12] 然后Overleaf是有一个功能的 [01:15:14] 它可以把它当成是一个git repo导出 [01:15:17] 然后你可以直接这个时候我最喜欢这个功能 [01:15:21] 是因为我要给学生改论文 [01:15:22] 然后给学生改论文 [01:15:24] 我就可以直接agent启动 [01:15:26] 就我可以把那个那个论文克隆到本地 [01:15:28] 我就不需要忍受那个网页界面了 [01:15:31] 然后我就可以打开我的codex [01:15:33] 然后让codex去帮我帮我直接起subagent的 [01:15:37] 给每一个给每一个.tex 文件都去修复 [01:15:41] 里面的这个语法错误 [01:15:42] 我可以我可以给一个这个我很长的prompt [01:15:44] 让它让他遵循质量论文就改好了 [01:15:46] 我说学生好文化结束了 [01:15:47] 这个改也已经改好改好了 [01:15:50] 然后我们说这个playground [01:15:52] 我可以 [01:15:53] 我难道不是应该我在我的学生每改改一次 [01:15:58] 对 [01:15:59] 比如说OK我不知道这样行不行 [01:16:06] 可以这个我难道不是学生每改一次 [01:16:10] 比如说我现在edit 了 [01:16:12] 或者我点运行了 [01:16:13] 或者我切换了 [01:16:14] 我就自动做一个git提交 [01:16:18] 然后我就可以把AI的点评 [01:16:20] 比如说当我申请AI助教的时候 [01:16:23] 他转圈圈 [01:16:23] 我就可以在这个git提交上面产生一个分叉 [01:16:29] 这是一个一个comment [01:16:33] 咳ChatGPT没有算的是 [01:16:35] 我产生一个这个东西的成本 [01:16:38] 远远大于把这个把剩下的东西 [01:16:41] persist下来的成本 [01:16:44] 就这个成本是忽略不计的 [01:16:46] 而而当我用这个数据库的时候 [01:16:49] 我确实得到了一些好处 [01:16:50] 比如说总体压缩的可能更小了 [01:16:52] 效性能更高了 [01:16:53] 但是这其实其实不是我要的 [01:16:57] 因为我的本质 [01:16:58] 我的需求是版本管理 [01:17:02] 所以我甚至就在最早期的时候 [01:17:05] 甚至最早期的时候 [01:17:06] 我可以把我的代码库和这个东西连在一起 [01:17:09] 连连在一起的来关系 [01:17:10] 就把它放在我的代码库里 [01:17:12] 然后直到我 [01:17:13] 就是我的代码库 [01:17:19] 就我的我的小朋友的代码 [01:17:22] 就直接存在我的代码库里 [01:17:24] 然后我可以把探索性的在这上面创建 [01:17:27] git的历史记录 [01:17:28] 然后直到我认为整个的比如说文件目录的格式 [01:17:32] commit message的格式 [01:17:34] 然后我怎么样使用这些文件都收敛了 [01:17:37] 然后我再把它迁移到数据库 [01:17:39] 这都是 [01:17:40] 这都是可以的 [01:17:41] 我觉得这个就还是挺好玩的 [01:17:44] 你们学任何东西都是有用的 [01:17:46] 你学git [01:17:47] 是有用的 [01:17:47] 你学这个mod agent的管理 [01:17:50] 你会 [01:17:51] 你就能够有一个机会去想到 [01:17:54] 一个和别人不一样的不太一样的设计诶我的 [01:18:05] 好在这里 [01:18:06] 还有一个好 [01:18:07] 那么接下来就是我们真的可以干一件 [01:18:14] 干一件事了 [01:18:17] 项目的早期阶段 [01:18:19] 你肯定不能用这个multi agent [01:18:22] 项目的早期阶段 [01:18:23] 你就是包工头 [01:18:27] 你先找一个应该找一个相对来说能力比较强 [01:18:30] 你能够用到的最强的agent [01:18:32] 然后你可以跟他多轮的对话 [01:18:35] 所以我要告诉大家 [01:18:37] 你们现在开始干就比什么都要好 [01:18:42] 我决定现在就开始直接 [01:18:47] 来sorry [01:18:54] 直接打开课程作业好 [01:18:59] 我不知道发生会发生什么 [01:19:01] 完全没有事先准备过 [01:19:09] 我还是要不开开两个 [01:19:15] 好额 [01:19:18] 我们有两种办法 [01:19:19] 第一种是直接 [01:19:22] 然后直接回车 [01:19:23] 这个其实我觉得对于每个同学来说 [01:19:25] 你们都可以体验体验一下 [01:19:27] 当然我今天来替大家替大家体验 [01:19:30] 我觉得更好的方式是 [01:19:49] 这是什么 [01:20:10] 我们来观察一下它 [01:20:12] 它会他会做什么 [01:20:14] 就是 [01:20:15] 有时候AI的直觉和人的直觉就有点不太一样 [01:20:19] 像如果你像一线模型 [01:20:20] 它会进入一个plan mode [01:20:22] 它会跟你再确认 [01:20:24] 可能会再确认一些事实 [01:20:25] 然后他再去会生成一个workflow [01:20:28] 然后如果你们看过比较 [01:20:29] 其实其实其实挺好玩的 [01:20:30] 比如像Claude Code [01:20:31] Claude Code [01:20:32] 它当他需要执行一个比较复杂的任务的时候 [01:20:36] 它会生成一段JAVASCRIPT [01:20:38] 一个一段typescript [01:20:39] 然后这个text script里面有一个有一个函数叫agent [01:20:44] 然后这个agent它里面是一个自然语言 [01:20:50] 当他用这种方式来组织workflow [01:20:52] 他甚至可以有循环 [01:20:53] 就是说我有好多任务 [01:20:54] 然后他可以在循环上面上面 [01:20:55] 来解决这个啊workflow [01:20:58] 然后你看到他这就直接开干了吗 [01:21:19] 用魔法对我 [01:21:21] 只能用魔法打败魔法 [01:21:22] 这个300token per second实在是太恐怖了 [01:21:31] 好OK [01:21:34] 不管了 [01:21:35] 先让他先让他搞 [01:21:38] 搞一会我 [01:21:39] 然后你发现这就是我前面上面前前面说这个 [01:21:45] 上下文工程或者提示词工程里面最危险的一点 [01:21:48] 你提示词里面的每一句 [01:21:51] 每一个词 [01:21:53] self attention都会看到它 [01:21:55] 然后看到他的时候 [01:21:57] 因为AI现在已经被训练成了prompt的舔狗 [01:22:00] 所以它有一种无可就是没有办法往外拉的倾向 [01:22:06] 需要遵循你的指令 [01:22:07] 所以当你把这个需求 [01:22:09] 尤其是这可能是一个讨论稿的需求 [01:22:11] 像我像我这是一个比较开放的需求 [01:22:13] 丢给他的时候 [01:22:14] 他会过度遵循这个指令 [01:22:16] 最终导致它会生成一个确实满足了指令 [01:22:22] 但是其实不是你想要的 [01:22:25] 就是你回头看那个实验的要求 [01:22:27] 这个实验要求其实是言外之意 [01:22:32] 其实是这一句话 [01:22:34] 叫实现一个持续为你工作的个人助手 [01:22:37] 这句话最重要 [01:22:39] 其他的话相对来说就没有那么重要 [01:22:43] 这些只是一些解读 [01:22:44] 你作为一个好的为你工作的个人助手 [01:22:48] 你觉得12345是比较比较重要的 [01:22:52] 那你们觉得就是当然这每个人都有自己的观点 [01:22:55] 对你们来说 [01:22:56] 如果你想实现一个你的个人助手什么最重要 [01:23:02] 就你实现的第一个feature是什么 [01:23:04] 你想实现什么 [01:23:09] 最大的就是你在可能一个月以内 [01:23:11] 遇到的最大的痛点问题 [01:23:13] 学习 [01:23:16] 高效的学习和复习 [01:23:18] 因为你们要卷成绩 [01:23:19] 所以这毫无疑问是最重要的一个学习排版案 [01:23:22] 你可以你可以 [01:23:23] 最好是这agent能够自动从外网上面收集数据 [01:23:27] 然后把它以一个层次化的方式归档 [01:23:30] 然后最终并且给我一个比较好的界面 [01:23:33] 这是你最想要的 [01:23:34] 然后你看我估计他十有八九没有 [01:23:38] 我来看一下 [01:23:45] 我要问他 [01:23:47] 其实我想要的是一个比较好的学习助手 [01:23:56] 能收集外网信息 [01:24:01] 除了设计外网信息 [01:24:02] 然后综合总结 [01:24:04] 根据我的进度学习 [01:24:07] 看哪部分能实现我这个功能诶 [01:24:16] 读一读一读 [01:24:18] 然后他在做database [01:24:21] 你看他在做database [01:24:26] 可以可以这样说 [01:24:27] 就是在没有你精心设想过讨论过的这个时候 [01:24:34] AI基本上就只会生成slop [01:24:38] 只只就只会生成 slop [01:24:41] 你看他 [01:24:44] 他 [01:24:49] email [01:24:54] 没有 [01:24:55] 也就是说其实你要的 [01:24:57] 就你脑袋里所想的那个东西 [01:25:00] 这就是我说的你的intent [01:25:02] 你的specification [01:25:03] 你的intention是有巨大gap的 [01:25:05] 然后但是当你一旦这个 [01:25:08] 这个模型看到说你要实现这个的时候 [01:25:11] 他就真的是真的去实现它了 [01:25:16] 然后我觉得肯定是做了一些不好的事情 [01:25:18] 比如说虽然当我提一卡通的时候 [01:25:22] 我真正需要的是一个browser use agent [01:25:25] 它能帮我在各种网页上面处理 [01:25:28] 一卡通只是一个作为测试的出口 [01:25:30] 他能把我的个人信息到一卡通上面 [01:25:33] 所以我可能第一步实现的 [01:25:35] 就不需要去 [01:25:36] 在这个你的教务系统上面做太多的设计 [01:25:40] 你作为过度设计反而反而不好 [01:25:42] 然后这个就是和刚才我看给大家 [01:25:45] 给大家看的那个例子啊是非常相关的 [01:25:48] 你看起来他做的所有的事情都是对的 [01:25:53] 从从README.md来看 [01:25:55] 他做的所有的事情都是正确的 [01:25:58] 没有没有一个错误 [01:25:59] 但最终他得到了一个你不想要的要的东西 [01:26:02] 所以 [01:26:05] 我看现在有没有git提交了 [01:26:11] 他甚至都没有创建一个git repository [01:26:16] 这就是你看你不跟他讲 [01:26:18] 当然我觉得可能如果是codex的话 [01:26:19] 他可能还是会初始化一个目录 [01:26:22] 或者他会问你这个项目应该怎么管理 [01:26:24] 就如果比如说我是一个成熟的产品经理的话 [01:26:27] 老板跟我说 [01:26:28] 这个以后我肯定会跟我的团队去沟通一下 [01:26:32] 项目怎么管 [01:26:33] 这个就在甚至在我写下第一行代码之前 [01:26:37] 我都要讨论好协作怎么做 [01:26:39] 项目怎么管 [01:26:40] 每天什么时候开会 [01:26:42] agent的很好玩 [01:26:43] 他就他就直接上手就上手就做 [01:26:46] 他觉得OK这就是一个用一次就丢掉的一个 [01:26:51] 一个东西 [01:26:52] 感觉他烧了我不少 [01:26:53] 可能烧了我不少 [01:26:54] token也无所谓了 [01:26:55] 这个我参与DPC哈里斯内测 [01:26:58] 他送了我1000块的额度 [01:26:59] 到现在还没有 [01:27:01] 还没有完全用完 [01:27:05] 所以你们在刚开始的时候还是回到项目 [01:27:11] 回到管管理脑袋里面 [01:27:14] 要有一个这样的模型 [01:27:15] 你不能直接把任务就丢给agent [01:27:19] 你现在想的是 [01:27:22] 先第一件事一定是创建一个空的这个好 [01:27:27] 然后创建完了以后 [01:27:28] 你就会想你的下一步要迈向哪里 [01:27:32] 下一步我也给大家展示了 [01:27:34] 不能 [01:27:35] 不能这样 [01:27:36] 下一步不能不能是这样的 [01:27:38] 你需要的是往前再迈一小步 [01:27:44] 慢往前再迈一小步 [01:27:45] 所以你发现现在AI啊他从零开始做一个东西 [01:27:49] 做出来 [01:27:49] slop的难度比他到一个成熟的项目里面去 [01:27:53] 做一个维护性的任务要大很多 [01:27:57] 我们对软件工程的真正的要求 [01:28:00] 或者说我如果我要跟一个team [01:28:03] 或者跟一个学生去谈论 [01:28:05] 我们要设计一个什么什么软件的时候 [01:28:08] 我的问题是你能不能以不变应万变 [01:28:11] 也就是说你现在软件设计一个架构 [01:28:14] 或者设计一个流程方法 [01:28:17] 能不能抵抗未来需求发生根本性的变化 [01:28:22] 所以你马上就看到在刚才那个例子里 [01:28:24] 就是数据库 [01:28:26] 说我要我要我要我要生成一个这个 [01:28:29] 要生成一个挣钱的产品 [01:28:31] 去挣这个宝妈们的钱 [01:28:33] 然后 [01:28:36] 我真正需要的是一个能扩展的架构 [01:28:41] 当未来有别的需求来了 [01:28:43] AI模型发生了变化 [01:28:45] 就我其实我在想这软件工程的时候 [01:28:48] 或者说我的合作模式发生了变化 [01:28:50] AI助教 [01:28:52] AI助教有可能是文字的助教 [01:28:53] 有可能是图像的助教 [01:28:55] 有可能有交互 [01:28:56] 有可能没有交互 [01:28:57] 它各种各样的需求在不断变化的时候 [01:29:03] 我还有没有可能我的架构 [01:29:05] 以最少的变化去应对需求的变化 [01:29:08] 而这个恰恰是大家在在软件工程课 [01:29:11] 也不讲这个这个数据库 [01:29:14] 这个操作系统课也不教 [01:29:15] 大家都说好 [01:29:16] 这个操作系统是长这样的 [01:29:17] 你啊为什么会 [01:29:18] 今天你会看到一个这样的操作系统 [01:29:20] 为什么会看到一个这样的数据库 [01:29:22] 数据库为什么要这样做 [01:29:23] 并发控制 [01:29:24] 都是有这样的一个一个原因 [01:29:27] 但软件软件工程说的最不一样的地方 [01:29:31] 就是对未来需求的变化 [01:29:33] 所以如果你们要 [01:29:37] 就是比如说这两节课 [01:29:39] 跟跟大家讲版本管理的时候 [01:29:42] 你要记得版本管理做的三件事 [01:29:46] 记住现在 [01:29:48] 记住历史 [01:29:49] 记住教训 [01:29:50] 这个是在agent的时代和软件工程 [01:29:53] 就古法编程的时代都成立了 [01:29:56] 你需要现在就是因为你必须要有一个repository [01:29:59] 不管是这个形式 [01:29:59] 还是就现在的一个C或者C++的那Python [01:30:03] JAVASCRIPT的项目 [01:30:03] 你都需要把文件管起来 [01:30:05] 那么你记住历史 [01:30:07] 是为了有一天你这个东西不要了 [01:30:10] 或者你删掉的一个东西 [01:30:12] 你最终发现对你是有用的 [01:30:14] 你还可以把它捞回来 [01:30:15] 然后在这个提交的历史过程当中 [01:30:18] 你能看到你是怎么演进到一个点 [01:30:21] 然后发现这件事情失败了 [01:30:22] 然后这个失败了 [01:30:23] 可能你会留在这 [01:30:24] 然后你会回到另外一个点 [01:30:25] 再开始另外一个 [01:30:27] 正确的 [01:30:28] 正正正确的路线 [01:30:30] 而这些东西都是在版本版本控制里的 [01:30:32] 然后这些lessons不停的都在警示你 [01:30:36] 你需要怎么做 [01:30:39] 你需要这个 [01:30:42] 你需要怎么样 [01:30:44] 从第一步开始迈出向后的一小步 [01:30:47] 那肯定显然不应该是看 [01:30:52] 他已经实现完了吗 [01:31:00] 提交人民奖学金申请 [01:31:02] 这 [01:31:04] 准备退课 [01:31:19] 看有没有git哎 [01:31:22] 他倒是做了一个提交 [01:31:25] 直接一个提交 [01:31:41] 引擎全部是真代码 [01:31:43] 手机端是真HTTP服务派是集成的 [01:31:49] 模拟的部分邮箱是没有的 [01:31:55] 哎好 [01:32:07] 它有一个入口层 [01:32:08] 它有一个编排层 [01:32:11] 有一个能力层 [01:32:13] 还是个非常非常典型的架构 [01:32:17] 数据层 [01:32:18] 我就不如不试图不试图re re review了 [01:32:24] 但显然他把它当成是一个是一个业务 [01:32:27] 逻辑系统来做 [01:32:28] 然后这其实是其实有非常大风险的 [01:32:30] 就是它看起来已经像一个教务系统了 [01:32:32] 哈哈这个软件已经看起来像一个教育系统 [01:32:34] 我下节课就会讲讲教务系统 [01:32:36] 而更其实现在更符合主流的best practice [01:32:41] 如果你真的要从零开始构建的话 [01:32:43] 你要用一个叫MVP的paradigm [01:32:45] 叫minimum [01:32:47] viable product或者minimal viable product [01:32:50] 有一个最小的验证版本 [01:32:53] 然后这有一句话叫the biggest risk in product development [01:32:57] Is building something [01:32:58] Nobody wants [01:32:59] 就是你做的东西 [01:33:00] 就是你看他做的东西就是我不要的对 [01:33:05] 这个东西绝绝大部分东西其实不是我要的 [01:33:07] 我刚才在他登代码的时候 [01:33:09] 我解释了诶 [01:33:10] 我其实想要的是什么 [01:33:15] 所以如果你要做一个最小的版本 [01:33:18] 其实他逼迫的是你要想清楚 [01:33:23] 什么样的需求才是你绝对要的对 [01:33:26] 刚才我刚才我已经说了 [01:33:27] 如果我要一个课程的 [01:33:31] 就如果我要做一个个人的助手 [01:33:33] 我最想要的是他能有让我学 [01:33:35] 提升我学习效率的能力 [01:33:37] 和提升我工作效率的能力 [01:33:39] 你总结出了这两条以后 [01:33:42] 你可能在第一个这个MVP里面没有任何的数据库 [01:33:47] 因为你会想到在任何时候 [01:33:49] 当你文件系统膨胀的时候 [01:33:51] 你都可以说跟AI直接说好 [01:33:53] 按照这个数据的组织帮我提炼出一个数据库 [01:33:56] 这个问题就结束了 [01:33:57] 所以你不需要在刚开始的时候就做数据库 [01:34:01] 因为一旦你带上一个数据库 [01:34:03] 你每次数据库重构都需要让agent做这个database的迁移 [01:34:07] 但文件系统不一样 [01:34:08] 文件系统你自己自己就可以 [01:34:10] 在你的这个文件管理器里去调整它的目录结构 [01:34:17] 直逐渐梳理到你舒服的一个结构上 [01:34:20] 你看你在里面调文件 [01:34:22] 和你去调这个database的schema [01:34:25] 你的心智负担是不一样的 [01:34:27] 人类已经训练过 [01:34:28] 对人类对直观的东西已经训练得非常舒服了 [01:34:31] 文件目录在计算机里面操作 [01:34:33] 你从小 [01:34:34] 从你小学的时候上电脑课开始 [01:34:35] 你就做这件事了 [01:34:36] 所以你对这个模式非常习惯 [01:34:38] 但一旦你说你要操作一个database schema的时候 [01:34:41] 你们很多同学还没有学过数据库课 [01:34:43] 你根本不知道它是什么 [01:34:44] 在你面对一个未知的东西的时候 [01:34:46] 你仍然能就你需要强行的说 [01:34:49] 做一次概念的翻译 [01:34:51] 我这个东西脑袋里面是这样的概念 [01:34:53] 我要翻译到数据库里是这样的 [01:34:55] 那你不如用一个你已经适应了 [01:34:57] 熟悉了的这个system [01:35:00] 用最简单的方式帮你把比如说这个文件的 [01:35:05] 这个学习资料的管理 [01:35:07] 学习资料的进入 [01:35:10] 通知消息的进入 [01:35:12] 就甚至到我现在到我现在 [01:35:15] 我自己回邮件的那agent都没有用任何的数据库 [01:35:19] 我的流程大概是这样的 [01:35:20] 我的流程是我的那个mail agent会收我的邮箱 [01:35:25] 然后会把那个email id放到我的一个共享的云盘 [01:35:30] 同步上 [01:35:30] 然后那个email id里面会有它的这个 [01:35:34] agent解析出来的 [01:35:35] 比如说我回复的草稿 [01:35:37] 然后这个邮件的分类 [01:35:39] 是不是垃圾邮件 [01:35:40] 这种我 [01:35:41] 然后然后再由下一级的流水线去处理 [01:35:44] 也就是说我先要明白的是 [01:35:46] 我的系统里面有哪几级流水线 [01:35:48] 然后这几级流水线之间他们应该怎么协作 [01:35:51] 哪些东西通过云盘 [01:35:54] 然后就比如说那么因为我很喜欢我的云盘 [01:36:01] 是不是引入云盘要做一些架构的修改 [01:36:08] 我希望邮件和资料等都和云盘保持同步 [01:36:17] 这就叫需求的更改 [01:36:19] 我现在不知道它的架构做的做的好不好 [01:36:22] 我让agent他帮我看一看 [01:36:23] 也就是说什么是一个好的软件架构 [01:36:26] 你当然在当前时候 [01:36:31] 这个你是有一个需求的 [01:36:34] 这个现在实现可能是满足这个需求的 [01:36:36] 但是当你的需求发生变更的时候 [01:36:39] 你相应的做出的那个变化是摧毁性的 [01:36:43] 是背上一个技术债还是别的 [01:36:45] 那就那就不知道了 [01:36:50] 然后我们来看一下他的这个这个设计 [01:36:53] 它有一个assistant.db [01:37:00] 他要把个人资料放到这里 [01:37:02] 邮件归档也放到这里 [01:37:04] 索引草稿仍然在在db [01:37:10] 现在看起来还不会引起很大的问题 [01:37:12] 因为绝大部分都是这样的 [01:37:15] 数据库 [01:37:18] 确实应该不会引起特别大的啊大的问题 [01:37:22] 但是随着这个项目的不断的进展 [01:37:24] 你就会你就会发现你有一种开发方式是这样 [01:37:29] 就是你上来就是一个大的 [01:37:31] 然后好几大步就把需求都实现完了 [01:37:35] 然后就拖着这个技术债不断地往后迭代 [01:37:37] 往后加功能加功能 [01:37:38] 还有一个是 [01:37:39] 你从最小的就得到一个特别精巧的架构 [01:37:41] 我举个我为什么要举举举刚才那个例子 [01:37:44] 就当你发现我用git管理这个学生的提交以后 [01:37:48] 很多事情都变得非常容易 [01:37:52] 而且我自己控制起来也会轻松 [01:37:56] 轻松很多 [01:37:57] 直到我遇到性能瓶颈之前 [01:37:58] 我都不去 [01:37:59] 不想要把它迁移到任何的一种数据库 [01:38:04] 然后这也意味着 [01:38:06] 其实你早期的prompt [01:38:07] 对整个项目的走向的影响是最大的 [01:38:11] 你每一次 [01:38:12] 就你最早的那个我直接把README给他 [01:38:14] 还说我要做一个MVP [01:38:16] 这都会对项目造成很大的影响 [01:38:18] 那我下一节课就周日就会进入 [01:38:21] 软件架构和构造的内容好 [01:38:24] 今天下课