本章目标:理解 Prompt 的设计原则,掌握 LangChain 模板系统、Few-Shot 提示和思维链(CoT)三大核心技术,能够写出让 AI 稳定输出你期望结果的提示词。
一、为什么 Prompt 如此重要?
很多人学会调用 LLM API 后,第一个困惑是:”为什么同一个问题,有时答得很好,有时答得一塌糊涂?”
答案几乎都在 Prompt 里。
同一个任务,两种 Prompt 的差距:
# ❌ 模糊的 Prompt
prompt_bad = "总结一下这篇文章"
# AI 可能输出:3 句话,也可能输出 3 段,风格不定,不知道要点
# ✅ 精准的 Prompt
prompt_good = """
请对以下文章进行总结。要求:
1. 用不超过 150 字
2. 必须包含:核心观点、关键数据、适用结论
3. 使用简洁的中文,避免专业术语
4. 格式为:【核心观点】... 【关键数据】... 【结论】...
文章内容:
{article}
"""
Prompt 工程的黄金公式:
高质量 Prompt = 清晰角色 + 明确任务 + 具体约束 + 期望格式
二、LangChain 为什么需要 Prompt 模板?
在真实项目里,Prompt 通常不是写死的字符串,而是根据用户输入动态生成的。LangChain 的 Prompt 模板解决了以下问题:
- 复用性:同一个提示结构可以填入不同的变量值
- 可测试性:模板和数据分离,单独测试模板逻辑
- 与 Chain 集成:模板可以无缝接入 LCEL 链(下一章讲解)
添加图片注释,不超过 140 字(可选)
三、Step 1:基础 Prompt 模板
PromptTemplate(纯文本模板)
from langchain_core.prompts import PromptTemplate
# ── 创建模板,用 {} 标记变量 ──────────────────────────────────
template = PromptTemplate(
input_variables=["topic", "audience", "length"],
template="""你是一位经验丰富的科普作家。
请为【{audience}】写一篇关于"{topic}"的科普文章。
要求:
- 文章长度:{length}字以内
- 语言:通俗易懂,避免专业术语
- 结构:先讲是什么,再讲为什么重要,最后给出实际例子
"""
)
# ── 填充变量生成最终 Prompt ──────────────────────────────────
formatted = template.format(
topic="区块链",
audience="初中生",
length="300"
)
print(formatted)
ChatPromptTemplate(对话模板,推荐使用)
from langchain_core.prompts import ChatPromptTemplate
# ── 多角色对话模板 ────────────────────────────────────────────
chat_prompt = ChatPromptTemplate.from_messages([
# system:定义 AI 的专业身份和行为准则
("system", """你是一位专业的{role},拥有{years}年从业经验。
回答时遵循以下规范:
- 先给出明确结论,再解释原因
- 如果问题超出专业范围,直接告知
- 用中文回答,简洁专业"""),
# human:用户的问题
("human", "{question}"),
])
# ── 格式化为消息列表 ──────────────────────────────────────────
messages = chat_prompt.format_messages(
role="心脏病学医生",
years=15,
question="心率超过 100 次/分钟算正常吗?",
)
# messages 是一个列表:[SystemMessage(...), HumanMessage(...)]
for msg in messages:
print(f"[{msg.__class__.__name__}]: {msg.content}")
与 LLM 直接调用:
from langchain_openai import ChatOpenAI
import os
llm = ChatOpenAI(
model="qwen-plus",
openai_api_key=os.getenv("DASHSCOPE_API_KEY"),
openai_api_base="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
# 方式一:先格式化,再调用
messages = chat_prompt.format_messages(role="营养师", years=10, question="早餐吃什么最健康?")
response = llm.invoke(messages)
print(response.content)
# 方式二:用链(推荐,下一章深讲)
chain = chat_prompt | llm
response = chain.invoke({"role": "营养师", "years": 10, "question": "早餐吃什么最健康?"})
print(response.content)
四、Step 2:Few-Shot 提示(示例驱动)
什么是 Few-Shot?
Few-Shot 是”给几个例子”的意思。你给模型展示几个”输入→输出”的例子,模型就能理解你期望的格式和风格,然后对新输入产生类似的输出。
适用场景:
- 需要特定格式的输出(JSON、表格、特定句式)
- 需要特定风格(文言文、专业术语、儿童语言)
- 模型不擅长的小众任务(情感分类、命名实体识别)
from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate
from langchain_openai import ChatOpenAI
# ── 定义示例:每个示例都是一个 dict ──────────────────────────
examples = [
{
"text": "这款手机电池续航太差了,一天充两次电,差评!",
"sentiment": "负面",
"reason": "用户对电池续航不满"
},
{
"text": "物流超快,下单第二天就到了,包装也很严实。",
"sentiment": "正面",
"reason": "用户对物流速度和包装满意"
},
{
"text": "质量还行,但价格有点贵,性价比一般。",
"sentiment": "中性",
"reason": "质量满意但价格不满意,整体中立"
},
]
# ── 单个示例的展示模板 ────────────────────────────────────────
example_prompt = PromptTemplate(
input_variables=["text", "sentiment", "reason"],
template="评论:{text}\n情感:{sentiment}\n原因:{reason}"
)
# ── Few-Shot 模板 ─────────────────────────────────────────────
few_shot_prompt = FewShotPromptTemplate(
examples=examples,
example_prompt=example_prompt,
prefix="你是一个电商评论情感分析专家。请分析以下评论的情感倾向(正面/负面/中性)并说明原因:\n\n参考示例:",
suffix="\n评论:{text}\n情感:", # 最后留空,让模型填写
input_variables=["text"],
example_separator="\n---\n", # 示例之间的分隔符
)
# ── 调用 ─────────────────────────────────────────────────────
llm = ChatOpenAI(
model="qwen-plus",
openai_api_key=os.getenv("DASHSCOPE_API_KEY"),
openai_api_base="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
test_reviews = [
"屏幕显示效果非常清晰,色彩还原准确,专业摄影师推荐!",
"买了之后根本用不了,联系客服也没人回,气死了。",
]
for review in test_reviews:
formatted = few_shot_prompt.format(text=review)
response = llm.invoke(formatted)
print(f"评论:{review}")
print(f"分析:{response.content}")
print("-" * 50)
Few-Shot 的本质原理:
五、Step 3:思维链提示(Chain of Thought)
为什么需要思维链?
直接问 AI 复杂问题时,它可能跳步推理导致出错。思维链(CoT)的思路是:强制模型一步步思考,每个步骤都显式写出来,这样错误更少,推理更可靠。
研究发现:在复杂推理任务上,CoT 提示可以将准确率提升 20-50%。
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
# ── 不带思维链(容易出错)────────────────────────────────────
no_cot_prompt = ChatPromptTemplate.from_messages([
("system", "你是数学老师,直接给出答案。"),
("human", "{question}"),
])
# ── 带思维链(逐步推理)──────────────────────────────────────
cot_prompt = ChatPromptTemplate.from_messages([
("system", """你是数学老师。解题时必须按以下格式逐步推理:
【分析】:理解题目,找出已知条件
【步骤1】:...(写出每一步的计算)
【步骤N】:...
【答案】:最终结果
绝不能跳过中间步骤,必须展示完整推理过程。"""),
("human", "{question}"),
])
llm = ChatOpenAI(
model="qwen-plus",
openai_api_key=os.getenv("DASHSCOPE_API_KEY"),
openai_api_base="https://dashscope.aliyuncs.com/compatible-mode/v1",
temperature=0, # 数学题用 0,确保结果稳定
)
question = """
一家餐厅周一到周五每天接待 80 位顾客,周六接待 120 位,周日不营业。
每位顾客平均消费 85 元,月均营业天数按 4.3 周计算。
请计算该餐厅每月的营业额。
"""
print("=" * 50)
print("不带思维链的回答:")
chain_no_cot = no_cot_prompt | llm
print(chain_no_cot.invoke({"question": question}).content)
print("\n" + "=" * 50)
print("带思维链的回答:")
chain_cot = cot_prompt | llm
print(chain_cot.invoke({"question": question}).content)
Zero-Shot CoT(无示例,直接触发推理):
# 只需要在问题末尾加上这句话,就能激活模型的推理模式
question_with_cot = f"{question}\n\n让我们一步一步地思考。"
💡 “让我们一步一步地思考” 这句话已被研究证明是一个非常有效的 CoT 触发词,适用于各种 LLM。
六、Prompt 最佳实践速查
原则 1:具体优于模糊
# ❌ 模糊
"帮我改进这段代码"
# ✅ 具体
"检查以下 Python 代码的潜在 bug 和性能问题,
按【问题】【位置】【修复建议】格式输出,
重点关注:空指针、资源泄漏、时间复杂度"
原则 2:使用分隔符隔离数据
# ❌ 容易被用户内容干扰(Prompt 注入风险)
f"总结这篇文章:{user_input}"
# ✅ 用 XML 标签或分隔符隔离
f"""总结以下<article>标签内的文章:
<article>
{user_input}
</article>
要求:100字以内,提取核心观点。"""
原则 3:角色设定要具体
# ❌ 过于泛泛
("system", "你是专家")
# ✅ 明确背景和能力
("system", """你是一位拥有 10 年经验的全栈工程师,
擅长 Python、React 和 AWS 架构。
当回答技术问题时,优先给出可直接运行的代码示例,
并标注关键参数的作用。""")
原则 4:控制输出格式
# 要求输出 JSON
("system", """以 JSON 格式输出,字段包括:
- "summary": 文章摘要(50字以内)
- "keywords": 关键词列表(3-5个)
- "sentiment": 情感倾向(positive/negative/neutral)
不要输出任何 JSON 之外的文字。""")
七、常见 Prompt 问题与调试方法
| 问题现象 | 可能原因 | 调试方法 |
|---|---|---|
| 输出格式不稳定 | 格式要求不够明确 | 在 prompt 中加入示例输出 |
| 答案偏离主题 | 系统提示太弱或无系统提示 | 强化 system 消息的约束 |
| 输出截断 | max_tokens 设置太小 | 增大 max_tokens |
| 数学计算出错 | 没有使用 CoT | 加入逐步推理要求 |
| 多语言混杂 | 没有语言约束 | 在 prompt 中明确”用中文回答” |
调试技巧:先 print(prompt.format(...)) 看格式化后的完整 Prompt,确认是否符合预期。
📌 下一章预告:学会了 Prompt 之后,下一章我们学习如何用 LCEL(LangChain 表达语言)把 Prompt、LLM、输出解析器串联成”链”,实现更复杂的多步骤任务。
作者:阿聪谈架构
公众号:阿聪谈架构(分享后端架构 / AI / Java 技术文章)
相关代码关注公众号:【阿聪谈架构】 回复:AI专栏代码