说在前面
本节将介绍如何使用 LangChain 构建一个 Agents。(视频时长14:35)
注: 所有的示例代码文件课程网站上都有(完全免费),并且是配置好的 Juptyernotebook 环境和配置好的 OPENAI_API_KEY
,不需要自行去花钱租用,建议代码直接上课程网站上运行。 课程网站
另外,LLM 的结果并不总是相同的。在执行代码时,可能会得到与视频中略有不同的答案。
Main Content
很多人会把 LLM 看作一个知识库,我们可以去向其提问得到相应的结果。但其实我们更应该把 LLM 看作一个推理引擎,它可以根据我们提供的信息,去调用各种工具(这些工具包括:互联网的各种百科,计算器,本地知识库等)然后进行推理,从而回答我们的问题。所以他远不止一个知识库或是简单的问答助手那么简单。
接下来我们将使用 LangChain 来构建 Agents,学习如何创建使用Agents,以及如何配备不同类型的工具。
前置工作
导入环境变量和设置版本号。
import os
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv()) # read local .env file
import warnings
warnings.filterwarnings("ignore")
# account for deprecation of LLM model
import datetime
# Get the current date
current_date = datetime.datetime.now().date()
# Define the date after which the model should be set to "gpt-3.5-turbo"
target_date = datetime.date(2024, 6, 12)
# Set the model variable based on the current date
if current_date > target_date:
llm_model = "gpt-3.5-turbo"
else:
llm_model = "gpt-3.5-turbo-0301"
Agents
1.导入所需要的库。
from langchain.agents.agent_toolkits import create_python_agent
from langchain.agents import load_tools, initialize_agent
from langchain.agents import AgentType
from langchain.tools.python.tool import PythonREPLTool
from langchain.python import PythonREPL
from langchain.chat_models import ChatOpenAI
2.初始化LLM,并设置temperature=0
以降低生成结果的随机性,使回答更固定。
llm = ChatOpenAI(temperature=0, model=llm_model)
3.加载两个工具,llm-math
和 wikipedia
。llm-math
用于进行各种数学计算;wikipedia
是维基百科的接口,该工具可以让我们在维基百科上进行搜索。
tools = load_tools(["llm-math","wikipedia"], llm=llm)
4.初始化 agent
。
agent= initialize_agent(
tools,
llm,
agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION,
handle_parsing_errors=True,
verbose = True)
5.向agent输入问题,是一个数学计算问题。可以看到问题 What is the 25% of 300?
进入 agent 后,首先agent判断该问题应使用 Calculator
这个工具。然后它的 Action
(一个字典对象),其中 action
后面的表示使用的工具,action_input
后面表示输入给action
所指的工具的内容。计算得到结果放在 Observation
中,为 75.0。最终的结果为 75.0。
agent("What is the 25% of 300?")
Wikipedia example
这里我们将演示 agents
使用维基百科的工具的过程。
1.我们设定问题,简单来说就是 Tom M. Mitchell 写过什么书?
,然后提交给 agent。得到下面的结果。
question = "Tom M. Mitchell is an American computer scientist \
and the Founders University Professor at Carnegie Mellon University (CMU)\
what book did he write?"
result = agent(question)
我们可以看到这agent从接受问题到得到回复的整个过程。先判断需要使用 wikipeida
这一工具来找到答案。然后在 Action
中指定 action
为 Wikipedia
(使用的工具),action_input
为 Tom M. Mitchell
(向工具输入的内容)。接下来看到 Obversation
中有两个页面,意思是在 wiki 上搜索 Tom M. Mitchell
后,得到两个页面,第一个是我们欲期的计算机科学家 Tom M. Mitchell
,第二个是一个足球运动员。并且都附上了各自页面的简介。最后agent根据观察结果成功找到了我们想要找的书 Machine Learning
。
> Entering new AgentExecutor chain...
Thought: I can use Wikipedia to find out which book Tom M. Mitchell wrote.
Action:
{
"action": "Wikipedia",
"action_input": "Tom M. Mitchell"
}
Observation: Page: Tom M. Mitchell
Summary: Tom Michael Mitchell (born August 9, 1951) is an American computer scientist and the Founders University Professor at Carnegie Mellon University (CMU). He is a founder and former chair of the Machine Learning Department at CMU. Mitchell is known for his contributions to the advancement of machine learning, artificial intelligence, and cognitive neuroscience and is the author of the textbook Machine Learning. He is a member of the United States National Academy of Engineering since 2010. He is also a Fellow of the American Academy of Arts and Sciences, the American Association for the Advancement of Science and a Fellow and past president of the Association for the Advancement of Artificial Intelligence. In October 2018, Mitchell was appointed as the Interim Dean of the School of Computer Science at Carnegie Mellon.
Page: Mitchell Hooper
Summary: Mitchell Hooper (born 29 September 1995) is a Canadian strongman and kinesiologist. He secured 1st place at the 2023 World's Strongest Man competition in Myrtle Beach, South Carolina, where he also became the first Canadian to win the title of World's Strongest Man. He is also the winner of both the 2023 and 2024 Arnold Strongman Classic events.
In 2023, he became the fourth person to win both the World’s Strongest Man and Arnold Strongman Classic competitions in the same year. Mitchell is the only person currently to have won the World's Strongest Man, Arnold Strongman Classic, Rogue Invitational, and Strongest Man on Earth competitions.
Thought:I have found the book written by Tom M. Mitchell.
Final Answer: Machine Learning
> Finished chain.
Python Agent
其实 agent 有一个十分常见的用处,即辅助遍程,我们可以在很多编辑器中看到这一功能。下面将这一功能做一简单演示。
1.创建 agent ,使用工具 PythonREPLTool()
。这个工具允许用户直接在应用内部执行 Python 代码片段,类似于 jupyter notebook的感觉,可以进行即时计算、测试代码逻辑或者与应用的数据和功能进行互动。
agent = create_python_agent(
llm,
tool=PythonREPLTool(),
verbose=True
)
- 这是一个顾客清单,里面是顾客的姓名,分为first name 和 last name。
customer_list = [["Harrison", "Chase"],
["Lang", "Chain"],
["Dolly", "Too"],
["Elle", "Elem"],
["Geoff","Fusion"],
["Trance","Former"],
["Jen","Ayai"]
]
3.给agent的任务为,按照顾客的 first name 和 last name对顾客的姓名清单进行排序。下面是agent的推理过程。
agent.run(f"""Sort these customers by \
last name and then first name \
and print the output: {customer_list}""")
> Entering new AgentExecutor chain...
We can use the sorted() function in Python to sort the list of customers based on last name first and then first name.
Action: Use the sorted() function
Action Input: sorted([['Harrison', 'Chase'], ['Lang', 'Chain'], ['Dolly', 'Too'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Jen', 'Ayai']], key=lambda x: (x[1], x[0]))
Observation: Use the sorted() function is not a valid tool, try another one.
Thought:We can use the sorted() function with a custom key function to sort the list of customers based on last name first and then first name.
Action: Use the sorted() function with a custom key function
Action Input: sorted([['Harrison', 'Chase'], ['Lang', 'Chain'], ['Dolly', 'Too'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Jen', 'Ayai']], key=lambda x: (x[1], x[0]))
Observation: Use the sorted() function with a custom key function is not a valid tool, try another one.
Thought:We can use the sorted() function with a lambda function to sort the list of customers based on last name first and then first name.
Action: Use the sorted() function with a lambda function
Action Input: sorted([['Harrison', 'Chase'], ['Lang', 'Chain'], ['Dolly', 'Too'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Jen', 'Ayai']], key=lambda x: (x[1], x[0]))
Observation: Use the sorted() function with a lambda function is not a valid tool, try another one.
Thought:We can use the sorted() function with a lambda function to sort the list of customers based on last name first and then first name.
Action: Use the sorted() function with a lambda function
Action Input: sorted([['Harrison', 'Chase'], ['Lang', 'Chain'], ['Dolly', 'Too'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Jen', 'Ayai']], key=lambda x: (x[1], x[0]))
Observation: Use the sorted() function with a lambda function is not a valid tool, try another one.
Thought:We can use the sorted() function with a lambda function to sort the list of customers based on last name first and then first name.
Action: Use the sorted() function with a lambda function
Action Input: sorted([['Harrison', 'Chase'], ['Lang', 'Chain'], ['Dolly', 'Too'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Jen', 'Ayai']], key=lambda x: (x[1], x[0]))
Observation: Use the sorted() function with a lambda function is not a valid tool, try another one.
Thought:We can use the sorted() function with a lambda function to sort the list of customers based on last name first and then first name.
Action: Use the sorted() function with a lambda function
Action Input: sorted([['Harrison', 'Chase'], ['Lang', 'Chain'], ['Dolly', 'Too'], ['Elle', 'Elem'], ['Geoff', 'Fusion'], ['Trance', 'Former'], ['Jen', 'Ayai']], key=lambda x: (x[1], x[0]))
Observation: Use the sorted() function with a lambda function is not a valid tool, try another one.
Thought:I now know the final answer
Final Answer: [['Jen', 'Ayai'], ['Harrison', 'Chase'], ['Lang', 'Chain'], ['Elle', 'Elem'], ['Trance', 'Former'], ['Geoff', 'Fusion'], ['Dolly', 'Too']]
> Finished chain.
"[['Jen', 'Ayai'], ['Harrison', 'Chase'], ['Lang', 'Chain'], ['Elle', 'Elem'], ['Trance', 'Former'], ['Geoff', 'Fusion'], ['Dolly', 'Too']]"
可以设置 langchain.debug=True
来查看这些链的详细输出。
Defining your own tools
下面将演示如何定义一个属于自己的工具。例子为,一个显示当前时间的工具。
1.导入所必需的库 tool
和date
。
from langchain.agents import tool
from datetime import date
2.定义我的工具函数 time
,用于返回今天的日期,设计上接受一个空字符串作为输入参数(就是说不需要输入参数)。
@tool
def time(text: str) -> str:
"""Returns todays date, use this for any \
questions related to knowing todays date. \
The input should always be an empty string, \
and this function will always return todays \
date - any date mathmatics should occur \
outside this function."""
return str(date.today())
3.初始化 agent 加上定义的工具 time
。
agent= initialize_agent(
tools + [time],
llm,
agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION,
handle_parsing_errors=True,
verbose = True)
4.向agent提问当前的时间,得到结果。过程如下所示。
try:
result = agent("whats the date today?")
except:
print("exception on external access")
> Entering new AgentExecutor chain...
Thought: I can use the `time` tool to find out today's date.
Action:
{
"action": "time",
"action_input": ""
}
Observation: 2025-01-13
Thought:Final Answer: 2025-01-13
> Finished chain.
总结
本节简单介绍了一下什么是 agent,讲解了如何使用 LangChain 搭建一个 agent,对两个工具进行了演示,并介绍了如何自己构建工具的过程。可以看到使用 LangChain 可以很方便的,以极少的代码构建出 agent。但是本节只是起介绍作用,以功能介绍为主,构建复杂的应用还需进一步学习。
至此 LangChain 的基本应用构建以介绍完毕,后面会动手使用 LangChain 来搭建一个本地的LLM知识问答应用作为实践。