第2章 Model I/O

一、Model I/O 介绍

Model I/O 部分是与语言模型进行交互的核心组件,包括输入提示(Prompt Template)、调用模型(Model)、输出解析(Output Parser)。简单来说,就是输入、处理、输出这三个步骤。

二、调用在线模型

2.1 大模型服务平台

LangChain作为一个“工具”,依赖于第三方集成各种大模型。有许多提供大模型API服务的平台,使用时只需要注册、充值并创建API-Key,之后即可使用API-Key与URL来调用平台提供的相应的模型的服务。

1)CloseAI:https://platform.closeai-asia.com/

2)OpenRouter:https://openrouter.ai/

3)阿里云百炼:https://bailian.console.aliyun.com/

4)百度千帆:https://console.bce.baidu.com/qianfan/overview

5)硅基流动:https://www.siliconflow.cn/

2.2 OpenAI SDK 调用模型

OpenAI 的 GPT 系列模型影响了大模型技术发展的开发范式和标准。所以无论是 Qwen、ChatGLM 等模型,它们的使用方法和函数调用逻辑基本遵循 OpenAI 定义的规范,没有太大差异。这就使得能够通过一个较为通用的接口来接入和使用不同的模型。

# pip install langchain langchain-openai
from openai import OpenAI

client = OpenAI(
    base_url="https://openrouter.ai/api/v1",  # 平台提供的 URL
    api_key="sk-...",  # 平台提供的 API-Key
)

completion = client.chat.completions.create(
    model="openai/gpt-oss-20b:free",  # 模型名称
    messages=[{"role": "user", "content": "将'你好'翻译成意大利语"}],  # 用户输入
)
print(completion.choices[0].message.content)

案例:以硅基流动为例

from openai import OpenAI

# 创建 OpenAI 客户端
client = OpenAI(
    api_key="sk-vr",
    base_url="https://api.siliconflow.cn/v1"
)

completion = client.chat.completions.create(
    model="Qwen/Qwen3-8B",  # 模型名称
    messages=[{"role": "user", "content": "请将下面内容翻译成英文:\n\n今天北京的苹果价格怎么样?"}],  # 问题
)

# 获取结果并打印
print(completion.choices[0].message.content)

2.3 API-Key 管理

通常有3种方式来管理API-Key:硬编码、写入.env文件、写入环境变量。

前面我们就是将 API-Key 硬编码仅代码中,这仅适用于临时测试,存在密钥泄露风险。

2.3.1.使用 .env 配置文件

使用 python-dotenv 加载本地配置文件,支持多环境管理。该方式有以下优势:

  • 配置文件可加入 .gitignore 避免泄露
  • 支持多环境配置(如 .env.prod 和 .env.dev)
  • 创建 .env 文件(项目根目录):
OPENAI_API_KEY="sk-…"
OPENAI_BASE_URL="https://api.siliconflow.cn/v1"

举例:显式读取 .env 中的环境变量

# pip install python-dotenv
import os
import dotenv
from openai import OpenAI

# 加载环境变量, 默认加载 .env 文件
dotenv.load_dotenv()

# 创建 OpenAI 客户端
client = OpenAI(
    api_key=os.getenv("OPENAI_API_KEY"),
    base_url=os.getenv("OPENAI_BASE_URL")
)

completion = client.chat.completions.create(
    model="Qwen/Qwen3-8B",  # 模型名称
    messages=[{"role": "user", "content": "请将下面内容翻译成英文:\n\n今天北京的苹果价格怎么样?"}],  # 问题
)

# 获取结果并打印
print(completion.choices[0].message.content)

举例:依靠 OpenAI 的默认行为读取 .env 环境变量

OpenAI 在创建时,会自动到环境变量中找 OPENAI_API_KEY 以及OPENAI_BASE_URL。如果在 .env 中配置的名字和上面的两个名字一样,无需再次赋值,只通过 dotenv.load_dotenv() 加载环境配置信息即可。

# pip install python-dotenv
import dotenv
from openai import OpenAI

# 加载环境变量, 默认加载 .env 文件
dotenv.load_dotenv()

# 创建 OpenAI 客户端
client = OpenAI() # 使用默认 .env 的 API 密钥

completion = client.chat.completions.create(
    model="Qwen/Qwen3-8B",  # 模型名称
    messages=[{"role": "user", "content": "请将下面内容翻译成英文:\n\n今天北京的苹果价格怎么样?"}],  # 问题
)

# 获取结果并打印
print(completion.choices[0].message.content)

2.3.2.在环境变量中配置

通过系统环境变量存储 API-Key,避免代码明文暴露。

终端设置变量(临时生效):

export OPENAI_API_KEY="sk-…"  # Linux/Mac
set OPENAI_API_KEY="sk-…"    # Windows CMD

在代码中通过 os.getenv() 读取API-Key:

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://openrouter.ai/api/v1",
    api_key=os.getenv("OPENAI_API_KEY"),
)

completion = client.chat.completions.create(
    model="openai/gpt-oss-20b:free",
    messages=[{"role": "user", "content": "你好"}],
)
print(completion.choices[0].message.content)

2.4 LangChain API 调用模型

初始化一个模型最简单的方法就是使用 init_chat_model,并设置必要的参数,例如 API-Key 和模型名称。除此之外还有一些其他参数。

参数

说明

model

模型名称或标识符

base_url

发送请求的 API 端点的 URL。常由模型的提供商提供

api_key

与模型提供商进行身份验证所需的 API 密钥

temperature

控制模型输出的随机性。数字越高,回答越有创意;数字越低,回答越确定,

timeout

在取消请求之前,等待模型响应的最大时间(以秒为单位)

max_tokens

限制响应中的总tokens 数量,控制输出长度

max_retries

请求失败时系统尝试重新发送请求的最大次数

通常通过聊天模型接口访问 LLM,该接口通常以消息列表作为输入并返回一条消息作为输出。

  • 输入:接受文本 PromptValue 或消息列表 List[BaseMessage],每条消息需指定角色(如 SystemMessage、HumanMessage、AIMessage)
  • 输出:返回带角色的消息对象(BaseMessage 子类),通常是 AIMessage
import os
import dotenv
from langchain.chat_models import init_chat_model
from langchain_core.messages import SystemMessage, HumanMessage

dotenv.load_dotenv()

llm = init_chat_model(
    model="Qwen/Qwen3-8B",
    model_provider="openai", # 可选, 默认为 openai,
    base_url=os.getenv("QWEN_BASE_URL"),
    api_key=os.getenv("QWEN_API_KEY"),
)

