当前位置: 首页 > news >正文

27、LangChain开发框架(四)-- LangChain接入工具基本流程

在上一篇针对agent做了简单的介绍,本篇重点介绍下工具在LangChain中的使用方法。

1、LangChain内部工具

我们首先介绍一个最基本的LangChain接入工具流程。在MCP爆火之前,LangChian生态中就已经内置集成了非常多的实用工具,开发者可以快速调用这些工具完成更加复杂工作流的开发。

LangChain内置工具列表:https://python.langchain.com/docs/integrations/tools/

在这里插入图片描述
这里以其中代码解释器为例,来介绍如何将内置工具接入LangChain的工作流中。

1.1 数据集介绍

数据集使用常见的开源数据集:titanic数据集

Titanic数据集是机器学习领域经典的入门数据集,记录了1912年泰坦尼克号沉船事件中部分乘客的生存信息。该数据集常用于分类任务(预测乘客是否幸存)和数据探索分析。

数据字段说明

数据集通常包含以下字段(具体字段可能因版本不同略有差异):

  • PassengerId:乘客的唯一标识符。
  • Survived:是否幸存(0=否,1=是)。
  • Pclass:船舱等级(1/2/3等舱,反映社会经济地位)。
  • Name:乘客姓名。
  • Sex:性别(male/female)。
  • Age:年龄(可能存在缺失值)。
  • SibSp:同船兄弟姐妹/配偶数量。
  • Parch:同船父母/子女数量。
  • Ticket:船票编号。
  • Fare:船票价格。
  • Cabin:船舱编号(缺失值较多)。
  • Embarked:登船港口(C=瑟堡,Q=皇后镇,S=南安普顿)。
数据集特点
  • 包含数值型(如Age、Fare)、类别型(如Sex、Pclass)和文本型(如Name)数据。
  • 存在缺失值(如Age、Cabin),需进行数据清洗或插补。
  • 可通过特征工程衍生新特征(如家庭规模=SibSp+Parch)。
典型应用场景
  1. 分类任务:预测乘客是否幸存(目标变量为Survived)。
  2. 探索性分析:研究性别、船舱等级等因素与生存率的关系。
  3. 数据清洗与特征工程:处理缺失值、编码类别变量等。
数据获取方式

可通过以下途径获取:

  • Kaggle竞赛平台(Titanic: Machine Learning from Disaster)。
  • Python库seaborn内置数据集:
    import seaborn as sns
    titanic = sns.load_dataset('titanic')
    
数据描述
dataset = pd.read_csv('titanic.csv')
dataset.head()
dataset.info()

<class ‘pandas.core.frame.DataFrame’>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
-|Column - |Non-Null Count - |Dtype


|0 | PassengerId |891 |non-null | int64
1 Survived 891 non-null int64
2 Pclass 891 non-null int64
3 Name 891 non-null object
4 Sex 891 non-null object
5 Age 714 non-null float64
6 SibSp 891 non-null int64
7 Parch 891 non-null int64
8 Ticket 891 non-null object
9 Fare 891 non-null float64
10 Cabin 204 non-null object
11 Embarked 889 non-null object
dtypes: float64(2), int64(5), object(5)
memory usage: 83.7+ KB

1.2 内置代码解释器工具功能测试

测试LangChain内置代码解释器工具功能

langchain_experimental.tools中导入PythonAstREPLTool

import pandas as pd
from langchain_core.prompts import ChatPromptTemplate
from langchain_experimental.tools import PythonAstREPLTooltool = PythonAstREPLTool(locals={"df": dataset})
tool.invoke("df['Age'].mean()")

PythonAstREPLTool 的初始化参数 locals 用于定义工具执行代码时可访问的局部变量。这里将变量 df 绑定到 dataset(通常是一个 pandas DataFrame),即工具内部可通过 df 访问 dataset 的数据。

tool也可以调用工具的 invoke 方法,传入字符串形式的 Python 代码片段,工具会在其局部变量环境中执行该代码。

np.float64(29.69911764705882)

直接使用dataframe计算,来验证下

dataset['Age'].mean()np.float64(29.69911764705882)
创建LangChain工作流并绑定内置工具
import os
from dotenv import load_dotenv 
load_dotenv(override=True)from langchain_core.messages import AIMessage, HumanMessage, SystemMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain.chat_models import init_chat_model
from langchain_core.output_parsers import StrOutputParser

