AutoGPT 进化实战:用 LangChain 从零打造你的自主 AI 代理

目录

  1. 什么是 AutoGPT?
  2. LangChain:打造 LLM 应用的瑞士军刀
  3. 环境配置和技术准备
  4. 第一步:定义核心任务框架
  5. 第二步:任务分解与执行的核心逻辑
  6. 第三步:集成工具和增强能力
  7. 第四步:加入记忆系统
  8. 完整实现:一个简易版 AutoGPT
  9. 总结

在这里插入图片描述

近年来,人工智能的快速发展催生了诸多令人兴奋的应用,而 AutoGPT 更是其中一颗耀眼的明星。AutoGPT 是一个基于 ChatGPT 的下一代多任务自动代理系统,能够连续、自动地执行多步骤任务,为开发者提供了解决复杂问题的新思路。

在这篇文章中,我们将深入拆解 AutoGPT 的核心理念,并通过 LangChain 框架,从零开始逐步实现一个简易版的 AutoGPT,让你不仅了解它的内涵,更能亲手打造它。


1. 什么是 AutoGPT?

简单来说,AutoGPT 是一个基于 LLMs 的自主执行系统,能够:

  1. 根据目标生成自己的行动计划。它不仅仅是被动地响应用户的单次指令,更能像一个项目经理一样,自主规划完成目标的步骤。
  2. 自主完成任务并学习调整。在执行过程中,AutoGPT 会监控进度,遇到问题会尝试调整策略,而不是简单地报错退出。
  3. 与外部资源交互(如搜索、调用 API、存储文件等)。这让它能够突破 LLM 本身的知识局限,连接真实世界的信息和工具。

它的关键能力在于将大语言模型(LLM,如 OpenAI 的 GPT-4)与工具、记忆以及自反思机制结合,从而变成一个“连续自主代理”。其典型的工作流程可以用下图表示:

Yes
No
Yes
No
用户目标
任务分解
子任务 1
执行子任务 1
完成?
子任务 2
调整策略
执行子任务 2
完成?
...
目标完成

用一句话概括 AutoGPT 是什么? 那就是 “让 LLM 给自己渐进式地产生 Prompt 数据,并不断执行”。它不再是被动执行指令的工具,而是一个能够自主思考、规划和行动的智能体。


2. LangChain:打造 LLM 应用的瑞士军刀

我们之所以选择 LangChain 来构建简易版 AutoGPT,是因为它为构建复杂的 LLM 应用提供了强大的工具支持,堪称 LLM 开发的“瑞士军刀”。LangChain 的核心优势在于其模块化和灵活性,主要体现在以下几个方面:

  1. Prompt 模块:LangChain 提供了强大的 PromptTemplate 功能,可以帮助开发者更有效地管理和动态生成提示词,这是驱动 LLM 工作的核心。
  2. 工具集成:LangChain 简化了外部工具的接入流程。无论是搜索引擎、Python REPL,还是文件存储等,都可以通过 LangChain 提供的接口轻松集成到 LLM 应用中。
  3. 记忆模块:对于需要上下文理解和长期对话的应用,LangChain 的 Memory 模块可以帮助 LLM 记住任务执行历史和对话内容,实现更连贯的交互体验。
  4. 链结构 (Chains):LangChain 的 Chains 功能允许开发者将多个 LLM 调用、工具调用等操作串联起来,构建复杂的任务执行流,这正是实现 AutoGPT 这种自主代理的关键。

接下来,我们将使用 LangChain 把这些模块组合在一起,亲手实现一个简易版 AutoGPT,让你体会 LangChain 的强大和便捷。


3. 环境配置和技术准备

在开始动手之前,我们需要先配置好开发环境。请确保你已经安装了以下工具和库:

pip install openai langchain python-dotenv

环境说明:

  • OpenAI API:你需要拥有 OpenAI 的 GPT-4 API 密钥。你可以在 OpenAI 官网申请 API 密钥并充值。
  • Python 环境:建议使用 Python 3.8 或更高版本。
  • LangChain 和 OpenAI 库:通过 pip install 命令安装,这是我们构建 AutoGPT 的核心依赖。
  • python-dotenv:用于安全地管理 API 密钥等敏感信息,避免硬编码在代码中。

