NVIDIA ResearchPi Extension Agent HarnessToken Efficiency

SoL-Pi 源码原理与技术学习文档

从“让 Agent 少做事”转向“让 Harness 少重复工作”:解析 SoL-Pi 如何在不修改 Pi 上游源码的前提下,通过四个可组合机制降低模型轮次、上下文重放、超长 Observation 与日志阅读成本。

分析对象:NVlabs/SoL-Pi · main 源码快照:1559b5c… 论文:arXiv 2609.20519 文档日期:2026-09-28
01

项目定位:SoL-Pi 到底是什么

一句话:SoL-Pi 是一个安装在原生 Pi 之上的独立扩展包,它不替换模型、不 Fork Pi Runtime,而是在 Agent Harness 的关键边界消除“重复但不增加决策价值”的工作。

仓库入口 src/sol-pi/index.ts 在 session_start 时读取配置,然后按开关注册四类扩展。所有机制默认关闭;项目级配置只有在 Pi 判断项目可信时才会读取。

ToolsAction Fusion
ObservationObservationPack
DelegationEvidence-Preserving Reducer
ContextOnline Context Compact
设计原则源码体现工程价值
No Pi patches只导入 Pi 公共 API,使用 ExtensionAPI / ExtensionContext / 公共 Tool Definition降低升级与维护成本
Explicit opt-in默认四个 feature 全为 false安全、可回滚、便于 A/B
Preserve evidence原始 Observation/日志归档;Reducer 失败时保留原结果压缩不等于丢证据
Runtime ownership stays with Pi模型、认证、Provider URL、Shell 行为继续由 Pi 管理扩展边界清晰
02

为什么需要 SoL-Pi:长时 Agent 的四类“结构性浪费”

1. 决策轮次浪费

修改文件之后,下一步往往高度可预测:测试、构建、启动或检查。如果中间仍让大模型再做一次“决定运行命令”的请求,这一轮推理价值很低。

2. 上下文重放浪费

一个大文件或长 Tool Result 首次读过之后,仍会跟随历史在后续 Provider Request 中一遍遍重放。

3. 日志阅读浪费

编译/测试可能输出数万行,但真正改变下一步决策的常常只有少数错误行与上下文。

4. 已完成子任务拖累

长任务里的已完成步骤继续留在活跃上下文中,直到原生自动 compaction 很晚才触发。

核心思想:优化对象不是“回答内容”,而是 Agent 与 Harness 之间的交互结构。只删除不再需要模型判断的中间步骤,或把可恢复证据移出高成本上下文。
03

Auto-Research 方法:机制不是拍脑袋设计出来的

项目页公开的方法是一个规模化的 Harness 自动研究流程:从大量候选方向出发,每个方向形成独立 lineage,经过 rollout、证据分析、实现、审查以及两层验证。首轮提出 152 个方向,最终只有 4 个机制进入 SoL-Pi。

01 Trajectory Rollouts
生成探索轨迹
观察真实 Agent 在哪里重复工作。
02 Map–Reduce Analysis
分轨迹提取证据,再汇总
避免单条轨迹偶然模式成为结论。
03 Proposal
提出一个可验证机制
机制要对应具体浪费边界。
04 Implementation + Reviewer
一个 Agent 实现,另一个 Agent 独立审查
失败则回到实现阶段修正。
05 In-Trajectory Validation
训练环境筛选
确认触发率、质量门槛与效率收益。
06 Held-Out Validation
冻结候选后做隔离测试
Held-out 失败直接淘汰,不把结果回灌为修复反馈。
研究方法里最值得借鉴的一点:它优化的是“约束效率(constrained efficiency)”——只有任务质量仍在预设能力底线内,token/cost 的下降才算有效优化。
04

总体架构:四个机制卡在四个不同边界

Task→ Agent / LLM→ Action→ Environment→ Observation→ Context↺
SoL-Pi Extension
├─ Action boundary → Action Fusion
│ edit/write + optional then_run → one tool observation
├─ Observation projection → ObservationPack
│ large repeated payload → stable handle + exact paged recall
├─ Delegated reading → Evidence-Preserving Reducer
│ long diagnostic log → verified compact receipt
└─ Context boundary → Online Context Compact
completed subtask → economic check → native Pi compaction → auto continue

入口注册逻辑