from dotenv import load_dotenv
load_dotenv(override=True)

  • dotenv 是一个用于管理环境变量的 Python 库,核心功能是从 .env 文件中读取键值对,并将其设置为系统环境变量。
    这里导入了 dotenv 库中的 load_dotenv 函数,该函数是加载 .env 文件的核心工具。
  • 参数 override=True 表示:如果系统中已经存在同名的环境变量(例如在终端中预先设置过),则用 .env 文件中的值覆盖已有的环境变量(即 .env 文件的配置优先)。
    若不设置此参数(默认 override=False),则不会覆盖已有环境变量,仅添加 .env 中新增的变量。
  • 项目中通常将 API 密钥、数据库密码等敏感信息写入 .env 文件(而非硬编码到代码中),再通过 load_dotenv 加载,避免敏感信息泄露(.env 一般会被添加到 .gitignore 中,不纳入版本控制)
  • 执行代码后,程序中可通过 os.getenv(“OPENAI_API_KEY”) 获取到 sk-xxxxxx,方便后续调用相关 API。
model  = init_chat_model(model="deepseek-chat", model_provider="deepseek")
llm_with_tools = model.bind_tools([tool])
response = llm_with_tools.invoke("我有一张表,名为'dataset',请帮我计算Fare字段的均值。"
)
responseAIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_00_eYMWf0694x3Rxg4JcCjHRH6J', 'function': {'arguments': '{"query": "import pandas as pd\\n\\n# 读取数据集\\ndataset = pd.read_csv(\'dataset.csv\')  # 假设数据文件名为dataset.csv\\n\\n# 计算Fare字段的均值\\nfare_mean = dataset[\'Fare\'].mean()\\nprint(f\\"Fare字段的均值为: {fare_mean}\\")"}', 'name': 'python_repl_ast'}, 'type': 'function', 'index': 0}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 83, 'prompt_tokens': 212, 'total_tokens': 295, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}, 'prompt_cache_hit_tokens': 0, 'prompt_cache_miss_tokens': 212}, 'model_name': 'deepseek-chat', 'system_fingerprint': 'fp_ffc7281d48_prod0820_fp8_kvcache', 'id': 'b787abe3-b729-4def-a691-b95593c01e7e', 'service_tier': None, 'finish_reason': 'tool_calls', 'logprobs': None}, id='run--096d3ff8-b060-4ea3-8aea-253d13f4dcea-0', tool_calls=[{'name': 'python_repl_ast', 'args': {'query': 'import pandas as pd\n\n# 读取数据集\ndataset = pd.read_csv(\'dataset.csv\')  # 假设数据文件名为dataset.csv\n\n# 计算Fare字段的均值\nfare_mean = dataset[\'Fare\'].mean()\nprint(f"Fare字段的均值为: {fare_mean}")'}, 'id': 'call_00_eYMWf0694x3Rxg4JcCjHRH6J', 'type': 'tool_call'}], usage_metadata={'input_tokens': 212, 'output_tokens': 83, 'total_tokens': 295, 'input_token_details': {'cache_read': 0}, 'output_token_details': {}})

使用output_parsers 对结果进行解析,结构化输出

from langchain_core.output_parsers.openai_tools import JsonOutputKeyToolsParserparser = JsonOutputKeyToolsParser(key_name=tool.name, first_tool_only=True)llm_chain = llm_with_tools | parserllm_chain.invoke("我有一张表,名为'df',请帮我计算Age字段的均值。"){'query': "df['Age'].mean()"}

这样便可得到我们需要的内容,然后进入前面定义好的tool

重新定义链
system = f"""
你可以访问一个名为 `df` 的 pandas 数据框,请根据用户提出的问题,编写 Python 代码来回答。只返回代码,不返回其他内容。只允许使用 pandas 和内置库。
"""
prompt = ChatPromptTemplate([("system", system),("user", "{question}")
])chain = prompt | llm_with_tools | parser | tool
chain.invoke({"question": "请计算Age字段的均值。"})np.float64(29.69911764705882)
chain.invoke({"question": "请计算Age字段和Fare字段的相关系数。"})
np.float64(0.09606669176903912)chain.invoke({"question": "请按照Pclass 字段计算Age字段的均值。"})Pclass
1    38.233441
2    29.877630
3    25.140620
Name: Age, dtype: float64

