跳到主要内容

优化提示(实验性)

MLflow 允许您通过 MLflow 的统一接口,利用 mlflow.genai.optimize_prompt() API 将您的提示集成到高级提示优化技术中。此功能可通过利用评估指标和标记数据来帮助您自动改进提示。MLflow 内置支持诸如 DSPy 的 MIPROv2GEPA 等优化算法。您还可以通过扩展 MLflow 的基础优化器类 BasePromptOptimizer 来实现自定义优化算法。

主要优点
  • 统一接口:通过中立的接口访问最先进的提示优化算法。
  • 可扩展:通过扩展基础优化器类来创建自定义优化算法。
  • 提示管理:与 MLflow 提示注册表集成,以实现可重用性、版本控制和 lineage。
  • 评估:利用 MLflow 的评估功能全面评估提示性能。

优化概述

为了使用 mlflow.genai.optimize_prompt() API,您需要准备以下内容

组件示例
提示
在 MLflow 中注册
mlflow.register_prompt(name="qa", template="Answer {{question}}")
评分器
评估提示质量
@scorer
def exact_match(expectations, outputs):
return expectations == outputs
数据
输入和预期
[
{"inputs": {"question": "2+2"}, "expectations": {"answer": "4"}},
{"inputs": {"question": "2+3"}, "expectations": {"answer": "5"}}
]
目标 LLM
要优化的模型
LLMParams(model_name="openai/gpt-4.1-mini")
优化器配置
优化设置
OptimizerConfig(
algorithm="DSPy/MIPROv2",
num_instruction_candidates=6,
max_few_show_examples=2
)

开始使用

这是一个优化问答提示的简单示例

作为先决条件,您需要安装 DSPy。

$ pip install dspy>=2.6.0 mlflow>=3.1.0

然后,运行以下代码注册初始提示并对其进行优化。

import os
from typing import Any
import mlflow
from mlflow.genai.scorers import scorer
from mlflow.genai.optimize import OptimizerConfig, LLMParams

os.environ["OPENAI_API_KEY"] = "<YOUR_OPENAI_API_KEY>"


# Define a custom scorer function to evaluate prompt performance with the @scorer decorator.
# The scorer function for optimization can take inputs, outputs, and expectations arguments, but not the trace argument.
# Note that the DSPy/MIPROv2 optimizer requires metrics to receive outputs as a dict.
@scorer
def exact_match(expectations: dict[str, Any], outputs: dict[str, Any]) -> bool:
return expectations["answer"] == outputs["answer"]


# Register the initial prompt
initial_template = """
Answer to this math question: {{question}}.
Return the result in a JSON string in the format of {"answer": "xxx"}.
"""

prompt = mlflow.genai.register_prompt(
name="math",
template=initial_template,
)

# The data can be a list of dictionaries, a pandas DataFrame, or an mlflow.genai.EvaluationDataset
# It needs to contain inputs and expectations where each row is a dictionary.
train_data = [
{
"inputs": {"question": "Given that $y=3$, evaluate $(1+y)^y$."},
"expectations": {"answer": "64"},
},
{
"inputs": {
"question": "The midpoint of the line segment between $(x,y)$ and $(-9,1)$ is $(3,-5)$. Find $(x,y)$."
},
"expectations": {"answer": "(15,-11)"},
},
{
"inputs": {
"question": "What is the value of $b$ if $5^b + 5^b + 5^b + 5^b + 5^b = 625^{(b-1)}$? Express your answer as a common fraction."
},
"expectations": {"answer": "\\frac{5}{3}"},
},
{
"inputs": {"question": "Evaluate the expression $a^3\\cdot a^2$ if $a= 5$."},
"expectations": {"answer": "3125"},
},
{
"inputs": {"question": "Evaluate $\\lceil 8.8 \\rceil+\\lceil -8.8 \\rceil$."},
"expectations": {"answer": "17"},
},
]

eval_data = [
{
"inputs": {
"question": "The sum of 27 consecutive positive integers is $3^7$. What is their median?"
},
"expectations": {"answer": "81"},
},
{
"inputs": {"question": "What is the value of $x$ if $x^2 - 10x + 25 = 0$?"},
"expectations": {"answer": "5"},
},
{
"inputs": {
"question": "If $a\\ast b = 2a+5b-ab$, what is the value of $3\\ast10$?"
},
"expectations": {"answer": "26"},
},
{
"inputs": {
"question": "Given that $-4$ is a solution to $x^2 + bx -36 = 0$, what is the value of $b$?"
},
"expectations": {"answer": "-5"},
},
]

