创建一个简单的 ReAct 代理应用程序,该应用程序可以检查天气。该应用程序由一个代理(LLM)和工具组成。当我们与应用程序交互时,我们将首先调用代理(LLM)来决定是否应该使用工具。然后我们将运行一个循环
- 如果代理说要采取行动(即调用工具),我们将运行工具并将结果传递回代理
- 如果代理没有要求运行工具,我们将结束(响应用户)
预构建的代理
请注意,这里我们将使用预构建的代理。LangGraph 的一大优势是你可以轻松创建自己的代理架构。因此,虽然从这里开始快速构建代理是不错的选择,但我们强烈建议你学习如何构建自己的代理,这样你就可以充分利用 LangGraph。
python
import asyncio
from typing import Literal
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent
from pyexpat.errors import messages
@tool
def get_wather(city:Literal["深圳","北京"]):
"""
查询所在城市的天气情况
:param city:
:return:
"""
if city == "深圳":
return "多云,很多云"
elif city == "北京":
return "下雨,很多雨"
else:
return "不知道设么天气"
tools = [get_wather]
llm = ChatOpenAI(base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
api_key="sk-3ad75cfac*********3d473b2a", model="qwen-plus")
#from langchain.agents import create_agent
graph = create_react_agent(llm, tools)
inputs = {"messages":["深圳天气怎么样"]}
async def main():
async for chunk in graph.astream(inputs,stream_mode="values"):
print(chunk)
asyncio.run(main())
向 ReAct 代理添加记忆
要启用内存,我们只需要将 checkpointer 传递给 create_react_agents
python
import asyncio
from typing import Literal
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from langgraph.checkpoint.memory import MemorySaver
from langgraph.prebuilt import create_react_agent
from pyexpat.errors import messages
@tool
def get_wather(city:Literal["深圳","北京"]):
"""
查询所在城市的天气情况
:param city:
:return:
"""
if city == "深圳":
return "多云,很多云"
elif city == "北京":
return "下雨,很多雨"
else:
return "不知道设么天气"
tools = [get_wather]
llm = ChatOpenAI(base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
api_key="sk-3ad75cfac***********d3d473b2a", model="qwen-plus")
#from langchain.agents import create_agent
# 初始化 MemorySaver 实例
memory = MemorySaver()
config = {"configurable": {"thread_id": "1"}}
graph = create_react_agent(llm, tools,checkpointer=memory)
async def main():
inputs = {"messages":["深圳天气怎么样"]}
async for chunk in graph.astream(inputs,config = config,stream_mode="values"):
#print(chunk)
print(chunk['messages'][-1])
inputs = {"messages":["它有哪些著名景点"]}
async for chunk in graph.astream(inputs,config = config,stream_mode="values"):
#print(chunk)
print(chunk['messages'][-1])
asyncio.run(main())
请注意,当我们传递相同的线程 ID 时,聊天历史记录会保留
python
content='深圳天气怎么样' additional_kwargs={} response_metadata={} id='77b64894-e4d6-471c-a69f-dab3c21a3eb6'
content='' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 20, 'prompt_tokens': 164, 'total_tokens': 184, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_provider': 'openai', 'model_name': 'qwen-plus', 'system_fingerprint': None, 'id': 'chatcmpl-8251795b-3fbb-49c4-8e99-f54ca41fbf62', 'finish_reason': 'tool_calls', 'logprobs': None} id='lc_run--c4399237-4cd3-40bb-85cc-30a3752a257a-0' tool_calls=[{'name': 'get_wather', 'args': {'city': '深圳'}, 'id': 'call_32920ee2116b42989b948c', 'type': 'tool_call'}] usage_metadata={'input_tokens': 164, 'output_tokens': 20, 'total_tokens': 184, 'input_token_details': {'cache_read': 0}, 'output_token_details': {}}
content='多云,很多云' name='get_wather' id='4dbec74f-07a3-4360-808b-4b1174c02378' tool_call_id='call_32920ee2116b42989b948c'
content='深圳目前的天气是多云,天空中有很多云。如果需要更详细的天气信息,比如温度、湿度或风速,请告诉我!' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 30, 'prompt_tokens': 203, 'total_tokens': 233, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_provider': 'openai', 'model_name': 'qwen-plus', 'system_fingerprint': None, 'id': 'chatcmpl-33f3ffd2-7729-4749-8eae-155fdbc2e861', 'finish_reason': 'stop', 'logprobs': None} id='lc_run--58e874f5-f9a6-4067-b01c-b48b166507b4-0' usage_metadata={'input_tokens': 203, 'output_tokens': 30, 'total_tokens': 233, 'input_token_details': {'cache_read': 0}, 'output_token_details': {}}
content='它有哪些著名景点' additional_kwargs={} response_metadata={} id='62d2b2a8-7ec9-42cc-994a-3b57a304bdfd'
content='深圳作为中国的一线城市,拥有许多著名的景点和地标,融合了现代都市风貌与自然风光。以下是一些深圳的著名景点:\n\n1. **世界之窗** \n 一个大型主题公园,汇集了全球130多个著名景观的微缩版,如埃菲尔铁塔、自由女神像、金字塔等,适合拍照和家庭游玩。\n\n2. **锦绣中华·民俗村** \n 包含"锦绣中华"(中国各地名胜微缩景观)和"民俗村"(展示中国56个民族文化的表演与建筑),是了解中国文化的好去处。\n\n3. **欢乐谷** \n 国家级主题乐园,拥有众多刺激的游乐设施、表演和主题活动,适合年轻人和家庭游客。\n\n4. **东部华侨城** \n 集生态旅游、休闲度假、户外运动为一体的综合性景区,包含大侠谷、茶溪谷等,风景优美,适合放松身心。\n\n5. **大梅沙海滨公园** \n 深圳著名的免费海滩,是市民和游客夏日戏水、晒太阳的好地方。\n\n6. **梧桐山** \n 深圳最高峰,适合登山爱好者,登顶可俯瞰深圳市区和香港新界,自然风光秀丽。\n\n7. **深圳湾公园** \n 沿海而建的带状公园,是骑行、散步、观鸟和看日落的热门地点,还能远眺香港。\n\n8. **平安金融中心云际观光层** \n 位于深圳第二高楼,海拔约592米,提供360度城市全景,是俯瞰深圳现代化天际线的最佳地点之一。\n\n9. **南头古城 & NANTOU PRIME** \n 历史悠久的古城,近年来经过改造,融合了文化、艺术与潮流元素,成为年轻人喜爱的打卡地。\n\n10. **蛇口海上世界** \n 以一艘巨型游轮"明华轮"为中心的综合商圈,集餐饮、娱乐、艺术展览于一体,夜晚灯光璀璨,氛围浪漫。\n\n如果你告诉我你喜欢自然、历史还是现代娱乐,我可以为你推荐更合适的景点哦!' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 461, 'prompt_tokens': 247, 'total_tokens': 708, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 64}}, 'model_provider': 'openai', 'model_name': 'qwen-plus', 'system_fingerprint': None, 'id': 'chatcmpl-c5c2376e-4559-40b8-84d4-c5c7e77a58ce', 'finish_reason': 'stop', 'logprobs': None} id='lc_run--34749ac8-7afc-4e9b-896c-82f5d1be2e82-0' usage_metadata={'input_tokens': 247, 'output_tokens': 461, 'total_tokens': 708, 'input_token_details': {'cache_read': 64}, 'output_token_details': {}}
向 ReAct 代理添加系统提示
您可以通过将字符串传递给state_modifier参数来添加自定义系统提示。
python
# 我们可以在这里添加系统提示
prompt = "请以导游身份回答问题"
graph = create_react_agent(llm, tools,checkpointer=memory,prompt=prompt)
python
content='深圳天气怎么样' additional_kwargs={} response_metadata={} id='7dbd2c8f-fc31-4408-bfa0-c5799179bffe'
content='' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 20, 'prompt_tokens': 171, 'total_tokens': 191, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_provider': 'openai', 'model_name': 'qwen-plus', 'system_fingerprint': None, 'id': 'chatcmpl-5b0218e5-348e-4221-a2b3-46960ea46ea3', 'finish_reason': 'tool_calls', 'logprobs': None} id='lc_run--d90547de-4b38-4043-8cf1-b4c617e1e2a1-0' tool_calls=[{'name': 'get_wather', 'args': {'city': '深圳'}, 'id': 'call_d498d96dd518449a996a74', 'type': 'tool_call'}] usage_metadata={'input_tokens': 171, 'output_tokens': 20, 'total_tokens': 191, 'input_token_details': {'cache_read': 0}, 'output_token_details': {}}
content='多云,很多云' name='get_wather' id='0f3d81a3-a5c9-4191-b96f-6651093061f7' tool_call_id='call_d498d96dd518449a996a74'
content='深圳目前的天气是多云,天空中有很多云层。气温适中,适合外出活动,但建议随身携带一件薄外套以防微凉。如果您有户外计划,不用担心,这样的天气非常适合拍照和散步哦!需要我为您推荐一些适合这种天气游玩的地方吗?' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 61, 'prompt_tokens': 210, 'total_tokens': 271, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_provider': 'openai', 'model_name': 'qwen-plus', 'system_fingerprint': None, 'id': 'chatcmpl-4a5672d0-491a-4297-a818-708aee6c18b0', 'finish_reason': 'stop', 'logprobs': None} id='lc_run--2d813894-70f5-48e4-a323-736b96489015-0' usage_metadata={'input_tokens': 210, 'output_tokens': 61, 'total_tokens': 271, 'input_token_details': {'cache_read': 0}, 'output_token_details': {}}
content='它有哪些著名景点' additional_kwargs={} response_metadata={} id='38e89cf6-76f7-4718-85cc-2cf2936f7ffd'
content='深圳作为一座现代化大都市,融合了科技、自然与人文景观,有许多值得一游的著名景点。以下是一些不容错过的热门打卡地:\n\n1. **世界之窗** \n 这是一个微缩景观主题公园,汇集了全球130多个著名景点的缩小版,比如埃菲尔铁塔、自由女神像、金字塔等,适合拍照和了解世界各地文化。\n\n2. **锦绣中华·民俗村** \n 中国首个文化主题公园,展示了中国56个民族的风情和建筑,还有精彩的民俗表演,非常适合家庭出游。\n\n3. **深圳湾公园** \n 沿海而建的超长滨海步道,是市民休闲散步、骑行的好去处。天气好的时候可以远眺香港,傍晚时分的日落特别美。\n\n4. **东部华侨城** \n 集生态旅游、娱乐设施和温泉于一体的大型综合度假区,包含大侠谷、茶溪谷等,适合亲子游或朋友结伴游玩。\n\n5. **梧桐山** \n 深圳最高峰,登山爱好者的好选择。登顶后可俯瞰整个深圳市区,云雾缭绕时宛如仙境。\n\n6. **大鹏所城 & 较场尾海滩** \n 大鹏所城是明代海防军事要塞,保存完好的古建筑群;旁边较场尾被称为"深圳鼓浪屿",有很多文艺民宿和海边咖啡馆。\n\n7. **欢乐谷 & 华侨城创意文化园(OCT-LOFT)** \n 欢乐谷是年轻人喜爱的主题乐园,有过山车、水上项目等刺激体验;而几步之遥的OCT-LOFT则是文艺青年的聚集地,常有艺术展、市集和独立书店。\n\n8. **平安金融中心云际观景台** \n 位于深圳最高楼之一,高达近600米,可以360度俯瞰全城,夜景尤为震撼。\n\n如果您告诉我您喜欢哪种类型的旅行------比如自然风光、历史文化还是现代都市体验------我可以为您定制更合适的推荐路线哦!' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 450, 'prompt_tokens': 285, 'total_tokens': 735, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_provider': 'openai', 'model_name': 'qwen-plus', 'system_fingerprint': None, 'id': 'chatcmpl-fe421516-8bc1-4190-932f-602840c0fec6', 'finish_reason': 'stop', 'logprobs': None} id='lc_run--e644e679-b9c0-4be5-b505-026c194330a1-0' usage_metadata={'input_tokens': 285, 'output_tokens': 450, 'total_tokens': 735, 'input_token_details': {'cache_read': 0}, 'output_token_details': {}}
python
import asyncio
from typing import Literal
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from langgraph.checkpoint.memory import MemorySaver
from langgraph.prebuilt import create_react_agent
from langgraph.types import interrupt, Command
from pyexpat.errors import messages
@tool
def get_wather(city:Literal["深圳","北京"]):
"""
查询所在城市的天气情况
:param city:
:return:
"""
c = interrupt("请确认城市")
print("确认结果",c)
if city == "深圳":
return "多云,很多云"
elif city == "北京":
return "下雨,很多雨"
else:
return "不知道设么天气"
tools = [get_wather]
llm = ChatOpenAI(base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
api_key="sk-3ad75cfac*********d3d473b2a", model="qwen-plus")
#from langchain.agents import create_agent
# 初始化 MemorySaver 实例
memory = MemorySaver()
config = {"configurable": {"thread_id": "1"}}
# 我们可以在这里添加系统提示
prompt = "请以导游身份回答问题"
graph = create_react_agent(llm, tools,checkpointer=memory,prompt=prompt,interrupt_before=["tools"])
async def main():
inputs = {"messages":["深圳天气怎么样"]}
async for chunk in graph.astream(inputs,config = config,stream_mode="values"):
#print(chunk)
print(chunk)
# 获取图的状态快照
snapshot = graph.get_state(config)
# 打印下一步信息
print("Next step: ", snapshot.next)
async for chunk in graph.astream(None,config = config,stream_mode="values"):
#print(chunk)
print(chunk)
# 对应interrupt 恢复
async for chunk in graph.astream(Command(resume="我已确认"),config = config,stream_mode="values"):
#print(chunk)
print(chunk)
# inputs = {"messages":["它有哪些著名景点"]}
# async for chunk in graph.astream(inputs,config = config,stream_mode="values"):
# #print(chunk)
# print(chunk['messages'][-1])
asyncio.run(main())
python
{'messages': [HumanMessage(content='深圳天气怎么样', additional_kwargs={}, response_metadata={}, id='7cc047ba-dd73-4f20-a9a2-8ccba960997c')]}
{'messages': [HumanMessage(content='深圳天气怎么样', additional_kwargs={}, response_metadata={}, id='7cc047ba-dd73-4f20-a9a2-8ccba960997c'), AIMessage(content='', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 20, 'prompt_tokens': 171, 'total_tokens': 191, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_provider': 'openai', 'model_name': 'qwen-plus', 'system_fingerprint': None, 'id': 'chatcmpl-bd18ec5b-6b5a-4357-a4fb-b7096d60dbc9', 'finish_reason': 'tool_calls', 'logprobs': None}, id='lc_run--6082f90a-19b1-4740-a1d5-b0837dbf093c-0', tool_calls=[{'name': 'get_wather', 'args': {'city': '深圳'}, 'id': 'call_a57e9fc6b47347c08f7815', 'type': 'tool_call'}], usage_metadata={'input_tokens': 171, 'output_tokens': 20, 'total_tokens': 191, 'input_token_details': {'cache_read': 0}, 'output_token_details': {}})]}
Next step: ('tools',)
{'messages': [HumanMessage(content='深圳天气怎么样', additional_kwargs={}, response_metadata={}, id='7cc047ba-dd73-4f20-a9a2-8ccba960997c'), AIMessage(content='', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 20, 'prompt_tokens': 171, 'total_tokens': 191, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_provider': 'openai', 'model_name': 'qwen-plus', 'system_fingerprint': None, 'id': 'chatcmpl-bd18ec5b-6b5a-4357-a4fb-b7096d60dbc9', 'finish_reason': 'tool_calls', 'logprobs': None}, id='lc_run--6082f90a-19b1-4740-a1d5-b0837dbf093c-0', tool_calls=[{'name': 'get_wather', 'args': {'city': '深圳'}, 'id': 'call_a57e9fc6b47347c08f7815', 'type': 'tool_call'}], usage_metadata={'input_tokens': 171, 'output_tokens': 20, 'total_tokens': 191, 'input_token_details': {'cache_read': 0}, 'output_token_details': {}})]}
{'__interrupt__': (Interrupt(value='请确认城市', id='d0a56560c10769b7b652b867c75366ad'),)}
{'messages': [HumanMessage(content='深圳天气怎么样', additional_kwargs={}, response_metadata={}, id='7cc047ba-dd73-4f20-a9a2-8ccba960997c'), AIMessage(content='', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 20, 'prompt_tokens': 171, 'total_tokens': 191, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_provider': 'openai', 'model_name': 'qwen-plus', 'system_fingerprint': None, 'id': 'chatcmpl-bd18ec5b-6b5a-4357-a4fb-b7096d60dbc9', 'finish_reason': 'tool_calls', 'logprobs': None}, id='lc_run--6082f90a-19b1-4740-a1d5-b0837dbf093c-0', tool_calls=[{'name': 'get_wather', 'args': {'city': '深圳'}, 'id': 'call_a57e9fc6b47347c08f7815', 'type': 'tool_call'}], usage_metadata={'input_tokens': 171, 'output_tokens': 20, 'total_tokens': 191, 'input_token_details': {'cache_read': 0}, 'output_token_details': {}})]}
确认结果 我已确认
{'messages': [HumanMessage(content='深圳天气怎么样', additional_kwargs={}, response_metadata={}, id='7cc047ba-dd73-4f20-a9a2-8ccba960997c'), AIMessage(content='', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 20, 'prompt_tokens': 171, 'total_tokens': 191, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_provider': 'openai', 'model_name': 'qwen-plus', 'system_fingerprint': None, 'id': 'chatcmpl-bd18ec5b-6b5a-4357-a4fb-b7096d60dbc9', 'finish_reason': 'tool_calls', 'logprobs': None}, id='lc_run--6082f90a-19b1-4740-a1d5-b0837dbf093c-0', tool_calls=[{'name': 'get_wather', 'args': {'city': '深圳'}, 'id': 'call_a57e9fc6b47347c08f7815', 'type': 'tool_call'}], usage_metadata={'input_tokens': 171, 'output_tokens': 20, 'total_tokens': 191, 'input_token_details': {'cache_read': 0}, 'output_token_details': {}}), ToolMessage(content='多云,很多云', name='get_wather', id='085d8e1f-7c5a-4e45-b51b-fa28e572b43e', tool_call_id='call_a57e9fc6b47347c08f7815')]}
{'messages': [HumanMessage(content='深圳天气怎么样', additional_kwargs={}, response_metadata={}, id='7cc047ba-dd73-4f20-a9a2-8ccba960997c'), AIMessage(content='', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 20, 'prompt_tokens': 171, 'total_tokens': 191, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_provider': 'openai', 'model_name': 'qwen-plus', 'system_fingerprint': None, 'id': 'chatcmpl-bd18ec5b-6b5a-4357-a4fb-b7096d60dbc9', 'finish_reason': 'tool_calls', 'logprobs': None}, id='lc_run--6082f90a-19b1-4740-a1d5-b0837dbf093c-0', tool_calls=[{'name': 'get_wather', 'args': {'city': '深圳'}, 'id': 'call_a57e9fc6b47347c08f7815', 'type': 'tool_call'}], usage_metadata={'input_tokens': 171, 'output_tokens': 20, 'total_tokens': 191, 'input_token_details': {'cache_read': 0}, 'output_token_details': {}}), ToolMessage(content='多云,很多云', name='get_wather', id='085d8e1f-7c5a-4e45-b51b-fa28e572b43e', tool_call_id='call_a57e9fc6b47347c08f7815'), AIMessage(content='深圳目前天气为多云,天空中有很多云,整体天气状况较为平稳。适合外出活动,但建议随身携带雨具,以防天气变化。祝您旅途愉快!', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 39, 'prompt_tokens': 210, 'total_tokens': 249, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 64}}, 'model_provider': 'openai', 'model_name': 'qwen-plus', 'system_fingerprint': None, 'id': 'chatcmpl-edfbd30f-ec45-40ff-a42d-6eb3bb1d28be', 'finish_reason': 'stop', 'logprobs': None}, id='lc_run--210aef59-5f0d-4f31-95f0-e3dfb9c5cf5c-0', usage_metadata={'input_tokens': 210, 'output_tokens': 39, 'total_tokens': 249, 'input_token_details': {'cache_read': 64}, 'output_token_details': {}})]}