session_start
  └─ loadSolPiConfig(ctx.cwd, getAgentDir(), ctx.isProjectTrusted())
      ├─ actionFusion            → registerActionFusion()
      ├─ observationPack         → registerObservationPack()
      ├─ evidencePreservingReducer → registerEvidencePreservingReducer()
      └─ onlineContextCompact    → registerOnlineContextCompact()

注意:入口通过 initialized 防止重复注册;Online Context Compact 在其它 context transformer 之后注册,以便它观察经过前序转换后的上下文。

05

Action Fusion:把“修改 → 验证”融合成一次 Tool 调用

目标

LLM→edit/write→LLM 再决策→bash
↓ 改为
LLM→edit/write + then_run→combined observation

扩展复用 Pi 自带 createEditToolDefinition() / createWriteToolDefinition(),只在参数 Schema 上增加可选的 then_run。因此原工具的提示、参数 shim、渲染器与核心语义仍由 Pi 提供。

执行流程

  1. 按 ctx.cwd 缓存 built-in tool definition。
  2. 解析真实文件路径,进入 SoL-Pi 的 per-file queue。
  3. 执行原始 edit/write。
  4. 若 mutation 失败:标记 [then_run:skipped],绝不执行命令。
  5. 若指定 then_run:计算 SHA-256,再让出一个 event-loop tick,再次计算。
  6. 目标内容发生变化则跳过 command,避免验证错误版本。
  7. 创建 Pi 原生 bash tool 运行命令,合并结果为一个 observation。

并发与失败语义

锁粒度
同一目标文件的 fused 操作
mutation 成功 / command 失败
文件修改保留,整体返回 failed 标识与命令错误
外部进程修改
SHA-256 二次校验可检测一部分竞争修改
全局互斥
没有;外部进程与其它扩展不受此 queue 约束
为什么这不是简单的 shell chaining?关键不在 edit && test,而在“保留 Pi 原工具语义 + 明确 mutation/validation 的不同失败语义 + 文件竞争检测 + 用一个 Tool Result 回给模型”。
06

ObservationPack:第一次完整看,后面只保留句柄,需要时精确召回

核心位置:Provider Context Projection

ObservationPack 不直接改 Session History,而是在 Pi 的 context 投影阶段替换后续要发给 Provider 的消息。这样会话日志仍保留原始结果,native compaction / resume 后也仍可通过 archive 召回。

Large Tool Result→ 首次若干次完整发送→ 本地 Archive→ Stable Handle→ obs_recall(page)

为什么是“Projection”,不是“修改历史”

  • 历史是事实记录;为了省 token 不应该破坏它。
  • Provider Request 是昂贵的“视图”;这里可以根据生命周期做压缩。
  • 句柄只负责寻址,原始 bytes 仍保存在 session-derived 目录。

公开研究中选出的 V2

项目页说明最终配置使用约 2048-byte head + 1536-byte tail + 前两次完整发送,之后进入 handle/recall 模式。这体现了一个重要折中:先保证模型建立对 Observation 的初始理解,再避免长期重放。

通用设计模式:把“长期可恢复”与“每轮都携带”解耦。Memory/Observation 系统真正要优化的是可访问性,而不是让所有数据永久常驻 prompt。
07

Evidence-Preserving Reducer:让便宜模型读长日志,但主 Agent 只接收可验证证据

问题边界

Reducer 面向长 diagnostic log,而不是通用摘要。它会把原始日志归档,然后让配置的 reducer provider/model 生成 compact receipt;只有 receipt 中保留的引用能在 source archive 中逐字验证时,才接受压缩结果。

Long log→Archive + hash→Reducer model→Receipt→Exact-quote verify
校验失败点处理原因
不满足候选条件保留原 Tool Result不为短输出增加复杂度
Reducer model 不可用 / 调用失败Fail-open效率机制不能阻断任务
Schema / source hash 不匹配拒绝 receipt防止跨日志或结构错误
引用不是原文 exact quote拒绝 receipt避免“摘要幻觉”变成证据
Likely-secret detector 命中不远程 reduction降低敏感日志外发风险
压缩后并没有更小保留原结果无收益则不改变行为
重要安全边界:secret detector 只是预防措施,不是完整 DLP/秘密扫描器。日志必须完全留在本地的场景,不应开启远程 Reducer。
08

Online Context Compact:从“窗口快满了再压缩”改为“子任务完成时判断是否值得压缩”

语义边界 + 经济边界

