news 2026/5/15 8:46:21

【Langchain】 ChatPromptTemplate:从“手动拼字符串“到“专业模板“的进化之路

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【Langchain】 ChatPromptTemplate:从“手动拼字符串“到“专业模板“的进化之路

零基础看懂 ChatPromptTemplate:从"手动拼字符串"到"专业模板"的进化之路

一句话总结:ChatPromptTemplate 是 LangChain 中专门用来组装聊天消息的"模板引擎",它能让你像填空题一样,把变量插进预设的对话结构里,告别手动拼接字符串的混乱时代。


一、为什么需要它?先看一个"翻车现场"

想象你要让 AI 扮演一个"暴躁的代码审查员",审查一段代码。最原始的做法是手动拼字符串:

# ❌ 原始人写法:手动拼接,极易出错language="Python"code="def add(a, b): return a + b"prompt=f""" 你是一个暴躁的代码审查员。 请用{language}的视角审查以下代码:{code}要求:1. 指出问题 2. 骂得狠一点 """

问题在哪?

  • 角色、指令、代码全混在一起,改一处可能牵一发而动全身
  • 如果对话有"历史记录",拼接起来更是灾难
  • 无法复用,每次都要重新写一遍格式

二、ChatPromptTemplate 是什么?

它是 LangChain 提供的"聊天消息组装器",核心思想:

把对话拆成"角色 + 内容"的消息块,留出变量占位符,最后统一填充。

fromlangchain.promptsimportChatPromptTemplate# ✅ 现代写法:结构清晰,像填空题template=ChatPromptTemplate.from_messages([("system","你是一个{personality}的代码审查员。"),# 系统消息:设定角色("human","请用{language}的视角审查这段代码:\n{code}"),# 人类消息:用户输入])

对比一目了然:

维度 手动拼接字符串 ChatPromptTemplate
结构 一锅粥 分角色、分消息块
复用 复制粘贴 定义一次,多次填充
维护 改一处崩全局 改模板不影响调用逻辑
扩展 地狱难度 轻松加消息、加变量


三、核心概念:三种"消息角色"

聊天模型(如 GPT-4、Claude)只认三种身份牌:

  1. system—— “幕后导演”
    设定 AI 的身份、语气、规则。用户看不到,但 AI 全程照做。
fromlangchain.promptsimportChatPromptTemplate template=ChatPromptTemplate.from_messages([("system","你是一位{style}的厨师,只做{ cuisine }菜。"),("human","我想学做{ dish }"),])# 填充变量,生成最终消息列表messages=template.invoke({"style":"严厉","cuisine":"川菜","dish":"麻婆豆腐"})print(messages)# 输出:# [# SystemMessage(content='你是一位严厉的厨师,只做川菜。'),# HumanMessage(content='我想学做麻婆豆腐')# ]
  1. human/user—— “提问的顾客”
    就是用户的输入。可以带变量,也可以纯文本。