message = [
    SystemMessage(content="你是一个诗人"),  # 系统提示
    HumanMessage(content="写一首关于夏天的诗")  # 用户问题
]

resp = llm.invoke(message)
print(type(resp))  # <class 'langchain_core.messages.ai.AIMessage'>
print(resp.content)

Token是什么?

大模型处理的最小单位是 token(相当于自然语言中的词或字),输出时逐个 token 依次生成。模型提供商通常也是以 token 的数量作为其计量或收费的依据。1个中文Token≈1-1.8个汉字,1个英文Token≈3-4字母。

Token与字符转化的可视化工具:

2.5.RateLimit 模型速率限制器 和  .with_retry()模型重试机制

2.5.1.RateLimit 模型速率限制器

LangChain 提供的RateLimit 模型速率限制器,作用是在请求发出之前,就在本地代码层面主动控制调用频率,防止因请求过快:

mport os
import dotenv
from langchain.chat_models import init_chat_model
from langchain_core.rate_limiters import InMemoryRateLimiter

dotenv.load_dotenv()

rate_limiter = InMemoryRateLimiter(
    requests_per_second=5,  # 每秒最多5个请求数
    check_every_n_seconds=1,  # 每1秒检查一次是否超过速率限制,(导致请求最多额外等待 1 秒)
    max_bucket_size=10,   # 桶容量 10 个(闲置 2 秒即可攒满),允许程序启动时瞬间爆发 10 个请求,允许你把“攒了 2秒的力气”在一瞬间全部打出去。适合批量处理积压的小任务
)

llm = init_chat_model(
    model="deepseek-v4-pro",
    model_provider='deepseek',
    base_url="https://api.deepseek.com",
    api_key=os.getenv('api_key'),
    temperature=0.7,
    max_tokens=10000,
    rate_limiter=rate_limiter,  # 使用速率限制器
)


resp = llm.invoke("请你说明你如何使用 LangChain?")
print(resp.content)

输出:

image

2.5.2. .with_retry()模型重试机制

使用重试机制:通过 .with_retry() 方法为模型调用添加指数退避重试策略,在遇到临时性故障(如速率限制错误)时自动重试
指数退避的等待时间:

  • 1s → 2s → 4s → 8s → 16s → …
  • 每次失败都指数增加等待时间,避免快速重复打爆 API。

抖动 = 在等待时间上随机增加/减少一点随机数

  • 防止集群中的多个客户端在相同时间重复同时回退,造成更大拥堵
  • 失败的请求不会同时发起,极大降低 API 或本地模型的压力。
# 使用重试机制
model = llm.with_retry(
    stop_after_attempt=3,  # 最多重试 3 次
    wait_exponential_jitter=True,  # 使用指数退避 + 随机抖动
)

2.6.init_embeddings() 

init_embeddings可以根据模型名称和模型供应商提供者初始化嵌入模型。

import os
import dotenv

# 1.使用init_embeddings初始化embedding
from langchain.embeddings import init_embeddings

dotenv.load_dotenv()
# 2.初始化嵌入模型:bge-m3
embedding = init_embeddings(
    model="bge-m3",
    provider="openai",
    api_key=os.getenv("VLLM_EMBEDDING_API_KEY"),
    openai_api_base=os.getenv("VLLM_EMBEDDING_BASE_URL"),
)

# 3.将文本转换为向量表示
resp = embedding.embed_query("如何使用 LangChain?")
print(resp)

输出

image

2.7.对话模型的 Message

对话模型的输入可以是文本提示、消息提示或是字典格式。

1)文本提示

文本提示是字符串,适用于不需要保留对话历史的直接生成任务。

resp = llm.invoke("你好")

2)消息提示

将消息对象列表输入模型,方便管理对话历史,包含系统指令以及处理多模态数据。

message = [
    SystemMessage(content="你是一个诗人"),  # 系统提示
    HumanMessage(content="写一首关于夏天的诗")  # 用户问题
]

resp = llm.invoke(message)

3)字典格式

也可以按照 OpenAI 聊天补全格式创建字典列表组成消息。一条消息通常包含 role(角色)、content(内容)、metadata(元数据)。

message = [
    {"role": "system", "content": "你是一个诗人"},
    {"role": "user", "content": "写一首关于夏天的诗"}
]

resp = llm.invoke(message)

4)消息类型

消息类型

描述

SystemMessage

代表一组初始指令,用于引导模型的行为。可以使用系统消息来设定语气、定义模型的角色,并建立响应的指导方针

HumanMessage

表示用户输入

AIMessage

模型生成的响应,包括文本内容、工具调用和元数据

ToolMessage

表示工具调用的输出

HumanMessage、AIMessage 和 SystemMessage 是常用的消息类型。

ToolMessage 是在工具调用场景下才会使用的特殊消息类型。

2.8.调用方法

聊天模型提供了三种主要的调用方法:

invoke / ainvoke

将单个输入转换为输出

batch / abatch

批量将多个输入转换为输出

stream / astream

从单个输入生成流式输出

带有“a”前缀的方法是异步的,需要与 asyncio 和 await 语法一起使用以实现并发。

2.7.1 非流式/流式输出

在Langchain中,语言模型的输出分为了两种主要的模式:流式输出非流式输出

  • 非流式输出:用户提出需求请编写一首诗,系统在静默数秒后突然弹出了完整的诗歌。如同一种“提交请求,等待结果”的流程,实现简单,但体验单调。
  • 流式输出:用户提问,请编写一首诗,当问题刚刚发送,系统就开始一字一句(逐个token)进行回复,更像是“实时对话”,贴近人类交互的习惯。
1)非流式输出:

这是 LangChain 与 LLM 交互时的默认行为,是最简单、最稳定的语言模型调用方式。当用户发出请求后,系统在后台等待模型生成完整响应,然后一次性将全部结果返回。

举例:invoke() 调用

import os
import dotenv
from langchain.chat_models import init_chat_model
from langchain_core.messages import SystemMessage, HumanMessage

dotenv.load_dotenv()

llm = init_chat_model(
    model="Qwen/Qwen3-8B",
    model_provider="openai", # 可选, 默认为 openai,
    base_url=os.getenv("QWEN_BASE_URL"),
    api_key=os.getenv("QWEN_API_KEY"),
    temperature=0.7,
)

message = [
    {"role": "system", "content": "你是一个诗人"},
    {"role": "user", "content": "写一首关于夏天的诗"}
]

