LangChain 表达式语言核心组合:Prompt + LLM + OutputParser

https://python.langchain.com.cn/docs/expression_language/cookbook/prompt_llm_parser

LangChain 表达式语言核心组合:Prompt + LLM + OutputParser 总结

LangChain 中最基础且高频的核心组合是 Prompt(提示)→ LLM/ChatModel(模型)→ OutputParser(输出解析器),几乎所有复杂链都基于此构建。文档围绕这一组合,从"基础用法""进阶解析""输入简化"三个维度展开,以下是详细总结。

一、基础组合:Prompt + LLM(无解析器)

核心是将"提示模板"与"模型"串联,实现"接收用户输入→填充提示→调用模型→返回原始模型输出"的流程,可灵活附加模型调用参数(如停止序列、函数调用规则)。

1. 最简实现(ChatPromptTemplate + ChatModel)

使用 ChatPromptTemplate 定义带变量的提示,搭配 ChatModel(如 ChatOpenAI),直接返回模型原生的 AIMessage 输出。

python 复制代码
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI

# 1. 定义带变量{foo}的聊天提示模板
prompt = ChatPromptTemplate.from_template("tell me a joke about {foo}")
# 2. 初始化模型
model = ChatOpenAI()
# 3. 串联链:提示 → 模型
chain = prompt | model

# 调用:传入变量{foo}的值,返回AIMessage
result = chain.invoke({"foo": "bears"})
# 输出:AIMessage(content="为什么熊不穿鞋子?\n\n因为它们有熊脚!", ...)

2. 附加模型调用参数(用 bind 方法)

通过 model.bind(**kwargs) 为模型调用附加固定参数,无需每次调用时重复传入,常见场景包括"设置停止序列""指定函数调用"。

场景1:附加停止序列(截断模型输出)
python 复制代码
# 绑定停止序列:模型输出遇到"\n"时停止
chain = prompt | model.bind(stop=["\n"])
result = chain.invoke({"foo": "bears"})
# 输出:AIMessage(content="为什么熊从不穿鞋?", ...)(仅到换行前)
场景2:附加函数调用规则

指定模型需调用的函数结构,让模型输出符合函数参数格式的结果(而非自然语言)。

python 复制代码
# 1. 定义函数结构(如"生成笑话"的函数)
functions = [
    {
        "name": "joke",
        "description": "一个笑话",
        "parameters": {
            "type": "object",
            "properties": {
                "setup": {"type": "string", "description": "笑话的开头"},
                "punchline": {"type": "string", "description": "笑话的结尾"}
            },
            "required": ["setup", "punchline"]
        }
    }
]

# 2. 绑定函数调用参数:指定调用"joke"函数
chain = prompt | model.bind(function_call={"name": "joke"}, functions=functions)
result = chain.invoke({"foo": "bears"})
# 输出:AIMessage(content='', additional_kwargs={'function_call': {'name': 'joke', 'arguments': '{"setup": "为什么熊不穿鞋子?", "punchline": "因为它们有熊脚!"}'}})

二、进阶组合:Prompt + LLM + OutputParser

在基础组合后添加 OutputParser,将模型原生输出(如 AIMessage、函数调用格式)转换为更易处理的格式(如字符串、JSON、指定键值),降低下游任务的处理成本。

1. 普通文本解析(StrOutputParser)

AIMessagecontent 提取为纯字符串,最常用的解析器之一。

python 复制代码
from langchain_core.output_parsers import StrOutputParser

# 串联链:提示 → 模型 → 字符串解析
chain = prompt | model | StrOutputParser()
result = chain.invoke({"foo": "bears"})
# 输出:"为什么熊不穿鞋子?\n\n因为它们有熊脚!"(纯字符串,无AIMessage包装)

2. 函数调用结果解析(针对函数调用场景)

当模型输出为函数调用格式时,使用专门的解析器提取结构化数据(如 JSON 整体、JSON 中的指定键)。

场景1:解析为完整 JSON(JsonOutputFunctionsParser)

提取函数调用的 arguments 部分,转换为 Python 字典。

python 复制代码
from langchain.output_parsers.openai_functions import JsonOutputFunctionsParser

# 串联链:提示 → 绑定函数调用 → 解析为JSON字典
chain = (
    prompt
    | model.bind(function_call={"name": "joke"}, functions=functions)
    | JsonOutputFunctionsParser()
)
result = chain.invoke({"foo": "bears"})
# 输出:{'setup': "为什么熊不喜欢快餐?", 'punchline': "因为它们抓不到它!"}(Python字典)
场景2:解析为 JSON 中的指定键(JsonKeyOutputFunctionsParser)

仅提取 JSON 中某个指定键的值(如仅要"笑话开头"setup)。

python 复制代码
from langchain.output_parsers.openai_functions import JsonKeyOutputFunctionsParser

# 串联链:提示 → 绑定函数调用 → 解析指定键"setup"
chain = (
    prompt
    | model.bind(function_call={"name": "joke"}, functions=functions)
    | JsonKeyOutputFunctionsParser(key_name="setup")
)
result = chain.invoke({"foo": "bears"})
# 输出:"为什么熊不穿鞋子?"(仅提取setup键的值)

三、简化输入:用 RunnablePassthrough 减少重复传参

默认情况下,链需要传入"与提示变量匹配的字典"(如 {"foo": "bears"}),通过 RunnablePassthrough 可简化为"直接传变量值"(如 ("bears")),底层自动映射为字典。

实现方式(用字典映射简化)

通过字典定义"提示变量→输入值"的映射,RunnablePassthrough() 表示"直接传递输入值作为该变量的值"。

python 复制代码
from langchain_core.runnables import RunnablePassthrough

# 简化链:输入值→自动映射为{"foo": 输入值} → 提示 → 模型 → 解析
chain = (
    {"foo": RunnablePassthrough()}  # 输入值直接映射给变量foo
    | prompt
    | model.bind(function_call={"name": "joke"}, functions=functions)
    | JsonKeyOutputFunctionsParser(key_name="setup")
)

# 调用:直接传"bears",无需传字典
result = chain.invoke("bears")
# 输出:"为什么熊不穿鞋子?"

四、核心总结(表格对比)

组合类型 结构 输出格式 适用场景
基础 Prompt+LLM Prompt → LLM AIMessage 需保留模型原生输出(如函数调用元数据)
带普通解析 Prompt → LLM → StrOutputParser 纯字符串 下游需简单文本(如直接展示、字符串处理)
带函数结果解析(完整) Prompt→LLM.bind→JsonOutputFunctionsParser Python字典 需完整函数调用参数(如执行后续函数)
带函数结果解析(指定键) Prompt→LLM.bind→JsonKeyOutputFunctionsParser 单个值(字符串/数字) 仅需函数参数中的某个字段
简化输入版 {"var": RunnablePassthrough()} → Prompt → ... 对应解析格式 希望减少传参复杂度(直接传值而非字典)

结尾交付物提议

要不要我帮你整理一份**"Prompt+LLM+解析器"全场景代码模板**?包含基础组合、函数调用、输入简化等所有核心场景的可直接运行代码,每个示例都带注释,你替换模型或提示词就能快速适配自己的需求。

相关推荐
寻星探路5 小时前
【深度长文】万字攻克网络原理:从 HTTP 报文解构到 HTTPS 终极加密逻辑
java·开发语言·网络·python·http·ai·https
曹牧8 小时前
Spring Boot:如何测试Java Controller中的POST请求?
java·开发语言
爬山算法8 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate
kfyty7259 小时前
集成 spring-ai 2.x 实践中遇到的一些问题及解决方案
java·人工智能·spring-ai
猫头虎9 小时前
如何排查并解决项目启动时报错Error encountered while processing: java.io.IOException: closed 的问题
java·开发语言·jvm·spring boot·python·开源·maven
李少兄9 小时前
在 IntelliJ IDEA 中修改 Git 远程仓库地址
java·git·intellij-idea
忆~遂愿9 小时前
ops-cv 算子库深度解析:面向视觉任务的硬件优化与数据布局(NCHW/NHWC)策略
java·大数据·linux·人工智能
小韩学长yyds9 小时前
Java序列化避坑指南:明确这4种场景,再也不盲目实现Serializable
java·序列化
仟濹9 小时前
【Java基础】多态 | 打卡day2
java·开发语言