有的时候最终的输出结果会报错,我们希望查看中间的结果,可以加上一个打印的操作

from langchain_core.runnables import RunnableLambdadef code_print(res):print("即将运行Python代码:", res['query'])return resprint_node = RunnableLambda(code_print)
print_code_chain = prompt | llm_with_tools | parser | print_node | tool
print_code_chain.invoke({"question": "请计算Age字段和Fare字段的相关系数。"})即将运行Python代码: import pandas as pd# 计算Age字段和Fare字段的相关系数
correlation = df['Age'].corr(df['Fare'])
print(f"Age和Fare的相关系数为: {correlation}")'Age和Fare的相关系数为: 0.09606669176903888\n'

至此,一个简单的包含官方内置工具的代码解释器工作流就搭建完成了。

2、 LangChain接入自定义外部工作流程

2.1 自定义一个外部工具

这里自定义一个查询天气的外部工具,
需要去openweathermap官网注册一个api-key,https://home.openweathermap.org/api_keys

将注册的key写在.env 文件中

import os
from dotenv import load_dotenv 
load_dotenv(override=True)OPENWEATHER_API_KEY = os.getenv("OPENWEATHER_API_KEY")

先测试一下是否注册成功

import requests,jsondef get_weather(loc):"""查询即时天气函数:param loc: 必要参数,字符串类型,用于表示查询天气的具体城市名称,\注意,中国的城市需要用对应城市的英文名称代替,例如如果需要查询北京市天气,则loc参数需要输入'Beijing';:return:OpenWeather API查询即时天气的结果,具体URL请求地址为:https://api.openweathermap.org/data/2.5/weather\返回结果对象类型为解析之后的JSON格式对象,并用字符串形式进行表示,其中包含了全部重要的天气信息"""# Step 1.构建请求url = "https://api.openweathermap.org/data/2.5/weather"# Step 2.设置查询参数params = {"q": loc,               "appid": os.getenv("OPENWEATHER_API_KEY"),    # 输入API key"units": "metric",            # 使用摄氏度而不是华氏度"lang":"zh_cn"                # 输出语言为简体中文}# Step 3.发送GET请求response = requests.get(url, params=params)# Step 4.解析响应data = response.json()return json.dumps(data)

自定义一个查询的函数,函数本身比较简单,主要是需要按照规范,注释清楚函数的作用、输入、输出信息,因为需要让大语言模型也能明白,这样后面大模型才知道如何进行调用。

测试一下,查看请输出

get_weather("hangzhou")'{"coord": {"lon": 120.1614, "lat": 30.2937}, "weather": [{"id": 800, "main": "Clear", "description": "\\u6674", "icon": "01n"}], "base": "stations", "main": {"temp": 17.95, "feels_like": 17.76, "temp_min": 17.95, "temp_max": 17.95, "pressure": 1025, "humidity": 75, "sea_level": 1025, "grnd_level": 1022}, "visibility": 10000, "wind": {"speed": 1.94, "deg": 4, "gust": 4.35}, "clouds": {"all": 2}, "dt": 1761317352, "sys": {"type": 1, "id": 9651, "country": "CN", "sunrise": 1761257236, "sunset": 1761297576}, "timezone": 28800, "id": 1808926, "name": "Hangzhou", "cod": 200}'

2.2 封装成工具

上面能够正常运行后,可以将其封装成LangChain可识别的工具,这里需要用到装饰函数。在 LangChain 中,@tool 装饰器用于将 Python 函数转换为可供语言模型(LLM)调用的工具(Tool)。这使得 LLM 能够在生成响应时,调用外部函数或 API,执行特定任务。

