LangChain补充四:Agent知识点和案例补充
https://www.alang.ai/langchain/101/lc07
一:基本流程和概念
(一)概念
LangChain Agent的核心思想是,使用大语言模型选择一系列要执行的动作。
在Chain中,一系列动作是硬编码在代码中的。
在Agent中,大语言模型被用作推理引擎,以确定要采取的动作及其顺序。
它包括 3 个组件:
- 规划:将任务分解为较小的子目标
- 记忆:短期(聊天历史)/ 长期(向量存储)
- 工具使用:可以利用不同的工具来扩展其功能。
(二)基本流程
工具定义--->定义工具集--->定义prompt--->创建模型实例--->创建Agent(传递进入llm、tools、prompt)--->创建Agent Executor
补充:OpenAI API已弃用
functions,而推荐使用tools。两者之间的区别是,tools API允许一次模型请求使用多个函数调用,这可以减少响应时间。1.工具定义(这里以Serp搜索工具、自定义工具、RAG检索工具为例)
serp搜索需要用到ApiKey,参考https://serpapi.com/manage-api-key
- Serp搜索
SerpAPI使用案例:
from langchain_community.utilities import SerpAPIWrapper
search = SerpAPIWrapper()
res= search.run("周星驰生日那天是星期几")
print(res)
SerpAPI工具定义:通过第三方api和调用内部封装方式(下面就是工具集合)
#三方api
search = SerpAPIWrapper() #搜索引擎
Tool.from_function(
func=search.run,
name="Search",
description="useful for when you need to answer questions about current events" #问一下实时的事情
)
#内部的封装好的
tool = load_tools(["serpapi"])[0]
- 自定义tool:最常用扩展方式
from datetime import datetime
from langchain_core.tools import tool
#函数自定义
@tool("weekday")
def weekday(date_str:str) -> str:
"""Convert date to weekday name"""
date_object = datetime.strptime(date_str, '%Y-%m-%d')
weekday_number = date_object.weekday()
weekdays = ['星期一','星期二','星期三','星期四','星期五','星期六','星期日']
return weekdays[weekday_number]
print(weekday("2024-07-08"))
- 创建RAG检索工具(里面有调用大模型编码api)
RAG使用:
添加RAG工具:
from langchain.tools.retriever import create_retriever_tool
retriever_tool = create_retriever_tool(
retriever=retriever,
name="movie_search",
description="按电影发布年份搜索关于周星驰的电影,并且查询关于周星驰扮演的角色,对于这种类型的问题,you must use this tool!",
)
2.定义工具集
tools = [searchTool,weekday,retriever_tool]
3.定义prompt
#pip install langchainhub
from langchain import hub
prompt = hub.pull("hwchase17/openai-functions-agent")
[
SystemMessagePromptTemplate(
prompt=PromptTemplate(input_variables=[], template='You are a helpful assistant')),
MessagesPlaceholder(
variable_name='chat_history', optional=True),
HumanMessagePromptTemplate(
prompt=PromptTemplate(input_variables=['input'], template='{input}')),
MessagesPlaceholder(variable_name='agent_scratchpad')
]
注意:这里prompt里面指定了我们传递的变量key是input,如果后续需要传递历史消息,变量是chat_history
4.创建模型实例
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
5.创建Agent(传递进入llm、tools、prompt):这里以create_openai_tools_agent为例
from langchain.agents import create_openai_tools_agent
agent = create_openai_tools_agent(llm, tools, prompt)
6.创建Agent Executor
from langchain.agents import AgentExecutor
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
#设置 verbose=True,以观察 Agent 调用过程
(三)调用实例
1.不需要调用tool
res = agent_executor.invoke({"input": "hi!"})
print(res)
2.调用search工具
res = agent_executor.invoke({"input": "周星驰是谁?"})
print(res)
3.调用search和weekday工具
res = agent_executor.invoke({"input": "周星驰的生日是星期几"})
print(res)
4.调用 RAG 检索工具
res = agent_executor.invoke({"input": "周星驰在2004年主演了什么电影?饰演的角色叫什么?"})
print(res)
二:增加记忆力
class Runnable(Generic[Input, Output], ABC)
/ \
|
|
|
class RunnableSerializable(Serializable, Runnable[Input, Output])
/ \
|
|
|
class Chain(RunnableSerializable[Dict[str, Any], Dict[str, Any]], ABC)
/ \
|
|
|
class AgentExecutor(Chain)
我们可以看到agent继承chain,两者都是Runnable的子类,可以参考
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, #这里没有考虑session_id,对话只维护一个历史
input_messages_key="input",
history_messages_key="chat_history", #prompt指定了占位
)
agent_with_chat_history.invoke(
{"input": "周星驰在2004年主演了什么电影"},
config={"configurable": {"session_id": "1"}},
)
agent_with_chat_history.invoke(
{"input": "饰演了什么角色呢?"},
config={"configurable": {"session_id": "1"}},
)
三:LangChain的代理对比
https://python.langchain.com/v0.1/docs/modules/agents/agent_types/
https://cloud.tencent.com/developer/article/2404258
LLM Completions 已经被标记为 Legacy(不建议使用),所以在实际应用中,建议使用 Chat Model 类型的 Agent 就可以了
| 代理类型 | 模型类型 | 历史对话支持 | 支持多输入的工具 | 支持同时调用多工具 | 使用时机 |
| Tool Calling | Chat | ✅ | ✅ | ✅ | 使用tool-calling模型时 |
| OpenAI Tools | Chat | ✅ | ✅ | ✅ | 废弃,tool-calling代替 |
| OpenAI Functions | Chat | ✅ | ✅ | 废弃,tool-calling代替可以并发调用 | |
| XML | LLM | ✅ | 使用擅长XML的模型时(比如:Anthropic),就可以用到这个agent | ||
| Structured Chat | Chat | ✅ | ✅ | 需要支持多输入的工具时 | |
| JSON Chat | Chat | ✅ | 擅长json的模型,普通chat模型加上prompt即可 | ||
| ReAct | LLM | ✅ | 简单的模型 | ||
| Self Ask With Search | LLM | 简单的模型,只有一个搜索工具 |
补充:Structured Chat 和 JSON Chat 的区别在于对 tool 入参类型的支持上,参数越多,LLM 对工具的学习成本就会越高,Agent 有可能会越不稳定。
Json chat只支持单参数的tool
@tool
def search(query: str) -> str:
"""Look up things online."""
return "LangChain"
Structured chat支持多参数tool,可以替代json chat
@tool
def multiply(a: int, b: int) -> int:
"""Multiply two numbers."""
return a * b
Tool calling更🐮,都替代