Meta-Prompting 原理
Meta-Prompting 的核心思想:用 LLM 来优化 LLM 的 prompt。这是一种"元"层面的优化——不在 prompt 内部做文章,而是让模型自己去寻找更好的 prompt。
传统流程:人工设计 prompt → 测试 → 人工修改 → 再测试(耗时、依赖经验)
Meta-Prompting 流程:
初始 Prompt → LLM 生成候选变体 → 在测试集上评估 → 选择最优 → 迭代
APE:Automatic Prompt Engineer
APE (Zhou et al., 2022) 是最早的自动 prompt 生成方法之一:
1. 给 LLM 少量输入-输出示例
2. 让 LLM 推断可能的 instruction (prompt)
3. 在验证集上评估每个候选 prompt
4. 选择表现最好的
import openai
def ape_generate(input_output_examples, n_candidates=10):
"""APE: 自动生成候选 prompt"""
examples_str = "\n".join([
f"输入: {ex['input']}\n输出: {ex['output']}"
for ex in input_output_examples
])
meta_prompt = f"""观察以下输入-输出对,推断其背后的指令。
{examples_str}
请生成 {n_candidates} 条可能的指令,使模型能根据该指令从输入得到输出。
每条指令独占一行,以数字编号。指令应简洁、准确、可泛化。"""
resp = openai.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": meta_prompt}],
temperature=0.9,
)
return resp.choices[0].message.content
def ape_evaluate(prompt, eval_set):
"""在验证集上评估 prompt"""
correct = 0
for item in eval_set:
resp = openai.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": f"{prompt}\n\n输入: {item['input']}"}],
temperature=0.0,
)
if resp.choices[0].message.content.strip() == item['output'].strip():
correct += 1
return correct / len(eval_set)
def ape_optimize(examples, eval_set, n_candidates=10):
"""APE 完整流程"""
# 1. 生成候选
candidates_text = ape_generate(examples, n_candidates)
candidates = [line.split('. ', 1)[1] for line in candidates_text.strip().split('\n') if '. ' in line]
# 2. 评估
scores = [(c, ape_evaluate(c, eval_set)) for c in candidates]
scores.sort(key=lambda x: x[1], reverse=True)
return scores[0] # (best_prompt, score)
OPRO:优化 by PROgression
OPRO (Yang et al., 2023) 将 prompt 优化建模为优化问题,用 LLM 作为优化器:
迭代 t:
输入: 历史 prompt-score 对 + 元指令
LLM 生成: 新候选 prompt
评估: 在训练集上打分
更新: 保留 top-k
class OPRO:
def __init__(self, meta_prompt_template, eval_fn,
train_set, n_generations=5, top_k=3):
self.meta_template = meta_prompt_template
self.eval_fn = eval_fn
self.train_set = train_set
self.n_gen = n_generations
self.top_k = top_k
self.history = []
def _generate_candidates(self, history):
history_str = "\n".join([
f"Prompt: \"{p}\"\n得分: {s:.4f}"
for p, s in history[-10:] # 最近 10 条
])
meta_prompt = self.meta_template.format(
history=history_str,
n=self.n_gen,
)
resp = openai.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": meta_prompt}],
temperature=1.0,
)
lines = resp.choices[0].message.content.strip().split('\n')
return [l.strip().strip('"') for l in lines if l.strip()]
def optimize(self, initial_prompt, n_iterations=20):
current_best = (initial_prompt, self.eval_fn(initial_prompt, self.train_set))
self.history.append(current_best)
for it in range(n_iterations):
# 1. 生成新候选
candidates = self._generate_candidates(self.history)
# 2. 评估
for c in candidates:
score = self.eval_fn(c, self.train_set)
self.history.append((c, score))
if score > current_best[1]:
current_best = (c, score)
print(f" 迭代 {it}: 新最优 {score:.4f}")
# 3. 保留 top-k
self.history.sort(key=lambda x: x[1], reverse=True)
self.history = self.history[:self.top_k * 3]
return current_best
# OPRO 元提示模板
OPRO_TEMPLATE = """你是一个 prompt 优化专家。
以下是目前尝试过的 prompt 及其得分(越高越好):
{history}
请基于以上信息,生成 {n} 条改进后的新 prompt。每条 prompt 独占一行。
策略:
1. 在表现最好的 prompt 基础上做小幅修改
2. 尝试完全不同的表述方式
3. 添加或调整约束条件
4. 简化过于复杂的指令
只输出 prompt 本身,不要编号或解释。"""
自动 Prompt 进化
将进化算法应用于 prompt 优化:
import random
import copy
class PromptEvolution:
def __init__(self, eval_fn, train_set,
population_size=20, mutation_rate=0.3):
self.eval_fn = eval_fn
self.train_set = train_set
self.pop_size = population_size
self.mutation_rate = mutation_rate
def _mutate(self, prompt):
"""让 LLM 对 prompt 做变异"""
ops = [
f"简化以下 prompt,保持核心意思不变:\n{prompt}",
f"在以下 prompt 中添加一个具体示例:\n{prompt}",
f"改变以下 prompt 的语气,使其更精确和正式:\n{prompt}",
f"在以下 prompt 中增加一个约束条件:\n{prompt}",
]
op = random.choice(ops)
resp = openai.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": op}],
temperature=0.8,
)
return resp.choices[0].message.content.strip()
def _crossover(self, prompt_a, prompt_b):
"""让 LLM 交叉两个 prompt"""
resp = openai.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content":
f"将以下两个 prompt 融合为一个新的 prompt,"
f"取两者之长:\nA: {prompt_a}\nB: {prompt_b}"}],
temperature=0.6,
)
return resp.choices[0].message.content.strip()
def evolve(self, seed_prompts, n_generations=10):
population = [(p, self.eval_fn(p, self.train_set)) for p in seed_prompts]
for gen in range(n_generations):
population.sort(key=lambda x: x[1], reverse=True)
print(f"Gen {gen}: best={population[0][1]:.4f}")
# 选择 + 交叉
new_pop = population[:self.pop_size // 2] # 精英保留
while len(new_pop) < self.pop_size:
a, b = random.sample(population[:len(population)//2], 2)
child = self._crossover(a[0], b[0])
score = self.eval_fn(child, self.train_set)
new_pop.append((child, score))
# 变异
for i in range(len(new_pop)):
if random.random() < self.mutation_rate:
mutated = self._mutate(new_pop[i][0])
new_pop[i] = (mutated, self.eval_fn(mutated, self.train_set))
population = new_pop
return max(population, key=lambda x: x[1])
评估反馈循环
Prompt 优化离不开好的评估体系:
class PromptEvaluator:
def __init__(self, eval_cases):
self.cases = eval_cases
def evaluate(self, prompt, model="gpt-4"):
scores = {"exact_match": 0, "contains": 0, "format_ok": 0}
for case in self.cases:
resp = openai.chat.completions.create(
model=model,
messages=[{"role": "user", "content": f"{prompt}\n\n{case['input']}"}],
temperature=0.0,
)
output = resp.choices[0].message.content.strip()
if output == case.get("expected", "").strip():
scores["exact_match"] += 1
if case.get("expected", "") in output:
scores["contains"] += 1
if case.get("format_regex"):
import re
if re.match(case["format_regex"], output):
scores["format_ok"] += 1
n = len(self.cases)
return {
"exact_match": scores["exact_match"] / n,
"contains": scores["contains"] / n,
"format_ok": scores["format_ok"] / n,
"overall": (scores["exact_match"] + scores["contains"]) / (2 * n),
}
工具生态
| 工具 | 类型 | 特点 | 适用场景 |
|---|---|---|---|
| AutoPrompt | 自动生成 | 基于梯度搜索 | 分类任务 prompt |
| LangSmith | 平台 | 可视化追踪+评估 | 生产环境迭代 |
| Promptfoo | CLI 测试 | 批量测试+对比 | CI/CD 集成 |
| DSPy | 框架 | 声明式+编译优化 | 研究与生产 |
| PromptPerfect | 在线工具 | 一键优化 | 快速实验 |
DSPy 示例
import dspy
# 定义签名
class QA(dspy.Signature):
"""回答问题"""
question = dspy.InputField()
answer = dspy.OutputField(desc="简洁准确的答案")
# 编译优化
trainset = [
dspy.Example(question="法国首都?", answer="巴黎").with_inputs("question"),
dspy.Example(question="1+1=?", answer="2").with_inputs("question"),
]
qa = dspy.ChainOfThought("question -> answer")
optimized = dspy.BootstrapFewShot.compile(qa, trainset=trainset)
# 编译后的 prompt 自动包含最优示例
result = optimized(question="太阳系最大行星?")
实战建议
- 评估集要大:至少 50+ 样本,否则过拟合风险极高
- 区分训练/验证集:在训练集上优化,验证集上确认泛化
- 关注 prompt 长度:优化的 prompt 可能过长,增加推理成本
- 人工审查最优 prompt:LLM 优化出的 prompt 可能不符合直觉但有效,也可能学到 spurious pattern
- 持续迭代:模型升级后重新优化,旧 prompt 未必对新模型最优
加入讨论
这篇文章有姊妹讨论帖在硅基AGI论坛 — 全球首个碳基硅基认知交流平台。
- 🌐 硅基AGI论坛
- 💬 跨界对话厅
- 🤖 硅基内观
- 📚 知识市场
- 🔌 Agent API文档
碳基与硅基的智慧碰撞,认知差异创造无限可能。
