1. 本章目标 #

上一章讲清了 System / Human / AI / Tool 消息。前几章里,提示词却多是写死在代码字符串里。业务一复杂,常见问题是:

提示词不只是「给模型看的一段话」,更是业务系统里可维护的一层配置。本章目标:

用 Prompt / ChatPrompt 模板把提示词做成可维护的一层:变量填充、少样本、系统提示设计。

学完你应能:

参考(API 在 langchain_core.prompts):

2. 为什么需要 Prompt 层 #

把用户输入直接拼进长字符串,Demo 很快,业务一长大就疼:角色、历史、示例、变量全搅在一起,又难测又难改。

硬编码:
  model.invoke("你是客服……用户说:" + user_text)

模板化:
  prompt = ChatPromptTemplate.from_messages([...])
  messages = prompt.format_messages(user_text=user_text, ...)
  model.invoke(messages)

模板层把「提示长什么样」从调用现场抽出来:

收益 说明
结构清晰 system / human / ai 角色分开写
变量安全 缺变量会报错,少拼字符串 bug
可复用 同一模板服务多个入口(API、脚本、Agent)
可组合 历史占位、少样本、partial 预填

和 Agent 的关系要分清两层:

入口 管什么 典型用法
create_agent(system_prompt=...)(第 2 章) 驾驭层级人设 / 全局约束 助手是谁、何时必须调工具
ChatPromptTemplate 业务场景级提示 翻译模板、抽工单模板、带历史问答

两者常并存:Agent 有总人设,具体业务链仍用模板组织输入。第 6 章会把模板接到结构化输出上。

3. PromptTemplate:字符串模板 #

PromptTemplate 产出的是一整段文本,不是消息列表。
适合简单补全、非聊天协议,或只想把一段拼好的字符串塞进某个字段。

聊天模型场景下它也能用(字符串会被当成一条用户消息),但角色边界不清。
本章主推下一节的 ChatPromptTemplate;本节先建立「变量填充」的直觉。

3.1. 1.PromptTemplate.py #

# 从 langchain_core.prompts 导入 PromptTemplate,用于创建可填充变量的提示词模板
from langchain_core.prompts import PromptTemplate

# 从 langchain.chat_models 导入 init_chat_model,用于按名称初始化聊天模型
from langchain.chat_models import init_chat_model

# 从 dotenv 导入 load_dotenv,用于从 .env 文件加载环境变量
from dotenv import load_dotenv

# 加载 .env 中的环境变量;override=True 表示覆盖已存在的同名变量
load_dotenv(override=True)

# {name} 是待填变量;缺变量时 format 会报错
# 用字符串模板创建 PromptTemplate,其中 {name} 为运行时填充的变量
prompt = PromptTemplate.from_template("你是简洁助手。用户叫{name},请用一句话打招呼。")

# 将 name 填充为「张三」,得到完整提示词文本
text = prompt.format(name="张三")
# 打印填充后的提示词,便于确认模板结果
print(text)

# 初始化 DeepSeek 聊天模型,temperature=0 使输出更稳定、更少随机性
model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
# 用填充后的提示词调用模型,并打印返回消息的文本内容
print(model.invoke(text).content)

要点:

4. ChatPromptTemplate:对话模板(主推) #

现代聊天模型按「多条带角色的消息」工作。ChatPromptTemplate 正是为此而设计:

相对字符串模板,它更贴近真实对话状态,也更容易插入历史和少样本。

4.1. 2.ChatPromptTemplate.py #

下面示例故意在模板里放了一轮「假历史」(human/ai),用来演示:模板不仅可以填变量,还可以预置对话结构。

# 从 langchain_core.prompts 导入 ChatPromptTemplate,用于创建多角色对话提示词模板
from langchain_core.prompts import ChatPromptTemplate

# 从 langchain.chat_models 导入 init_chat_model,用于按名称初始化聊天模型
from langchain.chat_models import init_chat_model

# 从 dotenv 导入 load_dotenv,用于从 .env 文件加载环境变量
from dotenv import load_dotenv

# 加载 .env 中的环境变量;override=True 表示覆盖已存在的同名变量
load_dotenv(override=True)

