——从手工作坊到流水线生产,一套方法论搞定所有提示词场景!

为啥要聊这个

前两篇我们把模型调通了,消息结构也捋顺了。但有个问题一直憋着没说——每次写Prompt都是字符串拼接,代码里一堆f-string和反斜杠,看得人血压飙升。

你肯定遇到过这种情况:

prompt = f"你是一个{role},请根据{product}的以下信息:{data},生成一段{style}风格的文案,字数控制在{words}字以内,注意{rule1}、{rule2}、{rule3}..."

这玩意儿写三次就想砸键盘。变量一多,引号嵌套就乱套,改个需求得在十几个地方同步修改。

Prompt模板就是来解决这个问题的。

今天重点说三件事:

  • 两大模板工具怎么选 —— 别再傻傻分不清

  • MessagesPlaceholder的妙用 —— 多轮对话的标准姿势

  • 三条铁律+两个案例 —— 直接抄作业


一、两大模板工具,别选错了

LangChain给了两个工具,很多人上来就懵。

PromptTemplate:轻量,但有限

这个生成的是纯字符串,适合单轮、不需要区分角色的任务。

template = PromptTemplate.from_template(
    "把下面这段文字翻译成{target_lang}:{text}"
)

prompt = template.format(target_lang="英文", text="今天天气不错")
# 输出:把下面这段文字翻译成英文:今天天气不错

简单直接,但有个致命缺陷——没有角色概念。你只能把"你是一个翻译官"这种指令和用户内容揉在一段话里,模型分不清哪个是系统设定、哪个是用户输入。

ChatPromptTemplate:生产环境唯一选择

这个生成的是结构化消息列表,支持System/Human/AI三种角色。

from langchain_core.prompts import ChatPromptTemplate

template = ChatPromptTemplate.from_messages([
    ("system", "你是{role},回答要{style}"),
    ("human", "{question}")
])

prompt = template.invoke({
    "role": "资深营养师",
    "style": "通俗易懂",
    "question": "每天喝多少水合适?"
})

输出的不是字符串,而是[SystemMessage, HumanMessage]列表。这意味着:

  • 模型能准确区分"系统设定"和"用户问题"

  • 不同角色的消息在API调用时自动映射到对应字段

  • 后期接入记忆管理、多轮对话时天然兼容

一句话结论:新项目无脑上ChatPromptTemplate,它能向下兼容纯文本需求,但反过来不行。


二、MessagesPlaceholder:多轮对话的标准化姿势

这是本篇文章最重要的知识点,没有之一。

先看问题:多轮对话时,历史消息怎么塞进模板?

错误示范——手动拼接:

history_str = "\n".join([f"用户:{h}\nAI:{a}" for h, a in history])
template = f"历史对话:{history_str}\n当前问题:{question}"

太丑了,而且丢失了消息类型信息。模型分不清哪句是用户说的、哪句是AI说的。

正确姿势——MessagesPlaceholder:

from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

template = ChatPromptTemplate.from_messages([
    ("system", "你是友好的问答助手"),
    MessagesPlaceholder(variable_name="history", optional=True, n_messages=4),
    ("human", "{question}")
])

看到没?在模板里开了一个插槽,专门用来塞历史消息列表。

调用的时候:

prompt = template.invoke({
    "history": [
        ("human", "我叫张伟"),
        ("ai", "你好张伟,有什么可以帮你的?"),
        ("human", "我问过订单"),
        ("ai", "您的订单正在派送中"),
    ],
    "question": "那什么时候能到?"
})

三个参数说清楚

参数 作用 使用建议
variable_name 指定历史消息的变量名 固定写"history"即可
optional 是否允许为空 首轮对话设为True,避免报错
n_messages 只取最近N条 强烈建议设置,防止上下文过长

最佳实践n_messages建议4-6条。太长会超Token限额,太短则丢失上下文。如果对话超过20轮,建议配合摘要压缩技术。


三、Prompt编写的三条铁律

不讲虚的,直接给原则。

原则一:角色要具体

❌ 你是一个助手
✅ 你是拥有10年经验的跨境电商运营专家,擅长用数据驱动方式撰写商品详情页

角色越具体,模型的措辞、语气、专业度越稳定。

