Cmpnd 发布了 dspy-wsp,一个将权重空间编程引入 DSPy 的原型优化器。权重空间编程是一种技术,前沿 LLM 读取另一个模型的权重并直接编辑它们。没有梯度、没有训练循环,也没有微调数据集。dspy-wsp 将其打包为 WeightSpace,一个可插入任何 DSPy 程序和指标的优化器。在 Cmpnd 的测试中,约 5 到 10 美元的 GPT-6-Astra 调用改善了它们尝试的每一个决策模型。你可以通过我们的 GPULeaderboard.com chrome 扩展查看部署选项和规格。
TL;DR
它是什么:一个 DSPy 优化器(WeightSpace),其中写入方 LLM 编辑学生模型的权重。MIT 许可证,pip install dspy-wsp,需要 DSPy 3.5。
规模:在 0.6B 到 9B 参数的开源决策模型上测试。一次 25 轮运行编辑了单个层或头。
运行环境:所有实验在一台 Mac 上运行。2B 模型使用约 6 GB 内存。d1-omni-600M 需要 4 GB 或更多(Mac 或 GPU)。
性能:仅 WeightSpace 就在 Typed Decisions 上增加了 1.9 到 16.1 分。配合 ReAnchor,增益为 6.5 到 20.0 分。
最佳:d1-omni-600M 从 50.9% 升至 69.1%(+18.3),使用 WeightSpace + ReAnchor。
最差:Clef-Flash(9B)仅从 WeightSpace 单独获得 +1.9。使用原论文更严格的规则,d1-omni-600M 仅获得 +2.8。
底线:最佳:一种廉价、无梯度的编辑,以小型、可验证的补丁形式交付。最差:非常实验性、缓慢(每次运行 78 到 167 分钟),且在较大模型上效果最弱。
什么是权重空间编程?
权重空间编程(WSP)将神经网络的权重视为一个可以被读取和重写的程序。这个想法来自 MIT 的研究:Sparks of Weight-Space Programming。
一个前沿模型(研究团队使用了 GPT-6-Astra)查看权重张量,推理每个部分计算什么,并修改它们以匹配用平实英语写成的目标。研究团队强调,WSP 命名了一种新兴能力,而非固定方法。在他们的实验中梯度被禁止,但该概念并不排除它们。
它与微调或提示优化有何不同?
比较开发者通常使用的 3 个杠杆会有所帮助:
提示优化(DSPy 的 MIPROv2、GEPA)编辑文本:指令和示例。模型的权重从不改变。
微调(DSPy 的 BootstrapFinetune,在 BetterTogether 内部使用)通过梯度下降改变权重。它需要训练数据、训练循环,通常还需要 GPU。
权重空间编程通过推理来改变权重。编辑器形成一个假设(“这些神经元对选项 B 打分过高”),编写代码来修补它们,并通过几次前向传播检查结果。
这篇研究文章将 WSP 定位为使用 LLM 优化文本产物之后的下一步。早期工作让 LLM 在提示、harness 和训练代码上进行爬山搜索。权重则留给 Adam 或训练好的权重生成网络。WSP 主张 LLM 推理现在可以直接触及权重。
原始研究展示了什么?
MIT 团队进行了 9 项实验。其中几项令人瞩目:
读取权重:Astra 仅凭权重就为 4 个 PPO 策略网络说出了正确的游戏名称(Breakout、Pong、Pac-Man、Freeway)。
修复损坏的策略:一个 Kinetix 的汽车上坡道策略在全部 256 个回合中失败。对其 3.5% 的权重做一次编辑,就使其在全部 1,024 个测试回合中成功。
从零开始编写:在 MinAtar Breakout 上,一个一次性写出的零初始化网络得分为 517.4。PPO 在 5 亿步后达到 25.3。
修复 LLM:Qwen3.5-0.8B 在数学问题上陷入循环。Astra 将问题追溯到 MLP 第 15 层和第 19 层,并改动了 131,072 个权重(占模型的 0.016%)。经过 50 次前向传播,MATH-500 从 7.9% 升至 48.1%,GSM8K 从 13.8% 升至 67.1%。
研究也显示了局限。在 Gemma 3 270M 上,编辑将 MATH-500 从 6.8% 提升到 7.0% 至 7.7% 之间。研究团队并未将其视为真正的提升。编辑可以移除障碍,但无法添加缺失的能力。
dspy-wsp 如何工作?
dspy-wsp 将这一研究循环转变为标准的 DSPy 优化器。GitHub 仓库描述了 3 个角色:
学生:你的 DSPy 程序所运行的小模型。其权重加载到本地 Python 进程中。
编写者:一个前沿 LLM,推荐使用最高推理强度的 gpt-6-astra。
沙箱:编写者运行代码的内核。macOS 使用内置的 sandbox-exec;Linux 使用 bubblewrap。
写作者按轮次工作。每一轮都有一段简短说明,然后是 1 个代码块。该代码块要么是:
一个 Python 代码块,用于读取或编辑沙箱内的权重,要么是
一个 forward 代码块,在你的 DSPy 程序上针对练习样例运行。
Forward 传递来自固定预算(测试中 max_passes=25)。当预算耗尽时,写作者的最佳编辑就成为补丁。随后一个隐藏的验证集会在相同的样例和种子上比较原始权重与编辑后的权重。
写作者能看到什么数据?
仓库对数据分离有明确说明:
trainset 是写作者的练习集。
holdout 会把一部分训练数据(示例中为 0.25)移入检查集。写作者可以在其上为编辑打分,但永远看不到这些样例。
valset 保持隐藏,只在最后运行一次。
指标可以返回 dspy.Prediction(score=..., feedback=...)。feedback 文本对写作者可见。
写作者实际改动了什么?
结果说明中列出了每一处编辑。这些编辑都很小且有针对性:
ModelTensor editedScopeTimeWriter costd1-omni-600Mhead.scorer.1.weight (+ bias, scorer.3.weight)112,640 of 1,048,576 entries, plus 22078 min$7.63NanoJev (Qwen3-0.6B)scalar.weight1,024 entries167 min$6.92d1-2Blayers.23.feed_forward.w2.weightAll 15.7M entries, rank-9 change83 min$5.42
d1-2B 没有决策头,因此写作者编辑了其第 23 层的骨干网络。在 d1-omni-600M 上,写作者重写了决策头 scorer 的一部分。
代码长什么样?
仓库示例对支持工单进行分类。该签名只使用决策类型输出:
复制代码已复制使用其他浏览器
import dspy
from typing import Literal
from dspy_wsp import WeightSpace, load_decision_backend
class Triage(dspy.Signature):
"""对支持工单进行分类。"""
ticket: str = dspy.InputField()
urgent: bool = dspy.OutputField(desc="这张工单需要今天回复吗?")
team: Literal["billing", "technical", "account"] = dspy.OutputField(desc="应该由哪个团队处理?")
backend = load_decision_backend("d1") # d1-omni-600M
optimizer = WeightSpace(
metric=metric,
writer_lm=dspy.LM("openai/gpt-6-astra", model_type="responses", reasoning_effort="max"),
backend=backend,
max_passes=25,
holdout=0.25,
run_dir="runs/triage",
)
compiled = optimizer.compile(dspy.Predict(Triage), trainset=train, valset=test)
compiled(ticket="I was charged twice this month.") # 在编辑后的权重上运行
编译后,程序调用的是编辑后的本地模型,而不是托管 API。compiled.wsp_patch.summary() 会显示改动了什么。
自动播放</button></div>
</div>
<!-- 3 处编辑 -->
<div class="pn" data-p="2">
<p class="lbl">写作者编辑的张量(GPT-6-Astra,25 轮)</p>
<div class="row" id="edb">
<button class="btn on" data-e="0">d1-omni-600M</button>
<button class="btn" data-e="1">NanoJev</button>
<button class="btn" data-e="2">d1-2B</button>
</div>
<div class="card" style="margin-top:12px">
<div style="font-size:13px"><code id="edt"></code></div>
<p id="edd" style="margin-bottom:0"></p>
<div class="mat" id="mat"></div>
</div>
<div class="kv">
<div><b id="k1"></b><span>改动的条目数</span></div>
<div><b id="k2"></b><span>写作者轮次</span></div>
<div><b id="k3"></b><span>运行时长</span></div>
<div><b id="k4"></b><span>写作者成本</span></div>
</div>
<p class="note">网格仅示意被编辑的份额,并非精确位置。来源:dspy-wsp 结果 README(2026-11-07)。</p>
</div>
<!-- 4 项结果 -->
<div class="pn" data-p="3">
<p class="lbl">Typed Decisions 测试准确率(400 个留出案例)</p>
<div class="row" id="rsb">
<button class="btn on" data-r="0">d1-omni-600M</button>
<button class="btn" data-r="1">NanoJev 0.6B</button>
<button class="btn" data-r="2">d1-2B</button>
<button class="btn" data-r="3">Clef-Flash 9B</button>
</div>
<div class="bars" id="bars"></div>
<p class="note">写作者为 GPT-6-Astra,25 次前向传播。增益为配对结果,标准误 ±0.7 至 1.4 个百分点。由 Cmpnd 自行报告。</p>
</div>
<!-- 5 成本 -->
<div class="pn" data-p="4">
<div class="kv" style="margin-top:0">
<div><b>$5.42 至 $7.63</b><span>写作者成本 / 次运行</span></div>
<div><b>78 至 167 分钟</b><span>运行时长 / 次运行</span></div>
<div><b>~6 GB</b><span>内存,2B 模型</span></div>
<div><b>MIT</b><span>许可证</span></div>
</div>
<div class="card" style="margin-top:12px">
<p class="lbl">发布补丁</p>
<p><code>pip install dspy-wsp</code>(DSPy 3.5,Python 3.10+)</p>
<p>补丁 = <code>manifest.json</code> + <code>edit.npz</code>,其中包含基础张量和编辑后张量的 sha256 哈希,因此任何拥有公开基础模型的人都能重建出完全一致的权重。</p>
<p>决策模型:<code>wsp_patch.write_checkpoint(...)</code> · LLM:<code>dspy-wsp apply</code>,然后在 vLLM 上提供服务。</p>
<p style="margin-bottom:0">本地运行:在 Apple 芯片上使用 MLX,在 Linux 上使用 PyTorch(如有 NVIDIA GPU 则使用 GPU)。</p>
</div>
<p class="note">注意事项:Cmpnd 称该软件包“非常实验性”。按照论文中更严格的规则,d1-omni-600M 仅提升了 +2.8。</p>
</div>
<div class="ft"><span>来源:cmpnd.ai、github.com/cmpnd-ai/dspy-wsp、rikiyat.github.io</span><a href="https://www.marktechpost.com" target="_blank" rel="noopener">由 Marktechpost 构建</a></div>
</div>
<script>
(function(){
var R=document.getElementById('mtp-wsp');
function q(s){return R.querySelector(s)} function qa(s){return R.querySelectorAll(s)}
function post(){try{parent.postMessage({mtpWspH:R.offsetHeight+40},'*')}catch(e){}}
qa('.tab').forEach(function(t){t.onclick=function(){qa('.tab').forEach(function(x){x.classList.remove('on')});t.classList.add('on');qa('.pn').forEach(function(p){p.classList.toggle('on',p.dataset.p===t.dataset.t)});if(t.dataset.t==='3')drawBars(rc);setTimeout(post,60)}});
/* 调节项 */
var wg=q('#wg');for(var i=0;i<64;i++){var c=document.createElement('i');wg.appendChild(c)}
var cells=wg.children;
var L=[
{p:1,w:0,t:'<b>提示词优化</b>(MIPROv2、GEPA)重写指令和示例。权重从不移动。',g:['编辑文本','无需 GPU'],n:['权重冻结']},
{p:0,w:1,t:'<b>微调</b>(BootstrapFinetune)在训练轨迹上用梯度下降微调大量权重。',g:['改变权重'],n:['需要梯度','需要训练循环']},
{p:0,w:2,t:'<b>权重空间编程</b>:前沿 LLM 读取张量,对其计算内容形成假设,编写代码修补其中少数几个,然后通过前向传播测试该编辑。',g:['改变权重','无需梯度','定向、带哈希的补丁'],n:['需要一个强大的写入 LLM']}
];
function lever(k){qa('#levb .btn').forEach(function(b){b.classList.toggle('on',+b.dataset.l===k)});var d=L[k];
q('#bx-p').classList.toggle('hot',d.p===1);q('#bx-w').classList.toggle('hot',d.w>0);q('#pchg').className=d.p?'chg':'';
for(var i=0;i<cells.length;i++){cells[i].className=''}
if(d.w===1){var n=0;var iv=setInterval(function(){for(var j=0;j<cells.length;j++){cells[j].className=Math.random()<.7?'b':''}if(++n>5)clearInterval(iv)},140)}
if(d.w===2){[19,20,27,28].forEach(function(x,ix){setTimeout(function(){cells[x].className='a'},200+ix*180)})}
q('#ldesc').innerHTML='<p style="margin-top:0">'+d.t+'</p><div class="tags">'+d.g.map(function(x){return '<span class="tg">'+x+'</span>'}).join('')+d.n.map(function(x){return '<span class="tg n">'+x+'</span>'}).join('')+'</div>';setTimeout(post,60)}
qa('#levb .btn').forEach(function(b){b.onclick=function(){lever(+b.dataset.l)}});lever(2);
/* loop */
var S=[
{b:25,t:'<span class="k">load_decision_backend("d1")</span>\n# student weights load into a local Python process\n# writer: gpt-6-astra, reasoning_effort="max"'},
{b:25,t:'<span class="k">```python</span> # runs in sandbox (sandbox-exec / bubblewrap)\nW = weights["head.scorer.1.weight"]\nprint(W.shape, W.std()) # read tensors like source code'},
{b:25,t:'# writer turn = short explanation + 1 code block\n"These scorer units push answers toward the wrong option.\n I will rescale them and check on practice examples."'},
{b:25,t:'<span class="k">```python</span>\nW[rows] *= scale # targeted edit, no gradients\n# change is recorded against the base tensor hash'},
{b:24,t:'<span class="k">```forward</span> # run the DSPy program on practice examples\n# score on holdout (writer sees scores, never examples)\n# keep the edit only if the metric improves'},
{b:0,t:'# budget spent: best edit becomes the patch\npatch/manifest.json + patch/edit.npz (sha256 hashed)\n# hidden valset compares original vs edited weights once'}
];
var cur=0,pl=null;
function step(k){cur=Math.max(0,Math.min(5,k));qa('.st').forEach(function(s){var i=+s.dataset.s;s.classList.toggle('on',i===cur);s.classList.toggle('done',i<cur)});
q('#term').innerHTML=S[cur].t;q('#budf').style.width=(S[cur].b/25*100)+'%';q('#budn').textContent=S[cur].b+' / 25';
if(cur===4){var b=24;var iv=setInterval(function(){b-=1;if(cur!==4||b<1){clearInterval(iv);return}q('#budf').style.width=(b/25*100)+'%';q('#budn').textContent=b+' / 25'},90)}}
qa('.st').forEach(function(s){s.onclick=function(){step(+s.dataset.s)}});
q('#next').onclick=function(){step(cur+1)};q('#prev').onclick=function(){step(cur-1)};
q('#play').onclick=function(){if(pl){clearInterval(pl);pl=null;q('#play').textContent=' Auto-play';return}step(0);q('#play').textContent='❚❚ Pause';pl=setInterval(function(){if(cur>=5){clearInterval(pl);pl=null;q('#play').textContent=' Auto-play';return}step(cur+1)},2200)};
step(0);
/* edits */
var E=[
{t:'head.scorer.1.weight (+ bias, scorer.3.weight)',d:'重写了决策头 scorer 的一部分:1,048,576 个条目中的 112,640 个(约 10.7%),外加 220 个 bias/输出条目。',k:['112,860','74','78 min','$7.63'],m:'a',f:0.107},
{t:'scalar.weight',d:'Qwen3-0.6B 主干上带决策头的单个小张量,共 1,024 个条目。',k:['1,024','68','167 min','$6.92'],m:'a',f:1},
{t:'layers.23.feed_forward.w2.weight',d:'d1-2B 没有决策头,因此写入者编辑了主干:全部 15.7M 个条目被改动,作为一次 rank-9 更新。',k:['15.7M','65','83 min','$5.42'],m:'r',f:1}
];
var mat=q('#mat');for(var i=0;i<200;i++){mat.appendChild(document.createElement('i'))}
function ed(k){qa('#edb .btn').forEach(function(b){b.classList.toggle('on',+b.dataset.e===k)});var e=E[k];q('#edt').textContent=e.t;q('#edd').textContent=e.d;
['k1','k2','k3','k4'].forEach(function(id,ix){q('#'+id).textContent=e.k[ix]});
var ms=mat.children,n=ms.length;for(var i=0;i<n;i++)ms[i].className='';
var on=k===1?20:Math.round(n*e.f);var idx=[];for(var i=0;i<n;i++)idx.push(i);
if(k===0){idx=idx.slice(0,on)}else if(k===1){idx=idx.slice(0,20)}
idx.forEach(function(x,j){setTimeout(function(){ms[x].className=e.m},j*(k===2?3:12))});setTimeout(post,60)}
qa('#edb .btn').forEach(function(b){b.onclick=function(){ed(+b.dataset.e)}});ed(0);
/* bars */
var D=[[50.9,60.2,66.9,69.1],[39.2,50.7,52.4,56.4],[60.6,70.1,74.0,77.9],[68.8,70.3,70.7,75.3]];
var N=['Unoptimized','ReAnchor','WeightSpace','WeightSpace + ReAnchor'],C=['#B0AAA6','#5B5452','#3A8A50','#1E4A2C'];
var bars=q('#bars');N.forEach(function(n,i){bars.insertAdjacentHTML('beforeend','<div class="br"><span>'+n+'</span><div class="trk"><div class="fill" style="background:'+C[i]+'"></div></div><span class="v"></span></div>')});
var G=[[0,9.3,16.1,18.3],[0,11.6,13.3,17.3],[0,9.5,13.4,17.3],[0,1.5,1.9,6.5]];
var rc=0;
function drawBars(k){rc=k;qa('#rsb .btn').forEach(function(b){b.classList.toggle('on',+b.dataset.r===k)});var r=qa('#bars .br');
r.forEach(function(row,i){var v=D[k][i];var f=row.querySelector('.fill');f.style.width='0';var g=i?' <small>+'+G[k][i].toFixed(1)+'</small>':'';row.querySelector('.v').innerHTML=v.toFixed(1)+'%'+g;setTimeout(function(){f.style.width=(v/85*100)+'%'},60+i*120)})}
qa('#rsb .btn').forEach(function(b){b.onclick=function(){drawBars(+b.dataset.r)}});drawBars(0);
window.addEventListener('load',post);window.addEventListener('resize',post);setTimeout(post,300);
})();
</script>
</body></html>
">
它的效果如何?Typed Decisions 基准测试结果
Cmpnd 在 Typed Decisions 上进行了测试,这是一个针对类型化概率决策的基准测试。模型读取 1 条非结构化状态,并一次性回答 5 个类型化问题。每个答案都是一个概率分布。测试集包含 400 个案例和 2,000 个决策。
每个模型从 GPT-6-Astra 获得了 25 次前向传播。增益为配对结果,标准误差为 ±0.7 至 1.4 个百分点。
模型未优化ReAnchor权重空间权重空间 + ReAnchord1-omni-600M50.9%60.2% (+9.3)66.9% (+16.1)69.1% (+18.3)NanoJev (Qwen3-0.6B)39.2%50.7% (+11.6)52.4% (+13.3)56.4% (+17.3)d1-2B60.6%70.1% (+9.5)74.0% (+13.4)77.9% (+17.3)Clef-Flash (9B)68.8%70.3% (+1.5)70.7% (+1.9)75.3% (+6.5)
来源:Cmpnd 博客中 d1-omni-600M、d1-2B 和 Clef-Flash 的图表;NanoJev 的结果 README。
ReAnchor 是 Cmpnd 早期的优化器。决策模型输出概率,阈值将这些概率转换为答案。ReAnchor 在不调用 LLM 的情况下重新拟合每个问题的阈值。权重空间会改变模型;ReAnchor 则重新校准其输出。两者叠加效果很好。
有三种模式尤为突出:
在展示的每个模型上,权重空间都优于单独使用 ReAnchor。在 d1-omni-600M 上,它带来了 +16.1 的提升,而后者为 +9.3。
最大的模型提升最少。9B 的 Clef-Flash 仅靠 WeightSpace 只提升了 +1.9。
这种组合在 9B 上最为关键。当两个优化器同时运行时,Clef-Flash 跃升至 +6.5。
写入模型有影响吗?
答案是肯定的。以 gpt-6.1-sol 作为写入模型时,仅 WeightSpace 就在 d1-omni-600M 上带来 +5.8、在 NanoJev 上带来 +12.1、在 d1-2B 上带来 −0.6。Astra 在相同模型上则分别带来 +16.1、+13.3 和 +13.4。
dspy-wsp 是否违背了原论文的规则?
略有违背,Cmpnd 也承认这一点。默认情况下,写入模型可以在其内核中重新计算决策头。设置 simulate_head=False 会强制执行论文中更严格的规则。在该规则下,d1-omni-600M 仅提升 +2.8 ± 0.7 分。加入 ReAnchor 后提升至 +9.3,并不比单独使用 ReAnchor 更好。
如何部署编辑后的模型?
每次运行都会向 run_dir 写入一个补丁。该补丁包含 manifest.json 和 edit.npz,其中只包含发生变更的条目。它还会存储每个基础张量和编辑后张量的 sha256 哈希值。任何拥有公开基础模型的人都可以精确重建编辑后的权重。
决策模型:compiled.wsp_patch.write_checkpoint(backend.weights_dir, "edited-d1/")
文本 LLM:dspy-wsp apply <base> <patch> <out>/,然后用 vLLM 提供服务。
程序:compiled.save("program.json"),并使用 allow_unsafe_lm_state=True 重新加载。
编辑后的模型在本地运行。在 Apple 芯片上使用 MLX。在 Linux 上使用 PyTorch,若存在 NVIDIA GPU 则在 GPU 上运行。
dspy-wsp 支持哪些模型?
BackendModelAliasArchitectureD1BackendLiquid AI d1-omni(文本路径)"d1"带决策头的编码器NanoJevBackendNanoJev"nanojev"带决策头的 Qwen3 骨干D1LMBackendLiquid AI d1 on LFM3"d1-2b"在问题位置作答的 LM
文本生成 LLM 通过 VLLMBackend(NVIDIA)、HFBackend(CUDA、MPS 或 CPU)和 MLXBackend(Apple 芯片)工作。由 Michael Isaac 贡献的 GEPASearch 选项为决策模型增加了种群搜索。
WeightSpace 与其他 DSPy 优化器相比如何?
MetricsWeightSpace (dspy-wsp)ReAnchorBootstrapFinetuneGEPAWhat changesModel weightsDecision thresholds, cuts, weightsModel weightsPrompt textHowFrontier LLM reasons and edits in a sandboxGrid search over cached probabilitiesGradient fine-tuning on bootstrapped tracesReflective prompt evolutionGradientsNoNoYesNoLLM calls during optimizationYes (writer, 25 passes)NoneTeacher for bootstrappingYesTypical cost$5.42 to $7.63 per runNear zeroNot disclosedNot disclosedOutputSmall hashed patchCalibrated programFine-tuned modelOptimized promptsSourcedspy-wspCmpndBetterTogether paperGEPA paper
关键要点
权重空间编程让前沿 LLM 直接编辑权重,无需梯度或训练数据。
dspy-wsp 将其封装为 DSPy 优化器:pip install dspy-wsp,MIT 许可证。
25 次 writer 迭代花费 $5.42 到 $7.63,耗时 78 到 167 分钟。
d1-omni-600M 在 WeightSpace + ReAnchor 下从 50.9% 提升到 69.1%。
在 9B 规模上收益下降,且该包明确为实验性。
查看 Cmpnd 博客文章、GitHub 仓库、完整结果以及原始的 Weight-Space Programming 研究。你可以通过我们的 GPULeaderboard.com Chrome 扩展在此查看部署选项和规格。
另外,欢迎在 Twitter 上关注我们,别忘了加入我们 150k+ 的 ML SubReddit 并订阅我们的 Newsletter。等等!你在 Telegram 上吗?现在你也可以在 Telegram 上加入我们。
需要与我们合作推广你的 GitHub 仓库或 Hugging Face 页面或产品发布或网络研讨会等?联系我们
文章 Cmpnd Releases dspy-wsp: Weight-Space Programming Comes to DSPy 首次发布于 MarkTechPost。