# Optimize the prompt
result = mlflow.genai.optimize_prompt(
target_llm_params=LLMParams(model_name="openai/gpt-4.1-mini"),
prompt=prompt,
train_data=train_data,
eval_data=eval_data,
scorers=[exact_match],
optimizer_config=OptimizerConfig(
num_instruction_candidates=8,
max_few_show_examples=2,
),
)

# The optimized prompt is automatically registered as a new version
print(result.prompt.uri)

在上面的示例中,平均性能分数从 0 增加到 0.5。优化过程完成后,您可以访问 MLflow 提示注册表页面并查看优化后的提示。

Optimized Prompt

请注意,DSPy/MIPROv2 优化器的优化提示期望输出为 JSON 字符串。因此,您需要在应用程序中使用 json.loads 来解析输出。有关如何加载优化后提示的信息,请参阅 加载和使用提示

import mlflow
import json
import openai


def predict(question: str, prompt_uri: str) -> str:
prompt = mlflow.genai.load_prompt(prompt_uri)
content = prompt.format(question=question)
completion = openai.chat.completions.create(
model="gpt-4.1-mini",
messages=[{"role": "user", "content": content}],
temperature=0.1,
)

return json.loads(completion.choices[0].message.content)["answer"]

配置

您可以使用 OptimizerConfig 自定义优化过程,其中包含以下参数

  • algorithm:要使用的优化算法。可以是字符串(例如,“DSPy/MIPROv2”、“DSPy/GEPA”)或自定义优化器类。默认值:“DSPy/MIPROv2”
  • num_instruction_candidates:要尝试的候选指令数。默认值:6
  • max_few_show_examples:在 few-shot 演示中显示示例的最大数量。默认值:6
  • optimizer_llm:用于优化的 LLM。对于 GEPA,这用作反射 LM(建议:使用更强大的模型,如 GPT-4)。默认值:None(使用目标 LLM)
  • extract_instructions:是否从初始提示模板中提取指令。默认值:True
  • verbose:在优化过程中是否显示优化器日志。默认值:False
  • autolog:是否自动记录优化参数、数据集和指标。如果设置为 True,将自动创建一个 MLflow 运行来存储它们。默认值:False

有关更多详细信息,请参阅 OptimizerConfig

自定义优化器

MLflow 支持通过扩展基础优化器类来创建自定义提示优化算法。这允许您实现特定领域的优化策略或与其他优化库集成。

BasePromptOptimizer

对于自定义优化逻辑,请扩展 BasePromptOptimizer

from mlflow.genai.optimize import BasePromptOptimizer, OptimizerConfig, OptimizerOutput
from mlflow.genai.optimize.types import LLMParams
from mlflow.entities.model_registry import PromptVersion
from mlflow.genai.scorers import Scorer
from typing import Optional, Callable, Any
import pandas as pd


class CustomOptimizer(BasePromptOptimizer):
# Inherit the BasePromptOptimizer class and implement the `optimize` method.
def optimize(
self,
prompt: PromptVersion,
target_llm_params: LLMParams,
train_data: pd.DataFrame,
scorers: list[Scorer],
objective: Optional[Callable[[dict[str, Any]], float]] = None,
eval_data: Optional[pd.DataFrame] = None,
) -> OptimizerOutput:
# Implement your custom optimization logic here

optimized_template = f"Please answer accurately: {prompt.template}"

return OptimizerOutput(
optimized_prompt=optimized_template,
optimizer_name="CustomOptimizer",
final_eval_score=0.85,
initial_eval_score=0.75,
)


# Use the custom optimizer
result = mlflow.genai.optimize_prompt(
target_llm_params=LLMParams(model_name="openai/gpt-4o-mini"),
prompt=prompt,
train_data=train_data,
scorers=[exact_match],
optimizer_config=OptimizerConfig(algorithm=CustomOptimizer),
)

DSPyPromptOptimizer

对于基于 DSPy 的优化,请扩展 DSPyPromptOptimizer 类,该类提供了 DSPy 集成基础设施

import dspy
from typing import Callable
from mlflow.genai.optimize import (
DSPyPromptOptimizer,
OptimizerOutput,
format_dspy_prompt,
)
from mlflow.entities.model_registry import PromptVersion


class CustomDSPyOptimizer(DSPyPromptOptimizer):
# Inherit the DSPyPromptOptimizer class and implement the `run_optimization` method.
def run_optimization(
self,
prompt: PromptVersion,
program: dspy.Module,
metric: Callable[[dspy.Example], float],
train_data: list,
eval_data: list,
) -> OptimizerOutput:
# Use DSPy's optimization components with your custom logic
# Example using DSPy's BootstrapFewShot optimizer
optimizer = dspy.BootstrapFewShot(
metric=metric,
max_bootstrapped_demos=self.optimizer_config.max_few_show_examples,
)

# Compile the program
compiled_program = optimizer.compile(
student=program,
trainset=train_data,
)

