LLM神秘小技巧
工具调用
用工具调用优化提示词
当在制作一个多用途的agent时,系统提示词往往需要很长,覆盖所有可能的用途。 这无疑会增加模型的负担,增加模型的困惑度,时模型无法正确遵循指令。 考虑到这种大量主要用于指导agent在不同场景下不同的行为,因此效率低下。 在某一实际场景下与当前场景无关的提示词将影响模型的判断,且token数增加使花费增加。
因此,这里提出了一个优化方案:
- 一些针对特殊场景的提示词,可以作为工具调用的返回结果,以role=tool的身份出现。
例如,在已有的实践场景中,我为agent提供了“绘制数学函数”的工具,但绘制数学函数有复杂的格式要。 这些格式若作为系统提示词的一部分,在大多数情况下,无需使用该工具,将浪费token,并反倒降低模型对其他指令的遵循。 因此,除提供正常的“绘制数学函数”工具外,额外提供了“绘制数学函数的格式说明”工具。 并在系统提示词中,要求模型在绘制数学函数前首先调用“绘制数学函数的格式说明”工具。 这样,在系统提示词中的长段的格式说明仅变为了一句话和一个工具,而当需要使用该工具时,模型会自行学习格式,最终调用“绘制数学函数”工具。
强制工具调用相对顺序
在上一节中,我们提出了一个优化方案,即一些针对特殊场景的提示词,可以作为工具调用的返回结果,以role=tool的身份出现。 但在实践中,由于模型的不确定性,模型在调用工具时,无法保证工具调用的相对顺序。 例如在上面的案例中,模型并没有按照要求调用“绘制数学函数的格式说明”工具,而是直接调用了“绘制数学函数”工具。导致模型无法正确绘制数学函数。
为了解决这个问题,我们提出了一个强制工具调用相对顺序的方案。 在“绘制数学函数”工具的params中,添加一个key
字段,该字段的值为一串随机字符串。 并提示模型,key
必须从“绘制数学函数的格式说明”工具的返回值中获取。 这样,由于模型需要调用“绘制数学函数”时,无法给出key
的值,将迫使模型调用先“绘制数学函数的格式说明”工具,以获取key
的值。
该方法可以与上一节中的优化方案结合使用,减少提示词,并保证模型必须学习了“绘制数学函数的格式说明”,再调用目标工具。
该反复亦可拓展,通过该方法可以建立工具之间的拓扑关系,从而引导模型按照一定的顺序调用工具。
其他
与大模型沟通json vs yaml
与大模型沟通时,常需要大模型给出格式化的数据再进行解析。目前在市面上主流的格式为json。 多数的工具调用等,其内部均使用json格式,但在实际应用中,让大模型给出yaml,效果往往优于json。
转义
yaml一大优势是很大程度上避免了转义。 例如,双引号在json中需要表示为:
0
1
2
{
"text": "\""
}
而在yaml中,可以表示为:
0
text: '"'
在“text”不是一个普通的string,而是例如一段程序代码时,会有更明显的区别。 例如考虑如下代码:
0
1
2
3
4
5
#include <iostream>
int main()
{
std::cout << "Hello, World!" << std::endl;
return 0;
}
在json中,需要表示为:
0
1
2
{
"text": "#include <iostream>\nint main()\n{\n std::cout << \"Hello, World!\" << std::endl;\n return 0;\n}\n"
}
而在yaml中,可以表示为:
0
1
2
3
4
5
6
text: |
#include <iostream>
int main()
{
std::cout << "Hello, World!" << std::endl;
return 0;
}
显然,yaml可以使代码几乎无需转义,原样输出,对大模型更友好,避免了错误的转义造成的问题。 当程序被替换为json时同理,json嵌套导致更复杂的转义问题,例如双引号在一次转义后变为\"
,在二次转义后变为\\\"
。
若出现代码包含转义的双引号(如果需要大模型写代码,这很常见),然后这段代码被作为一个json字段存储,而这个json字段由给到一个大模型(例如上下文压缩时), 那么这种次转义造成反斜杠翻倍,让大模型需要处理的转义,也很容易导致大模型输出的json不符合json规范,然而yaml则可以避免这个问题。
所以当文本内容本身为json/代码等时,使用yaml无疑更优。 并且yaml允许没有引号的字段,这可以大大减轻格式要求对大模型的负担。
嵌套
当出现复杂的json对象,例如
0
1
2
3
4
5
6
{
"obj": {
"obj": {
"text": "Hello, World!"
}
}
}
大模型在末尾要生成连续的}
,如果模型生成了正确的缩进,这可能有利于模型理解当前所在的层级,而若没有,这种反括号的连续生成,将使得模型生成正确json的概率大大降低。
而yaml则没有这个问题,yaml将迫使大模型缩进,这些缩进有利于模型理解当前所在的层级,当离开一个层级时,也无需像json那样生成}
,仅需改变缩进即可。