resp = llm.invoke(message)
print(type(resp))  # <class 'langchain_core.messages.ai.AIMessage'>
print(resp)
2)流式输出

流式输出是一种更具交互感的模型输出方式,用户不再需要等待完整答案,而是能看到模型逐个 token地实时返回内容。适合构建强调“实时反馈”的应用。

举例:stream() 流式输出

import os
import dotenv
from langchain.chat_models import init_chat_model
dotenv.load_dotenv()

llm = init_chat_model(
    model="Qwen/Qwen3-8B",
    model_provider="openai", # 可选, 默认为 openai,
    base_url=os.getenv("QWEN_BASE_URL"),
    api_key=os.getenv("QWEN_API_KEY"),
    temperature=0.7,
)

message = [
    {"role": "system", "content": "你是一个诗人"},
    {"role": "user", "content": "写一首关于夏天的诗"}
]

# stream()流式方法输出
for chunk in llm.stream(message):
    # 逐个打印内容块,并刷新缓冲区让即时显示内容
    print(chunk.content, end="", flush=True)

2.7.2 批量调用

将一组独立的请求批量发送给模型并行处理。

举例:batch() 批量调用

import os
import dotenv
from langchain.chat_models import init_chat_model

dotenv.load_dotenv()

llm = init_chat_model(
    model="Qwen/Qwen3-8B",
    model_provider="openai", # 可选, 默认为 openai,
    base_url=os.getenv("QWEN_BASE_URL"),
    api_key=os.getenv("QWEN_API_KEY"),
    temperature=0.7,
)

message = [
    [{"role": "system", "content": "你是一个诗人"},{"role": "user", "content": "写一首关于春天的诗"}],
    [{"role": "system", "content": "你是一个诗人"},{"role": "user", "content": "写一首关于夏天的诗"}],
    [{"role": "system", "content": "你是一个诗人"},{"role": "user", "content": "写一首关于秋天的诗"}],
    [{"role": "system", "content": "你是一个诗人"},{"role": "user", "content": "写一首关于冬天的诗"}]
]

resp = llm.batch(message) # 批量调用,返回的结果是一个列表,每个元素是一个AIMessage对象
# 逐个打印结果
for i, item in enumerate(resp):
    print(f"第 {i} 个结果:")
    print(item.content)
    print("+++++++++++++++++++++++++++++++++++++++++++++++++++++")

batch 默认没有依赖底层 API 的原生批量接口,而是使用线程池并行执行多个 invoke()。所以它对 IO 密集型任务(如调用远程 LLM API)很有效。

如果底层 API 自身提供批量接口(一次请求多个 prompt),那么子类可以重写 batch 方法来直接使用批量接口,这样效率会更高。

2.7.3 同步/异步调用

1)同步调用

每个操作依次执行,直到当前操作完成后才开始下一个操作,总的执行时间是各个操作时间的总和。

举例:使用 invoke() 同步调用

import os
import time

import dotenv
from langchain.chat_models import init_chat_model

dotenv.load_dotenv()

llm = init_chat_model(
    model="Qwen/Qwen3-8B",
    model_provider="openai", # 可选, 默认为 openai,
    base_url=os.getenv("QWEN_BASE_URL"),
    api_key=os.getenv("QWEN_API_KEY")
)

messages = [
    [{"role": "system", "content": "你是一个诗人"},{"role": "user", "content": "写一首关于春天的诗"}],
    [{"role": "system", "content": "你是一个诗人"},{"role": "user", "content": "写一首关于夏天的诗"}],
    [{"role": "system", "content": "你是一个诗人"},{"role": "user", "content": "写一首关于秋天的诗"}],
    [{"role": "system", "content": "你是一个诗人"},{"role": "user", "content": "写一首关于冬天的诗"}]
]

start_time = time.time()

resp = [llm.invoke(message) for message in messages]
print(resp)
end_time = time.time()

# 总耗时: 27.14240789413452
print("总耗时:", end_time - start_time) 
2)异步调用

异步调用,允许程序在等待某些操作完成时继续执行其他任务,而不是阻塞等待。这在处理 I/O 操作(如网络请求、文件读写等)时特别有用,可以显著提高程序的效率和响应性。

举例:使用 ainvoke() 异步调用

import asyncio
import os
import dotenv
from langchain.chat_models import init_chat_model

dotenv.load_dotenv()

llm = init_chat_model(
    model="Qwen/Qwen3-8B",
    model_provider="openai",  # 可选, 默认为 openai,
    base_url=os.getenv("QWEN_BASE_URL"),
    api_key=os.getenv("QWEN_API_KEY")
)

messages = [
    [{"role": "system", "content": "你是一个诗人"}, {"role": "user", "content": "写一首关于春天的诗"}],
    [{"role": "system", "content": "你是一个诗人"}, {"role": "user", "content": "写一首关于夏天的诗"}],
    [{"role": "system", "content": "你是一个诗人"}, {"role": "user", "content": "写一首关于秋天的诗"}],
    [{"role": "system", "content": "你是一个诗人"}, {"role": "user", "content": "写一首关于冬天的诗"}]
]


async def async_invoke():
    resp = [llm.ainvoke(message) for message in messages]
    return await asyncio.gather(*resp)  # 使用 asyncio.gather(), 等待所有任务完成

if __name__ == '__main__':
    result = asyncio.run(async_invoke())
    for i, item in enumerate(result):
        print(f"第 {i} 个结果:")
        print(item.content)
        print("+++++++++++++++++++++++++++++++++++++++++++++++++++++")

使用 asyncio.gather() 并行执行时,因为多个任务几乎同时开始,它们的执行时间将重叠。理想情况下,如果多个任务的执行时间相同,那么总执行时间应该接近单个任务的执行时间。

三、调用本地模型

3.1 Ollama介绍

Ollama是一个开源项目,其项目定位是:一个本地运行大模型的集成框架。目前主要针对主流的LlaMA架构的开源大模型设计,可以实现如 Qwen、Deepseek 等主流大模型的下载、启动和本地运行的自动化部署及推理流程。

目前作为一个非常热门的大模型托管平台,已被包括LangChain、Taskweaver等在内的多个热门项目高度集成。

3.2 Ollama安装

Ollama项目支持跨平台部署,目前已兼容Mac、Linux和Windows操作系统。

image

无论使用哪个操作系统,Ollama项目的安装过程都设计得非常简单。

访问 https://ollama.com/download 下载对应系统的安装文件。

  • Windows 系统执行.exe文件安装
  • Linux 系统执行以下命令安装:
curl -fsSL https://ollama.com/install.sh | sh