原则二:任务要拆解

不要在一个Prompt里塞三件事。

❌ 请分析情感、提取实体、生成摘要
✅ 拆成三个独立的Prompt,分步调用

模型不是多线程,任务越聚焦输出越精准。

原则三:约束要可验证

"写得好一点"这种话等于废话。可验证的约束长这样:

模糊约束 ❌ 可验证约束 ✅
写短一点 不超过200字
专业一些 包含至少3个行业术语
有趣一点 使用2个以上比喻或反问句
全面一些 覆盖5W1H(谁、什么、何时、何地、为何、如何)
温和一些 不使用"你错了""不对"等否定词

四、案例一:商品文案生成器(多变量注入)

电商场景标配,商品数据从数据库来,文案自动生成。

from langchain_core.prompts import ChatPromptTemplate

template = ChatPromptTemplate.from_messages([
    ("system", "你是资深电商文案策划,擅长用短文案激发购买欲"),
    ("human", """
商品名称:{name}
核心卖点:{selling_point}
目标人群:{audience}
价格:{price}

生成三段不同风格文案:
1. 朋友圈风格(带emoji,口语化)
2. 详情页风格(偏理性,带参数)
3. 直播话术风格(有互动感)
""")
])

prompt = template.invoke({
    "name": "便携式果汁杯",
    "selling_point": "无线充电、40秒榨汁",
    "audience": "25-35岁白领",
    "price": "299元"
})

关键点:多个变量可以来自不同数据源(商品库、价格系统、用户画像),模板层只负责组装。


五、案例二:客服回复生成器(多数据源聚合)

这个更接近真实业务流。

template = ChatPromptTemplate.from_messages([
    ("system", "你是专业客服,回复需:①安抚情绪 ②给方案 ③说后续步骤"),
    ("human", """
用户问题:{user_question}
订单号:{order_id}
订单状态:{order_status}
物流信息:{logistics}
预计解决时间:{eta}

生成200字以内回复,语气温和
""")
])

prompt = template.invoke({
    "user_question": "快递三天没更新了",
    "order_id": "ORD-20260721-0042",
    "order_status": "已发货",
    "logistics": "2026-07-20 15:32 从杭州发出",
    "eta": "2026-07-24 18:00前"
})

架构分层

┌─────────────────────────────────────┐
│           数据源层                    │
│  ┌─────────┐  ┌─────────┐          │
│  │订单系统  │  │物流系统  │          │
│  └─────────┘  └─────────┘          │
└──────────────┬──────────────────────┘
               ▼
┌─────────────────────────────────────┐
│           聚合层                     │
│  统一格式、筛选关键字段、计算ETA     │
└──────────────┬──────────────────────┘
               ▼
┌─────────────────────────────────────┐
│           Prompt模板层               │
│  变量注入 → 生成结构化消息列表       │
└──────────────┬──────────────────────┘
               ▼
┌─────────────────────────────────────┐
│           模型调用层                 │
└─────────────────────────────────────┘

Prompt层只管生成,不关心数据从哪来——这才是工程化的正确姿势。


六、工程落地小结

今天的内容可以浓缩成为:

场景 工具选择
单轮、无角色区分 PromptTemplate够用,但建议升级
多轮、有系统设定 直接上 ChatPromptTemplate
需要塞历史消息 用 MessagesPlaceholder 做插槽
变量来源复杂 模板只组装,数据由上游层提供

代码规范建议:

# 1. 所有模板统一放在 templates.py 或配置中心
# 2. 模板变量命名用 snake_case
# 3. 必填变量在 invoke 前做校验
# 4. 用 Pydantic 定义输入结构,不要裸传 dict

from pydantic import BaseModel

class ProductPromptInput(BaseModel):
    name: str
    selling_point: str
    audience: str
    price: str

# 校验通过后再 invoke
validated = ProductPromptInput(**raw_data)
prompt = template.invoke(validated.model_dump())

提高质量的三个追问:

  1. 模板里的系统角色够具体吗? —— 越具体输出越稳

  2. 每条约束能客观验证吗? —— 不能验证的约束都是废话

  3. 变量都来自上游经过校验的数据吗? —— 脏数据进去,垃圾文案出来

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