同一套客服话术里,城市名、用户名、检索片段每次不同,把字符串拼进 f-string 很快无法维护,也难做单元测试。PromptTemplate / ChatPromptTemplate 把「模板 + 变量 dict」变成 Runnable:左侧进变量,右侧出格式化后的 messages 或字符串。
段末注释:PromptTemplate = 带占位符的提示词模板;ChatPromptTemplate 专用于 Chat 场景,输出 message 列表。
1. 一句话定位
| 维度 | 内容 |
|---|---|
| 角色 | 能力层提示组装:变量 → 结构化 prompt |
| 输入 → 输出 | dict(变量名→值)→ PromptValue / list[BaseMessage] |
| 典型调用入口 | prompt.invoke({"city": "北京"})、prompt | model |
| 与 LangGraph | 节点内可先 invoke prompt 再调 model;状态驱动动态 prompt 常用 middleware |
2. 实现逻辑
Chat 场景典型 LCEL:
1 | 1. 定义 ChatPromptTemplate.from_messages([("system", "..."), ("human", "{question}")]) |
字段级变形:
1 | {"city": "上海", "context": "文档A..."} |
3. 原理说明
3.1 PromptTemplate vs ChatPromptTemplate
PromptTemplate(数据类)
功能:单字符串模板,适合 completion 型 LLM。
数据结构:template: str(必填);input_variables: list[str](可从 { } 推断);partial_variables: dict = {};template_format="f-string"。
最小维度:template 非空;input_variables 可为 [](无占位符)。
1 | from langchain_core.prompts import PromptTemplate |
ChatPromptTemplate(数据类)
功能:多轮角色模板,invoke 产出 Chat Prompt Value(可 .to_messages()),对接 ChatModel。
默认值:无系统消息时只有你提供的角色。
最小维度:from_messages 的 list len ≥ 1。
1 | ChatPromptTemplate.from_messages([("human", "{q}")]) |
3.2 from_messages 元组语法
ChatPromptTemplate.from_messages(messages)(类方法)
功能:用 (role, template) 或 Message 对象组模板。role 常用 "system" / "human" / "ai"。
最小维度:至少 1 条;占位符名须与 invoke 的 dict 键一致。
MessagesPlaceholder(数据类)
功能:把已有 list[BaseMessage] 插入模板(多轮历史)。
| 字段 | 类型 | 默认值 | 最小维度 |
|---|---|---|---|
variable_name |
str | 必填 | 非空,如 "history" |
optional |
bool | False |
False 时缺键报错 |
n_messages |
int / None | None |
None=全部;截断时 ≥1 |
1 | from langchain_core.prompts import MessagesPlaceholder |
3.3 Partial 与默认值
partial(**kwargs)(方法)
功能:预填部分变量,返回新模板。剩余变量在 invoke 时传入。
默认值:未 partial 的变量仍必填。
最小维度:至少 1 个关键字;值须能填进对应 {占位符}。
1 | prompt.partial(lang="中文").invoke({"province": "浙江"}) |
3.4 Runnable 语义
Prompt 实现 Runnable:invoke(dict) → ChatPromptValue。| model 时左输出须与 ChatModel 输入兼容。stream 在 prompt 上通常一次产出完整 messages,流式发生在下游 model。
最小维度:invoke 的 dict 必须覆盖全部未 partial 的 input_variables(少一个 KeyError)。
4. 最小可运行示例
1 | pip install -U langchain-openai |
1 | from langchain_openai import ChatOpenAI |
重要配置参数
| 参数(API 名) | 类型 / 默认值 | 功能说明 | 作用与影响 | 参考起点 | 配置指导 |
|---|---|---|---|---|---|
input_variables |
list[str],可推断 | 声明模板里必须由 invoke dict 提供的占位符名 | 缺键 KeyError;多写无害 | 与模板 { } 一致 |
与 invoke 键逐字相同 |
template / messages |
str 或 list,必填 | 提示正文或角色消息列表 | 过长费 token;system 决定角色与格式 | 短 system + 明确 human | system 写角色与输出格式 |
partial_variables |
dict,默认 {} |
创建时预填部分变量,invoke 不必再传 | 减少调用方传参;改值须重新 partial | 固定语言、日期 | 动态输入不要 partial |
MessagesPlaceholder |
对象,可选 | 把已有 list[BaseMessage] 插入模板指定位置 |
缺历史且 optional=False 则报错 |
变量名 history |
多轮配合 MessageHistory |
validate_template |
bool,默认 True | 构造时检查 { } 与 input_variables 是否对齐 |
False 则把错误推迟到 invoke | True | 动态拼模板才关 |
output_parser(链上) |
Parser | 把 model 输出收成 str/JSON 等 | 类型选错则下游拿到错误形态 | StrOutputParser | 结构化用 with_structured_output |
5. 易踩坑
- 变量名与
{}不一致:{question}与 invoke 键query不匹配会 KeyError。 - 把 RAG context 不转义直接拼进模板:若 context 含
{会被当占位符;用PromptTemplate的 escape 或单独 message 字段。 - Chat 模型仍用纯 PromptTemplate 单字符串:可行但丢失 system/user 分界;优先 ChatPromptTemplate。
小结
- ChatPromptTemplate 输出 messages,是
prompt | model的标准左侧。 - partial 预填常量;MessagesPlaceholder 接多轮历史。
- Prompt 本身是 Runnable,可 batch、可进 fallback 链。
- 注意占位符与 RAG 片段中的花括号 冲突。