return OptimizerOutput(
optimized_prompt=format_dspy_prompt(compiled_program),
optimizer_name="BootstrapFewShot",
)


# Use the custom DSPy optimizer
result = mlflow.genai.optimize_prompt(
target_llm_params=LLMParams(model_name="openai/gpt-4o-mini"),
prompt=prompt,
train_data=train_data,
scorers=[exact_match],
optimizer_config=OptimizerConfig(algorithm=CustomDSPyOptimizer),
)
注意

使用自定义优化器时,请确保它们返回一个 OptimizerOutput 对象,其中包含优化后的提示和评估分数。

性能基准

信息

我们正在积极进行基准测试。这些基准测试结果是初步的,可能会发生变化。

MLflow 提示优化可以提高您的应用程序在各种任务上的性能。以下是使用 MLflow 优化功能在多个数据集上进行测试的结果

  • ARC-Challenge:ai2_arc 数据集包含一组选择题科学问题
  • GSM8K:gsm8k 数据集包含一组语言多样化的中小学数学应用题
  • MATH:竞赛数学问题,需要高级推理和解决问题的能力
数据集模型基线优化后
MATHgpt-4.1o-nano17.25%18.48%
GSM8Kgpt-4.1o-nano21.46%49.89%
ARC-Challengegpt-4.1o-nano71.42%89.25%
MATHLlama4-maverick33.06%33.26%
GSM8KLlama4-maverick55.80%58.22%
ARC-ChallengeLlama4-maverick0.17%93.17%

上述结果是针对 gpt-4.1o-nanoLlama4-maverick 使用 DSPy 的 MIPROv2 算法和默认设置进行的基准测试,并为每个任务使用了特定的评估指标。如果您使用不同的模型、配置、数据集或起始提示,结果可能会发生变化。这些结果表明 MLflow 的提示优化可以解决许多挑战,并以最小的努力带来可衡量的性能提升。

常见问题

支持的数据集格式是什么?

mlflow.genai.optimize_prompt() API 的训练和评估数据可以是字典列表、pandas DataFrame、spark DataFrame 或 mlflow.genai.EvaluationDataset。无论哪种情况,数据都需要包含输入和预期列,这些列包含输入字段和预期输出字段的字典。每个输入或预期字典可以包含原始类型、列表、嵌套字典和 Pydantic 模型。数据类型是从数据集的第一行推断出来的。

# ✅ OK
[
{
"inputs": {"question": "What is the capital of France?"},
"expectations": {"answer": "Paris"},
},
]

# ✅ OK
[
{
"inputs": {"question": "What are the three largest cities of Japan?"},
"expectations": {"answer": ["Tokyo", "Osaka", "Nagoya"]},
},
]

# ✅ OK
from pydantic import BaseModel


class Country(BaseModel):
name: str
capital: str
population: int


[
{
"inputs": {"question": "What is the capital of France?"},
"expectations": {
"answer": Country(name="France", capital="Paris", population=68000000)
},
},
]

# ❌ NG
[
{
"inputs": "What is the capital of France?",
"expectations": "Paris",
},
]

如何组合多个评分器?

虽然 mlflow.genai.optimize_prompt() API 接受多个评分器,但在优化过程中,优化器需要将它们组合成一个单一的分数。默认情况下,优化器会计算所有数值或布尔型评分器的总分数。如果您想使用自定义聚合函数或使用返回非数字值的评分器,可以将自定义聚合函数传递给 objective 参数。

@scorer
def safeness(outputs: dict[str, Any]) -> bool:
return "death" not in outputs["answer"].lower()


@scorer
def relevance(expectations: dict[str, Any], outputs: dict[str, Any]) -> bool:
return expectations["answer"] in outputs["answer"]


def objective(scores: dict[str, Any]) -> float:
if not scores["safeness"]:
return -1
return scores["relevance"]


result = mlflow.genai.optimize_prompt(
target_llm_params=LLMParams(model_name="openai/gpt-4.1-mini"),
prompt=prompt,
train_data=train_data,
eval_data=eval_data,
scorers=[safeness, relevance],
objective=objective,
)

如何创建自定义优化器?

MLflow 提供了两个基础类来创建自定义优化器

  1. BasePromptOptimizer:用于自定义优化逻辑。为了进行自定义,您必须实现自己的 optimize 方法。
  2. DSPyPromptOptimizer:用于基于 DSPy 的优化。对此优化器的自定义涉及构建一个 run_optimization 方法。MLflow 将处理利用您的自定义接口所需的 DSPy 设置。

当您希望完全控制优化过程时,请选择 BasePromptOptimizer,或者当您希望在自定义优化策略的同时利用 DSPy 的生态系统时,请选择 DSPyPromptOptimizer