目录
一、什么是智能体?工具包又是什么?
二、智能体(Agent)的出现是为了解决哪些问题?
三、LangChain里面创建工具方式
3.1 @tool 装饰器:用来定义一个简单的工具函数,, 可以直接给函数加上这个装饰器,让函数成为可调用的工具
3.2 StructuredTool
3.3 继承BaseTool子类进行创建工具
四、LangChain工具包
4.1 如何使用内置工具包【联网搜索例子】
4.2 内置工具包整合LLM
4.3工具包调用Log
五、LangChain智能体执行引擎AgentExecutor
导读:本文围绕如何利用LangChain构建一个能够通过自然语言与MySQL数据库交互的AI智能体展开,详细介绍了从问题理解到SQL生成、执行再到结果解析的完整流程。文章首先强调了该智能体的核心能力:将用户提出的自然语言问题转化为结构化查询语句(如“统计每个地区的销量”),并自动连接数据库执行查询。在此基础上,系统还能将原始数据以更易理解的方式呈现给用户(例如将数值结果转换为自然语言描述)。此外,智能体具备自动修正SQL语法错误的能力,提高了系统的鲁棒性和用户体验。技术实现上使用了LangChain中的SQLDatabaseToolkit
和create_sql_agent
工具,结合LLM(如Qwen)进行推理与决策,实现了端到端的数据交互流程
一、什么是智能体?工具包又是什么?
-
智能体是一种具备自主决策能力的AI系统,通过感知环境、分析信息、调用工具、执行动作的闭环过程完成任务
-
智能体 = 大语言模型(LLM) + 工具(Tools) + 记忆(Memory)
智能体类比就是:一个具备自主决策能力的虚拟助手,能根据目标自主调用工具完成任务
二、智能体(Agent)的出现是为了解决哪些问题?
大模型的短板:虽然大语言模型(LLM)擅长文本生成,但缺乏:
实时数据获取能力(如天气/股票)、精确数学计算能力
专业领域知识(如法律/医疗)、外部系统对接能力
Tool工具就是解决这类问题的,通过Tool机制,好比给大模型插入翅膀
大白话解释: 你可以把“工具”理解为你在写程序时定义的一个个方法或函数。比如在 Java 或 Python 中,你经常会封装一些功能,用来完成特定的任务。如果这个方法是用来调用外部服务的 API(比如高德地图的开放接口),那它就是一个“工具”。
以高德地图为例,如果你想获取某个地点的数据,可能需要向高德提供的 API 发送请求。这时候你就可以在 Python 中写一个方法,让它去调用这个 API,然后把结果返回给你。只要在这个方法上加上特定的注解(比如 @tool
),它就会被识别为一个“工具”,可以在系统中被自动发现和使用。
简单来说,这个“工具”就是帮你干活的小助手,它可以联网、调用外部接口、执行任务,最终帮你拿到想要的信息或者完成某个操作。
三、LangChain里面创建工具方式
@tool装饰器
通过简单的@tool装饰器或StructuredTool即可实现,适用于大多数用例,
@tool但不能同时有同步和异步的方法,只能单独使用
LangChain Runnables
接受字符串或字典输入的LangChain Runnables使用as_tool方法转换为工具
允许为参数指定名称、描述和其他模式信息;
继承BaseTool类:
通过从BaseTool进行子类化来定义自定义工具,提供了对工具定义的最大控制,但需要编写更多的代码。
3.1 @tool 装饰器:用来定义一个简单的工具函数,, 可以直接给函数加上这个装饰器,让函数成为可调用的工具
from langchain_core.tools import tool@tool
def multiply(a: int, b: int) -> int:"""把传递的两个参数相乘"""return a * bprint("工具名称:", multiply.name)
print("工具描述:", multiply.description)
print("工具参数:", multiply.args)
print("工具返回值:", multiply.return_direct)
print("工具详细的schema:", multiply.args_schema.model_json_schema())print(multiply.invoke({"a": 2, "b": 3}))
# 定义了一个 `multiply` 工具,用于两个数字相乘,并在调用时显示该工具的名称、描述和参数列表。
3.2 StructuredTool
是LangChain中用于定义结构化参数工具的基类,相比普通
@tool
装饰器,它支持:
严格的参数模式定义(基于Pydantic模型)
多参数输入校验
自动生成工具调用示例
适用场景:需要多个输入参数或复杂参数类型的工具
from pydantic import BaseModel, Field
from langchain_core.tools import StructuredTool# 定义输入参数的数据结构
class CalculatorInput(BaseModel):a: int = Field(description="第一个数字")b: int = Field(description="第二个数字")# 定义计算函数
def multiply(a: int, b: int) -> int:"""Multiply two numbers."""return a * b
# 封装工具
calculator = StructuredTool.from_function(func=multiply,name="Calculator",description="用于计算两个数字的乘积",args_schema=CalculatorInput,return_direct=True,
)
print("工具名称:", calculator.name)
print("工具描述:", calculator.description)
print("工具参数:", calculator.args)
print("工具返回值:", calculator.return_direct)
print("工具详细的schema:", calculator.args_schema.model_json_schema())# 调用工具
print("工具调用结果:", calculator.invoke({"a": 2, "b": 3}))
3.3 继承BaseTool
子类进行创建工具
from pydantic import BaseModel, Field
from typing import Type
from langchain_core.tools import BaseTool
from pydantic import BaseModelclass CalculatorInput(BaseModel):a: int = Field(description="第一个参数")b: int = Field(description="第二个参数")class CustomCalculatorTool(BaseTool):name: str = "Calculator"description: str = "当你需要计算数学问题时候使用"args_schema: Type[BaseModel] = CalculatorInputreturn_direct: bool = Truedef _run(self, a: int, b: int) -> str:"""使用工具."""return a * bcalculator = CustomCalculatorTool()
print("工具名称:", calculator.name)
print("工具描述:", calculator.description)
print("工具参数:", calculator.args)
print("工具返回值:", calculator.return_direct)
print("工具详细的schema:", calculator.args_schema.model_json_schema())
print(calculator.invoke({"a": 2, "b": 3}))
@tool 用的会多一些~
四、LangChain工具包
为了方便开发者快速使用各种主流工具,LangChain官方加入了很多内置工具,开箱即用
所有工具都是 BaseTool 的子类,且工具是 Runnable可运行组件,支持 invoke、stream 等方法进行调用
也可以通过 name、 description、args、 returu_direct 等属性来获取到工具的相关信息
如果内置工具包不满足,即可以自定义工具
地址:https://python.langchain.com/docs/integrations/tools/
4.1 如何使用内置工具包【联网搜索例子】
选择对应的工具->安装依赖包->编写代码实战
搜索工具:选择 SearchApi,注册时100次免费搜索,注册账号获取 APIKEY
代码实操:
import os# 从langchain_community.utilities模块中导入SearchApiAPIWrapper类,用于封装搜索API
from langchain_community.utilities import SearchApiAPIWrapper# 设置环境变量SEARCHAPI_API_KEY,用于认证搜索API的密钥
os.environ["SEARCHAPI_API_KEY"] = "UVWAsik11111111"# 实例化SearchApiAPIWrapper对象,用于调用搜索API
search = SearchApiAPIWrapper()# 调用run方法执行搜索操作,参数为查询腾讯股价的中文字符串
result = search.run("今天腾讯的股价是多少")# 输出搜索结果
print(result)
4.2 内置工具包整合LLM
这种是相对原始调用工具方式,下面章节会讲经常用的简便方式.这种是方便理解工具调用的底层方式
# 基于LangChain 0.3.x的SearchApi工具实战(需安装依赖)
# pip install langchain-core langchain-openai langchain-communityfrom langchain_community.utilities import SearchApiAPIWrapper
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from langchain_core.messages import ToolMessage
from langchain_core.runnables import RunnablePassthrough
from langchain_core.prompts import ChatPromptTemplateimport os
from langchain_core.tools import tool
from pydantic import Field
import loggingos.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = "lsv2_pt_da11ddbcbb1111111111"
os.environ["LANGSMITH_ENDPOINT"] = "https://api.smith.langchain.com"
os.environ["LANGSMITH_PROJECT"] = "nnw_agent-search-llm"
logging.basicConfig(level=logging.DEBUG)
# ======================
# 第一步:配置搜索工具
# ======================
# 注册SearchAPI获取密钥:https://www.searchapi.io/# 设置SearchAPI的API密钥
os.environ["SEARCHAPI_API_KEY"] = "UVWAs1111111111"
# 实例化SearchApiAPIWrapper对象,用于调用搜索API
search = SearchApiAPIWrapper()# ======================
# 第二步:定义搜索工具
# ======================
@tool("web_search", return_direct=True)
def web_search(query: str) -> str:"""当需要获取实时信息、最新事件或未知领域知识时使用,输入应为搜索关键词"""try:results = search.results(query) # 获取前3条结果return "\n\n".join([f"来源:{res['title']}\n内容:{res['snippet']}"for res in results["organic_results"]])except Exception as e:return f"搜索失败:{str(e)}"# ======================
# 第三步:绑定LLM创建Agent
# ======================
# 初始化大模型
llm = ChatOpenAI(model_name="qwen-plus",base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",api_key="sk-005c3c25f6d0111111111",temperature=0.7,
)# 创建聊天提示模板
prompt = ChatPromptTemplate.from_messages([("system","你是一个AI助手,名称叫老王,请根据用户输入的查询问题,必要时可以调用工具帮用户解答",),("human", "{query}"),]
)# 定义工具字典
tool_dict = {"web_search": web_search}# 从字典中提取工具列表
tools = [tool_dict[tool_name] for tool_name in tool_dict]# 绑定工具到大模型
llm_with_tools = llm.bind_tools(tools=tools)# 创建运行链
chain = {"query": RunnablePassthrough()} | prompt | llm_with_tools# 定义查询
query = "今天北京天气如何?"# 执行链并获取响应
resp = chain.invoke({"query": query})
print(resp)# 判断是否需要调用工具 content=''不一定需要调用,根据tool_calls进行判断
# ======================
# 第四步:获取工具调用
# ======================
tool_calls = resp.tool_calls
if len(tool_calls) <= 0:print(f"不需要调用工具:{resp.content}")
else:# 将历史消息合并,包括用户输入和AI输出history_messages = prompt.invoke(query).to_messages()history_messages.append(resp)print(f"历史消息:{history_messages}")# 循环调用工具for tool_call in tool_calls:tool_name = tool_call.get("name")tool_args = tool_call.get("args")tool_resp = tool_dict[tool_name].invoke(tool_args)print(f"一次调用工具:{tool_name},参数:{tool_args},结果:{tool_resp}")# 将工具调用结果添加到历史消息中history_messages.append(ToolMessage(tool_call_id=tool_call.get("id"), name=tool_name, content=tool_resp))print(f"历史消息:{history_messages}")resp = llm_with_tools.invoke(history_messages)print(f"最终结果:{resp}")print(f"调用工具后的结果:{resp.content}")
4.3工具包调用Log
工具调用输入和输出
将用户输入的自然语言和工具列表一起输送给大模型 --> 让大模型进行语义理解 --> 然后大模型将需要调用的工具发送给agent -->agent进行工具调用 --> 工具调用结果同输入的自然语言问题和提示词等一起再送给大模型-->大模型经过最终整理后返回处理结果
五、LangChain智能体执行引擎AgentExecutor
为什么需要 AgentExecutor?
问题:当智能体(Agent)需要执行多步操作(如多次调用工具、循环推理)时,开发者需手动处理:
执行循环:根据模型输出决定是否继续调用工具。
错误处理:捕获工具调用或模型解析中的异常。
流程控制:限制最大迭代次数,防止无限循环。
日志记录:追踪每一步的输入、输出和中间状态。痛点:
代码冗余:重复编写循环和错误处理逻辑。
维护成本高:复杂任务中难以保证流程稳定性。
可观测性差:难以调试多步骤执行过程通过上面的例子就可以知道 写起来很麻烦 还要手动调用工具。
create_tool_calling_agent
是 LangChain 0.3 新增的智能体创建方法, 要求模型直接返回工具调用参数(如 JSON 格式),减少中间解析错误。
结构化工具调用:显式调用工具并传递结构化参数(支持复杂数据类型)
多步骤任务处理:适合需要按顺序调用多个工具的场景
精准控制:通过自定义 Prompt 模板指导 Agent 行为
from langchain_openai import ChatOpenAI
from langchain.agents import create_tool_calling_agent, Tool, AgentExecutor
from langchain.tools import tool
from datetime import datetime
from langchain_core.prompts import ChatPromptTemplate# 定义获取当前日期的工具函数
@tool
def get_current_date() -> str:"""获取当前日期"""formatted_date = datetime.now().strftime("%Y-%m-%d")return f"The current date is {formatted_date}"# 定义搜索航班的工具函数
@tool
def search_flights(from_city: str, to_city: str, date: str) -> str:"""根据城市和日期搜索可用航班"""return f"找到航班:{from_city} -> {to_city},日期:{date},价格:¥1200"# 定义预订航班的工具函数
@tool
def book_flight(flight_id: str, user: str) -> str:"""预订指定航班"""return f"用户 {user} 成功预订航班 {flight_id}"# 定义获取股票价格的函数
def get_stock_price(symbol) -> str:return f"The price of {symbol} is $100."# 创建工具列表,包括获取股票价格、搜索航班、预订航班和获取当前日期的工具
tools = [Tool(name="get_stock_price", func=get_stock_price, description="获取指定的股票价格"),search_flights,book_flight,get_current_date,
]# 初始化大模型
llm = ChatOpenAI(model_name="qwen-plus",base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",api_key="sk-005cxxxxxx",temperature=0.7,
)# 定义聊天提示模板
prompt = ChatPromptTemplate.from_messages([("system", "你是一个AI助手,必要时可以调用工具回复问题"),("human", "我叫老王,经常出差,身份证号是 33333333333333"),# ("placeholder", "{chat_history}"),("human", "{input}"),("placeholder", "{agent_scratchpad}"),]
)# 创建代理 专为工具调用优化的智能体,支持结构化输出。
agent = create_tool_calling_agent(llm, tools, prompt)# 初始化代理执行器 , verbose=True可以看到思考明细, return_intermediate_steps返回中间结果
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True, return_intermediate_steps=True
)# 运行代理并获取结果
result = agent_executor.invoke({"input": "苹果股票是多少?根据我的行程,帮我查询下明天的航班,从合肥去北京,并定机票"}
)
print(f"最终结果:{result}")
LLM大模型访问MySQL业务数据库文章浏览阅读1k次,点赞25次,收藏16次。创建能通过自然语言与SQL数据库交互的AI智能体,自动生成/执行SQL查询并解析结果核心能力:将用户问题(如“统计每个地区的销量”)转化为 SQL 查询语句。连接数据库执行 SQL,默认只读模式防止数据误修改。将数据库返回的原始数据(如)转换为用户友好的回答(如“总销售额为 $3500”)。自动修正 SQL 语法错误或逻辑问题(如字段名拼写错误)。LangChain 中专门用于连接 SQL 数据库并集成相关操作工具的模块包#使用 SQLDatabase.from_uri 连接数据库,自动读取表结构。_大模型 读取 mysql数据库 回答https://blog.csdn.net/wnn654321/article/details/148933263 这是一个完整的例子,使用的
create_sql_agent SQLDatabaseToolkit(
langchain定义的工具)