前言
- 上一章讲解了如何调用向量模型、使用向量数据库等,并将其融入到 langchain 的链式操作中
- 本章将讲解使用联网搜索和模型进行交互,并如何创建代理,使 langchain 自动操作模型获得我们想要的结果
准备工作
- 需要了解构建 LangChain 的一些用法,可以阅读本专栏内容,欢迎订阅
- pip安装LangChain:
pip install langchain
- 调用大模型key,我们主要是学习为主,能白嫖自然白嫖,不需要多么快速的响应,下面是对应的申请方式,都是免费的,其他模型都是需要对应token花费钱的。注意:我们只要申请openai的key,openai更加通用
- 以上模型都是免费的,可以放心使用,注意申请 openai 访问方式的key,
注意:本章内容需要使用向量模型,请注意申请
- 需要申请Tavily(一个搜索引擎)作为工具来配合 LangChain 进行联网搜索,Tavily每个月有一千条免费次数,足够我们学习使用了
- 建议使用 Jupyter Notebook,更加方便,安装教程
1. 构建 Tavily
语言模型本身其实做不了什么实际动作,它们能做的不过是输出一些文字而已。但 LangChain 有个挺重要的用法,就是搭建出一种 "代理" 机制。这种代理会把大型语言模型当成思考的核心,让它来判断该做哪些事,以及具体要给这些事提供什么信息。等这些事做完之后,得到的结果还能再送回给大型语言模型,让它接着判断:是还得再做点什么,还是说这事到这儿就可以结束了。
python
from langchain_community.tools.tavily_search import TavilySearchResults
search = 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"])
bash
| | | | | | | | | |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 时间 | 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 来让语言模型了解这些工具。
python
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
model = 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}")
可以看到我们现在的问题没有触发搜索服务
makefile
ContentString: 你好,请问有什么可以帮到您的吗?
ToolCalls: []
我们将问题换一下
python
response = model_with_tools.invoke([HumanMessage(content="北京的天气怎么样")])
可以看到已经成功触发搜索服务
python
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,不用咱们手动弄。
python
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
from langgraph.prebuilt import create_react_agent
model = 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"])
通过返回值,可以看到模型现在并没有调用搜索服务,因为我们问的问题不对
python
[
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': {}})
]
我们将问题换一下
python
response = agent_executor.invoke({"messages": [HumanMessage(content="北京的天气怎么样")]})
现在成功触发搜索服务
swift
[
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 调用代理来拿到最终的回应了。但要是代理得走好几个步骤,那可能就得等上一会儿。想实时看到中间的进展也不难,只要在消息产生的时候,让它们一条条流式返回就行。
python
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
from langgraph.prebuilt import create_react_agent
model = 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 方法来实现这一点。
python
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
from langgraph.prebuilt import create_react_agent
model = 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,这样它才知道该从哪个对话线程接着来。
python
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
from langgraph.prebuilt import create_react_agent
from langgraph.checkpoint.memory import MemorySaver
model = 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站视频分析等,欢迎持续关注