系列文章
LangChain 1.0 入门(一):Runnable 统一接口全解析(含完整代码+逐行输出解读)
LangChain 1.0 入门(二):LangChain 全模型标准化接入最佳实践(小白参数详解版)
LangChain 1.0 入门(三):稳定性双核心------重试机制+速率限速器参数详解与实战
LangChain 1.0 入门(四): Messages 深度解析------大模型对话上下文核心单元
LangChain 1.0 入门(五):提示词工程、partial变量、ChatPromptTemplate、Hub模板库
前言
提示词工程(Prompt Engineering)是大模型应用开发的核心环节,手写字符串拼接提示词难以维护、无法迭代调优。LangChain‑Core 的 Prompt 模板体系,就是把提示词工程代码化、工程化。本文先讲解提示词工程基础方法论,再结合 RAG知识库问答、代码助手、企业客服、Agent 系统指令真实业务场景,讲解API、核心参数、partial半成品模板、对话模板、LangSmith Hub模板仓库、生产踩坑与最佳实践,附带完整可运行Python示例。
环境依赖:
langchain‑core>=0.2.x,LangChain1.0生态;适配RAG、智能客服、内部助手、文档解析业务。
导入提醒:LangChain1.0全部从langchain_core导入,废弃旧路径langchain.prompts
python
from langchain_core.prompts import PromptTemplate, ChatPromptTemplate
一、提示词工程(Prompt Engineering)基础介绍
1.1 什么是提示词工程
提示词工程,指通过设计、编写、调优输入给大模型的指令文本,引导大模型按照预期的格式、逻辑、约束输出结果,而不是单纯写一句提问。
大模型本身不理解业务,它的行为完全由输入提示词来定义:你告诉它是什么角色、要做什么事、遵循什么规则、输出什么格式,模型就会对应产出内容。
传统方式:直接硬编码字符串写Prompt,适合Demo;
工程化方式:使用模板组件管理Prompt,适合线上业务系统。
1.2 高质量提示词五大核心要素
一套生产可用的提示词通常包含5部分,这也是我们写模板时需要拆解的模块:
- 角色设定(Role):AI是什么身份,例如:后端代码评审专家、企业知识库客服、技术文档摘要助手;
- 任务指令(Instruction):明确告诉模型要完成的具体工作,不能模糊;
- 上下文输入(Context):外部输入信息,用户问题、检索知识库、待处理文档、代码片段;
- 约束规则(Constraints):边界条件,禁止编造、输出格式、字数限制、语气风格;
- 输出示例(Few‑shot):给1~2个输入输出样例,引导模型对齐输出格式。
反面案例(差的提示词):
帮我分析这段代码
- 没有角色,没有约束,输出不可控;
正面案例(高质量提示词):
你是Python后端代码评审专家【角色】 任务:对传入代码做安全与性能评审,输出问题清单和修复代码【指令】 待评审代码:{code_snippet}【上下文】 约束:只输出Markdown格式,不做无关闲聊,没有问题就输出"代码无明显风险"【约束】
1.3 提示词工程面临的工程痛点
手工写Prompt在项目迭代中会遇到现实问题,这就是PromptTemplate要解决的问题:
- 提示词五大要素混杂在业务代码,角色、规则散落在各个接口,修改一处要改多处;
- 部分内容固定不变(角色、约束规则),部分内容每次请求动态变化(用户问题、检索上下文),每次调用重复拼接;
- Few‑shot示例很长,硬编码在业务代码可读性极差;
- 无法版本管理提示词,调优Prompt只能改代码发布;
- RAG、Agent场景,system系统指令反复复制粘贴,容易漏写某一条约束,造成模型输出异常;
- 很难复用社区已经调优好的成熟提示词。
Prompt模板的本质:把提示词工程的五大要素进行拆分管理,固定内容预填充,动态内容做变量插值。
二、为什么要使用Prompt模板?
在项目中直接使用f‑string拼接提示词,生产环境痛点:
- 系统角色、输出格式散落在业务各处,修改Prompt需要多处改代码;
- RAG场景,系统指令固定,用户问题、检索上下文每次动态变化,重复传参极易漏参;
- 对话模型需要维护
system/human/ai消息数组,字符串拼接极易出错; - Prompt无法版本管理,无法复用社区经过调优的成熟提示词;
- 变量内容包含换行、特殊符号,手动拼接容易出现格式错乱。
Prompt模板核心目标:提示词与业务逻辑解耦,模板可复用、可维护、可版本管理,实现提示词工程落地。
三、PromptTemplate 普通字符串模板
适用于:非对话大模型、文本生成、摘要、关键词提取等文本处理场景,模板内部使用{变量名}作为占位符。
3.1 from_template 快速创建(调试、原型开发)
自动解析模板中大括号占位符,自动推导input_variables,适合快速验证提示词工程想法。
业务示例场景:文档摘要生成
python
from langchain_core.prompts import PromptTemplate
# 业务:对输入文档片段做内容摘要,max_words控制摘要字数
prompt_template = PromptTemplate.from_template(
"""【角色】文档摘要助手
【任务指令】请对下面文档片段做内容摘要
【约束】摘要控制在{max_words}字以内,保留核心技术信息,不要冗余描述
【待处理文档】
{document_content}
【输出摘要】:"""
)
# format填充业务变量,渲染出最终prompt字符串
formatted_prompt = prompt_template.format(
max_words=150,
document_content="""LangChain‑Core是LangChain1.0的核心基础库,提供Prompt模板、消息结构、LCEL链式原语,不绑定任何大模型,可以对接各类国产以及海外大模型,用于快速搭建LLM应用。"""
)
print(formatted_prompt)
3.2 显式对象实例化(生产环境推荐)
手动显式声明input_variables,代码可读性强,启动阶段校验模板合法性。
PromptTemplate核心参数表
| 参数 | 说明 |
|---|---|
input_variables |
必填变量列表,.format()必须传入;一般为用户输入、检索文档、业务数据 |
template |
原始提示词模板字符串,使用{var}占位插值,存放角色、指令、约束、占位上下文 |
partial_variables |
预填静态固定变量;模板定义阶段赋值,后续可以被.partial()覆盖 |
validate_template |
布尔,校验占位符和变量是否匹配,开发环境建议True |
template_format |
模板语法,默认f‑string;可选mustache |
业务示例:内部技术文档关键词提取
python
from langchain_core.prompts import PromptTemplate
template = PromptTemplate(
input_variables=["doc_text", "extract_count"],
template="""
【角色】技术文档关键词提取助手
【任务】从下面技术文档中提取{extract_count}个核心业务关键词
【约束】只输出关键词,逗号分隔,不要多余解释
【文档内容】
{doc_text}
关键词输出:""",
validate_template=True
)
prompt_text = template.format(
doc_text="昇腾NPU基于CANN算子库,支持vLLM推理框架,通过Docker容器部署大模型服务。",
extract_count=4
)
print(prompt_text)
⚠️注意点:
- 占位符必须是英文大括号
{var},中文全角{}无法识别;- 如果需要输出字面
{}符号,写双大括号转义{``{ }}。
四、partial_variables / partial() 半成品模板(生产高频,提示词工程利器)
结合提示词工程五要素来看:
- 固定不变部分:角色设定、任务指令、约束规则、Few‑shot示例,几乎不会随每次请求变化;
- 动态变化部分:用户query、检索上下文、待处理文档,每次请求都不一样。
partial能力:提前填充角色、指令、约束这些固定提示词片段,得到半成品模板;只把动态业务内容留给后续format传入。避免每次调用重复传入一大段系统提示词。
两种用法:
- 构造对象:
partial_variables={...}静态预填固定值; - 运行时
.partial(**kwargs):支持覆盖旧值,支持传入函数做动态变量。
4.1 静态partial_variables 模板定义时预填
业务场景:企业内部技术问答助手,角色、输出约束固定,仅用户问题动态传入
python
from langchain_core.prompts import PromptTemplate
template = PromptTemplate(
input_variables=["user_query"],
template="""
【角色】公司内部技术知识库问答助手
【任务】回答员工技术问题
{answer_rule}
用户提问:{user_query}
回答:
""",
partial_variables={
"answer_rule": """【约束】
1. 只基于已有知识库内容回答,不知道直接回复"知识库未收录该问题"
2. 条理清晰分点作答,不要编造信息
3. 技术问题优先给出可执行操作步骤"""
}
)
# format 仅需要传入动态的 user_query
prompt = template.format(user_query="昇腾环境如何安装vLLM?")
print(prompt)
4.2 .partial() 运行时覆盖预填变量
同一套模板,不同业务场景动态切换提示词约束;对内技术人员输出详细,对外业务人员输出通俗。
python
# 覆盖预设回答规则,切换面向普通业务人员模式
prompt = template.partial(answer_rule="""【约束】
1. 语言通俗易懂,尽量少用专业术语
2. 不知道直接回复"知识库未收录该问题"
""").format(user_query="昇腾环境如何安装vLLM?")
print(prompt)
4.3 partial高级用法:传入函数生成动态变量
重要:
partial_variables静态字典不支持函数 ;只有.partial()支持传入函数。典型场景:注入当前时间、链路TraceId,丰富提示词上下文信息。
python
from datetime import datetime
from langchain_core.prompts import PromptTemplate
def get_current_datetime():
"""获取当前服务时间,模板渲染时自动执行"""
return datetime.now().strftime("%Y‑%m‑%d %H:%M:%S")
base_template = PromptTemplate(
input_variables=["question"],
template="""
【请求时间】{server_time}
【角色】业务咨询助手
用户业务咨询:{question}
回答:"""
)
# partial传入函数,渲染时自动调用执行
partial_tpl = base_template.partial(server_time=get_current_datetime)
final_prompt = partial_tpl.format(question="如何查询接口调用报错日志?")
print(final_prompt)
input_variables 与 partial变量对比
| 项目 | input_variables | partial_variables / .partial() |
|---|---|---|
| 是否必须format传入 | ✅必须 | ❌不需要 |
| 填入时机 | .format()每次业务调用 |
模板定义 / 运行时.partial() |
| 是否支持覆盖 | ✅ | ✅后调用覆盖先前值 |
| 是否支持函数 | ❌ | ✅仅.partial()支持函数 |
| 提示词工程对应模块 | 上下文、用户输入 | 角色、任务指令、约束规则、Few‑shot示例 |
✅生产最佳实践:RAG、Agent把角色、任务、约束规则全部放到partial预填;业务调用只传用户输入和检索结果,减少漏参bug。
五、ChatPromptTemplate对话消息模板(项目首选)
现在绝大多数LLM都是对话接口,接收消息数组,天然对应提示词工程的模块拆分:
system:存放角色、全局任务指令、约束规则(提示词工程核心固定部分)human:存放用户输入、待处理上下文ai:Few‑shot示例,历史对话回复
ChatPromptTemplate.from_messages()组装消息列表,每条消息内部同样支持{变量}插值。
关键区分:
PromptTemplate.format()返回字符串;ChatPromptTemplate.format_messages()返回消息对象列表,直接喂给聊天模型model.invoke(messages)。
业务示例场景:代码审查助手
python
from langchain_core.prompts import ChatPromptTemplate
chat_template = ChatPromptTemplate.from_messages([
("system", """
【角色】后端Python代码评审专家
【任务】对代码做安全、异常捕获、资源泄漏、代码规范评审
【约束】输出Markdown格式,列出风险点,给出修改后的完整代码
"""),
("human", "待评审代码片段:\n```python\n{code_snippet}\n```"),
("ai", "【问题摘要】1.缺少异常捕获;2.文件句柄未做安全关闭"), # Few‑shot输出示例
("human", "{user_follow_command}")
])
messages = chat_template.format_messages(
code_snippet="""
def read_file(file_path):
f = open(file_path,"r")
return f.read()
""",
user_follow_command="请输出修复之后完整可运行代码,同时逐条说明改动点"
)
# 打印消息结构
for msg in messages:
print(f"\n【角色】{msg.type}")
print(f"【内容】\n{msg.content}")
# response = model.invoke(messages)
元组简写映射:
("system", "内容")→SystemMessage("human", "内容")→HumanMessage("ai", "内容")→AIMessage
ChatPromptTemplate同样支持
.partial()预填system里面的角色、约束规则,RAG开发中非常高频。
六、LangSmith Hub 拉取社区成熟Prompt模板
提示词工程不一定全部从零手写,大量经过调优的提示词存放在LangSmith Hub,RAG、文本分类、摘要、Agent提示词直接拉取使用,支持版本标记,方便迭代提示词。
官网:https://smith.langchain.com/hub
前置准备:
- 注册LangSmith账号,获取
LANGSMITH_API_KEY; - 安装依赖:
pip install langsmith python‑dotenv; .env配置环境变量。
业务示例:拉取官方标准RAG提示词,官方模板内部已经封装好角色、任务、约束规则
python
import os
from dotenv import load_dotenv
from langsmith import Client
load_dotenv()
client = Client(api_key=os.getenv("LANGSMITH_API_KEY"))
# 拉取官方RAG提示模板 rlm/rag‑prompt,线上不要每次请求拉取,应用启动阶段拉取一次
prompt = client.pull_prompt("rlm/rag‑prompt")
formatted_prompt = prompt.format(
context="""vLLM是一款高性能大模型推理服务框架,支持PagedAttention,大幅提升吞吐量,可以在昇腾NPU上通过vLLM‑Ascend适配部署。""",
question="vLLM推理框架核心优势是什么?"
)
print(formatted_prompt)
# response = model.invoke(formatted_prompt)
⚠️生产注意事项:
pull_prompt是网络IO,禁止每次HTTP业务请求调用拉取;应用启动时全局拉取一次缓存;- 使用版本号锁定模板,例如
rlm/rag‑prompt:v1,避免官方模板更新导致业务逻辑突变; include_model=True会附带模型配置,国产大模型建议关闭该参数;- 增加try‑except捕获网络超时异常。
七、LCEL链式调用结合Prompt模板(线上标准写法)
模板不需要手动调用format_messages,直接通过管道符|和模型组成chain,输入字典自动填充模板变量。
python
from langchain_core.prompts import ChatPromptTemplate
# from langchain_openai import ChatOpenAI
# llm = ChatOpenAI(model="gpt‑4o‑mini")
# RAG问答模板,partial预填system中角色、任务、约束(提示词工程固定部分)
rag_chat_prompt = ChatPromptTemplate.from_messages([
("system", """
【角色】企业内部知识库助手
【任务】基于检索到的上下文回答用户问题
{limit_rule}"""),
("human", "参考上下文:\n{context}\n用户问题:{question}")
]).partial(limit_rule="""
【约束】
1. 仅依赖上下文信息回答;
2. 不知道就如实说明,禁止编造知识库不存在信息;
3. 回答分点简洁输出。
""")
# LCEL构建链路
# rag_chain = rag_chat_prompt | llm
# resp = rag_chain.invoke({
# "context":"检索回来的知识库文本......",
# "question":"用户实际提问"
# })
八、提示词工程 + PromptTemplate高频踩坑清单
- 提示词五要素缺失:只写问题,缺少角色、约束,模型输出不可控;
- 变量名大小写敏感,占位符key与传入字典key不一致直接抛出
KeyError; - 区分
format()返回字符串、format_messages()返回消息对象;对话模型误用format会导致报错; partial_variables静态字典不能放函数;动态函数变量只能用.partial(func=xxx);- 字面输出
{}符号,使用双大括号{``{}}转义; .partial()多次调用,后调用的同名变量覆盖前面,可以用来动态切换提示词约束;- Hub拉取模板要做启动缓存,不能每一次请求走网络;
- 检索上下文context为大文本时,要做长度截断,防止超出模型上下文窗口;
- Few‑shot示例不要硬编码在业务逻辑,放到system消息或者partial预填。
九、业务选型建议表
| 业务场景 | 推荐组件 |
|---|---|
| 文本摘要、关键词提取、非对话模型 | PromptTemplate |
| 对话大模型、RAG问答、智能客服、代码助手 | ChatPromptTemplate(优先) |
| 角色、任务、约束规则固定,仅输入动态变化 | ChatPromptTemplate + .partial()预填提示词固定片段 |
| 复用社区调优Prompt、提示词需要版本管理 | LangSmith Hub pull_prompt,启动缓存 |
十、总结
- 提示词工程核心:通过角色、任务指令、上下文、约束规则、Few‑shot示例引导大模型输出符合业务预期;
PromptTemplate用于普通字符串模板;ChatPromptTemplate处理system/human/ai结构化消息,是LLM业务开发首选;- 在模板体系中,
partial()专门存放提示词工程的角色、指令、约束规则,input_variables存放动态上下文;实现提示词的模块化; - LangSmith Hub可以复用成熟提示词,但线上必须缓存,规避网络开销;
- Prompt模板工程化的核心思想,就是把提示词工程从零散字符串变成可维护、可调试、可版本迭代的业务组件。