安装完成后,创建一个 .env 文件,并将你的 OpenAI API 密钥配置在其中:

OPENAI_API_KEY=你的_API_密钥

然后,在你的 Python 代码中,可以使用 dotenv 库加载环境变量:

from dotenv import load_dotenv
load_dotenv()
import os

api_key = os.getenv("OPENAI_API_KEY")

这样,我们就可以在代码中安全地使用 API 密钥了。环境准备就绪,让我们开始一步步构建简易版 AutoGPT。


4. 第一步:定义核心任务框架

AutoGPT 的核心是一个“任务执行器”(Task Executor)。它需要具备以下基础功能:

  1. 接受用户输入的目标:这是 AutoGPT 接收到的初始指令。
  2. 解析目标并定义初步的子任务:将大的目标分解成可执行的小步骤。
  3. 执行这些子任务,同时监控结果:按照分解的子任务顺序执行,并获取执行结果。

在代码中,我们很容易将这部分功能抽象为一个基础类 TaskExecutor

# task_executor.py

from langchain.prompts import PromptTemplate
from langchain.chat_models import ChatOpenAI
import os
from dotenv import load_dotenv

load_dotenv()

class TaskExecutor:
    def __init__(self, api_key=None, model="gpt-4"):
        # 初始化 OpenAI 模型
        if api_key is None:
            api_key = os.getenv("OPENAI_API_KEY")
        self.llm = ChatOpenAI(openai_api_key=api_key, model=model)

    def decompose_task(self, goal):
        """将目标解析为子任务"""
        prompt_template = PromptTemplate(
            input_variables=["goal"],
            template="""
            你的目标是:{goal}
            请将该目标分解为简单的步骤,每一步代表清晰的可执行子任务。
            返回的子任务请以列表形式呈现。
            """
        )
        prompt = prompt_template.format(goal=goal)
        response = self.llm.predict(prompt)
        return response.strip().split("\n") # 假设 LLM 返回的任务列表以换行符分隔

    def execute_task(self, task):
        """执行一个子任务"""
        print(f"执行子任务: {task}") # 打印当前执行的任务
        return self.llm.predict(task)

代码解释:

  • TaskExecutor:这是我们 AutoGPT 的基本执行器类。
  • __init__ 方法:初始化 ChatOpenAI 模型,使用 GPT-4 模型(你可以根据需要修改 model 参数)。API 密钥从环境变量中获取。
  • decompose_task 方法
    • 接收用户 goal 作为输入。
    • 使用 PromptTemplate 创建一个提示词模板,指示 LLM 将目标分解为子任务列表。
    • 调用 llm.predict(prompt) 获取 LLM 的响应,即分解后的子任务列表。
    • 使用 response.strip().split("\n") 将 LLM 返回的字符串解析为子任务列表(假设子任务之间用换行符分隔)。
  • execute_task 方法
    • 接收一个子任务 task 作为输入。
    • 调用 llm.predict(task) 执行子任务,实际上是让 LLM 完成这个子任务。
    • 打印正在执行的任务,方便我们观察 AutoGPT 的工作过程。

这个 TaskExecutor 类虽然简单,但已经具备了 AutoGPT 的雏形:接收目标、分解任务、执行任务


5. 第二步:任务分解与执行的核心逻辑

在一个完整的 AutoGPT 工作流程中,处理多步骤任务的能力至关重要。我们需要在 TaskExecutor 的基础上,添加一个任务循环,实现:

  1. 按顺序执行分解出的子任务
  2. 监控每个子任务的执行结果
  3. 根据执行结果判断是否需要调整任务或继续执行下一步(在简易版中,我们暂时简化为顺序执行所有子任务)。

代码实现

我们创建一个 TaskFlowExecutor 类,继承自 TaskExecutor,并添加任务流程控制的逻辑:

# task_flow_executor.py
from task_executor import TaskExecutor

