Single Agent 阶段性总结

embedded/2025/1/13 9:41:25/

Agent 通常指的是一类具备高度自主性的智能实体,它们能够巧妙地在特定环境里自主感知信息,运用内置的智能算法做出理性决策,进而精准无误地执行相应动作。相较于 RAG(检索增强生成)技术,Agent 可解决诸多难题。RAG 虽擅于知识检索整合,但面对动态变化场景稍显乏力。Agent 则不同,它能实时感知环境动态,主动调整策略。比如在供应链管理中,遇到物流堵塞,Agent 可迅速重新规划配送路径,优化资源分配,保障供应链畅通无阻,而 RAG 很难做到如此灵活应变,全方位提升效率与适应性。
在这里插入图片描述

Profile

Prompt engineering,例如 CoT(Chain of Thought,思维链)、ICL(In-Context Learning,上下文学习)等,已被证实是一种在不微调的情况下增强大语言模型LLM)能力的有效方法。由于 LLM 的本质是基于 token 预测,所以 Prompt engineering 相当于给 LLM 提供更多的前置 token,如此一来便更有可能预测出 “正确” 的 token(这纯属个人理解,在预训练阶段模型会接触大量文本,下一个 token 的候选者可能成千上万。此时若给予更多前置 token,依据条件概率,就更有机会生成所谓的正确 token)。

简介模块在此处的作用是定义代理的角色。代理(Agent)通常通过承担特定角色来执行任务,以查询天气的任务为例,一般我们会将 Agent 设定为天气预报员或检索人员,赋予其一定的天气相关背景知识以及检索天气的工具等。这部分信息通常涵盖基本信息(如年龄、性别和职业)、心理信息(反映代理的个性)以及社交信息(在多代理场景下会涉及代理之间的关系)等。

简单来讲,简介模块可理解为添加前置 token,助力 LLM 锁定后续 token 的生成范围,能有效激发 LLM 的 “潜意识”。需要注意的是,这并非仅 Agent 才有的模块,只要与 LLM 交互,就可能涉及这部分内容。

常用的简介生成策略如下:

  • 手工制作方法:Agent 的简介由人工指定,这也是最为常用的方式,即人工撰写系统提示。通过设定 Agent 角色,让 LLM 能够更好地生成期望结果,甚至可以设定 LLM 生成内容的格式等。这种方法能够精准把控一些具体细节,但不可避免地需要投入大量人工精力。
  • LLM 生成方法:Agent 的简介由 LLM 自动生成。有一种做法是指明档案生成规则,阐明目标群体中 Agent 简介的组成与属性,然后选择性地提供一些样本示例(few-shot),最后利用 LLM 生成所有简介。不过,该方法可能难以对生成的档案进行精确控制,从而导致与预期特征不一致或出现偏差。
  • 数据集对齐方法:Agent 的简介源自真实世界的数据集。简单来说,就是依据真实人类的信息,归纳总结成一段描述性文字提供给 LLM。例如,直接将现实生活中某类人的背景信息总结后赋予 LLM,这里要注意,由于单个人的信息可能过于独特,不一定能发挥预期作用,同时输入 token 限制也是一个问题。

PS. 在实际使用场景中,不必过于纠结使用哪种策略,甚至可以采用多种方法相结合的方式来生成对应的信息。

记忆(Memory)

结构

记忆模块用于存储从环境中感知到的信息,并借助记录的记忆推动未来行动。它帮助代理积累经验、实现自我进化,使其行为更加一致、合理、高效。简单而言,记忆可以是当前的聊天记录,比如新开一个对话窗口,该窗口的信息就会被当作记忆。往复杂了说,记忆可以包含过去所有的对话,此时以某个账户作为主体,这个主体与 LLM 发生的所有对话都能当作记忆。

