提示工程 (Prompts)

构建和管理提示以指导模型行为

PromptTemplate 基础

字符串模板

python
from langchain_core.prompts import PromptTemplate

# 基础模板
prompt = PromptTemplate(
    input_variables=["product", "feature"],
    template="为{product}写一个广告,突出{feature}这个特点。"
)

# 格式化提示
formatted = prompt.format(
    product="智能手表",
    feature="健康监测"
)
print(formatted)
# 输出: 为智能手表写一个广告,突出健康监测这个特点。

聊天模板

python
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

# 系统提示 + 用户输入
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个专业的{role}助手。"),
    ("user", "{user_input}")
])

formatted = prompt.format_messages(
    role="Python 编程",
    user_input="如何使用列表推导式?"
)
print(formatted)

高级功能

部分变量

python
from langchain_core.prompts import PromptTemplate

# 预设部分变量
prompt = PromptTemplate(
    template="向{name}介绍{product},重点介绍{feature}。",
    input_variables=["name", "feature"],
    partial_variables={"product": "LangChain"}
)

# 只需填入剩余变量
formatted = prompt.format(
    name="小明",
    feature="智能体功能"
)

消息占位符

python
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

# 使用 MessagesPlaceholder 插入动态消息历史
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个有帮助的助手。"),
    MessagesPlaceholder(variable="history"),  # 对话历史
    ("user", "{user_input}")
)

formatted = prompt.format_messages(
    history=[
        {"role": "user", "content": "你好"},
        {"role": "assistant", "content": "你好!有什么可以帮助你的?"}
    ],
    user_input="记得我之前说了什么吗?"
)

Few-shot 示例

静态示例

python
from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate

# 定义示例
examples = [
    {"input": "苹果", "output": "红色水果"},
    {"input": "香蕉", "output": "黄色水果"},
    {"input": "橙子", "output": "橙色水果"},
]

# 示例格式化模板
example_prompt = PromptTemplate(
    input_variables=["input", "output"],
    template="输入: {input}\n输出: {output}"
)

# 创建 Few-shot 提示
prompt = FewShotPromptTemplate(
    examples=examples,
    example_prompt=example_prompt,
    prefix="根据示例完成任务",
    suffix="输入: {input}\n输出:",
    input_variables=["input"]
)

# 使用
result = prompt.format(input="西瓜")
print(result)

动态示例选择

python
from langchain_core.prompts import FewShotPromptTemplate
from langchain_core.example_selectors import SemanticSimilarityExampleSelector
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma

# 创建示例库
examples = [
    {"question": "什么是Python?", "answer": "Python是一种编程语言"},
    {"question": "什么是列表?", "answer": "列表是Python的可变序列类型"},
    {"question": "什么是字典?", "answer": "字典是Python的键值对数据结构"},
    # ... 更多示例
]

# 使用语义相似度选择示例
selector = SemanticSimilarityExampleSelector.from_examples(
    examples=examples,
    embeddings=OpenAIEmbeddings(),
    vectorstore_cls=Chroma,
    k=2  # 选择最相似的2个示例
)

# 动态 Few-shot 提示
prompt = FewShotPromptTemplate(
    example_selector=selector,
    example_prompt=PromptTemplate(
        input_variables=["question", "answer"],
        template="问题: {question}\n答案: {answer}"
    ),
    suffix="问题: {question}\n答案:",
    input_variables=["question"]
)

输出解析器

基础解析

python
from langchain_core.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import ChatOpenAI

# 创建解析链
prompt = PromptTemplate.from_template("讲一个关于{topic}的简短笑话")
output_parser = StrOutputParser()
llm = ChatOpenAI(model="gpt-4o")

# 组合:prompt | llm | parser
chain = prompt | llm | output_parser

result = chain.invoke({"topic": "程序员"})
print(result)

结构化输出解析

