news 2026/4/19 17:43:36

从输入到输出:一文搞懂 LangChain Model I/O 的核心玩法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从输入到输出:一文搞懂 LangChain Model I/O 的核心玩法

简单来说就三步:拼提示词 -> 调大模型 -> 把结果整理成程序能用的格式


一、Model I/O 是什么

LangChain 是一个开发大模型应用的框架,而Model I/O是其中最基础、最核心的模块。它的名字听起来很技术,实际上只做三件简单的事情:

  • 输入(Input)

    :把用户的原始问题,加上你对模型的指令(比如“你是一个客服”),组合成一个完整的提示词(Prompt)

  • 处理(Model)

    :把这个提示词发给大模型,等待模型返回结果

  • 输出(Output)

    :把模型返回的文本,解析成你的程序可以直接使用的数据结构(比如字典、列表、对象)

如果没有 Model I/O,你需要手动拼接字符串、手动处理 API 请求、手动用正则表达式提取结果——不仅代码重复、容易出错,而且换一个模型就要重写一大片。

一个通俗的类比:假设你开了一家餐厅。

  • 顾客(用户)说“我要一份宫保鸡丁”——这是原始输入。

  • 但后厨的大厨(大模型)只看得懂标准化的菜单指令。于是你(Model I/O)把顾客的话翻译成“鸡丁 200g、花生米 50g、干辣椒 10g……”这样的标准格式——这就是输入处理

  • 然后你把菜单递给大厨,大厨开始炒菜——这就是模型调用

  • 大厨炒完菜,你把它装盘、摆成统一的样式端给顾客——这就是输出解析

Model I/O 就是帮你把这套流程标准化、自动化、可维护化。


二、调用在线模型:花钱买服务,省心省力

2.1 常见的大模型服务平台

目前有很多平台提供大模型 API 服务。你不需要自己买显卡、搭环境,只需注册账号、获取 API-Key,就能用代码调用他们部署好的模型。常见平台有:

  • CloseAI

    :OpenAI 兼容接口,价格相对便宜
    API-Key 管理:https://platform.closeai-asia.com/developer/api
    模型列表:https://platform.closeai-asia.com/pricing

  • OpenRouter

    :聚合多家模型,一个 Key 调用多种模型
    API-Key 管理:https://openrouter.ai/settings/keys
    模型列表:https://openrouter.ai/models

  • 阿里云百炼

    :通义千问系列,国内访问稳定
    API-Key 管理:https://bailian.console.aliyun.com/?tab=model#/api-key
    模型市场:https://bailian.console.aliyun.com/?tab=model#/model-market/all

  • 百度千帆

    :文心一言系列,生态完整
    API-Key 管理:https://console.bce.baidu.com/qianfan/apis/console/apiKey
    模型中心:https://console.bce.baidu.com/qianfan/modelcenter/model/buildIn/list

  • 硅基流动

    :国产算力平台,性价比高
    API-Key 管理:https://cloud.siliconflow.cn/me/account/ak
    模型列表:https://cloud.siliconflow.cn/me/models

这些平台都遵循 OpenAI 定义的 API 规范,所以调用方式几乎一模一样。

2.2 用 OpenAI SDK 直接调用

OpenAI 的 GPT 系列模型影响力极大,以至于几乎所有其他模型厂商都主动兼容它的调用格式。因此,下面这段代码只需更换 base_url 和 api_key,就能调用不同平台的模型。

# 安装依赖:pip install 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)

参数说明:

  • base_url:API 服务的入口地址,由平台提供。

  • api_key:身份凭证,相当于密码,需要保密。

  • model:具体使用哪个模型,不同平台提供的模型名称不同。

  • messages:对话历史,是一个列表。每个元素包含 role(角色)和 content(内容)。角色可以是 system(系统指令)、user(用户)、assistant(AI 的回复)。

2.3 API-Key 的安全管理

初学者最容易犯的错误是把 API-Key 直接写在代码里。一旦代码上传到 GitHub,别人就能看到你的密钥,然后用它来调用模型,扣除你的费用。

推荐做法:把密钥放在 .env 文件中,代码只读取这个文件。

首先,在项目根目录创建一个 .env 文件(注意这个文件要加入 .gitignore,不要提交到版本库):

OPENAI_API_KEY="sk-你的真实密钥" OPENAI_BASE_URL="https://openrouter.ai/api/v1"