这行命令的目的是从https://ollama.com/ 网站读取 install.sh脚本,并立即通过 sh 执行该脚本,在安装过程中会包含以下几个主要的操作:

  • 检查当前服务器的基础环境,如系统版本等;
  • 下载Ollama的二进制文件;
  • 配置系统服务,包括创建用户和用户组,添加Ollama的配置信息;
  • 启动Ollama服务;

3.3 模型下载

访问https://ollama.com/search可以查看Ollama支持的模型。使用命令行可以下载并运行模型,例如运行deepseek-r1:7b模型:

ollama run qwen3:8b

1)进入到Settings,可以切换模型目录

image

2)运行模型 ollama run qwen3:8b

当前模型如果不存在,可以联网下载

ollama run qwen3:8b

3)Ollama 常用命令说明

基础命令

  • ollama run <model>: 运行指定模型
  • ollama list: 列出已下载的模型
  • ollama pull <model>: 下载模型
  • ollama push <model>: 上传模型
  • ollama rm <model>: 删除本地模型

模型管理

  • ollama create <model> -f <modelfile>: 从 Modelfile 创建模型
  • ollama show <model>: 显示模型信息
  • ollama cp <source> <destination>: 复制模型

服务管理

  • ollama serve: 启动Ollama服务
  • ollama stop: 停止Ollama服务
  • ollama status: 查看服务状态

其他命令

  • ollama help: 显示帮助信息
  • ollama version: 显示版本信息

3.4 调用本地模型

举例:

# pip install langchain-ollama
from langchain_ollama import ChatOllama

ollama_llm = ChatOllama(
    model="qwen3:8b"
)
messages = {"role": "user", "content": "你好,请介绍一下你自己"}
resp = ollama_llm.invoke([messages])
print(resp.content)

若 Ollama 不在本地默认端口运行,需指定 base_url,即:

# pip install langchain-ollama
from langchain_ollama import ChatOllama

ollama_llm = ChatOllama(
    model="qwen3:8b",
    base_url="http://192.168.130.154:11434",  # 自定义地址
)
messages = {"role": "user", "content": "你好,请介绍一下你自己"}
resp = ollama_llm.invoke([messages])
print(resp.content)

四、Prompt Template

4.1 提示词模板介绍

在应用开发中,固定的提示词限制了模型的灵活性和适用范围。所以,PromptTemplate 是一个模板化的字符串,我们可以将变量插入到模板中,从而创建出不同的提示。PromptTemplate 接收用户输入,返回一个传递给LLM的信息(即提示词 prompt)。

提示模板以字典作为输入,其中每个键代表要填充的提示模板中的变量。并输出一个 PromptValue。这个 PromptValue 可以传递给聊天模型,也可以转换为字符串或消息列表。PromptValue 存在的目的是为了方便在字符串和消息之间切换。

有多种类型的提示模板,常用的有 PromptTemplate(字符串提示模板)和 ChatPromptTemplate(聊天提示模板)。

4.2 PromptTemplate

PromptTemplate 用于快速构建包含变量的提示词模板,并通过传入不同的参数值生成自定义的提示词。

参数

template

提示模板,包括变量占位符

input_variables

需要将其值作为提示输入的变量名称列表

partial_variables

提示模板携带的部分变量的字典。使用部分变量预先填充模板,无需后续在每次调用时再传递这些变量

方法

format()

使用输入格式化提示

4.2.1 实例化

方式1:使用构造方法实例化提示词模板

from langchain_core.prompts import PromptTemplate

template = PromptTemplate(
     template="请评价{product}的优缺点,包含{aspect1}和{aspect2}",
     input_variables=["product", "aspect1", "aspect2"],
)
# 使用模版生成提示词
prompt1 = template.format(product="手机", aspect1="续航", aspect2="拍照")
prompt2 = template.format(product="笔记本电脑", aspect1="性能", aspect2="便携性")
print(prompt1)
print(prompt2)

输出:

请评价手机的优缺点,包含续航和拍照
请评价笔记本电脑的优缺点,包含性能和便携性

方式2:使用 from_template 方法实例化提示词模板

from langchain_core.prompts import PromptTemplate


# 使用from_template方法创建模版
template = PromptTemplate.from_template("请给我一个关于{product}的评价,包含{aspect1}和{aspect2}")
# 使用模版生成提示词
prompt = template.format(product="手机", aspect1="续航", aspect2="拍照")
print(prompt)

输出:

请给我一个关于手机的评价,包含续航和拍照

4.2.2 部分提示模版

在生成提示之前可以赋予部分变量默认值。

  • 方式1:实例化过程中指定 partial_variables 参数
from langchain_core.prompts import PromptTemplate

template = PromptTemplate(
    template="请给我一个关于{product}的评价,包含{aspect1}和{aspect2}",
    input_variables=["product", "aspect1", "aspect2"],
    partial_variables={"aspect1": "价格", "aspect2": "性能"},  # 指定变量aspect1、aspect2的默认值
)

prompt = template.format(product="手机")  # 使用模版生成提示词, aspect1和aspect2的会使用之前的默认值
print(prompt) # 请给我一个关于手机的评价,包含系统和拍照
  • 方式2:使用 partial 方法指定默认值
from langchain_core.prompts import PromptTemplate

# 使用from_template方法创建模版
template = PromptTemplate.from_template("请给我一个关于{product}的评价,包含{aspect1}和{aspect2}")
# 预先定义部分变量的默认值
partial_template = template.partial(product="手机")
# 使用模版生成提示词
prompt = partial_template.format(aspect1="续航", aspect2="拍照")
print(prompt)  # 请给我一个关于手机的评价,包含续航和拍照

4.2.3 调用方式

除了 format 方法,也可以使用 invoke 方法调用。

invoke 方法返回 PromptValue 对象,可以使用 to_string 方法将其转换为字符串。

举例:invoke 方法调用

from langchain_core.prompts import PromptTemplate

# 使用from_template方法创建模版
template = PromptTemplate.from_template("请给我一个关于{product}的评价,包含{aspect1}和{aspect2}")
# 预先定义部分变量的默认值
partial_template = template.partial(product="手机")
# 使用模版生成提示词
prompt = partial_template.invoke({"aspect1": "续航", "aspect2":"拍照"})
print(prompt)  # 请给我一个关于手机的评价,包含续航和拍照

print(prompt, type(prompt))
# text='请给我一个关于手机的评价,包含续航和拍照' <class 'langchain_core.prompt_values.StringPromptValue'>

