前言
- 上一章讲解了如何调用向量模型、使用向量数据库等,并将其融入到 langchain 的链式操作中本章将讲解使用联网搜索和模型进行交互,并如何创建代理,使 langchain 自动操作模型获得我们想要的结果
准备工作
- 需要了解构建 LangChain 的一些用法,可以阅读本专栏内容,欢迎订阅pip安装LangChain:
pip install langchain
调用大模型key,我们主要是学习为主,能白嫖自然白嫖,不需要多么快速的响应,下面是对应的申请方式,都是免费的,其他模型都是需要对应token花费钱的。注意:我们只要申请openai的key,openai更加通用以上模型都是免费的,可以放心使用,注意申请 openai 访问方式的key,注意:本章内容需要使用向量模型,请注意申请
需要申请Tavily(一个搜索引擎)作为工具来配合 LangChain 进行联网搜索,Tavily每个月有一千条免费次数,足够我们学习使用了建议使用 Jupyter Notebook,更加方便,安装教程1. 构建 Tavily
语言模型本身其实做不了什么实际动作,它们能做的不过是输出一些文字而已。但 LangChain 有个挺重要的用法,就是搭建出一种 “代理” 机制。这种代理会把大型语言模型当成思考的核心,让它来判断该做哪些事,以及具体要给这些事提供什么信息。等这些事做完之后,得到的结果还能再送回给大型语言模型,让它接着判断:是还得再做点什么,还是说这事到这儿就可以结束了。
from langchain_community.tools.tavily_search import TavilySearchResultssearch = TavilySearchResults(max_results=2, tavily_api_key="申请的key")search_results = search.invoke("北京的天气怎么样")#print(search_results)for search_result in search_results: print(search_result["content"])
| | | | | | | | | || --- | --- | --- | --- | --- | --- | --- | --- | --- || 时间 | 08:00 | 11:00 | 14:00 | 17:00 | 20:00 | 23:00 | 02:00 | 05:00 || 天气 | | | | | | | | || 气温 | 21.4℃ | 23.6℃ | 26.8℃ | 29.8℃ | 24.4℃ | 23.3℃ | 21.6℃ | 20.2℃ || 降水 | 无降水 | 无降水 | 无降水 | 无降水 | 无降水 | 无降水 | 无降水 | 无降水 || 风速 | 2.9m/s | 6.8m/s | 7.5m/s | 7.9m/s | 7.6m/s | 2.9m/s | 2.7m/s | 3.2m/s || 风向 | 东北风 | 东南风 | 西南风 | 西北风 | 西北风 | 西北风 | 东北风 | 西北风 | [...] | | | | | | | | | || --- | --- | --- | --- | --- | --- | --- | --- | --- || 时间 | 08:00 | 11:00 | 14:00 | 17:00 | 20:00 | 23:00 | 02:00 | 05:00 || 天气 | | | | | | | | || 气温 | 23.7℃ | 27℃ | 30.2℃ | 30.8℃ | 28.1℃ | 26.5℃ | 21.1℃ | 19.2℃ || 降水 | 无降水 | 无降水 | 无降水 | 无降水 | 无降水 | 无降水 | 无降水 | 无降水 || 风速 | 3.3m/s | 7.4m/s | 7.3m/s | 7m/s | 7.9m/s | 3.3m/s | 2.2m/s | 1.8m/s || 风向 | 西南风 | 西北风 | 西北风 | 西北风 | 东北风 | 西北风 | 西北风 | 西北风 | [...] | | | | | | | | | || --- | --- | --- | --- | --- | --- | --- | --- | --- || 时间 | 08:00 | 11:00 | 14:00 | 17:00 | 20:00 | 23:00 | 02:00 | 05:00 || 天气 | | | | | | | | || 气温 | 24.4℃ | 26.9℃ | 29.8℃ | 28.8℃ | 26℃ | 24.6℃ | 21.8℃ | 19.2℃ || 降水 | 无降水 | 无降水 | 无降水 | 无降水 | 无降水 | 无降水 | 无降水 | 无降水 || 风速 | 3.3m/s | 1.9m/s | 2m/s | 3.3m/s | 1.4m/s | 3.3m/s | 3.1m/s | 2.1m/s || 风向 | 东北风 | 东北风 | 东南风 | 西南风 | 东南风 | 东南风 | 东北风 | 东北风 |....省略
2. 结合大模型
可以通过传入消息列表来调用语言模型,而且还能看到这模型调用工具的具体情况。为了实现这一点,我们使用 .bind_tools 来让语言模型了解这些工具。
from langchain_community.tools.tavily_search import TavilySearchResultsfrom langchain_openai import ChatOpenAIfrom langchain_core.messages import HumanMessagemodel = ChatOpenAI(model="GLM-4-Flash-250414", api_key="申请的key", base_url="https://open.bigmodel.cn/api/paas/v4/")search = TavilySearchResults(max_results=2, tavily_api_key="申请的key")tools = [search]# 查看是否调用了搜索引擎插件model_with_tools = model.bind_tools(tools)response = model_with_tools.invoke([HumanMessage(content="你好")])print(f"ContentString: {response.content}")print(f"ToolCalls: {response.tool_calls}")
可以看到我们现在的问题没有触发搜索服务
ContentString: 你好,请问有什么可以帮到您的吗?ToolCalls: []
我们将问题换一下
response = model_with_tools.invoke([HumanMessage(content="北京的天气怎么样")])
可以看到已经成功触发搜索服务
ContentString: ToolCalls: [{'name': 'tavily_search_results_json', 'args': {'query': '北京天气'}, 'id': 'call_-8535024601817840514', 'type': 'tool_call'}]
现在这儿没什么文本内容,但有个工具调用的提示 —— 它想让我们用 Tavily Search 这个工具。不过这还不算真的调用了工具,只是告诉我们该去调用而已。要想真把这个工具用起来,还得我们自己来创建代理才行。
3. 创建代理
工具和大型语言模型都定义好了,接下来就能创建代理了。使用 LangGraph 来做这个事。目前用的是高级接口来代理,不过 LangGraph 有个好处,就是这个高级接口背后有套低级的 API 支撑着,可控性很强。现在,咱们可以用大型语言模型和工具来初始化代理了。注意:咱们传进去的是 model,不是 model_with_tools。这是因为 create_react_agent 会在后台自动调用.bind_tools,不用咱们手动弄。
from langchain_community.tools.tavily_search import TavilySearchResultsfrom langchain_openai import ChatOpenAIfrom langchain_core.messages import HumanMessagefrom langgraph.prebuilt import create_react_agentmodel = ChatOpenAI(model="GLM-4-Flash-250414", api_key="申请的key", base_url="https://open.bigmodel.cn/api/paas/v4/")search = TavilySearchResults(max_results=2, tavily_api_key="申请的key")tools = [search]agent_executor = create_react_agent(model, tools)response = agent_executor.invoke({"messages": [HumanMessage(content="你好")]})print(response["messages"])
通过返回值,可以看到模型现在并没有调用搜索服务,因为我们问的问题不对
[HumanMessage(content='你好', additional_kwargs={}, response_metadata={}, id='6e48786c-51c2-4528-906a-d2c845dae667'), AIMessage(content='你好,请问有什么可以帮到你的吗?', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 12, 'prompt_tokens': 144, 'total_tokens': 156, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_name': 'GLM-4-Flash-250414', 'system_fingerprint': None, 'id': '20250711163033d5df63a239d44385', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None}, id='run--e5e4f578-512a-40d4-878e-781e85cfd572-0', usage_metadata={'input_tokens': 144, 'output_tokens': 12, 'total_tokens': 156, 'input_token_details': {}, 'output_token_details': {}})]
我们将问题换一下
response = agent_executor.invoke({"messages": [HumanMessage(content="北京的天气怎么样")]})
现在成功触发搜索服务
[HumanMessage(content='北京的天气怎么样', additional_kwargs={}, response_metadata={}, id='b4892f56-0a54-4600-8166-2fd8fee00e72'), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_-8535004707527408014', 'function': {'arguments': '{"query": "北京天气"}', 'name': 'tavily_search_results_json'}, 'type': 'function', 'index': 0}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 15, 'prompt_tokens': 146, 'total_tokens': 161, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_name': 'GLM-4-Flash-250414', 'system_fingerprint': None, 'id': '20250711163503f85b0431d2de4f4d', 'service_tier': None, 'finish_reason': 'tool_calls', 'logprobs': None}, id='run--ad0fc16e-d273-48db-aef8-1ee7e4883f1c-0', tool_calls=[{'name': 'tavily_search_results_json', 'args': {'query': '北京天气'}, 'id': 'call_-8535004707527408014', 'type': 'tool_call'}], usage_metadata={'input_tokens': 146, 'output_tokens': 15, 'total_tokens': 161, 'input_token_details': {}, 'output_token_details': {}}), ToolMessage(content='[{"title": "北京-天气预报 - 中央气象台", "url": "......", "content": "土壤水分监测\\n 农业干旱综合监测\\n 关键农时农事\\n 农业气象周报\\n 农业气象月报\\n 农业气象专报\\n 生态气象监测评估\\n 作物发育期监测\\n\\n 数值预报\\n\\n CMA全球天气模式\\n CMA全球集合模式\\n CMA区域模式\\n CMA区域集合模式\\n CMA台风模式\\n 海浪模式\\n\\n1. 当前位置:首页\\n2. 北京市\\n3. 北京天气预报\\n\\n省份:城市:\\n\\n09:50更新\\n\\n日出04:45\\n\\n 北京 \\n\\n30℃\\n\\n日落19:43\\n\\n 降水量 \\n\\n0mm\\n\\n西南风\\n\\n3级\\n\\n 相对湿度 \\n\\n43%\\n\\n 体感温度 \\n\\n29.9℃\\n\\n空气质量:良 \\n\\n舒适度:温暖,较舒适\\n\\n 雷达图 \\n\\nImage 4\\n\\n24小时预报7天预报10天预报11-30天预报\\n\\n 发布时间:06-12 08:00 \\n\\n 06/12 \\n\\n周四 \\n\\nImage 5\\n\\n 多云 \\n\\n 南风 \\n\\n 3~4级 \\n\\n 35℃ \\n\\n 23℃ \\n\\nImage 6 [...] 北京-天气预报\\n\\n===============\\n\\n北京Image 1Image 235℃ / 23℃\\n\\n | \\n\\nEnglish\\n\\nImage 3\\n\\n 热门城市 \\n\\n北京\\n\\n天津\\n\\n石家庄\\n\\n太原\\n\\n呼和浩特\\n\\n沈阳\\n\\n长春\\n\\n哈尔滨\\n\\n上海\\n\\n南京\\n\\n杭州\\n\\n合肥\\n\\n福州\\n\\n南昌\\n\\n济南\\n\\n郑州\\n\\n武汉\\n\\n长沙\\n\\n广州\\n\\n深圳\\n\\n南宁\\n\\n海口\\n\\n重庆\\n\\n成都\\n\\n贵阳\\n\\n昆明\\n\\n拉萨\\n\\n西安\\n\\n兰州\\n\\n西宁\\n\\n银川\\n\\n乌鲁木齐\\n\\n香港\\n\\n澳门\\n\\n台北\\n\\n 天气实况 \\n\\n天气图\\n\\n卫星云图\\n\\n雷达图\\n\\n降水量\\n\\n气温\\n\\n风\\n\\n能见度\\n\\n强对流\\n\\n土壤水分\\n\\n 天气预报 \\n\\n天气公报\\n\\n每日天气提示\\n\\n春运气象服务专报\\n\\n气象灾害预警\\n\\n重要天气提示\\n\\n重要天气盘点\\n\ [...] | | | | | | | | | |\n| --- | --- | --- | --- | --- | --- | --- | --- | --- |\n| 时间 | 08:00 | 11:00 | 14:00 | 17:00 | 20:00 | 23:00 | 02:00 | 05:00 |\n| 天气 | | | | | | | | |\n| 气温 | 24.4℃ | 26.9℃ | 29.8℃ | 28.8℃ | 26℃ | 24.6℃ | 21.8℃ | 19.2℃ |\n| 降水 | 无降水 | 无降水 | 无降水 | 无降水 | 无降水 | 无降水 | 无降水 | 无降水 |\n| 风速 | 3.3m/s | 1.9m/s | 2m/s | 3.3m/s | 1.4m/s | 3.3m/s | 3.1m/s | 2.1m/s |\n| 风向 | 东北风 | 东北风 | 东南风 | 西南风 | 东南风 | 东南风 | 东北风 | 东北风 |', 'score': 0.77364457, 'raw_content': None}], 'response_time': 2.54}), AIMessage(content='根据中央气象台的最新数据,北京当前的天气情况为:温度为30℃,相对湿度为43%,西南风3级,空气质量良好,舒适度温暖,较舒适。预计未来24小时天气多云,气温在35℃到23℃之间变化。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 56, 'prompt_tokens': 2174, 'total_tokens': 2230, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_name': 'GLM-4-Flash-250414', 'system_fingerprint': None, 'id': '202507111635074ea4af78c2ae42f6', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None}, id='run--1e2153aa-62ef-47b0-9c57-7af231edb353-0', usage_metadata={'input_tokens': 2174, 'output_tokens': 56, 'total_tokens': 2230, 'input_token_details': {}, 'output_token_details': {}})]
3.1 流式消息
咱们已经知道怎么用.invoke 调用代理来拿到最终的回应了。但要是代理得走好几个步骤,那可能就得等上一会儿。想实时看到中间的进展也不难,只要在消息产生的时候,让它们一条条流式返回就行。
from langchain_community.tools.tavily_search import TavilySearchResultsfrom langchain_openai import ChatOpenAIfrom langchain_core.messages import HumanMessagefrom langgraph.prebuilt import create_react_agentmodel = ChatOpenAI(model="GLM-4-Flash-250414", api_key="申请的key", base_url="https://open.bigmodel.cn/api/paas/v4/")search = TavilySearchResults(max_results=2, tavily_api_key="申请的key")tools = [search]agent_executor = create_react_agent(model, tools)for chunk in agent_executor.stream( {"messages": [HumanMessage(content="北京的天气怎么样")]}): print(chunk) print("----")
返回值
3.2 流式令牌
除了流式返回消息,流式返回令牌也是有用的。 我们可以使用 .astream_events 方法来实现这一点。
from langchain_community.tools.tavily_search import TavilySearchResultsfrom langchain_openai import ChatOpenAIfrom langchain_core.messages import HumanMessagefrom langgraph.prebuilt import create_react_agentmodel = ChatOpenAI(model="GLM-4-Flash-250414", api_key="申请的key", base_url="https://open.bigmodel.cn/api/paas/v4/")search = TavilySearchResults(max_results=2, tavily_api_key="申请的key")tools = [search]agent_executor = create_react_agent(model, tools)async for event in agent_executor.astream_events( {"messages": [HumanMessage(content="北京的天气怎么样?")]}, version="v1"): kind = event["event"] if kind == "on_chain_start": if ( event["name"] == "Agent" ): print( f"Starting agent: {event['name']} with input: {event['data'].get('input')}" ) elif kind == "on_chain_end": if ( event["name"] == "Agent" ): print() print("--") print( f"Done agent: {event['name']} with output: {event['data'].get('output')['output']}" ) if kind == "on_chat_model_stream": content = event["data"]["chunk"].content if content: print(content, end="|") elif kind == "on_tool_start": print("--") print( f"Starting tool: {event['name']} with inputs: {event['data'].get('input')}" ) elif kind == "on_tool_end": print(f"Done tool: {event['name']}") print(f"Tool output was: {event['data'].get('output')}") print("--")
返回值,是不是有点像我们常用的的一些ai助手深度思考的模样
4. 加入会话管理
代理本身是没什么记忆的,之前的互动它都记不住。要是想让它能记住东西,就得给它传个检查点。传检查点的时候,调用代理时还得带上 thread_id,这样它才知道该从哪个对话线程接着来。
from langchain_community.tools.tavily_search import TavilySearchResultsfrom langchain_openai import ChatOpenAIfrom langchain_core.messages import HumanMessagefrom langgraph.prebuilt import create_react_agentfrom langgraph.checkpoint.memory import MemorySavermodel = ChatOpenAI(model="GLM-4-Flash-250414", api_key="申请的key", base_url="https://open.bigmodel.cn/api/paas/v4/")memory = MemorySaver()search = TavilySearchResults(max_results=2, tavily_api_key="申请的key")tools = [search]# 直接调用搜索引擎让大模型回答agent_executor = create_react_agent(model, tools, checkpointer=memory)config = {"configurable": {"thread_id": "abc123"}}for chunk in agent_executor.stream( {"messages": [HumanMessage(content="北京的天气怎么样?")]}, config): print(chunk) print("----")for chunk in agent_executor.stream( {"messages": [HumanMessage(content="我刚问了什么?")]}, config): print(chunk) print("----")
返回值
本章讲解使用联网搜索和模型进行交互,如何创建代理,使 langchain 自动操作模型获得我们想要的结果,至此我们基础部分已经讲完,接下来我们将讲解进阶部分,包括构建检索增强生成 (RAG) 、操作sql数据库、图数据库、分析pdf等文档、B站视频分析等,欢迎持续关注