# 用消息列表创建 ChatPromptTemplate,每条消息可含待填充变量
prompt = ChatPromptTemplate.from_messages(
    # 消息模板列表:按 system / human / ai / human 顺序组织对话
    [
        # 系统消息:设定助手人设,{name} 为运行时填充的变量
        ("system", "你是乐于助人的助手,名字叫{name}。回答要短。"),
        # 人类消息:模拟用户的开场问候
        ("human", "你好!"),
        # AI 消息:模拟助手的自我介绍回复,同样使用 {name} 变量
        ("ai", "你好,我是{name},有什么可以帮你?"),
        # 人类消息:用户真正的提问,{user_input} 为运行时填充的变量
        ("human", "{user_input}"),
    ]
)

# 填充全部变量 → 消息列表
# 将 name 与 user_input 填入模板,得到完整的消息对象列表
messages = prompt.format_messages(
    # 助手名字填充为「小助」
    name="小助",
    # 用户输入填充为询问名字的问题
    user_input="你叫什么名字?",
)
# 遍历填充后的每条消息,便于确认模板结果
for m in messages:
    # 打印消息类型名称与消息文本内容
    print(type(m).__name__, ":", m.content)

# 初始化 DeepSeek 聊天模型,temperature=0 使输出更稳定、更少随机性
model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
# 用填充后的消息列表调用模型,并打印返回消息的文本内容
print(model.invoke(messages).content)

调试习惯:先 print 填完后的 messages,确认角色顺序和变量都对,再调模型。

4.2. 管道写法预览(LCEL) #

第 7 章会系统讲 Runnable / LCEL。这里先建立直觉:

prompt | model = 先按变量填模板,再把消息列表交给模型。

调用方只传字典,不必再手写 format_messages + invoke 两步。

4.2.1. 3.prompt_pipe_model.py #

# 从 langchain_core.prompts 导入 ChatPromptTemplate,用于创建多角色对话提示词模板
from langchain_core.prompts import ChatPromptTemplate

# 从 langchain.chat_models 导入 init_chat_model,用于按名称初始化聊天模型
from langchain.chat_models import init_chat_model

# 从 dotenv 导入 load_dotenv,用于从 .env 文件加载环境变量
from dotenv import load_dotenv

# 加载 .env 中的环境变量;override=True 表示覆盖已存在的同名变量
load_dotenv(override=True)

# 用消息列表创建 ChatPromptTemplate,每条消息可含待填充变量
prompt = ChatPromptTemplate.from_messages(
    # 消息模板列表:按 system / human 顺序组织翻译任务对话
    [
        # 系统消息:设定翻译目标语言变量 {target_lang},并要求只输出译文
        ("system", "把用户句子翻译成{target_lang},只输出译文。"),
        # 人类消息:待翻译的原文,{text} 为运行时填充的变量
        ("human", "{text}"),
    ]
)
# 初始化 DeepSeek 聊天模型,temperature=0 使输出更稳定、更少随机性
model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)

# 用 LCEL 管道把「填模板 → 调模型」串成一条链
chain = prompt | model
# 传入目标语言与原文,调用整条链得到模型回复
ai = chain.invoke({"target_lang": "英文", "text": "生活不止眼前的代码"})
# 打印模型返回消息的文本内容(即译文)
print(ai.content)

数据流可以记成:

{"target_lang","text"}  →  ChatPromptTemplate  →  messages  →  model  →  AIMessage

5. MessagesPlaceholder:插入历史消息 #

普通 {var} 只能填充字符串。多轮对话要插入的是一整段消息对象列表(第 4 章的 HumanMessage / AIMessage 等),这时用 MessagesPlaceholder。

典型结构:

[SystemMessage]          ← 人设
[...history...]          ← MessagesPlaceholder 插入
[HumanMessage]           ← 当前问题

这和第 4 章手写 history.append(...) 是同一思路,只是把「历史插在哪」声明进了模板。

5.1. 4.MessagesPlaceholder.py #

# 从 langchain_core.prompts 导入 ChatPromptTemplate 与 MessagesPlaceholder,用于对话模板与历史消息占位
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

# 从 langchain.messages 导入 HumanMessage 与 AIMessage,用于构造人类与助手消息对象
from langchain.messages import HumanMessage, AIMessage

# 从 langchain.chat_models 导入 init_chat_model,用于按名称初始化聊天模型
from langchain.chat_models import init_chat_model

# 从 dotenv 导入 load_dotenv,用于从 .env 文件加载环境变量
from dotenv import load_dotenv

# 加载 .env 中的环境变量;override=True 表示覆盖已存在的同名变量
load_dotenv(override=True)

