上次说到了为了解决react和多次对话中引用上下文的问题,使用了kv cache通过复用原来的kv值来直接生成新的内容,避免了重复的计算。但问题也由此而来,我们现在有了这个技术但如何去设计上下文,送进缓存中的内容到底是什么,以及如何解决上下文膨胀的问题。
一,优化提示词静态前缀
首先是系统提示词的优化,这个是用来约束agent的性格,比如在系统提示词中添加输出内容不可以超过三句话,可以避免agent陷入冗长的自我辩护。但应该注意的是过度使用提示词会导致信息稀释,因此在设计系统提示词时只需要保留关键约束就可以了。
接着时提示词的结构化,利用xml标签的层次化原则,能够给出机器可解析的精确语意,markdown则可以作为人机共读的组织逻辑。提示词结构化后不在分散,就像一本说明书一样从一个零零散散的几百条规则变成了一个有先后执行顺序的流程图,将每一条规则提示词进行划分,可以用xml进行层次划分标签指向markdown,markdown进行详细说明。
系统提示词最重要也是最容易被忽视的一点就是注入的内容不可以模糊,比如在设计一个经济管理agent时在省钱时不可以给它说("根据任务情况选择合适的计费类型")这种模糊的规则,将规则的裁决权交给模型这会导致agent及其不稳定,在设计这方面提示词时必须要精确细化到具体的数值上,比如高于 60% 用可退款模式、低于 30% 直接拒绝任务。
示例也是非常重要的,但在使用示例时需要注意几个点,首先需要让输出结果非常严谨,有固定格式时需要这比写几千字的规则更能约束模型,其次在写示例时不可以进行动态注入这种写法这回破坏prompt cache导致缓存失效,只能将其作为固定模板放在提示词的静态前缀中。所以在写示例时两三个优秀的示例比10个普通示例好。
除了系统提示词外,提示词静态前缀的另一个部分则是工具定义,这决定了agent调用工具的准确性,优秀的工具描述能让未使用过的人能准确使用正确的工具,工具定义也是如此。
二,动态提示词优化
除了静态前缀外,我们还需要动态的注入部分,在实际工作中情况往往都非常复杂,只是依赖静态前准无法适配所有场景就算可以全部穷举出来效率和输出结果质量也远不如动态注入。不把所有的知识全部塞给agent,让它按需加载,agent skill就是这个的工程化体现。
skill分为三层结构,最上层也就是agent必须读取的部分元数据层(也就是静态前缀中的工具定义部分),接着是skill.md核心流程层,这一层将接下来的步骤以一个详细流程的方式将后续每一步都准确的说明,防止模型自由的裁决,最后是子文档,这是上一层的进一步细化,agent按需进行加载,将上一层中每一个节点的技术细节都写入在文档中,以便agent能准确获取信息。
在知道了skill是做的后接下来有了一个具体实施的问题,也就是我的skill放在提示词中的哪里。首先是直接注入,这虽然能通过指令直接将内容全部发给模型但会破坏kv cache,若通过工具调用的方式来获取文档内容,这虽然保证了kv cahce不被破坏但工具调用本身就具有随机性,agent可能不会调用这个方法导致提示词缺少内容。最后有一种方法就可以保证kv cache不被破坏也不会出现漏看的情况,就是将元数据常驻,在上下文的末尾会放入一次元数据利用模型注意力机制让它能很好的获取现有的工具,接着模型选取元工具skill获取操作说明,根据上面的步骤执行任务最终得到结果。