五、(基础)别让大模型 “断网”!教你用 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站视频分析等,欢迎持续关注

相关推荐
yaocheng的ai分身2 小时前
介绍 Kiro
ai编程
都叫我大帅哥8 小时前
LangChain与PDF的奇妙之旅:从文档加载到智能问答的全面指南
python·langchain
soso196810 小时前
AI生成代码示例
ai编程
奇舞精选10 小时前
从 Claude System Prompt 看产品级 Prompt 设计
aigc·ai编程
马腾化云东11 小时前
本地部署mcp-server-chart服务:从零到生产的完整指南,实现AI智能图表可视化
echarts·ai编程·mcp
oil欧哟12 小时前
🧐 AI 批量检查数千份技术文档,如何实现高效文档纠错?
前端·人工智能·ai编程
我爱一条柴ya1 天前
【AI大模型】BERT微调文本分类任务实战
人工智能·pytorch·python·ai·分类·bert·ai编程
量子位1 天前
国产 Deep Research 杀出一匹「裸奔」黑马:免费开放,过程透明,网页报告一键即出
ai编程·deepseek
量子位1 天前
小扎自曝挖人秘诀:小团队我亲自带,豪掷数百亿建 GW 集群,大家不图天价薪酬只为 “造神”
ai编程