prompt_str = prompt.to_string()
print(prompt_str, type(prompt_str))
# 请给我一个关于手机的评价,包含续航和拍照 <class 'str'>

4.3 ChatPromptTemplate

ChatPromptTemplate是创建聊天消息列表的提示模板。相较于普通 PromptTemplate更适合处理多角色、多轮次的对话场景。支持 System/Human/AI 等不同角色的消息模板。

4.3.1 实例化

ChatPromptTemplate 可以通过构造方法或 from_messages 方法来实例化提示词模板。

实例化时需要传入 messages 参数,messages 参数支持如下格式:

  • tuple 构成的列表,格式为[(role, content)]
  • dict 构成的列表,格式为[{“role”:... , “content”:...}]
  • Message 类构成的列表

举例:

from langchain_core.prompts import ChatPromptTemplate

template = ChatPromptTemplate(
    [
        ("system", "你是一个AI智能体开发工程师,你叫{name},你正在开发一个智能助手,请使用中文回答问题。"),
        ("human", "你能帮我做什么呢?"),
        ("ai", "我能开发{thing}。"),
        ("human", "我需要开发一个{user_input},请给我一些建议。"),
    ]
)
# 使用format_messages方法生成提示
prompt = template.format_messages(name="深瞳", thing="Agent", user_input="查询农业信息的智能助手")

输出:

[
SystemMessage(content='你是一个AI智能体开发工程师,你叫深瞳,你正在开发一个智能助手,请使用中文回答问题。', additional_kwargs={}, response_metadata={}), 
HumanMessage(content='你能帮我做什么呢?', additional_kwargs={}, response_metadata={}), 
AIMessage(content='我能开发Agent。', additional_kwargs={}, response_metadata={}), HumanMessage(content='我需要开发一个查询农业信息的智能助手,请给我一些建议。', additional_kwargs={}, response_metadata={})
]

4.3.2 调用方式

推荐使用 from_messages 方法或 invoke 方法调用。

举例:invoke 方法调用

from langchain_core.prompts import ChatPromptTemplate

template = ChatPromptTemplate(
    [
        ("system", "你是一个AI智能体开发工程师,你叫{name},你正在开发一个智能助手,请使用中文回答问题。"),
        ("human", "你能帮我做什么呢?"),
        ("ai", "我能开发{thing}。"),
        ("human", "我需要开发一个{user_input},请给我一些建议。"),
    ]
)
# 使用invoke方法生成提示
prompt = template.invoke({"name":"深瞳", "thing":"Agent", "user_input":"查询农业信息的智能助手"})

print(prompt)

4.3.3 消息占位符

当希望在格式化过程中插入消息列表时,比如 Agent 暂存中间步骤,需要使用 MessagesPlaceholder,负责在特定位置添加消息列表。

举例:

from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

# 使用from_messages方法创建模版
template = ChatPromptTemplate.from_messages(
    [
        ("system", "你是一个AI智能体开发工程师,你正在开发一个智能助手,请使用中文回答问题。"),
        ("placeholder", "{conversation}")
        # 等同于 MessagesPlaceholder(variable_name="conversation", optional=True),
    ]
)

# 使用format_messages方法生成提示
prompt = template.format_messages(conversation=[
    ("human", "你能帮我做什么呢?"),
    ("ai", "我能开发Agent智能体"),
    ("human", "我需要开发一个关于智能客服的智能体,请给我一些建议。"),
])
print(prompt)

[
SystemMessage(content='你是一个AI智能体开发工程师,你正在开发一个智能助手,请使用中文回答问题。', additional_kwargs={}, response_metadata={}), 
HumanMessage(content='你能帮我做什么呢?', additional_kwargs={}, response_metadata={}), 
AIMessage(content='我能开发Agent智能体', additional_kwargs={}, response_metadata={}), 
HumanMessage(content='我需要开发一个关于智能客服的智能体,请给我一些建议。', additional_kwargs={}, response_metadata={})
]

4.3.4 多模态提示词

可以使用提示模板来格式化多模态输入,比如将图片链接作为输入。

举例:

准备一张图片:

1

 代码如下:

from langchain_core.prompts import ChatPromptTemplate
from langchain_ollama import ChatOllama


# 初始化模型
llm = ChatOllama(
    model="qwen2.5vl:7b",
    base_url="http://127.0.0.1:11434"
)

# 创建模版
template = ChatPromptTemplate([
    {"role": "system", "content": "用中文简单描述图片内容"},
    {"role": "user", "content": [{"image_url": "{image_url}"}]}
])
# template = ChatPromptTemplate([
#     ("system", "用中文简单描述图片内容"),
#     ("user", [{"type": "image_url", "image_url": {"url": "{image_url}"}}])
# ])

# 使用format_messages方法生成提示,准备一张本地图片
prompt = template.format_messages(image_url="1.png")

# 调用模型
response = llm.invoke(prompt)
print(response.content)

输出:

这张图片中,一位女性靠在窗户边,穿着一件白色的针织开衫,头发是棕色的,披散在肩上。背景是蓝色的墙壁和白色的百叶窗,阳光透过窗户洒在她的身上,营造出一种温暖的氛围。

4.4 外部加载Prompt

可以将 prompt 保存为 JSON 或者 YAML 等格式的文件,通过读取指定路径的格式化文件,获取相应的 prompt。这样方便对 prompt 进行管理和维护。

4.4.1 json格式提示词

prompts目录下创建json文件:prompt.json

{
  "_type": "prompt",
  "input_variables": ["name", "what"],
  "template": "请{name}讲一个{what}的故事"
}

代码:

from langchain_core.prompts import load_prompt

template = load_prompt("prompt.json", encoding="utf-8")
print(template.format(name="李丽", what="恐怖的"))

输出:

请李丽讲一个恐怖的的故事

4.4.2 yaml格式提示词

prompts目录下创建yaml文件:prompt.yaml

_type: "prompt"
input_variables: ["name", "what"]
template: "请{name}讲一个{what}的故事"

代码:

from langchain_core.prompts import load_prompt

template = load_prompt("prompt.yaml", encoding="utf-8")
print(template.format(name="李丽", what="恐怖的"))

4.5.LangChain Hub 模版库

使用提示词模版库之前需要先到LangSmith官网上申请一个api_key,官网地址:https://smith.langchain.com/

  • 先点击设置按钮

image

  • 点击创建API KEY

image

  • hub提示词模版库地址:https://smith.langchain.com/hub/

image

案例:

import os
from dotenv import load_dotenv
from langsmith import Client
from langchain.chat_models import init_chat_model