然后在代码中使用 python-dotenv 加载:

# pip install python-dotenv import os from openai import OpenAI from dotenv import load_dotenv # 加载 .env 文件中的变量到环境变量 load_dotenv() # 从环境变量中读取 client = OpenAI( base_url=os.getenv("OPENAI_BASE_URL"), api_key=os.getenv("OPENAI_API_KEY"), ) # 后续调用不变...

如果你更简洁,也可以利用 OpenAI 客户端的默认行为——它会自动从环境变量中查找 OPENAI_API_KEY 和 OPENAI_BASE_URL:

load_dotenv() client = OpenAI() # 不需要显式传递参数

三种管理方式的对比:

方式

优点

缺点

适用场景

硬编码

简单直接

密钥泄露风险高

临时测试,绝不提交到仓库

.env 文件

安全、支持多环境

需要额外安装 python-dotenv

开发和生产环境推荐

系统环境变量

系统级统一管理

设置稍麻烦,临时会话会丢失

CI/CD 或容器环境

2.4 LangChain 的统一接口:init_chat_model

OpenAI SDK 已经很方便了,但如果你今天用 OpenAI,明天想换成国产模型,后天又想用本地 Ollama,代码结构还是略有差异。LangChain 提供了 init_chat_model 函数,让你用完全相同的代码初始化任何模型。

import os from langchain.chat_models import init_chat_model # 无论用哪家模型,写法都一样 llm = init_chat_model( model="openai/gpt-oss-20b:free", # 模型名称 model_provider="openai", # 模型提供商(openai/anthropic/google等) base_url="https://openrouter.ai/api/v1", api_key=os.getenv("OPENROUTER_API_KEY"), ) # 调用方式也完全一样 response = llm.invoke("把'你好'翻译成意大利语") print(response.content) # response 是 AIMessage 对象,.content 取文本

如果你想换成阿里云的通义千问,只需修改 model 和 base_url,其他代码不用动。这就是统一接口的好处。

2.5 模型初始化的常用参数

调用模型时,除了指定模型名称,还可以调整一些参数来控制模型的行为。这些参数在 init_chat_model 中可以直接设置。

参数

类型

作用

通俗解释

temperature

float

控制输出的随机性

0=每次都一样,很确定;1=有创意;2=天马行空可能胡扯

max_tokens

int

限制回答的最大长度

类似微博字数限制,防止模型写长篇大论

timeout

int

请求超时时间(秒)

如果模型 30 秒没回,就放弃,不要傻等

max_retries

int

失败后重试次数

网络偶尔抖动,自动重试两次,不用手动重新运行

示例:

