LangChain 构建 AI 代理(Agent)
LangChain 构建 AI 代理(Agent)
任务介绍
本任务旨在使用 LangChain 和 LangGraph 构建一个智能 AI 代理系统。该代理能够:
- 自动判断是否需要调用工具:根据用户问题,智能决定是直接回答还是调用外部工具
- 工具调用能力:集成 Tavily 搜索引擎,可以实时获取网络信息
- 自动执行工具调用:通过代理执行器自动处理工具调用的完整流程
这是一个典型的 AI Agent 应用场景,展示了如何让大语言模型具备使用外部工具的能力,从而突破模型知识限制,获取实时信息。
任务解决逻辑
核心思路
AI 代理的核心思想是让大语言模型具备"思考-行动-观察"的能力:
- 思考阶段:模型分析用户问题,判断是否需要调用工具
- 行动阶段:如果需要,调用相应的工具(如搜索引擎)
- 观察阶段:获取工具返回的结果
- 回答阶段:基于工具结果生成最终答案
解决步骤
步骤 1:创建 LLM 模型
首先创建 Qwen 大语言模型作为代理的"大脑":
# 创建 Qwen LLM 模型
model = ChatOpenAI(model='qwen-turbo',api_key=qwen_api_key,base_url='https://dashscope.aliyuncs.com/compatible-mode/v1'
)
逻辑说明:模型负责理解用户意图和生成回答。
步骤 2:创建工具
创建 Tavily 搜索引擎工具,用于获取实时信息:
# LangChain内置了一个工具,可以轻松地使用Tavily搜索引擎作为工具。
# max_results: 只返回两个结果
search = TavilySearchResults(max_results=2)
tools = [search]
逻辑说明:工具是代理的"手",用于执行具体操作(如搜索、计算等)。
步骤 3:绑定工具到模型
将工具绑定到模型,让模型知道可以使用哪些工具:
# 让模型绑定工具
model_with_tools = model.bind_tools(tools)
逻辑说明:绑定后,模型会学习工具的描述和用法,能够判断何时调用工具。
步骤 4:模型自动判断是否需要工具
模型会根据问题自动判断是否需要调用工具:
问题1:中国的首都是哪个城市?
——该问题AI模型可以直接回答,因此不需要调用工具
问题2:北京天气怎么样?
——该问题AI模型不能回答,因此需要调用工具
# 模型可以自动推理:是否需要调用工具去完成用户的答案
resp = model_with_tools.invoke(
[HumanMessage(content='中国的首都是哪个城市?')]
)
# 结果:Model_Result_Content: 中国的首都是北京。
# Tools_Result_Content: [] # 不需要调用工具resp2 = model_with_tools.invoke([HumanMessage(
content='北京天气怎么样?')]
)
# 结果:Model_Result_Content: (空)
# Tools_Result_Content: [
#{'name': 'tavily_search_results_json', ...}
#] 需要调用工具
逻辑说明:
- 对于知识性问题(如"中国的首都是哪个城市?"),模型直接回答,
tool_calls为空 - 对于需要实时信息的问题(如"北京天气怎么样?"),模型生成工具调用请求,
tool_calls包含工具调用信息
步骤 5:创建代理执行器
使用 LangGraph 的预构建组件创建完整的代理执行器:
# 创建代理
agent_executor = chat_agent_executor.create_tool_calling_executor(
model, tools)
逻辑说明:代理执行器会自动处理以下流程:
- 接收用户消息
- 调用模型判断是否需要工具
- 如果需要,自动执行工具调用
- 将工具结果返回给模型
- 模型基于工具结果生成最终答案
步骤 6:执行代理查询
通过代理执行器处理用户问题:
resp = agent_executor.invoke({'messages':
[HumanMessage(content='北京天气怎么样?')]
})
print(resp['messages'][2].content) # 获取最终答案
逻辑说明:代理执行器会自动完成工具调用的完整循环,返回包含工具结果和最终答案的消息列表。
解决文字流程图
开始│├─→ [1. 初始化配置]│ ├─→ 设置 Qwen API Key│ └─→ 设置 Tavily API Key│├─→ [2. 创建 LLM 模型]│ └─→ 初始化 ChatOpenAI (qwen-turbo)│├─→ [3. 创建工具]│ └─→ 初始化 TavilySearchResults (搜索引擎工具)│├─→ [4. 绑定工具到模型]│ └─→ model.bind_tools(tools)│ └─→ 模型学习工具描述和用法│├─→ [5. 用户输入问题]│ └─→ 例如:"北京天气怎么样?"│├─→ [6. 模型分析问题]│ ├─→ 判断问题类型│ ├─→ 评估是否需要外部信息│ └─→ 决定是否调用工具│├─→ [7. 分支判断]│ ││ ├─→ [分支A: 不需要工具]│ │ ├─→ 模型直接生成答案│ │ └─→ 返回答案 (tool_calls = [])│ ││ └─→ [分支B: 需要工具]│ ├─→ 模型生成工具调用请求│ │ └─→ tool_calls = [{'name': 'tavily_search_results_json', ...}]│ ││ ├─→ [8. 代理执行器处理]│ │ ├─→ 解析工具调用请求│ │ ├─→ 执行工具调用│ │ │ └─→ search.invoke('北京天气怎么样?')│ │ ││ │ ├─→ 获取工具返回结果│ │ │ └─→ 搜索引擎返回天气信息│ │ ││ │ ├─→ 将工具结果传递给模型│ │ ││ │ └─→ 模型基于工具结果生成最终答案│ ││ └─→ [9. 返回最终答案]│ └─→ 包含工具结果和模型生成的回答│└─→ [10. 输出结果]└─→ 显示完整的对话历史和最终答案
关键代码片段
1. 工具绑定和判断逻辑
# 绑定工具
tools = [search]
model_with_tools = model.bind_tools(tools)# 模型自动判断
resp = model_with_tools.invoke([HumanMessage(
content='中国的首都是哪个城市?')])
# 不需要工具,直接回答
print(f'Model_Result_Content: {resp.content}') # 中国的首都是北京。
print(f'Tools_Result_Content: {resp.tool_calls}') # []resp2 = model_with_tools.invoke([HumanMessage(content='北京天气怎么样?')])
# 需要工具,生成工具调用请求
print(f'Model_Result_Content: {resp2.content}') # (空)
print(f'Tools_Result_Content: {resp2.tool_calls}') # [工具调用信息]
2. 代理执行器创建和使用
# 创建代理执行器(自动处理工具调用循环)
agent_executor = chat_agent_executor.create_tool_calling_executor(
model, tools)# 执行查询(自动完成:判断→调用工具→生成答案)
resp = agent_executor.invoke({'messages': [HumanMessage(content='北京天气怎么样?')]
})# 获取最终答案
print(resp['messages'][2].content) # 包含工具结果和模型生成的答案
完整代码
import os
from langchain_chroma import Chroma
from langchain_core.documents import Document
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnableLambda, RunnablePassthrough
from langchain_openai import ChatOpenAI # Qwen LLM 通过 OpenAI 兼容接口调用
from langchain_community.embeddings import DashScopeEmbeddings # Qwen 嵌入模型
from langchain_core.messages import HumanMessage
from langchain_community.tools.tavily_search import TavilySearchResults
from langgraph.prebuilt import chat_agent_executor# Qwen(通义千问)API Key
qwen_api_key = 'TripleH' # 请替换为您的 DashScope API Key
os.environ["TAVILY_API_KEY"] = 'TripleH'# 创建 Qwen LLM 模型
# 可选模型:qwen-turbo, qwen-plus, qwen-max, qwen-max-longcontext
model = ChatOpenAI(model='qwen-turbo', # 可以根据需要改为 qwen-plus 或 qwen-maxapi_key=qwen_api_key,base_url='https://dashscope.aliyuncs.com/compatible-mode/v1'
)# 没有任何代理的情况下
# result = model.invoke([HumanMessage(content='江苏南京天气怎么样?')])
# print(result.content)# LangChain内置了一个工具,可以轻松地使用Tavily搜索引擎作为工具。
# max_results: 只返回两个结果
search = TavilySearchResults(max_results=2)
# print(search.invoke('北京的天气怎么样?'))# # 让模型绑定工具
tools = [search]
model_with_tools = model.bind_tools(tools)# 模型可以自动推理:是否需要调用工具去完成用户的答案
resp = model_with_tools.invoke(([HumanMessage(content = '中国的首都是哪个城市?')]))# print(f'Model_Result_Content: {resp.content}')
# print(f'Tools_Result_Content: {resp.tool_calls}')
# Model_Result_Content: 中国的首都是北京。
# Tools_Result_Content: []resp2 = model_with_tools.invoke(([HumanMessage(content = '北京天气怎么样?')]))print(f'Model_Result_Content: {resp2.content}')
print(f'Tools_Result_Content: {resp2.tool_calls}')
# Model_Result_Content:
# Tools_Result_Content:
# [{'name': 'tavily_search_results_json',
# 'args': {'query': '北京天气怎么样?'}, 'id': 'call_bf9ade183d704c31a0e467', 'type': 'tool_call'}]# 创建代理agent_executor = chat_agent_executor.create_tool_calling_executor(model, tools)resp = agent_executor.invoke({'messages' : [HumanMessage(content='中国的首都是哪个城市?')]})
print('resp',resp['messages'])resp2 = agent_executor.invoke({'messages': [HumanMessage(content='北京天气怎么样?')]})
print('resp2',resp2['messages'])print('resp2',resp2['messages'][2].content)
总结
核心优势
- 智能判断:模型能够自动判断是否需要调用工具,无需手动指定
- 自动化执行:代理执行器自动处理工具调用的完整循环
- 实时信息:通过工具获取最新信息,突破模型知识限制
- 灵活扩展:可以轻松添加更多工具(计算器、数据库查询等)
应用场景
- 实时信息查询(天气、新闻、股价等)
- 复杂任务分解(需要多步骤完成的任务)
- 外部系统集成(调用 API、数据库等)
- 智能助手(能够使用多种工具完成用户需求)
技术要点
- 工具绑定:
model.bind_tools()让模型学习工具用法 - 工具调用:模型生成结构化的工具调用请求
- 代理执行器:
chat_agent_executor自动处理工具调用循环 - 消息流:通过消息列表管理对话历史和工具结果
这个系统展示了如何构建一个能够自主使用工具的 AI 代理,是实现更智能 AI 应用的重要基础。