load_dotenv()

# 通过langsmith的 api_key 初始化 client实例
client = Client(api_key=os.getenv("LANGSMITH_API_KEY"))

# 从hub中获取prompt
# 指定prompt标识符“”
prompt = client.pull_prompt("rlm/rag-prompt", include_model=True)

# input_variables=['context', 'question'] input_types={} partial_variables={} metadata={'lc_hub_owner': 'rlm', 'lc_hub_repo': 'rag-prompt', 'lc_hub_commit_hash': '50442af133e61576e74536c6556cefe1fac147cad032f4377b60c436e6cdcb6e'} messages=[HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['context', 'question'], input_types={}, partial_variables={}, template="You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the question. If you don't know the answer, just say that you don't know. Use three sentences maximum and keep the answer concise.\nQuestion: {question} \nContext: {context} \nAnswer:"), additional_kwargs={})]
print("==================================拉取回来的提示词=================================")
print(prompt)

# 使用提示词模版
formatted = prompt.format(
    context="LangChain 是一个开源框架,用于开发基于大型语言模型(LLM)的应用程序。它由 Harrison Chase 于 2022 年 10 月首次公开发布,核心目标是帮助开发者更高效地将 LLM 与外部数据、工具、API 和记忆系统结合,从而构建智能问答、对话系统、自动化助手等智能化应用。",
    question="LangChain 能做什么?"
)
print("==================================格式化后的提示词=================================")
print(formatted)

# 初始化模型
model = init_chat_model("deepseek-v4-pro", model_provider="deepseek", base_url="https://api.deepseek.com",
                        api_key=os.getenv("api_key"))

resp = model.invoke(formatted)
print("==================================大模型回复=================================")
print(resp.content)

print("==================================content_blocks=================================")
print(resp.content_blocks)

image

五、标准化内容块Content Blocks

为了统一所有模型厂商的输出格式,解决"换模型就要重写解析代码"的痛点:

LangChain 1.0 引入了 provider-agnostic与厂商无关 的 standard content blocks标准化内容块,使得消息中的多模态数据(图片、音频、PDF、视频等)能以统一、类型化的方式被构造与阅读。通过 content blocks 属性实现多模态统一处理,封装 TextBlock、ToolCallBlock、ImageBlock 等结构,扩展 LLM 应用至图片理解、语音交互等场景。其核心优势在于标准化内容流转与跨平台兼容性,可通过 langchain-openai 等厂商包直接初始化多模态模型,支持图片输入生成描述、语音转文本问答等功能,依赖 Model I/O 模块完成格式化与解析

支持类型:text 、 tool_call 、 image 、 audio 、 video       

场景内容块作用
📄 文档解析(PDF / 图片 / 表格) image block 把 Document OCR 图像传给模型
🔊 语音问答(ASR) audio block 发送语音样本
🎞 多模态 RAG 将检索到的图片、图表、视频帧作为 input blocks 传给模型
🤖 多工具 Agent 工具返回的媒体统一包装成 block 再传回模型
🧪 模型评估(LangSmith / LangChain Playground) 进行 multimodal prompt 测试与 A/B,对 content blocks 标注与评估。
import os
import dotenv
from langchain.chat_models import init_chat_model

dotenv.load_dotenv()

# 加载DeepSeek提供的模型
llm = init_chat_model(
    "deepseek-v4-pro",
    model_provider="deepseek",
    base_url="https://api.deepseek.com",
    api_key=os.getenv("api_key")
)

# 调用模型
resp = llm.invoke("请用中文回答:如何使用 LangChain?")
print(resp)

image

5.1.content_blocks标准化输出:

# 调用模型
resp = llm.invoke("请你介绍自己")
print(resp.content_blocks)

image

5.2.多模态输入content_blocks

如果需要把本地文件以 base64 形式发送,建议安装 pillow/ffmpeg 等按需工具

pip install pillow

base64 形式触及了网络传输与数据序列化的底层原理。
简单来说,将图片或音频转换为 Base64,主要是为了解决 “在纯文本协议(HTTP/JSON)中传输二进制数据(Binary Data)” 的兼容性问题。
绝大多数大模型 API(OpenAI, Anthropic, Google Gemini 等)都是基于 RESTful API,数据载荷(Payload)格式通常是 JSON。

  • JSON 的本质:JSON 是一种纯文本格式。它只能理解字符串(String)、数字、布尔值等文本数据。
  • 图片/音频的本质:它们是二进制数据(Binary Bytes)。如果你直接用文本编辑器打开一张 JPG 图片,你会看到乱码,其中包含了大量的不可见字符、控制字符(如换行符、空字符 \0 等)。
  • 冲突点:如果你直接把这些二进制乱码塞进 JSON 的字符串字段里(例如 {"image": "ÿØÿà..."}),这些特殊字符会破坏 JSON 的语法结构,导致服务端无法解析,或者被 HTTP 协议拦截。
  • 解决方案:Base64 编码可以将任意二进制数据,映射为 64 个标准的、可打印的 ASCII 字符(A-Z, a-z, 0-9, +, /)。这样,原本的二进制图片就变成了普通的字符串,可以完美地嵌入到 JSON 中。

content_blocks 是 LangChain v1 的标准化多模态消息单元,你可以用 dict 结构把图片与音频纳入消息里,框架会把它们转换为各 provider 可识别的格式;在实际使用时务必确认目标模型/provider 对 multimodal 的支持和所需的 mime_type / metadata 字段。       

import os
import dotenv
from langchain.chat_models import init_chat_model
from langchain_core.messages import HumanMessage, SystemMessage


dotenv.load_dotenv()

# 创建系统提示
system_message = SystemMessage(content="你是一个专业的问答助手")

# 构造用户消息:文件+图像
human_message = HumanMessage(content=[
    {"type": "text", "text": "请你描述图片的内容:"},
    {"type": "image_url", "image_url": {"url": "https://zrj18330672592.oss-cn-beijing.aliyuncs.com/20251015134735612.png", "mime_type": "image/jpeg", "metadata": "rag基础流程图"}}
])

# 创建一个消息列表
messages = [system_message, human_message]

# {'type': 'text', 'text': '请你描述图片的内容:'}
# {'type': 'image', 'id': 'lc_7583d430-4079-4318-a9f4-2306e52e9728', 'url': 'https://zrj18330672592.oss-cn-beijing.aliyuncs.com/20251015134735612.png', 'extras': {'image_url_mime_type': 'image/jpeg', 'image_url_metadata': 'rag基础流程图'}}
for message in human_message.content_blocks:
    print(message)