class TaskFlowExecutor(TaskExecutor):
    def __init__(self, api_key=None, model="gpt-4"):
        super().__init__(api_key, model)
        self.completed_steps = [] # 记录已完成的步骤,虽然当前版本暂未使用

    def execute_task_flow(self, goal):
        """按顺序完成任务流程"""
        # 第一步:先分解子任务
        sub_tasks = self.decompose_task(goal)
        print(f"任务分解结果:\n{sub_tasks}")

        # 第二步:循环执行子任务
        for task in sub_tasks:
            print(f"\n正在执行任务:{task}")
            result = self.execute_task(task)
            self.completed_steps.append((task, result)) # 记录任务和结果
            print(f"任务执行结果: \n{result}")

        print("\n所有子任务已完成!")

代码解释:

  • TaskFlowExecutor:继承自 TaskExecutor,扩展了任务流程控制功能。
  • __init__ 方法:调用父类 TaskExecutor__init__ 方法进行初始化,并初始化 completed_steps 列表,用于记录已完成的任务步骤和结果(虽然在当前简易版中暂时没有使用这个列表进行进一步的逻辑处理,但在更复杂的版本中,可以利用这个列表进行任务状态监控和调整)。
  • execute_task_flow 方法
    • 接收用户 goal 作为输入。
    • 调用 self.decompose_task(goal) 分解目标任务,获取子任务列表。
    • 任务循环:遍历 sub_tasks 列表,按顺序执行每个子任务:
      • 打印当前正在执行的任务。
      • 调用 self.execute_task(task) 执行子任务。
      • 将任务和执行结果添加到 self.completed_steps 列表中。
      • 打印任务执行结果。
    • 循环结束后,打印 “所有子任务已完成!” 提示。

运行示例:

创建一个主程序文件 main.py,并添加以下代码:

# main.py
from task_flow_executor import TaskFlowExecutor

if __name__ == "__main__":
    executor = TaskFlowExecutor()
    executor.execute_task_flow("为 ‘LangChain’ 编写一个 300 字的简介,并在结尾加上三个相关标签")

在终端运行 python main.py,你将看到类似以下的输出:

任务分解结果:
['1. 了解 LangChain 的核心概念和功能。', '2. 撰写 300 字左右的简介,突出 LangChain 的特点和优势。', '3. 确定 3 个与 LangChain 相关的标签。', '4. 将简介和标签整合输出。']

正在执行任务:1. 了解 LangChain 的核心概念和功能。
执行子任务: 1. 了解 LangChain 的核心概念和功能。
任务执行结果:
LangChain 是一个用于开发由语言模型驱动的应用程序的框架。它可以实现各种复杂的任务,例如文档问答、聊天机器人、代码理解和生成、API 交互等等。LangChain 的核心思想是将大型语言模型与各种外部数据源和计算资源连接起来,从而使它们能够执行更强大的任务。

正在执行任务:2. 撰写 300 字左右的简介,突出 LangChain 的特点和优势。
执行子任务: 2. 撰写 300 字左右的简介,突出 LangChain 的特点和优势。
任务执行结果:
LangChain 是一个强大的框架,旨在简化和加速基于大型语言模型(LLMs)的应用程序开发。它提供了一套全面的工具、组件和接口,使开发者能够轻松地将 LLMs 与各种数据源和外部工具集成。LangChain 的核心优势在于其模块化和灵活性,开发者可以根据需求自由组合和定制各种组件,构建出功能丰富的 LLM 应用。无论是构建智能聊天机器人、文档问答系统,还是进行复杂的数据分析和生成任务,LangChain 都能提供强大的支持。它支持多种 LLMs 模型,并提供了丰富的文档和社区支持,降低了 LLM 应用开发的门槛。使用 LangChain,开发者可以更专注于应用逻辑的创新,而无需从零开始构建 LLM 集成框架。

正在执行任务:3. 确定 3 个与 LangChain 相关的标签。
执行子任务: 3. 确定 3 个与 LangChain 相关的标签。
任务执行结果:
#LangChain #LLM应用 #AI开发

正在执行任务:4. 将简介和标签整合输出。
执行子任务: 4. 将简介和标签整合输出。
任务执行结果:
LangChain 是一个强大的框架,旨在简化和加速基于大型语言模型(LLMs)的应用程序开发。它提供了一套全面的工具、组件和接口,使开发者能够轻松地将 LLMs 与各种数据源和外部工具集成。LangChain 的核心优势在于其模块化和灵活性,开发者可以根据需求自由组合和定制各种组件,构建出功能丰富的 LLM 应用。无论是构建智能聊天机器人、文档问答系统,还是进行复杂的数据分析和生成任务,LangChain 都能提供强大的支持。它支持多种 LLMs 模型,并提供了丰富的文档和社区支持,降低了 LLM 应用开发的门槛。使用 LangChain,开发者可以更专注于应用逻辑的创新,而无需从零开始构建 LLM 集成框架。
#LangChain #LLM应用 #AI开发

