跳转至

Prompt 设计

✨ Prompt Template 的作用是什么?常见的变量替换方式有哪些?

作用一句话:把“变”与“不变”解耦,让提示词从一次性手写变成可编程的模块。

image.png

具体价值体现在四个层面:

  • 可维护性:修改提示词逻辑只需改模板,不用翻遍所有调用代码。

  • 可复用:同一套模板可用于不同输入,如客服、面试等场景共享结构。

  • 防注入与安全:变量经过转义后填入,减少用户输入污染指令的可能。

  • 工程化迭代:模板可版本控制、A/B 测试、多语言管理。

常见变量替换方式:

① Python 原生字符串方式

最简单,适合原型开发,但缺少高级特性。

# f-string (Python 3.6+)
user = "Alice"
task = "总结"
template = f"你是助手,请帮用户{user}完成{task}。"
# 缺点:模板与变量耦合,不安全

# str.format()
template = "你是助手,请帮用户{user}完成{task}。"
prompt = template.format(user="Alice", task="总结")

② Jinja2 模板引擎

具备逻辑控制、过滤器、循环等功能,是生产环境首选。

from jinja2 import Template

template = Template("""
你是一个{{ role }}。
任务:{{ task }}
{% if examples %}
示例:
{% for ex in examples %}
- 输入: {{ ex.input }} -> 输出: {{ ex.output }}
{% endfor %}
{% endif %}
现在请处理:{{ user_input }}
""")

prompt = template.render(
    role="翻译专家",
    task="中译英",
    examples=[{"input": "你好", "output": "Hello"}],
    user_input="世界"
)

③ LangChain PromptTemplate

专为 LLM 设计,集成了变量验证、消息角色封装、自动序列化。

from langchain.prompts import ChatPromptTemplate

template = ChatPromptTemplate.from_messages([
    ("system", "你是{role},风格为{style}。"),
    ("user", "{input}")
])

messages = template.format_messages(
    role="代码导师",
    style="简洁",
    input="解释 Python 装饰器"
)
# messages 直接可用于 LLM API 调用

④ 结构化占位符(防注入)

将用户输入作为单独的消息块传递,而不是直接拼进指令。

# OpenAI API 直接支持多消息角色,天然隔离
api_messages = [
    {"role": "system", "content": "你是翻译助手,只翻译后面用户输入的内容。"},
    {"role": "user", "content": user_raw_input}  # 变量在此,不混入 system
]

这种方式从根本上防止了“忽略之前指令”类的注入攻击。


🧪 Few-shot Prompt 的示例选择策略有哪些?如何动态选择最相关的示例?

核心原则:不是随便塞几个例子,而是找那些能让模型“触类旁通”的黄金样例。

🔸 示例选择策略

  • 随机选择:从示例池中随机抽,简单但可能抽到无关样例,效果波动大。

  • 固定示例:人工挑选一批最能代表任务边界情况的例子,稳定但缺乏适应性。

  • 基于相似度检索(动态 Few-shot):对输入 query 用 Embedding 模型编码,从示例库中检索语义最接近的 K 个示例。这是目前效果最好的方式。

  • 多样性抽样:在相似基础上,用 MMR(最大边际相关性)等算法保证示例之间不要重复覆盖同一类问题。

  • 元数据过滤:根据用户标签(语言、级别、业务线)先过滤再检索,提升针对性。

🔸 动态选择最相关示例的实现

from sentence_transformers import SentenceTransformer
import faiss
import numpy as np

class DynamicFewShotSelector:
    def __init__(self, examples, embed_model_name="all-MiniLM-L6-v2"):
        """
        examples: list of dict, keys "input" and "output"
        """
        self.examples = examples
        self.embedder = SentenceTransformer(embed_model_name)
        # 离线阶段:将所有示例的 input 向量化
        self.example_inputs = [ex["input"] for ex in examples]
        self.example_embeddings = self.embedder.encode(self.example_inputs)
        # 构建 FAISS 索引
        self.index = faiss.IndexFlatIP(self.example_embeddings.shape[1])
        self.index.add(self.example_embeddings)

    def select(self, query, k=3):
        query_emb = self.embedder.encode([query])
        scores, indices = self.index.search(query_emb, k)
        selected = [self.examples[idx] for idx in indices[0]]
        return selected

