LangChain系列 3: 提示词工程最佳实践
首先创建一组问答样例,明确任务的输入输出格式:python# 定义示例集(问答对)"question": "什么是蝙蝠侠?","answer": "蝙蝠侠是DC漫画中的超级英雄,真实身份是布鲁斯·韦恩,没有超能力,依靠科技和格斗技巧打击犯罪。},"question": "蜘蛛侠的超能力来自哪里?","answer": "蜘蛛侠的超能力来自被放射性蜘蛛咬伤,获得了蜘蛛般的敏捷、力量和感知能力。Lon
在大模型应用开发中,开发者常常面临两大核心挑战:一是模型输出的 "幻觉" 问题(生成与事实不符的内容),二是输出质量不稳定(如答非所问、格式混乱)。这些问题直接影响用户体验,甚至可能导致业务风险。而提示词工程(Prompt Engineering)正是解决这些问题的关键技术,其中 LongChain 框架凭借其强大的提示词管理能力,成为开发者的首选工具。
本文将系统讲解 LongChain 在提示词工程中的实践技巧,从基础概念到进阶优化,结合代码示例和场景分析,帮助初学者快速掌握提升大模型输出质量的核心方法。全文约 5000 字,涵盖提示词模板设计、示例工程化、向量相似度匹配等关键技术,适合大模型应用开发入门者系统学习。
一、提示词工程为什么需要 "模板化" 思维?
在与大模型交互时,很多开发者会直接将用户输入 "硬编码" 传递给模型,这种方式看似简单,却隐藏着严重的隐患。例如,当用户询问 "如何退款" 时,直接传递该问题可能导致模型生成模糊的回答(如 "请联系客服"),甚至出现幻觉(如虚构退款流程)。而提示词工程的核心目标,就是通过结构化设计,让模型的输出更精准、更可控。
1.1 从 "硬编码" 到 "模板化" 的必然性
与大模型的交互本质是 "文本输入 - 文本输出" 的过程,其中输入部分即提示词(Prompt)。直接使用用户输入作为提示词的弊端主要有三点:
- 质量不可控:用户输入往往简洁、模糊(如 "查订单"),模型难以理解具体需求;
- 幻觉频发:缺乏约束的提示词会让模型过度联想,生成与事实不符的内容;
- 安全性风险:恶意用户可能通过特殊输入诱导模型生成违规内容。
解决方案是采用提示词模板(Prompt Template) 管理方式,这与我们日常使用的短信模板、邮件模板逻辑一致。例如,短信平台会通过模板规范 "验证码短信" 的格式(如 "【XX 平台】您的验证码是 {code},5 分钟内有效"),既保证信息准确,又避免安全风险。提示词模板也同理,通过预定义结构约束模型的输入,从源头提升输出质量。
1.2 LongChain 框架的核心价值
LongChain 是一个专注于大模型应用开发的 Python 框架,其在提示词工程中的核心作用是:将用户输入转化为 "模型可理解的结构化提示词"。具体来说,它能实现三大功能:
- 参数化整合:将用户输入作为参数,与预定义的模板内容(如角色定义、上下文信息)拼接成完整提示词;
- 格式标准化:确保提示词符合模型接口要求(如 OpenAI 的 Message 格式);
- 流程自动化:支持提示词的动态生成、示例注入、结果解析等全流程管理。
举个简单例子:当用户输入 "你好" 时,LongChain 会基于模板自动生成如下提示词:
plaintext
系统角色:你是电商平台的智能客服,需使用礼貌用语,优先解决用户的订单问题。
用户输入:你好
上下文记录:无
请根据以上信息,以客服身份回复用户。
可以看到,经过模板处理的提示词包含了模型所需的全部信息,输出质量自然远高于直接输入 "你好"。
二、提示词模板:LongChain 的核心工具详解
提示词模板是 LongChain 的基础组件,掌握其类型、创建方法和应用场景,是入门提示词工程的第一步。
2.1 模板的两种核心类型及适用场景
LongChain 提供了多种提示词模板,其中最常用的是聊天模板(Chat Template) 和字符串模板(String Template),两者的区别如下:
| 模板类型 | 适用场景 | 核心特点 | 示例 |
|---|---|---|---|
| 聊天模板 | 多轮对话(如客服机器人、聊天助手) | 包含多轮消息记录,支持角色定义,保留上下文 | 系统消息 + 用户历史提问 + AI 历史回复 + 当前提问 |
| 字符串模板 | 单轮指令(如生成文案、翻译文本) | 单句结构,通过参数替换生成提示词,无上下文 | "请将以下文本翻译成英文:{text}" |
聊天模板的核心优势在于支持角色定义。在多轮对话中,我们需要明确三类角色的消息:
- 系统消息(System Message):定义 AI 的身份和行为准则(如 "你是专业的 Python 技术顾问,只回答编程相关问题");
- 人类消息(Human Message):用户输入的提示词(如 "如何用 Python 读取 CSV 文件?");
- AI 消息(Assistant Message):模型的历史回复(用于上下文衔接,如 "可以使用 pandas 库的 read_csv 方法")。
这些角色消息会被 LongChain 封装成模型可识别的格式(如 OpenAI 的messages参数),确保对话的连贯性和准确性。
2.2 从零开始创建提示词模板
下面通过代码示例,详细讲解两种模板的创建步骤。
2.2.1 字符串模板(String Template)的创建与使用
字符串模板适用于简单的单轮指令场景,创建步骤如下:
-
安装 LongChain 库
首先确保安装了必要的依赖:bash
pip install langchain openai # langchain是核心框架,openai用于调用模型 -
导入模板类并定义模板
使用PromptTemplate类创建字符串模板,通过{变量名}定义参数:python
from langchain.prompts import PromptTemplate # 定义模板内容,包含两个参数:topic(主题)和style(风格) template = "请讲一个关于{topic}的笑话,风格要{style}。" # 创建模板实例,指定参数列表 prompt = PromptTemplate( input_variables=["topic", "style"], template=template ) -
传入参数生成提示词
通过format方法传入参数,生成最终提示词:python
# 传入参数:主题为"程序员",风格为"幽默夸张" final_prompt = prompt.format(topic="程序员", style="幽默夸张") print(final_prompt) # 输出结果:请讲一个关于程序员的笑话,风格要幽默夸张。 -
调用大模型获取结果
将生成的提示词传递给大模型(以 OpenAI 为例):python
from langchain.llms import OpenAI # 初始化模型(需配置OPENAI_API_KEY环境变量) llm = OpenAI(model_name="gpt-3.5-turbo-instruct") # 调用模型 result = llm(final_prompt) print(result) # 输出示例:为什么程序员总是混淆万圣节和圣诞节?因为Oct 31(八进制31)等于Dec 25(十进制25)啊!
字符串模板的优点是简单直观,适合不需要上下文的场景。但对于需要多轮对话的场景(如客服机器人),则需要使用聊天模板。
2.2.2 聊天模板(Chat Template)的创建与使用
聊天模板通过ChatPromptTemplate类实现,支持多角色消息和上下文管理,创建步骤如下:
-
定义角色消息
分别定义系统消息、人类消息和 AI 消息(可选):python
from langchain.prompts import ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate # 系统消息模板:定义AI身份 system_template = "你是电商平台的客服机器人,职责是协助用户查询订单状态。请使用礼貌用语,回答简洁明了。" system_message_prompt = SystemMessagePromptTemplate.from_template(system_template) # 人类消息模板:接收用户输入 human_template = "我的订单号是{order_id},请帮我查询状态。" human_message_prompt = HumanMessagePromptTemplate.from_template(human_template) -
整合为聊天模板
将角色消息组合成聊天模板:python
# 组合系统消息和人类消息 chat_prompt = ChatPromptTemplate.from_messages([ system_message_prompt, human_message_prompt ]) -
生成提示词并调用模型
传入参数生成完整提示词,再调用大模型:python
from langchain.chat_models import ChatOpenAI # 生成提示词(包含角色信息) final_prompt = chat_prompt.format_prompt(order_id="OD123456").to_messages() # 调用聊天模型 chat_model = ChatOpenAI(model_name="gpt-3.5-turbo") result = chat_model(final_prompt) print(result.content) # 输出示例:您好!您的订单OD123456当前状态为"已发货",预计明天送达。如有疑问,请随时告知~
可以看到,聊天模板通过系统消息明确了 AI 的身份和行为准则,让输出更符合业务需求。如果需要支持多轮对话,只需在模板中加入 AI 的历史回复即可:
python
from langchain.schema import AIMessage
# 加入AI的历史回复(上下文)
chat_prompt = ChatPromptTemplate.from_messages([
system_message_prompt,
human_message_prompt,
AIMessage(content="您好!您的订单OD123456当前状态为'已发货'..."), # 历史回复
HumanMessagePromptTemplate.from_template("那可以修改收货地址吗?") # 新的用户输入
])
2.3 模板的动态管理:消息占位符的妙用
在复杂场景中,提示词模板需要动态插入上下文消息(如多轮对话历史),此时可使用MessagePlaceholder实现灵活的消息管理。
例如,在客服系统中,我们需要将用户的历史对话作为上下文传入模板:
python
from langchain.prompts import MessagePlaceholder
# 定义包含占位符的模板
chat_prompt = ChatPromptTemplate.from_messages([
system_message_prompt,
MessagePlaceholder(variable_name="history"), # 上下文占位符
human_message_prompt
])
# 历史对话记录(列表形式,包含人类消息和AI消息)
history = [
HumanMessage(content="我的订单OD123456什么时候发货?"),
AIMessage(content="您好!该订单已于今天上午发出,预计2天送达。")
]
# 传入历史对话和新参数
final_prompt = chat_prompt.format_prompt(
history=history,
order_id="OD123456"
).to_messages()
# 调用模型
result = chat_model(final_prompt)
print(result.content)
# 输出示例:您好!您的订单OD123456当前状态为"运输中",物流信息可在APP内查看~
通过MessagePlaceholder,我们无需修改模板结构,即可动态插入任意数量的上下文消息,极大提升了模板的复用性和灵活性。
三、示例工程化:用 Few-Shot 提示词解决 "幻觉" 问题
即使使用了提示词模板,模型仍可能因对任务理解不清晰而产生幻觉。例如,当用户询问 "什么是大语言模型" 时,模型可能会混淆 "大语言模型" 和 "编程语言" 的概念。解决这一问题的有效方法是Few-Shot 提示词—— 通过在提示词中插入少量示例,指导模型输出符合预期的结果。
3.1 Few-Shot 示例的核心价值
Few-Shot(小样本)示例是指在提示词中加入 1-5 个任务相关的问答样例,其作用类似于 "给模型举例子",主要价值体现在三点:
- 约束输出范围:通过示例明确任务边界,避免模型生成无关内容;
- 统一输出格式:示例可规定输出的结构(如 JSON、列表),方便后续解析;
- 强化事实准确性:示例中包含的事实信息可作为模型参考,减少幻觉。
例如,在开发 "编程语言识别" 功能时,若直接提问 "Python 是什么类型的语言?",模型可能回答模糊;而加入示例后:
plaintext
示例1:
问:Java是什么类型的语言?
答:Java是一种面向对象的编程语言。
示例2:
问:C语言是什么类型的语言?
答:C语言是一种面向过程的编程语言。
问:Python是什么类型的语言?
答:
模型会更准确地回答:"Python 是一种面向对象的编程语言。"
3.2 LongChain 中 Few-Shot 示例的实现
LongChain 通过FewShotPromptTemplate类实现示例的整合与管理,步骤如下:
3.2.1 定义示例集
首先创建一组问答样例,明确任务的输入输出格式:
python
# 定义示例集(问答对)
examples = [
{
"question": "什么是蝙蝠侠?",
"answer": "蝙蝠侠是DC漫画中的超级英雄,真实身份是布鲁斯·韦恩,没有超能力,依靠科技和格斗技巧打击犯罪。"
},
{
"question": "蜘蛛侠的超能力来自哪里?",
"answer": "蜘蛛侠的超能力来自被放射性蜘蛛咬伤,获得了蜘蛛般的敏捷、力量和感知能力。"
}
]
3.2.2 创建示例模板
定义示例在提示词中的展示格式:
python
from langchain.prompts import FewShotPromptTemplate, PromptTemplate
# 示例模板:规定单个示例的展示方式
example_template = """
问:{question}
答:{answer}
"""
example_prompt = PromptTemplate(
input_variables=["question", "answer"],
template=example_template
)
3.2.3 整合示例与问题
将示例集、示例模板和用户问题整合为最终提示词:
python
# 创建Few-Shot提示词模板
few_shot_prompt = FewShotPromptTemplate(
examples=examples, # 示例集
example_prompt=example_prompt, # 示例模板
suffix="问:{input_question}\n答:", # 用户问题的展示格式
input_variables=["input_question"] # 用户问题的参数名
)
# 生成提示词
final_prompt = few_shot_prompt.format(input_question="钢铁侠的真实身份是谁?")
print(final_prompt)
生成的提示词如下:
plaintext
问:什么是蝙蝠侠?
答:蝙蝠侠是DC漫画中的超级英雄,真实身份是布鲁斯·韦恩,没有超能力,依靠科技和格斗技巧打击犯罪。
问:蜘蛛侠的超能力来自哪里?
答:蜘蛛侠的超能力来自被放射性蜘蛛咬伤,获得了蜘蛛般的敏捷、力量和感知能力。
问:钢铁侠的真实身份是谁?
答:
调用模型后,输出会更准确:
python
# 调用模型
result = llm(final_prompt)
print(result)
# 输出:钢铁侠的真实身份是托尼·斯塔克,他是一位天才发明家和企业家,通过特制的装甲获得超能力。
3.3 示例格式化:让输出更易解析
在实际开发中,我们常需要模型输出结构化数据(如 JSON),以便后续处理。通过示例格式化,可强制模型遵循指定格式。
例如,要求模型以 JSON 格式输出 "电影信息":
python
# 定义带格式的示例
examples = [
{
"question": "《泰坦尼克号》的导演是谁?",
"answer": '{"电影名称": "泰坦尼克号", "导演": "詹姆斯·卡梅隆", "类型": "爱情片"}'
}
]
# 示例模板
example_template = """
问:{question}
答:{answer}
"""
example_prompt = PromptTemplate(
input_variables=["question", "answer"],
template=example_template
)
# 创建Few-Shot模板
few_shot_prompt = FewShotPromptTemplate(
examples=examples,
example_prompt=example_prompt,
suffix="问:《大白鲨》的导演是谁?\n答:",
input_variables=[]
)
# 生成提示词并调用模型
final_prompt = few_shot_prompt.format()
result = llm(final_prompt)
print(result)
# 输出:{"电影名称": "大白鲨", "导演": "史蒂文·斯皮尔伯格", "类型": "恐怖片"}
通过示例中的 JSON 格式,模型会自动遵循结构输出,避免了格式混乱的问题。
四、进阶优化:示例选择器与向量相似度匹配
当示例数量庞大(如成百上千条)时,将所有示例传入模型会导致两个问题:一是超出模型上下文长度限制(如 GPT-3.5-turbo 的 4096 tokens),二是无关示例会干扰模型判断。此时需要通过示例选择器(Example Selector) 筛选与当前问题最相关的示例。
4.1 示例选择器的核心原理
示例选择器的本质是 "从示例集中找到与当前问题最相似的 N 个示例",其实现依赖向量相似度匹配技术,步骤如下:
- 文本向量化:将示例和当前问题转换为高维向量(如 1536 维),向量的每个维度代表文本的一个语义特征;
- 相似度计算:通过计算向量之间的余弦距离(或欧氏距离),衡量文本的语义相似度(距离越小,相似度越高);
- 动态筛选:保留相似度最高的 Top N 个示例,传入提示词模板。
例如,当用户询问 "《大白鲨》的导演是谁" 时,选择器会从示例集中找到与 "电影导演" 相关的示例(如《泰坦尼克号》的示例),而忽略无关示例(如关于超级英雄的示例)。
4.2 基于 Chroma 向量数据库的示例选择器实现
LongChain 结合 Chroma(开源向量数据库)和 OpenAI 的 Embedding 模型,可快速实现语义相似度匹配的示例选择器,步骤如下:
4.2.1 安装依赖
bash
pip install chromadb # 向量数据库
pip install openai # 用于文本向量化
4.2.2 创建向量数据库并初始化选择器
python
from langchain.prompts import SemanticSimilarityExampleSelector
from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings
from langchain.prompts import FewShotPromptTemplate, PromptTemplate
# 1. 定义示例集
examples = [
{
"question": "《泰坦尼克号》的导演是谁?",
"answer": '{"电影名称": "泰坦尼克号", "导演": "詹姆斯·卡梅隆"}'
},
{
"question": "《大白鲨》的导演是谁?",
"answer": '{"电影名称": "大白鲨", "导演": "史蒂文·斯皮尔伯格"}'
},
{
"question": "蝙蝠侠的真实身份是什么?",
"answer": '{"角色": "蝙蝠侠", "真实身份": "布鲁斯·韦恩"}'
}
]
# 2. 初始化向量数据库(用于存储示例向量)
# 使用OpenAI的text-embedding-ada-002模型将文本转为向量
embeddings = OpenAIEmbeddings(model_name="text-embedding-ada-002")
vectorstore = Chroma.from_texts(
[example["question"] for example in examples], # 示例的问题文本
embeddings,
metadatas=examples # 关联完整示例信息
)
# 3. 创建语义相似度示例选择器
example_selector = SemanticSimilarityExampleSelector(
vectorstore=vectorstore, # 向量数据库
k=1 # 选择最相似的1个示例
)
4.2.3 关联提示词模板并使用
python
# 4. 定义示例模板
example_template = """
问:{question}
答:{answer}
"""
example_prompt = PromptTemplate(
input_variables=["question", "answer"],
template=example_template
)
# 5. 创建带选择器的Few-Shot模板
few_shot_prompt = FewShotPromptTemplate(
example_selector=example_selector, # 关联示例选择器
example_prompt=example_prompt,
suffix="问:《侏罗纪公园》的导演是谁?\n答:",
input_variables=[]
)
# 6. 生成提示词(自动筛选最相似的示例)
final_prompt = few_shot_prompt.format()
print(final_prompt)
生成的提示词会自动包含与 "《侏罗纪公园》的导演" 最相似的示例(即《大白鲨》的示例):
问:《大白鲨》的导演是谁?
答:{"电影名称": "大白鲨", "导演": "史蒂文·斯皮尔伯格"}
问:《侏罗纪公园》的导演是谁?
答:
调用模型后,输出会更准确:
python
result = llm(final_prompt)
print(result)
# 输出:{"电影名称": "侏罗纪公园", "导演": "史蒂文·斯皮尔伯格"}
4.3 示例选择器的进阶技巧
- 动态调整 k 值:根据问题复杂度调整选择的示例数量(简单问题 k=1,复杂问题 k=3);
- 结合关键词过滤:在相似度匹配前,先用关键词筛选示例(如先过滤出 "电影" 相关示例,再计算相似度);
- 定期更新示例集:通过用户反馈收集新示例,不断优化向量数据库的覆盖范围。
五、完整案例:构建一个高质量的客服问答系统
为帮助读者综合运用上述技术,下面以 "电商客服问答系统" 为例,展示 LongChain 提示词工程的完整落地流程。
5.1 需求分析
系统需实现以下功能:
- 识别用户的订单相关问题(如查询状态、修改地址);
- 输出格式统一为 JSON(包含 "问题类型" 和 "回答内容");
- 减少幻觉(如不虚构订单流程)。
5.2 技术方案
- 使用聊天模板定义客服机器人的身份和行为准则;
- 通过Few-Shot 示例规范输出格式和回答范围;
- 采用示例选择器动态筛选与用户问题相关的示例。
5.3 代码实现
python
from langchain.prompts import (
ChatPromptTemplate,
SystemMessagePromptTemplate,
HumanMessagePromptTemplate,
FewShotPromptTemplate,
PromptTemplate,
SemanticSimilarityExampleSelector
)
from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings
from langchain.chat_models import ChatOpenAI
from langchain.schema import HumanMessage, AIMessage
# 1. 定义系统消息(客服身份)
system_template = """
你是电商平台"优选商城"的客服机器人,仅回答与订单相关的问题(如查询状态、修改地址、退款政策等)。
若用户问题与订单无关,请回答:"抱歉,我仅能协助处理订单相关问题,您可以尝试咨询其他客服~"
"""
system_message_prompt = SystemMessagePromptTemplate.from_template(system_template)
# 2. 定义Few-Shot示例集
examples = [
{
"question": "我的订单OD789012什么时候发货?",
"answer": '{"问题类型": "查询发货时间", "回答内容": "订单OD789012已于2023-10-01发货,预计2天送达。"}'
},
{
"question": "能帮我把订单OD789012的地址改成北京市朝阳区吗?",
"answer": '{"问题类型": "修改收货地址", "回答内容": "已为您将订单OD789012的地址修改为北京市朝阳区,请注意查收~"}'
},
{
"question": "这个商品怎么退货?",
"answer": '{"问题类型": "退款政策", "回答内容": "请在收到商品后7天内,通过APP提交退货申请,我们将安排上门取件。"}'
}
]
# 3. 创建示例选择器
embeddings = OpenAIEmbeddings(model_name="text-embedding-ada-002")
vectorstore = Chroma.from_texts(
[example["question"] for example in examples],
embeddings,
metadatas=examples
)
example_selector = SemanticSimilarityExampleSelector(
vectorstore=vectorstore,
k=2
)
# 4. 定义示例模板
example_template = """
问:{question}
答:{answer}
"""
example_prompt = PromptTemplate(
input_variables=["question", "answer"],
template=example_template
)
# 5. 创建Few-Shot提示词
few_shot_prompt = FewShotPromptTemplate(
example_selector=example_selector,
example_prompt=example_prompt,
suffix="问:{user_question}\n答:",
input_variables=["user_question"]
)
# 6. 整合为聊天模板(包含上下文)
chat_prompt = ChatPromptTemplate.from_messages([
system_message_prompt,
HumanMessagePromptTemplate.from_template(few_shot_prompt.template), # 嵌入Few-Shot提示词
MessagePlaceholder(variable_name="history") # 上下文占位符
])
# 7. 模拟用户交互
chat_model = ChatOpenAI(model_name="gpt-3.5-turbo")
# 历史对话
history = [
HumanMessage(content="我的订单OD789012还没收到"),
AIMessage(content='{"问题类型": "查询物流", "回答内容": "订单OD789012当前处于派送中,快递员将在1小时内联系您。"}')
]
# 用户新问题
user_question = "能改一下这个订单的收货电话吗?"
# 生成提示词
final_prompt = chat_prompt.format_prompt(
user_question=user_question,
history=history
).to_messages()
# 调用模型
result = chat_model(final_prompt)
print(result.content)
# 输出示例:{"问题类型": "修改收货电话", "回答内容": "请提供新的收货电话,我们将为您更新订单OD789012的信息。"}
六、总结
LongChain 提示词工程通过模板化管理、示例工程化和相似度匹配三大技术,有效解决了大模型输出质量低、幻觉频发的问题。其核心价值在于:
- 降低开发门槛:无需深入理解模型原理,通过提示词设计即可提升效果;
- 提升系统可控性:模板和示例让模型输出更符合业务预期;
- 适配复杂场景:从单轮指令到多轮对话,均可通过灵活配置满足需求。
未来,随着大模型技术的发展,提示词工程将与 RAG(检索增强生成)、微调等技术进一步融合。开发者可关注 LongChain 的工作流编排功能(如异步调用、分支逻辑),结合向量数据库和知识库,构建更智能、更可靠的大模型应用。
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐

所有评论(0)