所有子任务已完成!

可以看到,TaskFlowExecutor 已经能够根据用户目标,分解出子任务并按顺序执行,初步展现了 AutoGPT 的工作流程。但这还只是一个非常基础的版本,能力还比较有限。接下来,我们将进一步增强它的能力。


6. 第三步:集成工具和增强能力

现阶段,我们的简易版 AutoGPT 只能使用 OpenAI 的 LLM 本身的能力,但 AutoGPT 的强大之处很大程度上来自于其 工具集成能力,例如调用搜索引擎获取最新信息、使用 Python REPL 执行代码、操作文件等等。

我们可以利用 LangChain 的 Tools 模块,让我们的 TaskFlowExecutor 具备调用外部工具的能力。这里我们以集成 互联网搜索工具 为例,演示如何扩展 AutoGPT 的能力。

6.1 安装搜索工具依赖

首先,我们需要安装 google-search-results 这个 Python 库,它是一个非官方的 Google Search API 客户端,可以方便地进行网页搜索:

pip install google-search-results

同时,你需要在 SerpApi 官网注册账号并获取 API 密钥,SerpApi 提供了 Google Search API 的服务,google-search-results 库底层就是调用 SerpApi 的接口。将 SerpApi 密钥也添加到 .env 文件中:

OPENAI_API_KEY=你的_API_密钥
SERPAPI_API_KEY=你的_SERPAPI_密钥

6.2 更新代码:集成搜索工具

接下来,我们创建一个 ToolIntegratedTaskExecutor 类,继承自 TaskFlowExecutor,并集成搜索工具:

# tool_integrated_task_executor.py
from task_flow_executor import TaskFlowExecutor
from langchain.tools import Tool
from langchain.utilities import SerpAPIWrapper
import os

class ToolIntegratedTaskExecutor(TaskFlowExecutor):
    def __init__(self, api_key=None, model="gpt-4"):
        super().__init__(api_key, model)
        # 初始化 SerpAPI 搜索工具
        serpapi_api_key = os.getenv("SERPAPI_API_KEY")
        self.search_tool = SerpAPIWrapper(serpapi_api_key=serpapi_api_key)
        self.tools = [
            Tool(
                name="搜索",
                func=self.search_tool.run,
                description="""在互联网上搜索信息。
                                 输入应该是搜索查询词。"""
            )
        ]

    def execute_task_with_tools(self, task):
        """结合工具完成子任务"""
        # 让 LLM 决定是否需要使用工具,以及使用哪个工具
        tool_choice_prompt_template = PromptTemplate(
            input_variables=["task", "tool_descriptions"],
            template="""
            你有一个任务需要完成: {task}
            你可以使用以下工具:
            {tool_descriptions}

            请判断是否需要使用工具来完成任务。
            如果需要,请明确指出需要使用哪个工具,并给出工具的输入。
            如果不需要,请直接给出完成任务的指令。

            请以如下格式返回:
            {{
                "tool_needed": true/false,
                "tool_name": "工具名称" (如果 tool_needed 为 true),
                "tool_input": "工具输入" (如果 tool_needed 为 true),
                "指令": "完成任务的指令" (如果 tool_needed 为 false,或工具调用后的下一步指令)
            }}
            """
        )

        tool_descriptions = "\n".join([f"- {tool.name}: {tool.description}" for tool in self.tools])
        tool_choice_prompt = tool_choice_prompt_template.format(
            task=task, tool_descriptions=tool_descriptions
        )

        tool_choice_response_str = self.llm.predict(tool_choice_prompt)
        print(f"工具选择响应 (JSON 格式):\n{tool_choice_response_str}") # 打印 JSON 格式的工具选择响应

        try:
            tool_choice_response = json.loads(tool_choice_response_str)
        except json.JSONDecodeError:
            print(f"JSON 解析错误,响应内容: {tool_choice_response_str}")
            return "工具选择响应 JSON 解析错误"

        if tool_choice_response.get("tool_needed", False):
            tool_name = tool_choice_response.get("tool_name")
            tool_input = tool_choice_response.get("tool_input")
            if tool_name and tool_input:
                print(f"调用工具: {tool_name}, 输入: {tool_input}")
                if tool_name == "搜索":
                    search_result = self.search_tool.run(tool_input)
                    return f"搜索结果:\n{search_result}"
                else:
                    return f"未知的工具名称: {tool_name}"
            else:
                return "工具名称或输入缺失"
        else:
            instruction = tool_choice_response.get("指令")
            if instruction:
                return self.execute_task(instruction)
            else:
                return "无需工具,但指令缺失"