由此明显可见,这里将记忆划分为短期记忆(即图片中的 unified memory)和长期记忆:

  • 短期记忆:最简单的做法是将当前窗口中的对话再次输入 LLM,如此一来 LLM 便拥有了短期记忆。其能记忆的长度取决于 LLM 输入 token 的上限,当然也可以采用压缩或提炼的方法来总结过往内容。
  • 长期记忆:可以简单理解为外挂数据库,也就是 RAG(Retrieval-Augmented Generation,检索增强生成),在此不多赘述,可参考相关内容。

这个模块实际上也是 RAG 与 Agent 逐渐融合之处,之前提及 modular RAG 时就已有记忆、循环等模块。有趣的是,很多人将 RAG 和 Agent 视为两种独立技术,认为某个方案的解决要么只用 RAG,要么只用 Agent。依我之见,这部分人对 RAG 的理解仅停留在 Naive RAG,即单轮次的简单检索增强,对 Agent 的理解也只是 LLM + 短期记忆 + 函数调用。从这个角度看,两者确实各有优劣,但在实际应用中,我们需要结合各种方法的优势才能达成理想效果。

对于记忆的处理,一种较为合理的方法是将长期和短期记忆相结合(即图片中的 Hybrid memory)。这与人的思维逻辑颇为相似,我们既需要当前正在进行对话的记忆,也需要过去积累学习所得的记忆。例如面试时,首先我们会基于已有的长期记忆进行自我介绍,随着面试深入,面试官可能使用一些代词指代对话中发生的事情,这时就需要利用短期记忆明确其提问内容。

格式

刚刚提到短期记忆指当前对话的内容,显然这部分记忆以自然语言形式存储,无需额外处理便可直接提供给 LLM。除此之外,还有许多其他格式的数据可用于存储过去的知识 / 记忆,这里简单列举两个:

  • embedding:将信息转化为 embedding 向量,再通过检索获取对应相关信息(没错,就是 RAG)。
  • 数据库:这一点很明显,在工业界许多结构化数据都存储在数据库中,通过 SQL 等语句能够轻松检索到对应信息。在确保 SQL 正确的情况下,甚至可以省去重排序(re-rank)的步骤。
    当然还有其他格式,如图结构、树结构等,它们各有优缺点,这里就不一一列举了,简言之,需要依据实际场景选择恰当的存储介质和格式。

操作

关于记忆的操作,主要有三个:读取、写入和反思。

  • 读取:这个操作与 RAG 的流程类似,即选择最相似 / 正确的信息读取出来即可。
  • 写入:取决于存储介质的不同,相关操作也有所差异。需要注意两点:1) 记忆重复,对于同一信息要尽量避免重复存储。说起来容易做起来难,对于 MySQL 这类数据库,如果确定了唯一键(UK),相对来说较易实现。但对于向量数据库(vectorDB)这种存储形式,很难保证没有重复数据,可以在元数据(metadata)字段添加一些标签,最后通过比对标签来避免或减少重复信息的存储。对于短期记忆而言,最简单的方法是直接利用 LLM 进行总结,减少重复信息。2) 记忆溢出,这里主要针对短期记忆,即 LLM 输入窗口的 token 限制,因为从逻辑上讲,数据库很少会出现超出存储上限的情况。对于短期记忆的长度问题,可以通过压缩总结的方法解决,同时也可以考虑使用支持长上下文(long-context)的 LLM 来提升短期记忆的存储上限。PS. 实际上在正常使用情况下,只需关注短期记忆的写入是否存在问题,因为业界很少有 Agent 会依据客户指令直接对数据库中的数据进行修改。
  • 反思:其实反思不算一个独立操作,当记忆被检索 / 读取出来后,与其他信息一同提供给 LLM,自然而然就可以通过提示让大模型依据已有信息进行一定思考,根据过去的行为 / 记忆 / 结果来规划下一步行动。

规划(Planning)

无反馈规划

