【LangChain实战】LangChain 学习笔记(一):从定义大模型到工具调用

👋 欢迎阅读

🏠个人主页: 愿旖旎

📘专栏传送门: 算法专栏

💻当前学习内容:LangChain

📑 目录


一、前置讲解

在进入正文前,先花 10 秒了解本篇会反复用到的核心概念,带着印象去读正文,学习效率更高。

🧠 前置知识一:ChatOpenAI 与 DeepSeek

用 OpenAI 兼容接口定义聊天模型,是 LangChain 接入大模型的第一步

📐 前置知识二:消息类型(System/Human/AI/Tool)

模型输入输出的统一格式------系统消息、用户消息、AI 回复、工具结果

📚 前置知识三:Runnable 接口

LangChain 组件的统一标准接口,支持调用、批处理、流式、组合

🔗 前置知识四:LCEL 链式(|)

用管道符把多个组件串成一条链,一次性执行得到最终结果

🛠️ 前置知识五:工具调用(Tool)

让模型具备与外部世界交互的能力,是 Agent 的基础


二、定义大模型

2.1 安装 AI 包和定义大模型
cpp 复制代码
pip install -U langchain-deepseek  # 安装 AI 包

# 定义大模型
from langchain_openai import ChatOpenAI
model = ChatOpenAI(model="deepseek-chat")
2.2 定义消息列表和调用大模型
cpp 复制代码
# 定义消息列表
from langchain_core.messages import HumanMessage, SystemMessage
messages = [
    SystemMessage(content="Translate the following from English into Chinese"),
    HumanMessage(content="I am QiLongHao!"),
]

LangChain 中的三类基础消息

消息类型 角色 说明
SystemMessage 系统角色 系统消息通常作为输入消息序列的第一条 ,用来启动 AI 行为
HumanMessage 用户角色 来自用户、从用户传递到模型的消息
AIMessage AI 角色 聊天模型回答的内容

调用大模型

cpp 复制代码
result = model.invoke(messages)
print(result.content)

model 是 LangChain Runnable (可运行)接口的实例,这意味着 model 提供了一个标准接口供我们与之交互 。要简单地调用模型,我们可以将消息列表传递给 .invoke 方法

AIMessage 的四个核心属性

属性 说明
content 消息的内容(文本)
additional_kwargs 与消息关联的其他有效负载数据 ,如模型提供商编码的工具调用
response_metadata 响应元数据(请求 ID、模型版本、响应头等),侧重"响应"本身,主要用于调试与日志
usage_metadata 使用元数据(Token 计数),侧重"资源消耗",主要用于成本计算与监控

只输出字符串(StrOutputParser)

cpp 复制代码
# 定义 str 字符串输出解析器
from langchain_core.output_parsers import StrOutputParser
result = model.invoke(messages)
parser = StrOutputParser()
print(parser.invoke(result))

若只想输出聊天模型返回的结果字符串,可以使用 StrOutputParser 输出解析器组件将大模型输出结果解析为最可能的字符串

2.3 链式执行

通过上述步骤可以发现,无论是调用大模型,还是输出解析 ,每次都调用了 invoke() 方法,最终才能得到想要的结果。

对于 LangChain 而言,它提供了链式执行的能力 ------只需定义各个组件将它们"链起来"一次性执行即可得到最终效果

cpp 复制代码
import os
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, SystemMessage
from langchain_core.output_parsers import StrOutputParser


# 定义大模型
model = ChatOpenAI(
    model="deepseek-chat",
    api_key=os.getenv("DEEPSEEK_API_KEY"),
    base_url="https://api.deepseek.com",
)

# 定义消息列表
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 接口是使用 LangChain Components(组件)的基础。

概念说明 :Components(组件)是在构建应用程序时提供的一系列核心构建块,例如语言模型、输出解析器、检索器、编译的 LangGraph 图等。