# 示例使用
examples = [
    {"input": "天气如何", "output": "多云转晴"},
    {"input": "今天几号", "output": "2026-07-01"},
    {"input": "你是谁", "output": "我是AI助手"}
]
selector = DynamicFewShotSelector(examples)
relevant = selector.select("今天天气怎么样", k=2)

# 构造 Prompt
def build_prompt(query, few_shot_examples):
    example_text = ""
    for ex in few_shot_examples:
        example_text += f"Q: {ex['input']}\nA: {ex['output']}\n"
    prompt = f"""
根据以下示例回答问题,要求格式一致。
{example_text}
Q: {query}
A:"""
    return prompt

print(build_prompt("今天天气怎么样", relevant))

进阶优化: 可在检索后再用大模型重排序,或使用长短混合示例(长文本示例负责教推理,短示例教格式),效果会再上一个台阶。


🌐 3. Agent 需要处理多语言用户输入,Prompt Template 如何设计才能兼顾多语言?

设计思想:指令统一为英语(LLM 理解指令的母语),内容与回复语言动态切换。

LLM 训练时绝大部分指令数据是英文,用英文写 system prompt 往往遵循性最好。因此,多语言模板的核心是:

  • 指令层固定英文(角色、规则、格式约束)。

  • 让模型“检测用户语言并用同语言回复”。

  • 动态注入语言特定的格式范例。

多语言友好模板架构

from langchain.prompts import ChatPromptTemplate
from langdetect import detect

system_base = """You are a multilingual customer support agent.
Follow these rules:
1. Detect the language of the user's message.
2. Reply in the SAME language.
3. Keep replies professional and helpful.
4. If the query is out of scope, politely decline in the detected language.
"""

# 语言专属的输出格式提示(可选,增强稳定性)
lang_hints = {
    "zh": "请用中文回复,使用亲切的「您」称呼。",
    "en": "Reply in English, be concise.",
    "ja": "日本語で返答し、敬語を使ってください。",
    "default": "Reply in the detected language naturally."
}

def build_multilingual_prompt(user_input: str):
    # 自动检测语言
    try:
        lang = detect(user_input)
    except:
        lang = "default"
    hint = lang_hints.get(lang, lang_hints["default"])

    # 组装系统提示
    system_msg = f"{system_base}\n当前语言指示:{hint}"

    # 使用 ChatPromptTemplate 保证角色隔离
    prompt_template = ChatPromptTemplate.from_messages([
        ("system", system_msg),
        ("user", "{input}")
    ])
    return prompt_template.format_messages(input=user_input)

# 测试
print(build_multilingual_prompt("我的订单什么时候发货?"))
print(build_multilingual_prompt("When will my order be shipped?"))

更深的工程化实践:

  • 国际化示例库:为每种语言准备 few-shot 范例,根据检测结果抽取对应语言的例子,能显著提高小语种稳定性。

  • 回退翻译管道:对稀缺语言,可先翻译成英文处理,再将英文回复翻译回原语言,但会增加延迟和不准确风险。

  • 结构化输出约束:要求模型输出 JSON,并在 schema 中定义多语言字段,例如 {"reply_zh": "...", "reply_en": "..."},由前端按需展示。

完整的多语言 Agent 代码骨架:

def multilingual_agent(user_input):
    lang = detect(user_input)
    # 1. 选择对应语言的 few-shot
    examples = select_few_shot(lang, user_input)
    # 2. 构建多语言系统提示
    system = build_system_prompt(lang)
    # 3. 最终组装
    messages = [
        {"role": "system", "content": system},
        *examples,
        {"role": "user", "content": user_input}
    ]
    response = llm(messages)
    return response

用一句话记住:

英语是“指令语言”,用户的母语是“交流语言”,模板把两者统一在同一个上下文中,让模型按指令切换输出语言,既不牺牲遵循性,又不丢失本地化体验。