首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >提示词工程

提示词工程

作者头像
江南一点雨
发布2026-03-26 17:06:56
发布2026-03-26 17:06:56
2190
举报
文章被收录于专栏:AI应用开发实践AI应用开发实践

事无巨细,提示词模板这块松哥也和大家做一个详细介绍。

本文基于 langchain。

一 优秀的提示词

什么样的提示词算优秀?

松哥的经验是四点:

  • 立角色
  • 讲问题
  • 定目标
  • 补要求
立角色

立角色就是指定回答者的身份(如专家、教师、程序员),提升专业性。

  • 无角色提问:“写一封投诉回复信。” → 回答可能缺乏针对性。
  • 角色设定提问:“作为资深客服主管,用专业且不失温和的语气,写一封针对物流延迟的投诉回复邮件。” → 回答会更符合客服场景,包含解决方案(如补偿措施)和礼貌用语。
讲问题

这个好理解,讲明白你的问题产生背景,你的具体问题。

问题要足够具体,最好能够结构化输出,这样模型也会结构化回答。

举个简单的例子:

  • 无结构提问:“如何准备面试?” → 回答可能冗长杂乱。
  • 结构化提问:“分三点说明:技术面试前需要准备的编程知识、沟通技巧、公司背景调研。” → 回答会按点分类,清晰易读。
定目标

告诉 AI 你的需求,以及你希望完成的目标。

补要求

补充要求,告诉 AI 回答的注意事项,以及限制条件,也可以给出回答示例。

举个简单例子:

  • 无示例提问:“写一份简历。” → 生成内容可能格式混乱。
  • 示例提问:“参考以下简历格式,写一份突出数据分析技能的简历: 【姓名】 【教育背景】 学校、专业、时间 【工作经验】公司、职位、成果(量化数据)→ 模型会严格按示例格式生成内容,并强调数据相关成果。

老实说,这些点其实都很简单,甚至有些幼稚。但是!!!网上铺天盖地的提示词课程,已经说明了这个问题虽然简单,还是有很多人不懂。一个简单的例子,前后端同事接口联调的时候,无论哪方出问题了,另一方能否一次性把问题讲明白?如果能,我相信他和 AI 对话也会做的很好;如果不能,那么他和 AI 对话估计也会差点意思。

二 两种模板

2.1 PromptTemplate

2.1.1 基础模板

通过占位符 {} 动态插入变量,生成标准提示词。

适用场景:单一变量替换的简单提示。

代码语言:javascript
复制
from langchain.prompts import PromptTemplate

# 定义模板
template = "请用{style}风格写一篇关于{topic}的200字短文。"
prompt = PromptTemplate(
    input_variables=["style", "topic"],  # 声明变量
    template=template
)

# 填充变量
result = prompt.format(style="幽默", topic="人工智能")
print(result)

输出

2.1.2 多变量混合

同时处理多个变量,支持复杂逻辑组合。

适用场景:需要多条件控制的提示生成。

代码语言:javascript
复制
template = """你是一名{role},请完成以下任务:
1. 分析用户需求:{demand}
2. 生成{output_type},要求语言为{language}
附加条件:{condition}"""

prompt = PromptTemplate(
    input_variables=["role", "demand", "output_type", "language", "condition"],
    template=template
)

result = prompt.format(
    role="数据科学家",
    demand="预测下季度销售额",
    output_type="分析报告",
    language="中文",
    condition="使用时间序列模型"
)
print(result)

输出

2.1.3 文件加载模板

从外部文件读取模板,实现代码与内容分离。

适用场景:需要频繁修改模板的场景。

步骤1:创建 story_prompt.txt 文件:

代码语言:javascript
复制
根据以下元素生成故事:
- 地点:{location}
- 角色:{characters}
- 冲突:{conflict}
要求:{requirements}

步骤2:代码加载模板:

代码语言:javascript
复制
with open(file="story_prompt.txt", mode="r",encoding="UTF-8") as f:
    template = f.read()

prompt = PromptTemplate(
    input_variables=["location", "characters", "conflict", "requirements"],
    template=template
)

result = prompt.format(
    location="火星殖民地",
    characters="AI机器人与人类工程师",
    conflict="氧气供应系统故障",
    requirements="包含技术细节和人性化描写"
)
print(result)

