Featured image of post 如何快速理解并改进Agent的设计

如何快速理解并改进Agent的设计

使用 agent 编程确实出现了很多曾经我们手工编程没有遇到过的问题和挑战。agent 做得速度甚至比你想的还要快。这是优点,同时也是缺点。

问题

我们习惯于在实现之前先跟 AI 讨论计划。但是我发现,由于没有实践过,AI 在跟你讨论设计时,边界都是靠想象出来的。你们反复在想象出来的边界上讨论,很浪费时间。一个比较快的方案是让 AI 先大概实现一版设计,然后人工在开发环境或者 QA 环境上测试一下,感受一下,再改这个设计。
但是这又带来了新的问题。agent 生成一个特性的速度很快。它也会告诉你大概的设计。但是实际上,你很难理解它说的设计细节。有的时候我会花费大量的时间再追问 AI 设计细节,然而依然不是太明白。我甚至都不知道从哪里开始问。
所以我们现在要考虑的问题不只是怎么跟 AI 沟通,还有怎么让人脑快速理解 agent 的设计。简单地说,我们要把 AI 的设计同步到我们的脑子里。

为什么要同步 AI 的系统设计

在 “Architecture, AI agents, and product empathy with Robert C. Martin” 中,Uncle Bob 提到 agent 写代码缺乏 设计感 和 危机感。我非常认同。先说说设计感。

缺乏设计感

AI 做的系统设计就像一个人不断地在一个设计上打补丁。agent 会先设计一个最简单的方案,然后缺什么补什么,不断地打补丁。所以你会觉得它的设计很绕。其实因为维护系统代码的也是 agent,未来的 agent 上下文也足够大,确实也不是什么问题。但是就怕遇到线上问题时,AI 不停地死循环,就是解决不掉。或者 AI 为了解决这个问题消耗了太多的时间和 token。这个时候就需要人亲自去看代码,找出 root cause。但是系统到了这个时候已经具备了一定的复杂度,人已经看不懂代码了。那么就会面临一个两难的抉择:

  1. 不重构系统,努力去理解 AI 的设计。可能会消耗大量的时间。
  2. 马上重构,有极大的风险搞坏系统,而且不知道怎么修。
    如果这发生在系统上线前夕,或者客户正在运行这套系统的时候急着等修复方案,这是很让人崩溃的。

缺乏危机感

agent 不拿工资,不会被开除,从不担心这个系统会不会出问题,会不会挂掉。AI 在设计时的判断标准只有这个设计看起来好还是不好。但我们知道,所有设计的好坏都是相对的。每个设计方案都有 trade-offs。
agent 似乎看了太多的系统设计题,所以常常坚持最小化设计,尽量不要过度设计。这是好的。然后它把设计都简单化,甚至没发现其中蕴藏的危机。当你跟它辩解的时候,它会说这是一个早期设计,它已经把未来可能遇到的问题和怎么优化写下来了。
这就是问题所在了。Agent 觉得你跟它对系统的未来是有同步规划的。然而并没有。甚至它自己都没有。因为每一轮的对话对于 LLM 来说几乎都是新对话,它下一轮的对话思想来自于会话上下文,并不真的是同一个人想出来的。所以规划开始漂移了。
而且 agent 并不担心一些看起来显而易见的错误。比如过于频繁的 IO 读写操作。当你质问它的时候,它又会说:“我知道有这个问题,我只是不想把设计复杂化。”“哦不,我们尽量不要改现有的设计,只在上面打补丁就好了。”

假设性设计

这个时候有一个方法很有效:假设性设计。具体的做法分为 3 轮:

  1. 第一轮: 你先跟 agent 进行短暂而且浅层的讨论。然后让 agent 快速实现出第一版设计。
  2. 第二轮: 把你的假设性设计告诉 agent。然后问它:“通过类比我们设计中的类似元素,向我解释我的设计跟你的设计有什么不同点。”对于人脑来说,“打个比方”是我们学习事物最快的方式。
  3. 第三轮: 在你跟 agent 同步了设计并改进了你的设计之后,让 agent 把系统重构成偏向于你的设计。