代码解释:

  • ToolIntegratedTaskExecutor:继承自 TaskFlowExecutor,扩展了工具集成能力。
  • __init__ 方法
    • 调用父类 TaskFlowExecutor__init__ 方法进行初始化。
    • 初始化 SerpAPIWrapper 作为搜索工具,需要从环境变量中获取 SerpApi 密钥。
    • 创建 self.tools 列表,目前只包含一个 “搜索” 工具,使用 langchain.tools.Tool 定义工具,func 参数指定工具的执行函数,description 提供工具的描述,用于 LLM 判断是否使用该工具。
  • execute_task_with_tools 方法
    • 接收子任务 task 作为输入。
    • 工具选择 Prompt:使用 PromptTemplate 创建一个提示词,询问 LLM 是否需要使用工具来完成任务,如果需要,需要指定工具名称和输入。提示词中包含了可用的工具描述。
    • 调用 llm.predict(tool_choice_prompt) 获取 LLM 的响应,期望 LLM 返回 JSON 格式的工具选择结果。
    • 解析 JSON 响应:尝试将 LLM 返回的字符串解析为 JSON 对象。
    • 根据工具选择结果执行操作
      • 如果 tool_neededtrue,则根据 tool_nametool_input 调用相应的工具。目前只实现了 “搜索” 工具的调用。
      • 如果 tool_neededfalse,则从 JSON 响应中获取 “指令”,并调用 self.execute_task(instruction) 执行该指令,即让 LLM 直接完成任务。

运行示例:

修改 main.py 文件,使用 ToolIntegratedTaskExecutor 并执行一个需要搜索的任务:

# main.py
from tool_integrated_task_executor import ToolIntegratedTaskExecutor
import json # 导入 json 库

if __name__ == "__main__":
    executor = ToolIntegratedTaskExecutor()
    goal = "查找最近一周关于 LangChain 的新闻,并总结成 200 字左右的摘要"
    sub_tasks = executor.decompose_task(goal)
    print(f"任务分解结果:\n{sub_tasks}")

    for task in sub_tasks:
        print(f"\n正在执行任务:{task}")
        result = executor.execute_task_with_tools(task) # 使用 execute_task_with_tools
        print(f"任务执行结果: \n{result}")

    print("\n所有子任务已完成!")

再次运行 python main.py,你可能会看到类似以下的输出(输出结果会因为搜索结果的实时性而有所不同):

任务分解结果:
['1. 使用搜索引擎查找最近一周关于 LangChain 的新闻。', '2. 筛选和阅读搜索结果,提取关键信息。', '3. 将关键信息总结成 200 字左右的摘要。']

正在执行任务:1. 使用搜索引擎查找最近一周关于 LangChain 的新闻。
工具选择响应 (JSON 格式):
{
    "tool_needed": true,
    "tool_name": "搜索",
    "tool_input": "最近一周 LangChain 新闻"
}
调用工具: 搜索, 输入: 最近一周 LangChain 新闻
任务执行结果:
搜索结果:
最近一周 LangChain 新闻的搜索结果:

LangChain中文网- LangChain 是一个用于开发由语言模型驱动的应用程序的框架。它可以实现各种复杂的任务,例如文档问答、聊天机器人、代码理解和生成、API 交互等等。

如何评价langchain 这个框架? - 知乎 - 2023年6月6日 — langchain 确实降低了llm 应用开发的门槛, 提供了各种modules 和chains, 文档也算清晰, 对新手友好. 但是, 它的缺点也同样明显, ...