它通过 update_plan 维护结构化计划。当某个 step 从未完成变为 completed,就得到一个“语义上适合压缩”的候选点;但是否真的 compact,还要结合上下文压力、预计未来请求数、上下文增长和 cache write/read 成本比做经济性判断。

Plan step completed→Boundary candidate→Economic check→abort active run→agent_settled→Pi native compact()→hidden triggerTurn

为什么要先 abort,再 compact

兼容文档指出,Pi 0.85.1 的 ExtensionContext.compact() 会终止活跃 Agent,而 agent_settled 只在整条 run drain 后触发。SoL-Pi 因此把 boundary 状态先持久化,然后主动 abort,让 compaction 在 settled 状态执行。

为什么 compact 后还能自动继续

成功后扩展通过 ExtensionAPI.sendMessage(..., triggerTurn: true) 注入一个隐藏的通用提醒,让 Pi 在 compacted context 上启动新 turn 并重建计划。取消或退出不会自动继续。

Plan 数据契约

[
  { "id": "step-1", "goal": "定位问题", "status": "completed" },
  { "id": "step-2", "goal": "实现修复", "status": "in_progress" },
  { "id": "step-3", "goal": "验证",     "status": "pending" }
]
  • step id 必须唯一;同一个 id 不应换 goal。
  • 建议最多一个 in_progress。
  • 有 pending 时,最好明确一个 in_progress。
  • 状态写入 Pi session log 的 versioned custom entries,不另建 OCC sidecar 文件。
09

Pi 生命周期挂接:SoL-Pi 为什么能保持“独立扩展”

Pi public extension surface used by SoL-Pi
├─ session_start
│ 读取可信配置、一次性注册机制
├─ registerTool()
│ 替换/扩展 edit、write;注册 obs_recall、update_plan
├─ context / before_provider_request
│ Provider 投影、上下文增长与边界判断
├─ tool_result
│ 长日志 reducer 候选处理
├─ turn_end / agent_settled
│ 统计、边界 compaction、自动 continuation
└─ session_before_tree
手动 compaction 期间阻止树导航改变 active leaf
架构价值:SoL-Pi 的“创新”主要发生在编排层,而不是模型层。它把 Pi 视为稳定内核,通过公开 Hook 组合新行为,因此可以单独测试、单独关闭、单独升级。
10

效率模型与实验:衡量的是“完成同样工作的成本”

51EdgeBench held-out tasks
44.7–49.0%论文报告的 recorded token traffic 降幅
≈ 1/3论文报告的 API cost 降幅
152 → 4候选研究方向 → 最终机制

Action Fusion 的机会估计

项目页公开的研究轨迹显示:Oracle Analysis 在 cross-turn transition 中发现约 12.3% 是“edit/write 后紧跟 command”的候选;如果所有 149 个候选都触发,轨迹反事实估计 model turns 可从 1,386 降至 1,237(约 -10.8%),总 tokens 从 32.38M 降至 28.64M(约 -11.5%)。这是轨迹反事实,不是实际重跑结果。

Online Context Compact 的成本直觉

提前 compaction 本身也有成本,因为它会产生摘要写入并破坏一部分 KV-cache 复用。因此 SoL-Pi 不把“子任务完成”直接等同于“立刻压缩”,而是使用配置项 cacheWriteReadRatio(默认 12.5)作为单一经济决策比率,并结合未来 horizon 与 window pressure 判断未来读取节省是否能偿还本次重写成本。

实验数字来自 SoL-Pi 论文与项目页;源码本身主要定义机制与运行时决策,不包含论文所有实验数据。
11

安全与失败回退:效率层必须“失败时回到原行为”

机制新增权限/风险保护与边界
Action Fusion文件修改 + shell command只在可信项目读取 project config;mutation 失败不运行 command;文件变化检测
ObservationPackSession 目录保存大 Observation本地归档;不破坏原 session history
EPR可把 eligible log 发给 reducer model显式开关、Pi 管认证、likely-secret 检查、exact quote 校验、失败保留原结果
OCCPlan/进度信息进入 session log不创建独立 payload capture;隐藏 continuation 不含任务特定数据
不要把 SoL-Pi 当安全沙箱。官方 SECURITY 明确说明:扩展继承 Pi 进程本身的文件系统、进程、网络与凭证权限,它不构成新的权限边界。
12

安装、配置与复现

环境要求

Node.js
22.19+
Pi
README 测试基线:@earendil-works/pi-coding-agent 0.85.1
包管理器
npm
License
MIT
npm install --global @earendil-works/pi-coding-agent@0.85.1
pi install git:github.com/NVlabs/SoL-Pi

