那还是上个月的事。客户报了个挺邪门的case,他们的Agent在调一个天气插件的时候,偶尔返回“晴转多云”,但同一时刻调用同一插件,另一个实例返回的是“暴雨橙色预警”。一开始以为又是缓存抖动,后来抓了完整的调用链才发现,两个实例加载的根本不是同一个版本的插件——一个走的是本地目录里被别人手改过的代码,一个走的是公司内部源上刚推的包。版本错位直接干翻了整个业务逻辑。
这个事让我想起很多团队做Agent外部能力扩展时,一上来就奔着“怎么把插件调起来”去,却很少想“插件是什么”这个更基础的问题。说白了,第三方插件就是给Agent装上的“义肢”,让它能碰它原生碰不到的东西:查数据库、发HTTP请求、读写文件、操作浏览器、调GPU算力。但这些能力一旦装上,就不再是Agent自己说了算的事,你得跟外部世界的混乱直接打交道。
先聊架构上的一个基本分叉:插件到底跑在Agent进程里,还是独立进程外。很多人图省事,用Python写个import,或者Node里require一下,完事。这种内嵌式插件最爽的是快,函数调用零开销,数据不用序列化。但你得明白,你等于把外部代码焊死在自己的血管里。某次插件内存泄漏,直接把这个Agent主进程拖崩,连带着所有会话全断。真要上生产,我宁愿用子进程或独立服务的方式,哪怕多一次IPC,但爆了只爆插件容器,主流程还在。
讲到这里必须提一下“插件协议”这层东西。第三方插件五花八门,不能让它爱怎么暴露就怎么暴露。我们需要给插件定义一个稳定的“插座”形状。最常见的是JSON-RPC风格:插件暴露一组方法名,入参和出参都是JSON能表达的。这样语言无关,C++写的插件也能被Go写的Agent调。别没事搞什么二进制协议,调试的时候你会哭的。定义协议时要把版本字段放到最前面,不然你将来改协议时,老插件会给你各种诡异的解