在 LangGraph 中使用 工具(Tools) 以及 ReAct 代理(ReAct Agent)创建一个基于 ReAct 机制的智能代理(Agent),代码版

在 LangGraph 中使用 工具(Tools) 以及 ReAct 代理(ReAct Agent)创建一个基于 ReAct 机制的智能代理(Agent),理论版

示例代码:

from typing import List
from langchain_core.tools import tool
from langchain_core.runnables.config import RunnableConfig


import os
from dotenv import load_dotenv
import yaml
from pyprojroot import here
from langchain_openai import ChatOpenAI
load_dotenv()

os.environ['OPENAI_API_KEY'] = os.getenv("OPENAI_API_KEY")
os.environ['OPENAI_API_BASE'] = os.getenv("OPENAI_API_BASE")
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
OPENAI_API_BASE= os.environ.get("OPENAI_API_BASE")
from langchain_openai import ChatOpenAI

chat = ChatOpenAI(
    openai_api_base=OPENAI_API_BASE,
    openai_api_key=OPENAI_API_KEY,
    # tream=True,
    temperature=0)

messages = [
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "Hello, how are you?"}
]

# Call the model with the messages
response = chat.invoke(messages)

# Print the response
print(response)
print('\n')
print(response.content)


from typing import List

from langchain_core.tools import tool
from langchain_core.runnables.config import RunnableConfig

from langgraph.prebuilt import ToolNode

user_to_pets = {}


@tool(parse_docstring=True)
def update_favorite_pets(
    # NOTE: config arg does not need to be added to docstring, as we don't want it to be included in the function signature attached to the LLM
    pets: List[str],
    config: RunnableConfig,
) -> None:
    """Add the list of favorite pets.

    Args:
        pets: List of favorite pets to set.
    """
    user_id = config.get("configurable", {}).get("user_id")
    user_to_pets[user_id] = pets


@tool
def delete_favorite_pets(config: RunnableConfig) -> None:
    """Delete the list of favorite pets."""
    user_id = config.get("configurable", {}).get("user_id")
    if user_id in user_to_pets:
        del user_to_pets[user_id]


@tool
def list_favorite_pets(config: RunnableConfig) -> None:
    """List favorite pets if asked to."""
    user_id = config.get("configurable", {}).get("user_id")
    return ", ".join(user_to_pets.get(user_id, []))


tools = [update_favorite_pets, delete_favorite_pets, list_favorite_pets]
user_to_pets = {}

from langgraph.prebuilt import create_react_agent
from IPython.display import Image, display

graph = create_react_agent(chat, tools)

try:
    display(Image(graph.get_graph().draw_mermaid_png()))
except Exception:
    pass

from langchain_core.messages import HumanMessage

user_to_pets.clear()  # Clear the state

print(f"User information prior to run: {user_to_pets}")

inputs = {"messages": [HumanMessage(content="my favorite pets are cats and dogs")]}
for chunk in graph.stream(
    inputs, {"configurable": {"user_id": "123"}}, stream_mode="values"
):
    chunk["messages"][-1].pretty_print()

print(f"User information after the run: {user_to_pets}")
from langchain_core.messages import HumanMessage

print(f"User information prior to run: {user_to_pets}")

inputs = {"messages": [HumanMessage(content="what are my favorite pets")]}
for chunk in graph.stream(
    inputs, {"configurable": {"user_id": "123"}}, stream_mode="values"
):
    chunk["messages"][-1].pretty_print()

print(f"User information prior to run: {user_to_pets}")
print(f"User information prior to run: {user_to_pets}")

inputs = {
    "messages": [
        HumanMessage(content="please forget what i told you about my favorite animals")
    ]
}
for chunk in graph.stream(
    inputs, {"configurable": {"user_id": "123"}}, stream_mode="values"
):
    chunk["messages"][-1].pretty_print()

print(f"User information prior to run: {user_to_pets}")

下面我将详细解释这段代码的每个部分,并用简单的例子说明其作用。


1. 导入依赖库和加载环境变量

from typing import List
from langchain_core.tools import tool
from langchain_core.runnables.config import RunnableConfig
  • 解释
    • List 用于类型提示,说明某个变量或者函数参数是一个列表(例如字符串列表)。
    • tool 是一个装饰器,用来将普通函数包装成工具,使得语言模型(LLM)在处理对话时可以调用这些函数。
    • RunnableConfig 用于传递一些运行时配置,比如用户信息。
