2023 年 6 月 23 日 Lilian Weng
利用大语言模型(LLM)作为核心驱动的智能代理是一个极富创意的概念。有一些令人印象深刻的概念验证示例,比如 AutoGPT、GPT-Engineer 和 BabyAGI,都为我们展示了巨大的可能性。LLM 不仅可以创作流畅的文本、故事、散文和代码,更重要的是,它可以成为解决各种问题的强大工具。
Agent 系统简介#
LLM 驱动的自主 Agent 系统中,LLM 就像 Agent 的大脑,辅以几个核心组件:
-
计划环节
- 细分目标与拆解:Agent 把庞大的任务拆成小块,每一块都是一个小目标,让复杂任务变得简单易搞定。
- 反思与优化:Agent 会反思自己过去的行为,学习并改正错误,使得以后能更好地开展工作,提高工作成果的品质。
-
记忆部分
- 短时记忆:在上下文学习环节(详见 Prompt Engineering),模型就是利用短时记忆来学习的。
- 长时记忆:长时记忆使 Agent 能长期记住和回想起(无限的)信息,这通常是通过外部向量存储和快速取回功能实现的。
-
使用工具
- Agent 学会了调用外部 API,这样就能获得那些在模型权重中没有的信息(预训练后很难修改这些权重)。这些信息包括最新的数据、执行代码的能力和访问独家信息源等。
图 1. LLM 驱动的自主 Agent 系统简图。
第一部分:计划
对于一项复杂的任务来说,通常需要进行多个步骤。执行任务的代理需要了解这些步骤,并事先进行计划。
任务分解
思维链条(CoT;Wei 等人,2022)已逐渐成为增强模型在处理复杂任务时性能的标准技巧。通过“分步思考”的指导,模型能有效利用测试阶段的计算资源,把艰难的任务分解成更小更简单的几个步骤。CoT 不仅将庞大的任务分解为多个容易处理的小任务,还揭示了模型思维过程的一些线索。
思维之树(Yao 等人,2023 年)是 CoT 的进一步拓展,其在每个思考阶段都开展多重推理探索。简单来说,该方法首先把一个问题拆解成数个思考步骤,然后每一步都产生多个想法,形成了一种‘树状’的结构。在搜索的过程中,它可以采用 BFS(广度优先搜索)或是 DFS(深度优先搜索),并通过分类器(通过提示方式)或者多数票来评估每个状态。
我们可以通过三种方式来分解任务:
(1) 通过 LLM 搭配简单的提示,比如 "Steps for XYZ. 1."
或 "What are the subgoals for achieving XYZ?"
;
(2) 使用特定于任务的说明,比如为编写小说的任务写一个大纲,使用 "Write a story outline."
;
(3) 或者直接通过人工输入。
有另外一种独特的方法,名为 LLM+P(Liu 等人,2023 年),这个方法主要是依赖一个外部的传统规划器来进行长期的规划。它使用了一种名为 Planning Domain Definition Language(PDDL)的工具,作为描述规划问题的中介接口。在这个过程中,LLM 首先会把问题翻译成“Problem PDDL”,然后请求规划器根据已有的“Domain PDDL”来创建一个 PDDL 计划,最后再将这个 PDDL 计划翻译回自然语言。简而言之,规划的步骤是外包给外部工具完成的,这需要有特定领域的 PDDL 和适当的规划器,虽然这在某些机器人领域是常见的,但在很多其他领域并不是这样。
Thought: ...Action: ...Observation: ...... (多次重复)
图 2. 这是一幅描绘知识浓厚任务(比如 HotpotQA 和 FEVER)与决策任务(如 AlfWorld Env, WebShop)推理路径的示意图。(图片来自:Yao et al. 2023)。
无论是进行知识密集型任务还是决策任务的实验,ReAct
都比只用 Act
(并且删去了 Thought: …
步骤)的基准表现得更好。
Reflexion (Shinn & Labash 2023) 是一个特别的框架,能够赋予计算机代理动态记忆和自省能力,从而增强其推理技能。Reflexion 遵循标准的 RL 设定,奖励模型只给出简单的正负奖励,动作空间则参照 ReAct 的设定,将任务相关的动作空间通过语言增强,使得复杂推理步骤成为可能。在每次执行动作 at 后,代理会计算一个启发式 ht,然后根据自省的结果,选择是否 重置 环境,开始新一轮的尝试。
图 3:呈现了 Reflexion 框架的插图。这幅插图的信息来源于 Shinn & Labash, 2023 的研究。
启发式函数是一个能判断计划轨迹是否效率不高或者是否产生“幻觉”的工具,一旦判断出这两种情况,该计划轨迹就应当被终止。所谓的效率不高的计划轨迹,就是那些花费了很长时间但最终并没有成功的轨迹。而“幻觉”则是指在环境中进行一连串相同动作却得出相同观察结果的情况。
“自反思”是通过给 LLM 展示两个案例来实现的,每个案例包括一对失败的轨迹和指导未来计划调整的理想反思。然后,这些反思会被添加到智能代理的工作记忆中(最多三个),作为查询 LLM 时的上下文。
图 4:该插图展示了在 AlfWorld Env 和 HotpotQA 进行的实验结果。结果显示,在 AlfWorld 环境中,“幻觉”比计划效率低的情况更为常见,这是一个值得注意的失败模式。图片信息来源于 Shinn & Labash, 2023 的研究。
回顾链技术(CoH; Liu 等人,2023)帮助计算机模型通过学习过去的反馈来改善自己的性能。它依赖一组人类反馈数据,每条数据包含提示、模型的回答、人类对回答的评分和事后反馈。所有的反馈数据都是按照评分排序的。这个技术的核心是让模型通过学习这些排序过的反馈数据来自我调整和改进。
为了防止模型过于依赖特定数据(即过拟合),回顾链技术还引入了一个额外的技巧:它使用正则化来增强模型对原始预训练数据的学习。此外,训练时还会随机隐藏 0%-5% 的数据,以防模型仅仅是复制反馈而不是真正学习。
在他们的实验中,研究者们使用了来自 WebGPT 对比、人类反馈总结和人类偏好数据集的混合数据。
如图 5 所示,通过使用回顾链技术进行细致的调整,计算机模型能够根据指导逐步提升自己的输出质量。(图片来源:Liu 等人 2023)
CoH 的核心思想是呈现一个由逐渐优化的输出组成的历史轨迹,并指导计算模型顺应这个趋势,从而产生更优秀的结果。算法蒸馏(Algorithm Distillation,AD;参见 Laskin 等人 2023 年的研究)采用相同的思路,它应用在强化学习任务中,通过长期的历史数据来塑造和训练一个算法。考虑一个情境:一个智能代理(如机器人)多次与其环境互动,在每一次互动中,它的表现都略有提升。AD 方法就是将这些学习和提升的经验串联起来,作为模型的输入。这样,我们有理由期望该智能代理在下一次行动时,其表现会超越之前的所有尝试。AD 的最终目标并不仅仅是训练一个针对特定任务的策略,而是学习和掌握强化学习的整个过程。
图 6 展示了算法蒸馏(AD)是如何运作的。 (图片来源:Laskin 等人 2023 年的研究)。
该研究提出了一个假设:任何可以生成学习历史集的算法,都可以通过“行为克隆”技术转化为神经网络模型。这些学习历史数据是由一组源策略生成的,每种策略都是为了完成一个特定任务而训练的。在训练过程中,每进行一次 RL 运算,系统都会随机选取一个任务,并使用该任务的多次互动历史来进行训练。这样,通过训练,学到的策略将不会依赖于任何特定任务。
实际上,由于模型只能处理有限长度的上下文窗口,我们需要确保每个“剧集”足够简短,这样才能构建多个“剧集”的历史记录。要学习近乎最优的上下文中的强化学习(RL)算法,2-4 个“剧集”的多剧集上下文是必要的。此外,上下文中的 RL 的诞生也依赖于拥有足够长的上下文。
相较于三个比较基准 —— ED(专家蒸馏,通过专家的轨迹进行行为克隆,而不是依赖学习历史),source policy(为 UCB 生成轨迹以进行蒸馏),以及 RL^2(由 Duan et al. 2017 提出,由于需要在线 RL,被视为上界)—— AD 在仅使用离线 RL 的情况下,展现了接近 RL^2 的性能,并且学习速度超过其他基准。当以 source policy 的部分训练历史作为条件时,AD 的改进速度也远超 ED 基准。
图 7. 对比图展示了在需要记忆和探索的环境中,AD、ED、source policy 与 RL^2 的表现。此处只赋予二进制奖励。source policies 在“黑暗”环境中是通过 A3C 训练得到的,而在 watermaze 中则是通过 DQN 训练得到的。(图片来源:Laskin et al. 2023)
第二组件:内存
在此要向 ChatGPT 表达深深的感谢,因为它在起草这一部分时给了我很大的帮助。通过与 ChatGPT 的交谈,我对人类大脑以及用于高速 MIPS 的数据结构有了更多的了解。
记忆的多样性#
记忆,简单来说,就是我们大脑中用来获取、存储、保留和随后提取信息的一套系统。人脑中存在着几种不同的记忆方式。
-
感觉记忆:这是记忆的第一步,它能在刺激消失后短暂保留感觉信息(如视觉和听觉)。比如你看到一张图片或听到一段音乐,感觉记忆帮你保留这些信息几秒钟,分为图像记忆、回声记忆和触觉记忆。
-
短期记忆或 工作记忆:当我们意识到某些信息并需要用它们来进行学习和推理等复杂认知任务时,这些信息就存储在短期记忆中。研究发现,短期记忆能存储约 7 个信息单元,时间大约 20-30 秒(参见 Miller 1956)。
-
长期记忆:长期记忆的储存时间惊人地长,从几天到几十年不等,几乎没有容量上限。它分为两个部分:
- 显性记忆:包括我们可以有意识回忆起的事实和事件记忆,比如过去的经历和知识点。
- 隐性记忆:这是一种无意识的记忆,主要和自动化的技能和习惯有关,比如骑车或打字。
图 8. 人类记忆分类示意图。
简单来说,我们可以这样理解:
- 感觉记忆就像是大脑学习和识别基础输入(如文本和图片)的方式;
- 短期记忆帮助我们在有限的时间和空间内学习和处理信息;
- 长期记忆则是大脑中用来储存和检索大量信息的“硬盘”。
最大内积搜索(MIPS)简介
通过使用外部内存,我们能有效地扩大电脑的“注意力跨度”。一种标准的做法是将数据的“嵌入表示”保存在一个特殊的数据库中,这个数据库可以快速进行最大内积搜索(MIPS)。为了让搜索速度更快,人们通常会使用一种叫做 近似最近邻(ANN) 的算法,这种算法能返回大约排名前 k 的邻居,虽然牺牲了一点点的准确性,但速度提升很多。
为了实现快速的 MIPS,人们常常选用以下几种 ANN 算法:
- LSH(局部敏感哈希):它使用一种特殊的 哈希 函数,使得相似的数据会被映射到同一个“桶”中,而这些“桶”的数量要比数据的数量要少得多。
- ANNOY(近似最近邻哦耶):它的核心是一种叫做 随机投影树 的数据结构,这种结构包括很多二叉树。每个非叶子节点都代表一个超平面,这个超平面将数据空间分成两半,每个叶子节点则存储一个数据点。这些树是独立随机生成的,所以在一定程度上模拟了哈希函数的作用。在进行 ANNOY 搜索时,系统会在所有的树中进行搜索,找到离搜索目标最近的数据,然后将结果整合起来。这个方法在某种程度上类似于 KD 树,但更容易扩展。
-
HNSW:HNSW 受到“小世界网络”理论的启发,该理论认为网络中的任何节点都可以在很少的步骤内到达其他大多数节点——就像社交网络中大家常说的“六度分隔”现象。HNSW 的结构就像是多层的小世界网络,底层有我们的数据,而中间层则像是搭建了一些高速通道,帮助我们更快地找到信息。搜索数据时,HNSW 会从顶层的一个随机点开始,然后一层层向下,直到找到目标数据。在这个过程中,顶层的每一步都可以跨越很大的数据区域,而底层则更专注于精细调整搜索结果的准确性。
-
FAISS:FAISS 是 Facebook 的人工智能搜索工具,它假设高维空间里的数据分布是呈高斯分布的,也就是说,数据点会自然地形成一些集群。FAISS 的做法是先将这些集群标出来,然后在每个集群里细化搜索。简而言之,先大致定位,再精细查找。
-
ScaNN:ScaNN 的独特之处在于它采用了一种叫做“各向异性向量量化”的技术。简单来说,它在量化数据点时,更注重保持数据点与查询点之间的内积和原始距离的相似性,而不仅仅是找一个最近的量化中心。
图 9:这是几种 MIPS 算法的对比图,测量标准是 recall@10。(图片来源:Google Blog, 2020)
想要了解更多 MIPS 算法及其性能比较,可以访问 ann-benchmarks.com。
组件三:使用工具的艺术
人类使用工具这一点非常了不起,并让我们与众不同。我们能创造、改造并运用各种各样的工具,以实现那些超越了我们身体和思维能力的事情。给 LLMs(大语言模型)配上这些“外挂”,就能大大增强它们的能力和功能。
图 10:上图是一只在水中漂浮的海獭,它正在用石头敲击开贝壳。其他动物也会使用工具,但是与人类相比,他们使用工具的方式简单多了。(图片来自:动物使用工具)
MRKL (Karpas 等人,2022),是“Modular Reasoning, Knowledge and Language”的缩写,它是一个为自主代理设计的神经 – 符号架构。一个 MRKL 系统是由很多“专家”模块组成的,而通用型 LLMs 则扮演着路由器的角色,把问题“导航”给最擅长解决它的专家模块。这些专家模块有的基于神经网络(比如深度学习模型),有的则是符号型的(比如数学计算器、货币转换器和天气 API)。
科学家们用算术测试为例,进行了一个实验,研究细调后的 LLM 如何调用计算器。实验发现,LLM(采用 7B Jurassic1-large 模型)在解决口头表达的数学题时,比直接给出的数学题更为困难,因为它不能准确无误地提取基础算术运算中的正确参数。结果突显了一点:只有当外部符号工具可以稳定运行时,正确地知道何时以及如何使用这些工具才显得尤为重要,而这一切都取决于 LLM 的能力。
TALM(即 Tool Augmented Language Models,由 Parisi 等人于 2022 年提出)和 Toolformer(由 Schick 等人于 2023 年提出)都是通过细调语言模型,让其学会使用外部工具的 API。模型训练数据集的扩充,是基于新加入的 API 调用注释是否能提升模型输出质量来决定的。更多相关细节,可以参阅 Prompt Engineering 里的“External APIs”一节。
值得一提的是,ChatGPT 的 Plugins 功能 和 OpenAI API 的 函数调用功能 都是 LLM 结合工具使用能力的实践例子。这些工具 API 集合可以是由第三方开发者提供(如 Plugins 功能),也可以是用户自定义的(如函数调用功能)。
HuggingGPT (Shen et al. 2023) 是一个独特的框架,它运用 ChatGPT 作为任务的指挥中心,从 HuggingFace 平台上挑选出合适的模型来执行任务。这个选择过程是基于对模型的描述分析,而它的“回应”方式则是通过总结各个模型执行任务后的结果。
图 11. 这是一张简单展示 HuggingGPT 如何运作的示意图。(图片来源:Shen et al. 2023)
简单来说,整个系统可以分为 4 个主要阶段:
(1) 任务规划:在这个阶段,LLM(大语言模型)就像是一个“大脑”,它将用户的请求分解成多个小任务。每一个小任务都有四个重要的属性,分别是:任务的类型、ID、依赖关系和参数。而 LLN 是通过 few-shot 示例来学习和指导如何更好地分解和规划这些任务的。
指导说明:
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 助手需从模型列表中协助用户挑选出一个最适合处理用户请求的模型。AI 助手只需输出最合适的模型的 id,并附上选择理由。输出格式必须是严格的 JSON 格式:“id”:“id”,“reason”:“选择的详细原因”。我们为你准备了一份模型列表{{ Candidate Models }},请从中选择一个模型。
(3) 执行任务:专家模型将针对特定任务进行操作,并记录下执行结果。
操作说明:
AI 助手通过输入和推断结果描述各个步骤和最终结果。过程包括:用户输入{{用户输入}},任务计划{{任务}},选择模型{{模型分配}}和执行任务{{预测}}。首先,助手直截了当地回答用户的问题,然后以第一人称的方式呈现任务过程、分析和推断结果。如果推断结果涉及文件路径,助手会提供完整路径。
在“响应生成”阶段,LLM 收到执行的结果,并简洁地向用户呈现。
若要将 HuggingGPT 运用到实际,还需克服几个挑战:首先,由于与其他模型的交互和 LLM 的多轮推断,使得整个过程较为缓慢,需要提高效率;其次,为了准确执行复杂任务,它需要一个较长的上下文窗口;最后,LLM 的输出和外部模型服务的稳定性也有待提高。
API-Bank(由 Li 等人在 2023 年提出)是一个评估工具增强型 LLM 性能的基准测试,它包含 53 个常用 API 工具,一个完整的工具增强型 LLM 工作流程和 264 个注释对话(涉及 568 个 API 调用)。API 涉及多个领域,如搜索引擎、计算器、日历查询、智能家居控制、日程管理、健康数据管理和账户验证流程等。鉴于 API 种类繁多,LLM 首先通过 API 搜索引擎找到合适的 API,然后参照相应文档进行调用。
图 12. 图片展示了在 API-Bank 流程中,LLM 是如何做出 API 调用的——这里用伪代码的方式呈现出来。(图片来源:Li et al. 2023)
API-Bank 流程让 LLM 要做出一系列决策,每做一个决策,我们都可以评估它的准确性。这些决策包括:
- 判断是否需要使用 API 调用。
- 选出正确的 API 进行调用:如果效果不理想,LLM 还得反复调整 API 输入内容(比如,为搜索引擎 API 选定搜索关键词)。
- 根据 API 的返回结果做出响应:如果返回的结果不够好,模型可以选择微调并再次发起调用。
这个基准测试就是为了评估代理(agent)使用工具的能力,总共分三个等级来考核:
- Level-1 主要看模型能不能准确 发起 API 调用。模型需根据 API 的描述,判断是否需要调用指定 API,然后准确无误地发起调用,并对 API 返回的结果做出适当的响应。
- Level-2 考核的是模型 检索 API 的能力。模型需要寻找可能满足用户需求的 API,并通过阅读相关文档学会如何使用它们。
- Level-3 则是检验模型是否能 有计划地调用 API。当面对用户提出的模糊需求(比如组织团队会议,或者为出行预订飞机票/酒店/餐厅),模型可能需要发起多次 API 调用来满足需求。
案例探索
探秘科学发现助手
ChemCrow (Bran 等人,2023) 是一个专注于化学领域的工具,它通过集成了 13 个专家精心设计的小工具,助力科学家们在有机合成、药物开发和新材料设计等方面更轻松地开展工作。ChemCrow 的工作流程是建立在 LangChain 平台上的,整个系统的运作模式是根据先前在 ReAct 和 MRKLs 中描述的原理,同时融合了 CoT 推理和与特定任务相关的各种工具:
- LLM(大语言模型)首先需要了解每一个小工具的名称、用途和它们处理信息的方式。
- 随后,它会根据用户的提问,灵活运用这些小工具给出回答。这个过程也会遵循 ReAct 格式的步骤 – 即“思考,行动,行动输入,观察”。
有趣的是,虽然从 LLM 的角度来看,GPT-4 和 ChemCrow 的表现几乎持平,但如果换成是化学领域的专家来评判,他们更看重的是答案的实用性和科学准确性,从这一点来看 ChemCrow 的表现其实要远超 GPT-4。这也暗示了,当我们用 LLM 来自评其在某个需要深入专业知识的领域的表现时,可能会存在一些盲点和误判,因为 LLM 可能没有足够的“知识深度”来准确识别和评估其回答的准确性。
在 2023 年的一项研究中,Boiko 等人探索了大语言模型(LLM)在科学发现领域的应用,这种智能代理可以自行设计、计划并实施复杂的科学实验。它们可以浏览网页、阅读文档、执行代码、控制机器人进行实验,并与其他大语言模型互动。
例如,当有人要求这个智能代理“开发一种新型抗癌药物”时,它会进行以下操作:
- 询问目前抗癌药物研发的最新趋势;
- 确定一个研究目标;
- 请求设计一种针对目标的化合物;
- 一旦找到合适的化合物,就尝试着进行合成。
研究者还讨论了使用这种代理的风险,尤其是在非法药品和生物武器方面。他们为代理提供了一份包含已知化学武器的清单,并要求其尝试合成。结果,11 个请求中有 4 个(36%)得到了积极的回应,代理甚至尝试查询文档来执行合成程序。另外 7 个请求被拒绝,其中 5 个是在网络搜索之后被拒绝的,2 个则仅仅是基于输入提示就被拒绝了。
生成性代理模拟#
在一项名为“生成性代理”的实验中 (Park, et al. 2023),研究者们创造了一个生动有趣的虚拟世界。在这个世界里,有 25 个由 LLM(大语言模型)驱动的虚拟角色,它们仿佛生活在“模拟人生”的游戏环境中,相互交往和互动。这些智能的虚拟角色能够展现出类似人类的行为,让交互应用变得更加生动和真实。
这些虚拟角色之所以能如此“活灵活现”,是因为“生成性代理”巧妙地将 LLM 融合了记忆、计划和反思等多种机制。这使得这些虚拟角色不仅可以依据过去的经验做出反应,还能与其他角色进行协作和互动。
-
Memory 流:这是一个长期记忆单元(外部数据库),用于记录代理在使用自然语言时的各种经验。
- 每一项记录都是一个观测,也就是代理直接提供的事件。- 代理之间互相交流也会产生新的自然语言表述。
-
Retrieval 模型:该模型通过筛选相关性、新近性和重要性,为代理行为提供上下文指导。
- 新近性:近期的事件会得到更高的评分
- 重要性:能够辨别日常记忆和核心记忆。可直接向 LM 提问获取。
- 相关性:取决于其与当前情况或查询的关联程度。
-
Reflection 机制:这个机制会随时间推移,把记忆整合成更高层次的推断,从而指导代理未来的行动。它们是对过去事件的高层次概括(注意这和 self-reflection 有细微差别)
- 通过向 LM 提供 100 个最近的观测,来产生 3 个重要的高层问题,然后再让 LM 回答这些问题。
-
Planning & Reacting:该环节将反思和环境信息转化为具体行动。
- 计划主要是为了在不同时刻优化可信度。
- 提示模板:
{ 关于代理 X 的简介 }。以下是 X 今天的宏观计划:1)
- 在规划和应对过程中,都会考虑到代理之间的关系以及一个代理对另一个代理的观察。
- 环境信息是以树状结构展现的。
图 13. 生成性代理架构。(图片来源:Park et al. 2023)
这个有趣的模拟实验呈现了一些自发产生的社交行为,比如信息的传播,记忆关系(例如两个“代理人”能延续之前的话题进行交谈),以及社交活动的协调(比如,组织并举办派对,邀请了许多人参加)。
验证概念的示例
AutoGPT 这个项目引起了众多人的关注,因为它展示了创建一个以 LLM 为主要控制器的自主“代理人”的可能性。虽然由于其自然语言界面的问题,它在可靠性方面存在一些问题,但它无疑是一个很酷的概念验证展示。AutoGPT 大量的代码是用于解析格式的。
下面是 AutoGPT 使用的系统信息示例,其中 {{...}}
是用户的输入内容:
You are {{ai-name}}, {{user-provided AI bot description}}.Your decisions must always be made independently without seeking user assistance. Play to your strengths as an LLM and pursue simple strategies with no legal complications.GOALS:1. {{user-provided goal 1}}2. {{user-provided goal 2}}3. ...4. ...5. ...Constraints:1. ~4000 word limit for short term memory. Your short term memory is short, so immediately save important information to files.2. If you are unsure how you previously did something or want to recall past events, thinking about similar events will help you remember.3. No user assistance4. Exclusively use the commands listed in double quotes e.g. "command name"5. Use subprocesses for commands that will not terminate within a few minutesCommands:1. Google Search: "google", args: "input": "<search>"2. Browse Website: "browse_website", args: "url": "<url>", "question": "<what_you_want_to_find_on_website>"3. Start GPT Agent: "start_agent", args: "name": "<name>", "task": "<short_task_desc>", "prompt": "<prompt>"4. Message GPT Agent: "message_agent", args: "key": "<key>", "message": "<message>"5. List GPT Agents: "list_agents", args:6. Delete GPT Agent: "delete_agent", args: "key": "<key>"7. Clone Repository: "clone_repository", args: "repository_url": "<url>", "clone_path": "<directory>"8. Write to file: "write_to_file", args: "file": "<file>", "text": "<text>"9. Read file: "read_file", args: "file": "<file>"10. Append to file: "append_to_file", args: "file": "<file>", "text": "<text>"11. Delete file: "delete_file", args: "file": "<file>"12. Search Files: "search_files", args: "directory": "<directory>"13. Analyze Code: "analyze_code", args: "code": "<full_code_string>"14. Get Improved Code: "improve_code", args: "suggestions": "<list_of_suggestions>", "code": "<full_code_string>"15. Write Tests: "write_tests", args: "code": "<full_code_string>", "focus": "<list_of_focus_areas>"16. Execute Python File: "execute_python_file", args: "file": "<file>"17. Generate Image: "generate_image", args: "prompt": "<prompt>"18. Send Tweet: "send_tweet", args: "text": "<text>"19. Do Nothing: "do_nothing", args:20. Task Complete (Shutdown): "task_complete", args: "reason": "<reason>"Resources:1. Internet access for searches and information gathering.2. Long Term memory management.3. GPT-3.5 powered Agents for delegation of simple tasks.4. File output.Performance Evaluation:1. Continuously review and analyze your actions to ensure you are performing to the best of your abilities.2. Constructively self-criticize your big-picture behavior constantly.3. Reflect on past decisions and strategies to refine your approach.4. Every command has a cost, so be smart and efficient. Aim to complete tasks in the least number of steps.You should only respond in JSON format as described belowResponse Format:{ "thoughts": { "text": "thought", "reasoning": "reasoning", "plan": "- short bulletedn- list that conveysn- long-term plan", "criticism": "constructive self-criticism", "speak": "thoughts summary to say to user" }, "command": { "name": "command name", "args": { "arg name": "value" } }}Ensure the response can be parsed by Python json.loads
GPT – Engineer 则是另一个计划,目标是根据用自然语言描述的任务来创建整个代码库。GPT-Engineer 被指导去考虑构建小组件的清单,并在需要的时候询问用户以获取必要的澄清。
下面是一个由 GPT – Engineer 发送给 OpenAI ChatCompletion 端点用于任务澄清的样本对话,用户的输入被 {{ user input text }}
所包围。
[ { "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)nnClarifying 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.}}nnIs 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 则是实际的代码内容:FILENAMECODE首先,你需要从“entrypoint”文件开始工作,然后依次查看和处理它所引入的文件。请注意,你编写的代码必须是可以正常运行的,不可以有任何占位符。命名文件时,请遵循适用的语言和框架的最佳实践。每个文件中要包括所有必要的导入和类型定义,而且不同文件中的代码必须是可以协同工作的。在编写代码时,如果对某个部分感到不太确定,可以先写一个可能是正确的版本。记得包含所有必要的模块依赖和包管理器依赖定义文件。在最后提交前,要仔细检查,确保文件中包含了架构的所有部分。还有一些实用的小知识:通常,不同的类应该放在不同的文件中。对于 Python 代码,你需要创建一个合适的 requirements.txt 文件;对于 NodeJS,需要创建一个合适的 package.json 文件。在每个函数定义的开头,要简短注释说明其用途,对于复杂的逻辑也要加以注释解释。在编写代码时,请遵循相关语言的最佳实践,确保你写的代码能够清晰地解释你定义的包或项目是什么。在使用 Python 时,我们更喜欢使用以下工具:- pytest- dataclasses
对话样本:
[ { "role": "system", "content": "You will get instructions for code to write.nYou will write a very long answer. Make sure that every detail of the architecture is, in the end, implemented as code.nMake sure that every detail of the architecture is, in the end, implemented as code.nnThink step by step and reason yourself to the right decisions to make sure we get it right.nYou will first lay out the names of the core classes, functions, methods that will be necessary, as well as a quick comment on their purpose.nnThen you will output the content of each file including ALL code.nEach file must strictly follow a markdown code block format, where the following tokens must be replaced such thatnFILENAME is the lowercase file name including the file extension,nLANG is the markup code block language for the code's language, and CODE is the code:nnFILENAMEn```LANGnCODEn```nnYou will start with the "entrypoint" file, then go to the ones that are imported by that file, and so on.nPlease note that the code should be fully functional. No placeholders.nnFollow a language and framework appropriate best practice file naming convention.nMake sure that files contain all imports, types etc. Make sure that code in different files are compatible with each other.nEnsure to implement all code, if you are unsure, write a plausible implementation.nInclude module dependency or package manager dependency definition file.nBefore you finish, double check that all parts of the architecture is present in the files.nnUseful to know:nYou almost always put different classes in different files.nFor Python, you always create an appropriate requirements.txt file.nFor NodeJS, you always create an appropriate package.json file.nYou always add a comment briefly describing the purpose of the function definition.nYou try to add comments explaining very complex bits of logic.nYou always follow the best practices for the requested languages in terms of describing the code written as a definednpackage/project.nnnPython toolbelt preferences:n- pytestn- dataclassesn" }, # … same conversation as earlier, ended with "Make your own assumptions and state them explicitly before starting". { "role": "assistant", "content": "Assumptions:n1. Model: The model will contain the game's data, such as level information, character states, and enemy positions.n2. View: The view will handle the game's visuals, including rendering the game objects, backgrounds, and updating the display.n3. Controller: The controller will manage user input, such as keyboard controls, and update the model accordingly.nnWith these assumptions in mind, is there any specific aspect of the keyboard control implementation you would like me to clarify?" }, { "role": "user", "content": "Please now remember the steps:nnThink step by step and reason yourself to the right decisions to make sure we get it right.nFirst lay out the names of the core classes, functions, methods that will be necessary, As well as a quick comment on their purpose.nnThen you will output the content of each file including ALL code.nEach file must strictly follow a markdown code block format, where the following tokens must be replaced such thatnFILENAME is the lowercase file name including the file extension,nLANG is the markup code block language for the code's language, and CODE is the code:nnFILENAMEn```LANGnCODEn```nnPlease note that the code should be fully functional. No placeholders.nnYou will start with the "entrypoint" file, then go to the ones that are imported by that file, and so on.nFollow a language and framework appropriate best practice file naming convention.nMake sure that files contain all imports, types etc. The code should be fully functional. Make sure that code in different files are compatible with each other.nBefore you finish, double check that all parts of the architecture is present in the files.n" }]
挑战#
在深入了解以 LLM(大语言模型)为核心的智能代理的主要理念和示例之后,我发现这些系统普遍存在几个问题:
-
上下文长度有限:由于上下文容量有限,这使得系统难以包含丰富的历史信息、详细指令、API 调用上下文和响应。设计系统时必须考虑这个通信带宽的限制。长或无限的上下文窗口能帮助系统通过反思学习,从而避免重复过去的错误。虽然通过矢量存储和检索可以访问更多的知识,但其表达能力不如全注意力机制强大。
-
长期规划和分解任务困难:在长时间线上做计划和有效探索解决方案空间始终是一个难题。LLM 在遇到未预见的错误时,很难及时调整计划,这使它们不如人类通过实践学习那样稳健。
-
自然语言接口的可靠性有待提高:现有的智能代理系统主要通过自然语言让 LLM 和其他外部模块(比如内存和工具)进行交互。但是,模型输出的可靠性是个问题,因为 LLM 有时会产生格式错误,甚至拒绝遵从某些指令。这也是为什么很多演示代码都集中在解析模型输出上。