# 项目本地安装
pi install git:github.com/NVlabs/SoL-Pi --local --approve

推荐从低风险机制开始

{
  "version": 1,
  "actionFusion": true,
  "observationPack": true,
  "evidencePreservingReducer": false,
  "onlineContextCompact": false,
  "cacheWriteReadRatio": 12.5
}

官方 README 也把这组配置作为保守起点:前两者不额外调用模型,也不会停止一个正在运行的 Agent run。

配置查找顺序

  1. 可信项目中的 .pi/sol-pi.json
  2. ~/.pi/agent/sol-pi.json
  3. 都没有时使用内置默认值(四机制关闭)

项目配置覆盖全局配置,不做 merge。未知 key、错误 version、非 boolean feature、非法 ratio 等都会直接阻止扩展加载,而不是悄悄忽略。

源码验证命令

npm ci --ignore-scripts
npm run check
npm audit --audit-level=high
node scripts/check-pi-compat.mjs

npm run check = TypeScript typecheck + 完整 Vitest + npm pack --dry-run。

13

可迁移设计思想:如何应用到自己的 Agent Runtime

A. 把 Runtime 优化拆成四层

Agent Runtime Efficiency
├─ Decision efficiency:减少没有信息增益的 LLM round-trip
├─ Observation efficiency:大结果可召回,不长期重放
├─ Delegation efficiency:便宜模型读取,强验证器守住证据
└─ Context efficiency:在语义边界按经济条件 compact

B. “存储”和“Prompt 投影”分离

Session log 保存事实,Provider projection 决定当前请求需要看多少。这比直接改聊天历史更稳定,也更适合 resume、branch、compaction。

C. 压缩系统必须有 Recall 通道

真正可靠的压缩不是“摘要后删掉”,而是“热上下文变小 + 冷证据仍能精确寻址”。

D. LLM 输出后加确定性校验器

EPR 最重要的不是“用小模型总结”,而是 exact-quote/source-hash/schema 检查。把生成模型当候选生成器,把程序当裁判。

E. 所有效率机制都要 Fail-open

优化失败应退化到原始路径,不应让主任务失败。效率插件的 SLO 首先是“不能降低可完成性”。

如果移植到 Java Agent Runtime,可抽象成这些接口

interface ContextProjector {
    List<Message> project(Session session, List<Message> history);
}

interface ObservationArchive {
    ObservationHandle archive(byte[] content);
    byte[] recall(ObservationHandle id, int page);
}

interface ToolDecorator {
    Tool decorate(Tool original);
}

interface CompactionPolicy {
    CompactionDecision evaluate(PlanState plan, ContextUsage usage, Economics economics);
}

interface EvidenceVerifier<T> {
    VerificationResult verify(T candidate, ArchivedSource source);
}

这样可以把 SoL-Pi 的思想迁移到任何 Think → Action → Tool → Observation 循环,而不绑定 TypeScript 或 Pi。

14

总结:SoL-Pi 真正值得学习的不是四个 Feature,而是一种 Harness 优化范式

SoL-Pi 的核心公式可以概括为:
保留任务能力与可验证证据 → 找到重复交互 → 在最窄边界做机制化替换 → 用公开 Runtime Hook 接入 → Fail-open → 用 held-out 任务验证节省是否真实迁移。

Action Fusion 消掉无信息增益的模型轮次;ObservationPack 把“可访问”与“每轮重放”分离;Evidence-Preserving Reducer 把便宜模型的阅读能力放在确定性证据验证之后;Online Context Compact 则把 compaction 从纯粹的 token-window 事件升级为“语义边界 + 经济判断”。四者共同说明:Agent 系统的成本优化空间,很大一部分存在于 Harness 的数据生命周期与控制流,而不一定要重新训练模型。

主要资料

  • NVlabs/SoL-Pi GitHub:README、src/sol-pi、docs/configuration.md、docs/compatibility.md、SECURITY.md
  • 论文:SoL-Pi: Recursively Scaling Auto-Research Loops for Efficient Agent Harness,arXiv:2609.20519
  • NVIDIA Research 项目页:SoL-Pi 方法、四机制研究过程与实验图表

本文将“源码可直接确认的实现”与“论文/项目页公开的实验数据”分开表述;实验结果不等同于对任意模型、任意任务和任意 Pi 版本的性能保证。

← 返回内容索引