第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/
- API-Key管理:https://platform.closeai-asia.com/developer/api
- API文档:https://doc.closeai-asia.com/tutorial/api/openai.html
- 模型:https://platform.closeai-asia.com/pricing
2)OpenRouter:https://openrouter.ai/
- API-Key管理:https://openrouter.ai/settings/keys
- API文档:https://openrouter.ai/docs/community/frameworks-and-integrations-overview
- 模型:https://openrouter.ai/models
3)阿里云百炼:https://bailian.console.aliyun.com/
- API-Key管理:https://bailian.console.aliyun.com/?tab=model#/api-key
- API文档:https://bailian.console.aliyun.com/?tab=doc#/doc/?type=model
- 模型:https://bailian.console.aliyun.com/?tab=model#/model-market/all
4)百度千帆:https://console.bce.baidu.com/qianfan/overview
- API-Key管理:https://console.bce.baidu.com/qianfan/ais/console/apiKey
- API文档:https://cloud.baidu.com/doc/qianfan-docs/s/Mm8r1mejk
- 模型:https://console.bce.baidu.com/qianfan/modelcenter/model/buildIn/list
5)硅基流动:https://www.siliconflow.cn/
- API-Key管理:https://cloud.siliconflow.cn/me/account/ak
- API文档:https://docs.siliconflow.cn/cn/userguide/capabilities/text-generation
- 模型:https://cloud.siliconflow.cn/me/models
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 调用模型
通常通过聊天模型接口访问 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)
2.5 模型初始化相关参数
初始化一个模型最简单的方法就是使用 init_chat_model,并设置必要的参数,例如 API-Key 和模型名称。除此之外还有一些其他参数。
|
参数 |
说明 |
|
model |
模型名称或标识符 |
|
base_url |
发送请求的 API 端点的 URL。常由模型的提供商提供 |
|
api_key |
与模型提供商进行身份验证所需的 API 密钥 |
|
temperature |
控制模型输出的随机性。数字越高,回答越有创意;数字越低,回答越确定, |
|
timeout |
在取消请求之前,等待模型响应的最大时间(以秒为单位) |
|
max_tokens |
限制响应中的总tokens 数量,控制输出长度 |
|
max_retries |
请求失败时系统尝试重新发送请求的最大次数 |
Token是什么?
大模型处理的最小单位是 token(相当于自然语言中的词或字),输出时逐个 token 依次生成。模型提供商通常也是以 token 的数量作为其计量或收费的依据。1个中文Token≈1-1.8个汉字,1个英文Token≈3-4字母。
Token与字符转化的可视化工具:
- OpenAI提供:https://platform.openai.com/tokenizer
- 百度智能云提供:https://console.bce.baidu.com/support/#/tokenizer
2.6 对话模型的 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.7 调用方法
聊天模型提供了三种主要的调用方法:
|
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等在内的多个热门项目高度集成。
- Ollama官方地址:https://ollama.com
- Ollama Github开源地址:https://github.com/ollama/ollama
3.2 Ollama安装
Ollama项目支持跨平台部署,目前已兼容Mac、Linux和Windows操作系统。

无论使用哪个操作系统,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,可以切换模型目录

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 多模态提示词
可以使用提示模板来格式化多模态输入,比如将图片链接作为输入。
举例:
准备一张图片:

代码如下:
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="恐怖的"))
五、Output Parsers
5.1 输出解析器介绍
在应用开发中,大模型的输出可能是下一步逻辑处理的关键输入。因此,在这种情况下,规范化输出是必须要做的任务,以确保应用能够顺利进行后续的逻辑处理。
语言模型返回的内容通常都是文本字符串,而实际 AI 应用开发过程中有时希望模型可以返回更直观、更格式化的内容,LangChain 提供了输出解析器(Output Parser)将模型输出解析为结构化数据。
有多种类型的输出解析器,常用的有 StrOutputParser(字符串解析器)与 JsonOutputParser(JSON解析器)。
5.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,通义千问的超大规模语言模型。我能够帮助你解答问题、提供信息、进行创作,或者只是闲聊。有什么我可以帮你的吗?😊
5.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 支持多种模式类型和强制结构化输出的方法。
6.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': '🦁'}]}
6.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='🐰')]
6.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)

浙公网安备 33010602011771号