# 使用多模型模型
llm = init_chat_model(
    "gemma-4-26B-A4B-it",
    model_provider="openai",
    base_url=os.getenv("VLLM_REASON_SERVICE_URL"),
    api_key=os.getenv("api_key")
)

resp = llm.invoke(messages)
print(resp.content)

image

5.3.内容块创建标准格式

comparison = """
┌─────────────┬──────────────────────────────────────────────────────┐
│ 内容块类型   │ 标准格式(LangChain 1.0)                            │
├─────────────┼──────────────────────────────────────────────────────┤
│ 文本        │ {"type": "text", "text": "..."}                      │
│ 图像        │ {"type": "image", "url": "...", "mime_type": "..."}  │
│ 音频        │ {"type": "audio", "url": "...", "mime_type": "..."}  │
│ 视频        │ {"type": "video", "url": "...", "mime_type": "..."}  │
│ 文件        │ {"type": "file", "url": "...", "mime_type": "..."}   │
│ Base64 图像 │ {"type": "image", "base64": "...", "mime_type": "..."} │
│ Base64 音频 │ {"type": "audio", "base64": "...", "mime_type": "..."} │
│ OpenAI 图像 │ {"type": "image_url", "image_url": {"url": "..."}}   │
└─────────────┴──────────────────────────────────────────────────────┘
"""

#OpenAI 内容块支持对比表:

support_table = """
┌─────────────┬──────────┬─────────────────────────────────────┐
│ 内容块类型   │ 支持情况 │ 说明                                │
├─────────────┼──────────┼─────────────────────────────────────┤
│ text        │ ✅ 支持  │ 纯文本内容                          │
│ image_url   │ ✅ 支持  │ 图像 URL(支持 jpg, png, gif, webp)│
│ audio       │ ❌ 不支持│ 需要先用 Whisper 转录为文本         │
│ video       │ ❌ 不支持│ 需要提取关键帧或转录音频            │
│ file        │ ❌ 不支持│ 需要提取文本内容                    │
└─────────────┴──────────┴─────────────────────────────────────┘
"""

六、Output Parsers

6.1 输出解析器介绍

在应用开发中,大模型的输出可能是下一步逻辑处理的关键输入。因此,在这种情况下,规范化输出是必须要做的任务,以确保应用能够顺利进行后续的逻辑处理。

语言模型返回的内容通常都是文本字符串,而实际 AI 应用开发过程中有时希望模型可以返回更直观、更格式化的内容,LangChain 提供了输出解析器(Output Parser)将模型输出解析为结构化数据。

有多种类型的输出解析器,常用的有 StrOutputParser(字符串解析器)与 JsonOutputParser(JSON解析器)

6.2 StrOutputParser

StrOutputParser 是一个简单的解析器,从结果中提取 content 字段。

举例:将模型输出结果解析为字符串

from langchain_core.output_parsers import StrOutputParser
from langchain_ollama import ChatOllama

ollama_llm = ChatOllama(
    model="qwen3:8b",
    base_url="http://192.168.130.154:11434",  # 自定义地址
)
messages = [
    {"role": "system", "content": "你好,请介绍一下你自己"},
    {"role": "user", "content": "你好"},
]

# 调用invoke方法
resp = ollama_llm.invoke(messages)
print(resp)
"""
content='你好!我是Qwen,通义千问的超大规模语言模型。我能够帮助你解答问题、提供信息、进行创作,或者只是闲聊。有什么我可以帮你的吗?😊' 
additional_kwargs={} 
response_metadata={'model': 'qwen3:8b', 'created_at': '2025-12-09T02:34:39.1717765Z', 'done': True, 'done_reason': 'stop', 'total_duration': 11788952800, 'load_duration': 100126900, 'prompt_eval_count': 20, 'prompt_eval_duration': 186150600, 'eval_count': 174, 'eval_duration': 11479165500, 'model_name': 'qwen3:8b', 'model_provider': 'ollama'} id='lc_run--019b00f5-ccb5-7193-9603-7eb1bf5508b8-0' usage_metadata={'input_tokens': 20, 'output_tokens': 174, 'total_tokens': 194}
"""

# 调用StrOutputParser()将结果转为字符串
resp_str = StrOutputParser().invoke(resp)
print(resp_str)  # 你好!我是Qwen,通义千问的超大规模语言模型。我能够帮助你解答问题、提供信息、进行创作,或者只是闲聊。有什么我可以帮你的吗?😊

6.3 JsonOutputParser

JSON 解析器用于将大模型的自由文本输出转换为结构化JSON数据的工具。特别适用于需要严格结构化输出的场景,比如 API 调用、数据存储或下游任务处理。

JsonOutputParser 能够结合 Pydantic 模型进行数据验证,自动验证字段类型和内容(如字符串、数字、嵌套对象等)

使用 get_format_instructions() 获取JSON解析的格式化指令:

invoke调用

from typing import List

from langchain_core.output_parsers import JsonOutputParser
from langchain_ollama import ChatOllama
from pydantic import BaseModel, Field
from langchain_core.prompts import ChatPromptTemplate

# 定义数据模型
class PersonInfo(BaseModel):
    name: str = Field(description="用户姓名")
    age: int = Field(description="用户年龄")
    hobbies: List[str] = Field(description="用户爱好列表")


# 创建解析器
parser = JsonOutputParser(pydantic_object=PersonInfo)
# 获取格式化命令
format_instructions = parser.get_format_instructions()
print(format_instructions) # The output should be formatted as a JSON instance that conforms to the JSON schema below. 。。。

ollama_llm = ChatOllama(
    model="qwen3:8b",
    base_url="http://192.168.130.154:11434",  # 自定义地址
)
messages = [
    {"role": "system", "content": "请严格按照一下格式回答用户的问题:{format_instructions}"},
    {"role": "user", "content": "你好,请介绍一下蔡徐坤,他今年30岁,喜欢唱、跳rap篮球"},
]

# 创建模版, 并传入格式化命令,parser.get_format_instructions()表示使用解析器生成的格式化命令 
prompt_template = ChatPromptTemplate.from_messages(messages).partial(format_instructions=parser.get_format_instructions())

# 调用invoke方法,传入格式化后的提示
res_json = ollama_llm.invoke(prompt_template.format_messages())
print(res_json.content)  # {"name": "蔡徐坤", "age": 30, "hobbies": ["唱", "跳", "rap", "篮球"]}

链式调用

from typing import List