# 用消息列表创建 ChatPromptTemplate,支持插入历史与当前问题变量
prompt = ChatPromptTemplate.from_messages(
    # 消息模板列表:按 system / 历史占位 / human 顺序组织对话
    [
        # 系统消息:设定助手为简洁风格,并要求结合历史回答
        ("system", "你是简洁助手,结合历史回答。"),
        # 历史消息占位符:运行时插入名为 history 的消息对象列表
        MessagesPlaceholder("history"),
        # 人类消息:当前用户问题,{question} 为运行时填充的变量
        ("human", "{question}"),
        # 结束消息模板列表
    ]
    # 结束 ChatPromptTemplate.from_messages 调用
)

# 构造模拟的多轮对话历史,供 MessagesPlaceholder 插入
history = [
    # 人类消息:用户自称叫李雷
    HumanMessage("我叫李雷。"),
    # AI 消息:助手确认用户名字为李雷
    AIMessage("好的,李雷。"),
    # 结束历史消息列表
]

# 将 history 与 question 填入模板,得到完整的消息对象列表
messages = prompt.format_messages(
    # 把预先构造的历史消息列表填入 history 占位符
    history=history,
    # 当前问题填充为询问自己的名字
    question="我叫什么名字?",
    # 结束 format_messages 调用
)

# 遍历填充后的每条消息,便于确认模板结果
for m in messages:
    # 打印消息类型名称与消息文本内容
    print(type(m).__name__, ":", m.content)

# 初始化 DeepSeek 聊天模型,temperature=0 使输出更稳定、更少随机性
model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
# 用填充后的消息列表调用模型,并打印返回消息的文本内容
print(model.invoke(messages).content)

注意:

6. 少样本(Few-shot) #

少样本 = 在提示里放若干「输入 → 期望输出」例子,让模型模仿格式与风格。
口头规则(「请只输出标签」)往往不如「看两个例子照着做」稳,尤其是分类、抽取、固定格式输出。

三种写法由易到难:

写法 适合 产出形态
模板里直接写死 human/ai 示例 示例少、几乎不变 聊天消息
FewShotPromptTemplate 示例多、要统一文本格式 一整段字符串
FewShotChatMessagePromptTemplate 聊天模型 + 可维护示例列表 聊天消息对

原则:示例的输出格式必须和最终想要的格式一模一样(多一个句号、多一句解释,都会被模型学歪)。

6.1. 聊天消息里直接写死示例(最简单) #

适合示例少、几乎不变:直接把几组 ("human", ...) / ("ai", ...) 写进 from_messages。

6.1.1. 5.few_shot_inline.py #

# 从 langchain_core.prompts 导入 ChatPromptTemplate,用于创建多角色对话提示词模板
from langchain_core.prompts import ChatPromptTemplate

# 从 langchain.chat_models 导入 init_chat_model,用于按名称初始化聊天模型
from langchain.chat_models import init_chat_model

# 从 dotenv 导入 load_dotenv,用于从 .env 文件加载环境变量
from dotenv import load_dotenv

# 加载 .env 中的环境变量;override=True 表示覆盖已存在的同名变量
load_dotenv(override=True)

# 用消息列表创建 ChatPromptTemplate,内含系统指令、少样本示例与用户输入变量
prompt = ChatPromptTemplate.from_messages(
    # 消息模板列表:按 system / human / ai / human 顺序组织少样本对话
    [
        # 系统消息:规定情感分类标签,并要求模型只输出标签
        ("system", "将情感分类为:正面 / 负面 / 中性。只输出标签。"),
        # 少样本示例 1:正面情感的用户输入
        # 示例 1
        ("human", "今天天气真好,心情不错。"),
        # 少样本示例 1:对应的期望输出标签
        ("ai", "正面"),
        # 少样本示例 2:负面情感的用户输入
        # 示例 2
        ("human", "快递又丢了,太糟心了。"),
        # 少样本示例 2:对应的期望输出标签
        ("ai", "负面"),
        # 真正待分类的用户输入占位,{text} 为运行时填充的变量
        # 真正的用户输入
        ("human", "{text}"),
        # 结束消息模板列表
    ]
    # 结束 ChatPromptTemplate.from_messages 调用
)

# 初始化 DeepSeek 聊天模型,temperature=0 使输出更稳定、更少随机性
model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
# 用管道将提示词模板与模型串联成可调用链
chain = prompt | model
# 传入待分类文本调用链,并打印模型返回的情感标签
print(chain.invoke({"text": "这部电影一般般,不好不坏。"}).content)