import os
from dotenv import load_dotenv
import yaml
from pyprojroot import here
from langchain_openai import ChatOpenAI
load_dotenv()
  • 解释
    • os 模块用于和操作系统交互,例如操作环境变量。
    • load_dotenv() 会自动从项目根目录下的 .env 文件中加载环境变量,这样你就可以在代码中使用 API 密钥等敏感信息。
    • yamlpyprojroot.here 分别用于解析 YAML 配置和确定项目根目。
    • ChatOpenAI 是一个与 OpenAI 聊天模型交互的封装类。
os.environ['OPENAI_API_KEY'] = os.getenv("OPENAI_API_KEY")
os.environ['OPENAI_API_BASE'] = os.getenv("OPENAI_API_BASE")
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY")
OPENAI_API_BASE= os.environ.get("OPENAI_API_BASE")
  • 解释
    • 从环境变量中获取 OPENAI_API_KEYOPENAI_API_BASE,并把它们设置到 os.environ 中,确保程序运行时可以正确使用这些密钥。
    • 同时把它们存入变量 OPENAI_API_KEYOPENAI_API_BASE,后面创建 ChatOpenAI 实例时会用到。
  • 举例说明:假如你的 .env 文件中包含一行 OPENAI_API_KEY=abcdef123456,那么加载后 OPENAI_API_KEY 变量就会保存这个值,用于身份验证。

2. 创建 ChatOpenAI 实例并发送初始消息

from langchain_openai import ChatOpenAI

chat = ChatOpenAI(
    openai_api_base=OPENAI_API_BASE,
    openai_api_key=OPENAI_API_KEY,
    # tream=True,
    temperature=0)
  • 解释
    • 利用上一步获取的 API 基础地址和密钥,创建一个 ChatOpenAI 对象,这个对象负责与 OpenAI 的 API 进行通信。
    • 参数 temperature=0 表示生成回复时没有随机性,保证输出结果稳定。
    • 注释掉的 # tream=True 是希望开启流式输出,但这里没有启用。
messages = [
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "Hello, how are you?"}
]
  • 解释
    • 定义了一个消息列表,告诉模型如何扮演角色。
    • 第一条消息是系统消息,设定了助手的行为(“你是一个乐于助人的助手”);第二条消息是用户问候。
response = chat.invoke(messages)
  • 解释
    • 将消息列表传递给 ChatOpenAI 对象,并调用 invoke 方法,从模型那里获得回复。
print(response)
print('\n')
print(response.content)
  • 解释
    • 打印整个回复对象(可能包含元数据)以及仅打印回复的文本内容。
  • 举例说明:如果模型回复 "I'm doing well, thank you!",则 response.content 就显示这句话,而 print(response) 可能还会包含其它调试信息。

3. 定义管理用户喜爱宠物信息的工具函数

首先,定义一个全局变量来存储每个用户的宠物信息:

user_to_pets = {}
  • 解释
    • 这个空字典用于保存用户与他们喜爱宠物的对应关系,比如形如 {"123": ["cats", "dogs"]}

3.1 更新宠物列表的函数

@tool(parse_docstring=True)
def update_favorite_pets(
    # NOTE: config arg does not need to be added to docstring, as we don't want it to be included in the function signature attached to the LLM
    pets: List[str],
    config: RunnableConfig,
) -> None:
    """Add the list of favorite pets.

    Args:
        pets: List of favorite pets to set.
    """
    user_id = config.get("configurable", {}).get("user_id")
    user_to_pets[user_id] = pets
  • 解释
    • 使用 @tool(parse_docstring=True) 装饰器,将这个函数注册为工具,方便后续由语言模型调用
    • 参数 pets 是一个字符串列表,代表用户喜爱的宠物。
    • 参数 config 传递额外的配置信息(例如用户的 ID)。
    • 函数内部通过 config.get("configurable", {}).get("user_id") 提取用户 ID,并将传入的宠物列表存入全局字典 user_to_pets 中。
  • 举例说明:当调用 update_favorite_pets 时,如果传入 pets=["cats", "dogs"],且 config={"configurable": {"user_id": "123"}},那么字典 user_to_pets 将更新为 {"123": ["cats", "dogs"]}

3.2 删除宠物列表的函数

@tool
def delete_favorite_pets(config: RunnableConfig) -> None:
    """Delete the list of favorite pets."""
    user_id = config.get("configurable", {}).get("user_id")
    if user_id in user_to_pets:
        del user_to_pets[user_id]
  • 解释
    • 同样通过 @tool 装饰器将这个函数变成一个工具。
    • 仅通过传入的 config 参数获得用户 ID,并检查该用户是否在 user_to_pets 中;如果存在,则删除其对应的宠物信息。
  • 举例说明:假如用户 “123” 已经存储了宠物列表,调用这个函数后就会删除 {"123": [...]} 这一项。

