运行根目录下几个ipynb文件- Learn-Agent.ipynb- 学习《Custom agent 自定义代理》部分- v1-Create-Custom-Agent.ipynb- v2-Create-Custom-Agent.ipynb- 基于v1,新增一些职位描述(JD)信息- v3-Create-Custom-Agent.ipynb- 基于v2,新增一些简历(CV)信息- Learn-Function calling.ipynb- 理解Function calling理念- 补充-路由链.ipynb- 与本课、与Agent无关,是前面课程遗留的知识点
一 Learn-Agent
1.1 Define tools 定义工具
- LangChain Decorators ✨ | 🦜️🔗 LangChain
from dotenv import load_dotenv, find_dotenvload_dotenv(find_dotenv())from langchain_community.document_loaders import WebBaseLoader
from langchain_community.vectorstores import FAISS
from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitterloader = WebBaseLoader("https://docs.smith.langchain.com/overview")
docs = loader.load()
documents = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200
).split_documents(docs)
vector = FAISS.from_documents(documents, OpenAIEmbeddings())
retriever = vector.as_retriever()retriever.get_relevant_documents("how to upload a dataset")[0]
from langchain.tools.retriever import create_retriever_toolretriever_tool = create_retriever_tool(retriever,"langsmith_search","Search for information about LangSmith. For any questions about LangSmith, you must use this tool!",
)tools = [retriever_tool]
1.2 Create the agent 创建代理
from langchain_openai import ChatOpenAIllm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)from langchain import hub# Get the prompt to use - you can modify this!
prompt = hub.pull("hwchase17/openai-functions-agent")
prompt.messagesfrom langchain.agents import create_openai_functions_agentagent = create_openai_functions_agent(llm, tools, prompt)from langchain.agents import AgentExecutoragent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
1.3 Run the agent 运行代理
agent_executor.invoke({"input": "hi!"})agent_executor.invoke({"input": "how can langsmith help with testing?"})
1.4 Adding in memory 添加内存
# Here we pass in an empty list of messages for chat_history because it is the first message in the chat
agent_executor.invoke({"input": "hi! my name is bob", "chat_history": []})
from langchain_core.messages import AIMessage, HumanMessageagent_executor.invoke({"chat_history": [HumanMessage(content="hi! my name is bob"),AIMessage(content="Hello Bob! How can I assist you today?"),],"input": "what's my name?",}
)
1.5 keep track of these messages automatically 自动跟踪这些消息
from langchain_community.chat_message_histories import ChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistorymessage_history = ChatMessageHistory()agent_with_chat_history = RunnableWithMessageHistory(agent_executor,# This is needed because in most real world scenarios, a session id is needed# It isn't really used here because we are using a simple in memory ChatMessageHistorylambda session_id: message_history,input_messages_key="input",history_messages_key="chat_history",
)agent_with_chat_history.invoke({"input": "hi! I'm bob"},# This is needed because in most real world scenarios, a session id is needed# It isn't really used here because we are using a simple in memory ChatMessageHistoryconfig={"configurable": {"session_id": "<foo>"}},
)
agent_with_chat_history.invoke({"input": "what's my name?"},# This is needed because in most real world scenarios, a session id is needed# It isn't really used here because we are using a simple in memory ChatMessageHistoryconfig={"configurable": {"session_id": "<foo>"}},
)
二 Concepts 概念
- Schema 图式
- Agent 代理
- AgentExecutor 代理执行器
- Tools 工具
- Toolkits 工具包
2.1 OpenAI tools
# Get the prompt to use - you can modify this!
prompt = hub.pull("hwchase17/openai-tools-agent")prompt.messages
2.2 JSON Chat Agent
# Get the prompt to use - you can modify this!
prompt = hub.pull("hwchase17/react-chat-json")prompt.messages
# Get the prompt to use - you can modify this!
prompt = hub.pull("hwchase17/structured-chat-agent")prompt.messagesprint(prompt.messages[0].prompt.template)
2.3 Structured chat
# Get the prompt to use - you can modify this!
prompt = hub.pull("hwchase17/structured-chat-agent")print(prompt.messages[0].prompt.template)
2.4 ReAct
# Get the prompt to use - you can modify this!
prompt = hub.pull("hwchase17/react")
promptprint(prompt.template)
# Get the prompt to use - you can modify this!
prompt = hub.pull("hwchase17/self-ask-with-search")
promptprint(prompt.template)
三 Custom agent 自定义代理
3.1 Load the LLM 加载LLM
from langchain_openai import ChatOpenAIllm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
3.2 Define Tools 定义工具
from langchain.agents import tool@tool
def get_word_length(word: str) -> int:"""Returns the length of a word."""return len(word)get_word_length.invoke("abc")tools = [get_word_length]tools
3.3 Create Prompt 创建提示
由于 OpenAI 函数调用针对工具使用进行了微调,因此我们几乎不需要任何关于如何推理或如何输出格式的说明。
我们将只有两个输入变量: input 和 agent_scratchpad 。
input 应为包含用户目标的字符串。
agent_scratchpad 应该是包含先前代理工具调用和相应工具输出的消息序列。
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholderprompt = ChatPromptTemplate.from_messages([("system","You are very powerful assistant, but don't know word's lens",),("user", "{input}"),MessagesPlaceholder(variable_name="agent_scratchpad"),]
)prompt.messages[0].prompt.template
# "You are very powerful assistant, but don't know current events"
3.4 Bind tools to LLM 将工具绑定到LLM
要将我们的工具传递给代理,我们只需将它们格式化为 OpenAI 工具格式,然后传递给我们的模型即可。(通过绑定函数,我们可以确保每次调用模型时都能将它们传入)。
llm_with_tools = llm.bind_tools(tools)llm_with_tools.kwargs['tools']
3.5 Create the Agent 创建代理
from langchain.agents.format_scratchpad.openai_tools import (format_to_openai_tool_messages,
)
from langchain.agents.output_parsers.openai_tools import OpenAIToolsAgentOutputParseragent = ({"input": lambda x: x["input"],"agent_scratchpad": lambda x: format_to_openai_tool_messages(x["intermediate_steps"]),}| prompt| llm_with_tools| OpenAIToolsAgentOutputParser()
)
3.6 Run the agent 运行代理
from langchain.agents import AgentExecutoragent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)agent_executor.invoke({"input": "How many letters in the word eudca"})
llm.invoke("How many letters in the word educa")
# AIMessage(content='5')
3.7 Adding memory 添加内存
from langchain.prompts import MessagesPlaceholderMEMORY_KEY = "chat_history"
prompt = ChatPromptTemplate.from_messages([("system","You are very powerful assistant, but bad at calculating lengths of words.",),MessagesPlaceholder(variable_name=MEMORY_KEY),("user", "{input}"),MessagesPlaceholder(variable_name="agent_scratchpad"),]
)from langchain_core.messages import AIMessage, HumanMessagechat_history = []agent = ({"input": lambda x: x["input"],"agent_scratchpad": lambda x: format_to_openai_tool_messages(x["intermediate_steps"]),"chat_history": lambda x: x["chat_history"],}| prompt| llm_with_tools| OpenAIToolsAgentOutputParser()
)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)input1 = "how many letters in the word educa?"
result = agent_executor.invoke({"input": input1, "chat_history": chat_history})
chat_history.extend([HumanMessage(content=input1),AIMessage(content=result["output"]),]
)
agent_executor.invoke({"input": "is that a real word?", "chat_history": chat_history})
四 Tools 工具
from langchain_community.tools import WikipediaQueryRun
from langchain_community.utilities import WikipediaAPIWrapperapi_wrapper = WikipediaAPIWrapper(top_k_results=1, doc_content_chars_max=100)
tool = WikipediaQueryRun(api_wrapper=api_wrapper)tool.name # 'wikipedia'
4.1 Defining Custom Tools 定义自定义工具
# Import things that are needed generically
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools import BaseTool, StructuredTool, tool@tool
def search(query: str) -> str:"""Look up things online."""return "LangChain"print(search.name)
print(search.description)
print(search.args)"""search
search(query: str) -> str - Look up things online.
{'query': {'title': 'Query', 'type': 'string'}}"""@tool
def multiply(a: int, b: int) -> int:"""Multiply two numbers."""return a * bprint(multiply.name)
print(multiply.description)
print(multiply.args)"""multiply
multiply(a: int, b: int) -> int - Multiply two numbers.
{'a': {'title': 'A', 'type': 'integer'}, 'b': {'title': 'B', 'type': 'integer'}}"""from langchain_openai import ChatOpenAI# 参数temperature设置为0.0,从而减少生成答案的随机性。
llm = ChatOpenAI(temperature=0)from langchain.agents import load_tools# llm-math 工具结合语言模型和计算器用以进行数学计算
# wikipedia工具通过API连接到wikipedia进行搜索查询。
tools = load_tools(["llm-math","wikipedia"], llm=llm #第一步初始化的模型
)from langchain.agents import initialize_agent
from langchain.agents import AgentType# 初始化代理
agent= initialize_agent(tools, #第二步加载的工具llm, #第一步初始化的模型agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION, #代理类型handle_parsing_errors=True, #处理解析错误verbose = True #输出中间步骤
)agent("计算300的25%")
question = "Tom M. Mitchell是一位美国计算机科学家,\
也是卡内基梅隆大学(CMU)的创始人大学教授。\
他写了哪本书呢?"agent(question)
from langchain import hub
base_prompt = hub.pull("langchain-ai/openai-functions-template")
base_promptbase_prompt.messagesfrom langchain_experimental.tools import PythonREPLTooltools = [PythonREPLTool()]instructions = """You are an agent designed to write and execute python code to answer questions.
You have access to a python REPL, which you can use to execute python code.
If you get an error, debug your code and try again.
Only use the output of your code to answer the question.
You might know the answer without running any code, but you should still run the code to get the answer.
If it does not seem like you can write code to answer the question, just return "I don't know" as the answer.
"""instructions = """您是一个设计用于编写和执行python代码以回答问题的代理。
您可以访问python REPL,可以使用它来执行python代码。
如果出现错误,请调试代码,然后重试。
只使用代码的输出来回答问题。
您可能在不运行任何代码的情况下就知道了答案,但您仍然应该运行代码来获得答案。
如果你似乎无法编写代码来回答这个问题,只需返回“我不知道”作为答案。
"""prompt = base_prompt.partial(instructions=instructions)
prompt
from langchain_openai import ChatOpenAI
from langchain.agents import create_openai_functions_agentagent = create_openai_functions_agent(ChatOpenAI(temperature=0), tools, prompt)
agent
from langchain.agents import AgentExecutor
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
agent_executorcustomer_list = ["小明","小黄","小红","小蓝","小橘","小绿",]agent_executor.invoke({"input": f"将使用pinyin拼音库这些客户名字转换为拼音,并打印输出列表: {customer_list}。"})
# !pip install pypinyinagent_executor.invoke({"input": f"将使用pinyin拼音库这些客户名字转换为拼音,并打印输出列表: {customer_list}。"})
import langchain
langchain.debug=True
agent_executor.invoke({"input": f"将使用pinyin拼音库这些客户名字转换为拼音,并打印输出列表: {customer_list}。"})
langchain.debug=False
import langchain
langchain.debug=True
agent_executor.invoke({"input": "第 10 个斐波那契数是多少?"})
langchain.debug=False
from langchain_openai import ChatOpenAIllm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)from langchain.agents import tool@tool
def get_word_length(word: str) -> int:"""Returns the length of a word."""return len(word)get_word_length.invoke("abc") # 3tools = [get_word_length]from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholderprompt = ChatPromptTemplate.from_messages([("system","You are very powerful assistant, but don't know current events",),("user", "{input}"),MessagesPlaceholder(variable_name="agent_scratchpad"),]
)llm_with_tools = llm.bind_tools(tools)
4.2 关联工具
from langchain.agents.format_scratchpad.openai_tools import (format_to_openai_tool_messages,
)
from langchain.agents.output_parsers.openai_tools import OpenAIToolsAgentOutputParseragent = ({"input": lambda x: x["input"],"agent_scratchpad": lambda x: format_to_openai_tool_messages(x["intermediate_steps"]),}| prompt| llm_with_tools| OpenAIToolsAgentOutputParser()
)from langchain.agents import AgentExecutoragent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)list(agent_executor.stream({"input": "How many letters in the word eudca"}))
# 导入tool函数装饰器
from langchain.agents import tool
from datetime import date@tool
def time(text: str) -> str:"""返回今天的日期,用于任何需要知道今天日期的问题。\输入应该总是一个空字符串,\这个函数将总是返回今天的日期,任何日期计算应该在这个函数之外进行。"""return str(date.today())# 初始化代理
agent= initialize_agent(tools=[time], #将刚刚创建的时间工具加入代理llm=llm, #初始化的模型agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION, #代理类型handle_parsing_errors=True, #处理解析错误verbose = True #输出中间步骤
)# 使用代理询问今天的日期.
# 注: 代理有时候可能会出错(该功能正在开发中)。如果出现错误,请尝试再次运行它。
agent("今天的日期是?")