APE 自动化指令集构建与优化实践
背景介绍
Automatic Prompt Engineer (APE) 基于论文《Large Language Models Are Human-Level Prompt Engineers》(2023.3)。其核心思想是通过逆向工程,根据输入和输出样本让模型生成并寻找更优的 Prompt。这种方法旨在减少人工编写指令的成本,并利用大模型自身的能力来优化任务描述。
指令生成策略
Few-Shot 样本设计
作者基于原始输入 + 输出(部分样本仅有输出,如自由生成类任务),让大模型预测原始指令是什么。虽然论文中提到了多种模板,但实际测试表明,只要采用"Few-Shot 样本在前,待生成的指令在最后"的向前生成类型即可。
原始论文使用 text-davinci-002,每个样本使用 5 条 few-shot 样例作为上下文。在实际应用中,可以将生成指令的模型改为 ChatGPT,并根据对话模型的特点调整 Prompt 模板。ChatGPT 相比 Davinci 系列废话较多,需要明确约束其输出格式。
关键经验总结
- 抽象任务的样本多样性:对于相对抽象、偏生成类的任务,Few-Shot 样本要给够,模型才有可能猜到'无偏'的指令。例如相似新闻标题生成任务,如果样本太少,模型可能只能预测到子集指令。需要根据任务输入输出的多样性程度调整 Few-Shot 样本数。
- 构建指令样本说人话:样本中的输出应符合作务语意。例如将判断两个标题是否描述同一事件的分类任务,如果输出是'相同/不相同',模型能准确预测指令;如果输出过于模糊,模型会给出笼统的回答。
- 不要你以为,要模型以为:在医学术语标准化等任务上对比发现,合理使用的模型生成指令往往比人工编写的指令准确率更高。这可能是因为模型之间的一致性,使得模型生成的指令能提供更精准的任务描述。
指令打分机制
为了评估多组样本生成的多个候选指令的优劣,主要使用两种打分方式:
Accuracy(准确率)
使用模型预测的正确率。例如对于 QA 问题,根据不同指令在相同样本上模型回答的准确率来评价指令的效果。
Log Probability(对数概率)
使用模型预测的 logprobs 作为评价指标。这是一个 Trick:将输入 + 输出 + 指令都喂给模型,计算模型生成原始输出的概率。这解决了生成类任务解码随机性导致不同指令无法比较的问题。
获取 LogProbs 方法:调用 OpenAI 接口时设置
echo=True,logprobs=1,返回所有采样 token 的 logprobs。设置max_tokens=0不让模型生成新文本,即可让模型原样返回输入及对应的条件概率。
优化流程
作者加入了随机搜索:过滤低分指令,对高分指令集让模型基于特定模板生成相似指令,排序选出最优。在实际实现中,建议保留人工干预环节:针对得到的高分指令,补充自己认为缺少核心信息后,再次使用 Log Prob 打分评估是否有提升。
代码实现示例
以下是一个简化的 Python 实现框架,展示了如何调用 API 进行指令生成与打分。
import openai
import os
from typing import List, Dict
# 初始化客户端
client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
def generate_instruction(input_data: str, output_data: , few_shots: []) -> :
prompt_template =
formatted_few_shots = .join([ i, s (few_shots)])
full_prompt = prompt_template.(
=input_data,
output=output_data,
**{: s[], : s[] i, s (few_shots)}
)
response = client.chat.completions.create(
model=,
messages=[{: , : full_prompt}],
temperature=
)
response.choices[].message.content
() -> :
prompt =
response = client.chat.completions.create(
model=,
messages=[{: , : prompt}],
echo=,
logprobs=,
max_tokens=
)
total_logprob = (token.logprob token response.choices[].logprobs.content_tokens)
total_logprob
__name__ == :
samples = [
{: , : },
{: , : }
]
instruction = generate_instruction(, , samples)
score = score_instruction(instruction, , )
()
()