输出

2.1.4 部分模板填充

预先填充部分变量,延迟填充剩余变量。

适用场景:需要分阶段构建提示的流程。

代码语言:javascript
复制
from langchain.prompts import PromptTemplate

template = "在{platform}平台,为{product}撰写广告文案,突出卖点:{selling_points}"
prompt = PromptTemplate.from_template(template)

# 预填充平台和产品
partial_prompt = prompt.partial(platform="抖音", product="智能手表")
final_prompt = partial_prompt.format(selling_points="健康监测、超长续航")

print(final_prompt)

输出

2.1.5 Few-shot 示例模板

结合示例数据生成教学式提示。

适用场景:需要示例引导模型输出的场景。

代码语言:javascript
复制
from langchain.prompts import FewShotPromptTemplate, PromptTemplate

# 示例数据集
examples = [
    {"query": "太阳质量", "answer": "1.989×10³⁰ kg"},
    {"query": "地球半径", "answer": "6371 km"}
]

# 单个示例模板
example_template = """
问题:{query}
答案:{answer}
"""
example_prompt = PromptTemplate(
    input_variables=["query", "answer"],
    template=example_template
)

# 组合Few-shot模板
few_shot_prompt = FewShotPromptTemplate(
    examples=examples,
    example_prompt=example_prompt,
    prefix="请根据示例回答科学问题",
    suffix="问题:{input}\n答案:",
    input_variables=["input"]
)

result = few_shot_prompt.format(input="月球引力")
print(result)

输出

2.1.6 模板组合继承

通过拼接多个模板生成复杂提示。

适用场景:需要模块化构建的大型提示系统。

代码语言:javascript
复制
base_template = """你是一位{expert_type}专家,需要完成以下任务:"""

detail_template = """
任务详情:
{task_description}
技术约束:
{constraints}
"""

full_template = base_template + detail_template

prompt = PromptTemplate(
    input_variables=["expert_type", "task_description", "constraints"],
    template=full_template
)

result = prompt.format(
    expert_type="网络安全",
    task_description="设计企业级防火墙策略",
    constraints="1. 支持IPv6 2. 吞吐量≥10Gbps"
)

print(result)

输出