template=ChatPromptTemplate.from_messages([("system","你是翻译官,把用户的话翻译成{target_lang}。"),("human","{user_input}"),# 变量占位])result=template.invoke({"target_lang":"日语","user_input":"今天天气真好"})# HumanMessage(content='今天天气真好')
  1. ai/assistant—— “假装 AI 已经说过的话”
    这是精髓! 用来构造"少样本示例(Few-shot)",让 AI 模仿特定格式。
template=ChatPromptTemplate.from_messages([("system","你是一个情感分析器,只输出'正面'或'负面'。"),# 👇 假装这是上一轮对话:用户问,AI 答("human","这部电影太棒了!"),("ai","正面"),("human","浪费了我两个小时。"),("ai","负面"),# 👇 真正的用户输入("human","{text}"),])result=template.invoke({"text":"主角演技炸裂"})# 模型看到历史示例后,大概率输出:正面

四、四种创建方式(从简到繁)

方式 1:元组列表(最常用,推荐⭐)

fromlangchain.promptsimportChatPromptTemplate template=ChatPromptTemplate.from_messages([("system","你是{role},擅长{skill}。"),("human","请帮我{task}"),])messages=template.invoke({"role":"前端专家","skill":"React","task":"优化一个渲染卡顿的组件"})

方式 2:Message 对象(更灵活,可加额外参数)

fromlangchain.promptsimportChatPromptTemplatefromlangchain.prompts.chatimportSystemMessagePromptTemplate,HumanMessagePromptTemplate system_template=SystemMessagePromptTemplate.from_template("你是{role},语气要{tone}。")human_template=HumanMessagePromptTemplate.from_template("帮我{task}")chat_prompt=ChatPromptTemplate.from_messages([system_template,human_template])

方式 3:字符串直接转(适合单轮简单场景)

fromlangchain.promptsimportChatPromptTemplate# 只有一个消息时,默认当作 human 消息template=ChatPromptTemplate.from_template("把这句话翻译成{lang}:{text}")messages=template.invoke({"lang":"英语","text":"你好世界"})

方式 4:混合使用(历史记录 + 新输入)

fromlangchain_core.messagesimportAIMessage,HumanMessage# 从真实的聊天历史构造history=[HumanMessage(content="你好"),AIMessage(content="你好!有什么可以帮你的吗?"),]template=ChatPromptTemplate.from_messages([("system","你是客服机器人。"),*history,# 展开历史记录("human","{new_question}"),# 最新问题])messages=template.invoke({"new_question":"怎么退款?"})

五、实战案例:从简单到复杂

案例 1:带格式的代码审查(基础用法)

fromlangchain.promptsimportChatPromptTemplate template=ChatPromptTemplate.from_messages([("system","""你是一位{style}的{language}代码审查专家。 审查规则: 1. 检查是否有空指针风险 2. 检查是否有性能隐患 3. 用{style}的语气给出建议"""),("human","""请审查以下代码: ```{language} {code} ```"""),])# 使用messages=template.invoke({"style":"温和但犀利","language":"Java","code":""" public String getName(User user) { return user.getProfile().getName(); } """})# 可以直接传给模型# response = model.invoke(messages)

案例 2:动态 Few-shot 学习(让 AI 模仿格式)

假设你要让 AI 从非结构化文本中提取"人物-关系"对,并且严格按 JSON 格式输出:

template=ChatPromptTemplate.from_messages([("system","你是一个信息抽取助手。从文本中提取人物关系,只输出 JSON 数组,不要解释。"),# 示例 1("human","文本:小明是小红的哥哥,他们一起去了公园。"),("ai",'[{"person1": "小明", "relation": "哥哥", "person2": "小红"}]'),# 示例 2("human","文本:张三是李四的老板,王五是他们公司的客户。"),("ai",'[{"person1": "张三", "relation": "老板", "person2": "李四"}, {"person1": "王五", "relation": "客户", "person2": "公司"}]'),# 真实输入("human","文本:{input_text}"),])result=template.invoke({"input_text":"曹操是刘备的敌人,关羽是刘备的结拜兄弟。"})# AI 会模仿前面的 JSON 格式输出,而不是胡说八道

案例 3:多轮对话记忆(结合历史记录)

fromlangchain_core.messagesimportAIMessage,HumanMessage# 假设这是从数据库取出的历史记录chat_history=[HumanMessage(content="我想订一张去上海的机票"),AIMessage(content="好的,请问您想哪天出发?"),HumanMessage(content="明天"),AIMessage(content="明天上午 9 点有一班,可以吗?"),]template=ChatPromptTemplate.from_messages([("system","你是航空公司客服,叫小助手。"),*chat_history,("human","{input}"),])messages=template.invoke({"input":"可以,帮我订了吧"})# 模型能根据上下文理解"可以"指的是"上午 9 点那班"

案例 4:条件分支(根据变量动态改变提示词)

template=ChatPromptTemplate.from_messages([("system","你是{level}教程作者,用{level}的语言解释概念。"),("human","请解释什么是{concept}"),])# 同一套模板,不同变量 = 完全不同的风格beginner=template.invoke({"level":"零基础","concept":"递归"})# 系统消息:你是零基础教程作者,用零基础的语言解释概念。expert=template.invoke({"level":"资深工程师","concept":"递归"})# 系统消息:你是资深工程师教程作者,用资深工程师的语言解释概念。

六、高级技巧

技巧 1:部分填充(Partial Variables)

有些变量是固定的,不想每次调用都传:

template=ChatPromptTemplate.from_messages([("system","你是{role},使用{language}回答问题。"),("human","{question}"),])# 先绑定固定变量partial_template=template.partial(role="Python 专家",language="中文")# 之后只需要传变化的 questionmessages=partial_template.invoke({"question":"怎么写装饰器?"})

技巧 2:管道组合(Pipeline)

可以把模板和模型串成流水线:

fromlangchain_openaiimportChatOpenAI model=ChatOpenAI(model="gpt-4")# 模板 + 模型 = 一个完整的链chain=template|model# 直接传入变量,自动经过模板格式化再传给模型response=chain.invoke({"role":"诗人","language":"中文","question":"写一首关于春天的诗"})

技巧 3:MessagePlaceholder(插入任意消息列表)

当你不知道历史记录有多少条时:

fromlangchain.promptsimportMessagesPlaceholder template=ChatPromptTemplate.from_messages([("system","你是客服机器人。"),MessagesPlaceholder(variable_name="history"),# 这里会插入任意数量的消息("human","{input}"),])# history 可以传一个消息列表messages=template.invoke({"history":[HumanMessage(content="你好"),AIMessage(content="您好!有什么可以帮您?"),HumanMessage(content="查一下订单"),],"input":"订单号 12345"})

七、常见坑与解决方案

坑 现象 解决
变量名写错KeyError: 'langauge'仔细检查占位符{}里的名字
忘记invoke得到的是模板对象,不是消息 必须调用.invoke(variables)
单双引号混乱 JSON 里的引号和 f-string 冲突 用from_messages的元组写法,避免手动转义
历史记录顺序错 AI 回答错乱 确保是 human/ai/human/ai 交替
变量是列表/对象 直接插进去变成<object>先用json.dumps()转成字符串


八、总结:一张图看懂流程

┌─────────────────┐ ┌──────────────────┐ ┌─────────────┐ │ 定义模板 │ → │ 填充变量 │ → │ 发给模型 │ │ │ │ │ │ │ │ system: 你是{role}│ │ role="医生" │ │ SystemMessage│ │ human: 帮我{task} │ │ task="看报告" │ │ HumanMessage │ │ │ │ │ │ │ │ ChatPromptTemplate│ │ .invoke() │ │ model.invoke()│ └─────────────────┘ └──────────────────┘ └─────────────┘

核心口诀:

角色分清楚,变量留占位,调用 invoke 填,直接丢给模型算。

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

ColorUI:15分钟构建高颜值小程序的完整色彩系统解决方案

ColorUI&#xff1a;15分钟构建高颜值小程序的完整色彩系统解决方案 【免费下载链接】coloruicss 鲜亮的高饱和色彩&#xff0c;专注视觉的小程序组件库 项目地址: https://gitcode.com/gh_mirrors/co/coloruicss 在当今竞争激烈的小程序市场中&#xff0c;视觉体验已成…

作者头像 李华
网站建设 2026/5/15 8:42:07

Docusaurus技能库插件:数据驱动与组件化集成实战

1. 项目概述&#xff1a;一个为Docusaurus注入灵魂的技能库插件如果你正在使用Docusaurus构建技术文档、博客或知识库&#xff0c;并且希望站点不仅仅是静态内容的堆砌&#xff0c;而是能动态展示你的技能图谱、项目经验&#xff0c;甚至是一个交互式的个人名片&#xff0c;那么…

作者头像 李华
网站建设 2026/5/15 8:38:09

基于大语言模型的塔罗牌AI解读系统:技术架构与实现详解

1. 项目概述&#xff1a;当塔罗占卜遇见AI最近在GitHub上看到一个挺有意思的项目&#xff0c;叫“chatgpt-tarot-divination”。光看名字&#xff0c;你大概就能猜到它的核心玩法&#xff1a;用AI来解读塔罗牌。这可不是简单的“随机抽牌固定释义”&#xff0c;而是结合了像Cha…

作者头像 李华
网站建设 2026/5/15 8:36:14

从Git历史到数据洞察:构建代码仓库统计分析工具的设计与实践

1. 项目概述&#xff1a;一个为开发者量身定制的代码统计工具 在软件开发的日常中&#xff0c;无论是个人复盘、团队汇报&#xff0c;还是项目交接&#xff0c;我们常常会遇到一个看似简单却颇为棘手的问题&#xff1a;如何客观、量化地评估一个代码仓库的“工作量”或“活跃度…

作者头像 李华
网站建设 2026/5/15 8:26:32

WindowsCleaner:终极Windows系统清理指南,专治C盘爆红和电脑卡顿

WindowsCleaner&#xff1a;终极Windows系统清理指南&#xff0c;专治C盘爆红和电脑卡顿 【免费下载链接】WindowsCleaner Windows Cleaner——专治C盘爆红及各种不服&#xff01; 项目地址: https://gitcode.com/gh_mirrors/wi/WindowsCleaner 你是否经常遇到C盘空间告…

作者头像 李华