能自我编写的提示词:一项Kotlin实验
内容摘要
Koog Agents Optimization Library 是 JetBrains Research 开发的一个研究库,用于优化 Koog 智能体的提示词。借助它,你可以为每条指令编写初版,标记值得调优的步骤,向该库提供训练集,并指定一种为智能体输出评分的方法。随后,该库会运行你的智能体,从发生的情况中学习,并将更好的指令作为一个单独的 JSON 文件返回;你可以读取、审查并提交它。无需重写智能体。
本文示例使用 GEPA,这是一个提示词优化器,会从智能体的失败和成功中学习。在本文中,我们将带你了解在隐私基准 PUPA 上运行的示例。GEPA 将我们智能体的得分从 81.19 提高到 94.22。
👉 Koog Agent Optimization Library(GitHub)
👉 文档
👉 示例
一个待优化的智能体
Koog 是 JetBrains 用于构建智能体的 Kotlin 框架。它把智能体当作程序来处理:你将控制流声明为由节点和边组成的类型化图,每个步骤都可以携带自己的提示词、工具和模型。
我们用它编写了一个完整的智能体:这是我们对 PAPILLON 的移植版本;PAPILLON 是一个隐私流水线,GEPA 将其用作基准之一。它运行在 PUPA 上;PUPA 是一个用户查询数据集,这些查询带有个人详细信息。智能体必须在借助大型外部模型回答此类查询的同时,不把任何这些详细信息交给该模型;因此它会重写问题、去掉这些详细信息,发送重写后的版本,并根据返回内容撰写回复。
这里真正完成工作的只有三个步骤:第一步重写问题,第二步调用大型模型,第三步撰写回复。其余都只是配套管道。这三个步骤中有两个包含由人编写的指令,而它们正是你希望优化器接手的步骤。
将步骤标记为可优化
该库新增了一个构建器。在你想调优的步骤上,将 subgraphWithTask 换成 optimizableSubgraphWithTask,并把指令从它原本埋藏于其中的字符串里提取出来:
将步骤标记为“可优化”后,图本身保持不变。指令只是移到了它自己的参数中,优化器可以在那里找到并替换它。当没有可加载的产物时,该步骤会使用你编写的文本运行。
运行优化器
GEPA 会在训练集上运行你的智能体,向第二个模型展示哪里出了问题,并要求它给出更好的指令。然后它会尝试该指令,并在你设定的预算内一轮又一轮地重复。在这些轮次中,它会同时保留多个候选指令,因此不会丢掉那个只在你最难的样本上胜出的指令。
优化器需要智能体作者提供一样东西:一个函数,它接收一次已完成的运行,并返回评分以及关于运行情况的简短摘要。评分决定哪些候选者能存活下来,而文本则由第二个模型读取。在这里,该文本就是一行数字:
这一行,再加上该步骤自身接收和产生的内容,就是 GEPA 在编写下一节中的指令时所拥有的全部依据。
剩下的只是两个调用:
train 会写入产物,loadOptimizedAgent 会将其读回,并交给你一个运行新指令的智能体副本。该库中的每个优化器都有这两个相同的方法,因此在它们之间切换时,周围的代码无需改动。
GEPA 写了什么
剥离个人详细信息的那个步骤最初使用以下指令:
给定一个私密用户查询,为一个强大的外部 LLM 创建隐私保护请求。
该 LLM 可以在不了解用户私人信息的情况下提供帮助。
两行文字,刻意含糊。它完全没有说明脱敏到什么程度才算足够。
到运行结束时,同一个步骤已经在运行一条 4,456 个字符的指令。以下是其中三段:
上面指令中的每一个细节都来自运行过程,而不是我们写出来的。你大概不会坐下来写出那套占位词、关于教授姓名和课程代码的规则,或者结尾处的总体策略。该策略陈述了一个我们从未提到的权衡:将泄露保持在零,同时保留足够完成任务所需的细节。
结果
我们想知道 Koog 中的 GEPA 实现是否能完成它应该完成的事情,因此我们在该项目自身使用的基准上运行了它,并检查智能体是否表现更好。
以 PUPA 为例,也就是上述智能体运行的基准。它的基线已经是 81.19,向上提升的空间很小,但优化仍将其提高了 13 分,达到 94.22。两个数字都是五次运行的平均值,而且提升具有统计显著性。
其余基准,包括我们的数值与原始实现相比如何,可在文档中查看。
另外三个优化器
除 GEPA 外,该库还在同一接口下实现了另外三个优化器:
- BootstrapFewShot 会从你的成功运行中挖掘示范。除了运行你自己的智能体之外,它不进行任何 LLM 调用,因此是最先尝试的成本最低选项。
- MIPROv2 会在指令和示范之间进行搜索。
- ACE 会积累一本随系统提示词一同使用的洞察手册,适用于你希望智能体积累知识,而不是仅仅获得措辞更好的指令的场景。
在它们之间切换只需更换一个构造函数;周围的 train 和 loadOptimizedAgent 调用保持不变。编写自己的优化器意味着实现同样这两个方法,而我们这四个优化器都能适配它们,无需任何特殊旁路。
在哪里找到它
该库、其文档以及完整的基准结果都在开源仓库中。它所依赖的可优化子图支持目前位于 Koog 的一个分支中;我们预计它会被合并到上游。