自构建代理:LangChain4j实验
主要收获
- 我们让一个由 LLM 驱动的代码助手使用 LangChain4j 的文档和 API 自行设计并实现了一个多智能体编码系统。
- 这个自建的编码智能体随后修复了真实存在的 bug,通过了测试,并通过 LangChain4j 暴露了自身的执行流程。
- 我们比较了两种关键的人工智能智能体模式,发现更刚性的工作流模式比更自主的监督者模式执行速度快三倍,原因是消除了 LLM 引发的协调开销。
- 使用新引入的
MonitoredAgent接口,可以清晰获取智能体调用报告以及智能体系统的拓扑结构。 - 实验中,同一个智能体设计在较旧、较便宜的模型上会陷入工具调用循环导致失败,但在较新的模型上则成功完成了 bug 修复任务。
我们决定进行一次元实验:把 LangChain4j 的文档交给一个代码助手,让它构建一个自己的副本。具体来说,我们希望它设计一个多智能体系统,能够像人类工程师(或代码助手本身)一样编写、测试和调试代码。一个 LLM 能够根据文档构建自己的副本,这件事本身就说明了 LangChain4j 的两点特性:第一,API 足够清晰易懂,模型可以直接使用;第二,框架提供了足够强大的编排能力,使得生成的系统能够端到端地执行真实的调试任务。
这个项目也让我们有机会对 LangChain4j 的新监控工具进行压力测试。当你让 AI 构建另一个 AI 时,你确实需要看到内部发生了什么。本文解释了实验的经过,并介绍了最终的项目成果,该项目可在这个仓库中获取。
“氛围编码”一个智能体系统
为了让代码助手构建它的第一个智能体编码器,我们编写了以下提示:
学习 LangChain4j 智能体框架的 API 和能力,基于其文档和源代码,设计一个基于该框架的智能体编码器,使其成为你自己的克隆版。
经过几分钟的思考和运作,助手认为 LangChain4j 的监督者模式最适合这个任务。它提出了一个初始架构:
代码助手还设计并实现了监督者使用的四个子智能体及其系统消息和用户消息。这些智能体负责探索现有代码、制定行动计划、按照计划实现操作、并通过编译和执行来检验生成的代码。代码助手随后为每个智能体正确实现了所需的工具:探索智能体的文件系统浏览器、实现智能体的代码编辑器、以及执行智能体的代码运行能力。
第一次迭代的结果令人印象深刻。如果你曾使用过代码助手,你会知道这大致就是那些“专业”助手在现实中使用的模式:它们通常执行与实验中四个智能体建模的相同的四个动作。然后,助手以监督者式的方式编排这些动作来完成当前任务——这与我们的实现如出一辙。代码助手能够设计和实现这样一个系统,表明它至少在高层次上了解自己的内部工作原理,并能将这种理解转化为具体的智能体系统设计。
让智能体编码器工作起来
为了测试代码助手设计的智能体编码器,我们让它先写一些有 bug 的代码,然后利用新创建的系统来修复它们。代码助手生成了下面这个包含四个稍有缺陷的方法的 Calculator 类:
接着,它生成了一个测试,将包含 Calculator 类的文件夹克隆到临时目录,然后对该目录执行 LangChain4j 的智能体编码器:
现在是时候运行代码,看看使用常见 LLM 时该实现是否真的有效了。我们为监督者和编码智能体都使用了 OpenAI 的 gpt-4o。选择这个模型是因为 OpenAI API 是默认的基础 URL,gpt-4o 是 LangChain4j 中的默认模型。还有一个好处是,该模型也支持工具调用。
可惜事情并不顺利。几分钟后,我们收到了一个错误:
显然,LLM 陷入了工具调用循环,而 LangChain4j 在超过默认的最大允许次数 100 后中断了该循环。这个限制可以通过 AiServices 的 maxToolCallingRoundTrips() 方法进行配置,但通常这是一个非常合理的默认值。同一个智能体实际上需要超过 100 次工具调用是非常不合理的。
幸运的是,我们之前就在较旧或较不先进的模型上见过这个问题,因此我们改用更现代的 gpt-5-mini 模型重新运行了相同的测试。又过了几分钟,系统输出了以下内容:
这次,系统成功修复了 Calculator 类中的所有 bug,并使所有测试通过。它还将临时文件夹中的代码正确修改为:
成功之后,我们想更清晰地了解监督者智能体的执行流程。LangChain4j-agentic 的 1.12.2-beta22 版本引入了一项新功能:只需让建模根智能体的接口扩展 MonitoredAgent 接口,即可监控智能体编码器的执行。
这个接口允许我们打印智能体调用报告以及系统拓扑,如下图所示。它清晰地展示了智能体编码器的运行方式。
[LOADING...]
图1:由 LangChain4j 可观测性 UI 生成的基于监督者的架构的系统拓扑和执行追踪截图。(图片来源:作者截图)
从监督者到工作流
监督者模式因其自主性而有用,但这种自由也带来了隐藏的开销。为了看看是否能让系统更高效、更可预测,我们要求代码助手使用基于工作流的方法重新设计智能体编码器。
在保留监督者实现的基础上,增加第二个实现,以更确定性的方式实现类似行为,仅使用 LangChain4j 智能体框架提供的工作流模式。特别是,生成一系列行动步骤,尽可能重用现有智能体,并在必要时添加评审循环。
按照要求,这次它提出了一个更确定性的架构:一个严格的五步序列。前四步与之前的智能体对应,第五步引入了一个专门的 SummarizerAgent,它接管了之前由监督者隐式处理的汇总职责。计划和执行步骤都不是单个智能体,而是通过循环结构实现,允许它们进行多次迭代,在继续前进之前调整和改进工作。
例如,执行循环由三个子智能体组成:执行器、评估器和重构智能体。这些智能体会被迭代调用,直到评估分数足够好或者达到最大迭代次数。在这个具体例子中,“足够好”的分数被设定为准确率百分之八十,这是一个相当常见且现实的阈值。迭代次数上限设为 5,以防止如果准确率从未达到百分之八十阈值时产生过多的 LLM 调用和令牌消耗。
针对这个替代实现运行与之前相同的测试,产生了非常相似的结果,输出如下:
和之前一样,智能体编码器修复了所有 bug 并使所有测试通过,但这次执行追踪显示了一个更复杂的拓扑,包含更多智能体和边。
[LOADING...]
图2:由 LangChain4j 可观测性 UI 生成的基于工作流的架构的系统拓扑和执行追踪截图。(图片来源:作者截图)
然而,这次尽管涉及的智能体数量更多,完整的调试会话版本(与监督者实现相比)却快了整整三倍:两分钟对六分多钟。节省时间的原因在于监督者智能体本身引入的开销——它必须自主生成所有其他智能体的调用及相应参数来协调它们。
结论
在本文中,我们展示了如何使用 LangChain4j 智能体框架,通过“氛围编码”的方式构建一个智能体编码器,让 LLM 自行设计和实现该系统。在这种背景下,LangChain4j 智能体框架的 API 表现出了易用性,使 LLM 能够自主设计和实现一个复杂的智能体编码器,同时其能力足以让代码助手在该系统中克隆自己的内部工作机制,创建了一种元智能体编码器。
我们还展示了如何将该系统投入真实的调试会话,监控其执行并可视化其拓扑。结果令人印象深刻:系统使用一个精心设计的智能体拓扑修复了所有 bug 并通过了所有测试。
最后,这个实验展示了基于工作流与基于更自主监督者的智能体实现之间速度与自主性的权衡。当效率、速度和可预测性至关重要时,选择工作流模式。工作流模式是一种更刚性的方法,在我们的案例中,其执行速度大约是监督者模式的三倍。这种效率来自于消除了 LLM 引发的协调开销,转而依赖确定性的架构和严格顺序的步骤。该模式非常适合那些可以分解为预定义的顺序阶段的任务,并且通常包含内置的循环结构用于迭代改进。
当自主性和动态灵活性比执行速度更重要时,选择监督者模式。监督者模式更加自主,允许主智能体自主生成其他所有智能体的调用及对应参数,动态地进行协调。但这种自由带来了隐藏的开销,使其显著变慢。
关于作者
Kevin Dubois
Kevin Dubois 是一位软件架构师和平台工程师,拥有超过二十年的职业生涯。他经常作为主题演讲嘉宾出席世界各地的会议,分享他在云原生和 AI 软件开发、开发者体验、开源及 Java 方面的经验与知识。Kevin 还是一位作家和 Java 冠军。他目前在 IBM 担任高级首席开发者倡导者,并且是 CNCF 开发者体验技术咨询小组的技术负责人以及 Agentic AI 基金会大使。
Mario Fusco
Mario Fusco 是 IBM 的高级首席软件工程师,担任 Drools 项目负责人。他的兴趣包括高性能系统和生成式 AI。Mario 是 Quarkus 和 LangChain4j 等广泛采用的项目活跃贡献者。他还是一位 Java 冠军,JUG Milano 协调员,经常发表演讲,并合著了由 Manning 出版的《Modern Java in Action》。