使用 LangChain 代理构建数学应用
原文:towardsdatascience.com/building-a-math-application-with-langchain-agents-23919d09a4d3在这个教程中,我将演示如何使用代理创建一个自定义的数学应用,利用 OpenAI 的 GPT3.5 模型。对于应用前端,我将使用,这是一个易于使用的开源 Python 框架。这个生成式数学应用,我们可以称之为“数学天才”,旨在
原文:
towardsdatascience.com/building-a-math-application-with-langchain-agents-23919d09a4d3
在这个教程中,我将演示如何使用LangChain代理创建一个自定义的数学应用,利用 OpenAI 的 GPT3.5 模型。对于应用前端,我将使用Chainlit,这是一个易于使用的开源 Python 框架。这个生成式数学应用,我们可以称之为“数学天才”,旨在帮助用户解决数学或推理/逻辑问题。
“数学天才”的应用架构图。插图由作者绘制。
为什么大型语言模型(LLMs)在数学上遇到困难?
大型语言模型(LLMs)在数学以及推理任务上表现不佳是众所周知的,这是许多语言模型的共同特征。造成这种情况有几个不同的原因:
-
**训练数据不足:**一个原因是它们训练数据的局限性。在庞大的文本数据集上训练的语言模型可能缺乏足够的数学问题和解决方案。这可能导致对数字的误解、忘记重要的计算步骤以及缺乏定量推理技能。
-
**缺乏数值表示:**另一个原因是 LLMs 被设计成理解和生成文本,它们在操作上使用的是标记而不是数值。大多数基于文本的任务可以有多个合理的答案。然而,数学问题通常只有一个正确解。
-
**生成性:**由于这些语言模型的生成性,对于 LLMs 来说,生成对数学问题始终准确和精确的答案可能具有挑战性。
这使得“数学问题”成为利用 LangChain 代理的完美候选者。代理是使用语言模型与其他工具交互以分解复杂问题的系统(更多内容将在后面介绍)。本教程的代码可在我的GitHub上找到。
环境设置
我们可以先创建一个新的conda环境,使用python=3.11。
conda create -n math_assistant python=3.11
激活环境:
conda activate math_assistant
接下来,让我们安装所有必要的库:
pip install -r requirements.txt
在OpenAI注册并获取自己的密钥以开始调用 gpt 模型。一旦你有了密钥,在你的仓库中创建一个.env文件并存储 OpenAI 密钥:
OPENAI_API_KEY="your_openai_api_key"
应用流程
Math Wiz 的应用流程概述在下方的流程图中。我们管道中的代理将有一套工具可供使用,以回答用户查询。大型语言模型(LLM)作为代理的“大脑”,指导其决策。当用户提交问题,代理使用 LLM 选择最合适的工具或工具组合来提供答案。如果代理确定需要多个工具,它还将指定工具的使用顺序。
LangChain 代理分解。作者插画
我们 Math Wiz 应用的代理将使用以下工具:
-
维基百科工具:这个工具将负责使用维基百科 API 获取最新的维基百科信息。虽然 LangChain 中可以集成付费工具和 API,但我将使用维基百科作为应用的网络信息来源。
-
计算器工具:这个工具将负责解决用户的数学查询。这包括任何涉及数值计算的内容。例如,如果用户询问 4 的平方根是什么,这个工具就适用。
-
推理工具:在我们的应用设置中,最后的工具将是一个推理工具,负责处理基于逻辑/推理的用户查询。任何数学应用题也应该由这个工具来处理。
现在我们有了大致的应用设计,我们可以开始考虑构建这个应用。
理解 LangChain 代理
LangChain 代理旨在通过提供更复杂和交互式任务的接口来增强与语言模型的交互。我们可以将代理视为用户和大型语言模型之间的中介。代理旨在将看似复杂的用户查询分解成更简单、可执行的步骤。
在我们的应用流程中,我们定义了一些不同的工具,我们希望在我们的数学应用中使用这些工具。根据用户输入,代理应该决定使用这些工具中的哪一个。如果一个工具不是必需的,则不应使用。LangChain 代理可以简化这一点。这些代理使用语言模型来选择要采取的一系列操作。本质上,LLM 充当代理的“大脑”,指导它针对特定查询使用哪个工具,以及使用顺序。这与 LangChain 链不同,在 LangChain 链中,操作序列是硬编码在代码中的。LangChain 提供了一整套可以与代理集成的工具。这些工具包括但不限于在线搜索工具、基于 API 的工具、基于链的工具等。有关 LangChain 代理及其类型的更多信息,请参阅此。
步骤-by-步骤实现
第 1 步
创建一个chatbot.py脚本并导入必要的依赖项:
from langchain_openai import OpenAI
from langchain.chains import LLMMathChain, LLMChain
from langchain.prompts import PromptTemplate
from langchain_community.utilities import WikipediaAPIWrapper
from langchain.agents.agent_types import AgentType
from langchain.agents import Tool, initialize_agent
from dotenv import load_dotenv
load_dotenv()
第 2 步
接下来,我们将定义我们的基于 OpenAI 的语言模型。LangChain 提供了langchain-openai包,可以用来定义 OpenAI 模型的一个实例。我们将使用 OpenAI 的gpt-3.5-turbo-instruct模型。dotenv包已经处理了 API 密钥,因此你在这里不需要明确定义它:
llm = OpenAI(model='gpt-3.5-turbo-instruct',
temperature=0)
我们将在这个 LLM(大型语言模型)中同时使用我们的数学和推理链,并将其作为我们代理的决策者。
第 3 步
当构建自己的代理时,你需要提供它可以使用的工具列表。除了实际调用的函数外,Tool还包括几个其他参数:
-
name(字符串),是必需的,并且必须在提供给代理的工具集中是唯一的。 -
description(字符串),是可选的但推荐使用,因为它被代理用来确定工具的使用。
我们现在将创建我们的三个工具。第一个将是使用维基百科 API 包装器的在线工具:
wikipedia = WikipediaAPIWrapper()
wikipedia_tool = Tool(name="Wikipedia",
func=wikipedia.run,
description="A useful tool for searching the Internet
to find information on world events, issues, dates, years, etc. Worth
using for general topics. Use precise questions.")
在上面的代码中,我们定义了一个维基百科 API 包装器的实例。之后,我们将其包装在 LangChain 的Tool中,包括名称、函数和描述。
接下来,让我们定义我们将用于计算任何数值表达式的工具。LangChain 提供了LLMMathChain,它使用numexprPython 库来计算数学表达式。明确定义这个工具将用于什么也很重要。描述可以帮助代理在特定用户查询的工具集中决定使用哪个工具。对于我们的基于链的工具,我们将使用Tool.from_function()方法。
problem_chain = LLMMathChain.from_llm(llm=llm)
math_tool = Tool.from_function(name="Calculator",
func=problem_chain.run,
description="Useful for when you need to answer questions
about math. This tool is only for math questions and nothing else. Only input
math expressions.")
最后,我们将定义用于基于逻辑/推理查询的工具。我们首先创建一个提示来指导模型执行特定任务。然后,我们将为这个工具创建一个简单的LLMChain,传递 LLM 和提示。
word_problem_template = """You are a reasoning agent tasked with solving
the user's logic-based questions. Logically arrive at the solution, and be
factual. In your answers, clearly detail the steps involved and give the
final answer. Provide the response in bullet points.
Question {question} Answer"""
math_assistant_prompt = PromptTemplate(input_variables=["question"],
template=word_problem_template
)
word_problem_chain = LLMChain(llm=llm,
prompt=math_assistant_prompt)
word_problem_tool = Tool.from_function(name="Reasoning Tool",
func=word_problem_chain.run,
description="Useful for when you need
to answer logic-based/reasoning questions.",
)
第 4 步
我们现在将使用我们上面创建的工具初始化我们的代理。我们还将指定 LLM 以帮助它选择使用哪些工具以及它们的顺序:
agent = initialize_agent(
tools=[wikipedia_tool, math_tool, word_problem_tool],
llm=llm,
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
verbose=False,
handle_parsing_errors=True
)
print(agent.invoke(
{"input": "I have 3 apples and 4 oranges. I give half of my oranges
away and buy two dozen new ones, alongwith three packs of
strawberries. Each pack of strawberry has 30 strawberries.
How many total pieces of fruit do I have at the end?"}))
应用程序对逻辑问题的回答
创建 Chainlit 应用程序
我们将使用Chainlit,一个开源的 Python 框架,来构建我们的应用程序。使用 Chainlit,你可以用几行简单的代码构建对话式人工智能应用程序。要深入了解 Chainlit 的功能以及应用程序的设置,你可以查看我的文章:
我们将在我们的应用程序中使用两个装饰器函数。这些将是 @cl.on_chat_start 和 @cl.on_message 装饰器函数。@cl.on_chat_start 将负责包装在用户会话启动时应执行的所有代码。@cl.on_message 将包含我们希望在用户发送查询时执行的代码片段。
让我们使用这两个装饰器函数重构我们的 chatbot.py 脚本。让我们首先将 chainlit 包导入到我们的 chatbot.py 脚本中:
import chainlit as cl
接下来,让我们编写围绕 @cl.on_chat_start 装饰器函数的包装函数。我们将在此函数中添加我们的 LLM、工具和代理初始化代码。我们将把我们的 agent 存储在用户会话内的一个变量中,以便在用户发送消息时检索。
@cl.on_chat_start
def math_chatbot():
llm = OpenAI(model='gpt-3.5-turbo-instruct',
temperature=0)
# prompt for reasoning based tool
word_problem_template = """You are a reasoning agent tasked with solving t he user's logic-based questions. Logically arrive at the solution, and be factual. In your answers, clearly detail the steps involved and give the final answer. Provide the response in bullet points. Question {question} Answer"""
math_assistant_prompt = PromptTemplate(
input_variables=["question"],
template=word_problem_template
)
# chain for reasoning based tool
word_problem_chain = LLMChain(llm=llm,
prompt=math_assistant_prompt)
# reasoning based tool
word_problem_tool = Tool.from_function(name="Reasoning Tool",
func=word_problem_chain.run,
description="Useful for when you need to answer logic-based/reasoning questions."
)
# calculator tool for arithmetics
problem_chain = LLMMathChain.from_llm(llm=llm)
math_tool = Tool.from_function(name="Calculator",
func=problem_chain.run,
description="Useful for when you need to answer numeric questions. This tool is only for math questions and nothing else. Only input math expressions, without text",
)
# Wikipedia Tool
wikipedia = WikipediaAPIWrapper()
wikipedia_tool = Tool(
name="Wikipedia",
func=wikipedia.run,
description="A useful tool for searching the Internet to find information on world events, issues, dates, "
"years, etc. Worth using for general topics. Use precise questions.",
)
# agent
agent = initialize_agent(
tools=[wikipedia_tool, math_tool, word_problem_tool],
llm=llm,
agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
verbose=False,
handle_parsing_errors=True
)
cl.user_session.set("agent", agent)
接下来,让我们定义 @cl.on_message 装饰器的包装函数。这将包含当用户向我们的应用程序发送查询时的代码。我们首先将检索在会话开始时设置的代理,然后异步调用它。
@cl.on_message
async def process_user_query(message: cl.Message):
agent = cl.user_session.get("agent")
response = await agent.acall(message.content,
callbacks=[cl.AsyncLangchainCallbackHandler()])
await cl.Message(response["output"]).send()
我们可以使用以下命令运行我们的应用程序:
chainlit run chatbot.py
应用程序应在 localhost:8000 上可用。
让我们也在我们的仓库中编辑 chainlit.md 文件。当你运行上述命令时,它会自动创建。
# Welcome to Math Wiz! 🤖
Hi there! 👋 I am a reasoning tool to help you with your math or logic-based reasoning questions. How can I
help today?
刷新浏览器标签页以使更改生效。
数学大师前端。图片由作者提供
示例
应用程序的演示可以在此查看:
测试和验证
现在让我们验证我们机器人的性能。我们没有在我们的机器人中集成任何内存,因此每个查询都必须是它自己的函数调用。让我们向我们的应用程序提出几个数学问题。为了比较,我附上了来自 Chat GPT 3.5 和我们的数学大师应用程序的相同查询的每个响应的截图。
算术问题
问题 1
What is the cube root of 625?
# correct answer = 8.5498
数学大师对:“625 的立方根是多少?”的回应。图片由作者提供。
ChatGPT 对:“625 的立方根是多少?”的回应。图片由作者提供。
我们的数学大师应用程序能够正确回答。然而,ChatGPT 的回应是错误的。
问题 2
what is cube root of 81? Multiply with 13.27, and subtract 5.
# correct answer = 52.4195
数学大师对:“81 的立方根是多少?乘以 13.27,然后减去 5。”的回应。图片由作者提供。
Chat GPT 对:“81 的立方根是多少?乘以 13.27,然后减去 5。”的回答。图片由作者提供。
我们的数学达人应用也能正确回答这个问题。然而,ChatGPT 的回答再次不正确。偶尔,ChatGPT 可以正确回答数学问题,但这取决于提示工程和多个输入。
推理问题
问题 1
让我们向我们的应用提出一些推理/逻辑问题。其中一些问题包含算术成分。我期望代理能够决定在每种情况下使用哪种工具。
I have 3 apples and 4 oranges. I give half of my oranges away and buy two
dozen new ones, alongwith three packs of strawberries. Each pack of
strawberry has 30 strawberries. How many total pieces of fruit do I have at
the end?
# correct answer = 3 + 2 + 24 + 90 = 119
数学达人对计算总水果数量的回答。图片由作者提供。
ChatGPT 对计算总水果数量的回答。图片由作者提供。
我们的数学达人应用能够正确回答这个问题。然而,ChatGPT 的回答是错误的。它不仅无必要地复杂化了推理步骤,而且未能得出正确答案。然而,在另一个场合,ChatGPT 能够正确回答这个问题。这当然是不可靠的。
问题 2
Steve's sister is 10 years older than him. Steve was born when the cold war
ended. When was Steve's sister born?
# correct answer = 1991 - 10 = 1981
数学达人对基于历史事件计算年龄的回答。图片由作者提供。
ChatGPT 基于历史事件计算年龄的回答。图片由作者提供。
我们的数学达人应用能够正确回答这个问题。ChatGPT 的回答再次是错误的。尽管它能够正确地计算出冷战结束的年份,但在数学部分的计算上出了错。因为比史蒂夫大 10 岁,妹妹的年龄计算应该从史蒂夫出生的那一年减去。ChatGPT 执行了加法,这表明它缺乏推理能力。
问题 3
give me the year when Tom Cruise's Top Gun released raised to the power 2
# correct answer = 1987**2 = 3944196
数学达人对基于电影上映日期的算术问题的回答。图片由作者提供。
ChatGPT 对基于电影上映日期的算术问题的回答。图片由作者提供。
我们的数学达人应用能够正确回答这个问题。ChatGPT 的回答再次是错误的。尽管它能够正确地计算出电影的上映日期,但最后的计算是错误的。
结论与下一步
在这个教程中,我们使用了 LangChain 代理和工具来创建一个数学求解器,它还能处理用户的推理/逻辑问题。我们看到我们的 Math Wiz 应用正确回答了所有问题,然而,ChatGPT 给出的大多数答案都是错误的。这是构建工具的一个很好的第一步。然而,如果输入包含基于字符串的文本,LLMMathChain可能会失败。这可以通过几种不同的方式来解决,例如为你的代码创建错误处理工具,为LLMMathChain添加后处理逻辑,以及使用自定义提示。你还可以通过包括一个用于更复杂和准确结果的搜索工具来提高工具的有效性,因为维基百科有时可能没有更新信息。你可以在我的GitHub上找到这个教程的代码。
如果你觉得这个教程有帮助,请考虑通过给它五十个赞来支持。你可以跟随,我会分享 AI 空间中的工作演示、解释和有趣的项目。在LinkedIn和X上跟我打招呼!我在那里分享指南、代码片段和其他有用的内容。👋
更多推荐



所有评论(0)