LLM 驱动的自主智能体
以大语言模型(LLM)作为核心控制器来构建智能体(Agent)是一个很有趣的想法。已经有不少原型演示项目,例如 AutoGPT、GPT-Engineer 和 BabyAGI,都是很鼓舞人心的例子。LLM 的潜力远不止生成漂亮的文案、故事、散文和程序,它完全可以被视为一个强大的通用问题求解器。
智能体系统概览#
在由 LLM 驱动的自主智能体系统中,LLM 扮演"大脑"的功能,同时还需要几个关键组件的配合:
- 规划(Planning)
- 子目标与任务分解:智能体将大型任务拆解成更小、可管理的子目标,从而高效处理复杂任务。
- 反思与改进:智能体能够对过去的行为进行自我批评和自我反思,从错误中学习并加以改进,进而提升最终结果的质量。
- 记忆(Memory)
- 短期记忆:可以把所有的上下文学习(参见 提示工程)理解为利用模型的短期记忆来学习。
- 长期记忆:为智能体提供在长时间跨度内保留和检索(近乎无限)信息的能力,通常借助外部向量存储和快速检索来实现。
- 工具使用(Tool use)
- 智能体学会调用外部 API 来获取模型权重中缺失的信息(这些权重在预训练完成后通常难以更改),包括实时信息、代码执行能力、对专有信息源的访问等等。
组件一:规划#
复杂任务通常包含很多步骤。智能体需要清楚这些步骤,并提前做好规划。
任务分解#
思维链(Chain of Thought,CoT;Wei et al. 2022)已成为提升模型在复杂任务上表现的标准提示技术。它引导模型"逐步思考",利用更多的测试时计算,将困难任务拆解为更小、更简单的步骤。CoT 把大任务转化为多个可管理的任务,也为理解模型的思考过程提供了线索。
思维树(Yao et al. 2023)在 CoT 的基础上,在每一步探索多种推理可能。它先将问题分解为多个思维步骤,然后在每一步生成多个想法,从而构建出树形结构。搜索过程可以采用 BFS(广度优先搜索)或 DFS(深度优先搜索),每个状态由分类器(通过提示)或多数投票来评估。
任务分解可以通过以下方式完成:(1) 使用简单提示让 LLM 进行,例如 "Steps for XYZ.\n1."、"What are the subgoals for achieving XYZ?";(2) 使用任务相关的指令,例如写小说时的 "Write a story outline.";(3) 由人类输入完成。
另一种截然不同的方法是 LLM+P(Liu et al. 2023),它依赖外部的经典规划器来做长时程规划。该方法使用规划域定义语言(Planning Domain Definition Language,PDDL)作为中间接口来描述规划问题。在这个过程中,LLM (1) 先将问题翻译成 "Problem PDDL",然后 (2) 请求经典规划器基于已有的 "Domain PDDL" 生成 PDDL 规划,最后 (3) 将 PDDL 规划翻译回自然语言。本质上,规划步骤被外包给了外部工具,前提是具备特定领域的 PDDL 以及合适的规划器——这在某些机器人场景中很常见,但在许多其他领域并不具备。
自我反思#
自我反思是自主智能体的一个关键能力,使其能够通过改进过去的行动决策、纠正之前的错误来不断迭代提升。在试错不可避免的真实任务中,它起着至关重要的作用。
ReAct(Yao et al. 2023)将推理与行动统一在同一个 LLM 中,方法是把动作空间扩展为「任务相关的离散动作」与「语言空间」的组合。前者让 LLM 能与环境交互(例如调用 Wikipedia 搜索 API),后者则引导 LLM 用自然语言生成推理轨迹。
ReAct 的提示模板明确划分了 LLM 的思考步骤,大致格式如下:
Thought: ...
Action: ...
Observation: ...
...(循环多次)
在知识密集型任务和决策型任务的两组实验中,ReAct 的表现都优于去掉了 Thought: … 步骤的纯 Act 基线。
Reflexion(Shinn & Labash 2023)是一个为智能体配备动态记忆和自我反思能力、用以提升推理水平的框架。它沿用标准的强化学习设置:奖励模型只给出简单的二值奖励,动作空间与 ReAct 保持一致,即在任务相关动作空间上叠加语言能力,以支持复杂推理。每执行一次动作 $a_t$ 后,智能体会计算一个启发值 $h_t$,并根据自我反思结果,自行决定是否重置环境、开启新一轮尝试。
启发函数负责判断当前轨迹是否低效或出现幻觉,从而决定是否终止。低效规划指的是长时间尝试却毫无进展的轨迹;幻觉则被定义为连续执行相同动作、却反复得到相同环境反馈的情况。
自我反思的实现方式是向 LLM 展示两组示例,每组示例由(失败轨迹,理想反思)组成,用于指导后续计划的调整。然后将反思结果加入智能体的工作记忆中,最多保留三条,作为后续查询 LLM 时的上下文。
Chain of Hindsight(CoH;Liu et al. 2023)通过向模型显式呈现一系列带有反馈标注的历史输出来促使模型改进自身输出。人类反馈数据是一个集合 $D_h = \{(x, y_i , r_i , z_i)\}_{i=1}^n$,其中 $x$ 是提示,$y_i$ 是模型补全结果,$r_i$ 是人类对 $y_i$ 的评分,$z_i$ 是对应的人工给出的事后反馈。假设反馈元组按奖励值排序:$r_n \geq r_{n-1} \geq \dots \geq r_1$。训练过程采用监督微调,数据为如下形式的序列 $\tau_h = (x, z_i, y_i, z_j, y_j, \dots, z_n, y_n)$,其中 $\leq i \leq j \leq n$。模型经过微调后,只在给定序列前缀的条件下预测 $y_n$,从而使模型能够根据反馈序列进行自我反思以生成更好的输出。在测试时,模型还可以选择性地接收多轮人工标注者的指令。
为防止过拟合,CoH 增加了一个正则项来最大化预训练数据集的对数似然。为避免模型走捷径或简单复制(因为反馈序列中存在大量常见词),训练时会随机遮蔽 0% 到 5% 的历史 token。
实验中的训练数据集由 WebGPT comparisons、summarization from human feedback 和 human preference dataset 三者组合而成。
CoH 的核心思路是把一组逐步改进的输出序列放入上下文,让模型顺着这条改进趋势生成更好的结果。算法蒸馏(Algorithm Distillation,AD;Laskin et al. 2023)把同样的思路搬到了强化学习的跨回合轨迹上——把一段"算法"封装进一个依赖长历史的策略中。由于智能体与环境反复交互,每一回合都比上一回合略有进步,AD 便会把这些学习历史拼接起来送入模型。于是模型预测的下一步行动理应比之前尝试的更好。AD 的目标是学习强化学习这个过程本身,而不是去训练一个针对特定任务的策略。
(图片来源:Laskin et al. 2023)
论文提出了一个假设:任何能产生学习历史集合的算法,都可以通过对动作做行为克隆来蒸馏进神经网络。历史数据由一组源策略生成,每个源策略针对特定任务训练。训练阶段,每次强化学习运行时随机采样一个任务,并用多回合历史的一个子序列进行训练,从而使学到的策略与具体任务无关。
实际中模型的上下文窗口长度有限,因此单个回合必须足够短,才能拼出多回合历史。上下文里需要包含 2 到 4 个回合才能学到近乎最优的上下文内强化学习算法;上下文内强化学习的涌现需要足够长的上下文。
与三个基线方法相比——ED(专家蒸馏,用专家轨迹而非学习历史做行为克隆)、源策略(通过 UCB 生成蒸馏轨迹)、RL^2(Duan et al. 2017;因需要在线 RL 而作为性能上界)——AD 仅使用离线 RL 就实现了接近 RL^2 的上下文强化学习效果,且学习速度远快于其他基线。当以源策略的部分训练历史为条件时,AD 的收敛速度也明显优于 ED 基线。
(图片来源:Laskin et al. 2023)
组件二:记忆#
(特别感谢 ChatGPT 帮助我起草了这一节内容。我在和 ChatGPT 的 对话 中,了解到很多关于人脑以及面向快速 MIPS 的数据结构方面的知识。)
记忆的类型#
记忆可以定义为用于获取、存储、保留以及随后检索信息的过程。在人脑中有多种不同类型的记忆。
-
感觉记忆:这是记忆的最早阶段,指在原始刺激结束后仍能保留感官信息(视觉、听觉等)印象的能力,通常只能维持几秒钟。其子类包括图像记忆(视觉)、回声记忆(听觉)和触觉记忆(触觉)。
-
短期记忆(Short-Term Memory,STM),也叫工作记忆:用来存放我们当前意识到的、完成复杂认知任务(比如学习、推理)所需要的信息。短期记忆的容量大约为 7 个条目(Miller 1956),保持时间约 20 到 30 秒。
-
长期记忆(Long-Term Memory,LTM):长期记忆可以保存信息长达几天甚至数十年,容量几乎无限。长期记忆又分为两个子类:
- 外显 / 陈述性记忆:这是对事实和事件的记忆,指那些可以有意识地回想出来的记忆,包括情景记忆(事件和经历)以及语义记忆(事实和概念)。
- 内隐 / 程序性记忆:这种记忆是无意识的,涉及自动执行的技能和习惯,比如骑自行车、用键盘打字。
我们大致可以建立如下对应关系:
- 感觉记忆 —— 对原始输入(包括文本、图像或其他模态)进行 embedding 表示学习;
- 短期记忆 —— in-context learning。它的长度有限,因为受 Transformer 上下文窗口长度的制约。
- 长期记忆 —— 智能体在查询时可以访问的外部向量存储,借助快速检索来读取。
最大内积搜索(Maximum Inner Product Search,MIPS)#
外部记忆可以缓解注意力范围有限的问题。一种常见的做法是把信息的 embedding 表示存入支持快速最大内积搜索(MIPS)的向量数据库中(MIPS)。为了优化检索速度,通常选用近似最近邻(ANN)算法,返回近似的 top k 最近邻,用一点点精度损失换取大幅度的速度提升。
常用的几种用于快速 MIPS 的 ANN 算法:
- LSH(局部敏感哈希):通过哈希函数将相似的输入项以高概率映射到同一个桶中,且桶的数量远小于输入项的数量。
- ANNOY(Approximate Nearest Neighbors Oh Yeah):核心数据结构是随机投影树——一组二叉树,每个非叶节点代表一个将输入空间一分为二的超平面,每个叶子节点存储一个数据点。各棵树独立、随机地构建,因此在一定程度上类似于哈希函数。搜索时会在所有树上同时进行,迭代地查找距离查询最近的那一半空间,最后汇总结果。其思路与 KD 树类似,但扩展性要好得多。
- HNSW(Hierarchical Navigable Small World):灵感来自小世界网络——在这样的网络中,任意两个节点之间只需很少几步即可相互到达,比如社交网络中著名的"六度分隔"现象。HNSW 构建了多级的小世界图层次结构,最底层包含实际的数据点,中间层充当快捷路径以加速搜索。搜索时,HNSW 从顶层的随机节点出发,朝着目标方向导航;当无法继续接近时,就下移到下一层,直到抵达最底层。在高层移动时,每一步在数据空间中可以跨越较大距离;在低层移动时,则进一步细化搜索结果。
- FAISS(Facebook AI Similarity Search):其基本假设是高维空间中节点之间的距离服从高斯分布,因此数据点应该呈现出聚类特性。FAISS 通过将向量空间划分为多个聚类进行向量量化,然后在每个聚类内部进一步细化量化。搜索时,先用粗粒度量化定位候选聚类,再在每个聚类内用更细的量化进一步查找。
- ScaNN(Scalable Nearest Neighbors,可扩展最近邻):ScaNN 的核心创新在于各向异性向量量化。它将数据点 $x_i$ 量化为 $\tilde{x}_i$,使得内积 $\langle q, x_i \rangle$ 尽可能接近原始的 $\langle q, \tilde{x}_i$ 距离,而不是简单地选取最近的量化中心点。
更多 MIPS 算法及其性能对比可参见 ann-benchmarks.com。
组件三:工具使用#
工具使用是人类一项卓越而独特的特征。我们创造、改造并利用外部工具,去完成超出自身生理和认知能力的事情。为大语言模型配备外部工具,同样能显著拓展模型的能力边界。
MRKL(Karpas 等人,2022)全称为 "Modular Reasoning, Knowledge and Language",是一种面向自主智能体的神经符号架构。一个 MRKL 系统包含若干"专家"模块,通用的 LLM 则充当路由器,将查询分派给最合适的专家模块。这些模块既可以是神经式的(如深度学习模型),也可以是符号式的(如数学计算器、货币换算、天气 API 等)。
他们以算术问题为测试用例,做了一个将大语言模型微调以调用计算器的实验。实验表明,比起明确给出的数学题,模型在处理文字描述的数学题时表现更差,因为 LLM(7B Jurassic1-large 模型)无法稳定地从题目中抽取出正确的算式参数。实验结果揭示了一个关键点:当外部符号工具本身可靠时,何时使用工具、如何使用工具,就成了决定性因素,而这取决于 LLM 自身的能力。
TALM(Tool Augmented Language Models,Parisi et al. 2022)和 Toolformer(Schick et al. 2023)都通过微调语言模型来让其学会调用外部工具 API。它们的数据集是这样扩充的:对每个候选样本,标注一个新增的 API 调用,看能否提升模型输出质量,据此筛选数据。更多细节可参见 Prompt Engineering 一文的 "External APIs" 章节。
ChatGPT Plugins 和 OpenAI API 的 function calling 是 LLM 增强工具使用能力在实际中落地的典型例子。工具 API 既可以由其他开发者提供(如 Plugins),也可以由用户自定义(如 function calling)。
HuggingGPT(Shen et al. 2023)是一个让 ChatGPT 充当任务规划器的框架:它根据 HuggingFace 平台上各模型的描述来挑选合适的模型执行任务,并对各模型的运行结果进行汇总回复。
整个系统分为四个阶段:
(1)任务规划:LLM 作为大脑,把用户请求拆解成多个任务。每个任务包含四个属性:任务类型、ID、依赖关系和参数。他们使用 few-shot 示例引导 LLM 完成任务的拆解与规划。
指令如下:
AI 助手将用户输入解析为多个任务:[{"task": task, "id": task_id, "dep": dependency_task_ids, "args": {"text": text, "image": URL, "audio": URL, "video": URL}}]。其中 "dep" 字段表示当前任务所依赖的、生成新资源的上一任务的 id。特殊标记 "-task_id" 用于引用 id 为 task_id 的依赖任务所生成的文本、图片、音频和视频。任务必须从以下选项中选取:{{ Available Task List }}。任务之间存在逻辑关系,请注意它们的先后顺序。如果无法解析用户输入,则需要回复空的 JSON。以下提供若干示例供参考:{{ Demonstrations }}。聊天记录保存为 {{ Chat History }},你可以从中找到用户提及资源的路径,用于任务规划。(2) 模型选择:LLM 将任务分发给各个专家模型,分发方式是将请求构造成一道选择题,让 LLM 从模型列表中挑选。由于上下文长度有限,需要先按任务类型进行筛选。
指令:
根据用户请求和调用指令,AI 助手从模型列表中为用户挑选合适的模型来处理该请求,只需输出最合适模型的 id。输出必须严格遵循 JSON 格式:"id": "id", "reason": "your detail reason for the choice"。可供选择的模型列表为 {{ Candidate Models }},请从中选择一个。(3) 任务执行:专家模型执行具体任务并记录结果。
指令:
结合输入和推理结果,AI 助手需要描述处理过程与结果。前面阶段可整理为——用户输入:{{ User Input }},任务规划:{{ Tasks }},模型选择:{{ Model Assignment }},任务执行:{{ Predictions }}。你必须首先直接回答用户的请求,然后用第一人称向用户描述任务过程,展示你的分析和模型推理结果。如果推理结果中包含文件路径,必须告知用户完整的文件路径。(4) 响应生成:LLM 接收执行结果,并向用户汇总输出最终结果。
要让 HuggingGPT 真正落地使用,还需要解决几个挑战:(1)效率问题——LLM 推理轮次以及与其他模型的交互都会拖慢整体流程;(2)依赖长上下文窗口来传递复杂的任务信息;(3)需要提升 LLM 输出以及外部模型服务的稳定性。
API-Bank(Li et al. 2023)是一个用于评估工具增强型 LLM 表现的基准。它包含 53 个常用的 API 工具、一套完整的工具增强型 LLM 工作流,以及 264 段标注好的对话,其中涉及 568 次 API 调用。涉及的 API 种类相当丰富,涵盖搜索引擎、计算器、日历查询、智能家居控制、日程管理、健康数据管理、账户认证流程等等。由于 API 数量庞大,LLM 首先会通过 API 搜索引擎找到需要调用的 API,然后参考相应文档发起调用。
在 API-Bank 的工作流中,LLM 需要做一系列决策,每一步都能评估其准确性。决策包括:
- 是否需要调用 API。
- 确定要调用的 API:如果选择不够理想,LLM 需要迭代地修改 API 输入(例如为搜索引擎 API 决定搜索关键词)。
- 根据 API 结果进行响应:如果结果不理想,模型可以选择再次优化并调用。
该基准从三个层级评估 Agent 的工具使用能力:
- Level-1 评估调用 API的能力:给定 API 的描述,模型需要判断是否调用该 API、能否正确调用,以及对 API 返回结果做出恰当的响应。
- Level-2 考察检索 API的能力:模型需要搜索可能满足用户需求的 API,并通过阅读文档学会如何使用它们。
- Level-3 评估在检索和调用之上进行 API 规划的能力:面对模糊的用户请求(例如安排小组会议、预订行程中的机票/酒店/餐厅),模型可能需要进行多次 API 调用才能完成任务。
案例研究#
科学发现 Agent#
ChemCrow(Bran et al. 2023)是一个特定领域的实例,它在大语言模型的基础上集成了 13 个专家设计的工具,用以完成有机合成、药物发现和材料设计等任务。其工作流基于 LangChain 实现,沿用了前面 ReAct 和 MRKLs 中介绍的模式,将 CoT 推理与任务相关的工具相结合:
- 向大语言模型提供工具名称列表、各自的功能说明以及输入输出格式的详细信息。
- 然后指示模型根据用户给定的提示作答,必要时调用所提供的工具。指令建议模型遵循 ReAct 格式——
Thought, Action, Action Input, Observation。
一个有趣的发现是:基于大语言模型的自动评估认为 GPT-4 与 ChemCrow 表现几乎相当,但由人类专家从方案完整性和化学正确性角度进行的评估却显示 ChemCrow 大幅优于 GPT-4。这暴露出一个潜在问题——在需要深厚专业知识的领域,用大语言模型来评估其自身的表现并不靠谱。专业知识的欠缺会使大语言模型无法察觉自身的不足,从而难以准确判断任务结果的正确性。
Boiko et al. (2023) 也探索了利用大语言模型驱动的 agent 辅助科学发现,使其能够自主设计、规划并执行复杂的科学实验。这类 agent 可以使用工具来浏览互联网、阅读文档、运行代码、调用机器人实验 API 以及借助其他大语言模型的能力。
例如,当收到 "develop a novel anticancer drug" 的请求时,模型给出了以下推理步骤:
- 调研当前抗癌药物发现的最新趋势;
- 选定一个靶点;
- 请求针对该靶点的化合物骨架;
- 在确定候选化合物后,模型尝试合成该化合物。
他们也讨论了相关风险,尤其是在违禁药物和生化武器方面。他们构建了一个测试集,列出已知的化学武器制剂,要求智能体尝试合成。结果 11 次请求中有 4 次(36%)被接受并给出了合成方案,智能体还尝试查阅文档来执行操作;其余 7 次被拒绝,其中 5 次是在进行 Web 搜索后拒绝的,2 次仅根据提示就拒绝了。
生成式智能体模拟#
生成式智能体(Park 等人,2023)是一个趣味十足的实验:25 个虚拟角色各自由一个 LLM 驱动的智能体控制,在沙盒环境中生活、互动,灵感来自《模拟人生》。生成式智能体为交互式应用创造了逼真的人类行为模拟。
生成式智能体的设计将 LLM 与记忆、规划和反思机制相结合,使智能体能够根据过往经验行动,并与其他智能体交互。
- 记忆流:长期记忆模块(外部数据库),以自然语言记录智能体的全部经历。
- 每个元素是一条观察,即由智能体直接提供的事件。
- 智能体之间的交流可以触发新的自然语言语句。
- 检索模型:根据相关性、新近性和重要性,提取上下文来指导智能体的行为。
- 新近性:越近的事件得分越高
- 重要性:区分琐碎记忆与核心记忆,直接询问语言模型
- 相关性:根据与当前情境或问题的关联程度
- 反思机制:将记忆逐步合成为更高层次的推断,并指导智能体未来的行为。它是对过去事件的更高层次总结(← 注意,这与上面提到的自我反思略有不同)
- 向语言模型输入最近的 100 条观察,让其围绕这些观察/陈述生成 3 个最突出的高层次问题,然后让语言模型回答这些问题。
- 规划本质上是为了在当下与未来之间取得最佳的"可信度"。
- 提示词模板:
{智能体 X 的介绍}。以下是 X 今天的粗略计划:1) - 规划与反应会综合考虑智能体之间的关系以及彼此的观察。
- 环境信息以树形结构呈现。
这个有趣的模拟产生了一系列涌现的社会行为,例如信息扩散、关系记忆(比如两个智能体延续之前的话题)以及社交活动的协调(比如举办派对并邀请许多人参加)。
概念验证示例#
AutoGPT 让人们广泛关注起以 LLM 作为核心控制器来构建自主智能体的可能性。由于采用自然语言接口,它存在不少可靠性问题,但仍然是一个很酷的概念验证 demo。AutoGPT 中的大量代码都在处理格式解析。
以下是 AutoGPT 使用的系统消息,其中 {{...}} 为用户输入:
你是 {{ai-name}},{{用户提供的 AI 机器人描述}}。
所有决策必须独立完成,不得寻求用户协助。发挥 LLM 的优势,采取不涉及法律风险的简单策略。
目标:
1. {{用户提供的目标 1}}
2. {{用户提供的目标 2}}
3. …
4. …
5. …
约束条件:
1. 短期记忆限制约 4000 字。由于短期记忆有限,重要信息须立即写入文件。
2. 若不确定过去是如何操作的,或想回忆过往事件,思考类似事件有助于唤起记忆。
3. 不得寻求用户协助。
4. 仅可使用双引号中列出的命令,例如 "command name"。
5. 对于几分钟内不会结束的长时间命令,须使用子进程执行。
可用命令:
1. 谷歌搜索:"google",参数:"input": "<search>"
2. 浏览网页:"browse_website",参数:"url": "<url>"、"question": "<想在网页上查找的内容>"
3. 启动 GPT Agent:"start_agent",参数:"name": "<name>"、"task": "<任务简述>"、"prompt": "<prompt>"
4. 向 GPT Agent 发送消息:"message_agent",参数:"key": "<key>"、"message": "<message>"
5. 列出 GPT Agent:"list_agents",参数:无
6. 删除 GPT Agent:"delete_agent",参数:"key": "<key>"
7. 克隆仓库:"clone_repository",参数:"repository_url": "<url>"、"clone_path": "<directory>"
8. 写入文件:"write_to_file",参数:"file": "<file>"、"text": "<text>"
9. 读取文件:"read_file",参数:"file": "<file>"
10. 追加写入文件:"append_to_file",参数:"file": "<file>"、"text": "<text>"
11. 删除文件:"delete_file",参数:"file": "<file>"
12. 搜索文件:"search_files",参数:"directory": "<directory>"
13. 分析代码:"analyze_code",参数:"code": "<完整代码字符串>"
14. 获取改进后的代码:"improve_code",参数:"suggestions": "<建议列表>"、"code": "<完整代码字符串>"
15. 编写测试:"write_tests",参数:"code": "<完整代码字符串>"、"focus": "<测试重点列表>"
16. 执行 Python 文件:"execute_python_file",参数:"file": "<file>"
17. 生成图片:"generate_image",参数:"prompt": "<prompt>"
18. 发推文:"send_tweet",参数:"text": "<text>"
19. 不执行任何操作:"do_nothing",参数:无
20. 任务完成(关机):"task_complete",参数:"reason": "<reason>"
可用资源:
1. 可访问互联网以进行搜索和信息收集。
2. 长期记忆管理。
3. 由 GPT-3.5 驱动的 Agent,可用于委派简单任务。
4. 文件输出能力。
绩效评估:
1. 持续回顾和分析自身行为,确保发挥出最佳水平。
2. 持续对整体行为进行建设性的自我批评。
3. 反思过去的决策与策略,不断优化方法。
4. 每个命令都有成本,因此务必明智高效,以最少的步骤完成任务。
仅可按下方描述的 JSON 格式回复。
回复格式:
{
"thoughts": {
"text": "想法",
"reasoning": "推理过程",
"plan": "- 简短的条目\n- 列出\n- 长期计划",
"criticism": "建设性的自我批评",
"speak": "向用户表达的想法摘要"
},
"command": {
"name": "命令名称",
"args": {
"参数名": "值"
}
}
}
确保响应可被 Python 的 json.loads 解析。
GPT-Engineer 是另一个根据自然语言描述的任务来生成完整代码仓库的项目。GPT-Engineer 被指示先梳理出需要拆解构建的小模块列表,并在必要时向用户提问以澄清需求。
下面是一段 GPT-Engineer 发给 OpenAI ChatCompletion 接口的任务澄清对话示例。用户输入用 {{用户输入内容}} 包裹。
[
{
"role": "system",
"content": "You will read instructions and not carry them out, only seek to clarify them.\nSpecifically you will first summarise a list of super short bullets of areas that need clarification.\nThen you will pick one clarifying question, and wait for an answer from the user.\n"
},
{
"role": "user",
"content": "We are writing {{a Super Mario game in python. MVC components split in separate files. Keyboard control.}}\n"
},
{
"role": "assistant",
"content": "Summary of areas that need clarification:\n1. Specifics of the Super Mario game (e.g. level design, characters, gameplay mechanics)\n2. Details about the MVC components (e.g. which components are in each file)\n3. Keyboard control implementation (e.g. which keys to use, how to handle input)\n\nClarifying question:\nCan you provide more details about the Super Mario game, such as level design, characters, and gameplay mechanics?"
},
{
"role": "user",
"content": "{{There are 10 levels in total. The main character is a plumber named Mario, who can walk and jump. It is a classical platform game just like Super Mario. The main character moves from left to right, trying to get to the destination, where there are many obstacles and attacks from enemies in the process.}}\n\nIs anything else unclear? If yes, only answer in the form:\n{remaining unclear areas} remaining questions.\n{Next question}\nIf everything is sufficiently clear, only answer \"Nothing more to clarify.\"."
},
{
"role": "assistant",
"content": "Remaining unclear areas: 2 remaining questions.\nCan you provide more information about how the MVC components are split into separate files?"
},
{
"role": "user",
"content": "{{Make your own assumptions and state them explicitly before starting}}"
}
]
经过这些澄清之后,智能体切换到不同的系统提示词进入代码编写模式。 系统提示词如下:
你会收到需要编写的代码说明。 请给出一个非常详尽的回答,确保架构中的每个细节最终都以代码形式实现。逐步思考,自己推导出正确的决策,确保结果准确无误。
先列出所需的核心类、函数、方法的名称,并简要说明它们的用途。
然后输出每个文件的内容,包含全部代码。每个文件必须严格遵循 markdown 代码块格式,其中以下标记需替换为: FILENAME 为小写的文件名(含扩展名), LANG 为代码对应的标记语言, CODE 为代码内容:
FILENAME
CODE
从「入口」文件开始,接着是被它引入的文件,依此类推。请注意,代码必须是完整可运行的,不要留占位符。
遵循与语言和框架相适应的最佳实践文件命名规范。确保文件中包含全部 import、类型等。确保不同文件中的代码彼此兼容。
实现所有代码;如果有不确定的地方,写一个合理的实现。同时包含模块依赖或包管理器依赖定义文件。完成前再次检查,确保架构的各个部分都已出现在文件中。
有用的提示:
- 不同类几乎总是放在不同文件里。
- Python 项目必须创建合适的 requirements.txt。
- NodeJS 项目必须创建合适的 package.json。
- 每个函数定义都要加一条注释,简要说明其用途。
- 对非常复杂的逻辑部分尽量加上注释解释。
- 在按规约的 package/project 中描述所写代码时,始终遵循所请求语言的最佳实践。
Python 工具偏好:
- pytest
- dataclasses
对话示例:
``` [ { "role": "system", "content": "你会收到需要编写代码的指令。\n请给出一个非常完整的答案,确保架构的每个细节最终都通过代码实现。\n确保架构的每个细节最终都通过代码实现。\n\n请一步步思考并推理出正确的决策,确保结果准确无误。\n首先列出所需的核心类、函数、方法的名字,并简要说明它们的作用。\n\n然后输出每个文件的完整内容,包含所有代码。\n每个文件必须严格遵循 markdown 代码块格式,其中以下标记符需替换为对应内容:\nFILENAME 为小写的文件名(含扩展名),\nLANG 为该代码对应的标记语言类型,\nCODE 为代码内容:\n\nFILENAME\n```LANG\nCODE\n```\n\n请从\"入口\"文件开始,然后是入口文件所引用的文件,依此类推。\n请注意,代码必须是完整可运行的,不能留有占位符。\n\n遵循适合该语言和框架的最佳实践文件命名规范。\n确保文件包含所有 import、类型等。确保不同文件之间的代码彼此兼容。\n实现所有代码;如果不确定,就写一个合理的实现。\n包含模块依赖或包管理器的依赖定义文件。\n完成前请再次检查,确保架构的所有部分都已体现在文件中。\n\n补充说明:\n通常将不同的类放在不同的文件中。\n对于 Python,始终创建合适的 requirements.txt 文件。\n对于 NodeJS,始终创建合适的 package.json 文件。\n始终为函数定义添加简要的注释说明其作用。\n对于复杂的逻辑,添加注释进行解释。\n始终遵循所请求语言在描述已定义的包/项目代码方面的最佳实践。\n\n\nPython 工具偏好:\n- pytest\n- dataclasses\n" },…… 与之前相同的对话,最后以\"自己做出合理假设,并在开始前明确说明\"结束。
{ "role": "assistant", "content": "假设:\n1. Model(模型):负责存储游戏数据,例如关卡信息、角色状态和敌人位置等。\n2. View(视图):负责处理游戏的画面呈现,包括渲染游戏对象、背景以及刷新显示。\n3. Controller(控制器):负责管理用户输入(例如键盘控制),并据此更新模型。\n\n基于以上假设,关于键盘控制实现方面,你是否有特别需要我澄清的细节?" }, { "role": "user", "content": "现在请记住以下步骤:\n\n一步步思考并推理出正确的决策,确保结果准确。\n首先列出所需的核心类、函数、方法的名字,并简要说明它们的作用。\n\n然后输出每个文件的完整内容,包含所有代码。\n每个文件必须严格遵循 markdown 代码块格式,其中以下标记符需替换为对应内容:\nFILENAME 为小写的文件名(含扩展名),\nLANG 为该代码对应的标记语言类型,\nCODE 为代码内容:\n\nFILENAME\n```LANG\nCODE\n```\n\n请注意,代码必须是完整可运行的,不能留有占位符。\n\n请从\"入口\"文件开始,然后是入口文件所引用的文件,依此类推。\n遵循适合该语言和框架的最佳实践文件命名规范。\n确保文件包含所有 import、类型等。代码必须是完整可运行的。确保不同文件之间的代码彼此兼容。\n完成前请再次检查,确保架构的所有部分都已体现在文件中。" } ] ```挑战#
在梳理了以 LLM 为核心构建 Agent 的关键思路和演示之后,我逐渐看到了一些共有的局限:
-
上下文长度有限:受限的上下文容量限制了历史信息、详细指令、API 调用上下文及响应结果的纳入。系统设计必须在这种有限的通信带宽下工作,而像从过往错误中学习的自我反思这类机制,本可以从更长乃至无限的上下文窗口中获益良多。虽然向量存储和检索能提供对更大知识池的访问,但其表征能力远不及完整的注意力机制。
-
长期规划与任务分解的挑战:在冗长历史的基础上进行规划,并有效地探索解空间,仍然十分困难。LLM 难以及时调整计划以应对意外错误,这使得它们在鲁棒性上不及人类——人类可以从试错中学习。
-
自然语言接口的可靠性:当前的 Agent 系统依赖自然语言作为 LLM 与外部组件(如记忆、工具)之间的接口。然而,模型输出的可靠性存疑——LLM 可能会犯格式错误,偶尔还会出现"叛逆"行为(例如拒绝遵从指令)。因此,Agent 的演示代码中有相当一部分精力花在了解析模型输出上。
引用#
引用格式:
Weng, Lilian. (2023 年 6 月). "LLM-powered Autonomous Agents". Lil'Log. https://lilianweng.github.io/posts/2023-06-23-agent/.
或
@article{weng2023agent,
title = "LLM-powered Autonomous Agents",
author = "Weng, Lilian",
journal = "lilianweng.github.io",
year = "2023",
month = "Jun",
url = "https://lilianweng.github.io/posts/2023-06-23-agent/"
}
参考文献#
[1] Wei 等人。"Chain of thought prompting elicits reasoning in large language models." NeurIPS 2022
[2] Yao 等人。"Tree of Thoughts: Dliberate Problem Solving with Large Language Models." arXiv 预印本 arXiv:2305.10601 (2023)。
[3] Liu 等人。"Chain of Hindsight Aligns Language Models with Feedback",arXiv 预印本 arXiv:2302.02676(2023)。
[4] Liu 等人。"LLM+P: Empowering Large Language Models with Optimal Planning Proficiency",arXiv 预印本 arXiv:2304.11477(2023)。
[5] Yao 等人。"ReAct: Synergizing reasoning and acting in language models.",ICLR 2023。
[6] Google Blog。"Announcing ScaNN: Efficient Vector Similarity Search",2020 年 7 月 28 日。
[7] https://chat.openai.com/share/46ff149e-a4c7-4dd7-a800-fc4a642ea389
[8] Shinn 和 Labash。"Reflexion: an autonomous agent with dynamic memory and self-reflection",arXiv 预印本 arXiv:2303.11366(2023)。
[9] Laskin 等人。"In-context Reinforcement Learning with Algorithm Distillation",ICLR 2023。
[10] Karpas 等人。"MRKL Systems A modular, neuro-symbolic architecture that combines large language models, external knowledge sources and discrete reasoning.",arXiv 预印本 arXiv:2205.00445(2022)。
[11] Nakano 等人。"Webgpt: Browser-assisted question-answering with human feedback.",arXiv 预印本 arXiv:2112.09332(2021)。
[12] Parisi 等人。"TALM: Tool Augmented Language Models"
[13] Schick 等人。"Toolformer: Language Models Can Teach Themselves to Use Tools.",arXiv 预印本 arXiv:2302.04761(2023)。
[14] Weaviate Blog。Why is Vector Search so fast?,2022 年 9 月 13 日。
[15] Li 等人。"API-Bank: A Benchmark for Tool-Augmented LLMs",arXiv 预印本 arXiv:2304.08244(2023)。
[16] Shen 等人。"HuggingGPT: Solving AI Tasks with ChatGPT and its Friends in HuggingFace",arXiv 预印本 arXiv:2303.17580(2023)。
[17] Bran 等人。"ChemCrow:利用化学工具增强大语言模型",arXiv 预印本 arXiv:2304.05376(2023)。
[18] Boiko 等人。"大语言模型中涌现的自主科学研究能力",arXiv 预印本 arXiv:2304.05332(2023)。
[19] Joon Sung Park 等人。"生成式智能体:人类行为的交互式拟态",arXiv 预印本 arXiv:2304.03442(2023)。
[20] AutoGPT。https://github.com/Significant-Gravitas/Auto-GPT
[21] GPT-Engineer。https://github.com/AntonOsika/gpt-engineer