3.3 查询宠物列表的函数

@tool
def list_favorite_pets(config: RunnableConfig) -> None:
    """List favorite pets if asked to."""
    user_id = config.get("configurable", {}).get("user_id")
    return ", ".join(user_to_pets.get(user_id, []))
  • 解释
    • 该函数用于返回当前用户的喜爱宠物信息。
    • 通过 config 获取用户 ID,然后从 user_to_pets 中查找该用户的宠物列表,最后将列表转换成用逗号分隔的字符串返回。
  • 举例说明:如果用户 “123” 的宠物列表是 ["cats", "dogs"],那么函数返回的字符串就是 "cats, dogs"
tools = [update_favorite_pets, delete_favorite_pets, list_favorite_pets]
user_to_pets = {}
  • 解释
    • 将上面定义的三个工具函数放入列表 tools,方便后面传递给代理。
    • 重新清空 user_to_pets,以确保状态干净。

4. 创建 React Agent 并显示工作图

from langgraph.prebuilt import create_react_agent
from IPython.display import Image, display

graph = create_react_agent(chat, tools)
  • 解释
    • 这里调用 create_react_agent 函数,根据之前创建的 chat 模型实例和工具列表 tools 构造一个“反应式代理”(react agent)
    • 这个代理可以根据用户的输入自动决定是否调用某个工具函数,从而管理内部状态(例如用户的宠物信息)。
try:
    display(Image(graph.get_graph().draw_mermaid_png()))
except Exception:
    pass
  • 解释
    • 尝试将代理内部的工作流程图转换为 Mermaid 格式的 PNG 图片,并在 Jupyter Notebook 中显示。如果环境不支持(例如在非 Notebook 环境中),则忽略异常不报错。

5. 使用 Agent 处理对话并测试工具

5.1 设置(更新)用户的宠物信息

from langchain_core.messages import HumanMessage

user_to_pets.clear()  # Clear the state

print(f"User information prior to run: {user_to_pets}")

inputs = {"messages": [HumanMessage(content="my favorite pets are cats and dogs")]}
for chunk in graph.stream(
    inputs, {"configurable": {"user_id": "123"}}, stream_mode="values"
):
    chunk["messages"][-1].pretty_print()

print(f"User information after the run: {user_to_pets}")
  • 解释
    • 首先调用 user_to_pets.clear() 清空之前的状态,确保没有旧数据干扰。
    • 打印当前的用户信息(此时应该是空字典 {})。
    • 创建一个输入,消息内容为 "my favorite pets are cats and dogs",表示用户在告诉代理自己的喜好。
    • 调用 graph.stream(...) 方法:
      • 传入 输入消息 和一个 配置字典 {"configurable": {"user_id": "123"}} ,这样代理在处理消息时知道这是用户 “123”。
      • 通过流式处理,每个返回的消息块都会调用 pretty_print() 方法进行格式化输出。
    • 最后,再次打印 user_to_pets,此时应该已经更新为 {"123": ["cats", "dogs"]}
  • 举例说明:你在聊天中说“my favorite pets are cats and dogs”,代理就会调用 update_favorite_pets,将用户 “123” 的宠物信息存储下来。

5.2 查询用户的宠物信息

from langchain_core.messages import HumanMessage

print(f"User information prior to run: {user_to_pets}")

inputs = {"messages": [HumanMessage(content="what are my favorite pets")]}
for chunk in graph.stream(
    inputs, {"configurable": {"user_id": "123"}}, stream_mode="values"
):
    chunk["messages"][-1].pretty_print()

print(f"User information prior to run: {user_to_pets}")
  • 解释
    • 这段代码发送一条消息 "what are my favorite pets",询问当前用户喜爱的宠物。
    • 代理在接收到这条消息后,会调用 list_favorite_pets 工具函数,根据用户 ID “123” 查找并返回宠物列表。
  • 举例说明:如果之前已存储了 ["cats", "dogs"],代理就会回答 "cats, dogs"

5.3 删除(遗忘)用户的宠物信息

print(f"User information prior to run: {user_to_pets}")

inputs = {
    "messages": [
        HumanMessage(content="please forget what i told you about my favorite animals")
    ]
}
for chunk in graph.stream(
    inputs, {"configurable": {"user_id": "123"}}, stream_mode="values"
):
    chunk["messages"][-1].pretty_print()

print(f"User information prior to run: {user_to_pets}")
  • 解释
    • 最后一部分发送消息 "please forget what i told you about my favorite animals",要求代理删除之前存储的宠物信息。
    • 代理解析这条消息后,会调用 delete_favorite_pets 工具函数,删除用户 “123” 的记录。
    • 最终打印时,user_to_pets 应该为空 {},表示信息已被删除。
  • 举例说明:当你说“please forget what i told you about my favorite animals”,系统会清除之前存储的宠物信息,相当于把记忆清空。

