构建一个具有两种工具的代理:一种用于在线查找,另一种用于查找加载到索引中的特定数据。
准备操作
在LangChain中有一个内置的工具,可以方便地使用Tavily搜索引擎作为工具。
访问Tavily(用于在线搜索)注册账号并登录,获取API 密钥
设置OpenAI和TAVILY的API密钥
import os
os.environ["OPENAI_BASE_URL"] = "https://xxx.com/v1"
os.environ["OPENAI_API_KEY"] = "sk-BGFnOL9Q4c99B378Bxxxxxxxxxxxxxxxx13bc437B82c2"
os.environ["TAVILY_API_KEY"] = 'tvly-Scx77cTxxxxxxxxxxxxx3rmxRIM8'
定义工具
首先需要创建想要使用的工具。这里使用两个工具:
Tavily(用于在线搜索)
创建的本地索引的检索器
1.Tavily在线搜索
# 加载所需的库
from langchain_community.tools.tavily_search import TavilySearchResults
# 查询 Tavily 搜索 API 并返回 json 的工具
search = TavilySearchResults()
# 执行查询
res = search.invoke("目前市场上苹果手机15的平均售价是多少?")
print(res)
执行查询结果如下:
2.创建检索器
根据上述查询结果中的某个URL中,获取一些数据创建一个检索器。
这里使用一个简单的本地向量库FAISS,使用FAISS的CPU版本,需要安装FAISS库:
pip install faiss-cpu
from langchain_community.document_loaders import WebBaseLoader
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter
# 加载HTML内容为一个文档对象
loader = WebBaseLoader("https://www.ithome.com/0/718/713.htm")
docs = loader.load()
# 分割文档
documents = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200).split_documents(docs)
# 向量化
vector = FAISS.from_documents(documents, OpenAIEmbeddings())
# 创建检索器
retriever = vector.as_retriever()
# 测试检索结果
print(retriever.get_relevant_documents("iPhone 15平均销售价格是多少?")[1])
检索结果如下:
3.得到工具列表
from langchain.tools.retriever import create_retriever_tool
# 创建一个工具来检索文档
retriever_tool = create_retriever_tool(
retriever,
"iPhone_price_search",
"搜索有关 iPhone 15 的价格信息。对于iPhone 15的任何问题,您必须使用此工具!",
)
# 创建将在下游使用的工具列表
tools = [search, retriever_tool]
初始化大模型
选择将驱动代理的LLM,为了模型回答更严谨,设置temperature=0
from langchain_openai import ChatOpenAI
# 初始化大模型
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
创建Agent
这里使用LangChain中一个叫OpenAI functions的代理,然后得到一个AgentExecutor代理执行器。
AgentExecutor是代理执行器,它实际上调用代理,执行其选择的操作,将操作输出传回代理,然后重复。
from langchain import hub
# 获取要使用的提示
prompt = hub.pull("hwchase17/openai-functions-agent")
# 打印Prompt
print(prompt)
# 使用OpenAI functions代理
from langchain.agents import create_openai_functions_agent
# 构建OpenAI函数代理:使用 LLM、提示模板和工具来初始化代理
agent = create_openai_functions_agent(llm, tools, prompt)
from langchain.agents import AgentExecutor
# 将代理与AgentExecutor工具结合起来
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
运行Agent
注意:目前这些都是无状态查询
# 执行代理
agent_executor.invoke({"input": "目前市场上苹果手机15的平均售价是多少?如果我在此基础上加价5%卖出,应该如何定价??"})
执行部分日志记录如下:
> Entering new AgentExecutor chain...
Invoking: `iPhone_price_search` with `{'query': 'iPhone 15 average selling price'}`
苹果 iPhone 15/Pro系列国行价格出炉,5999 元起 - IT之家
根据搜索结果,苹果 iPhone 15 系列的国行价格从 5999 元起售。如果您想在此基础上加价5%,您可以按照以下方式定价:
- iPhone 15:5999 元 + 5% = 6298.95 元
- iPhone 15 Plus:6999 元 + 5% = 7348.95 元
- iPhone 15 Pro:7999 元 + 5% = 8398.95 元
- iPhone 15 Pro Max:9999 元 + 5% = 10498.95 元
您可以根据以上价格定价出售您的苹果手机 15 系列产品。希望这可以帮助到您!
> Finished chain.
添加记忆
目前代理是无状态的,这意味着它不记得以前的交互。为了给它记忆,需要传入chat_history
。
注意:
chat_history
是正在使用提示符中的一个变量,因此需要调用它。如果使用不同的提示,可能需要更改变量名称
具体Prompt提示模板内容如下:
记忆测试:
# 加载所需的库
from langchain_community.tools.tavily_search import TavilySearchResults
# 查询 Tavily 搜索 API 并返回 json 的工具
search = TavilySearchResults()
# 创建将在下游使用的工具列表
tools = [search]
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
from langchain import hub
# 获取要使用的提示
prompt = hub.pull("hwchase17/openai-functions-agent")
# 使用OpenAI functions代理
from langchain.agents import create_openai_functions_agent
# 创建使用 OpenAI 函数调用的代理
agent = create_openai_functions_agent(llm, tools, prompt)
from langchain.agents import AgentExecutor
# 得到代理工具执行器
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
# 执行代理
# 传入一个空的消息列表给chat_history,因为它是聊天中的第一条消息
res = agent_executor.invoke({"input": "hi! my name is bob", "chat_history": []})
print(res)
from langchain_core.messages import AIMessage, HumanMessage
agent_executor.invoke(
{
"chat_history": [
HumanMessage(content=res['input']),
AIMessage(content=res['output']),
],
"input": "what's my name?",
}
)
执行日志如下,代理明显有了记忆
> Entering new AgentExecutor chain...
Hello Bob! How can I assist you today?
> Finished chain.
{'input': 'hi! my name is bob', 'chat_history': [], 'output': 'Hello Bob! How can I assist you today?'}
> Entering new AgentExecutor chain...
Your name is Bob! How can I assist you today, Bob?
> Finished chain.
自动跟踪这些消息,可以将其包装在RunnableWithMessageHistory中
from langchain_community.chat_message_histories import ChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory
message_history = ChatMessageHistory()
agent_with_chat_history = RunnableWithMessageHistory(
agent_executor,
lambda session_id: message_history,
input_messages_key="input",
history_messages_key="chat_history",
)
agent_with_chat_history.invoke(
{"input": "hi! I'm bob"},
config={"configurable": {"session_id": "<foo>"}},
)
agent_with_chat_history.invoke(
{"input": "what's my name?"},
config={"configurable": {"session_id": "<foo>"}},
)
执行日志如下:
> Entering new AgentExecutor chain...
Hello Bob! How can I assist you today?
> Finished chain.
> Entering new AgentExecutor chain...
Your name is Bob! How can I assist you, Bob?
> Finished chain.