LangChain 19 Agents Reason+Action自定义agent处理OpenAI的计算缺陷

LangChain系列文章

  1. LangChain 实现给动物取名字,
  2. LangChain 2模块化prompt template并用streamlit生成网站 实现给动物取名字
  3. LangChain 3使用Agent访问Wikipedia和llm-math计算狗的平均年龄
  4. LangChain 4用向量数据库Faiss存储,读取YouTube的视频文本搜索Indexes for information retrieve
  5. LangChain 5易速鲜花内部问答系统
  6. LangChain 6根据图片生成推广文案HuggingFace中的image-caption模型
  7. LangChain 7 文本模型TextLangChain和聊天模型ChatLangChain
  8. LangChain 8 模型Model I/O:输入提示、调用模型、解析输出
  9. LangChain 9 模型Model I/O 聊天提示词ChatPromptTemplate, 少量样本提示词FewShotPrompt
  10. LangChain 10思维链Chain of Thought一步一步的思考 think step by step
  11. LangChain 11实现思维树Implementing the Tree of Thoughts in LangChain’s Chain
  12. LangChain 12调用模型HuggingFace中的Llama2和Google Flan t5
  13. LangChain 13输出解析Output Parsers 自动修复解析器
  14. LangChain 14 SequencialChain链接不同的组件
  15. LangChain 15根据问题自动路由Router Chain确定用户的意图
  16. LangChain 16 通过Memory记住历史对话的内容
  17. LangChain 17 LangSmith调试、测试、评估和监视基于任何LLM框架构建的链和智能代理
  18. LangChain 18 LangSmith监控评估Agent并创建对应的数据库
    在这里插入图片描述

在这里插入图片描述

1. Agents 代理

Agents的核心理念是利用语言模型选择一系列要采取的行动。在Chains中,一系列行动是硬编码的(在代码中)。在Agents中,语言模型被用作推理引擎,以确定要采取哪些行动以及顺序。

概念 这里有几个关键组成部分:

1.1 Agent

这是负责决定下一步该采取什么步骤的链条。这由语言模型和提示驱动。这个链条的输入包括:

  1. 工具:可用工具的描述
  2. 用户输入:高层次目标
  3. 中间步骤:为了实现用户输入而先前执行的任何(动作,工具输出)对

输出是下一步要采取的行动或发送给用户的最终响应(代理动作或代理完成)。动作指定一个工具和该工具的输入。

不同的代理有不同的推理提示风格,不同的编码输入方式和不同的解析输出方式。有关内置代理的完整列表,请参见代理类型。您还可以轻松构建自定义代理,我们将在下面的入门部分中展示如何操作。

1.2 工具

工具是代理可以调用的函数。围绕工具有两个重要的设计考虑:

  1. 为代理提供访问正确工具的权限
  2. 以对代理最有帮助的方式描述工具

如果没有同时考虑这两个方面,你将无法构建一个可工作的代理。如果你不给代理访问正确的工具集,它将永远无法完成你给它的目标。如果你没有很好地描述工具,代理将不知道如何正确使用它们。

LangChain 提供了广泛的内置工具集,但也使定义自己的工具(包括自定义描述)变得容易。有关内置工具的完整列表,请参见工具集成部分。

1.3 工具包

对于许多常见任务,代理将需要一组相关工具。为此,LangChain提供了工具包的概念 - 大约3-5个工具组成,用于实现特定目标。例如,GitHub工具包中有一个用于搜索GitHub问题的工具,一个用于读取文件的工具,一个用于评论的工具等等。

LangChain提供了广泛的工具包供您使用。有关内置工具包的完整列表,请参阅工具包集成部分。

1.4 AgentExecutor

代理执行器是代理的运行时。这实际上是调用代理,执行它选择的动作,将动作输出传递回代理,并重复。在伪代码中,大致如下:

next_action = agent.get_action(...)
while next_action != AgentFinish:
    observation = run(next_action)
    next_action = agent.get_action(..., next_action, observation)
return next_action

虽然这可能看起来很简单,但这个运行时为您处理了几个复杂情况,包括:

  1. 处理代理选择不存在的工具的情况
  2. 处理工具出错的情况
  3. 处理代理产生的无法解析为工具调用的输出的情况
  4. 在所有级别(代理决策,工具调用)记录和观察到标准输出和/或LangSmith。

1.5 其他类型的代理运行时

AgentExecutor类是LangChain支持的主要代理运行时。但是,我们还支持其他更实验性的运行时。这些包括:

  • 计划并执行代理
  • Baby AGI
  • Auto GPT

