LangChain 学习记录 03:提示词模板 PromptTemplate 与 ChatPromptTemplate 详解

发布时间:2026/7/14 19:39:31

LangChain 学习记录 03:提示词模板 PromptTemplate 与 ChatPromptTemplate 详解 LangChain 学习记录 03提示词模板 PromptTemplate 与 ChatPromptTemplate 详解摘要在大模型应用开发里Prompt 不是随手拼出来的一段字符串而是影响模型输出质量、代码可维护性和项目稳定性的核心资产。本文围绕 LangChain 的提示词模板展开重点讲清楚为什么不要长期依赖 f-string 手动拼 PromptPromptTemplate和ChatPromptTemplate分别适合什么场景partial和partial_variables如何减少重复传参MessagesPlaceholder为什么是多轮对话的关键FewShotPromptTemplate如何用示例引导模型输出一句话概括Prompt Template 的作用是把“怎么问模型”这件事标准化、参数化、可复用。文章目录LangChain 学习记录 03提示词模板 PromptTemplate 与 ChatPromptTemplate 详解摘要一、为什么需要提示词模板二、Prompt Template 的底层逻辑三、PromptTemplate最基础的字符串模板常见写法对比四、ChatPromptTemplate聊天模型的主力模板system、human、ai 的区别五、partial 与 partial_variablespartial 的核心价值partial 和 partial_variables 区别六、MessagesPlaceholder给历史对话留位置七、FewShotPromptTemplate用示例教模型做事八、项目中怎么选九、常见坑1. 模板变量名和 invoke 输入不一致2. 把 ChatPromptTemplate 当成普通字符串3. MessagesPlaceholder 传入的不是消息列表4. Few-shot 示例太多十、小结参考资料一、为什么需要提示词模板刚开始调用大模型时我们很容易这样写topic向量数据库style通俗易懂promptf请用{style}的方式解释什么是{topic}这当然能跑。但真实项目里的 Prompt 往往不是一句话而是包含角色设定任务目标输入数据输出格式约束条件示例历史对话安全边界如果全部用字符串拼接代码会慢慢变成这样prompt(你是一个专业助手。\nf请分析下面内容{text}\n要求\n1. 输出 JSON\n2. 不要添加解释\nf3. 语气要{style}\n)一开始看着还行后面需求一改Prompt 四处散落维护起来就像在旧项目里找一个没有注释的全局变量心态非常容易裂开。提示词模板解决的就是这个问题把 Prompt 的固定部分和可变部分分离。也就是固定模板 动态变量 最终 Prompt二、Prompt Template 的底层逻辑先看一张逻辑图。LangChain 中的提示词模板大概遵循这个流程变量输入 ↓ PromptTemplate / ChatPromptTemplate ↓ PromptValue ↓ Chat Model 或 LLM这里有一个容易忽略的点PromptTemplate 调用后不一定直接得到普通字符串。它可能生成一个PromptValue这个中间对象可以适配不同模型给普通 LLM 时可以转成字符串给 Chat Model 时可以转成消息列表这就是 LangChain 组件能无缝接入 LCEL 链的原因。后面你会经常看到chainprompt|model|parser这里的prompt能接到model前面就是因为它们都遵循统一的输入输出协议。三、PromptTemplate最基础的字符串模板PromptTemplate适合简单文本生成场景。比如fromlangchain_core.promptsimportPromptTemplate promptPromptTemplate.from_template(请用{style}的风格解释什么是{topic}。)resultprompt.invoke({style:通俗易懂,topic:向量数据库})print(result)这里的{style}和{topic}是占位符。调用时传入{style:通俗易懂,topic:向量数据库}LangChain 会把变量填进模板生成最终 Prompt。你也可以把它理解成一个函数defprompt(style,topic):returnf请用{style}的风格解释什么是{topic}。只不过 LangChain 的模板更适合后续接入模型、解析器和 Chain。常见写法对比写法说明适合场景f-stringPython 原生字符串拼接临时实验、小脚本PromptTemplateLangChain 字符串模板单轮文本生成ChatPromptTemplate聊天消息模板对话模型、多轮问答FewShotPromptTemplate示例驱动模板需要给模型示范输出模式如果你只是写一个极小 demof-string 没问题。但只要准备做项目就建议尽早换成 Prompt Template。四、ChatPromptTemplate聊天模型的主力模板现在大多数大模型接口都属于 Chat Model。Chat Model 不只是接收一段字符串而是接收一组消息system系统规则 human用户输入 ai模型历史回复所以更常用的是ChatPromptTemplate。fromlangchain_core.promptsimportChatPromptTemplate promptChatPromptTemplate.from_messages([(system,你是一名耐心的技术导师擅长用简单例子解释复杂概念。),(human,请解释{question})])prompt_valueprompt.invoke({question:LangChain 中的 PromptTemplate 有什么用})print(prompt_value)这段模板里有两条消息system给模型设定身份和行为规则 human用户真正要问的问题system、human、ai 的区别角色作用示例system设定模型身份、规则、边界你是一个严谨的代码审查助手human用户当前输入请解释这段代码ai模型之前的回复常用于示例或历史这段代码的作用是…一个更贴近项目的例子review_promptChatPromptTemplate.from_messages([(system,你是一个资深 Python 代码审查助手。),(human,请审查下面代码指出潜在问题\n{code})])这个模板比普通字符串更清晰系统身份放在system用户任务放在human变量{code}独立传入代码更像在描述业务流程而不是乱拼字符串。五、partial 与 partial_variables有时模板里有些变量是固定的。比如promptPromptTemplate.from_template(请用{style}风格解释{topic}要求不超过{max_words}字。)如果style总是“通俗易懂”我们不想每次都传promptprompt.partial(style通俗易懂)之后调用时只需要传剩下的变量resultprompt.invoke({topic:RAG,max_words:100})partial 的核心价值提前填充一部分变量让模板变成更具体的模板。这有点像函数默认参数defexplain(topic,style通俗易懂):...partial 和 partial_variables 区别方式使用时机特点partial()模板创建之后再填充变量灵活适合运行时决定partial_variables模板创建时就固定变量更自描述适合固定配置示例promptPromptTemplate(template请用{style}风格解释{topic},input_variables[topic],partial_variables{style:通俗易懂})如果这个固定值来自用户选择、配置文件或运行时上下文优先用partial()。如果这个固定值就是模板定义的一部分可以用partial_variables。六、MessagesPlaceholder给历史对话留位置多轮对话中我们需要把历史聊天记录插入 Prompt。这时就要用MessagesPlaceholder示例fromlangchain_core.promptsimportChatPromptTemplate,MessagesPlaceholder promptChatPromptTemplate.from_messages([(system,你是一个耐心的学习助手。),MessagesPlaceholder(variable_namehistory),(human,{input})])这里的MessagesPlaceholder(variable_namehistory)可以理解为这里先空着运行时把历史消息列表塞进来。运行时可以传prompt.invoke({history:[(human,我叫张三),(ai,你好张三)],input:我叫什么})最终模型看到的上下文大概是system你是一个耐心的学习助手 human我叫张三 ai你好张三 human我叫什么重点MessagesPlaceholder 本身不保存历史它只是给历史消息留一个插槽。真正自动保存和读取历史后面通常会配合RunnableWithMessageHistory。七、FewShotPromptTemplate用示例教模型做事有些任务光靠一句指令不够稳定。比如你希望模型把情绪词转换成近义词高兴 - 开心 难过 - 悲伤 生气 - 愤怒这时可以用 Few-shot prompting也就是给模型几个示例。fromlangchain_core.promptsimportFewShotPromptTemplate,PromptTemplate examples[{input:高兴,output:开心},{input:难过,output:悲伤},{input:生气,output:愤怒},]example_promptPromptTemplate.from_template(输入{input}\n输出{output})promptFewShotPromptTemplate(examplesexamples,example_promptexample_prompt,prefix请把用户输入的情绪词转换成一个近义词。,suffix输入{word}\n输出,input_variables[word])resultprompt.invoke({word:开心})print(result)生成的 Prompt 大致是请把用户输入的情绪词转换成一个近义词。 输入高兴 输出开心 输入难过 输出悲伤 输入生气 输出愤怒 输入开心 输出Few-shot 的底层逻辑是不是只告诉模型规则而是给模型看“输入和输出应该长什么样”。这对以下任务特别有用分类格式转换风格模仿固定结构输出少量业务规则示范八、项目中怎么选可以用这张表快速判断。场景推荐模板原因简单文本生成PromptTemplate轻量适合字符串 Prompt调用聊天模型ChatPromptTemplate支持 system/human/ai 角色多轮对话ChatPromptTemplate MessagesPlaceholder可以插入历史消息需要示例引导FewShotPromptTemplate用样例稳定模型行为固定部分变量partial()减少重复传参我的建议如果你现在主要用 ChatOpenAI、ChatOllama 等聊天模型优先掌握 ChatPromptTemplate。PromptTemplate要会但真实项目里ChatPromptTemplate更常用。九、常见坑1. 模板变量名和 invoke 输入不一致模板里写的是请解释{topic}调用时却传{question:LangChain}这样会报错。正确写法{topic:LangChain}变量名要对上程序不认“差不多”。2. 把 ChatPromptTemplate 当成普通字符串ChatPromptTemplate生成的是消息结构不是简单字符串。它的优势正是能区分system / human / ai不要强行把它当普通字符串拼来拼去。3. MessagesPlaceholder 传入的不是消息列表错误思路{history:用户你好\nAI你好}更推荐{history:[(human,你好),(ai,你好有什么可以帮你)]}因为聊天模型更容易理解结构化消息。4. Few-shot 示例太多示例不是越多越好。示例太多会增加 token 成本挤占上下文窗口让 Prompt 变难维护通常先从 2 到 5 个高质量示例开始。十、小结这一篇主要讲了 LangChain 的提示词模板。你可以这样记PromptTemplate普通字符串模板。 ChatPromptTemplate聊天消息模板。 MessagesPlaceholder给历史消息留插槽。 FewShotPromptTemplate用示例引导模型。 partial提前填充部分变量。最重要的是这句话提示词模板不是为了少写字符串而是为了让 Prompt 变得可复用、可维护、可组合。下一篇继续学习Output Parser 输出解析器。如果说 Prompt Template 负责“怎么问”那么 Output Parser 就负责“怎么把模型回答变成程序能用的数据”。参考资料LangChain Python 官方文档https://docs.langchain.com/oss/python/langchainLangChain Core API Referencehttps://reference.langchain.com/python/langchain-core/

相关新闻