规划能力并非 Agent 所独有,任何一个大语言模型都具备一定的规划能力。当与 Agent 的其他模块相结合时,便能进一步提升整个任务的完成度。简单来说,当 LLM 没有其他模块辅助时,只能进行一些简单的规划推理,例如 Cot、Tot、Got、ReWOO 等,这种情况被称为无反馈规划,即 LLM 制定规划后,不会得到外部反馈就直接生成结果。当然,这里面也包含单路径推理多路径推理等方法,如下图所示:
在这里插入图片描述

这种方法效果的优劣,直接取决于 LLM 本身的能力,换言之,一旦规划出现问题,那么得出的结论必然也是错误的。因此,一种可行的方法是,直接使用外部规划器(如 PDDL,Planning Domain Definition Language,规划领域定义语言)来制定计划,之后将这部分信息提供给 LLM 生成结果。通过外部规划器进行规划能够避免 LLM 因自身能力不足导致的规划失误。若想让这种方法自动化运行,就离不开函数调用(function calling)的能力,遇到问题时,调用外部规划器,获取所需计划后再交由 LLM 生成最终结果。

有反馈规划

什么是有反馈规划呢?简单来讲,就是 LLM 得到一定反馈后再进行下一步计划或修改之前的计划,其中最著名的就是 ReAct。这类方法的优势在于,当计划中的某个环节结果与最初计划相差甚远时,能够及时修正计划,避免整个任务失败。这里的反馈又可分为以下三类:

  • 环境反馈:最具代表性的就是 ReAct 框架,通过思考 - 执行 - 观察三个步骤不断调用工具与环境交互,最终得到结果。还有一个较为知名的框架是 LLM Compiler,它结合了 ReWOO 和 ReAct 的优势,通过设定规划器(planner)和求解器(solver),并与环境进行交互。与 ReAct 不同的是,规划器会给出完整的执行步骤,求解器执行全部内容后,规划器会查看每一步执行结果并思考是否需要重新规划。
  • 人类反馈:这一点比较明确,即在程序运行的关键节点引入人工介入,例如人工审查或输入,使整个流程更具可控性。
  • 模型反馈:简单来说,就是用模型替代人类进行反馈,可以引入第二个 LLM 或专门训练的模型来提供反馈。与环境反馈只能给出执行结果不同,模型反馈能够依据当前状态给出详细的修改反馈。

行动(Action)

说到 Agent,让人印象最为深刻的便是函数调用,也就是这里提及的行动(Action)。通过调用外部工具能够获取精准答案,弥补 LLM 在某些方面的不足,例如数学计算。

目标

对于一些具有明确任务的问题,如四则运算,只需调用不同的工具来计算每一步结果即可(环境反馈)。而对于一些较为模糊的任务,如论文撰写修改,可能需要调用两个 LLM 返回修改内容,以求得完美答案(模型反馈)。
因此,这里行动的目标不仅仅是完成任务,还可能涉及在完成任务过程中必要的交流与探索。

产生方式

  • 从记忆中调用动作:根据当前任务,依据从 Agent 记忆中检索到的信息生成动作。仍以 ReAct 为例,根据当前任务的反馈以及之前的思考,确定下一步的行动。
  • 遵循计划中的行动:Agent 依据预先制定的计划采取行动。例如 ReWOO 或外部规划器,Agent 会严格按照计划执行相关步骤。

行动空间

行动空间指的是 Agent 可以执行的所有可能行动的集合,大致可分为两类:(1)外部工具和(2)LLMs 的内部知识。

外部工具

  • API / 工具函数:利用外部 API / 函数来扩充行动空间。以四则运算为例,可以定义加减乘除四个工具函数,让 LLM 根据输入判断应按何种步骤进行运算,每一步都调用对应的函数以获取准确结果。当然,对于更为复杂的任务,可以直接调用其他模型来辅助生成结果,完成任务。

  • 数据库 / 知识库:集成外部数据库或知识库能使 Agent 获取特定领域的信息,从而生成更贴合实际的行动。可以将 RAG 封装成一个外部函数,通过调用这个函数工具,提取对应数据库中的信息。