您也可以始终创建自己的自定义执行逻辑,我们将在下面展示如何做到这一点。

2. 开始代码实现​

为了更好地理解代理框架,让我们使用LangChain表达语言(LCEL)从头开始构建一个代理。我们需要构建代理本身,定义自定义工具,并在自定义循环中运行代理和工具。最后,我们将展示如何使用标准的LangChain AgentExecutor来使执行更容易。

一些重要的术语(和模式)需要知道:

  1. AgentAction:这是一个表示代理应该采取的行动的数据类。它有一个工具属性(这是应调用的工具的名称)和一个tool_input属性(该工具的输入)
  2. AgentFinish:这是一个表示代理已经完成并应该返回给用户的数据类。它有一个return_values参数,是一个要返回的字典。它通常只有一个键 - 输出 - 是一个字符串,因此通常只返回这个键。
  3. intermediate_steps:这些代表传递的先前代理操作和相应的输出。这些对于将来的迭代非常重要,这样代理就知道它已经做了什么工作。这被定义为List[Tuple[AgentAction, Any]]。请注意,observation目前被保留为Any类型,以便最大程度地灵活。实际上,这通常是一个字符串。

2.1 设置:LangSmith

根据定义,代理在返回用户可见的输出之前会采取一系列自主确定的、依赖输入的步骤。这使得调试这些系统特别棘手,观察特别重要。LangSmith在这种情况下特别有用。

在使用LangChain构建时,任何使用LCEL构建的内置代理或自定义代理都将自动在LangSmith中被追踪。如果我们使用AgentExecutor,不仅会得到代理规划步骤的完整追踪,还会得到工具的输入和输出的追踪。

要设置LangSmith,我们只需要设置以下环境变量:

export LANGCHAIN_TRACING_V2="true"
export LANGCHAIN_API_KEY="<your-api-key>"

2.2 定义代理

我们首先需要创建我们的代理。这是负责决定下一步采取什么行动的链条。

在这个例子中,我们将使用OpenAI函数调用来创建这个代理。这通常是创建代理的最可靠方式。

在本指南中,我们将构建一个具有自定义工具访问权限的自定义代理。我们选择这个例子是因为在大多数实际用例中,您将需要自定义代理或工具。我们将创建一个简单的工具,用于计算单词的长度。这很有用,因为由于标记化,LLMs实际上可能会搞砸这个。我们将首先创建它而不带有记忆,但然后我们将展示如何添加记忆。记忆是为了启用对话而必需的。

首先,让我们加载我们将用来控制代理的语言模型。

from langchain.chat_models import ChatOpenAI

llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)

我们可以看到它在尝试计算字符串"educa"中的字母时遇到了困难。

llm.invoke("how many letters in the word educa?")
    AIMessage(content='There are 6 letters in the word "educa".')

接下来,让我们定义一些要使用的工具。让我们编写一个非常简单的Python函数来计算传入的单词的长度。

from langchain.agents import tool


@tool
def get_word_length(word: str) -> int:
    """Returns the length of a word."""
    return len(word)


tools = [get_word_length]

现在让我们创建提示。因为OpenAI函数调用是为工具使用而优化的,我们几乎不需要任何关于如何推理或如何输出格式的指令。我们只需要两个输入变量:输入和agent_scratchpad。输入应该是包含用户目标的字符串。agent_scratchpad应该是包含先前代理工具调用和相应工具输出的消息序列。

from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder

prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "You are very powerful assistant, but bad at calculating lengths of words.",
        ),
        ("user", "{input}"),
        MessagesPlaceholder(variable_name="agent_scratchpad"),
    ]
)

代理如何知道它可以使用哪些工具?在这种情况下,我们依赖于OpenAI调用LLMs的功能,它们将函数作为单独的参数,并经过专门训练,知道何时调用这些函数。

要将我们的工具传递给代理,我们只需要将它们格式化为OpenAI函数格式,并将它们传递给我们的模型。(通过绑定函数,我们确保它们在每次调用模型时被传递。)

from langchain.tools.render import format_tool_to_openai_function

llm_with_tools = llm.bind(functions=[format_tool_to_openai_function(t) for t in tools])

将这些部分组合在一起,我们现在可以创建代理。我们将导入最后两个实用程序函数:一个用于格式化中间步骤(代理动作、工具输出对)以将其转换为可以发送到模型的输入消息的组件,以及一个用于将输出消息转换为代理动作/代理完成的组件。

