在开发Bridgic Agent的过程中,我逐渐感受到不断演进的agent技术架构的一个趋势。一句话先概括结论:agent的架构正向着「长久存续」的方向发展。
这并不等同于说,现在的agent需要一个更长久的记忆,这样简单的一个判断。
这篇文章可能会稍微抽象一些。但我会尽量多引用一些具体的case来辅助说明。
agent作为一个全新的产品品类出现在大众的视野中,基本上是从CLI的形式开始的。像早期的Claude Code,是给工程师用于编程的工具。工程师本来就在终端里完成很多工作,这种产品形式就比较自然。加上这些CLI工具提供了相对丰富的TUI交互形式,对于工程师群体的交互体验已经“足够好”了。
这种工具本质上还是类似于Linux系统上的其他命令行,在使用时打开它,完成工作了就可以退出。在使用这种工具的过程中,你只能同时跟一个会话交互。如果想和另外一个会话交互,你必须先切换到另一个会话里面。在TUI的交互模式下,这也很自然。
但是,当agent发展到桌面端(desktop)形式之后,就产生了一个新的问题:你可以同时打开多个会话,每个会话里启动一个新的任务。也就是说,你可以同时和多个会话进行交互了。这是桌面端这种产品形态上面,最自然的一种交互。
这表面上看似乎也没有什么问题。但是,由于用户可以同时跟多个会话交互,导致desktop类型的应用有了一个深刻的变化:整个应用的生命周期跟会话的生命周期不一致了。因为你不必像以前TUI的交互那样,在打开一个新的会话之前,必须先退出以前的会话。
这个时候,如果一个会话里出现了某种human-in-the-loop(与人交互)的操作,比如可能是权限询问,也可能是让用户做出某些选项的询问,那么这个会话就可能一直等在那。从技术层面来说,这会进一步产生两个问题:
所以你会看到,目前市面上绝大多数桌面版的agent,一旦出现了这种情况,它采用了一种临时的、折中的解法:比如,agent弹出了某种与人交互的界面或弹框而等待用户做出选择的时候,这个时候你如果非要退出软件,它都会给你弹一个警告窗,告诉你当前还有会话没完成,是否真的退出。如果你非要选择退出,那么会话数据将会丢失。
这种情况之所以出现,跟前面提到的agent这个产品品类的演化路径有一定关系。由于agent脱胎于TUI,从最开始就是一个客户端产品,所以它的整个架构也就被很多公司沿袭下来,是一个基于客户端的架构。在前面这种与人交互的情况下,在技术层面上整个会话都会处于一种await造成的状态中,这至少阻塞住了那个协程(coroutine)。这也导致很多状态在内存里,所以才会进程重启后,会话没法完全恢复。
当然了,即使是desktop这种可以同时开多个会话的产品形态,一个用户同时打开的会话数量也还算不上很多,而里面恰好产生了与人交互的情况,就更少了。所以这个问题并不算严重。总是可以通过某种临时性手段规避处理一下。
然而,agent的发展还会面临另外一个趋势,它会走向云端部署。每个人都会有这样一种强烈的需求,希望我的电脑关机了,我的那个agent还能继续在干活儿。这里多说两句:为什么在这个AI时代,agent会以桌面端的形式出现呢?而不是像互联网时代那样,服务跑在云端,用户通过浏览器访问?至少两个原因:
总之,AI在应用端的快速发展也造就了Electron框架的盛行,并且促进了TS语言在AI圈的广泛应用(更早期则主要是Python)。同时,这也是一个「桎梏」。典型的路径依赖。
不管怎么说,agent从桌面端走向云端,也是一个无法避免的趋势。除了需求始终存在之外,原因同样还有两个:
现在问题来了,当agent走向云端的时候,前面那两个不怎么算严重的问题(资源释放问题和重启产生的持久化问题),就变得非常严重!
第一,前后端是分离的。
当前端界面上需要等待用户做出某种响应时,背后的那个会话是不应该在内存里阻塞住的。相反,它应该能「停下来」,释放资源,等用户操作完之后,这个会话应该能够resume,也就是继续执行。
前面我们分析过,这个情况在desktop的客户端上,问题不算太严重。但是,在Bridgic Agent的设计上,却是一个相当严重的问题。为什么呢?因为Bridgic Agent的一个很重要的设计原则是「Agent 引导人」。所谓「Agent 引导人」,就是它在底层实现机制上就非常善于做出主动的一种交互,然后等待用户做出选择。就类似下面这种:
甚至是用户在输入任务时的错漏,它也会通过主动询问的方式来和用户做确认。比如下面这个例子,我在开始输入任务时提到了一个飞书表格的状态字段,但其实是我记错了,那个表格里没有这么一个字段。真正字段名叫做“技能状态”。这个时候Bridgic Agent会主动弹出下面的交互框,提示我做出正确的选择。显然,这种精细度的控制,对于agent能够在真实场景中完成任务是非常有必要的。
那么问题就来了,在用户使用Bridgic Agent的过程中,他很可能同时跑了多个会话,而每个会话中都极易出现等待用户的操作。所以在Bridgic Agent的架构中,虽然它目前还只是一个desktop端的软件,但却必须要解决这个问题。请记住这样一种客观事实:用户有可能永远不会去响应某一个会话中的交互请求,而是把它扔在那不管了。反正用户可以随时开一个新的会话重新执行那个任务。
要解决这个问题,就必须要把前端架构从后端架构中分离出来。而如果还是像一个纯客户端架构那样,使用await等待的方式把前端界面和背后的会话耦合在一个逻辑里,则是完全不可取的。
第二,agent的生命周期从内存状态中分离出来。
换一种说法也就是,agent是「长久存续」的。而不是说,我把软件一关,背后那个agent就不存在了。
为什么这样说呢?因为这与用户的视角是一致的。
我们先考虑更极端的情况,假设你正通过浏览器与一个云端部署的agent进行交互。在任务完成之前,你可能中间断断续续经历了很长时间,几个小时甚至几天后,又重新回来继续交互。那么,在这么长的时间里,我们前面分析过了,由于资源释放的缘故,这个agent不可能一直在内存等着你。但你也不会仅仅因为它在中间被逐出内存了而认为它不存在了。
agent未来会执行越来越长的现实世界任务。再假设agent和人一起协作的场景,agent和人在一个群里,它监听群里的消息做出某种响应。显然,在群里没有消息的时候,这个agent也没有必要一直占用内存等待在那里。这也是一种极大的资源浪费(想象一下有大量的群组需要监听等待)。
回到具体的场景,在Bridgic Agent中,也存在同样的问题需要解决。我们前面说过,在Bridgic Agent与人主动交互的时候,它必须能停下来,而不是在内存中等待。停下来意味着释放内存,意味着它需要持久化,也意味着它需要在收到用户响应后从持久化状态中恢复,包括会话数据和交互状态等各种数据。
这里说到持久化、中断和恢复,再多说几句:这个能力恰恰是agent运行模式天生就可能具备的。从第一性的角度来看,程序代码是很难持久化、中断和恢复的。虽然以前的软件架构也存在序列化和反序列化的可能,但面对复杂依赖环境时的扩展问题会是一场噩梦。在agent模式下由于所有上下文几乎都是文本,这个情况有所改观。
另外,从用户的视角看,你和agent的一个会话交互,你永远没法说它何时算是结束了。你随时可以回来跟它进行后续的交互。那么,从这个意义上说,我们可以认为agent这个实体在概念上是永远存在的、永不结束的,与它的内存占用状态是分离的。
简单总结一下,未来的agent架构必然是前后端分离的,是可以随时中断、持久化和重启的。也就是说,agent的生命周期是和它的内存状态分离的。在这里,我称呼符合这种特征的agent架构为「长久存续」的一种架构。
很显然,这样的一种架构是更能满足云端部署的要求的。当然,这个架构也是客户端和云端通吃的。只是当前市面上的agent由于路径依赖的缘故,也因为问题还不算严重,暂时还没有走到这一步。
而Bridgic Agent从一开始就秉持的「Agent 引导人」的设计原则,让它对于这种架构形式有了更迫切的要求。所以,Bridgic Agent的架构,也就与一个真正的云端agent架构只有“一墙之隔”了。
本文分析了agent架构的其中一种演进方向,以及在实际开发项目中的体现。但这肯定不是agent的全部。
我接下来会继续跟大家分享agent相关开发经验。欢迎留言讨论。
(正文完)
其它精选文章: