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)
将 AIMessage
的 content
提取为纯字符串,最常用的解析器之一。
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+解析器"全场景代码模板**?包含基础组合、函数调用、输入简化等所有核心场景的可直接运行代码,每个示例都带注释,你替换模型或提示词就能快速适配自己的需求。