步骤1:申请APIkey并配置环境变量
- 申请APIkey
以OpenAI为例,官⽹地址:https://platform.openai.com/
将APIKey在⾃⼰本地保存好,后续接⼊ChatGPT时需要使⽤。 - 配置环境变量
将APIKey配置在环境变量中主要是为了保证其隐私性。由于apikey⽐较隐私,为避免在程序中暴
露,可提前将各个apikey配置在环境变量中,这样在程序中就可以通过获取对应环境变量拿到api
key,保证了apikey的隐私。

步骤2:定义⼤模型
- 安装OpenAI包
pip install -U langchain-openai-
- 定义⼤模型
定义⼤模型
python
from langchain_openai import ChatOpenAI
model = ChatOpenAI(model="gpt-5-mini")
步骤3:定义消息列表
python
#
定义消息列表
from langchain_core.messages import HumanMessage, SystemMessage
messages = [
SystemMessage(content="Translate the following from English into Chinese"),
HumanMessage(content="hi!"),
]
参数说明:
• SystemMessage :表⽰系统⻆⾊消息,系统消息通常作为输⼊消息序列中的第⼀条传⼊,是⽤来启动AI⾏为的消息。
• HumanMessage :表⽰⽤⼾⻆⾊消息,是来⾃⽤⼾的、从⽤⼾传递到模型的消息。
步骤4:调⽤⼤模型model 是LangChain Runnable(可运⾏)接⼝的实例,这意味着我们与之交互。要简单地调⽤模型,我们可以将消息列表传递给model 提供了⼀个标准接⼝供.invoke ⽅法。
使⽤.invoke ⽅法进⾏⼤模型调⽤,核⼼代码:
python
result = model.invoke(messages)
print(result
输出结果(调试可以看⻅result类型为AIMessage):
python
content='你好!' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 2, 'prompt_tokens': 20, 'total_tokens': 22, 'completion_tokens_details'{'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0,'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-5-mini-2024-07-18', 'system_fingerprint': 'fp_560af6e559',
'id': 'chatcmpl-C5l29mi6KkQSFO3qaElDJD5Lj9nBn', 'service_tier': 'default', 'finish_reason': 'stop', 'logprobs': None} id='run--777ef0be-55c2-411a-a4ab104a45c22f20-0' usage_metadata={'input_tokens': 20, 'output_tokens': 2, 'total_tokens': 22, 'input_token_details': {'audio': 0, 'cache_read': 0},
'output_token_details': {'audio': 0, 'reasoning': 0}}
输出说明:
AIMessage :来⾃AI的消息。从聊天模型返回,作为对提⽰(输⼊)的响应。
content :消息的内容。◦
additional_kwargs :与消息关联的其他有效负载数据。对于来⾃AI的消息,可能包括模型提供程序编码的⼯具调⽤。◦
response_metadata :响应元数据。例如:响应标头、logprobs、令牌计数、模型名称。
侧重于"响应"本⾝的信息,⽐如这次请求的ID、使⽤的模型版本、以及服务提供商返回
的所有原始元数据。它主要⽤于调试、⽇志记录和获取请求的上下⽂信息。
usage_metadata :消息的使⽤元数据,例如令牌计数。
侧重于"资源消耗"的量化信息,即这次请求消耗了多少Token。它主要⽤于成本计算、监控和预算控制。
若只想输出聊天模型返回的结果字符串,可以使StrOutputParser
输出解析器组件,将⼤模型输出结果解析为最可能的字符串。核⼼代码:
python
# 定义str字符串输出解析器
from langchain_core.output_parsers import StrOutputParser
parser = StrOutputParser()
print(parser.invoke(result))
步骤6:链式执⾏
通过上述步骤,⽆论是调⽤⼤模型,还是输出解析,我们发现,每次都调⽤了⼀个invoke()⽅法,最终才会得到我们想要的结果。
对于LangChain,它给我们提供了链式执⾏的能⼒,即我们只需要定义各个"组件",将它们"链起来",⼀次性执⾏即可得到最终效果。
python
# 定义⼤模型
model = ChatOpenAI(model="gpt-5-mini")
# 定义消息列表
messages = [
SystemMessage(content="Translate the following from English into Chinese"),
HumanMessage(content="hi!"),
]
# 定义输出解析器
parser = StrOutputParser()
# 定义链
chain = model | parser
# 执⾏链
result = chain.invoke(messages)
print(result)
LangChain相关概念
3.1 Runnable接⼝
Runnable接⼝是使⽤LangChainComponents(组件)的基础。
概念说明:
Components(组件):⽤来帮助当我们在构建应⽤程序时,提供了⼀系列的核⼼构建块,例如语⾔模型、输出解析器、检索器、编译的LangGraph图等。
Runnable定义了⼀个标准接⼝,允许Runnable组件:
• Invoked(调⽤):单个输⼊转换为输出。
• Batched(批处理):多个输⼊被有效地转换为输出。
• Streamed(流式传输):输出在⽣成时进⾏流式传输。
• Inspected(检查):可以访问有关Runnable的输⼊、输出和配置的原理图信息。
spected(检查):可以访问有关 u able的输⼊、输出和配置的原理图信息。
• Composed(组合):可以组合多个Runnable,以使⽤LCEL协同⼯作以创建复杂的管道。
因此,在快速上⼿中,我们定义的语⾔模型(model)、输出解析器(StrOutputParser)都是
Runnable接⼝的实例!他们都使⽤了Invoked(调⽤)的能⼒,回顾⼀下:
python
#
语⾔模型(model)
model = ChatOpenAI(model="gpt-5-mini")
result = model.invoke(messages)
# 语⾔模型是Runnable 接⼝实例,允许invoke调⽤
# 输出解析器(StrOutputParser)
parser = StrOutputParser()
parser.invoke(result)
# 输出解析器是Runnable 接⼝实例,允许invoke调⽤
python
chain = model | parser
chain.invoke(messages)
# 链是 Runnable 接⼝实例,允许invoke调⽤
可以看到,LCEL其实是⼀种编排解决⽅案,它使LangChain能够以优化的⽅式处理链的运⾏时执
⾏。任何两个Runnable实例都可以"链"在⼀起成序列。上⼀个可运⾏对象的.invoke() 调⽤的输出作为输⼊传递给下⼀个可运⾏对象。⽅法就是使⽤ |(管道/运算符):
chain = model | parser
⼆、聊天模型核⼼能⼒
- 定义聊天模型
⼤语⾔模型(LLM)在各种与语⾔相关的任务(例如⽂本⽣成、翻译、摘要、问答等)中表现出⾊。
现代LLM通常通过聊天模型接⼝访问,该接⼝将消息列表作为输⼊,并返回消息作为输出,⽽不是使
⽤纯⽂本。
这⾥需要注意LLM 与LangChain中聊天模型的关系:
• 在LangChain的官⽅⽂档中,认为LLM ⼤多数是纯⽂本补全模型。这些纯⽂本模型封装的API接受⼀个字符串提⽰作为输⼊,并输出⼀个字符串补全结果(实际上LLM还包括多模态输⼊)。
OpenAI的GPT-5就是作为LLM来实现的。
• LangChain中的聊天模型通常由LLM 提供⽀持,但经过专⻔调整以⽤于对话。关键在于,它们不是接受单个字符串作为输⼊,⽽是接受聊天消息列表,并返回⼀条AI消息作为输出。

通过API定义聊天模型
1.1.1 ⽅式1:ChatOpenAI

python
from langchain_openai import ChatOpenAI
model = ChatOpenAI(
model="gpt-5-mini",
temperature=0,
max_tokens=None,
timeout=None,
max_retries=2,
# api_key="...",
# base_url="...",
# organization="...",
# other params...
)
若使⽤其它与OpenAI兼容的⼤模型,例如DeepSeek,则可以使⽤以下定义⽅式:
python
port os
OPENAI_API_KEY = os.getenv('OPENAI_API_KEY')
from langchain_openai import ChatOpenAI
model = ChatOpenAI(
base_url="https://api.deepseek.com/v1",https://api.deepseek.com/v1
openai_api_key=OPENAI_API_KEY,
model="deepseek-chat",
#
openai_api_key
:需要单独申请DeepSeek的APIKey,然后重新进⾏环境变量配置。
◦
DeepSeekAPIKey申请地址:https://platform.deepseek.com/api_keys。
invoke() 调⽤
Runnable接⼝中的 .invoke() 调⽤。该⽅法是将单个输
⼊转换为对应的输出。例如对于聊天模型来说,就是根据⽤⼾的问题输⼊,输出相应的答案。
invoke() ⽅法定义:
python
stractmethod invoke(
input: Input,
config: RunnableConfig | None = None,
**kwargs: Any, ) → Output

请求参数:
• input:输⼊⼀个Runnable实例
• config (默认空):⽤于Runnable 的配置。
返回值:
• 返回⼀个Runnable实例
class langchain_core.runnables.config.RunnableConfig 常⽤参数说明

⽅式2:init_chat_model
上⾯的ChatOpenAI
⽤于明确创建OpenAI聊天模型的实例。⽽init_chat_model() 是⼀个⼯⼚函数,它可以初始化多种⽀持的聊天模型(如OpenAI、Anthropic、FireworksAI等),不仅仅是OpenAI的聊天模型。
init_chat_model() 函数定义
python
langchain.chat_models.base.init_chat_model(
model: str,
*,
model_provider: str | None = None,
configurable_fields: Literal[None] = None,
config_prefix: str | None = None,
**kwargs: Any,
) → BaseChatModel
init_chat_model() 常⽤参数说明

init_chat_model() 返回值说明函数返回⼀个与指定的model_name和model_provider相对应的ChatOpenAI
,
BaseChatModel (如ChatAnthropic 等)。注意要是模型可配置,则返回⼀个聊天模型模拟器,该模
拟器在传⼊配置后,于运⾏时才会初始化底层模型。
基本⽤法
使⽤不同的模型提供⽅,需要安装为其各⾃包,与设置各⾃的APIKey环境变量!例如:
• OpenAI环境变量配置为:OPENAI_API_KEY="your_openai_api_key"◦
安装命令:
pip install -U langchain-openai
• Anthropic环境变量配置为:ANTHROPIC_API_KEY="your_anthropic_api_key"◦
安装命令:
pip install -U langchain-anthropic
• DeepSeek环境变量配置为:DEEPSEEK_API_KEY="your_deepseek_api_key"◦
安装命令:
pip install -U langchain-deepseek
• GoogleVertexAI环境变量配置为:GOOGLE_API_KEY="your_google_api_key"◦
安装命令:
pip install -U langchain-google-vertexai
python
from langchain.chat_models import init_chat_model
# 返回langchain_openai.ChatOpenAI 实例
gpt_model = init_chat_model("gpt-5-mini", model_provider="openai",
temperature=0)
# 返回langchain_deepseek.ChatDeepSeek 实例
deepseek_model = init_chat_model("deepseek-chat", model_provider="deepseek",
temperature=0)
# 由于所有模型集成都实现了ChatModel接⼝,因此可以以相同的⽅式使⽤它们。
print("gpt-5-mini: " + gpt_model.invoke("what's your name").content + "\n")
print("deepseek-chat: " + deepseek_model.invoke("what's your name").content +
"\n")
⽰例2:创建可配置模型
class langchain_core.runnables.config.RunnableConfig 常⽤参数说明
python
configurable_model_1 = init_chat_model(temperature=0)
# 动态修改配置,初始化模型并调⽤
configurable_result_1 = configurable_model_1.invoke(
"what's your name", config={"configurable": {"model": "gpt-5-mini"}}
)
print("configurable1: " + configurable_result_1.content + "\n")
⽰例3:具有默认值的可配置模型
python
# 可配置模型模拟器
configurable_model_2 = init_chat_model(
model="gpt-5-mini",
temperature=0,
configurable_fields=("model", "model_provider", "temperature", "max_tokens"),
config_prefix="first",
)
# 动态修改配置,初始化模型并调⽤
configurable_result_2 = configurable_model_2.invoke(
"what's your name?",
config={
"configurable": {
"first_model": "deepseek-chat",
"first_temperature": 0.5,
"first_max_tokens": 100,
}
},
)
print("configurable2: " + configurable_result_2.content + "\n")
输出:
python
configurable2: My name is DeepSeek Chat! I'm here to help you with any questions or topics you're curious about. How can I assist you today?
通过本地部署的LLM定义聊天模型
ChatOllama
若想使⽤ChatOllama,需要先安装Ollama包:
python
pip install -U langchain_ollama
class langchain_ollama.chat_models.base.ChatOllama
是LangChain为通过Ollama部署的聊天模型提供的具体实现类。
ChatOllama 同样也实现了标准的Runnable接⼝。
ChatOllama常⽤初始化参数说明

python
from langchain_ollama import ChatOllama
ollama_model = ChatOllama(model="deepseek-r1:70b",
base_url='http://192.168.100.220:11434')
result = ollama_model.invoke("what's your name?")
print(result)
聊天模型--调⽤⼯具
⼯具调⽤根本作⽤是让⼤语⾔模型(LLM)具备与外部世界交互的能⼒。
LLM本⾝是⼀个封闭的知识系统,其能⼒受限于其训练数据(存在滞后性)和内在的⽂本⽣成逻辑。
它⽆法执⾏直接计算、查询实时信息、操作数据库或调⽤任何外部API。⼯具调⽤打破了这层壁垒,其
作⽤具体体现在:
- 扩展能⼒边界:模型可以借助⼯具完成它⾃⾝⽆法完成的任务,如执⾏数学计算、搜索⽹络、查询数据库等。
- 保证信息实时性:通过调⽤搜索⼯具或数据库查询⼯具,LLM可以获取最新的、训练数据中不存在的信息,避免回答过时或"⼀本正经地胡说⼋道"。
- 处理复杂任务:将⼀个复杂的⽤⼾请求(如"分析我上个⽉的消费趋势")分解成多个步骤,并依次调⽤不同的⼯具(如"从数据库获取数据"->"⽤Python进⾏数据分析"->"⽣成图表")来协同完成。协调这件事这更体现在Agent智能体上。
- 连接现有系统:可以将企业内部已有的系统、API和数据库封装成⼯具,让LLM成为⼀个⽤⾃然语⾔驱动的统⼀接⼝,极⼤地提升了⾃动化和集成能⼒。
在LangChain中,聊天模型提供了额外的功能:⼯具调⽤。它能使LLM与外部服务、API和数据库进⾏交互。⼯具调⽤还可⽤于从⾮结构化数据中提取结构化信息并执⾏各种其他任务。
例如,当我们希望获取当前天⽓情况时,由于LLM⽆法获取实时信息,此时我们就可以借助⼯具,通过外部服务进⾏搜索完成查询:

再例如,当我们希望获取数据库表中的数据时,由于LLM⽆法直接获取表数据,此时我们就可以借助
⼯具,通过与数据库交互完成查询:

创建⼯具
使⽤@tool 装饰器创建⼯具
在LangChain中,实现了⼀个@tool 装饰器来创建⼯具,@tool
装饰器是⾃定义⼯具的最简单⽅法。如下所⽰:
python
from langchain_core.tools import tool
@tool
def multiply(a: int, b: int) -> int:
"""Multiply two integers.
Args:
a: First integer
b: Second integer
"""
return a * b
print(multiply.invoke({"a": 2, "b": 3})) # 输出: 6
print(multiply.name) # 输出: multiply
print(multiply.description) # 输出: Multiply two ...省略...b: Second integer
print(multiply.args) # 输出: {'a': {'title': 'A', 'type': 'integer'}, 'b': {'title': 'B', 'type': 'integer'}}
可以看出,⼯具通过@tool 加Python函数 实现,其中:
• 该装饰器默认使⽤函数名称作为⼯具名称。
• 该装饰器将使⽤函数的⽂档字符串作为⼯具的描述。
因此,函数名、类型提⽰和⽂档字符串都是传递给⼯具Schema 的⼀部分,不可缺失。定义好的描述是使模型良好运⾏的重要部分。
什么是Schema?
答:想象以不同的⽅式,在JSON中表⽰有关⼀个⼈的信息:
⽰例1:
python
{
"name": "张⼩红",
"birthday": "1732年2⽉22⽇",
"address": "陕西省西安市雁塔区"
}
⽰例2
python
{
"surname": "王",
"given_name": "刚",
"birthday": "1732-02-22",
"address": {
"district": "萧⼭区",
"city": "杭州市",
"province": "浙江省"
"country": "中国"
}
}
这两种表述同样有效,尽管⽰例2显然⽐⽰例1更正式。记录的设计在很⼤程度上取决于其在应⽤程
序中的预期⽤途,因此这⾥没有正确或错误的答案。
但是,当应⽤程序说"给我⼀个⼈的JSON记录"时,重要的是要确切地知道该如何组织记录。例如,我们需要知道需要哪些字段,以及如何表⽰这些值。这就是
JSON Schema 的⽤武之地。
你可能⻅过这种可视化配置⽅式,实际上是在构造
JSON Schema :

转换成编码⽅式,则为以下内容(此JSONSchema⽚段描述了上述第⼆个⽰例的结构):
python
{
"type": "object",
"properties": {
"surname": { "type": "string" },
"given_name": { "type": "string" },
"birthday": { "type": "string", "format": "date" },
"address": {
"type": "object",
"properties": {
"district": { "type": "string" },
"city": { "type": "string" },
"province": { "type": "string" },
"country": { "type" : "string" }
}
}
}
}
若⽤此JSON Schema "验证"⽰例1,那么⽰例1是不符合当前JSON Schema 的,但是⽰例2可以"验证"通过。
注意,JSON Schema 是数据本⾝,⽽不是计算机程序,它只是⼀种"描述其他数据结构"的声明格式。简明扼要地描述数据的表⾯结构,并根据数据⾃动验证数据容易。但是,由于JSON Schema 不能包含任意代码,因此⽆法表达数据元素之间的关系存在某些约束。
因此,对于⾜够复杂的数据格式,任何"验证⼯具"都可能有两个验证阶段:⼀个在Schema (或结构)级别,⼀个在语义级别。后⼀种检查可能需要使⽤更通⽤的编程语⾔来实现。
最后回答⼀下问题,schema 就是描述其他数据结构的声明格式,⽤于⾃动验证数据⽽存在。
有了以上概念铺垫,对于⼯具schema,它将从函数名、类型提⽰和⽂档字符串中获取相关属性,以此来声明⼀个⼯具,包括其名称、描述、输⼊参数、输出类型等等。这⾥需要说明的是,若是简单定义⼯具,如上述⽰例,⼯具schema需要解析Google⻛格的⽂档字符串去获取【参数描述】。
什么是Google⻛格的⽂档字符串?Google⻛格是Python⽂档字符串的⼀种写作规范。它并⾮Python 语⾔官⽅强制要求,⽽是由Google为其内部Python项⽬制定的规范,后来因为其极⾼的可
读性和简洁性⽽在整个Python社区中变得⾮常流⾏。它使⽤Args: ,Returns: 等关键字,参数描述简洁明了,如下所⽰:
python
def fetch_data(url, retries=3):
"""从给定的URL获取数据。
Args:
url (str): 要从中获取数据的URL。
retries (int, optional): 失败时重试的次数。默认为3。
Returns:
dict: 从URL解析的JSON响应。
"""
# ... 函数实现...
除了这种⽅式,还有其他⽅式可以让⼯具schema,获取相关⼯具声明需要的内容。下⾯再展⽰其他常
⽤的⼯具定义模式:
模式1:依赖Pydantic类
若使⽤@tool 定义⼯具时,没有提供⽂档字符串,则会报错:
python
from langchain_core.tools import tool
@tool
def add(a: int, b: int) -> int:
return a + b
@tool
def multiply(a: int, b: int) -> int:
return a * b
点击运⾏,报错:ValueError: Function must have a docstring if description not provided.
此时,在LangChain中,可以使⽤Pydantic类,提供运⾏时数据验证和类型检查。通过Field(description="...") 添加字段描LangChain会⾃动提取。
注意,除⾮提供默认值,否则所有字段都是required 。如下所⽰:
python
# pydantic
数据验证
from pydantic import BaseModel, Field
class AddInput(BaseModel):
"""Add two integers."""
a: int = Field(..., description="First integer")
b: int = Field(..., description="Second integer")
class MultiplyInput(BaseModel):
"""Multiply two integers."""
a: int = Field(..., description="First integer")
b: int = Field(..., description="Second integer")
# 定义⼯具
from langchain_core.tools import tool
@tool(args_schema=AddInput)
def add(a: int, b: int) -> int:
# 未提供描述
return a + b
@tool(args_schema=MultiplyInput)
def multiply(a: int, b: int) -> int:
# 未提供描述
return a * b
注意是代码中@tool 的args_schema 参数,它表⽰⼯具函数在未提供描述、⽂档字符串等需要传递给⼯具Schema 的内容时,依赖Pydantic类使⽤args_schema 参数,定义并提供⼯具输⼊参数
的schema。默认为None。
点击运⾏,不会报错,且将来运⾏时会进⾏数据验证。因此,我们再次印证了函数名、类型提⽰和⽂档字符串都是传递给⼯具
Schema 的⼀部分,不可缺失。
2.1.1.2 模式2:依赖Annotated
在LangChain中,可以依赖Annotated 和⽂档字符串传递给⼯具
Schema
。如下所⽰:
python
from langchain_core.tools import tool
from typing_extensions import Annotated
@tool
def add(
a: Annotated[int, ..., "First integer"],
b: Annotated[int, ..., "Second integer"]
) -> int:
"""Add two integers."""
return a + b
@tool
def multiply(
a: Annotated[int, ..., "First integer"],
b: Annotated[int, ..., "Second integer"]
) -> int:
"""Multiply two integers."""
return a * b
绑定⼯具
为了实际将这些⼯具绑定到聊天模型,可以使⽤聊天模型的.bind_tools() ⽅法。如下所⽰:
python
from langchain_openai import ChatOpenAI
# 定义⼤模型
model = ChatOpenAI(model="gpt-4o-mini")
...
# 绑定⼯具,返回⼀个Runnable 实例
tools = [add, multiply]
model_with_tools = model.bind_tools(tools)
bind_tools() ⽅法定义
python
bind_tools(
tools: Sequence[dict[str, Any] | type | Callable | BaseTool],
*,
tool_choice: dict | str | Literal['auto', 'none', 'required', 'any'] | bool
| None = None,
strict: bool | None = None,
parallel_tool_calls: bool | None = None,
**kwargs: Any,
) → Runnable[PromptValue | str | Sequence[BaseMessage | list[str] |
tuple[str, str] | str | dict[str, Any]], BaseMessage]
请求参数:
• tools:绑定到此聊天模型的⼯具定义列表。⽀持的类型为:字典、pydantic.BaseModel类、Python 函数和BaseTool(如
@tool 装饰器创建的类)。
• tool_choice (默认空):要求模型调⽤哪个⼯具。可以设置为:
◦ 形式为'<<tool_name>>' 的str:调⽤<tool_name>⼯具。
◦ 'auto' :⾃动选择⼯具(包括⽆⼯具)。
◦ 'none' :不调⽤⼯具。
◦ 'any' 或'required' 或True :强制调⽤⾄少⼀个⼯具。
◦ False 或None :⽆效果,默认OpenAI的⾏为。
• strict (默认空):
◦ 如果为True ,则保证模型输出与⼯具定义中提供的JSON Schema 完全匹配。输⼊也将根Schema 进⾏验证。
◦ 如果为False ,则不会验证输⼊,也不会验证模型输出。
◦ 如果为None ,则不会将strict 参数传递给模型。
• parallel_tool_calls :默认为None ,允许并⾏⼯具使⽤。设置为
False 以禁用并行⼯具。
• kwargs(Any) :任何附加参数都直接传递给
返回值:
• 返回⼀个Runnable实例。
◦ 该实例⽀持多种格式输⼊:
▪ 原始提⽰PromptValue
▪ 字符串:"上海天⽓如何?"
▪ 消息或消息列表:HumanMessage(content="...")
◦ 该实例的输出:
▪ 包含⼯具调⽤信息的AIMessage
工具调用
通过.bind_tools() ⽅法我们可知,它返回了⼀个Runnable实例,因此我们可以使⽤该Runnable实例,调⽤.invoke() ⽅法,完成⼯具调⽤。⽰例如下:
python
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
from langchain_core.tools import tool
from typing_extensions import Annotated
# 定义⼤模型
model = ChatOpenAI(model="gpt-4o-mini")
@tool
def add(
a: Annotated[int, ..., "First integer"],
b: Annotated[int, ..., "Second integer"]
) -> int:
"""Add two integers."""
return a + b
@tool
def multiply(
a: Annotated[int, ..., "First integer"],
b: Annotated[int, ..., "Second integer"]
) -> int:
"""Multiply two integers."""
return a * b
# 绑定⼯具
tools = [add, multiply]
model_with_tools = model.bind_tools(tools)
# 调⽤⼯具
result = model_with_tools.invoke("9乘6等于多少?")
print(result)
⼯具调⽤的⼀个关键原则是,模型根据输⼊的相关性决定何时使⽤⼯具。模型并不总是需要调⽤⼯具。例如,给定⼀个不相关的输⼊,模型不会调⽤该⼯具:
python
result = model_with_tools.invoke("hello world!")
print(result)
强制模型调⽤⼯具
当然我们也可以让模型强制调⽤⼯具,那就需要在绑定⼯具时,设置tool_choice="any" ,表⽰强制调⽤⾄少⼀个⼯具。⽰例如下:
python
model_with_tools = model.bind_tools(tools, tool_choice="any")
result = model_with_tools.invoke("hello world!")
print(result)
⼯具属性
现在我们知道,输出结果是⼀个AIMessage 。但是,如果调⽤了⼯具,则result 将具有⼀个tool_calls 属性。此属性包括执⾏该⼯具所需的⼀切,包括⼯具名称和输⼊参数,⽰例如下:
python
model_with_tools = model.bind_tools(tools, tool_choice="any")
result = model_with_tools.invoke("9乘6等于多少?")
print(result.tool_calls)
输出结果:
python
[{'name': 'multiply', 'args': {'a': 9, 'b': 6}, 'id':
'call_csFbMmYD4Dmz8yMja3ZWK1QW', 'type': 'tool_call'}]
将工具输出传递给聊天模型
到这里可以发现,我们仅仅只是成功调用了工具,但是聊天模型并没有给我们返回我们真正需要的答案。此时就需要:
- 将工具输出传递给聊天模型,包括 HumanMessage、AIMessage (工具调用)、ToolMessage
- 聊天模型根据以上消息输入,将最终结果 AIMessage 返回。
为什么要发 ToolMessage 呢?
之前我们讲过,聊天模型通常不是接受单个字符串作为输入,而是接受聊天消息(XxxMessage)列表,因此在这里我们需要将工具的返回,构造成 ToolMessage,再传输给聊天模型!!!
方便的是,如果我们使用 @tool 装饰器创建的工具,使用 tool.invoke(tool_calls),将自动返回一个 ToolMessage。完整示例如下:
python
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
from langchain_core.tools import tool
from typing_extensions import Annotated
# 定义大模型
model = ChatOpenAI(model="gpt-4o-mini")
# 定义工具
@tool
def add(
a: Annotated[int, ..., "First integer"],
b: Annotated[int, ..., "Second integer"]
) -> int:
"""Add two integers."""
return a + b
@tool
def multiply(
a: Annotated[int, ..., "First integer"],
b: Annotated[int, ..., "Second integer"]
) -> int:
"""Multiply two integers."""
return a * b
# 绑定工具
tools = [add, multiply]
model_with_tools = model.bind_tools(tools)
# 添加AIMessage到消息中去
messages = [
HumanMessage("9乘6等于多少? 5加3等于多少? ")
]
ai_msg = model_with_tools.invoke(messages)
messages.append(ai_msg)
for tool_call in ai_msg.tool_calls:
# 根据工具名选择对应工具函数(不区分大小写)
selected_tool = {"add": add, "multiply": multiply}[tool_call["name"].lower()]
# 执行工具调用,返回 ToolMessage
tool_msg = selected_tool.invoke(tool_call)
# 将 ToolMessage 加入消息
messages.append(tool_msg)
print(messages)
result = model.invoke(messages)
print(result)