@tool 装饰器的作用@tool 装饰器将一个普通的 Python 函数转换为 LangChain 的工具对象,具备以下功能:自动推断工具的名称、描述和参数模式:通过解析函数的名称和文档字符串,自动生成工具的元数据。支持自定义配置:可以通过装饰器参数自定义工具的名称、描述、参数模式等。与 LLM 兼容:生成的工具对象可以传递给支持工具调用的聊天模型,使模型能够执行特定的函数。
from langchain_core.tools import tool@tool
def get_weather(loc):"""查询即时天气函数:param loc: 必要参数,字符串类型,用于表示查询天气的具体城市名称,\注意,中国的城市需要用对应城市的英文名称代替,例如如果需要查询北京市天气,则loc参数需要输入'Beijing';:return:OpenWeather API查询即时天气的结果,具体URL请求地址为:https://api.openweathermap.org/data/2.5/weather\返回结果对象类型为解析之后的JSON格式对象,并用字符串形式进行表示,其中包含了全部重要的天气信息"""# Step 1.构建请求url = "https://api.openweathermap.org/data/2.5/weather"# Step 2.设置查询参数params = {"q": loc,               "appid": os.getenv("OPENWEATHER_API_KEY"),    # 输入API key"units": "metric",            # 使用摄氏度而不是华氏度"lang":"zh_cn"                # 输出语言为简体中文}# Step 3.发送GET请求response = requests.get(url, params=params)# Step 4.解析响应data = response.json()return json.dumps(data)

查看工具函数的属性,如果能正常查看说明封装成功

print(get_weather.name)
print(get_weather.description)
print(get_weather.args)get_weather
查询即时天气函数
:param loc: 必要参数,字符串类型,用于表示查询天气的具体城市名称,    注意,中国的城市需要用对应城市的英文名称代替,例如如果需要查询北京市天气,则loc参数需要输入'Beijing':return:OpenWeather API查询即时天气的结果,具体URL请求地址为:https://api.openweathermap.org/data/2.5/weather    返回结果对象类型为解析之后的JSON格式对象,并用字符串形式进行表示,其中包含了全部重要的天气信息
{'loc': {'title': 'Loc'}}

接下来,便可以通过新的llm_with_tools模型通过invoke方法来调用模型。代码如下:

from langchain.chat_models import init_chat_model# 初始化模型
model = init_chat_model("deepseek-chat", model_provider="deepseek")# 定义 天气查询 工具函数
tools = [get_weather]# 将工具绑定到模型
llm_with_tools = model.bind_tools(tools)response = llm_with_tools.invoke("你好, 请问杭州的天气怎么样?")print(response)content='我来帮您查询杭州的天气情况。' additional_kwargs={'tool_calls': [{'id': 'call_00_fAeFff70ejt1xNCAiZvasSaG', 'function': {'arguments': '{"loc": "Hangzhou"}', 'name': 'get_weather'}, 'type': 'function', 'index': 0}], 'refusal': None} response_metadata={'token_usage': {'completion_tokens': 25, 'prompt_tokens': 251, 'total_tokens': 276, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}, 'prompt_cache_hit_tokens': 0, 'prompt_cache_miss_tokens': 251}, 'model_name': 'deepseek-chat', 'system_fingerprint': 'fp_ffc7281d48_prod0820_fp8_kvcache', 'id': 'a5d535bf-d141-4efa-a277-c26d2c0b5e22', 'service_tier': None, 'finish_reason': 'tool_calls', 'logprobs': None} id='run--317f2959-3cf0-42f0-95d6-2bf050199e27-0' tool_calls=[{'name': 'get_weather', 'args': {'loc': 'Hangzhou'}, 'id': 'call_00_fAeFff70ejt1xNCAiZvasSaG', 'type': 'tool_call'}] usage_metadata={'input_tokens': 251, 'output_tokens': 25, 'total_tokens': 276, 'input_token_details': {'cache_read': 0}, 'output_token_details': {}}

可以看到已经正常在调用并返回了

response.additional_kwargs{'tool_calls': [{'id': 'call_00_fAeFff70ejt1xNCAiZvasSaG','function': {'arguments': '{"loc": "Hangzhou"}', 'name': 'get_weather'},'type': 'function','index': 0}],'refusal': None}

在打印的结果中可以看到:

  • tool_calls:这是一个列表,包含了模型生成的工具调用信息。每个工具调用信息是一个字典,包含以下字段:
    id:工具调用的唯一标识符。
    function:一个字典,描述了被调用的函数信息:
    name:函数的名称。
    arguments:传递给函数的参数,以 JSON 字符串的形式表示。
    type:工具调用的类型,通常为 ‘function’。

  • 说明,tool_calls 列表包含一个工具调用,表示模型调用了名为 get_weather 的函数,并传递了参数 {“loc”: “Hangzhou”}。

  • refusal:如果模型拒绝执行某个操作或回答某个问题,refusal 字段将包含相关信息。在您的示例中,refusal 为 None,表示模型没有拒绝任何操作。

