LangChain+Ollama+DeepSeek 全链路认知:LangChain 模型 IO 模块实战
写在前面
- 博文内容涉及 LangChain 模型IO 模块认知
- 以及
模型包装器,提示词模版,输出解析器
认知以及Demo - 理解不足小伙伴帮忙指正 :),生活加油
我看远山,远山悲悯
持续分享技术干货,感兴趣小伙伴可以关注下 ^_^
Lang Chain 模块认知 模型 IO
Lang Chain
是在 LLM
爆发之后,最早有一定知名度的开源工具,其他生态大部分工具也都基于 Lang Chain
的架构方式,所以通过学习 Lang Chain
可以了解 大部分的 AI 应用工具,今天和小伙伴分享 Lang Chain
模块中的 模型 IO
模型 I/O 模块作为 LangChain
框架的核心组件,通过封装 50 余种大语言模型的 API 接口,构建了跨平台的统一交互范式。
其核心设计目标在于屏蔽底层 API 差异(如 OpenAI 的文本补全接口与智谱清言的聊天式接口差异),使开发者仅需通过标准化的 LLM 和 ChatModel 包装器类即可调用各类模型。
这种抽象机制不仅支持云端最新模型(如 GPT-4、DeepSeek-R1)的无缝接入,还能快速集成本地部署的开源模型(通过 Ollama 加载)或 HuggingFace 社区模型,开发者仅需调整初始化参数即可完成模型切换,无需重写业务逻辑代码。
通过 PromptTemplate
标准化输入格式、OutputParser
结构化输出结果,该模块将复杂的 API
调用协议简化为 3-5 行代码即可完成的标准化流程,真正实现了"一次编码,多模型适配
"的开发体验
模型IO
的核心功能:
模型包装器
:通过接口调用大语言模型提示词模板管理
:将输入进行模板化,并动态地选择和管理这些模板输出解析器
:从模型输出中提取信息
下面我们依次看一下这三块内容
模型包装器
模型包装器分类:
LLM 模型包装器
: 通用的LLM
模型包装器(返回值为 串)from langchain_community.llms import Ollama
聊天模型包装器
: 专门针对聊天类型API的聊天模型(聊天模型包装器)(返回值为AIMesssage
)from langchain_community.chat_models import ChatOllama
分别来看一下
LLM 模型包装器
LLM模型包装器
通过 langchain_community.llms
获取的模型包装器(如 OpenAI 等)均为 BaseLLM 的子类,它们通过继承统一基类的方法与属性,实现了对50余种大语言模型(如 OpenAI 的 text-davinci-003、Llama.cpp 本地模型)API 的标准化封装。
开发者仅需调用 invoke
或 generate
方法即可完成文本补全、代码生成等任务,无需关注底层 API 的差异化调用协议(如 OpenAI 的文本补全接口与智谱清言的聊天式接口差异)。此类包装器尤其适用于自由文本生成场景(如文案创作、代码续写),并通过 PromptTemplate 实现输入模板化,显著降低多模型切换的代码改造成本。
下面为一个 LLM 模型包装器的Demo
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : demo.py
@Time : 2025/03/09 01:13:15
@Author : Li Ruilong
@Version : 1.0
@Contact : liruilonger@gmail.com
@Desc : LangChain Demo
"""
# here put the import lib
#pip install langchain langchain-community ollama -i https://pypi.tuna.tsinghua.edu.cn/simple
from langchain_community.llms import Ollama
# 初始化 Ollama 连接
llm = Ollama(
base_url="http://localhost:11434", # Ollama 默认端口
model="deepseek-r1:latest",
temperature=0.3, # 控制创造性(0-1)
num_ctx=4096 # 上下文长度
)
# 单次对话
response = llm.invoke("LLM 是什么?")
print("回答:", response)
print("===========================================================")
# 流式输出(适合长文本)
for chunk in llm.stream("LLM 如何学习?"):
print(chunk, end="", flush=True)
聊天模型包装器
聊天模型包装器
langchain_community.chat_models
提供的聊天模型包装器(如 ChatOpenAI、ChatAnthropic
)专为多轮对话场景设计,通过结构化消息类型(SystemMessage、HumanMessage、AIMessage
)实现对话状态管理。
此类包装器适配 GPT-4、DeepSeek-R1
等先进模型的 Chat 类型 API,支持以消息列表作为输入(例如系统角色设定+用户提问),并返回 AIMessage
类型的结构化响应。
其核心优势在于简化复杂对话逻辑的开发流程
,例如客服机器人需维护的上下文记忆(Memory 模块)与多轮意图理解,开发者可通过 LLMChain
将聊天模型与提示词模板、输出解析器无缝串联,实现“对话即代码”的高效开发范式
聊天模型包装器Demo
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : demo_prompt.py
@Time : 2025/03/09 04:06:14
@Author : Li Ruilong
@Version : 1.0
@Contact : liruilonger@gmail.com
@Desc : None
"""
# here put the import lib
from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate
from langchain_community.chat_models import ChatOllama
from langchain_community.llms import Ollama
from langchain_core.prompts import ChatPromptTemplate, HumanMessagePromptTemplate
# 初始化 Ollama 连接
llm = Ollama(
base_url="http://localhost:11434", # Ollama 默认端口
model="deepseek-r1:latest",
temperature=0.3, # 控制创造性(0-1)
num_ctx=4096 # 上下文长度
)
# 配置本地模型
chat_model = ChatOllama(model="deepseek-r1:latest")
chat_template = ChatPromptTemplate.from_messages([
("system", "你是一位唐诗研究专家,用中文回答时保持古典韵味"),
("human", "请赏析{poem_title}的意境"),
("ai", "好的,我将从以下三个方面分析:\n1. 意象运用\n2. 情感表达\n3. 历史背景"),
("human", "{user_question}")
])
messages = chat_template.format_messages(
poem_title="《登鹳雀楼》",
user_question="诗中'更上一层楼'有何哲学深意?"
)
for msg in messages:
print(chat_model.invoke(messages))
提示词模板
提示词模板(PromptTemplate)
是AI交互中的结构化生成工具,其本质是通过预定义模板字符串(含占位符)动态生成适配场景的提示词
。
例如,使用{变量}
占位符可将用户输入、任务指令、示例数据
等元素动态注入模板,实现“一次设计,多次复用”
的工程化开发模式,其核心价值在于将复杂提示逻辑抽象为标准化的代码组件,开发者可通过调整输入变量(如input_variables=["style","topic"]
)快速切换任务场景,无需重写底层逻辑。
提示词模板
的三层结构化设计
指令层(Instruction Layer)
明确的指令定义任务目标与执行规则
,例如 “你是一名数据科学家,请用时间序列模型预测销售额”即为典型指令。此类指令通过角色设定
(role)、任务说明
(task)和格式约束
(如“输出表格”),强制对齐模型输出与业务需求
。
示例层(Few-shot Layer)
少量示例(Few-shot Learning)可显著提升模型理解能力
。例如通过投喂“SPD项目需求描述+预期输出框架”
的示例对,引导模型生成符合行业规范的方案。这种“输入-输出”
示例对可视为模板中的静态知识库
,用于激活模型的类比推理能力
。
动态输入层(Dynamic Input Layer)
用户输入变量(如topic=“人工智能”)作为模板的动态参数,决定生成内容的细粒度。比如 社团活动策划案例
中,“预算限制”“目标人群”等变量被注入模板,使AI输出的策划案兼具通用框架与个性化细节。支持链式调用,例如通过LLMChain
串联多个模板实现多轮对话。
从技术实现看,提示词模板常封装为可复用类,其核心方法包括:
变量声明
:通过input_variables
定义占位符参数类型;模板加载
:支持从外部文件读取模板,实现代码与内容分离;格式控制
:强制输出结构化内容(如Markdown表格、JSON),降低后续数据解析成本
下面我们看一些常见的模版
基础提示模板 (PromptTemplate)
单变量,多变量带格式控制
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : demo_prompt.py
@Time : 2025/03/09 04:06:14
@Author : Li Ruilong
@Version : 1.0
@Contact : liruilonger@gmail.com
@Desc : None
"""
# here put the import lib
from langchain_core.prompts import PromptTemplate
from langchain_community.llms import Ollama
# 初始化 Ollama 连接
llm = Ollama(
base_url="http://localhost:11434", # Ollama 默认端口
model="deepseek-r1:latest",
temperature=0.3, # 控制创造性(0-1)
num_ctx=4096 # 上下文长度
)
# 单变量模板
simple_template = """你是一个资深{role},请用中文回答:
问题:{question}
答案:"""
prompt = PromptTemplate.from_template(simple_template)
print(prompt.format(role="算法工程师", question="如何优化快速排序?"))
chain = llm
print(chain.invoke(prompt.format(role="算法工程师", question="如何优化快速排序?")))
# 多变量带格式控制
advanced_template = PromptTemplate(
input_variables=["language", "task"],
template="""
请用{language}编写一个{task}的代码示例,
要求包含详细的注释和异常处理。
"""
)
print(chain.invoke(advanced_template.format(language="Python", task="文件读写操作")))
)
少量示例模板 (FewShotPromptTemplate)
顾名思义,在推理前提供几个推理Demo,我们在最开始也讲到这种提示模版
# here put the import lib
from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate
from langchain_community.llms import Ollama
# 初始化 Ollama 连接
llm = Ollama(
base_url="http://localhost:11434", # Ollama 默认端口
model="deepseek-r1:latest",
temperature=0.3, # 控制创造性(0-1)
num_ctx=4096 # 上下文长度
)
# 示例数据集
examples = [
{"input": "高兴", "output": "笑容如春风拂面,眼中闪烁着星辰般的光芒"},
{"input": "悲伤", "output": "眼角低垂似凋零的花瓣,双肩微微颤动如秋叶飘零"}
]
# 单个示例模板
example_template = """
输入情感:{input}
文学化描述:{output}
"""
# 构建完整模板
few_shot_prompt = FewShotPromptTemplate(
examples=examples,
example_prompt=PromptTemplate(
input_variables=["input", "output"],
template=example_template
),
suffix="请将以下情感转化为文学描述:\n情感:{input}",
input_variables=["input"]
)
print(llm.invoke(few_shot_prompt.format(input="愤怒")))
聊天提示模板 (ChatPromptTemplate)
聊天提示模版,ChatPromptTemplate
能整合不同角色的消息(系统、用户、AI),形成连贯的对话上下文
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : demo_prompt.py
@Time : 2025/03/09 04:06:14
@Author : Li Ruilong
@Version : 1.0
@Contact : liruilonger@gmail.com
@Desc : None
"""
# here put the import lib
from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate
from langchain_community.chat_models import ChatOllama
from langchain_community.llms import Ollama
from langchain_core.prompts import ChatPromptTemplate, HumanMessagePromptTemplate
# 初始化 Ollama 连接
llm = Ollama(
base_url="http://localhost:11434", # Ollama 默认端口
model="deepseek-r1:latest",
temperature=0.3, # 控制创造性(0-1)
num_ctx=4096 # 上下文长度
)
# 配置本地模型
chat_model = ChatOllama(model="deepseek-r1:latest")
chat_template = ChatPromptTemplate.from_messages([
("system", "你是一位唐诗研究专家,用中文回答时保持古典韵味"),
("human", "请赏析{poem_title}的意境"),
("ai", "好的,我将从以下三个方面分析:\n1. 意象运用\n2. 情感表达\n3. 历史背景"),
("human", "{user_question}")
])
messages = chat_template.format_messages(
poem_title="《登鹳雀楼》",
user_question="诗中'更上一层楼'有何哲学深意?"
)
for msg in messages:
print(chat_model.invoke(messages))
组合模板 (PipelinePromptTemplate)
PipelinePromptTemplate 是 LangChain 框架中用于组合复杂提示词流程的核心工具,特别适用于需要分阶段处理或多模块协作的场景。以下是其核心特性与用法详解
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File : demo_prompt.py
@Time : 2025/03/09 04:06:14
@Author : Li Ruilong
@Version : 1.0
@Contact : liruilonger@gmail.com
@Desc : None
"""
# here put the import lib
from langchain_core.prompts import PromptTemplate
from langchain_community.llms import Ollama
from langchain_core.prompts import PipelinePromptTemplate
# 初始化 Ollama 连接
llm = Ollama(
base_url="http://localhost:11434", # Ollama 默认端口
model="deepseek-r1:latest",
temperature=0.3, # 控制创造性(0-1)
num_ctx=4096 # 上下文长度
)
# 基础模板
base_template = """
{concept}({year}年提出)的核心思想是:
{summary}
"""
# 详细说明模板
detail_template = """
请用中文分点说明{concept}:
1. 基本定义
2. 主要应用场景
3. 最新发展(截至{year})
"""
combined_prompt = PipelinePromptTemplate(
final_prompt=PromptTemplate.from_template(base_template),
pipeline_prompts=[
("summary", PromptTemplate.from_template(detail_template))
]
)
print(llm.invoke(combined_prompt.format(
concept="注意力机制",
year=2023
)))
自定义模板 (Custom Template)
通过继承StringPromptTemplate 实习动态模版参数
from langchain_core.prompts import StringPromptTemplate
from pydantic import BaseModel
class CodePrompt(BaseModel):
language: str
framework: str = "无框架"
class CodeTemplate(StringPromptTemplate):
def format(self, **kwargs) -> str:
prompt = f"""
# 代码生成助手
语言:{kwargs['language']}
框架:{kwargs.get('framework', '标准库')}
功能需求:{kwargs['requirement']}
附加要求:{kwargs.get('constraint', '无')}
"""
return prompt.replace(" ", "") # 清理缩进
template = CodeTemplate(input_variables=["language", "framework", "requirement"])
print(template.format(
language="Python",
framework="FastAPI",
requirement="创建文件上传接口",
constraint="限制文件大小为10MB"
))
文件加载模板 (load_prompt)
类似运维剧本中的 模版文件,熟悉 Ansible 的小伙伴对这个应该不陌生
# 创建模板文件 prompt.yaml
"""
_type: prompt
input_variables: ["country"]
template:
请用中文介绍{country}的:
1. 历史沿革
2. 文化特色
3. 现代发展
"""
from langchain_core.prompts import load_prompt
loaded_prompt = load_prompt("prompt.yaml")
print(loaded_prompt.format(country="意大利"))
模板选择参考
模板类型 | 适用场景 | 优势 |
---|---|---|
PromptTemplate |
简单问答、代码生成 | 快速构建基础提示 |
ChatPromptTemplate |
对话系统 | 支持多角色消息 |
FewShotPromptTemplate |
需要示例引导的任务 | 提升模型输出一致性 |
PipelinePromptTemplate |
复杂逻辑分解 | 实现提示的模块化组合 |
自定义模板 | 特殊格式要求 | 完全控制提示结构 |
通过组合这些模板,可以构建适应各种复杂场景的提示工程系统。建议根据具体任务复杂度选择适当模板。
输出解析器
输出解析器,顾名思义将模型生成的输出格式转化为可以在代码中直接使用的格式
。对于这个问题,通常使用LangChain 的输出解析器(OutputParsers)工具来解决
使用 LangChain 输出解析器(Output Parsers)的常见场景 Demo 示例,涵盖结构化数据、JSON、列表等格式的自动转换:
基础解析器:Pydantic 模型结构化输出
将 LLM 输出转换为符合预定义结构的 Python 对象
from langchain_core.pydantic_v1 import BaseModel, Field
from langchain_core.output_parsers import PydanticOutputParser
# 1. 定义数据结构模型
class Book(BaseModel):
title: str = Field(description="书名")
author: str = Field(description="作者")
year: int = Field(description="出版年份")
genres: list[str] = Field(description="书籍分类")
# 2. 创建解析器
parser = PydanticOutputParser(pydantic_object=Book)
# 3. 自动生成格式指令(注入提示词)
format_instructions = parser.get_format_instructions()
print(format_instructions)
# 输出示例:
# "请用以下JSON格式输出...属性包括 title, author, year, genres..."
# 4. 组合提示词模板
from langchain_core.prompts import PromptTemplate
prompt = PromptTemplate(
template="请根据描述生成书籍信息:{query}\n{format_instructions}",
input_variables=["query"],
partial_variables={"format_instructions": format_instructions},
)
from langchain_community.llms import Ollama
llm = Ollama(
base_url="http://localhost:11434", # Ollama 默认端口
model="deepseek-r1:latest",
temperature=0.3, # 控制创造性(0-1)
num_ctx=4096 # 上下文长度
)
# 5. 调用模型并解析
chain = prompt | llm | parser
result = chain.invoke({"query": "鲁迅的第一本小说集"})
print(type(result)) # <class '__main__.Book'>
print(result.title) # 《呐喊》
JSON 格式解析器
直接解析模型返回的 JSON 字符串为 Python 字典
from langchain_core.output_parsers import JsonOutputParser
# 1. 定义解析器
parser = JsonOutputParser()
# 2. 提示词模板(自动包含JSON格式要求)
prompt = PromptTemplate(
template="生成包含姓名、年龄和兴趣的用户信息:{input}\n{format_instructions}",
input_variables=["input"],
partial_variables={"format_instructions": parser.get_format_instructions()},
)
from langchain_community.llms import Ollama
llm = Ollama(
base_url="http://localhost:11434", # Ollama 默认端口
model="deepseek-r1:latest",
temperature=0.3, # 控制创造性(0-1)
num_ctx=4096 # 上下文长度
)
# 3. 调用并解析,通过表达式的方式
chain = prompt | llm | parser
data = chain.invoke({"input": "一个热爱AI的00后开发者"})
print(data)
# 输出示例:
# {'name': '张晓明', 'age': 24, 'interests': ['人工智能', '编程']}
列表解析器
将模型输出的无序文本转换为有序列表
from langchain_core.output_parsers import CommaSeparatedListOutputParser
parser = CommaSeparatedListOutputParser()
format_instructions = parser.get_format_instructions() # "用逗号分隔的列表"
prompt = PromptTemplate(
template="列举5个{theme}相关的关键技术:\n{format_instructions}",
input_variables=["theme"],
partial_variables={"format_instructions": format_instructions},
)
from langchain_community.llms import Ollama
llm = Ollama(
base_url="http://localhost:11434", # Ollama 默认端口
model="deepseek-r1:latest",
temperature=0.3, # 控制创造性(0-1)
num_ctx=4096 # 上下文长度
)
chain = prompt | llm | parser
tech_list = chain.invoke({"theme": "自动驾驶"})
print(tech_list)
# 输出示例:
# ['激光雷达', '计算机视觉', '高精地图', '路径规划', 'V2X通信']
结构化文本解析器
提取文本中的关键字段(类似键值对)
from langchain_core.output_parsers import StructuredOutputParser, ResponseSchema
# 1. 定义响应字段
response_schemas = [
ResponseSchema(name="company", description="公司名称"),
ResponseSchema(name="industry", description="所属行业"),
ResponseSchema(name="revenue", description="年营收(单位:亿元)", type="float"),
]
# 2. 创建解析器
parser = StructuredOutputParser.from_response_schemas(response_schemas)
format_instructions = parser.get_format_instructions()
# 3. 组合提示词
prompt = PromptTemplate(
template="分析以下企业:{text}\n{format_instructions}",
input_variables=["text"],
partial_variables={"format_instructions": format_instructions},
)
from langchain_community.llms import Ollama
llm = Ollama(
base_url="http://localhost:11434", # Ollama 默认端口
model="deepseek-r1:latest",
temperature=0.3, # 控制创造性(0-1)
num_ctx=4096 # 上下文长度
)
# 4. 执行解析
chain = prompt | llm | parser
output = chain.invoke({"text": "华为2023年营收超过7000亿元"})
print(output)
# {'company': '华为', 'industry': '信息与通信技术', 'revenue': 7000.0}
日期时间解析器
自动解析文本中的日期时间
from langchain.output_parsers import DatetimeOutputParser
parser = DatetimeOutputParser()
format_instructions = parser.get_format_instructions() # 要求输出ISO 8601格式
prompt = PromptTemplate(
template="将以下日期转换为标准格式:{date}\n{format_instructions}",
input_variables=["date"],
partial_variables={"format_instructions": format_instructions},
)
from langchain_community.llms import Ollama
llm = Ollama(
base_url="http://localhost:11434", # Ollama 默认端口
model="deepseek-r1:latest",
temperature=0.3, # 控制创造性(0-1)
num_ctx=4096 # 上下文长度
)
chain = prompt | llm | parser
result = chain.invoke({"date": "明年端午节"})
print(result.strftime("%Y-%m-%d")) # 2025-05-31(假设当前是2024年)
自动重试解析器
当解析失败时自动重试
from langchain.output_parsers import RetryOutputParser
# 包裹基础解析器(以JSON为例)
base_parser = JsonOutputParser()
parser = RetryOutputParser.from_llm(parser=base_parser, llm=llm)
# 使用示例(当第一次解析失败时自动调整提示)
try:
data = parser.parse("非标准回答:{name: 'AI助手'}")
except:
# 自动触发重试逻辑
fixed_data = parser.parse_with_prompt("...", original_prompt)
通过组合不同的输出解析器,可以轻松实现从自由文本到程序可消费数据结构的无缝衔接。具体选择取决于业务场景是否需要强结构(Pydantic)、弱结构(JSON)或简单列表等格式。
博文部分内容参考
© 文中涉及参考链接内容版权归原作者所有,如有侵权请告知 :)
《LangChain 入门指南构建高可复用、可扩展的 LLM 应用程序》
© 2018-至今, 保持署名-非商用-相同方式共享(CC BY-NC-SA 4.0)
- 点赞
- 收藏
- 关注作者
评论(0)