from langchain_core.output_parsers import JsonOutputParser
from langchain_ollama import ChatOllama
from pydantic import BaseModel, Field
from langchain_core.prompts import ChatPromptTemplate

# 定义数据模型
class PersonInfo(BaseModel):
    name: str = Field(description="用户姓名")
    age: int = Field(description="用户年龄")
    hobbies: List[str] = Field(description="用户爱好列表")


# 创建解析器
parser = JsonOutputParser(pydantic_object=PersonInfo)
# 获取格式化命令
format_instructions = parser.get_format_instructions()
print(format_instructions) # The output should be formatted as a JSON instance that conforms to the JSON schema below. 。。。

ollama_llm = ChatOllama(
    model="qwen3:8b",
    base_url="http://192.168.130.154:11434",  # 自定义地址
)
messages = [
    {"role": "system", "content": "请严格按照一下格式回答用户的问题:{format_instructions}"},
    {"role": "user", "content": "你好,请介绍一下蔡徐坤,他今年30岁,喜欢唱、跳rap篮球"},
]

# 创建模版, 并传入格式化命令
prompt_template = ChatPromptTemplate.from_messages(messages)

# 链式调用(Chain),分别是:提示词模版|模型|解析器
chain = prompt_template | ollama_llm | parser
res_josn = chain.invoke({"format_instructions": parser.get_format_instructions()})
print(res_josn) # {'name': '蔡徐坤', 'age': 30, 'hobbies': ['唱', '跳', 'rap', '篮球']}

七、Structured Outputs

可以要求模型按照给定的模式格式提供其响应,这有助于确保输出可以被轻松解析并在后续处理中使用。LangChain 支持多种模式类型和强制结构化输出的方法。

7.1 TypedDict

TypedDict 提供了一个使用 Python 内置类型的简单方案,但是没有验证功能。

from typing import TypedDict, Annotated, List
from langchain_ollama import ChatOllama


# 数据模型准备
class Animal(TypedDict):
    name: Annotated[str, "动物名称"]
    emoji: Annotated[str, "动物表情"]


class AnimalList(TypedDict):
    animals: Annotated[List[Animal], "动物和标签列表"]


ollama_llm = ChatOllama(
    model="qwen3:8b",
    base_url="http://192.168.130.154:11434",  # 自定义地址
)

messages = [
    {"role": "user", "content": "生成任意三种动物以及他们的emoji表情"},
]

# 指定模型处理后输出结构
llm_with_structured_output = ollama_llm.with_structured_output(AnimalList)
# 调用invoke方法
resp = llm_with_structured_output.invoke(messages)
print(resp) #{'animals': [{'name': '狗', 'emoji': '🐶'}, {'name': '猫', 'emoji': '🐱'}, {'name': '狮子', 'emoji': '🦁'}]}

7.2 Pydantic

pydantic 是一个第三方库,不是 Python 标准库的一部分。它最初于 2015 年发布,用于数据验证和设置管理。

主要特性
✅ 数据验证和设置管理
✅ 类型提示支持
✅ JSON 序列化/反序列化
✅ 与现代 Python 特性兼容

from typing import List
from langchain_ollama import ChatOllama
from pydantic.v1 import Field, BaseModel


# 数据模型准备
class Animal(BaseModel):
    name: str = Field(description="动物")
    emoji: str = Field(description="动物表情")


class AnimalList(BaseModel):
    animals: List[Animal] = Field(description="动物和标签列表")


ollama_llm = ChatOllama(
    model="qwen3:8b",
    base_url="http://192.168.130.154:11434",  # 自定义地址
)

messages = [
    {"role": "user", "content": "生成任意三种动物以及他们的emoji表情"},
]

# 指定模型处理后输出结构
llm_with_structured_output = ollama_llm.with_structured_output(AnimalList)
# 调用invoke方法
resp = llm_with_structured_output.invoke(messages)
print(resp)  # animals=[Animal(name='狗', emoji='🐶'), Animal(name='猫', emoji='🐱'), Animal(name='兔子', emoji='🐰')]

7.3 JSON Schema

若需最大程度的控制或互操作性,可以提供一个原始的 JSON Schema。详情可参考 https://platform.openai.com/docs/guides/structured-outputs/json-schema#supported-schemas

可以将原始响应与解析后的表示一起返回,可在调用 with_structured_output 时设置 include_raw=True 来实现。

 

import os
from langchain.chat_models import init_chat_model

llm = init_chat_model(
    model="openai/gpt-oss-20b:free",
    model_provider="openai",
    base_url="https://openrouter.ai/api/v1",
    api_key=os.getenv("OPENROUTER_API_KEY"),
)

schema = {
    "name": "animal_list",
    "schema": {
        "type": "array",
        "items": {
            "type": "object",
            "properties": {
                "animal": {"type": "string", "description": "动物名称"},
                "emoji": {"type": "string", "description": "动物的emoji表情"},
            },
            "required": ["animal", "emoji"],
        },
    },
}

messages = [{"role": "user", "content": "任意生成三种动物,以及他们的 emoji 表情"}]

llm_with_structured_output = llm.with_structured_output(
    schema, method="json_schema", include_raw=True
)
resp = llm_with_structured_output.invoke(messages)
print(resp)
print(resp["raw"])
print(resp["parsed"])
# [{'animal': '企鹅', 'emoji': '🐧'}, {'animal': '大象', 'emoji': '🐘'}, {'animal': '袋鼠', 'emoji': '🦘'}]

注意,如果使用ollama部署的模型,with_structured_output(schema, method="json_mode", include_raw=True)中一定是method="json_mode"

from langchain_ollama import ChatOllama


schema = {
    "name": "animal_list",
    "schema": {
        "type": "array",
        "items": {
            "type": "object",
            "properties": {
                "animal": {"type": "string", "description": "动物名称"},
                "emoji": {"type": "string", "description": "动物的emoji表情"},
            },
            "required": ["animal", "emoji"],
        },
    },
}

ollama_llm = ChatOllama(
    model="qwen3:8b",  # llama3.1:8b
    base_url="http://127.0.0.1:11434"
)

messages = [
    {"role": "user", "content": "生成任意三种动物以及他们的emoji表情"},
]

# 指定模型处理后输出结构
llm_with_structured_output = ollama_llm.with_structured_output(schema, method="json_mode", include_raw=True)

# 调用invoke方法
resp = llm_with_structured_output.invoke(messages)
print(resp["raw"].content)

 

posted @ 2025-12-08 18:17  酒剑仙*  阅读(88)  评论(0)    收藏  举报