from langchain.agents.format_scratchpad import format_to_openai_function_messages
from langchain.agents.output_parsers import OpenAIFunctionsAgentOutputParser

agent = (
    {
        "input": lambda x: x["input"],
        "agent_scratchpad": lambda x: format_to_openai_function_messages(
            x["intermediate_steps"]
        ),
    }
    | prompt
    | llm_with_tools
    | OpenAIFunctionsAgentOutputParser()
)

现在我们有了我们的代理,让我们来玩一下吧!让我们传递一个简单的问题和空的中间步骤,看看它返回什么:

agent.invoke({"input": "how many letters in the word educa?", "intermediate_steps": []})
    AgentActionMessageLog(tool='get_word_length', tool_input={'word': 'educa'}, log="\nInvoking: `get_word_length` with `{'word': 'educa'}`\n\n\n", message_log=[AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{\n  "word": "educa"\n}', 'name': 'get_word_length'}})])

我们可以看到它响应一个AgentAction以采取行动(实际上是AgentActionMessageLog - AgentAction的子类,还跟踪完整的消息日志)。

如果我们设置了LangSmith,我们将看到一个跟踪,让我们检查每个步骤中的输入和输出的序列。https://smith.langchain.com/public/04110122-01a8-413c-8cd0-b4df6eefa4b7/r
在这里插入图片描述

2.3 定义运行时

所以这只是第一步 - 现在我们需要为此编写一个运行时。最简单的方法就是不断循环调用代理,然后执行动作,直到返回AgentFinish为止。让我们在下面编写代码:

from langchain.schema.agent import AgentFinish

user_input = "how many letters in the word educa?"
intermediate_steps = []
while True:
    output = agent.invoke(
        {
            "input": user_input,
            "intermediate_steps": intermediate_steps,
        }
    )
    if isinstance(output, AgentFinish):
        final_result = output.return_values["output"]
        break
    else:
        print(f"TOOL NAME: {output.tool}")
        print(f"TOOL INPUT: {output.tool_input}")
        tool = {"get_word_length": get_word_length}[output.tool]
        observation = tool.run(output.tool_input)
        intermediate_steps.append((output, observation))
print(final_result)
    TOOL NAME: get_word_length
    TOOL INPUT: {'word': 'educa'}
    There are 5 letters in the word "educa".

Woo! It’s working.

整合代码实现

# 导入与 OpenAI 语言模型交互的模块。
from langchain.llms import OpenAI  

# 导入用于创建和管理提示模板的模块。
from langchain.prompts import PromptTemplate  

# 导入用于构建基于大型语言模型的处理链的模块。
from langchain.chains import LLMChain  

# 导入从 .env 文件加载环境变量的库。
from dotenv import load_dotenv  

# 导入创建和管理 OpenAI 聊天模型实例的类。
from langchain.chat_models import ChatOpenAI

# 加载 .env 文件中的环境变量。
load_dotenv()  

# 设置环境变量,包括项目 ID 和 Langchain API 的相关设置。
import os
from uuid import uuid4
unique_id = uuid4().hex[0:8]
os.environ["LANGCHAIN_PROJECT"] = f"Tracing word length - {unique_id}"

# 初始化 LangSmith 客户端。
from langsmith import Client
client = Client()

# 创建 ChatOpenAI 实例。
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0, verbose=True)

# 定义一个自定义工具,用于获取单词的长度。
from langchain.agents import tool

@tool
def get_word_length(word: str) -> int:
    """Returns the length of a word."""
    return len(word)

tools = [get_word_length]

# 创建聊天提示模板。
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder

prompt = ChatPromptTemplate.from_messages(
    [
        ("system", "You are very powerful assistant, but bad at calculating lengths of words."),
        ("user", "{input}"),
        MessagesPlaceholder(variable_name="agent_scratchpad"),
    ]
)

# 将 ChatOpenAI 实例与工具绑定。
from langchain.tools.render import format_tool_to_openai_function

llm_with_tools = llm.bind(functions=[format_tool_to_openai_function(t) for t in tools])

# 定义代理。
from langchain.agents.format_scratchpad import format_to_openai_function_messages
from langchain.agents.output_parsers import OpenAIFunctionsAgentOutputParser

agent = (
    {
        "input": lambda x: x["input"],
        "agent_scratchpad": lambda x: format_to_openai_function_messages(x["intermediate_steps"]),
    }
    | prompt
    | llm_with_tools
    | OpenAIFunctionsAgentOutputParser()
)

# 处理用户输入,使用代理执行循环,直到获取最终结果。
from langchain.schema.agent import AgentFinish

user_input = "how many letters in the word educa?"
intermediate_steps = []
while True:
    output = agent.invoke(
        {
            "input": user_input,
            "intermediate_steps": intermediate_steps,
        }
    )
    if isinstance(output, AgentFinish):
        final_result = output.return_values["output"]
        break
    else:
        print(f"TOOL NAME: {output.tool}")
        print(f"TOOL INPUT: {output.tool_input}")
        tool = {"get_word_length": get_word_length}[output.tool]
        observation = tool.run(output.tool_input)
        intermediate_steps.append((output, observation))
print(final_result)

输出结果

(develop)⚡ % python Agents/chat_agents_word_length.py                    ~/Workspace/LLM/langchain-llm-app
TOOL NAME: get_word_length
TOOL INPUT: {'word': 'educa'}
There are 5 letters in the word "educa".

代码

https://github.com/zgpeace/pets-name-langchain/tree/develop

参考

https://python.langchain.com/docs/modules/agents/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/214406.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

USART的PAL库编程

USART驱动的工作原理 总结一下我们之前使用中断的方式来进行数据的发送和接收 如果收到数据数据在RDR寄存器中 RXNE标志位就从0到1触发中断 进入中断服务函数 把数据缓存在队列中 然后在到进程函数中断接收数据函数中进行出队处理 发送数据就是把中断关闭&#xff08;标志位TXE…

算法通关村第十六关-白银挑战滑动窗口经典题目

大家好我是苏麟 , 今天带来滑动窗口经典的一些题目 . 我们继续来研究一些热门的、高频的滑动窗口问题 大纲 最长子串专题无重复字符的最长子串 长度最小的子数组盛最多水的容器 最长子串专题 无重复字符的最长子串 描述 : 给定一个字符串 s &#xff0c;请你找出其中不含有重…

某60区块链安全之Create2实战二学习记录

区块链安全 文章目录 区块链安全Create2实战二实验目的实验环境实验工具实验原理实验内容Create2实战二 实验步骤Create2实战二 实验目的 学会使用python3的web3模块 学会分析以太坊智能合约中的伪随机数问题 学会利用Create2可在同一地址部署不同合约特性解决伪随机数问题 找…

【Docker实操】创建一个Node服务

一、安装node 请查看阿里云官网教程&#xff1a;如何快速部署Node.js项目。&#xff08;注意要在根目录操作&#xff09;apt install nodejs、apt install npm执行上面两个命名来安装 安装完成后&#xff0c;执行node -v、npm -v&#xff0c;如果出现版本&#xff0c;就是安装…

排序算法介绍(四)快速排序

0. 简介 快速排序&#xff08;Quick Sort&#xff09;是一种高效的排序算法&#xff0c;采用了分治的思想。它选择一个基准元素&#xff0c;通过一趟排序将待排序序列分割成独立的两部分&#xff0c;其中一部分的所有元素都比基准元素小&#xff0c;另一部分的所有元素都比基准…

【ArcGIS Pro微课1000例】0044:深度学习--面部模糊(马赛克)

本文讲解ArcGIS Pro中通过深度学习工具实现人脸面部模糊,起到马赛克的作用。 文章目录 一、效果对比二、工具介绍三、案例实现一、效果对比 原始图片: 深度学习后的模糊照片: 二、工具介绍 本工具为ArcGIS Pro工具箱中的深度学习工具中的:使用深度学习分类像素,如下所示…

彻底解决ModuleNotFoundError: No module named ‘exceptions‘【Bug完美解决】

文章目录 项目场景:问题描述原因分析:解决方案:此Bug解决方案总结心得项目场景: 根据本文可找到bug原因并彻底解决**ModuleNotFoundError: No module named ‘exceptions‘**Bug 报错: E:\Anconda\python.exe c:\Users\24190\PycharmProjects\pythonProject4py尝试 gong…

Linux4.7、环境变量

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 目录 基本概念 见见环境变量 指令原理 常见环境变量及其测试 环境变量相关指令 环境变量组织方式 通过代码获取环境变量 通过系统变量获取环境变量以及设置环境变量 环境变量的全局属性 基本概念 首先&#xff0c;…

【Vulnhub 靶场】【Momentum: 2】【简单】【20210628】

1、环境介绍 靶场介绍&#xff1a;https://www.vulnhub.com/entry/momentum-2,702/ 靶场下载&#xff1a;https://download.vulnhub.com/momentum/Momentum2.ova 靶场难度&#xff1a;简单 发布日期&#xff1a;2021年06月28日 文件大小&#xff1a;698 MB 靶场作者&#xff1…

TeXworks 初次使用 debug方法

下载Texlive&#xff0c;打开TeXworks editor 编译排版&#xff0c;可能会报很多错&#xff1a; 1. ! Fatal Package fontspec Error: The fontspec package requires either XeTeX or (fontspec) LuaTeX. (fontspec) (fontspec) …

【数据结构】二叉树遍历的非递归实现

前言&#xff1a; 本文使用栈以非递归的形式遍历整颗二叉树&#xff0c;我是通过数组模拟栈来实现的&#xff0c;如果对用数组模拟栈不太熟悉&#xff0c;你可以直接使用Stack类作为栈实现。 前序(先序)遍历&#xff1a; 要求&#xff1a;二叉树节点的打印顺序为&#xff1a;中…

山西电力市场日前价格预测【2023-12-04】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2023-12-04&#xff09;山西电力市场全天平均日前电价为179.48元/MWh。其中&#xff0c;最高日前电价为362.01元/MWh&#xff0c;预计出现在18:00。最低日前电价为0.00元/MWh&#xff0c;预计出…

Leetcode1094. 拼车

Every day a Leetcode 题目来源&#xff1a;1094. 拼车 解法1&#xff1a;差分数组 对于本题&#xff0c;设 a[i] 表示车行驶到位置 i 时车上的人数。我们需要判断是否所有 a[i] 都不超过 capacity。 trips[i] 相当于把 a 中下标从 fromi 到 toi−1 的数都增加 numPassenge…

游戏配置表的导入使用

游戏配置表是游戏策划的标配&#xff0c;如下图&#xff1a; 那么程序怎么把把这张配置表导入使用&#xff1f; 1.首先&#xff0c;利用命令行把Excel格式的文件转化成Json格式&#xff1a; json-excel\json-excel json Tables\ Data\copy Data\CharacterDefine.txt ..\Cli…

Siemens-NXUG二次开发-Java开发环境配置[20231203]

Siemens-NXUG二次开发-Java开发环境配置[20231203] 1.NX/UG Java API官方开发文档2.安装Java83.安装jetbrain idea3.windows系统环境变量配置4.使用idea创建项目5.NXOpen Java代码生效流程6.API体系简述6.代码示例 1.NX/UG Java API官方开发文档 西门子NX/UG Java api开发文档…

一款自动帮你生成UI界面和代码的AI神器

我的新书《Android App开发入门与实战》已于2020年8月由人民邮电出版社出版&#xff0c;欢迎购买。点击进入详情 只要描述你想要的UI是什么样的&#xff0c;它就能帮你生成&#xff0c;是不是很神奇&#xff1f; v0使用 AI 模型根据简单的文本提示生成用户界面和代码&#xff…

U盘不仅能在电脑上使用,在手机上也可使用,包括安卓和苹果手机,但苹果的较特殊

许多最好的安卓手机都使用USB-C端口在电脑上充电和来回传输文件,但如果你需要给老板发电子邮件的文件放在闪存驱动器或全尺寸SD卡上呢? 幸运的是,使用廉价的适配器电缆,你可以将USB加密狗或读卡器直接连接到手机上。你甚至可以直接使用USB-C闪存驱动器,以实现更轻松的过程…

Java基础之数组拷贝

Arrays.copyOf 详解 copyOf是Arrays类下面的一个方法,用于拷贝各种数组 以整型数组为例&#xff1a;int [ ] copyOf(int [ ]array,int newLength);第一个参数是想要拷贝到数组&#xff0c;第二个参数是新拷贝得到的数组的大小&#xff08;不一定非得和原始数组大小一样&…

深层神经网络(第四周)

这里省略了深层神经网络的前向传播和反向传播&#xff0c;内容和之前相似&#xff0c;不做过多描述。若今后需要&#xff0c;可以再补习。 一、为什么使用深层表示 解决问题时其实并不需要很大的神经网络&#xff0c;但是得有深度&#xff0c;得有比较多的隐藏层。这是为什么…

DBS note7 (end):DB Design

目录 一、前言 二、引言 三、Entity-Relationship Models&#xff08;实体-关系模型&#xff09; 1、关系约束 三、函数依赖和正则化 1、BCNF分解 2、无损分解 3、依赖关系保留分解 一、前言 略读过一遍CS186&#xff0c;对于CS186来说&#xff0c;绝对不止这 7 篇笔记…