運行根目錄下幾個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("今天的日期是?")