五、(基础)别让大模型 “断网”!教你用 LangChain 开发联网 AI Agent,实操教程来了

前言

  1. 上一章讲解了如何调用向量模型、使用向量数据库等,并将其融入到 langchain 的链式操作中
  2. 本章将讲解使用联网搜索和模型进行交互,并如何创建代理,使 langchain 自动操作模型获得我们想要的结果

准备工作

  • 需要了解构建 LangChain 的一些用法,可以阅读本专栏内容,欢迎订阅
  • pip安装LangChain:pip install langchain
  • 调用大模型key,我们主要是学习为主,能白嫖自然白嫖,不需要多么快速的响应,下面是对应的申请方式,都是免费的,其他模型都是需要对应token花费钱的。注意:我们只要申请openai的key,openai更加通用
    • 腾讯元宝:hunyuan-lite,申请地址
    • 智谱AI:GLM-4-Flash-250414,申请地址,更推荐,响应速度快,更精准,对 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站视频分析等,欢迎持续关注

相关推荐
Goboy3 小时前
OpenClaw 卸载教程,一篇讲透
ai编程
刀法如飞5 小时前
AI时代,程序员都应该是需求描述工程师
程序员·aigc·ai编程·需求文档
还好还好不是吗8 小时前
使用 trae skills免费codeview 你的最新pr代码
ai编程·trae
孟健9 小时前
得物前端部门,没了
ai编程
该用户已不存在9 小时前
除了OpenClaw还有谁?五款安全且高效的开源AI智能体
人工智能·aigc·ai编程
量子位10 小时前
给龙虾定MBTI、发工牌,还让龙虾偷技能…打工人得适应新环境了
openai·ai编程
天空11010 小时前
Claude Code 支持 LSP 了,AI 编程终于不再靠 grep 找代码
ai编程
海上日出10 小时前
2026 AI Agent 全景图:从"会聊天"到"会干活",打工人如何抓住这波生产力革命?
ai编程
码路飞11 小时前
FastMCP 实战:一个 .py 文件,给 Claude Code 装上 3 个超实用工具
python·ai编程·mcp