用 LangChain 和 GPT 快速构建聊天机器人应用 - InfoQ - 2023年5月29日 — LangChain 旨在为 LLM 应用开发提供全面的解决方案。它可以被用于聊天机器人、通用代理、问答等多种场景。LangChain 的主要特点包括: 模块化:LangChain ...

【技术干货】大型语言模型应用开发框架LangChain初探 - 华为云 - 2023年5月31日 — LangChain 是一个用于开发由语言模型驱动的应用程序的框架。LangChain 可以实现以下应用场景:. 1、数据增强型生成:. 将语言模型与您自己的数据 ...

LangChain 代理和工具 Agents and Tools - 掘金 - 2023年6月6日 — LangChain 代理和工具 Agents and Tools.  LangChain Agents. 代理是使用语言模型来决定采取哪些操作的链。与链不同的是,代理不以固定、预定的顺序执行。

... (更多搜索结果)

正在执行任务:2. 筛选和阅读搜索结果,提取关键信息。
工具选择响应 (JSON 格式):
{
    "tool_needed": false,
    "指令": "请筛选和阅读之前搜索到的关于 LangChain 最近一周新闻的搜索结果,提取关键信息。"
}
执行子任务: 请筛选和阅读之前搜索到的关于 LangChain 最近一周新闻的搜索结果,提取关键信息。
任务执行结果:
LangChain 是一个用于开发由语言模型驱动的应用程序的框架,它可以实现各种复杂的任务,例如文档问答、聊天机器人、代码理解和生成、API 交互等等。LangChain 旨在为 LLM 应用开发提供全面的解决方案,它可以被用于聊天机器人、通用代理、问答等多种场景。LangChain 的主要特点包括模块化,它可以被用于数据增强型生成。

正在执行任务:3. 将关键信息总结成 200 字左右的摘要。
工具选择响应 (JSON 格式):
{
    "tool_needed": false,
    "指令": "请将之前提取的关键信息总结成 200 字左右的摘要。"
}
执行子任务: 请将之前提取的关键信息总结成 200 字左右的摘要。
任务执行结果:
LangChain 框架是一个用于开发由语言模型驱动的应用程序的工具,旨在简化和加速基于大型语言模型(LLMs)的应用开发。它提供了全面的解决方案,包括模块化组件和接口,支持与各种数据源和外部工具集成。LangChain 的应用场景广泛,涵盖聊天机器人、通用代理、问答系统等,其核心特点是模块化和灵活性,方便开发者根据需求自由组合和定制组件,构建功能丰富的 LLM 应用。同时,LangChain 也降低了 LLM 应用开发的门槛,提供了丰富的文档和社区支持。

所有子任务已完成!

可以看到,当执行到 “使用搜索引擎查找…” 这个子任务时,ToolIntegratedTaskExecutor 成功地选择了 “搜索” 工具,并使用 “最近一周 LangChain 新闻” 作为关键词进行了搜索,并将搜索结果返回。后续的子任务则基于搜索结果继续执行。

通过集成搜索工具,我们的简易版 AutoGPT 已经具备了连接互联网获取信息的能力,这大大扩展了它的应用场景。


7. 第四步:加入记忆系统

为了实现更复杂的、需要上下文理解的任务,我们需要让 AutoGPT 具备 记忆能力,记住之前的对话历史和任务执行过程中的关键信息。LangChain 的 Memory 模块正是为此而生。

我们可以使用 ConversationBufferMemory 这种最简单的记忆模块,它会将对话历史以 buffer 的形式存储下来。

7.1 更新代码:集成记忆模块

创建一个 MemoryTaskExecutor 类,继承自 ToolIntegratedTaskExecutor,并集成记忆模块:

# memory_task_executor.py
from tool_integrated_task_executor import ToolIntegratedTaskExecutor
from langchain.memory import ConversationBufferMemory
import json