下面我们继续调用JsonOutputKeyToolsParser输出解析器来处理模型响应。

from langchain_core.output_parsers.openai_tools import JsonOutputKeyToolsParserparser = JsonOutputKeyToolsParser(key_name=get_weather.name, first_tool_only=True)llm_chain = llm_with_tools | parser
llm_chain.invoke("请问杭州今天天气如何?"){'loc': 'Hangzhou'}

组合起来看一下是否能够输出调用结果

get_weather_chain = llm_with_tools | parser | get_weather'{"coord": {"lon": 120.1614, "lat": 30.2937}, "weather": [{"id": 800, "main": "Clear", "description": "\\u6674", "icon": "01n"}], "base": "stations", "main": {"temp": 17.95, "feels_like": 17.76, "temp_min": 17.95, "temp_max": 17.95, "pressure": 1025, "humidity": 75, "sea_level": 1025, "grnd_level": 1022}, "visibility": 10000, "wind": {"speed": 1.94, "deg": 4, "gust": 4.35}, "clouds": {"all": 2}, "dt": 1761317352, "sys": {"type": 1, "id": 9651, "country": "CN", "sunrise": 1761257236, "sunset": 1761297576}, "timezone": 28800, "id": 1808926, "name": "Hangzhou", "cod": 200}'

2.3 整合成链

from langchain.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParser# Prompt 模板
output_prompt = PromptTemplate.from_template("""你将收到一段 JSON 格式的天气数据,请用简洁自然的方式将其转述给用户。
以下是天气 JSON 数据:```json{weather_json}```请将其转换为中文天气描述,例如:
“北京当前天气晴,气温为 23°C,湿度 58%,风速 2.1 米/秒。”
只返回一句话描述,不要其他说明或解释。"""
)
output_chain = output_prompt | model | StrOutputParser()full_chain = get_weather_chain | output_chain
response = full_chain.invoke("请问杭州今天的天气如何?")
print(response)杭州当前天气晴,气温为18°C,湿度75%,风速1.94/秒。
http://www.dtcms.com/a/524666.html

相关文章:

  • 找人做网站要准备什么九江网站网站建设
  • 帝可得智能售货机系统实战Day1:从环境搭建到区域管理功能落地 (1)
  • 10.2Web Component
  • 有没有做产品团购的网站wordpress文章页禁止右键
  • Nginx 反向代理解析:从原理到生产级配置实战
  • [理论题] 2025 年 “技耀泉城” 海右技能人才大赛网络安全知识竞赛题目(四)
  • 文化馆网站数字化建设介绍重庆seo网站建设
  • 【Betaflight源码学习】之初始化函数(init.c)
  • STM32H750寄存器操作(硬件I2C)
  • 算法18.0
  • RHCA - DO374 | Day02:管理内容集和执行环境
  • 网站建设明细价格表包头seo营销公司
  • JAVA 锁机制【待完善】
  • 不平均的分治——根号分治
  • USP-(DeepSpeed-Ulysses-Attention and Ring-Attention)
  • Ubuntu部署集群环境(3台)
  • VoCo-LLaMA: Towards Vision Compression with Large Language Models 译读笔记
  • 国网北京电力建设研究院网站惠州网站建设电话
  • 鹤壁市住房和城乡建设局网站上线了建站教程
  • centos8.5运行ai00-server报错`GLIBC_2.39‘ not found,解决方法
  • 冷换仓的隐性代价:从安全策略到地址信誉体系的重新思考
  • 如何用Vue CLI 创建 Vue 项目
  • 网站开发专业前景完整php网站开发
  • 企业建网站110平米三室一厅简装图片
  • CAS汽车固件签名:从“完成签名”到“安全治理”的演进之路
  • 免费手机网站模板sem竞价推广怎么做
  • 企业数字化转型的关键一步:打通研发全流程
  • Unity 资源导出的问题,依赖关系过多。
  • 网站开发公司内部数据字典深圳网站建设设计公司
  • 网站建设维护公司地址如何做好网站内容