Runnable 定义了一个标准接口,允许 Runnable 组件:

能力 说明
Invoked(调用) 单个输入转换为输出
Batched(批处理) 多个输入被有效地转换为输出
Streamed(流式传输) 输出在生成时进行流式传输
Inspected(检查) 可以访问有关 Runnable 的输入、输出和配置的原理图信息
Composed(组合) 可以组合多个 Runnable,使用 LCEL 协同工作创建复杂管道

所有能力参考官方文档

因此,在快速上手中,我们定义的语言模型(model)、输出解析器(StrOutputParser都是 Runnable 接口的实例 !他们都使用了 Invoked(调用) 的能力。

python 复制代码
# 语言模型(model)
model = ChatOpenAI(model="deepseek-chat")
result = model.invoke(messages)  # 语言模型是 Runnable 接口实例,允许 invoke 调用
​
# 输出解析器(StrOutputParser)
parser = StrOutputParser()
parser.invoke(result)  # 输出解析器是 Runnable 接口实例,允许 invoke 调用

重点Runnable 解决了原生大模型的一个问题------切换大模型困难 ,因为它是一个标准接口 ,因此不会因为换模型导致发生一系列连锁反应

3.2 LCEL

LangChain Expression Language(LCEL) :采用声明性方法 ,从现有 Runnable 对象构建新的 Runnable 对象。

通过 LCEL 构建出的新 Runnable 对象,被称为 RunnableSequence ,表示可运行序列RunnableSequence 就是一种 ------通过调试就能发现,chain 的类型就是 RunnableSequence

重要的是,RunnableSequence 也是 Runnable 接口 的实例,它实现了完整的 Runnable 接口,因此它可以与其他任何 Runnable相同的方式使用。

python 复制代码
chain = model | parser
chain.invoke(messages)  # 链是 Runnable 接口实例,允许 invoke 调用

核心机制 :上一个 Runnable 实例(组件)的执行结果 (即 .invoke() 的返回值)会作为输入 传递给下一个 Runnable 实例。


四、聊天模型核心能力

4.1 定义聊天模型

大语言模型(LLM) 在各种与语言相关的任务(如文本生成、翻译、摘要、问答等)中表现出色。现代 LLM 通常通过聊天模型接口 访问,该接口将消息列表 作为输入,并返回消息作为输出,而不是使用纯文本。

这里需要注意 LLMLangChain聊天模型的关系:

概念 说明
LLM(纯文本补全模型) 封装的是接受字符串提示、输出字符串补全结果的 API(实际还支持多模态输入)
聊天模型 由 LLM 提供支持但专门调整用于对话 :接受聊天消息列表 ,返回一条 AI 消息
4.2 通过 API 定义聊天模型
4.2.1 ChatOpenAI(方法一)

ChatOpenAI 定义聊天模型在快速上手 模块中已经涉及。class langchain_openai.chat_models.base.ChatOpenAILangChainOpenAI 的聊天模型(如 gpt-5.1deepseek )提供的具体实现类。其继承了 class langchain_openai.chat_models.base.BaseChatOpenAI,且 BaseChatOpenAI 实现了标准的 Runnable 接口。

常用参数说明

参数 说明
max_tokens 控制模型输出内容的最大长度,以 Token(词元)为单位
timeout 客户端等待服务器返回完整响应的最长时间(通常以秒为单位)
max_retries 请求因临时性故障失败时,SDK 内部自动重试的最大次数

例子

python 复制代码
model = ChatOpenAI(
    model="deepseek-chat",
    api_key=os.getenv("DEEPSEEK_API_KEY"),
    base_url="https://api.deepseek.com",
    temperature=1,
    max_tokens=10,
    # ......
)
4.2.2 invoke() 调用

介绍方法二之前,需要先了解 Runnable 接口中的 .invoke() 调用。该方法将单个输入 转换为对应的输出 。例如对于聊天模型 ,就是根据用户的问题输入,输出相应的答案。

说明
input 要传给 Runnable 的输入数据(如消息列表、字符串)
config(默认空) 用于 Runnable 的配置参数
返回值 Runnable 处理后的输出(如 AIMessage 或解析后的字符串)

config参数属性:

4.2.3 init_chat_model(方法二)

ChatOpenAI 用于明确创建 OpenAI 聊天模型的实例。而 init_chat_model() 是一个工厂函数 ,它可以初始化多种支持的聊天模型(如 OpenAIAnthropicFireworksAI 等),而不仅仅是 OpenAI 的聊天模型。

对比 ChatOpenAI init_chat_model()
定位 OpenAI 系聊天模型的具体实现类 多厂商聊天模型的统一工厂函数
指定模型 model="deepseek-chat" model="deepseek-chat" + model_provider="deepseek"
优点 直接明确 一个入口初始化任意厂商模型

返回值 :函数返回一个与指定的 model_namemodel_provider 相对应的 BaseChatModel (如 ChatOpenAIChatAnthropic 等)。

例子

python 复制代码
from langchain.chat_models import init_chat_model
from langchain_core.messages import HumanMessage, SystemMessage

# ========== 1. 初始化聊天模型(init_chat_model 统一入口) ==========
model = init_chat_model(
model="deepseek-chat",
model_provider="deepseek",   # 自动使用 langchain-deepseek 的 ChatDeepSeek
temperature=0.7,             # 可选:随机性 0~2,越大越发散
max_tokens=2048,             # 可选:最大输出 token 数
)
# 不用写 api_key 和 base_url!
# ChatDeepSeek 默认 base_url 就是 api.deepseek.com,Key 自动从环境变量 DEEPSEEK_API_KEY 读

# ========== 2. 最基础用法:直接问一句话 ==========
resp = model.invoke("用一句话介绍你自己")
print("【直接问】", resp.content)

# ========== 3. 多轮对话:传消息列表 ==========
messages = [
SystemMessage(content="你是一个乐于助人的中文助手"),
HumanMessage(content="1+1等于几?"),
]
resp2 = model.invoke(messages)
print("【多轮对话】", resp2.content)

# ========== 方式一:bind() ------ 一次调用临时改参数 ==========
# 改 temperature(低=严谨,高=有创意)
r1 = model.bind(temperature=2).invoke(messages)
print("【bind 改 temperature】", r1.content)


# ========== 方式二:configurable_fields ------ 运行时可切换 ==========
configurable_model_2 = init_chat_model(
model="deepseek-chat",
model_provider="deepseek",
configurable_fields=("model", "model_provider", "temperature"),
)
r2 = configurable_model_2.invoke(messages, config={"configurable": {"temperature": 1}})
print("【configurable 改 temperature】", r2.content)

临时改参数两种方式对比

方式 用法 特点
bind() model.bind(temperature=2).invoke(...) 一次调用临时改参数,最直接
configurable_fields init_chat_model(..., configurable_fields=(...)) 运行时通过 config 切换,更灵活

五、聊天模型调用工具

工具调用 的根本作用是让大语言模型(LLM) 具备与外部世界交互的能力。LLM 本身是一个封闭的知识系统,其能力受限于训练数据 (存在滞后性)和内在的文本生成逻辑 。它无法执行直接计算、查询实时信息、操作数据库或调用任何外部 API。工具调用打破了这层壁垒,其作用具体体现在:

作用 说明
扩展能力边界 模型可借助工具完成自身无法完成的任务:数学计算、搜索网络、查询数据库
保证信息实时性 通过搜索/数据库工具获取训练数据中不存在的最新信息,避免回答过时或"一本正经地胡说八道"
处理复杂任务 将复杂请求(如"分析上个月消费趋势")分解成多步 ,依次调用不同工具协同完成(协调更体现在 Agent 智能体上)
连接现有系统 把企业内部系统、API、数据库封装成工具,让 LLM 成为自然语言驱动的统一接口
5.1 创建工具(@tool)

LangChain 中,实现了一个 @tool 装饰器来创建工具@tool 装饰器是自定义工具的最简单方法。

python 复制代码
from langchain_core.tools import tool

@tool(parse_docstring=True)
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'}}

可以看出,工具 通过 @toolPython 函数实现,其中:

  • 该装饰器默认使用函数名称 作为工具名称

  • 该装饰器将使用函数的文档字符串 作为工具的描述

因此,函数名类型提示文档字符串 都是传递给工具 Schema 的一部分,不可缺失。

认识 Schema :Schema(模式/架构)可以理解为一份数据的"蓝图"或"说明书" 。它不包含数据本身,而是定义和描述了数据的结构、格式和规范,确保数据在生产者和消费者之间能被正确理解和使用。

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响应。
   """
   # ... 函数实现 ...
5.1.1 依赖 Pydantic

若使用 @tool 定义工具时,没有提供文档字符串,则会报错 。此时,在 LangChain 中,可以使用 Pydantic 类,提供运行时数据验证类型检查 。通过 Field(description="...") 添加字段描述,LangChain 会自动提取(可以把 Args 部分删除)。

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")

# 定义工具
from langchain_core.tools import tool

@tool(args_schema=AddInput)
def add(a: int, b: int) -> int:
    return a + b
5.1.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

两种参数描述方式对比:

方式 写法 适用
Pydantic class XxxInput(BaseModel) + Field(description=...) + args_schema= 参数多、需要类型校验
Annotated Annotated[int, ..., "描述"] 直接内联 参数少、更简洁
5.2 创建工具(StructuredTool)

class langchain_core.tools.structured.StructuredTool 类用于初始化工具 ,其中 from_function 类方法通过给定的函数 来创建并返回一个工具

from_function 参数说明

参数 说明
func 要设置的工具函数
coroutine 协程函数 ,要设置的异步工具函数
name 工具名称 ,默认为函数名称
description 工具描述 ,默认为函数文档字符串
args_schema 工具输入参数的 Schema,默认为 None
response_format 工具响应格式,默认为 "content"

例子(正常)

python 复制代码
from langchain_core.tools import StructuredTool

def multiply(a: int, b: int) -> int:
    """Multiply two numbers."""
    return a * b

calculator_tool = StructuredTool.from_function(func=multiply)
print(calculator_tool.invoke({"a": 2, "b": 3}))  # 输出:6

例子(进阶:args_schema + description)

python 复制代码
from langchain_core.tools import StructuredTool
from pydantic import BaseModel, Field

class CalculatorInput(BaseModel):
    a: int = Field(description="first number")
    b: int = Field(description="second number")

def multiply(a: int, b: int) -> int:
    return a * b

calculator_tool = StructuredTool.from_function(
    func=multiply,                # 引用函数
    name="Calculator",            # 工具名
    description="两数相乘",        # 介绍功能
    args_schema=CalculatorInput,  # 介绍参数
)

print(calculator_tool.invoke({"a": 2, "b": 3}))  # 输出:6
print(calculator_tool.name)                      # 输出:Calculator
print(calculator_tool.description)               # 输出:两数相乘
print(calculator_tool.args)                      # 输出:{'a': {'description': 'first number', ...}, ...}
5.2.1 response_format

LangChain 中,如果希望工具区分消息内容(content) 和其他工件(artifact) ,可以通过将 response_format 设置为 "content_and_artifact" 来实现。这样,大模型 可以读取 content ,而一些用于构造 content原始数据 可以保存为 artifact ,便于后续记录、分析等步骤使用。artifact 通常使用字典(Dict)列表(List) 来保存。

字段 说明 例子
content 模型可读的结构化、简洁文本 "今天北京晴,气温在25°C到32°C之间。建议穿短袖衣物。"
artifact 构造 content 的原始数据(如 API 完整 JSON 响应) 搜索结果条目的标题、链接、摘要、排名等元数据
python 复制代码
# Artifact 的⽰例结构
{
   'results': [
       {
           'title': '北京天⽓预报 - 中国天⽓⽹',
           'link': 'https://weather.com.cn/...',
           'snippet': '北京今天⽩天晴,最⾼⽓温32°C,夜间晴,最低⽓温25°C...'
       },
       {
           'title': '北京实时天⽓ - Weather.com',
           'link': 'https://www.weather.com/...',
           'snippet': 'Bejing, China Weather. Mostly sunny. High 32C...'
       }
       # ... 更多结果
   ],
   'search_parameters': { ... },
   'search_information': { ... }
}

在定义工具 时,需要指定 response_format="content_and_artifact" 参数,并确保返回一个元组 (content, artifact)

python 复制代码
from langchain_core.tools import StructuredTool
from pydantic import BaseModel, Field
from typing import List, Tuple

class CalculatorInput(BaseModel):
    a: int = Field(description="first number")
    b: int = Field(description="second number")

def multiply(a: int, b: int) -> Tuple[str, List[int]]:
    nums = [a, b]
    content = f"{nums}相乘的结果是{a * b}"
    return content, nums

calculator_tool = StructuredTool.from_function(
    func=multiply,
    name="Calculator",
    description="两数相乘",
    args_schema=CalculatorInput,
    response_format="content_and_artifact"
)

print(calculator_tool.invoke({"a": 2, "b": 3}))  # 输出:('...相乘的结果是6', [2, 3])

为什么这样设计

  • LLM 主要理解文本 ,因此工具的主要输出 content 必须是结构良好、简洁的文本,便于模型推理和生成后续指令。

  • 链(Chain) 中,工具调用之后 的其他组件或函数,可能需要原始且结构化的数据 (即 artifact )来执行特定操作。这些数据可能庞大且非文本,不适合直接塞给模型。

  • artifact 是为链中后续组件或函数 使用的,不直接被大模型使用

5.3 绑定工具

为了实际将这些工具 绑定到聊天模型 ,可以使用聊天模型的 .bind_tools() 方法:

python 复制代码
# 绑定工具,返回一个 Runnable 实例
tools = [add, multiply]
model_with_tools = model.bind_tools(tools)

参数说明

参数 说明
tools 绑定到聊天模型的工具定义列表 ,支持:字典pydantic.BaseModel 类、Python 函数BaseTool (如 @tool 创建的类)
tool_choice(默认空) 要求模型调用哪个工具,见下表
strict(默认空) True 保证模型输出与 JSON Schema 完全匹配False 不验证;None 不传递该参数
parallel_tool_calls(默认 None) 允许并行工具调用 ;设为 False 可禁用
kwargs(Any) 附加参数,直接传递给 bind()

tool_choice 取值

行为
'<<tool_name>>' 调用指定的工具
'auto' 自动选择工具(包括无工具
'none' 不调用工具
'any' / 'required' / True 强制调用至少一个工具
False / None 无效果,使用模型默认行为

返回值 :返回一个 Runnable 实例。

  • 该实例支持多种格式输入 :原始提示 PromptValue字符串 (如 "上海天气如何?")、消息或消息列表

  • 该实例的输出 :一个 AIMessage 对象,其中包含工具调用信息

5.3.1 工具调用
python 复制代码
import os
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="deepseek-chat",
    api_key=os.getenv("DEEPSEEK_API_KEY"),
    base_url="https://api.deepseek.com"
)

@tool
def add(a: int, b: int) -> int:
    """Add two integers.

    Args:
         a: First integer
         b: Second integer
    """
    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)

输出说明AIMessage 来自 AI 的消息,从聊天模型返回,作为对提示(输入) 的响应。其中:

  • content :消息的内容

  • additional_kwargs :与消息关联的其他有效载荷数据 ,可能包含模型提供商编码的工具调用

  • response_metadata响应元数据,例如响应头、logprobs、令牌计数、模型名称等。

注意工具调用的关键原则是模型根据输入的相关性决定何时使用工具 ,模型并不总是需要调用工具。例如,给定一个不相关的输入,模型不会调用该工具:

python 复制代码
result = model_with_tools.invoke("hello world!")
print(result)
5.3.2 强制模型调用工具

我们也可以强制模型调用工具 ,在绑定工具时设置 tool_choice="any" ,表示强制调用至少一个工具

cpp 复制代码
model_with_tools = model.bind_tools(tools, tool_choice="any")
result = model_with_tools.invoke("hello world!")
print(result)
5.3.3 工具属性

现在我们知道,输出结果是一个 AIMessage 。但是,如果调用了工具 ,则 result 将具有一个 tool_calls 属性。此属性包括执行该工具所需的一切,包括工具名称输入参数

python 复制代码
# 绑定工具
tools = [add, multiply]
model_with_tools = model.bind_tools(tools, tool_choice="any")
# 调用工具
result = model_with_tools.invoke("9加6等于多少?")
print(result.tool_calls)
5.3.4 将工具输出传递给聊天模型

到这里可以发现,我们仅仅只是成功调用了工具 ,但聊天模型 并没有返回我们真正需要的答案。此时需要:

  1. 将工具输出传递给聊天模型 ,包括 HumanMessageAIMessage(工具调用)

  2. 聊天模型 根据以上消息列表 输入,将最终结果以 AIMessage 返回。

为什么要发 ToolMessage 呢? 之前讲过,聊天模型通常不是 接受单个字符串作为输入,而是接受聊天消息(XxxMessage)列表 。因此我们需要将工具的返回结果构造成 ToolMessage ,再传输给聊天模型。方便的是 ,如果我们使用 @tool 装饰器创建的工具 ,调用 tool.invoke(tool_calls)自动返回一个 ToolMessage

python 复制代码
import os
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage
from langchain_core.tools import tool

# 1. 初始化模型
model = ChatOpenAI(
    model="deepseek-chat",
    api_key=os.getenv("DEEPSEEK_API_KEY"),   # Key 从环境变量读
    base_url="https://api.deepseek.com",     # DeepSeek 接口地址,必须指定
)

# 2. 定义工具
@tool
def add(a: int, b: int) -> int:
    """Add two integers."""  # docstring 第一行 = 工具描述
    return a + b

@tool
def multiply(a: int, b: int) -> int:
    """Multiply two integers."""
    return a * b

# 3. 绑定工具
model_with_tools = model.bind_tools([add, multiply])

# 4. 第一轮:模型决定是否调用工具
messages = [HumanMessage("9乘6等于多少?5加3等于多少?")]  # 对话历史
ai_message = model_with_tools.invoke(messages)             # 模型返回:直接回答 或 工具申请单
messages.append(ai_message)                                # 回复加入历史

# 5. 执行模型请求的工具
for tool_call in ai_message.tool_calls:
    tool_message = {"add": add, "multiply": multiply}[tool_call["name"]].invoke(tool_call)
    messages.append(tool_message)                          # 工具结果回传

# 6. 模型给出最终答案
result = model.invoke(messages)
print(result.content)

工具调用完整流程总结

步骤 动作
① 绑定工具 model.bind_tools([add, multiply])
② 模型决策 模型返回直接回答,或带有 tool_calls 的 AIMessage(工具申请单)
③ 执行工具 tool_calls 调用对应工具,得到 ToolMessage
④ 回传结果 把 ToolMessage 追加进消息列表
⑤ 模型作答 模型根据完整消息列表给出最终答案

六、复盘(附答案)

💡 思考题

  1. LangChain 中 SystemMessage、HumanMessage、AIMessage、ToolMessage 分别代表什么角色?为什么工具结果要构造成 ToolMessage 回传?

  2. Runnable 接口是什么?它解决了原生大模型的什么问题?

  3. LCEL 的 chain = model | parser 是如何工作的?chain.invoke(messages) 发生了什么?

  4. 创建工具有哪几种方式?各有什么特点?

  5. 工具调用的完整流程分几步?为什么说"模型并不总是需要调用工具"?

📝 答案

  1. SystemMessage (系统角色):消息序列第一条,启动 AI 行为HumanMessage (用户角色):用户传给模型的输入;AIMessage (AI 角色):聊天模型返回的回答(含工具调用信息 tool_calls);ToolMessage (工具角色):工具执行后返回的结果。因为聊天模型接受的是"消息列表"而不是单个字符串,所以必须把工具结果构造成 ToolMessage 再回传给模型,模型才能据此给出最终答案。

  2. Runnable 是 LangChain 组件的统一标准接口 ,支持调用(invoke)、批处理(batch)、流式(stream)、检查(inspect)、组合(compose)五种能力。它解决了"切换大模型困难"的问题------模型、解析器、链都实现同一标准接口,换模型不会引发连锁反应。

  3. chain = model | parser 用 LCEL 构建了一条 RunnableSequencechain.invoke(messages) 时:上一个组件的输出作为下一个组件的输入------模型先对消息生成 AIMessage,解析器再把结果解析为字符串,一次性得到最终结果。

  4. 四种方式:@tool 装饰器 (最简单,函数名=工具名,文档字符串=描述);@tool + Pydantic (用 args_schema 提供参数描述与类型校验,适合没文档字符串时);@tool + Annotated (在参数上内联描述,更简洁);StructuredTool.from_function(面向对象式,可显式指定 name/description/args_schema/response_format)。

  5. 五步:绑定工具 (bind_tools)→ 模型决策 (返回直接回答或带 tool_calls 的 AIMessage)→ 执行工具 (按 tool_calls 调用,得到 ToolMessage)→ 回传结果 (追加进消息列表)→ 模型作答因为工具调用应由模型"按输入相关性"自主决定------不相关的输入(如"hello world")就不该调用工具,强制调用(tool_choice="any")只是可选手段。


🎯 闭幕

从"定义大模型"到"Runnable 与 LCEL",从"聊天模型"到"工具调用"------这一篇帮你把 LangChain 的入门实战走了一遍。

如果本文对你有帮助,欢迎:

👍 点赞 | ⭐ 收藏 | 👤 关注作者 | 💬 留言交流你的疑问或补充

你的每一次互动都是我继续更新的动力,我们下一篇见!🚀

相关推荐
月华路1 小时前
《模型不玄学》第16章 概率校准
人工智能·深度学习·机器学习
临沂GEO1 小时前
用好地域流量,提升内容自然搜索曝光
网络·python
艾莉丝努力练剑2 小时前
【AI大模型接入SDK】ChatGPT API
网络·c++·人工智能·websocket·网络协议·学习·chatgpt
枫叶林FYL3 小时前
【群体智能集群控制工程实践】第8章 无人机蜂群测试与部署
人工智能·无人机
andrsted6 小时前
用练题簿小程序 - 让错题不再白错
学习·微信小程序·小程序·学习方法
2601_949950636 小时前
练题簿,把培训从“走过场”变成“真落地”
人工智能·学习·小程序·刷题·小程序推荐
诸神缄默不语8 小时前
备战 AI 出海 DAY 0:海外数据采集
大数据·人工智能
Ysn07199 小时前
YOLO-Master工程:experts.py 专家结构详解与目标检测专家设计启发
人工智能·yolo·目标检测
BingoGo9 小时前
使用 GPT-6 Astra 模型 请立刻更新你的 Skill 与提示词
人工智能