前面三篇讲了 Runnable 协议和 LCEL 管道。从这篇开始,我们把底层 core 的几块具体积木逐个拆开。第一块,是和 LLM 打交道时最常写的——prompt

这一篇讲 PromptTemplate。但它要解决的核心问题,不是「怎么写好一段 prompt 文案」(那是另一门学问),而是怎么把散落在代码里的 prompt 文案,变成可复用、可管理的组件

先看问题:prompt 散落是技术债

很多人写 LLM 应用,prompt 是直接拼字符串的:

# 散落在业务代码里的 prompt
result = model.invoke(f"你是一个客服,用户问:{question},请回答:{context}")

这种写法在 demo 阶段没问题,一旦认真做应用,立刻暴露三个问题:

  • 难复用:同一段 prompt 在多处用,复制粘贴,改一处忘改另一处
  • 难维护:prompt 一改就要动业务代码,不能独立迭代
  • 难测试:想测 prompt 在不同输入下的效果,得把整个调用链跑起来

prompt 散落在代码里的问题

PromptTemplate 要解决的,就是把 prompt 从「散落的字符串」变成「独立的、可复用的组件」。

PromptTemplate:固定文案 + 变量

PromptTemplate 的思路很朴素:把 prompt 拆成「固定文案」和「变量」两部分。固定文案写死在模板里,变量在运行时填入。

from langchain_core.prompts import ChatPromptTemplate

prompt = ChatPromptTemplate.from_template(
    "你是一个客服,用户问:{question},请结合以下资料回答:{context}"
)

# 运行时填变量
prompt.invoke({"question": "怎么退款", "context": "退款政策..."})

这样带来三个直接收益:

  • 可复用:模板定义一次,到处用
  • 可独立迭代:改 prompt 不动业务代码
  • 可测试:传不同变量,看模板渲染成什么,不用跑整条链

PromptTemplate:固定文案 + 变量

关键:PromptTemplate 也是 Runnable

这是容易被忽略但很重要的一点——PromptTemplate 本身就是一个 Runnable

这意味着它有上一篇讲的所有能力:invoke 填变量、batch 批量填、stream 流式渲染、能被管道符 | 串进链。所以前面那个 prompt | model | parser 里的 prompt,就是 PromptTemplate。

# prompt 是 Runnable,能进管道
chain = prompt | model | parser
chain.invoke({"question": "怎么退款", "context": "..."})

这就把 prompt 从「写死在代码里的字符串」提升成了「链里的一等公民」——它和 model、parser 平起平坐,都是可组合的积木。

ChatPromptTemplate 与消息角色

和模型对话时,prompt 不是一段平铺文本,而是带角色的消息序列:系统消息(system,定基调)、用户消息(human,提需求)、AI 消息(ai,之前的回答)。

ChatPromptTemplate 就是处理这种「带角色的消息序列」的模板:

聊天消息的三种角色

角色 含义 典型用途
System 系统设定,定角色和规则 「你是客服,回答要简洁」
Human 用户输入 「怎么退款」
AI 模型之前的回答 「退款流程是……」

为什么要区分角色?因为模型对不同角色的内容,权重不一样:system 消息被视为「指令」,模型会强烈遵循;human 是「请求」;ai 是「上下文」(尤其在多轮对话里,ai 消息构成历史)。把 prompt 拆成角色消息,能更精确地控制模型行为。

prompt = ChatPromptTemplate.from_messages([
    ("system", "你是客服,回答简洁,只基于提供的资料"),
    ("human", "用户问题:{question}"),
])

模板的核心价值:prompt 与代码解耦

讲到这里,PromptTemplate 的真正价值就清楚了:它实现了 prompt 和业务代码的解耦

  • 业务代码只负责「拿到变量,调链」
  • prompt 文案集中在模板里,由写 prompt 的人(可能不是写代码的人)独立维护
  • 改 prompt 效果,可以不动一行业务代码,直接改模板

prompt 与业务代码解耦

这点在团队协作时尤其重要:产品/运营想调 prompt 措辞,不用拉上开发改代码上线;开发改业务逻辑,也不用担心碰到 prompt。两者的迭代节奏解开了。

收束:prompt 是一等公民

这一篇讲了 PromptTemplate:

  • 它把 prompt 从散落的字符串,变成「固定文案 + 变量」的模板
  • 它是 Runnable,能进管道、能批量、能流式
  • ChatPromptTemplate 处理带角色的消息(system/human/ai)
  • 核心价值是 prompt 与业务代码解耦

下一篇讲和 prompt 配对的另一块积木——输出解析器。prompt 负责把输入喂给模型,解析器负责把模型的自由文本回答,变成程序能消费的结构化数据。这两块一起,才构成完整的 Model I/O。


关于十三Tech

我是十三,All in AI Agent 方向的架构师,专注 AI 工程实践。我相信 AI 是程序员的最佳搭档。

如果你想跟完这套「图解 LangChain」,欢迎关注公众号 「十三Tech」。全系列 42 篇,会按认识基础、LangGraph 状态机、Agent 与 middleware、RAG 检索、Tools/MCP/记忆、生产化收束这条线更新。

十三Tech公众号二维码