一,上下文工程回顾
之前在agent概览中提到过上下文工程包含的部分,包含了系统提示词,工具定义,工具调用返回结果,历史记录和思考过程。上下文是决定了agent能力上限的关键。
这里有一个一般人的会有的误区,上下文工程绝对不是prompt优化比如在提示词中多添加“绝对不可以”、“必须要”这类的修饰词来限制模型。这会产生许多缺点,首先就是模型是不可控的只是添加输入是无法优化agent。必须要这样理解,模型只是做决策,只能做决策真正决定模型输出是输入的信息,这个信息就是上下文。
二,agent通过api调用上下文
要让agent变得聪明就必须要在调用上下文时添加api,让整个过程变得透明。不是依赖于模型本身,觉得模型足够聪明可以自行调取上下文,这是不可取的,必须要用代码的形式展现出来。
上下文可以分为动态和静态部分,静态为系统提示词(定位模型当前的角色)和工具定义,动态为历史记录,工具返回结果和当前用户消息。结构图为:
其中每一块都在调用api时有具体命名,分别为:system(系统提示词),user(用户消息),assistant(助手消息:包含了之前的文本回复和工具调用),tool(工具返回结果)。此外tools(工具定义)是作为独立字段而非消息。这样设计是为了更好的调取api,当模型无法通过本身来回答时就会调取外部的api。
agent调用api的流程为:模型处理静态前缀和动态轨迹获取信息,发现需要调用工具来获取信息,发起第一次请求,得到工具调用结果和上一轮对话信息历史记录全部打包开始第二轮api调用若发现已得到工具返回结果跳出循环。
以上的agent带工具调用的多轮交互就是agent的核心。但同时随着轮数的增加动态轨迹部分会成指数级增长,为了解决这个问题就需要用到KV Cache优化和上下文压缩技术了。
三,KV Cache
这个和transform有着相似之处,为什么它能大大提升agent的处理速度呢,首先先来了解kv是什么。
在静态前缀和动态轨迹输入给模型之前会利用拆词器将它们转化为一个个的token,每个token都有自己的向量信息(由模型参数和词向量决定),叠加这个token在语句中的位置向量也就是它现在在哪个位置,就会产生qkv三个新的向量,其中q用来查询,k是用来匹配,v则是用来存储这个token的真正信息。
那这个和agent上下文有什么关系呢。有关系而且使用kv cache能大大提升agent的上下文能力,根据上述信息我们可以知道每个token的kv只和本身的词向量、模型的参数以及之前的token的词向量有关,只要前面内容没变不论进行多少次的react都不会变。我们就可以使用缓存将前文的kv给存入,只取最后一个token的qkv来计算可以很快得到下一个token是什么。所以在使用kv cache时只有计算第一个token的时间最长,后续都可以复用前面计算的结果。模型本身是无状态的,当用户输入、历史记录和工具结果输入时若不进行缓存会大大降低生成的效率,若在缓存中存入上一轮的kv值下轮来复用就可以加快模型的处理速度。可以让模型不用反复计算每一次的输入信息。
但仅仅只是这样并不能完全解决agent处理效率慢的问题,因为缓存容量是有限制,随着会话次数的增加,缓存也会装不下,这是就该使用上下文压缩技术了。并且若是将所有原始信息都塞给模型也是不可取的,这会导致上下文腐化噪音过多。