class MemoryTaskExecutor(ToolIntegratedTaskExecutor):
    def __init__(self, api_key=None, model="gpt-4"):
        super().__init__(api_key, model)
        self.memory = ConversationBufferMemory() # 初始化记忆模块

    def execute_task_with_memory(self, task):
        """结合记忆完成子任务"""
        # 加载记忆
        memory_variables = self.memory.load_memory_variables({})
        context = memory_variables.get("history", "") # 获取对话历史

        # 构建带记忆的 Prompt,让 LLM 知道上下文
        memory_prompt_template = PromptTemplate(
            input_variables=["context", "task", "tool_descriptions"],
            template="""
            这是之前的对话历史:
            {context}

            你有一个任务需要完成: {task}
            你可以使用以下工具:
            {tool_descriptions}

            请判断是否需要使用工具来完成任务。
            如果需要,请明确指出需要使用哪个工具,并给出工具的输入。
            如果不需要,请直接给出完成任务的指令。

            请以如下格式返回:
            {{
                "tool_needed": true/false,
                "tool_name": "工具名称" (如果 tool_needed 为 true),
                "tool_input": "工具输入" (如果 tool_needed 为 true),
                "指令": "完成任务的指令" (如果 tool_needed 为 false,或工具调用后的下一步指令)
            }}
            """
        )

        tool_descriptions = "\n".join([f"- {tool.name}: {tool.description}" for tool in self.tools])
        memory_prompt = memory_prompt_template.format(
            context=context, task=task, tool_descriptions=tool_descriptions
        )

        tool_choice_response_str = self.llm.predict(memory_prompt)
        print(f"工具选择响应 (JSON 格式, 带记忆):\n{tool_choice_response_str}") # 打印带记忆的工具选择响应

        try:
            tool_choice_response = json.loads(tool_choice_response_str)
        except json.JSONDecodeError:
            print(f"JSON 解析错误,响应内容: {tool_choice_response_str}")
            return "工具选择响应 JSON 解析错误"

        if tool_choice_response.get("tool_needed", False):
            tool_name = tool_choice_response.get("tool_name")
            tool_input = tool_choice_response.get("tool_input")
            if tool_name and tool_input:
                print(f"调用工具: {tool_name}, 输入: {tool_input}")
                if tool_name == "搜索":
                    search_result = self.search_tool.run(tool_input)
                    # 保存记忆:工具调用结果也作为上下文
                    self.memory.save_context({"task": task}, {"response": f"搜索结果:\n{search_result}"})
                    return f"搜索结果:\n{search_result}"
                else:
                    return f"未知的工具名称: {tool_name}"
            else:
                return "工具名称或输入缺失"
        else:
            instruction = tool_choice_response.get("指令")
            if instruction:
                llm_response = self.execute_task(instruction)
                # 保存记忆:LLM 的响应也作为上下文
                self.memory.save_context({"task": task}, {"response": llm_response})
                return llm_response
            else:
                return "无需工具,但指令缺失"

代码解释:

  • MemoryTaskExecutor:继承自 ToolIntegratedTaskExecutor,扩展了记忆能力。
  • __init__ 方法
    • 调用父类 ToolIntegratedTaskExecutor__init__ 方法进行初始化。
    • 初始化 ConversationBufferMemory 实例 self.memory,用于存储对话历史。
  • execute_task_with_memory 方法
    • 加载记忆self.memory.load_memory_variables({}) 从记忆模块加载变量,ConversationBufferMemory 默认使用 “history” 键存储对话历史,所以通过 memory_variables.get("history", "") 获取历史对话内容,作为上下文 context
    • 带记忆的 Prompt:在之前的工具选择 Prompt 基础上,增加了 {context} 变量,将历史对话内容也放入 Prompt 中,让 LLM 在做工具选择和任务执行时能够参考上下文信息。
    • 保存记忆:在每次 LLM 响应后, سواء是工具调用结果还是 LLM 直接给出的回复,都使用 self.memory.save_context({"task": task}, {"response": llm_response}) 将当前的任务和响应保存到记忆模块中,以便在后续的任务中作为上下文使用。

运行示例:

修改 main.py 文件,使用 MemoryTaskExecutor 并执行一个需要上下文记忆的任务:

# main.py
from memory_task_executor import MemoryTaskExecutor
import json