期望输出应接近 中性(而不是一整句解释)。

6.2. FewShotPromptTemplate(字符串少样本) #

当示例变多、又希望统一管理「每条示例长什么样」时,用:

examples 列表
    + example_prompt(单条怎么格式化)
    + prefix / suffix(任务说明与真正输入)
→ 拼成一整段文本

它更偏字符串侧,常和 PromptTemplate 一起用。

6.2.1. 6.FewShotPromptTemplate.py #

# 从 langchain_core.prompts 导入 PromptTemplate 与 FewShotPromptTemplate,用于创建字符串模板与少样本提示词模板
from langchain_core.prompts import PromptTemplate, FewShotPromptTemplate

# 从 langchain.chat_models 导入 init_chat_model,用于按名称初始化聊天模型
from langchain.chat_models import init_chat_model

# 从 dotenv 导入 load_dotenv,用于从 .env 文件加载环境变量
from dotenv import load_dotenv

# 加载 .env 中的环境变量;override=True 表示覆盖已存在的同名变量
load_dotenv(override=True)

# 定义少样本示例列表,每项包含词语及其反义词
examples = [
    # 示例 1:词语「开心」对应反义词「难过」
    {"word": "开心", "antonym": "难过"},
    # 示例 2:词语「高」对应反义词「矮」
    {"word": "高", "antonym": "矮"},
    # 结束少样本示例列表
]

# 用字符串模板创建单条示例的 PromptTemplate,规定「词语 / 反义词」的展示格式
example_prompt = PromptTemplate.from_template("词语:{word}\n反义词:{antonym}")

# 用示例列表、单例模板与前后缀组装 FewShotPromptTemplate
few_shot = FewShotPromptTemplate(
    # 传入少样本示例列表,供模板逐条格式化后拼入提示词
    examples=examples,
    # 传入单条示例的格式化模板
    example_prompt=example_prompt,
    # 前缀:说明任务目标,并要求参照示例格式作答
    prefix="给出词语的反义词。参照示例格式作答。\n",
    # 后缀:放置真正待求反义词的输入占位,并以「反义词:」引导模型续写
    suffix="\n词语:{input}\n反义词:",
    # 声明运行时需要填充的变量名为 input
    input_variables=["input"],
    # 结束 FewShotPromptTemplate 构造
)

# 将 input 填充为「冷」,得到完整的少样本提示词文本
text = few_shot.format(input="冷")
# 打印填充后的提示词,便于确认模板结果
print(text)

# 初始化 DeepSeek 聊天模型,temperature=0 使输出更稳定、更少随机性
model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
# 用填充后的提示词调用模型,并打印返回消息的文本内容
print(model.invoke(text).content)

建议先 print(text) 看拼出来的全文:prefix、每条示例、suffix 是否按预期排列。

6.3. FewShotChatMessagePromptTemplate(聊天少样本) #

把示例也做成 human/ai 消息对,更贴合 Chat Model,也更容易和 ChatPromptTemplate 嵌套组合。

结构通常是:

system
few_shot_prompt  → 展开成多组 human/ai
human(真正输入)

6.3.1. 7.FewShotChatMessagePromptTemplate.py #

# 从 langchain_core.prompts 导入 ChatPromptTemplate 与 FewShotChatMessagePromptTemplate,用于聊天提示词与少样本聊天模板
from langchain_core.prompts import (
    # 导入 ChatPromptTemplate,用于创建多角色对话提示词模板
    ChatPromptTemplate,
    # 导入 FewShotChatMessagePromptTemplate,用于构建聊天消息形式的少样本提示
    FewShotChatMessagePromptTemplate,
    # 结束 from langchain_core.prompts 的导入
)

# 从 langchain.chat_models 导入 init_chat_model,用于按名称初始化聊天模型
from langchain.chat_models import init_chat_model

# 从 dotenv 导入 load_dotenv,用于从 .env 文件加载环境变量
from dotenv import load_dotenv

# 加载 .env 中的环境变量;override=True 表示覆盖已存在的同名变量
load_dotenv(override=True)

# 定义少样本示例列表,每项包含输入算式与期望输出
examples = [
    # 示例 1:输入「2+2」对应输出「4」
    {"input": "2+2", "output": "4"},
    # 示例 2:输入「2+3」对应输出「5」
    {"input": "2+3", "output": "5"},
    # 结束少样本示例列表
]

