写在前文
什么是Agent?
是一种能够感知环境、自主决策并采取行动以实现特定目标的智能程序或系统
是指一种能够模拟人类思考和行为来自动执行任务,以解决复杂问题的程序或系统;
以下是我个人理解,可能不太准确。
比如我们可以把Agent理解为是一个人,独立自己的一个有独立思考、行动能力的人,人的大脑是“规划模块”也有记忆功能,而人的眼睛、鼻子、耳朵是“感知模块”、人的手脚是“行动模块”,锄头、刀、勺子、叉子就是“工具模块”了。
也就是说,假如你有一个指令,比如你要计算“1+1等于几”。你把命令发给这个人也就是Agent,Agent的规划模块即这个人的大脑就会去规划他的行动---比如需要什么步骤才能完成任务?比如需要那些工具?需要怎么做才能得到结果?聪明的Agent也会根据其他信息去验证结果的准确性,然后把最准确的答案反馈给你。
如果把Agent比作一个人,所以在“1+1等于几”这个命令的驱动下,可能会发生如下步骤:
1、你告诉这个人你需要计算1+1等于几。
2、这个人Agent,拿到这个指令后,会去规划怎么才能完成这个命令。比如我需要用手(行动)去使用计算器(工具)才能计算,
3、此刻你只有手,你是找不到计算器的,这时候你明白,需要眼睛(感知)去帮你找到你的计算器。
4、但是光有感知和行动还是不够,你家很大,你不可能说为了找一个计算器,把整个家翻出来吧?这就需要你的大脑的记忆来帮你找到计算器了。在你的记忆中,你知道计算器在哪里。
5、但是有了记忆、有了眼睛、有了手,你依然不一定能拿到你的计算器,这个时候可能还需要脚(另外的行动),带你走过去。可能还需要梯子(额外的工具),带你爬上去...等等之类的。
6、最终流程可能就是:你收到指令以后,经过大脑的分析,你需要计算器来获得答案,在你的记忆中,你的计算器在2楼的衣柜顶部,这个时候你就需要一个梯子工具、手脚行动、眼睛感知、大脑记忆模块来共同行动你才能拿到计算器。也就是说,首先你通过记忆知道你的梯子在三楼,然后控制你脚根据眼睛的视线感知,你去三楼用手搬一个梯子到二楼的衣柜旁边,然后架上梯子去拿衣柜顶部的计算器,再用手输入你的数字计算获得最终答案。获得答案后,你通过视觉感知,在通过嘴巴喉咙的行动模块告诉发给你命令的这个人。
当然,聪明的智能体,他可能会通过其他信息,来验证这个答案是否正确,而不仅仅是根据指令去完成任务...。
Agent就一个创建Agent(人)+Agent执行器(手脚);
agent类型
--- 好像在传统定义Agent的时候会用到,但是在使用langgraph的时候不会用到~~~~ 会话类型CONVERSATIONAL_REACT_DESCRIPTION:其他代理通常优化用于查找最佳响应的工具,但在对话环境中这并不理想,因为您可能希望代理能够与用户进行聊天。 聊天模型CHAT_CONVERSATIONAL_REACT_DESCRIPTION:使用聊天模型创建对话代理,而不是 LLM。 结构化工具聊天STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION: OPENAI函数OPENAI_FUNCTIONS: 自问自答带搜索SELF_ASK_WITH_SEARCH:
创建方法
1、使用 create_tool_calling_agent 创建 agent 、使用 AgentExecutor 创建 Agent_Executor
2、使用 create_openai_tools_agent 创建 agent 、使用 AgentExecutor 创建 Agent_Executor
3、使用 initialize_agent 创建 agent
4、使用 langchain 的 create_react_agent 创建 agent 和 executor
5、使用 langgraph 的 create_react_agent 创建 agent
6、使用 langgraph 的 create_tool_calling_executor创建Agent --- 工作中推荐
7、原生ReActAgent --- 了解
初始化
初始化工具包
其他方法,见上一篇
os.environ['serpapi_api_key'] = 'xxxxxxxx'
os.environ["TAVILY_API_KEY"] = 'tvly-xxxxxxxx'
# 提供了很多常用的网站,比如天气网站,可以查询到很多天气
tavily = TavilySearchResults(max_results=2)
# 提供了搜索功能
serpApi = SerpAPIWrapper()
@tool("xiang_u")
def xiang_U(a: int, b: int) -> int:
""" a和b参数需要“U”时才会使用
Args:
a: First integer
b: Second integer
"""
print(f'调用了U函数:[{a},{b}]')
return a + b
@tool("xiang_t")
def xiang_T(a: int, b: int) -> int:
""" a和b参数需要“T”时才会使用
Args:
a: First integer
b: Second integer
"""
print(f'调用了T函数:[{a},{b}]')
return a * b
@tool("add", return_direct=True)
def add_(a: int, b: int) -> int:
"""Add two integers.
Args:
a: First integer
b: Second integer
"""
return a + b
@tool("multiply", return_direct=True)
def multiply_(a: int, b: int) -> int:
"""Multiply two integers.
Args:
a: First integer
b: Second integer
"""
return a * b
@tool("tavily", return_direct=True)
def tavily_(question: str):
"""
只有需要了解某个地方和某日的天气时才会调用这个工具
:return:
"""
print(f"调用天气工具了...{question}")
return tavily.run(question)
@tool("serpApi", return_direct=True)
def serpApi_(question: str):
"""
只有需要了解实时信息或者不知道的事情的时候才会使用这个工具
:return:
"""
print(f"调用搜索工具了...{question}")
return serpApi.run(question)
初始化LLMs并与工具集合绑定
from typing import TypedDict, Annotated
from langchain.agents import create_tool_calling_agent, AgentExecutor, create_openai_tools_agent, initialize_agent, \
AgentType
from langchain.memory import ConversationBufferMemory
from langchain_core.messages import HumanMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables import RunnableWithMessageHistory
from langgraph.checkpoint.memory import MemorySaver, InMemorySaver
from langgraph.graph import add_messages, StateGraph
from langgraph.prebuilt import create_react_agent, chat_agent_executor
from tensorboard.notebook import display
from utils import *
# 工具集合
tools = [add_, multiply_, tavily_, serpApi_, xiang_T, xiang_U]
# ### DK系列的好像都不支持tool调用,Qwen系有一部分不支持...
# #### llama 不支持调用 Tools ,所以此处报错...:does not support tools (status code: 400)
# 支持工具调用:部分Qwen(qwen2.5)、llama3.1:latest、llama3-groq-tool-use(这个好像是微调了...)、部分ChatGLM
llm = ChatOpenAI(base_url='https://open.bigmodel.cn/api/paas/v4/',
api_key='ءءءءء.ءءءء',
model='glm-4-plus',
temperature=0.8,
verbose=False)
### 绑定tools时是不会自动自行方法的,需要我们手动调用...
llm_with_tool = llm.bind_tools(tools)
原始调用Tools ---- 了解即可
就是在不结合Agent的时候调用工具生成文本的方法
def test01():
from langchain_core.tracers import ConsoleCallbackHandler
from langchain_core.messages import HumanMessage
### 原来绑定tools时是不会自动自行方法的,需要我们手动调用...
llm_with_tool = llm.bind_tools(tools)
query_0 = "2U8的结果是多少?"
ai_msg = llm_with_tool.invoke(query_0, config={"callbacks": [ConsoleCallbackHandler()]})
print(f"ai返回的消息:{ai_msg}")
print(f"打印出要调用的工具方法:{ai_msg.tool_calls}") # 打印出要调用的方法..。
messages = [HumanMessage(content=query_0), ai_msg]
for tool_call in ai_msg.tool_calls:
# [{'name': 'jiemeng', 'args': {'question': '梦见了一条蛇'}, 'id': 'call_-8969341968746077052', 'type': 'tool_call'}]
print(tool_call)
selected_tool = {"add": add_,
"multiply": multiply_,
"xiang_u": xiang_U,
"xiang_t": xiang_T,
"tavily": tavily_,
"serpapi": serpApi_,
"jiemeng": jiemeng_
}[tool_call["name"].lower()]
tool_msg = selected_tool.invoke(tool_call)
messages.append(tool_msg)
print(f"tool_msg返回的数据:{tool_msg}")
print(f"最终结果:{llm_with_tool.invoke(messages)}")
print("---------------原始使用---------------")
test01()
1、创建Agent:原生langchain创建一个agent --- 了解
关于提示词使用时,可以使用huggingface官方的,也可以使用自定义;官方的需要VPN下载。
原始的langchain创建agent,
- 使用create_tool_calling_agent创建agent、
- 使用AgentExecutor创建Agent_Executor
使用hub创建的提示词
def create_calling_agent_hub_prompt():
"""
使用hub提示词模板
:return:
"""
from langchain import hub
from langchain.agents import create_tool_calling_agent
from langchain.agents import AgentExecutor
prompt_hub_1 = 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')]
print(f"使用hub获得的提示词:[{prompt_hub_1.messages}]")
agent_hub_prompt_1 = create_tool_calling_agent(
llm=llm,
tools=tools,
prompt=prompt_hub_1
)
agent_hub_prompt_executor_1 = AgentExecutor(
agent=agent_hub_prompt_1,
tools=tools,
)
print(agent_hub_prompt_executor_1.invoke({"input": "成都天气今天怎么样?"})['output'])
使用自定义提示词
def create_calling_agent_custorm_prompt():
"""
使用自定义提示词模板创建Agent
:return:
"""
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.prompts import MessagesPlaceholder
from langchain.agents import create_tool_calling_agent
from langchain.agents import AgentExecutor
prompt_chat_custom_1 = ChatPromptTemplate.from_messages(
[
("system",
"""
你是我定义的一个工具,一个搜索实时信息的工具
这代表着如果有你不知道的信息,你都可以使用它们获得最准确的结果。
如果工具也无法处理,请直接回复“无法处理”即可,切勿过多修饰。
"""),
("human", "{text}"),
# 添加,不然报错ValueError: Prompt missing required variables: {'agent_scratchpad'}
# 等价于("placeholder", "{agent_scratchpad}")....("placeholder", "{其他...参数}"),
MessagesPlaceholder(variable_name='agent_scratchpad'),
]
)
agent_custom_chat_1 = create_tool_calling_agent(
llm=llm,
tools=tools,
prompt=prompt_chat_custom_1
)
agent_custom_chat_executor_1 = AgentExecutor(
agent=agent_custom_chat_1,
tools=tools,
)
# print(f"使用ChatPromptTemplate获得的提示词:[{prompt_chat_custom_1}]")
print(f"{agent_custom_chat_executor_1.invoke({"text": "1U8等于多少?"})}")
2、创建Agent --- Langchain create_openai_tools_agent创建
即:通过create_openai_tools_agent创建Agent,通过AgentExecutor去创建Agent的执行器
def create_openai_tools_agent():
# ### 使用自定义提示词模板创建Agent
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.prompts import MessagesPlaceholder
from langchain.agents import create_openai_tools_agent
from langchain.agents import AgentExecutor
prompt_chat_custom_1 = ChatPromptTemplate.from_messages(
[
("system",
"""
你是我定义的一个工具,一个搜索实时信息的工具
这代表着如果有你不知道的信息,你都可以使用它们获得最准确的结果。
如果工具也无法处理,请直接回复“无法处理”即可,切勿过多修饰。
"""),
("human", "{text}"),
# 添加,不然报错ValueError: Prompt missing required variables: {'agent_scratchpad'}
# 等价于("placeholder", "{agent_scratchpad}")....("placeholder", "{其他...参数}"),
MessagesPlaceholder(variable_name='agent_scratchpad'),
]
)
prompt_2 = prompt_chat_custom_1
agent_openai_2 = create_openai_tools_agent(
llm=llm,
tools=tools,
prompt=prompt_2,
)
agent_executor_2 = AgentExecutor(
agent=agent_openai_2,
tools=tools,
)
print(f"{agent_executor_2.invoke({"text": "1T7等于多少"})['output']}")
3、创建Agent --- 老版本使用initialize_agent创建(过时)
# 此处使用ZERO_SHOT_REACT_DESCRIPTION可能会报错:ValueError: ZeroShotAgent does not support multi-input tool add.,
# 原因是工具中的参数是输入了多个参数:比如 def add_(a: int, b: int)
# agent可选:ZERO_SHOT_REACT_DESCRIPTION、REACT_DOCSTORE、SELF_ASK_WITH_SEARCH、CONVERSATIONAL_REACT_DESCRIPTION、CHAT_ZERO_SHOT_REACT_DESCRIPTION、CHAT_CONVERSATIONAL_REACT_DESCRIPTION、STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION、OPENAI_MULTI_FUNCTIONS、OPENAI_FUNCTIONS 具体可以参考:AgentType类,但是,,这种方法是过时的,官方推荐的是通过“LangGraph”来创建Agent,LangGraph中好像不太需要AgentType
def create_initialize_agent():
from langchain.agents import initialize_agent
from langchain.agents import AgentType
agent = initialize_agent( # 过时
tools=tools,
llm=llm,
agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION,
# verbose=True
)
# print(f"{agent.run({"input": {"text": "1U8等于多少"}})}") # 过时了,使用invoke
# print(f"create_initialize_agent:{agent.invoke({"input": "1T8等于多少"})}")
print(f"create_initialize_agent:{agent.invoke({"input": "1U8等于多少"})['output']}")
4、创建Agent --- 使用create_react_agent创建
create_react_agent有两个:
- langchain.agents.create_react_agent
- langgraph.prebuilt.create_react_agent
如果我们使用langchain.agents的create_react_agent话,那么我们需要再提示词中添加如下参数: tools、tool_names、input、agent_scratchpad...
使用langchain.agents.create_react_agent
def create_langchain_react_agent():
"""
如果要使用langchain.agents.create_react_agent的话,那么必须传递进:
tools、tool_names、input、agent_scratchpad这几个参数
流程为:通过create_react_agent获取Agent,通过AgentExecutor获取执行器,然后再用执行器.invoke()
:return:
"""
from langchain.agents import create_react_agent
from langchain import hub
# prompt = hub.pull("hwchase17/react") # 示例prompt 标准的ReAct模板
# 下面是翻译出来的 --- 使用这种,可能会出现问题..最好的办法还是使用hub.pull("hwchase17/react")直接使用
prompt = PromptTemplate.from_template("""
尽你所能回答以下问题。
您可以访问以下工具: \n\n{tools}\n\n
使用以下格式:\n\n
Question: 输入的问题\n
Thought: 你的思考过程
Action: 要采取的操作应该是〔{tool_names}〕之一\n
Action Input: 工具输入\n
Observation: 工具返回结果\n
...(重复思考/行动/工具输入/观察 可以重复N次)\n
Thought: 我现在知道最终答案了\n
Final Answer: 最终结论\n\n
Begin!\n\n
Question: {input}\n
Thought: {agent_scratchpad}
""")
# 创建Agent
langchain_react_agent = create_react_agent(llm, tools, prompt)
# 创建执行器
from langchain.agents import AgentExecutor
agent_executor = AgentExecutor(
agent=langchain_react_agent,
tools=tools,
max_iterations=3,
handle_parsing_errors=True # 发生错误时,则错误将作为观察结果发送回LLM。
)
result = agent_executor.invoke({"input": "1U8等于多少?"}, config=config)
print(result)
使用langgraph.prebuilt.create_react_agent --- 不带提示词
def create_langgraph_no_prompt_react_agent():
"""
不带提示词
是langgraph.prebuilt不是langchain.agents
"""
from langgraph.prebuilt import create_react_agent
agent_langgraph_no_prompt_4 = create_react_agent(
model=llm,
tools=tools
)
from langchain_core.messages import HumanMessage
# result = agent_langgraph_no_prompt_4.invoke({"messages": [HumanMessage(content="what is 1U8?")]})
result = agent_langgraph_no_prompt_4.invoke({"messages": "1U8等于多少?"}, config=config)
print(f"HumanMessage数据体发送:{result["messages"][-1].content}")
# messages_4 = agent_langgraph_no_prompt_4.invoke({"messages": [("human", "1U8等于多少")]})
# print(f"human字符串发送:{messages_4}")
#
# new_query_result = agent_langgraph_no_prompt_4.invoke(
# {"messages": messages_4["messages"] + [("human", "9T1呢?")]}
# )
# print(f"new query:{new_query_result["messages"][-1].content}")
使用langgraph.prebuilt.create_react_agent --- 带字符串提示词
def create_langgraph_str_prompt_react_agent():
"""带字符串提示词"""
from langgraph.prebuilt import create_react_agent
system_message_str_4 = """
你是一个工具助手
"""
agent_langgraph_str_prompt_4 = create_react_agent(model=llm, tools=tools, prompt=system_message_str_4)
# print(f"带字符串提示词:{agent_langgraph_str_prompt_4.invoke({"messages": [("human", "1U8等于多少?")]})["messages"][-1].content}")
print(f"带字符串提示词:{agent_langgraph_str_prompt_4.invoke({"messages": "1U8等于多少?"})["messages"][-1].content}")
使用langgraph.prebuilt.create_react_agent --- 带对象提示词
即创建的带有role(System/human/AI)之类的提示词
def create_langgraph_obj_prompt_react_agent():
"""带对象提示词"""
from langchain_core.messages import SystemMessage
from langgraph.prebuilt import create_react_agent
system_message_str_4 = """
你是一个助手
"""
system_message_object_4 = SystemMessage(content=system_message_str_4)
agent_langgraph_object_prompt_4 = create_react_agent(model=llm, tools=tools, prompt=system_message_object_4)
print(f"带object提示词:{agent_langgraph_object_prompt_4.invoke(
{"messages": [("human", "1T8等于多少?")]}
)["messages"][-1].content}")
5、创建Agent:使用create_tool_calling_executor创建
""" 推荐使用... langgraph.prebuilt.chat_agent_executor.create_tool_calling_executor和langgraph.prebuilt.create_react_agent的区别: create_react_agent:基于ReAct框架 模式:采用经典的 ReAct(Reason + Act) 模式,代理通过显式的推理步骤(Thought)和工具调用(Action)循环解决问题。 流程:每个步骤生成文本格式的思考(如 "Thought: 我需要查询天气;Action: search_tool(...)"),执行器解析动作、调用工具、返回结果(Observation),循环直到任务完成。 适用场景:教学或调试场景,需要观察代理的思考过程。使用不支持结构化输出的模型(如某些开源LLM)。 create_tool_calling_executor:工具调用执行器。基于模型原生工具调用能力。 模式:直接利用模型原生的结构化工具调用能力(如OpenAI的tool_calls),无需显式生成思考步骤。 流程:模型直接返回工具名及参数(结构化数据),执行器调用工具并返回结果,模型根据结果决定下一步,流程更简洁。 适用场景:生产环境的高效工具调用,适合支持结构化输出的模型(如结合GPT-4处理多步骤用户请求)。需要减少Token消耗、提升响应速度的场景。create_react_agent | create_tool_calling_executor 需要自定义提示模板和输出解析器 | 依赖模型原生能力,实现更简单 需处理中间步骤(思考、动作分离) | 直接执行工具调用 适用于所有模型(如开源LLM) | 通常需特定模型支持(如GPT-4)ReAct代理: - 要求模型生成的文本符合Thought/Action/Observation格式,对模型输出规范性要求较高。兼容性广,可用于任何能生成此格式文本的模型(如开源LLM)。 - 需要解析非结构化文本,处理潜在的格式错误,流程步骤更多。适合需要人类可读的中间推理步骤的场景。 Tool Calling执行器: - 依赖模型原生支持结构化工具调用(如OpenAI的API返回的tool_calls字段)。效率更高,但需特定模型支持。 - 直接处理结构化数据,省去文本解析步骤,错误率更低。适合自动化程度高、需快速执行工具的场景。 """
def create_langgraph_tool_calling_executor():
# ### 也可以使用hub自带的提示词
from langchain import hub
# prompt = hub.pull("wfh/react-agent-executor")
"""
input_variables=['{messages}']
input_types={'{messages}': list[typing.Annotated[typing.Union[typing.Annotated[langchain_core.messages.ai.AIMessage, Tag(tag='ai')], typing.Annotated[langchain_core.messages.human.HumanMessage, Tag(tag='human')], typing.Annotated[langchain_core.messages.chat.ChatMessage, Tag(tag='chat')], typing.Annotated[langchain_core.messages.system.SystemMessage, Tag(tag='system')], typing.Annotated[langchain_core.messages.function.FunctionMessage, Tag(tag='function')], typing.Annotated[langchain_core.messages.tool.ToolMessage, Tag(tag='tool')], typing.Annotated[langchain_core.messages.ai.AIMessageChunk, Tag(tag='AIMessageChunk')], typing.Annotated[langchain_core.messages.human.HumanMessageChunk, Tag(tag='HumanMessageChunk')], typing.Annotated[langchain_core.messages.chat.ChatMessageChunk, Tag(tag='ChatMessageChunk')], typing.Annotated[langchain_core.messages.system.SystemMessageChunk, Tag(tag='SystemMessageChunk')], typing.Annotated[langchain_core.messages.function.FunctionMessageChunk, Tag(tag='FunctionMessageChunk')], typing.Annotated[langchain_core.messages.tool.ToolMessageChunk, Tag(tag='ToolMessageChunk')]], FieldInfo(annotation=NoneType, required=True, discriminator=Discriminator(discriminator=<function _get_type at 0x000001FED38EF240>, custom_error_type=None, custom_error_message=None, custom_error_context=None))]]} partial_variables={} metadata={'lc_hub_owner': 'wfh', 'lc_hub_repo': 'react-agent-executor', 'lc_hub_commit_hash': 'bccfbbc5de8559d19d44c8ea2229bb6d06c99e402ea29b8694b294a31730a7a5'}
messages=[
SystemMessagePromptTemplate(
prompt=PromptTemplate(
input_variables=[],
input_types={},
partial_variables={},
template='You are a helpful assistant.'),
additional_kwargs={}
),
MessagesPlaceholder(variable_name='{messages}')
]
"""
# ### 使用ChatPromptTemplate定义提示词
# from langchain_core.prompts import ChatPromptTemplate
# from langchain_core.prompts import MessagesPlaceholder
# prompt_chat_prompt_template_4 = ChatPromptTemplate.from_messages(
# [
# ("system", "你是我定义的一个系统助手"),
# # 必须加,而且好像必须使用默认key“messages”
# # 否则报错:langgraph.errors.InvalidUpdateError: Must write to at least one of ['messages', 'structured_response']
# MessagesPlaceholder(variable_name='messages'),
# # ("placeholder", "{messages}"),
# ]
# )
prompt_template = """ 你是我定义的一个系统助手 """
from langchain_core.messages import SystemMessage
prompt = SystemMessage(content=prompt_template)
from langgraph.prebuilt.chat_agent_executor import create_tool_calling_executor
# chat_agent_executor.create_tool_calling_executor封装了 create_react_agent
agent_prompt_chat_prompt_template_4 = create_tool_calling_executor(
model=llm,
tools=tools,
prompt=prompt
)
print(f"1:{agent_prompt_chat_prompt_template_4.invoke(
{"messages": [("human", "请问1U8等于多少?")]},
# config=config
)["messages"][-1].content}")
print("-" * 100)
# print(f"2:{agent_prompt_chat_prompt_template_4.invoke(
# {"messages": "请问1U8等于多少?"},
# # config=config
# )["messages"][-1].content}")
# print("-" * 100)
#
# print(f"3:{agent_prompt_chat_prompt_template_4.invoke(
# {"messages": [{"role": "human", "content": "what is 1 T 8"}]}
# )["messages"][-1].content}")
# print("-" * 100)
# for e in agent_prompt_chat_prompt_template_4.stream(
# input={"messages": [{"role": "human", "content": "what is 1 T 8"}]},
# stream_mode='values'):
# message = e['messages'][-1]
# print(message)
# if isinstance(message, tuple):
# print(message)
# else:
# message.pretty_print()
6、创建Agent:使用Langchain的API手动创建
即使用ReAct Agent方式
ReActAgent 是基于 ReAct(Reasoning and Acting)框架实现的智能体,其核心思想是模型通过交替进行推理(Reasoning)和行动(Acting)来完成任务。
在代码中,它的工作流程是:
- 调用模型生成响应;
- 若响应中包含工具调用(tool_calls),则并行执行所有工具;
- 将工具执行结果追加到消息历史中,重新调用模型生成新响应;
- 循环直到模型不再调用工具,返回最终结果。
ReActAgent(用户代码中的实现):
- 核心:通过交替进行 推理(Reasoning) 和 行动(Action) 完成任务。
- 是一个手动实现的 ReAct 逻辑,通过 while 循环显式控制工具调用和模型迭代。
- 需要自行管理消息历史、工具调用结果的拼接。
- 灵活性更高,但需要更多底层代码。
create_react_agent(如 LangChain 等框架提供的函数):
- 核心:内置标准化ReAct流程(思考→行动→观察循环);自动处理工具调用和中间状态管理
- 通常是框架封装好的高阶函数,通过预设的提示词(prompt)和流程自动处理 ReAct 逻辑。
- 适用于快速搭建标准Agent场景
创建ReAct代理,步骤如下:
1、定义模型和工具
- llm = llm
- tools = [工具一、工具二...]
2、定义任务
- 任务一:调用模型,我们希望使用消息列表查询我们的聊天模型。
- 任务二:调用工具,如果我们的模型生成工具调用,我们希望执行它们。
3、定义入口点:入口点 将处理这两个任务的编排
- 当我们的 call_model(任务一) 任务生成工具调用时
- call_tool(任务二) 任务将为每个工具调用生成响应
- 我们将所有消息附加到单个消息列表中。
4、使用
5、添加线程级持久性 --- 即历史记录
- 选择一个 检查点:在这里我们将使用 MemorySaver,一个简单的内存检查点。
- 更新我们的入口点以接受先前的消息状态作为第二个参数。在这里,我们只是将消息更新附加到先前的消息序列。
- 选择哪些值将从工作流返回,哪些值将由检查点程序保存为 previous,使用 entrypoint.final(可选)
1、定义模型和工具
# ### 1、定义模型和工具
react_model = ChatOllama(model='qwen2.5:1.5b', temperature=0, verbose=True)
# react_model = get_llm('glm')
# 工具集合
react_tools = tools
# 绑定工具到模型
react_llm_with_tool = react_model.bind_tools(tools)
2、定义任务
# ### 2、定义任务
from langchain_core.messages import ToolMessage
from langgraph.func import entrypoint, task
tools_by_name = {tool.name: tool for tool in tools}
@task
def call_model(messages):
"""Call model with a sequence of messages."""
return react_llm_with_tool.invoke(messages)
@task
def call_tool(tool_call):
tool = tools_by_name[tool_call["name"]]
observation = tool.invoke(tool_call["args"])
return ToolMessage(content=observation, tool_call_id=tool_call["id"])
3、定义入口点
无记忆版本
# ### 3、定义入口点
# 无记忆
@entrypoint()
def agent(messages):
llm_response = call_model(messages).result()
while True:
if not llm_response.tool_calls:
break
# 执行工具
tool_result_futures = [
call_tool(tool_call) for tool_call in llm_response.tool_calls
]
tool_results = [fut.result() for fut in tool_result_futures]
# 添加消息到消息列表
messages = add_messages(messages, [llm_response, *tool_results])
# 获取模型返回
llm_response = call_model(messages).result()
return llm_response
有记忆:添加线程级别记忆
# 有记忆
# 选择一个 检查点:在这里我们将使用 MemorySaver,一个简单的内存检查点。
checkpointer = MemorySaver()
@entrypoint(checkpointer=checkpointer)
# 更新我们的入口点以接受先前的消息状态作为第二个参数。在这里,我们只是将消息更新附加到先前的消息序列。
def agent(messages, previous):
if previous is not None:
messages = add_messages(previous, messages)
llm_response = call_model(messages).result()
while True:
if not llm_response.tool_calls:
break
tool_result_futures = [
call_tool(tool_call) for tool_call in llm_response.tool_calls
]
tool_results = [fut.result() for fut in tool_result_futures]
messages = add_messages(messages, [llm_response, *tool_results])
llm_response = call_model(messages).result()
# 生成最终响应的消息
messages = add_messages(messages, llm_response)
# 选择哪些值将从工作流返回,哪些值将由检查点程序保存为 previous,使用 entrypoint.final(可选)
return entrypoint.final(value=llm_response, save=messages)
4、使用
使用无记忆版本
# 使用
user_message = {"role": "user", "content": "1U7等于多少"}
print(user_message)
for step in agent.stream([user_message]):
for task_name, message in step.items():
if task_name == "agent":
continue
print(f"\n{task_name}:")
message.pretty_print()
使用:有记忆
# ### 4、使用:有记忆
config = {"configurable": {"thread_id": "1"}}
print(f"带历史记录的ReActAgent: {agent.invoke([{"role": "user", "content": "hi,我叫UU。请问1U7等于多少?"}], config)}")
print(f"带历史记录的ReActAgent: {agent.invoke([{"role": "user", "content": "我刚刚说我叫什么?"}], config)}")
print(f"带历史记录的ReActAgent: {agent.invoke([{"role": "user", "content": "我刚刚问你什么了?"}], config)}")
# for step in agent.stream([user_message], config):
# for task_name, message in step.items():
# if task_name == "agent":
# continue # Just print task updates
# print(f"\n{task_name}:")
# message.pretty_print()
7、在langchain中添加momery内存
自己拼装历史消息
def add_memory_langchain_calling_agent_custom_history():
"""方法一:自己拼装历史消息..."""
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.prompts import MessagesPlaceholder
prompt_chat_custom_6 = ChatPromptTemplate.from_messages(
[
("system",
"""
你是我定义的一个工具,一个可以根据我给你提供的工具列表来解决实际问题的工具。
这代表着如果有你不知道的信息,你都可以使用它们获得最准确的结果。
如果工具也无法处理,请直接回复“无法处理”即可,除此之外,切勿过多修饰。
"""),
MessagesPlaceholder(variable_name='agent_history_demo6'), # 历史记录的key
("human", "{agent_input6}"),
# 添加agent_scratchpad,不然报错ValueError: Prompt missing required variables: {'agent_scratchpad'}
MessagesPlaceholder(variable_name='agent_scratchpad'),
# ("placeholder", "{agent_scratchpad}"),
]
)
from langchain.agents import create_tool_calling_agent
agent_memory_6 = create_tool_calling_agent(
llm=llm,
tools=tools,
prompt=prompt_chat_custom_6,
)
from langchain_core.messages import HumanMessage
from langchain_core.messages import AIMessage
from langchain.agents import AgentExecutor
agent_executor = AgentExecutor(agent=agent_memory_6, tools=tools)
chat_history_messages = [
HumanMessage(content="你好,我的名字叫张三"),
AIMessage(content="你好,张三!我有什么可以帮助你的?"),
]
print(agent_executor.invoke({"agent_history_demo6": chat_history_messages, "agent_input6": "我的名字是啥?"}))
使用 RunnableWithMessageHistory创建
def add_memory_langchain_calling_agent_runnable_history():
"""方法二:使用 RunnableWithMessageHistory创建"""
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.prompts import MessagesPlaceholder
prompt_chat_custom_6 = ChatPromptTemplate.from_messages(
[
("system", """
你是我定义的一个工具,一个可以根据我给你提供的工具列表来解决实际问题的工具。
这代表着如果有你不知道的信息,你都可以使用它们获得最准确的结果。
如果工具也无法处理,请直接回复“无法处理”即可,除此之外,切勿过多修饰。
"""),
MessagesPlaceholder(variable_name='agent_history_demo6'), # 历史记录的key
("human", "{agent_input6}"),
# 添加agent_scratchpad,不然报错ValueError: Prompt missing required variables: {'agent_scratchpad'}
MessagesPlaceholder(variable_name='agent_scratchpad'),
# ("placeholder", "{agent_scratchpad}"),
]
)
from langchain.agents import create_tool_calling_agent
agent_memory_6 = create_tool_calling_agent(
llm=llm,
tools=tools,
prompt=prompt_chat_custom_6,
)
from langchain.agents import AgentExecutor
agent_executor_6 = AgentExecutor(
agent=agent_memory_6,
tools=tools,
verbose=True,
)
from langchain_core.runnables import RunnableWithMessageHistory
agent_with_chat_history_6 = RunnableWithMessageHistory(
agent_executor_6,
get_session_history=get_session_history,
input_messages_key='agent_input6',
history_messages_key='agent_history_demo6',
)
config_6 = {'configurable': {"session_id": "1234"}}
print(agent_with_chat_history_6.invoke({"agent_input6": "hi,你好我叫UU,你叫什么?"}, config=config_6))
print(agent_with_chat_history_6.invoke({"agent_input6": "对了我忘了,我刚刚说我叫什么来着?"}, config=config_6))
使用 ConversationBufferMemory 创建
def add_memory_langchain_calling_agent_buffer_memory():
"""方法三:使用 ConversationBufferMemory 创建"""
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.prompts import MessagesPlaceholder
prompt_chat_custom_6 = ChatPromptTemplate.from_messages(
[
("system",
"""
你是我定义的一个工具,一个可以根据我给你提供的工具列表来解决实际问题的工具。
这代表着如果有你不知道的信息,你都可以使用它们获得最准确的结果。
如果工具也无法处理,请直接回复“无法处理”即可,除此之外,切勿过多修饰。
"""),
MessagesPlaceholder(variable_name='agent_history_demo6'), # 历史记录的key
("human", "{agent_input6}"),
# 添加agent_scratchpad,不然报错ValueError: Prompt missing required variables: {'agent_scratchpad'}
MessagesPlaceholder(variable_name='agent_scratchpad'),
# ("placeholder", "{agent_scratchpad}"),
]
)
from langchain.agents import create_tool_calling_agent
agent_memory_6 = create_tool_calling_agent(
llm=llm,
tools=tools,
prompt=prompt_chat_custom_6,
)
# memory_6 = ConversationBufferMemory(memory_key="agent_history_demo6",return_messages=True)
from langchain.agents import AgentExecutor
agent_executor_new_6 = AgentExecutor(
agent=agent_memory_6,
tools=tools,
memory=get_memory(uid="123456", key='agent_history_demo6'),
# memory=memory_6,
)
print(agent_executor_new_6.invoke({"agent_input6": "Hello,我叫UU"}))
print(agent_executor_new_6.invoke({"agent_input6": "我忘了,我刚刚说我叫什么?"}))
8、在LangGraph中添加momery内存
在LangGraph中使用langgraph.prebuilt.chat_agent_executor.create_tool_calling_executor或者langgraph.prebuilt.create_react_agent 创建Agent的时候,一般都需要状态管理来实现添加内存的功能,但是我们可以使用checkpointer=MemorySaver()添加本地内存...
def add_memory_in_checkpointer_by_thread_id():
system_message_7 = """
你是我定义的一个代理助手,我会给你很多工具,你可以根据我给你提供的工具来帮我解决实际的问题。
这代表着如果有你不知道的信息,你都可以使用我给你提供的工具获得最准确的结果。
如果工具也无法处理,请直接回复“无法处理”即可,除此之外,切勿过多修饰。
"""
from langchain_core.tracers import ConsoleCallbackHandler
config_7 = {
"configurable": {"thread_id": "12345"},
# "callbacks": [ConsoleCallbackHandler()]
}
from langgraph.checkpoint.memory import MemorySaver
checkpointer_thread_id_7 = MemorySaver() # 是根据thread_id来创建的...
# checkpointer_thread_id_7 = InMemorySaver()
from langgraph.prebuilt import create_react_agent
from langgraph.prebuilt import chat_agent_executor
# langgraph_agent_executor_7 = create_react_agent(
langgraph_agent_executor_7 = chat_agent_executor.create_tool_calling_executor(
llm,
tools,
prompt=system_message_7,
checkpointer=checkpointer_thread_id_7,
)
print(
f"使用MemorySaver()的step1:{langgraph_agent_executor_7.invoke({"messages": [("user", "hi,我叫KK。")]}, config=config_7)["messages"][-1].content}")
print(
f"使用MemorySaver()的step2:{langgraph_agent_executor_7.invoke({"messages": [("user", "对了我刚刚说我叫什么来着?")]}, config=config_7)["messages"][-1].content}")
# print(f"使用MemorySaver()的step2:{langgraph_agent_executor_7.invoke({"messages": [("user", "对了我刚刚说我叫什么来着?今天的成都天气是多少?")]}, config=config_7)["messages"][-1].content}")