PS. 在定义 API / 工具函数时,需要给出相应的功能描述、参数需求等。而且当 API / 工具函数过多时,需要考虑输入 token 上限。个人经验表明,当一个 Agent 拥有过多工具,或者存在两个描述相近的工具时,可能导致 LLM 无法正确调用。

内部知识

除了使用外部工具,许多智能体还依靠 LLM 的内部知识来指导其行动。这种说法有点类似于早期的评论模型,通过给模型赋予不同角色来完成任务,这其实也是多 Agent 的雏形,不同的 Agent 实际上都是同一个模型,只是给予了不同的系统提示,最终相互协作完成任务。

PS. 个人观点认为,对于特定任务,如果条件允许,最好优先使用外部工具获取关键信息。只有在无法通过外部工具得到确切答案时,才考虑使用内部知识。经验教训显示,当一个 LLM 在初次推理时无法得出想要的答案,那么第二次推理大概率也难以得到正确信息。

行动影响

行动影响指的是 Agent 行动带来的后果。其实这没什么太多可解释的,通过外部工具调用得到结果后,可能会导致计划改变等情况出现,进而可能需要制定新的计划等。


http://www.ppmy.cn/embedded/153520.html

相关文章

【广西乡镇界】arcgis格式shp数据乡镇名称和编码2020年内容测评

【广西乡镇界】arcgis格式shp数据乡镇名称和编码2020年内容测评

[JavaEE] Spring IoCDI

目录 一、IoC 1.1 IoC 概念 1.2 IoC的作用 二、DI 2.1 DI 概念 2.2 属性注入(Field Injection) 2.3 构造方法注入(Constructor Injection) 2.4 Setter 注入(Setter Injection) 2.5 三种注入优缺点分析 2.5.1 属性注入 2.5.2 构造函数注入 2.5.3 Setter 注入 三、IoC…

【conda】迁移到其他ubuntu机器

想把部署在一台4070机器的conda 环境导出到3090机器查看已安装的环境 conda env list环境导出 conda env export > semantic-text2image-search.yml 4070的conda环境导出 nvidia-smi 命令可以查看 GPU 的基本信息,包括显存、CUDA 驱动版本等: Driver Version:当前 NVIDI…

ros2笔记-6.2 使用urdf创建机器人模型

本节主要跟着小鱼老师的视频操作,不同的仿真平台有不同的建模语言,但是几乎都支持URDF。 本节使用URDF创建一个机器人模型。 6.2.1 帮机器人创建一个身体 URDF使用XML来描述机器人的结构和传感器、执行器等信息。 在chapt6/chap6_ws/src创建功能包:r…

GCC安全编译选项

文章目录 GCC安全编译选项1.BIND_NOW2.NX3.PIC4.PIE5.SP6.NO Rpath/Runpath7.FS8.Ftrapv9.Strip10.安全编译Python GCC安全编译选项 1.BIND_NOW 定义:立即绑定,打开GOT表重定位只读选项 使用方式:LDFlAGS"-Wl,-z,relro,-z,now" ./configure 2.NX 堆栈不可执行:打…

Golang笔记——rune和byte

大家好,这里是Good Note,关注 公主号:Goodnote,专栏文章私信限时Free。本文详细介绍Golang中的两种字符类型rune和byte,介绍他们的区别,编码方式和简单的使用。 文章目录 byte 类型rune 类型UTF-8 与 Unico…

2024最新版Node.js下载安装保姆级教程【图文详解】

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行时环境,允许开发者在服务器端运行 JavaScript。它以非阻塞、事件驱动的架构处理高并发,适用于构建高效的网络应用。在 APP 自动化测试中,Node.js 常用于构建测试框架(如 WebD…

开源临床试验软件OpenClinica的安装

本文是为帮网友 A萤火虫 解决安装问题做的记录; 简介 什么是 OpenClinica ? OpenClinica 是世界上第一个商业开源临床试验软件,主要用于电子数据捕获(EDC)和临床数据管理(CDM)。它的设计旨在优…