Guide · 使用教程
DSPy Python 教程:提示词优化的数据划分、评分指标与预算控制
使用固定版本、合成客服消息和本地模拟模型,验证数据隔离、严格评分、编译与保存,并说明 GEPA 预算及真实优化边界。
在正式运行提示词优化前,先验证训练样本没有混入验收集、评分器能拒绝错误输出,并且保存后的程序能重新加载。本教程用 DSPy 的真实接口和本地模拟模型完成这些检查,再说明如何为 GEPA 设计数据和预算。
验证使用 Python 3.11 与 dspy==3.4.1,样本均为合成客服消息。DummyLM 是框架里的测试辅助类,答案由脚本预设,不能测量模型能力或优化效果;测试期间阻断网络连接,没有调用付费模型,也没有运行真实 GEPA 搜索。
1. 固定版本与运行范围
在一个新目录创建环境:
python3.11 -m venv .venv
source .venv/bin/activate
python -m pip install 'dspy==3.4.1'
下面直接使用 dspy 包,不安装历史名称的替代包。当前官方文档与项目入口见 DSPy和仓库。完整依赖、模型和 adapter 也应随实验固定,升级后重新验收。
2. 建立数据隔离和严格评分
保存为 workflow.py。每个样本保留唯一 id 和来源 source,供划分审计使用;模型输入只含 text,参考标签不会放进待预测输入。
验证器检查来源跨集合、重复 id,以及经 Unicode NFKC、大小写与空格规范化后的精确重复。这个指纹只用于去重,不能发现所有语义近重复,也不是敏感数据匿名化方法。
评分函数只接受合法且完全匹配的标签,返回布尔值。这样可以避免把“合法 JSON”或“非空字符串”误当正确,也避免在接受真值的接口里把低但非零的分数无意视为通过。不同优化器对 metric 返回值有不同要求,应按当前接口核对。
hashlib
os
unicodedata
os.environ.setdefault(, )
dspy
dspy.utils DummyLM
dspy.configure_cache(enable_disk_cache=, enable_memory_cache=)
LABELS = {, , }
SPLITS = {
: [
{: , : , : , : },
{: , : , : , : },
],
: [
{: , : , : , : },
{: , : , : , : },
],
: [
{: , : , : , : },
{: , : , : , : },
],
}
():
normalized = .join(unicodedata.normalize(, text).casefold().split())
hashlib.sha256(normalized.encode()).hexdigest()
():
(splits) != {, , }:
ValueError()
ids, source_owner, content_owner = (), {}, {}
split, rows splits.items():
rows:
ValueError()
row rows:
( (row.get(k), ) row[k].strip()
k (, , , )):
ValueError()
row[] LABELS row[] ids:
ValueError()
ids.add(row[])
key, owner [(row[], source_owner), (fingerprint(row[]), content_owner)]:
key owner owner[key] != split:
ValueError()
owner[key] = split
(dspy.Signature):
text: = dspy.InputField()
label: = dspy.OutputField()
():
[dspy.Example(text=r[], label=r[]).with_inputs() r rows]
():
gold.label LABELS:
ValueError()
actual = (pred, , )
(actual, ) actual LABELS actual == gold.label
():
correct, errors = ,
example examples(rows):
:
prediction = program(**example.inputs())
correct += (exact_label(example, prediction))
Exception:
errors +=
{: (rows), : correct, : errors,
: correct / (rows) rows ,
: errors == }
():
validate_splits(SPLITS)
scripted = {r[]: {: r[]} r SPLITS[]}
dspy.context(lm=DummyLM(scripted)):
dspy.BootstrapFewShot(
metric=exact_label, max_bootstrapped_demos=,
max_labeled_demos=, max_rounds=, max_errors=,
).(dspy.Predict(Route), trainset=examples(SPLITS[]))
():
passed = exact_label(gold, pred)
dspy.Prediction(score=(passed), feedback=(
passed
))
():
dspy.GEPA(
metric=gepa_metric, auto=, max_metric_calls=,
reflection_lm=reflection_lm, num_threads=, track_stats=,
)
常见问题
- 教程会调用付费模型吗?
- 不会。本地运行使用 DSPy DummyLM 预设输出,测试期间阻断网络;没有运行真实 GEPA 搜索或付费模型请求。
- 九组测试通过是否证明模型优化有效?
- 不能。它们验证数据隔离、评分、原生编译、JSON 回读和预算配置。模拟答案已预设,不代表模型学习或泛化。
- 最终 test 为什么不传入 compile?
- trainset 与 valset 会参与更新或候选选择。最终测试应在程序和指标冻结后单独运行,避免验收信息泄漏。
- metric calls 等于所有模型调用吗?
- 不等于。多模块执行、反思、judge 和工具会产生不同请求与 token,用量预算不能直接当美元硬上限。
- 指纹检查能发现所有近重复吗?
- 不能。它只检查经规范化的精确重复,还要按来源分组并人工或用适当方法检查语义近重复。
- 为什么异常不从分母删除?
- 只统计成功样本会掩盖无法处理或测量失败的情况。本例保留完整样本数、errors,并以 measurement_ok 标明测量是否正常。