2.1.7 最佳实践建议

  1. 变量命名规范:使用 snake_case 命名变量(如 user_name
  2. 错误处理:始终用 try/except 包裹 format() 调用
  3. 模板版本控制:对模板文件使用 Git 管理
  4. 性能优化:对高频使用的模板进行缓存(如 functools.lru_cache

2.2 ChatPromptTemplate

很明显,这个是针对聊天场景的提示词模板。

2.2.1 基础角色消息模板

使用不同角色的消息模板(系统、用户、助手)构建对话结构。

适用场景:创建包含多角色消息的标准聊天提示。

代码语言:javascript
复制
from langchain.prompts import (
    ChatPromptTemplate,
    SystemMessagePromptTemplate,
    HumanMessagePromptTemplate,
    AIMessagePromptTemplate
)

# 定义各角色消息模板
system_template = SystemMessagePromptTemplate.from_template(
    "你是一位{role},用{language}回答问题"
)
human_template = HumanMessagePromptTemplate.from_template("问题:{question}")
ai_template = AIMessagePromptTemplate.from_template("答案草稿:{draft}")

# 组合成聊天模板
chat_prompt = ChatPromptTemplate.from_messages([
    system_template,
    human_template,
    ai_template
])

# 填充变量
messages = chat_prompt.format_messages(
    role="历史学家", 
    language="白话文",
    question="秦始皇统一六国的时间",
    draft="初步推测为公元前3世纪"
)

print(messages)

输出

2.2.2 动态对话历史管理

使用 MessagesPlaceholder 插入对话历史上下文。

适用场景:需要维护多轮对话的场景。

代码语言:javascript
复制
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain.schema import HumanMessage, AIMessage

# 定义包含历史记录的模板
chat_prompt = ChatPromptTemplate.from_messages([
    SystemMessagePromptTemplate.from_template("你是数学辅导AI"),
    MessagesPlaceholder(variable_name="history"),
    HumanMessagePromptTemplate.from_template("用户问题:{input}")
])

# 模拟历史对话
history = [
    HumanMessage(content="3的平方是多少?"),
    AIMessage(content="答案是9"),
    HumanMessage(content="再加5呢?"),
    AIMessage(content="答案是14")
]

# 填充当前问题
messages = chat_prompt.format_messages(
    history=history,
    input="现在乘以2是多少?"
)

print(messages)

输出

2.2.3 Few-shot 示例模板

通过示例对话指导模型输出格式。

适用场景:需要示例引导回答风格的场景。

代码语言:javascript
复制
from langchain.prompts import (
    ChatPromptTemplate,
    HumanMessagePromptTemplate,
    AIMessagePromptTemplate
)

# 创建示例模板
example_template = ChatPromptTemplate.from_messages([
    HumanMessagePromptTemplate.from_template("{user_example}"),
    AIMessagePromptTemplate.from_template("{ai_example}")
])

# 组合完整模板
few_shot_prompt = ChatPromptTemplate.from_messages([
    SystemMessagePromptTemplate.from_template("你是一个茶艺专家"),
    example_template,
    HumanMessagePromptTemplate.from_template("用户提问:{input}")
])

# 填充数据
messages = few_shot_prompt.format_messages(
    user_example="如何泡绿茶?",
    ai_example="1. 取3g茶叶\n2. 80℃水冲泡\n3. 等待2分钟",
    input="如何冲泡普洱茶?"
)

print(messages)

输出

2.2.4 部分变量预填充

提前固定部分参数,动态填充剩余参数。

适用场景:需要复用基础配置的场景。

代码语言:javascript
复制
from langchain.prompts import ChatPromptTemplate

# 基础模板
base_prompt = ChatPromptTemplate.from_messages([
    SystemMessagePromptTemplate.from_template("你是{company}的客服"),
    HumanMessagePromptTemplate.from_template("用户反馈:{feedback}")
])

# 预填充公司名称
partial_prompt = base_prompt.partial(company="华为公司")

# 填充剩余变量
messages = partial_prompt.format_messages(
    feedback="订单号1234未收到货物"
)

print(messages)

输出

2.2.5 动态角色切换

代码语言:javascript
复制
from langchain.prompts import ChatPromptTemplate,SystemMessagePromptTemplate,HumanMessagePromptTemplate

role_selector = {
    "tech": "技术专家",
    "child": "幼儿园老师"
}

prompt = ChatPromptTemplate.from_messages([
    SystemMessagePromptTemplate.from_template(
        "你是一个{role},用{level}语言回答"
    ),
    HumanMessagePromptTemplate.from_template("{question}")
])

messages = prompt.format_messages(
    role=role_selector["child"],
    level="童趣易懂",
    question="为什么天空是蓝色的?"
)
print(messages)

就这些玩法~

总结下,ChatPromptTemplate 的核心优势在于:

  1. 支持多角色消息编排
  2. 灵活管理对话历史
  3. 可组合不同类型模板
  4. 内置验证和部分填充功能

三 自定义模板

在实际应用场景中,我们还可以在如上两种模板基础之上,自定义提示词模板。自定义模板,就可以实现参数校验等等不同的逻辑。

假设我现在有这样一个需求,我希望传入一个函数名,系统能够据此读取出函数的内容,并给出解释。

那么我的代码如下:

代码语言:javascript
复制
from langchain.prompts import StringPromptTemplate
from langchain_openai import ChatOpenAI
import inspect

llm = ChatOpenAI(
    openai_api_base="https://dashscope.aliyuncs.com/compatible-mode/v1",
    openai_api_key="sk-xxx",
    model_name="qwen-max-2025-01-25",
    temperature=0
)

def hello():
    print("hello javaboy")
    return "hello ai"

PROMPT_TEMP = """你是一个经验丰富的python程序员,现在给你如下函数名称,你会按照如下格式,输出这段代码的名称、源码以及中文解释。
函数名称:{function_name}
源代码:{source_code}
代码解释:
"""

class CustomPrompt(StringPromptTemplate):
    def format(self,**kwargs)-> str:
        source_code=inspect.getsource(kwargs["function_name"])
        prompt=PROMPT_TEMP.format(
            function_name=kwargs["function_name"].__name__,
            source_code=source_code
        )
        return prompt
cp = CustomPrompt(input_variables=["function_name"])
pm = cp.format(function_name=hello)
message = llm.invoke(pm)
print(message.content)

最终执行结果如下:

另外,Python 里边还提供了两种模板,这个小伙伴们可以自行了解下,有 Java 基础这个应该很好懂:

  • jinja2
  • f-string

四 三层提示词设计

4.1 概念

通过将提示词分解为 策略层 → 逻辑层 → 执行层 的三层架构,实现复杂任务的模块化控制。其设计原理类似于我们 Java 的 MVC 分层模式:

层级

作用

控制颗粒度

修改频率

策略层

定义任务目标与边界

宏观

逻辑层

控制推理流程与规则

中观

执行层

实现具体操作步骤

微观


4.2 分层设计的优势

  1. 解耦与复用
    • 各层独立修改,例如调整执行层细节不会影响策略层
    • 可复用中间层模块(如将逻辑层用于相似任务)
  2. 可控性增强
    • 通过分层隔离风险,避免「蝴蝶效应」
    • 每层可单独添加验证机制
  3. 可解释性提升
    • 分阶段调试更容易定位问题
    • 生成过程可视化程度高
  4. 扩展性优化
    • 新增功能只需扩展对应层级
    • 便于集成外部工具/数据

4.3 案例:市场调研报告生成系统

4.3.1 策略层(Strategic Layer)

定义任务目标和整体约束,相当于「需求文档」。

代码语言:javascript
复制
strategy_prompt = """
角色:资深市场分析师  
核心任务:生成{industry}行业季度分析报告  
目标受众:企业高管  
核心要求:  
1. 包含TOP3趋势预测  
2. 必须引用至少{data_sources}个权威数据源  
3. 风险分析部分占比≥20%  
禁用内容:{forbidden_topics}  
输出格式:Markdown"""

4.3.2 逻辑层(Logic Layer)

控制分析流程和推理规则,相当于「算法流程图」。

代码语言:javascript
复制
logic_prompt = """
执行流程:  
1. 【数据收集】  
   - 从以下渠道获取信息:  
     {data_channels}  
   - 验证数据时效性(≥2023年)  

2. 【趋势分析】  
   IF 发现新兴技术相关数据 THEN  
     使用Gartner技术成熟度曲线分析  
   ELSE  
     采用PEST模型  

3. 【风险评估】  
   根据{risk_framework}框架分级  
   必须包含:  
   - 政策风险  
   - 供应链风险量化表"""

# 可配置参数  
config = {  
    "data_channels": ["行业白皮书", "上市公司财报", "国家统计局"],  
    "risk_framework": "COSO ERM"  
}

4.3.3 执行层(Execution Layer)

具体操作步骤和格式规范,相当于「代码实现」。

代码语言:javascript
复制
execution_prompt = """
生成步骤:  
[1] 标题:  
   - 行业名称+季度+「发展趋势与挑战分析」  
   - 示例:2023Q4人工智能行业发展趋势与挑战分析  

[2] 正文结构:  
   ## 一、核心趋势  
   - 趋势1(数据支撑:{quote_style})  
   - 趋势2(对比去年同期变化)  

   ## 二、风险评估  
   | 风险类型 | 概率 | 影响 | 缓解措施 |  
   |----------|------|------|----------|  

   ## 三、建议方案  
   - 短期(1年内):{action_verbs}  
   - 长期:技术路线图建议  

格式规范:  
   - 数据引用格式:[来源](链接)  
   - 风险概率使用★符号(1-5个)  
   - 禁止使用第一人称"""

# 微调参数  
style_config = {  
    "quote_style": "脚注编号引用",  
    "action_verbs": ["优化", "并购", "生态合作"]  
}

4.3.4 分层调用流程

代码语言:javascript
复制
def generate_report(industry):  
    # 策略层初始化  
    strategy = strategy_prompt.format(  
        industry=industry,  
        data_sources=5,  
        forbidden_topics=["未公开并购信息"]  
    )  

    # 逻辑层配置  
    logic = logic_prompt.format(**config)  

    # 执行层定制  
    execution = execution_prompt.format(**style_config)  

    # 组装完整提示  
    full_prompt = f"""  
    {strategy}  
    ------------------------  
    {logic}  
    ------------------------  
    {execution}  
    """  

    # 调用大模型  
    return llm.invoke(full_prompt)  

# 执行生成  
report = generate_report("新能源电池")

4.3.5 对比单层提示的优势

假设使用传统单层提示:

代码语言:javascript
复制
# 单层提示的典型问题:  
monolithic_prompt = """  
你是一个市场分析师,需要生成新能源电池行业报告,包含趋势预测和风险分析,  
用Markdown格式,数据要来自权威来源,记得分析政策风险,不要用第一人称,  
还要...(所有细节混在一起)  
"""  

这种提示词存在几个问题:

  1. 修改数据来源需要重写整个提示
  2. 无法复用趋势分析模块到其他行业
  3. 风险条款遗漏时难以定位
  4. 格式调整可能破坏内容逻辑

通过三层架构设计,可使复杂提示词的维护成本降低约 60%(根据 Anthropic 2023 年工程实践数据),同时生成质量稳定性提升 2-3 倍。这种设计尤其适合需要长期迭代的 AI 应用场景。

五 YAML 格式的模板

5.1 基础准备

1. 安装依赖

代码语言:javascript
复制
pip install pyyaml langchain

2. 示例 YAML 文件 (prompts/config.yaml):

代码语言:javascript
复制
# 基础提示模板
basic_prompt:
  input_variables: ["adjective", "content"]
  template: |
    用{adjective}的风格描述以下内容:
    {content}

# 多角色对话模板
chat_prompt:
  messages:
    - role: system
      content: 你是一位{expert_type}专家
    - role: human
      content: 请解释{concept}

5.2 基础模板读取

功能:加载简单文本模板

代码语言:javascript
复制
from langchain.prompts import PromptTemplate
import yaml

def load_yaml_prompt(file_path, prompt_name):
    with open(file=file_path, mode='r',encoding='UTF-8') as f:
        config = yaml.safe_load(f)
    
    prompt_config = config[prompt_name]
    return PromptTemplate(
        input_variables=prompt_config['input_variables'],
        template=prompt_config['template']
    )

# 使用示例
prompt = load_yaml_prompt('prompts/prompt-01.yaml', 'basic_prompt')
result = prompt.format(adjective="幽默", content="量子物理")
print(result)

输出

5.3 对话模板读取

功能:加载多角色对话配置

代码语言:javascript
复制
from langchain.prompts import ChatPromptTemplate, HumanMessagePromptTemplate, SystemMessagePromptTemplate
import yaml

def load_chat_prompt(file_path, prompt_name):
    with open(file=file_path, mode='r',encoding='UTF-8') as f:
        config = yaml.safe_load(f)
    
    chat_config = config[prompt_name]['messages']
    messages = []

    for msg in chat_config:
        if msg['role'] == 'system':
            messages.append(SystemMessagePromptTemplate.from_template(msg['content']))
        elif msg['role'] == 'human':
            messages.append(HumanMessagePromptTemplate.from_template(msg['content']))

    return ChatPromptTemplate.from_messages(messages)

# 使用示例
chat_prompt = load_chat_prompt('prompts/prompt-01.yaml', 'chat_prompt')
messages = chat_prompt.format_messages(
    expert_type="人工智能", 
    concept="机器学习"
)

for msg in messages:
    print(f"{msg.type}: {msg.content}")

输出

5.4 模板动态继承

功能:实现模板的层次化继承

YAML 配置 (advanced_prompt.yaml):

代码语言:javascript
复制
base_prompt:
  template: "基础内容:{base_content}"
  
extended_prompt:
  inherits: base_prompt
  adds:
    - template: "\n扩展内容:{extended_content}"

实现代码

代码语言:javascript
复制
def load_inherited_prompt(file_path, prompt_name):
    with open(file=file_path, mode='r',encoding='UTF-8') as f:
        config = yaml.safe_load(f)
    
    current_config = config[prompt_name]
    full_template = ""

    # 处理继承
    if 'inherits' in current_config:
        parent = load_inherited_prompt(file_path, current_config['inherits'])
        full_template += parent.template

    # 添加当前模板
    full_template += current_config.get('template', '')
    
    # 处理追加内容
    for addition in current_config.get('adds', []):
        full_template += addition['template']

    return PromptTemplate.from_template(full_template)

# 使用示例
prompt = load_inherited_prompt('prompts/advanced_prompt.yaml', 'extended_prompt')
result = prompt.format(base_content="基础部分", extended_content="扩展部分")
print(result)

输出

当然,利用 Python 对 JSON、TXT 等不同格式文件的读取能力,我们一样也可以将提示词管理在这些格式的文件中。

六 长度示例选择器

6.1 问题背景

在大语言模型(LLM)应用开发中,当提示词(Prompt)中包含大量示例时,可能会超出模型的上下文窗口限制(如 GPT-4 的 128K token 限制)。直接截断示例会导致信息缺失,而固定数量的示例则无法灵活适应不同长度的输入。

LengthBasedExampleSelector 的作用是 动态调整示例数量

  1. 对于较短的输入,自动包含更多示例以增强模型理解;
  2. 对于较长的输入,减少示例数量以避免超出长度限制。

6.2 案例

6.2.1 场景

生成中文词语的反义词,根据输入长度动态选择示例数量。

6.2.2 步骤说明

  1. 定义示例集:包含多个词语及其反义词的字典列表;
  2. 创建模板:格式化每个示例的展示方式;
  3. 初始化选择器:设置最大长度阈值;
  4. 构建动态提示模板:结合选择器生成最终提示词。
代码语言:javascript
复制
import os
os.environ["OPENAI_API_KEY"] = "your_api_key"  # 替换为实际API密钥

from langchain.prompts import PromptTemplate, FewShotPromptTemplate
from langchain.prompts.example_selector import LengthBasedExampleSelector

# 1. 定义示例集(中文反义词)
examples = [
    {"input": "高兴", "output": "悲伤"},
    {"input": "高大", "output": "矮小"},
    {"input": "明亮", "output": "昏暗"},
    {"input": "温暖", "output": "寒冷"},
    {"input": "快速", "output": "缓慢"}
]

# 2. 创建示例格式化模板
example_template = """
原词:{input}
反义:{output}
"""
example_prompt = PromptTemplate(
    input_variables=["input", "output"],
    template=example_template
)

# 3. 初始化LengthBasedExampleSelector
example_selector = LengthBasedExampleSelector(
    examples=examples,
    example_prompt=example_prompt,
    max_length=30,  # 格式化后提示词的最大长度(含输入)
    get_text_length=lambda x: len(x)  # 默认按字符数计算长度
)

# 4. 构建动态提示模板
dynamic_prompt = FewShotPromptTemplate(
    example_selector=example_selector,
    example_prompt=example_prompt,
    prefix="根据输入生成对应的中文反义词:",
    suffix="原词:{query}\n反义:",
    input_variables=["query"],
    example_separator="\n"
)

# 测试不同输入长度下的示例选择
short_query = "开心"
long_query = "这是一个非常非常长的输入句子,用来演示当输入内容过长时示例数量如何减少"

print("短输入时的提示词:\n", dynamic_prompt.format(query=short_query))
print("\n长输入时的提示词:\n", dynamic_prompt.format(query=long_query))

6.3 关键参数

参数

作用

默认值

max_length

格式化后提示词的最大字符数(含输入内容)

必填

get_text_length

自定义长度计算逻辑(如按 token 数计算)

len(text)

example_prompt

控制单个示例的格式化方式

必填

七 MMR

7.1 问题背景

在自然语言处理任务中,传统相似度检索可能返回高度重复的相似结果。例如在构建反义词提示词模板时,若直接选择前 k 个最相似示例,可能得到多个同类型词汇(如多个情绪类词汇),而无法覆盖其他语义类别。

MMR 算法通过平衡相关性多样性解决此问题,其核心公式为:

代码语言:javascript
复制
MMR = argmax [λ * sim1(Q,D) - (1-λ) * max sim2(D,R)]

其中 sim1 衡量与问题的相关性,sim2 衡量与已选结果的冗余度,λ 参数控制多样性权重(默认 0.5)。

7.2 应用场景

  1. 示例选择:构建 Few-shot 提示模板时避免示例同质化
  2. 推荐系统:电商商品/内容推荐需兼顾相关性与多样性
  3. 文本摘要:提取关键句时避免语义重复

7.3 完整代码案例

代码语言:javascript
复制
from langchain.prompts import PromptTemplate, FewShotPromptTemplate
from langchain_community.embeddings import OpenAIEmbeddings
from langchain_community.vectorstores import FAISS
from langchain.prompts.example_selector import MaxMarginalRelevanceExampleSelector
from langchain_community.embeddings import QianfanEmbeddingsEndpoint

os.environ["QIANFAN_AK"] = "xxx"
os.environ["QIANFAN_SK"] = "xxx"

# 步骤1:定义示例数据集
examples = [
    {"input": "happy", "output": "sad"},      # 情绪类
    {"input": "tall", "output": "short"},     # 尺寸类 
    {"input": "sunny", "output": "gloomy"},   # 天气类
    {"input": "hard", "output": "soft"},     # 质地类
    {"input": "fast", "output": "slow"}      # 速度类
]

# 步骤2:创建MMR选择器
example_selector = MaxMarginalRelevanceExampleSelector.from_examples(
    examples=examples,
    embeddings=QianfanEmbeddingsEndpoint(),  # 使用OpenAI文本嵌入模型
    vectorstore_cls=FAISS,           # 向量存储库类型
    k=3,                             # 最终选择3个示例
    fetch_k=10                       # 预筛选10个候选
)

# 步骤3:构建提示词模板
example_prompt = PromptTemplate(
    input_variables=["input", "output"],
    template="输入词: {input}\n反义词: {output}"
)

mmr_prompt = FewShotPromptTemplate(
    example_selector=example_selector,
    example_prompt=example_prompt,
    prefix="请根据以下示例生成反义词:",
    suffix="输入词: {query}\n反义词:",
    input_variables=["query"]
)

# 测试不同查询的示例选择
print(mmr_prompt.format(query="light"))  
# 可能输出包含hard/soft(质地)、fast/slow(速度)等跨类别示例

7.4 关键参数

参数

说明

k

最终返回的示例数量(建议 3-5)

fetch_k

预筛选候选集大小(需 ≥k)

lambda_mult

多样性权重(0-1,默认 0.5。值越大相关性越重要,值越小多样性越优先)

7.5 执行效果对比

当查询词为 "energetic" 时:

  • 传统相似度检索可能返回:
代码语言:javascript
复制
[happy/sad, sunny/gloomy, windy/calm]  # 均为情绪/天气类
  • MMR算法检索可能返回:
代码语言:javascript
复制
[energetic/lethargic, tall/short, hard/soft]  # 跨情绪、尺寸、质地类别

7.6 建议

  1. 嵌入模型选择:建议使用 text-embedding-3-large 等高维模型提升区分度
  2. 数据预处理:对示例进行词性标注/分类,辅助评估多样性
  3. 计算资源考量:MMR 时间复杂度为 O(kN),大数据集需配合 ANN 算法加速

八 最大余弦相似度

8.1 背景

在 RAG(检索增强生成)场景中,提示词工程需要根据用户输入动态选择最相关的知识库示例。最大余弦相似度通过计算向量空间中文本的语义相似性,可有效筛选与当前问题最匹配的参考示例,从而提升生成结果的质量。

余弦相似度的核心原理是将文本映射为高维向量(如 1536 维),通过向量夹角的余弦值衡量语义相似性。当值为 1 时表示语义完全一致,0 表示无关,-1 则完全相反。

8.2 代码案例

本案例需要首先安装 chromadb 依赖:

代码语言:javascript
复制
pip install langchain-openai chromadb

8.2.1 场景说明

构建反义词生成系统,根据输入词语动态选择最相关的示例构建提示词模板。

代码语言:javascript
复制
from langchain_core.prompts import (
    FewShotPromptTemplate, 
    PromptTemplate
)
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
from langchain_community.embeddings import QianfanEmbeddingsEndpoint
from langchain_core.example_selectors.semantic_similarity import SemanticSimilarityExampleSelector
# 1. 初始化Embedding模型(需替换为实际API密钥)

os.environ["QIANFAN_AK"] = "xxx"
os.environ["QIANFAN_SK"] = "xxx"
embeddings = QianfanEmbeddingsEndpoint()

# 2. 定义示例数据集
examples = [
    {"input": "happy", "output": "sad"},
    {"input": "tall", "output": "short"},
    {"input": "energetic", "output": "lethargic"},
    {"input": "sunny", "output": "gloomy"},
    {"input": "windy", "output": "calm"},
]

# 3. 创建示例选择器(保留最相似的2个示例)
example_selector = SemanticSimilarityExampleSelector.from_examples(
    examples=examples,
    embeddings=embeddings,
    vectorstore_cls=Chroma,  # 使用Chroma向量数据库
    k=2  # 选择相似度TOP2的示例
)

# 4. 构建动态提示词模板
example_prompt = PromptTemplate(
    input_variables=["input", "output"],
    template="输入词: {input}\n反义词: {output}"
)

dynamic_prompt = FewShotPromptTemplate(
    example_selector=example_selector,
    example_prompt=example_prompt,
    prefix="根据以下示例生成反义词:",
    suffix="输入词: {query}\n反义词:",
    input_variables=["query"]
)

# 5. 测试不同输入
print("--- 输入'tall'时的提示词 ---")
print(dynamic_prompt.format(query="tall"))
# 输出包含与"tall"相似度最高的2个示例(如"tall→short"和"happy→sad")

print("\n--- 输入'sunny'时的提示词 ---") 
print(dynamic_prompt.format(query="sunny"))
# 输出包含"sunny→gloomy"及相似度次高的示例(如"windy→calm")

8.2.2 关键实现解析

  1. 向量化处理:通过 OpenAIEmbeddings 将示例文本转换为向量。
  2. 相似度计算:Chroma 向量库自动计算输入 query 与所有示例的余弦相似度。
  3. 动态筛选k=2 参数确保每次选择相似度最高的前 2 个示例构建上下文。

8.3 扩展应用场景

  1. 多模态问答:将问题与知识库 QA 对进行相似度匹配
  2. 文档排序:在检索阶段使用余弦相似度筛选 TopN 相关文档
  3. 个性化推荐:根据用户历史对话选择相似案例生成回复

8.4 注意事项

  1. 向量模型选择:不同模型(如 text-embedding-3-small vs ada-002)会影响相似度计算精度
  2. 阈值设定:可添加相似度阈值过滤低质量匹配(如仅保留 >0.8 的示例)
  3. 计算效率:大规模数据建议采用 FAISS 等高性能向量库

好啦,提示词就和大伙聊这些。本文中的所有代码案例均可以直接运行

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-03-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 江南一点雨 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一 优秀的提示词
  • 二 两种模板
    • 2.1 PromptTemplate
      • 2.1.1 基础模板
      • 2.1.2 多变量混合
      • 2.1.3 文件加载模板
      • 2.1.4 部分模板填充
      • 2.1.5 Few-shot 示例模板
      • 2.1.6 模板组合继承
      • 2.1.7 最佳实践建议
    • 2.2 ChatPromptTemplate
      • 2.2.1 基础角色消息模板
      • 2.2.2 动态对话历史管理
      • 2.2.3 Few-shot 示例模板
      • 2.2.4 部分变量预填充
      • 2.2.5 动态角色切换
  • 三 自定义模板
  • 四 三层提示词设计
    • 4.1 概念
    • 4.2 分层设计的优势
    • 4.3 案例:市场调研报告生成系统
      • 4.3.1 策略层(Strategic Layer)
      • 4.3.2 逻辑层(Logic Layer)
      • 4.3.3 执行层(Execution Layer)
      • 4.3.4 分层调用流程
      • 4.3.5 对比单层提示的优势
  • 五 YAML 格式的模板
    • 5.1 基础准备
    • 5.2 基础模板读取
    • 5.3 对话模板读取
    • 5.4 模板动态继承
  • 六 长度示例选择器
    • 6.1 问题背景
    • 6.2 案例
      • 6.2.1 场景
      • 6.2.2 步骤说明
    • 6.3 关键参数
  • 七 MMR
    • 7.1 问题背景
    • 7.2 应用场景
    • 7.3 完整代码案例
    • 7.4 关键参数
    • 7.5 执行效果对比
    • 7.6 建议
  • 八 最大余弦相似度
    • 8.1 背景
    • 8.2 代码案例
      • 8.2.1 场景说明
      • 8.2.2 关键实现解析
    • 8.3 扩展应用场景
    • 8.4 注意事项
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档