这样它会列出可行性和你的设计的缺陷。通过比较你的设计和它的设计的差异点,可以快速地让你自己理解系统的设计,也让它理解你的想法。
最后一步也很重要。融合它给你的意见,你把你的设计修改完善,最好可以让它将系统重构成更偏向你的设计的实现。因为你的实现是人脑比较容易理解的实现,这对于未来的你自己或者你的同事都很有帮助。

实际操作

这是我在开发一个 AI 语音翻译机器人时候遇到的实际案例。

例子1

我最近在做一个 AI 语音翻译机器人。但是每个人的语音被识别 + 翻译 + 生成语音的总用时都不一样。有可能后面一个人说的话的译文语音已经生成好了,前一个人的语音还在处理中。

所以我现在需要保证译文播放的顺序性。我们很容易就想到,我们需要一个队列,让它可以做到后一个人的译文语音可以等待前一个人的译文语音。

第一轮: 我让 agent 快速地做出了这个功能。它也跟我解释了大概的设计思想。它说核心在于设计了一个 playback-queue。但是当我打开 playback-queue 之后,我发现完全看不懂。设计思路特别绕。它是先做好了一个没有等待功能的 queue,然后在上面补一个等待队列。然后又想到有一些任务会失败,再继续补一个专门处理失败的用例,但并没有复用前面的设计。然后它又引入了一个指针,来回调整这个指针的位置。最终它打了一堆补丁后,这个系统还是可以自洽地运行起来。但是代码却很晦涩难懂。这充分体现了 agent 设计感的缺失。

第二轮: 不过没有关系。我把我的假设性设计告诉了它,我的设计就是一个简单的队列,其中的元素有不同的状态,从而实现等待、跳过、完成这几个状态的管理。它说它实现了相同的事情,然后把它的设计中的元素跟我的设计中的元素做了一个对比。通过这个对比,我也发现了我的设计的不足之处。最后我让它改进了设计。整个过程大概只有 1 个小时。换做是以前,我得不断地追问,都不一定能理解它的设计。

第三轮: 我让它结合我们之前的讨论,再做一版。这个时候它说的点我都能理解了。

例子2

还是同一个 AI 语音翻译机器人。我需要一个计费功能。需求很简单:计费,当用户余额用完后拒绝服务并通知用户。

第一轮: 我让 agent 快速地去实现了这个功能。它很快实现出来了,但是它跟我解释的时候,我隐约感觉有点不对。它反复强调了如何快速地拒绝服务,从而达到控制亏损的效果,或者是如何快速地跟数据库同步账户余额。然后我很快发现,它非常精细地控制整个流程的每一个环节的成本。一条几秒语音就要操作 5 次数据库!然而当我质问它的时候,它说确实有隐藏的风险,但是它已经记下来了,未来会改进的。这体现了 agent 对未来缺乏危机感。

第二轮: 我给出了我的假设性设计,我减小了记录的细粒度,引入了缓存,并且允许用户的余额为负数。然后我跟它讨论了我和它的设计的相似之处和差异。同时我又发现了我的设计的不足之处。

第三轮: 我让它照着改进后的方案重构了代码。整个过程花费了大概 2 个小时。

总结

使用 agent 写代码后,唯一的瓶颈在于人类工程师的时间和注意力。如何更加快速而高效地完成系统级别的改动,同时又要保证这个改动是可控的,不会在未来产生严重的后果,对于快速交付产品有着至关重要的意义。因为别的企业的工程师可能比你更快、更稳。


关于作者

我是代码Plato。

我相信,人类的创造力才是 AI Coding 的真实之树,而代码与模型不过是投射在洞穴墙上的影子。

微博:@代码Plato 主页:https://weibo.com/u/1041257881