# 用消息列表创建单条示例的 ChatPromptTemplate,规定 human/ai 消息对格式
example_prompt = ChatPromptTemplate.from_messages(
    # 消息模板列表:按 human / ai 顺序组织单条少样本示例
    [
        # 人类消息:示例中的用户输入,{input} 为示例变量
        ("human", "{input}"),
        # AI 消息:示例中的期望输出,{output} 为示例变量
        ("ai", "{output}"),
        # 结束消息模板列表
    ]
    # 结束 ChatPromptTemplate.from_messages 调用
)

# 用示例列表与单例模板组装 FewShotChatMessagePromptTemplate
few_shot_prompt = FewShotChatMessagePromptTemplate(
    # 传入少样本示例列表,供模板逐条格式化为消息对后拼入提示词
    examples=examples,
    # 传入单条示例的消息格式化模板
    example_prompt=example_prompt,
    # 结束 FewShotChatMessagePromptTemplate 构造
)

# 用消息列表创建最终 ChatPromptTemplate,串联系统指令、少样本与用户输入
final_prompt = ChatPromptTemplate.from_messages(
    # 消息模板列表:按 system / few-shot / human 顺序组织完整对话
    [
        # 系统消息:设定助手为算术助手,并要求只输出最终数字
        ("system", "你是算术助手。只输出最终数字。"),
        # 插入少样本聊天消息模板,运行时展开为多组 human/ai 示例
        few_shot_prompt,
        # 人类消息:真正待计算的用户输入,{input} 为运行时填充的变量
        ("human", "{input}"),
        # 结束消息模板列表
    ]
    # 结束 ChatPromptTemplate.from_messages 调用
)

# 初始化 DeepSeek 聊天模型,temperature=0 使输出更稳定、更少随机性
model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
# 用管道将最终提示词模板与模型串联成可调用链
chain = final_prompt | model
# 传入待计算算式调用链,并打印模型返回的最终数字
print(chain.invoke({"input": "10+8"}).content)

聊天场景优先这种写法;字符串版更多留给非对话场景,或需要导出纯文本 prompt 的场合。

7. partial:预填部分变量 #

一个模板里往往既有「几乎不变」的变量(租户名、产品线、固定角色),也有「每次请求都变」的变量(用户问题)。

partial 的作用:把前者先锁死,得到一个变量更少的新模板;调用时只需传业务变量。

base(role, user_name, question)
        │ partial(role=..., user_name=...)
        ▼
prompt(question)   ← 调用方更简单

适合多租户、多产品共用同一骨架、只换几个固定字段的场景。

7.1. 8.partial.py #

# 从 langchain_core.prompts 导入 ChatPromptTemplate,用于创建多角色对话提示词模板
from langchain_core.prompts import ChatPromptTemplate

# 从 langchain.chat_models 导入 init_chat_model,用于按名称初始化聊天模型
from langchain.chat_models import init_chat_model

# 从 dotenv 导入 load_dotenv,用于从 .env 文件加载环境变量
from dotenv import load_dotenv

# 加载 .env 中的环境变量;override=True 表示覆盖已存在的同名变量
load_dotenv(override=True)

# 用消息列表创建基础 ChatPromptTemplate,含角色、用户名与问题变量
base = ChatPromptTemplate.from_messages(
    # 消息模板列表:按 system / human 顺序组织对话
    [
        # 系统消息:设定助手角色 {role}、面向用户 {user_name},并要求回答简短
        ("system", "你是{role},面向用户{user_name},回答要短。"),
        # 人类消息:用户当前问题,{question} 为运行时填充的变量
        ("human", "{question}"),
        # 结束消息模板列表
    ]
    # 结束 ChatPromptTemplate.from_messages 调用
)

# 预填角色与用户名,只剩 question
prompt = base.partial(role="售后顾问", user_name="王女士")

# 初始化 DeepSeek 聊天模型,temperature=0 使输出更稳定、更少随机性
model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
# 用管道将预填后的提示词模板与模型串联成可调用链
chain = prompt | model
# 传入用户问题调用链,并打印模型返回消息的文本内容
print(chain.invoke({"question": "订单两天了还没发货,怎么办?"}).content)

PromptTemplate.partial(...) 同理。
也可以 partial 出两套链:prompt_a = base.partial(product_name="A")、prompt_b = base.partial(product_name="B"),再对比回答差异。

