本节摘要:拆解 DSPy 使用率最高的编译器:自举机制的完整执行序列、四个核心参数(max_bootstrapped_demos、max_labeled_demos、max_rounds、metric)的作用点与调法、编译开销的估算公式,以及三类失败模式的排查清单。理解了它,就理解了 DSPy 所有编译器的公共地基。
先建立一个心智图像:BootstrapFewShot 编译时,你的程序会被复制成两份角色。一份当"考生"——拿训练集逐题作答;一份当"模板"——最终交付的编译产物。考生答题的完整轨迹(每个预测器收到了什么、输出了什么)被记录下来,指标逐条验收,合格轨迹按预测器拆解成示范,注入模板的对应预测器。整个过程里没有任何权重更新,"学习"完全体现为示范的筛选与注入——严格说,它优化的不是模型,是模型看到的上下文。

metric 是验收官,3.5 节已经讲透,这里只补一句编译视角的话:它同时决定"哪些轨迹能当示范"与"示范教给模型什么",改指标等于换老师。其余三个参数控制数量与轮次:
三个参数与开销的关系可以记成一个粗略公式:编译期调用次数 ≈ 训练集规模 × 链路预测器数 × max_rounds(外加验证开销)。五十条训练集、两个预测器、一轮自举,就是约一百次模型调用起步——预算紧的时候先动哪个参数,现在可以算着办。
自举的一个结构性弱点是"一次定终身":一轮自举只产出一套示范,自举质量依赖轨迹抽样的运气,运气差的编译轮次会交出明显偏弱的产物。BootstrapFewShotWithRandomSearch 的对策是把自举放进候选框架:编译时并行产出一组候选程序——零样本版(纯指令无示范)、仅标注示范版、若干个不同自举种子的版本——然后在验证集上逐个打分,返回最优者。它同时回答了两个问题:这轮自举的运气如何(各候选分数差距就是运气方差),以及哪个形态最适合当前任务(有时零样本版反而赢,说明示范在帮倒忙)。
from dspy.teleprompt import BootstrapFewShotWithRandomSearch optimizer = BootstrapFewShotWithRandomSearch( metric=exact_match, max_bootstrapped_demos=2, # 每个候选的自举上限压低,控制总开销 max_labeled_demos=8, num_candidate_programs=8, # 候选数量:含零样本版与若干自举种子 num_threads=16, # 候选评估的并发线程 ) best_program = optimizer.compile(my_program, trainset=trainset, valset=devset)
开销与收益的换算值得记住:八个候选意味着评估开销约为单次自举的八倍,但换来对自举方差的直接观测。实践中它常被用作"诊断器"——当你怀疑自举不稳时,先跑一遍带随机搜索的变体看候选分数分布:分布紧凑说明自举稳定,可以退回便宜的纯自举;分布散乱说明运气主导,要么加大示范上限,要么接受"多编几次取最优"的工作流。
把一段真实感的编译日志压缩后逐行解读,帮你建立"读日志"的手感:
Bootstrapping 4 examples... # 自举段:目标 4 条示范 Round 1: 50 tries, 21 passed # 第一轮:跑 50 条,21 条过指标 Round 2: 21 tries, 9 passed # 第二轮:带示范再跑,合格率提升 Selected 4 examples. # 凑齐 4 条,注入示范池
三个信号藏在数字里。第一轮合格率四成出头,说明零样本能力及格,自举有原料;第二轮合格率从四成涨到接近一半,说明示范注入立刻见效——这是程序"可教"的直接证据,若第二轮不涨反跌,要警惕示范污染。预算视角同样可算:两轮合计七十一次程序执行,每次执行的调用数等于链路预测器数,乘上单次 token 成本就是这次编译的自举开销——日志不是流水账,是账本。
参数之外再补一条调试期的实用技巧:编译前先做一次"迷你自举"——把训练集砍到十条、示范上限设为二、只跑一轮,几十秒内验证整条编译链路(数据格式、指标可用性、模型连通、示范注入)是否畅通。迷你自举跑通了,正式编译大概率一次成功;跑不通,报错也在小规模下最好定位。这相当于编译世界的冒烟测试,成本可以忽略,省下的却是正式编译动辄数十分钟的等待与排错。
失败模式一:合格轨迹产出率过低,编译器报示范不足。病因通常在两头——要么程序零样本能力太弱(模型小、签名要求过高),要么指标太苛刻。排查:先人工抽二十条训练集让程序裸跑,数一数指标能放行几条;放行率过半还凑合,不足两成就先补 max_labeled_demos 保底或换更强模型,别急着调自举参数。
失败模式二:示范注入了,分数不涨反跌。多半是示范污染:指标放行了答案对但过程歪的轨迹(比如多跳程序里第二跳蒙对了)。治理靠 trace 模式加验中间字段,或收紧指标(3.5 节的双重回路正为此设计)。
失败模式三:验证集分数好,换批数据就垮。这是分布问题的典型症状——自举示范全部来自训练集分布,训练集太窄时示范成了"偏科教材"。对策:扩充训练集覆盖面优先于一切参数调整;若确实无法扩充,把 max_bootstrapped_demos 调小、max_labeled_demos 调大,让更稳定的人工标注主导示范池。
这三类失败覆盖了实践中的绝大多数编译事故。排查的共同起点是同一个动作:打开历史检查工具,直接看示范池里进了什么——产物可审计,是自举路线区别于一切"玄学调优"的底气。