总结

这段代码实现了一个基于 OpenAI 模型的对话系统,并结合了自定义工具来管理用户状态(这里是用户喜欢的宠物信息)。其主要功能包括:

  1. 初始化与环境配置:加载必要的库,读取环境变量,创建 OpenAI 聊天模型实例。
  2. 工具函数定义:定义三个工具函数:
    • update_favorite_pets 用于存储或更新用户的宠物列表。
    • delete_favorite_pets 用于删除用户的宠物记录。
    • list_favorite_pets 用于查询用户的宠物列表。
  3. ****创建代理(Agent):将聊天模型和工具函数结合起来,构造一个能够在对话中根据用户意图自动调用工具的代理。
  4. 对话与状态管理演示
    • 用户通过对话告诉系统自己的宠物喜好,系统存储该信息;
    • 后续查询时,系统根据存储返回相应数据;
    • 当用户要求“忘记”信息时,系统清除存储的数据。

通俗例子

  • 你第一次告诉代理 “my favorite pets are cats and dogs”,系统就把这条信息记在了“123”号用户的档案里。
  • 然后你问 “what are my favorite pets”,系统就会查找并回复 “cats, dogs”。
  • 最后你说 “please forget what i told you about my favorite animals”,系统就删除了这个档案,恢复到初始状态。

通过这种设计,不仅实现了对话功能,还能够在对话中管理状态,让模型的回答和操作更加灵活和有针对性。

### ReAct Framework中的Agent功能与使用方法 ReAct框架是一种结合了语言模型和外部工具的框架,旨在通过推理(Reasoning)和行动(Action)来增强AI代理Agent)的能力。在ReAct框架中,Agent的功能被设计为能够根据环境感知进行推理,并采取适当的行动以实现目标[^1]。 #### 1. Agent的核心功能 ReAct框架中的Agent主要具备以下核心功能: - **感知能力**:Agent通过传感器感知环境信息。这些信息可以来自自然语言输入、视觉数据或其他形式的数据[^1]。 - **推理能力**:Agent利用语言模型生成推理步骤,帮助其理解当前状态并制定行动计划。这种推理过程通常以逐步的方式呈现,确保每一步都清晰且可验证。 - **行动能力**:基于推理结果,Agent会执行具体的操作或调用外部工具以改变环境状态。例如,Agent可以查询数据库、搜索网络或与其他系统交互[^2]。 #### 2. 使用方法 ReAct框架中的Agent使用方法主要包括以下几个方面: ##### (1) 初始化与配置 在开始使用Agent之前,需要对其进行初始化和配置。这包括定义Agent的目标、指定可用的外部工具以及设置运行环境。例如,可以通过以下代码初始化一个简单的Agent: ```python from react.agent import ReactAgent # 定义目标 goal = "Find the population of Tokyo" # 初始化Agent agent = ReactAgent(goal=goal, tools=["search", "database_query"]) ``` ##### (2) 感知与推理 Agent通过感知环境信息并生成推理步骤来解决问题。感知阶段通常涉及从外部源获取数据,而推理阶段则依赖于语言模型生成逻辑链条。例如: ```python # 获取环境信息 observation = agent.observe() # 生成推理步骤 reasoning_steps = agent.reason(observation) ``` ##### (3) 行动与反馈 根据推理结果,Agent会采取行动并与环境交互。行动的结果会被反馈回Agent,以便其调整后续策略。例如: ```python # 执行行动 action_result = agent.act(reasoning_steps) # 更新状态 agent.update_state(action_result) ``` #### 3. 示例应用 以下是一个完整的示例,展示如何使用ReAct框架中的Agent来解决实际问题: ```python from react.agent import ReactAgent # 定义目标 goal = "What is the capital of Japan and its population?" # 初始化Agent agent = ReactAgent(goal=goal, tools=["search", "database_query"]) # 获取环境信息 observation = agent.observe() # 生成推理步骤 reasoning_steps = agent.reason(observation) # 执行行动 action_result = agent.act(reasoning_steps) # 更新状态 agent.update_state(action_result) # 输出最终结果 print(agent.get_result()) ``` #### 4. 注意事项 在使用ReAct框架中的Agent时,需要注意以下几点: - 确保Agent的目标明确且具体,以便其能够有效执行任务。 - 根据任务需求选择合适的外部工具,避免不必要的复杂性。 - 监控Agent的行为,确保其推理和行动符合预期。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值