8. 系统提示设计 #

系统提示写得好,往往比堆很多 few-shot 更划算:成本低、意图清晰、边界明确。
可按下面六段组织(不必每次全写,但要想清楚有没有漏项):

1. 角色:你是谁
2. 目标:要完成什么
3. 能力与边界:能做什么 / 不能做什么
4. 工具策略:何时必须调工具(若有)
5. 输出格式:长短、语言、是否 JSON
6. 失败行为:信息不足时怎么问澄清

和 Agent 的关系:

两者可以叠加,但不要互相打架(例如一边说「尽量简短」,一边又要求长篇分析)。

8.1. 9.system_prompt_design.py #

# 从 langchain_core.prompts 导入 ChatPromptTemplate,用于创建多角色对话提示词模板
from langchain_core.prompts import ChatPromptTemplate

# 从 langchain.chat_models 导入 init_chat_model,用于按名称初始化聊天模型
from langchain.chat_models import init_chat_model

# 从 dotenv 导入 load_dotenv,用于从 .env 文件加载环境变量
from dotenv import load_dotenv

# 加载 .env 中的环境变量;override=True 表示覆盖已存在的同名变量
load_dotenv(override=True)

# 定义系统提示词:设定电商售后助手角色、目标、边界与输出格式,并用 strip 去掉首尾空白
SYSTEM = """
你是电商售后助手。

目标:用最短步骤帮用户解决问题。

边界:
- 不承诺未核实的退款时效
- 不知道物流状态时,请用户提供订单号

输出:
- 先给结论(1 句)
- 再给 1~3 条可执行步骤
- 使用中文
""".strip()

# 用消息列表创建 ChatPromptTemplate,串联系统提示与用户问题
prompt = ChatPromptTemplate.from_messages(
    # 消息模板列表:按 system / human 顺序组织对话
    [
        # 系统消息:使用上方定义的 SYSTEM 提示词
        ("system", SYSTEM),
        # 人类消息:用户当前问题,{question} 为运行时填充的变量
        ("human", "{question}"),
        # 结束消息模板列表
    ]
    # 结束 ChatPromptTemplate.from_messages 调用
)

# 初始化 DeepSeek 聊天模型,temperature=0 使输出更稳定、更少随机性
model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
# 打印模型对用户问题的回复文本内容
print(
    # 用管道将提示词模板与模型串联成可调用链
    (prompt | model)
    # 传入用户问题调用链,询问快递长时间显示运输中的情况
    .invoke({"question": "我的快递一直显示运输中,已经五天了。"})
    # 取出返回消息的文本内容
    .content
)

改系统提示后,先固定几条测试问句做回归,比凭感觉改完就上线更靠谱。

9. 可维护性建议 #

模板层一旦进业务,就要当「配置」来维护,而不是当一次性字符串。

做法 说明
模板与业务代码分离 模板集中定义,入口只 invoke 变量
先 format 再调模型 出问题先 print(messages),别先怪模型
少样本要「像真输出」 示例格式必须和期望的最终格式一致
变量命名稳定 {question} / {context} 全项目统一
敏感信息不进 prompt 密钥、身份证等不要拼进模板
用 LangSmith 对比版本 改 prompt 前后对照 trace / 评测集

口诀:

结构用模板,格式靠 few-shot,边界写进 system;改完先 print messages。

10. 练习 #

  1. 翻译模板:用 ChatPromptTemplate 做「源语言 / 目标语言 / 文本」三变量翻译链。
  2. 带历史客服:MessagesPlaceholder("history") + 两轮假历史,问第三轮是否记得用户名。
  3. 情感分类 few-shot:至少 3 条示例,测 5 句新文本,看标签是否稳定。
  4. partial 多租户:同一模板 partial(product_name=...) 出两套「不同产品」的助手,对比回答。

11. 本章小结 #

  1. Prompt 层把提示词从散落字符串变成可复用组件。
  2. 聊天场景主用 ChatPromptTemplate;需要整段文本时用 PromptTemplate。
  3. MessagesPlaceholder 插入消息历史;few-shot 用示例教格式。
  4. partial 预填固定变量;系统提示写清角色、边界、输出格式。
  5. prompt | model 是后续 LCEL 的起点。

下一章:结构化输出——用 Pydantic / Structured Output 抽出订单、工单等稳定结构。