if __name__ == "__main__":
    executor = MemoryTaskExecutor()
    goal = "查找 OpenAI 创始人 Sam Altman 的出生日期和毕业院校"
    executor.execute_task_flow(goal)

    goal_follow_up = "那他的主要研究方向是什么?" # 追问,希望模型能记住之前的上下文
    print(f"\n--- 追问: {goal_follow_up} ---")
    executor.execute_task_flow(goal_follow_up)

运行 python main.py,观察输出。在追问 “那他的主要研究方向是什么?” 时,由于集成了记忆模块,AutoGPT 应该能够记住之前提问的是关于 Sam Altman 的信息,并在此基础上继续回答关于他的研究方向,而不是重新从头开始理解问题。

通过加入记忆系统,我们的简易版 AutoGPT 已经初步具备了上下文理解和多轮对话的能力,更接近一个真正的自主代理。


8. 完整实现:一个简易版 AutoGPT

最后,我们将上述所有模块整合到一个 SimpleAutoGPT 类中,使其更易于使用和调用。

# simple_auto_gpt.py
from memory_task_executor import MemoryTaskExecutor
import json

class SimpleAutoGPT(MemoryTaskExecutor):
    def __init__(self, api_key=None, model="gpt-4"):
        super().__init__(api_key, model)

    def run(self, goal):
        """运行 AutoGPT 流程"""
        print(f"目标:{goal}\n")
        sub_tasks = self.decompose_task(goal)
        print(f"分解的子任务:\n{sub_tasks}\n")

        for task in sub_tasks:
            print(f"正在执行任务:{task}")
            result = self.execute_task_with_memory(task) # 使用带记忆的任务执行方法
            print(f"任务完成:{task} -> 结果:\n{result}\n")

        print("所有任务完成!\n")

使用 SimpleAutoGPT

修改 main.py 文件:

# main.py
from simple_auto_gpt import SimpleAutoGPT

if __name__ == "__main__":
    autogpt = SimpleAutoGPT()
    autogpt.run("写一篇关于 LangChain 的完整教程,并将其发布到 Medium 博客平台")

现在,只需要创建一个 SimpleAutoGPT 实例,调用 run(goal) 方法,就可以让它自主地分解任务、调用工具、利用记忆来完成用户设定的目标了。

至此,我们已经成功地从零开始,逐步实现了一个简易版的 AutoGPT。虽然这个版本还非常基础,但它已经包含了 AutoGPT 的核心组件和工作流程:任务分解、工具集成、记忆系统

9. 总结

在本篇教程中,我们深入拆解了 AutoGPT 的核心理念,并使用 LangChain 框架,从零开始逐步构建了一个简易版的 AutoGPT。我们学习了如何:

  1. 定义核心任务执行器和子任务分解逻辑 (TaskExecutor, TaskFlowExecutor)。
  2. 集成外部工具,扩展 AutoGPT 的能力 (ToolIntegratedTaskExecutor,集成搜索工具)。
  3. 引入记忆模块,让 AutoGPT 具备上下文理解能力 (MemoryTaskExecutor)。
  4. 将各个模块整合,构建一个可运行的简易 AutoGPT 系统 (SimpleAutoGPT)。

通过这篇文章,你应该对 AutoGPT 的原理有了更直观的理解,并掌握了使用 LangChain 构建类似自主代理的技术。

未来扩展方向:

如果你希望进一步扩展这个简易版 AutoGPT,可以考虑以下方向:

  • 深化工具链集成:加入更多类型的工具,例如文件操作工具、代码执行工具、API 调用工具等,让 AutoGPT 能够处理更广泛的任务。
  • 优化 Prompt 设计:目前的 Prompt 设计还比较简单,可以通过更精细的 Prompt 工程,让 AutoGPT 在任务分解、工具选择、指令生成等方面更加智能和高效。
  • 引入反思和调整机制:在任务执行过程中,加入反思和调整的环节,让 AutoGPT 能够根据执行结果动态调整策略,提高任务完成的成功率和质量。
  • 构建更复杂的记忆系统:例如使用向量数据库存储长期记忆,实现更强大的知识检索和利用能力。
  • 用户界面和交互优化:为 AutoGPT 开发用户友好的界面,使其更易于使用和交互。

希望这篇教程能够为你开启 AI 自主代理开发的大门,激发你在 AI 领域的更多创新灵感!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

海棠AI实验室

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值