python
from langchain_core.prompts import PromptTemplate
from langchain_core.output_parsers import JSONOutputParser
from langchain_openai import ChatOpenAI

# 定义期望的 JSON 结构
parser = JSONOutputParser()

# 提示模板中包含格式说明
prompt = PromptTemplate(
    template="回答以下问题,输出格式:{format_instructions}\n\n问题:{question}",
    input_variables=["question"],
    partial_variables={"format_instructions": parser.get_format_instructions()}
)

llm = ChatOpenAI(model="gpt-4o")
chain = prompt | llm | parser

result = chain.invoke({"question": "Python 的主要特点是什么?"})
print(result)  # 返回解析后的字典

自定义解析器

python
from langchain_core.output_parsers import BaseOutputParser

class CommaSeparatedListParser(BaseOutputParser):
    """解析逗号分隔的列表"""
    def parse(self, text: str):
        return [item.strip() for item in text.split(",")]

    @property
    def _type(self):
        return "comma-separated-list"

# 使用
parser = CommaSeparatedListParser()
result = parser.parse("苹果, 香蕉, 橙子")
print(result)  # ['苹果', '香蕉', '橙子']

提示优化技巧

清晰性原则:提示应该明确指定任务、输入格式和输出格式。避免模糊的指令。
python
# ❌ 不好的提示
bad_prompt = "写个排序"

# ✓ 好的提示
good_prompt = """
请用 Python 写一个快速排序函数,要求:
1. 包含完整的函数定义
2. 添加类型注解
3. 添加详细的文档字符串
4. 包含一个简单的使用示例
"""
避免提示注入:当提示包含用户输入时,要警惕提示注入攻击。始终验证和清理用户输入。
python
# 使用提示模板来防止注入
from langchain_core.prompts import PromptTemplate

# 安全:使用模板自动转义
prompt = PromptTemplate(
    template="请回答以下问题:{question}",
    input_variables=["question"]
)

# 而不是字符串拼接(不安全)
# unsafe = f"请回答以下问题:{user_input}"

管道组合

LangChain 使用 | 操作符将提示、模型和解析器连接成链:

graph LR
    A[PromptTemplate] --> B[ChatModel]
    B --> C[OutputParser]
    C --> D[结果]
python
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import ChatOpenAI

# 创建组件
prompt = ChatPromptTemplate.from_template("解释{concept},用三句话")
llm = ChatOpenAI(model="gpt-4o")
parser = StrOutputParser()

# 使用 | 组合成链
chain = prompt | llm | parser

# 等价于:
# chain = (
#     prompt
#     | llm
#     | parser
# )

# 调用
result = chain.invoke({"concept": "递归"})
print(result)

常见使用模式

模式 用途 代码示例
系统提示 定义助手角色 ("system", "你是{role}")
少样本 提供示例 FewShotPromptTemplate
对话历史 多轮对话 MessagesPlaceholder("history")
结构化输出 JSON 解析 JSONOutputParser()
自动重试 修复格式错误 RunnableRetry

✏️ 练习题

选择题 1. MessagesPlaceholder 的主要用途是?
A. 格式化用户输入
B. 插入动态对话历史
C. 解析模型输出
D. 选择 Few-shot 示例
编程题 2. 创建一个聊天提示模板,包含:系统提示、对话历史占位符、用户输入,并实现调用
查看参考答案
python
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_openai import ChatOpenAI

# 创建聊天模板
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个专业的{domain}顾问。"),
    MessagesPlaceholder(variable="chat_history"),
    ("user", "{user_input}")
])

# 创建模型
llm = ChatOpenAI(model="gpt-4o")

# 组合成链
chain = prompt | llm

# 调用
response = chain.invoke({
    "domain": "Python 编程",
    "chat_history": [
        {"role": "user", "content": "什么是装饰器?"},
        {"role": "assistant", "content": "装饰器是修改函数行为的函数..."}
    ],
    "user_input": "能举个具体例子吗?"
})

print(response.content)