llm = init_chat_model( model="...", model_provider="...", base_url="...", api_key="...", temperature=0.7, # 中等创意 max_tokens=500, # 回答最多 500 token timeout=30, # 30 秒超时 max_retries=2, # 失败后最多重试 2 次 )

2.6 Token 是什么

Token 是大模型处理文本的最小单位。它不是字符,也不是单词,而是一种介于两者之间的粒度。

  • 1 个中文汉字 ≈ 1 ~ 1.8 个 Token

  • 1 个英文单词 ≈ 3 ~ 4 个字母,平均分成 1~2 个 Token

例如,"Hello world" 可能被拆成 "Hello" 和 " world" 两个 Token。"你好世界" 可能被拆成 "你"、"好"、"世界" 三个 Token。

模型提供方通常按 Token 数量收费,同时也用 Token 数量限制一次请求的输入+输出总长度。你可以使用 OpenAI 提供的在线 Tokenizer 工具来查看任意文本会消耗多少 Token。

2.7 消息的类型:谁在说话?

在多轮对话中,每条消息都有一个角色(role),告诉模型这句话是谁说的。LangChain 中常用的消息类型有:

消息类型

对应的 role

用途

SystemMessage

system

设定模型的行为、角色、规则。例如:“你是一个客服,态度要友好。”

HumanMessage

user

用户真正的问题或指令。

AIMessage

assistant

模型上一次的回答。用于多轮对话时把历史告诉模型。

ToolMessage

tool

高级用法,当模型调用了外部工具(如查天气、计算)后,工具返回的结果。

代码中可以使用类,也可以使用字典,两种方式等价:

# 方式一:使用类(类型提示更清晰) from langchain.messages import SystemMessage, HumanMessage messages = [ SystemMessage("你是一个诗人"), HumanMessage("写一首关于春天的诗"), ] # 方式二:使用字典(更接近 OpenAI 原始格式) messages = [ {"role": "system", "content": "你是一个诗人"}, {"role": "user", "content": "写一首关于春天的诗"}, ]

2.8 模型调用的四种方法

LangChain 的聊天模型提供了四种调用方法,适用不同场景:

方法

说明

适用场景

invoke

单个输入,等待完整结果后返回

默认方式,最常用

stream

单个输入,逐个 token 流式返回

聊天机器人,让用户感觉 AI 在“打字”

batch

多个输入,并行处理,返回列表

有大量独立问题要问,追求吞吐量

ainvoke

异步版本,不阻塞主线程

同时做多件事(如同时调用模型和读取文件)

2.8.1 invoke:最简单的一次性调用

response = llm.invoke("你好,介绍一下你自己") print(response.content) # 等待全部生成完后一次性打印

2.8.2 stream:流式输出,逐字显示

# stream 返回一个生成器,每次吐出一个 token for chunk in llm.stream("写一首关于秋天的诗"): # end="" 表示不换行,flush=True 表示立即输出到屏幕 print(chunk.content, end="", flush=True)

效果就是 AI 一个字一个字地“打”出来,用户体验非常自然。尤其对于长回答,用户不需要等待 10 秒后突然看到一大段文字。

2.8.3 batch:批量并行处理

当你有一批相互独立的请求时,batch 会使用线程池并行执行多个 invoke,总耗时接近单个请求的耗时(而不是逐个累加)。

# 准备多个独立的对话 questions = [ [{"role": "user", "content": "写一首关于春天的诗"}], [{"role": "user", "content": "写一首关于夏天的诗"}], [{"role": "user", "content": "写一首关于秋天的诗"}], ] # 批量调用,返回结果列表 results = llm.batch(questions) for r in results: print(r.content)

假设每个请求需要 6 秒,串行需要 18 秒,batch 并行只需要约 6 秒。

2.8.4 ainvoke:异步调用,不阻塞

当你的程序需要同时做多件事情(比如一边调模型,一边读文件,一边发网络请求),同步调用会卡住整个程序。异步调用允许你“同时”发起多个请求,在等待模型返回时继续执行其他任务。

import asyncio from langchain.chat_models import init_chat_model llm = init_chat_model(...) async def ask(question): return await llm.ainvoke(question) async def main(): # 同时发起三个请求 tasks = [ask("写一首关于春天的诗"), ask("写一首关于夏天的诗"), ask("写一首关于秋天的诗")] results = await asyncio.gather(*tasks) for r in results: print(r.content) # 运行异步主函数 asyncio.run(main())

asyncio.gather 会并发执行所有任务。如果每个请求 6 秒,三个同时进行,总耗时仍然约 6 秒。

同步 vs 异步对比:

  • 同步:任务 A 完成 → 任务 B 开始 → 任务 B 完成 → 任务 C 开始。总时间 = 各任务时间之和。

  • 异步:任务 A、B、C 同时开始,谁先完成谁先返回。总时间 ≈ 最慢的那个任务的时间。


三、调用本地模型:免费、隐私、离线

3.1 Ollama 是什么

Ollama 是一个开源工具,目标是在你自己的电脑上运行大模型。你不需要联网,不需要付费,数据也不会离开你的机器。

你可以把它理解为“大模型版的 Docker”——你只需要敲一行命令,它就会自动下载模型、配置环境、启动服务,完全不用操心底层细节。

Ollama 的主要优势:

  • 免费:没有 API 调用费用,不限次数。

  • 隐私:所有数据都在本地,不会上传到任何服务器。

  • 简单:一条命令就能跑起来。

  • 跨平台:支持 Windows、macOS、Linux。

官方地址:https://ollama.com
GitHub 开源地址:https://github.com/ollama/ollama
模型仓库:https://ollama.com/search

3.2 安装 Ollama

根据你的操作系统选择安装方式:

  • Windows

    :访问 https://ollama.com/download,下载 .exe 安装包,双击安装。

  • macOS

    :下载 .dmg 文件,拖到 Applications 文件夹。

  • Linux

    :打开终端,执行以下命令:

curl -fsSL https://ollama.com/install.sh | sh

安装完成后,在终端输入 ollama --version,如果能显示版本号,说明安装成功。

3.3 下载并运行模型

Ollama 支持大量开源模型,如 DeepSeek、Qwen、Llama 等。以 DeepSeek-R1 的 70 亿参数版本(7b 表示 7 billion,即 70 亿参数)为例:

ollama run deepseek-r1:7b
  • 第一次运行时会自动下载模型文件(约 4GB,取决于网络速度,可能需要几分钟到十几分钟)。

  • 下载完成后自动进入交互式对话界面,你可以直接在里面提问。

  • 之后再次运行同一模型,会直接启动,无需重新下载。

常用 Ollama 命令:

命令

作用

ollama run <模型名>

运行模型(若不存在则自动下载)

ollama list

查看已下载的模型列表

ollama rm <模型名>

删除本地模型,释放硬盘空间

ollama pull <模型名>

只下载模型,不运行

如果 C 盘空间紧张,可以修改模型存储目录:在 Ollama 设置(Settings)中找到 "Model location",改为其他盘符的路径。

3.4 在 LangChain 中调用本地 Ollama 模型

Ollama 启动后默认在 http://localhost:11434 开启一个 API 服务。LangChain 提供了 ChatOllama 类来连接这个服务。

# 安装依赖:pip install langchain-ollama from langchain_ollama import ChatOllama # 连接本地 Ollama 服务 ollama_llm = ChatOllama(model="deepseek-r1:7b") # 调用方式与在线模型完全一致 response = ollama_llm.invoke("你好,请介绍一下你自己") print(response.content)

如果你的 Ollama 运行在另一台机器上(例如你有一台专门跑模型的 Linux 服务器),可以指定 IP 和端口:

ollama_llm = ChatOllama( model="deepseek-r1:7b", base_url="http://192.168.1.100:11434", # 改为你服务器的地址 )

注意:本地模型的性能取决于你的硬件(尤其是显存)。7B 参数模型大约需要 4-6GB 显存,如果没有独立显卡,CPU 也能运行但速度较慢。


四、Prompt Template:别再手动拼接字符串

4.1 为什么需要提示词模板

假设你正在做一个智能客服,用户问“这个商品多少钱”,你需要加上系统指令“你是一个客服,态度要友好”。没有模板时,你可能这样写:

product = "手机" user_question = "这个多少钱" prompt = f"你是一个客服。用户的问题是:{user_question},商品是{product}"

一两个地方还好,当你有几十个不同的场景,每个场景的提示词结构都不一样时,维护起来就是灾难。改一个字可能要翻遍所有代码。

使用模板的好处:

  • 提示词的结构集中在一个地方,修改一处全局生效。

  • 业务代码中只需要传变量,不用关心格式细节。

  • 可以把提示词单独存成文件(JSON/YAML),方便非技术人员调整。

4.2 复习 Python 的str.format()

LangChain 的 PromptTemplate 底层使用的是 Python 字符串的 format 方法。先快速回顾一下:

# 最简单的:按顺序替换 "Hello, {}".format("张三") # 输出: Hello, 张三 # 用数字指定位置 "Name: {0}, Age: {1}".format("李四", 25) # Name: 李四, Age: 25 # 用变量名(推荐,可读性最好) "Name: {name}, Age: {age}".format(name="王五", age=30) # 从字典中解包 person = {"name": "赵六", "age": 35} "Name: {name}, Age: {age}".format(**person)

4.3 PromptTemplate:基础字符串模板

PromptTemplate 是最简单的提示模板,用于构建包含变量的字符串。

方式一:使用构造函数

from langchain_core.prompts import PromptTemplate template = PromptTemplate( template="请评价{product}的优缺点,包括{aspect1}和{aspect2}。", input_variables=["product", "aspect1", "aspect2"], ) # 填充变量 prompt1 = template.format(product="智能手机", aspect1="电池续航", aspect2="拍照质量") print(prompt1) # 输出:请评价智能手机的优缺点,包括电池续航和拍照质量。 prompt2 = template.format(product="笔记本电脑", aspect1="处理速度", aspect2="便携性") print(prompt2) # 输出:请评价笔记本电脑的优缺点,包括处理速度和便携性。

方式二:使用 from_template 类方法(更简洁)

template = PromptTemplate.from_template("请给我一个关于{topic}的{type}解释。") prompt = template.format(type="详细", topic="量子力学") print(prompt) # 输出:请给我一个关于量子力学的详细解释。

from_template 会自动解析花括号中的变量名,不需要手动指定 input_variables。

4.4 部分填充模板(Partial)

有些变量在很多次调用中都是一样的(比如固定的系统指令)。你可以提前把这些变量填好,生成一个“半成品”模板,后面每次调用只需要填剩下的变量。

方式一:在构造函数中指定 partial_variables

template = PromptTemplate( template="foo {bar}", input_variables=["bar"], # 注意:foo 已被预填充,不需要出现在 input_variables 中 partial_variables={"foo": "hello"}, # 预先填充 foo ) prompt = template.format(bar="world") print(prompt) # hello world

方式二:使用 partial 方法

template = PromptTemplate.from_template("foo {bar}") partial_template = template.partial(foo="hello") # 预填充 foo prompt = partial_template.format(bar="world") print(prompt) # hello world

4.5 ChatPromptTemplate:多角色对话模板

如果你的应用涉及多轮对话(有系统消息、用户消息、AI 消息),PromptTemplate 就不够用了。这时候需要用 ChatPromptTemplate。

from langchain_core.prompts import ChatPromptTemplate template = ChatPromptTemplate.from_messages([ ("system", "你是一个 AI 开发工程师,你的名字是{name}。"), ("human", "你能帮我做什么?"), ("ai", "我能开发很多{thing}。"), ("human", "{user_input}"), ]) # 填充所有变量 prompt = template.format_messages( name="小谷AI", thing="AI应用", user_input="你好" ) print(prompt) # 输出是一个消息列表: # [SystemMessage(content="你是一个 AI 开发工程师,你的名字是小谷AI。"), # HumanMessage(content="你能帮我做什么?"), # AIMessage(content="我能开发很多AI应用。"), # HumanMessage(content="你好")]

format_messages 返回的是消息对象列表,可以直接传给模型的 invoke 方法。

4.6 MessagesPlaceholder:动态插入对话历史

在聊天机器人中,用户会连续说很多句话。你不可能在模板里写死 10 个 HumanMessage 占位符。MessagesPlaceholder 就像一个“插槽”,你可以在运行时把整个对话历史塞进去。

from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder # 定义一个模板,预留一个位置给历史消息 template = ChatPromptTemplate.from_messages([ ("system", "你是一个友好的助手。"), MessagesPlaceholder(variable_name="history"), # 历史消息放在这里 ("human", "{input}"), ]) # 运行时,把历史消息列表传进去 prompt = template.format_messages( history=[ ("human", "你好!"), ("ai", "你好!有什么可以帮你的?"), ("human", "我想学 Python"), ("ai", "太好了,Python 很容易上手。"), ], input="从哪里开始学?" )

为什么不能用普通变量 {history}?
如果直接写 {history},传入列表时会被转换成字符串,变成类似 "[('human', '你好'), ...]" 的乱码,模型无法理解。MessagesPlaceholder 会保持消息的结构,让模型正确识别每条消息的角色。

4.7 从外部文件加载 Prompt

把 Prompt 写在代码里,改的时候需要重新部署。更好的做法是把 Prompt 单独存成 JSON 或 YAML 文件,代码只负责加载。这样产品经理或运营人员也可以直接修改提示词。

JSON 文件示例(prompts/prompt.json):

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

YAML 文件示例(prompts/prompt.yaml):

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

加载代码:

from langchain_core.prompts import load_prompt # 加载 JSON 文件 template = load_prompt("prompts/prompt.json", encoding="utf-8") print(template.format(name="张三", what="搞笑的")) # 加载 YAML 文件 template = load_prompt("prompts/prompt.yaml", encoding="utf-8") print(template.format(name="年轻人", what="滑稽"))

五、Output Parser:让模型输出变成程序可直接用的数据

5.1 为什么需要输出解析器

大模型返回的是一个字符串,例如:"北京今天的天气是晴天,气温25度"。但你的程序可能需要的是这样的数据:

{"city": "北京", "weather": "晴天", "temperature": 25}

如果没有解析器,你就得自己写正则表达式去匹配“天气是”后面跟什么、“气温”后面跟什么,非常麻烦且容易出错。输出解析器自动完成这个转换。

5.2 StrOutputParser:提取纯文本

模型返回的是一个 AIMessage 对象,它包含 content、additional_kwargs 等字段。很多时候你只需要 content 这个字符串。StrOutputParser 就是帮你提取它。

from langchain_core.output_parsers import StrOutputParser response = llm.invoke("你好") print(type(response)) # <class 'langchain_core.messages.ai.AIMessage'> parser = StrOutputParser() text = parser.invoke(response) print(type(text)) # <class 'str'> print(text) # "你好!有什么我可以帮忙的吗?"

5.3 JsonOutputParser:转换为字典或列表

如果你希望模型返回 JSON 格式的数据(例如在数据提取、结构化输出场景),可以使用 JsonOutputParser。通常需要配合 Pydantic 模型来定义期望的结构,解析器会自动验证。

from pydantic import BaseModel, Field from langchain_core.output_parsers import JsonOutputParser from langchain.chat_models import init_chat_model # 1. 定义期望的数据结构 class Prime(BaseModel): prime: list[int] = Field(description="素数列表") count: list[int] = Field(description="小于该素数的素数个数") # 2. 创建解析器,并获取格式说明指令 parser = JsonOutputParser(pydantic_object=Prime) format_instructions = parser.get_format_instructions() # 3. 把格式说明放进系统提示词中 llm = init_chat_model(...) messages = [ {"role": "system", "content": format_instructions}, {"role": "user", "content": "生成5个1000到100000之间的素数,并标出小于每个素数的素数个数"}, ] response = llm.invoke(messages) # 4. 解析响应 result = parser.invoke(response) print(result) # 输出类似: # {'prime': [1009, 2003, 3001, 4001, 5003], 'count': [168, 303, 430, 584, 669]}

注意:get_format_instructions() 会生成一段很长的指令文本(例如 "The output should be formatted as a JSON instance...")。你必须把它放在系统消息或用户消息中,否则模型不知道应该输出 JSON。


六、结构化输出:更可靠的方式

with_structured_output 是比 OutputParser 更高级的方法。两者的区别:

  • OutputParser

    :模型先以自由文本回答,然后你在外部用解析器处理。模型可能会在 JSON 前后加一些解释文字,导致解析失败。

  • with_structured_output

    :在调用时就告诉模型“你必须用这个格式回答”,模型直接按格式生成,不会有多余文字。可靠性更高。

6.1 使用 TypedDict(轻量级,无运行时验证)

from typing import TypedDict, Annotated from langchain.chat_models import init_chat_model class Animal(TypedDict): animal: Annotated[str, "动物名称"] emoji: Annotated[str, "对应表情"] class AnimalList(TypedDict): animals: Annotated[list[Animal], "动物列表"] llm = init_chat_model(...) structured_llm = llm.with_structured_output(AnimalList) result = structured_llm.invoke("生成三种动物和它们的表情符号") print(result) # {'animals': [{'animal': '猫', 'emoji': '🐱'}, {'animal': '狗', 'emoji': '🐶'}, {'animal': '熊猫', 'emoji': '🐼'}]}

TypedDict 只提供类型提示,不进行运行时验证。如果模型返回的数据类型不对,不会报错。

6.2 使用 Pydantic(推荐,带验证和描述)

Pydantic 会自动校验字段类型,如果模型返回的数据不符合定义,会抛出异常。同时可以通过 Field(description=...) 给字段添加描述,帮助模型理解每个字段的含义。

from pydantic import BaseModel, Field class Animal(BaseModel): animal: str = Field(description="动物名称") emoji: str = Field(description="动物的表情符号") class AnimalList(BaseModel): animals: list[Animal] = Field(description="动物与表情的列表") structured_llm = llm.with_structured_output(AnimalList) result = structured_llm.invoke("生成三种动物和它们的表情符号") # result 是一个 Pydantic 对象,可以直接用 . 访问属性 for animal in result.animals: print(f"{animal.animal}: {animal.emoji}")

为什么推荐 Pydantic?

  • 类型安全:字段类型不匹配时会报错。

  • 自带验证:可以添加自定义验证器(例如检查字符串长度、数值范围)。

  • 字段描述:通过 description 帮助模型更准确地生成内容。

  • 嵌套结构:轻松定义复杂的嵌套数据模型。

6.3 使用 JSON Schema(最大灵活性)

如果你需要与现有 API 对接,或者对输出格式有极致的控制要求,可以直接传入一个 JSON Schema 字典。设置 include_raw=True 可以同时返回原始响应和解析后的结果,便于调试。

schema = { "type": "array", "items": { "type": "object", "properties": { "animal": {"type": "string", "description": "动物名称"}, "emoji": {"type": "string", "description": "表情符号"}, }, "required": ["animal", "emoji"], }, } structured_llm = llm.with_structured_output(schema, include_raw=True) result = structured_llm.invoke("生成三种动物和表情符号") print(result["parsed"]) # 解析后的结构化数据 print(result["raw"]) # 模型的原始输出(包含可能的前言后语)

include_raw=True 返回的字典包含以下字段:

  • parsed:解析成功后的结构化数据

  • raw:原始的 AIMessage 对象

  • parsing_error:如果解析失败,这里会有错误信息


七、总结

Model I/O 是 LangChain 中最基础也最重要的模块。掌握它,你就掌握了与大模型对话的标准流程。

三个核心组件回顾:

1. Prompt Template(提示词模板)

  • 把固定结构和可变内容分开,提高代码可维护性。

  • PromptTemplate:用于简单字符串提示。

  • ChatPromptTemplate:用于多角色、多轮对话。

  • MessagesPlaceholder:用于动态插入对话历史。

  • 可以从外部 JSON/YAML 文件加载,方便非技术人员调整。

2. Model(模型调用)

  • init_chat_model 统一了所有在线和本地模型的初始化方式。

  • invoke:一次一问,等待完整结果(最常用)。

  • stream:逐字输出,适合聊天机器人。

  • batch:批量并行处理,适合大量独立请求。

  • ainvoke:异步调用,不阻塞主线程。

  • Ollama 让你在本地免费、离线、隐私地运行大模型。

3. Output Parser(输出解析)

  • StrOutputParser:提取纯文本内容。

  • JsonOutputParser:将模型输出解析为字典/列表,常与 Pydantic 配合。

  • with_structured_output:更可靠的结构化输出,推荐使用 Pydantic 模型。

一条学习建议:

刚开始学习时,建议先用 invoke + StrOutputParser 跑通最基础的流程,理解输入输出的基本模式。等你对 Prompt 调优有感觉了,再尝试 stream(提升用户体验)和结构化输出(让数据更规范)。Model I/O 玩熟了,LangChain 的大门才算真正打开——后面还有 Chain(链式调用)、RAG(检索增强生成)、Agent(智能体)等更精彩的内容等着你去探索。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/19 17:42:33

集合进阶(双列集合的特点、Map(常用api、遍历方式))

1.双列集合的特点①双列集合一次需要存一对数据&#xff0c;分别为键和值 ②键不能重复&#xff0c;值可以重复 ③键和值是一一对应的&#xff0c;每一个键只能找到自己对应的值 ④键值这个整体我们称之为“键值对”或者“键值对对象”&#xff0c;在Java中叫做“Entry对象”2.…

作者头像 李华
网站建设 2026/4/19 17:41:29

逆向(二):CALL的实战构建与线程注入

1. CALL的基本概念与应用场景 在逆向工程领域&#xff0c;CALL技术就像是一把能够直接操控程序内部逻辑的"手术刀"。简单来说&#xff0c;它允许我们直接调用目标程序内部的函数&#xff0c;就像这些函数是我们自己写的一样。想象一下&#xff0c;你正在玩一个在线游…

作者头像 李华
网站建设 2026/4/19 17:40:41

如何5步掌握B站视频下载?BilibiliDown跨平台解决方案终极指南

如何5步掌握B站视频下载&#xff1f;BilibiliDown跨平台解决方案终极指南 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader &#x1f633; 项目地址: https://gitcode.com/gh_mi…

作者头像 李华
网站建设 2026/4/19 17:40:21

避开这5个坑,你的医学影像AI项目才算真正开始

医学影像AI项目启动前必须规避的5个数据陷阱 当CT扫描仪输出的DICOM文件静静躺在服务器里时&#xff0c;大多数工程师会迫不及待地开始标注工作——这往往是第一个致命错误。去年某三甲医院的胰腺癌检测项目就因此损失了三个月时间&#xff1a;团队发现所有冠状位图像的标注坐标…

作者头像 李华
网站建设 2026/4/19 17:37:13

抖音无水印下载器终极指南:3分钟学会批量下载抖音视频

抖音无水印下载器终极指南&#xff1a;3分钟学会批量下载抖音视频 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback suppo…

作者头像 李华