oh-my-pi snapcompact 压缩研究:eager 缩放协议提示词(exp08-archive-eager)的设计、解析与两阶段执行
【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pi
本篇技术指南围绕 oh-my-pi 仓库中 snapcompact 包研究目录下的提示词模板 exp08-archive-eager.md 展开,剖析它在"foveated 两阶段读取"实验(exp08)中的角色、逐条指令的设计意图,以及它与实验代码 exp08_foveate.py 如何通过ZOOM rows A-B协议完成"先粗读、再定点放大"的两轮问答闭环。读完本文,你将掌握这套面向视觉 LLM 的位图文本读取提示词协议的结构、eager/conservative/phrase 三种策略的差异,以及如何把"放大请求"解析、行带合并、重渲染回注对话等机制落地为可复现的实验流程。
一、背景:为什么需要 foveated 两阶段读取
snapcompact 是 oh-my-pi 的位图帧上下文压缩包(见 README.md):与其让 LLM 总结被丢弃的会话历史,它把文本序列化后渲染成密集的像素字体 PNG 帧,让视觉模型直接读回。渲染与 PNG 编码全部在本机原生代码(@oh-my-pi/pi-natives)中完成,不调用 LLM、无 API 延迟。
在此基础上,研究目录(packages/snapcompact/research)开展了一系列"如何让视觉模型更可靠地读取位图"的消融实验。其中 exp08 的思路是foveated(中央凹式)两级读取:第一轮用比常规更密的像素字体渲染整页归档图,让模型能答就答、不能答就申请放大;第二轮只把被请求的行带切片重新渲染成大字号图,继续问答。
为什么要把第一轮压得更密?exp08_foveate.py 的模块 docstring 给出了关键数字:采用 5x8 像素字体时,1568px 方形帧可容纳313 列 × 196 行 = 61348 字符/页,比此前 6x10 字体的最优方案(img-6x10-sent基线)密度高出约 1.5 倍。密度提升的直接收益是单页能装进更多被压缩的会话文本,代价则是字迹更小、更容易误读——这正是"放大协议"要补偿的部分。
二、eager 提示词全文结构与逐条解析
exp08-archive-eager.md 全文只有 10 行,是一个带模板占位符的系统提示词,按功能可拆成四个层次:
2.1 图像格式声明(模板参数注入)
The attached image contains encyclopedia passages rendered as a bitmap: monospace pixel font, {cols} characters per row, {rows} rows, read left-to-right then top-to-bottom. Rows are numbered 1 (top) to {rows} (bottom). Original paragraph breaks were collapsed to spaces.
这一句为模型建立了"图像 = 字符网格"的坐标系:等宽像素字体、每行{cols}字符、共{rows}行、按从左到右、从上到下的顺序阅读,行号自上而下编号。{cols}与{rows}不是写死的——在 run_cell_chunk 中通过load_prompt(prompt_file).format(cols=cols, rows=rows)由实验代码动态填充,cols/rows来自 bdf.py 的 capacity():rows = size // pitch // repeat、cols = (size - (columns-1)*gutter) // columns // adv。行坐标系与后续的行带寻址(ZOOM rows A-B)一一对应,是整套协议的地基。
Original paragraph breaks were collapsed to spaces.
提示词还主动告知模型"原文换行已被折叠成空格",防止模型因为预期中"段落应该换行"而错位理解网格内容。
2.2 怀疑论指令(eager 变体的核心)
IMPORTANT: this font is rendered BELOW the size you can read reliably. Characters that look legible are often misread (digits, names, and dates especially). Be skeptical of your own reading.
这是全文最重要的一句话:它明确告诉模型——当前字体尺寸低于可靠阅读阈值,看似清晰的字符也可能读错,尤其是数字、专有名词与日期,请对自己的阅读结果保持怀疑。这条"自我怀疑"指令的作用是引导模型不要把不确定的读取当作确定答案输出,而是主动触发放大机制。对比保守版 exp08-archive.md,后者只说"字体刻意很小,多数内容努力可读,但某些区域可能读不出",而 eager 变体把风险语气加重为"几乎必然误读、务必怀疑",两者在触发放大的阈值上形成了鲜明的策略差异(详见第四节)。
2.3 三档回答协议
Questions follow after the image. Answer them using ONLY text you can read in the image.
- Give a direct short extractive answer ONLY when you are fully certain of every character in it.
- For any question where you are not fully certain — wrong-looking digits, a name you might be misreading, a region that is small or smudged — reply exactly
ZOOM rows A-Bfor that question (e.g.ZOOM rows 41-47). That row band will be re-rendered for you at a large, comfortable font. Zooming is cheap and encouraged; guessing is penalized.- Estimate the row range from the vertical position of the region (row 1 = top edge, row {rows} = bottom edge). If unsure of the exact rows, give a generous range — a margin around your estimate is included automatically.
- If you cannot even locate a relevant region, reply exactly UNREADABLE for that question.
这一节把每个问题的作答空间收窄为三档,且给出了严格的触发条件:
- 直接抽取式回答(extractive answer):仅在对每一个字符都完全确信时输出("fully certain of every character")。措辞刻意收紧——不是"大致看得清"而是"逐字符确信",把模糊读取排除在直接回答之外。
- 放大请求
ZOOM rows A-B:只要存在任何不确定——疑似读错的数字、可能误读的名字、区域太小或模糊——都必须回复精确格式ZOOM rows A-B(如ZOOM rows 41-47)。行号按图像垂直位置估算,顶边为第 1 行,并鼓励给出宽松区间,因为代码侧会"自动包含余量"(pad)。句末的 "Zooming is cheap and encouraged; guessing is penalized" 是对模型的激励约束:放大成本低且被鼓励,猜测会被惩罚——这解释了为什么该变体命名为eager(急切放大)。 - UNREADABLE:连相关区域都无法定位时的最终兜底。
Output a numbered list, one answer per line, no commentary.
收尾要求严格的机器可解析输出格式:每个问题一行、按问题编号输出、无任何多余评论。这一约定直接对接实验代码的squad.parse_numbered()(见 squad.py),后者按\d+[.):]正则把回答逐行还原为编号数组,缺失项补空字符串。
三、三种读取策略的对比:conservative / eager / phrase
exp08_foveate.py 中 PROTO 表把三种协议条件与提示词文件、放大余量(pad)、寻址方式绑定在一起:
| 条件 | 提示词文件 | pad | 寻址方式 | 策略语义(源码注释原文) |
|---|---|---|---|---|
fov | exp08-archive.md | 2 | rows | conservative:仅在过小时放大,行寻址,紧余量 |
fov2(eager) | exp08-archive-eager.md | 12 | rows | eager:除非完全确信否则放大,行寻址,宽余量 |
fov3 | exp08-archive-phrase.md | 12 | phrase | eager 提示 + 短语寻址(模型引用部分辨认出的锚词,harness 在 chunk 中模糊定位该行带) |
三点关键差异:
- 放大触发阈值:conservative 要求"区域太小才放大",eager 则反过来要求"除非完全确信否则放大"。二者是同一坐标系下两个极端:conservative 省放大轮次但可能硬答错,eager 更频繁申请放大但把误读风险转移给放大轮。
- pad 余量:eager/phrase 的
pad=12行远大于 conservative 的pad=2行,与提示词中"give a generous range"的指引呼应——宽余量保证行带切片一定能覆盖目标内容。 - 寻址方式:rows 模式让模型直接给出行号区间;phrase 模式则让模型引用 3-8 个单词的锚短语(见 exp08-archive-phrase.md),由 harness 用 locate_phrase() 在 chunk 文本中做大小写归一化后的模糊匹配,再把字符跨度换算成行号。
四、从ZOOM rows A-B到重渲染:harness 的执行闭环
eager 提示词只是"输入侧"的一半,另一半在实验代码中。一次完整的两轮执行流程如下(对应 run_cell_chunk):
第一轮(归档图问答):从 SQuAD 式段落流flow(由 squad.build_flow 生成、按 chunk 预算切分)中采样问题后,把整段 chunk 用 5x8 字体渲染成一张归档 PNG(f"exp08-arch-{ARCHIVE_FONT}-{variant}-{sha8(...)}.png",带内容哈希缓存与原子写入)。消息序列为:提示词模板(已填充 cols/rows)+ 归档图 + 编号问题列表。模型第一轮回答进入qa1。
ZOOM 请求解析:对每条回答,rows 模式走 parse_zoom(),用两个正则解析:
_ZOOM_RANGE = re.compile(r"(?i)\bzoom\b[^\d]*(\d+)\s*(?:[-\u2013\u2014]|to\b)\s*(\d+)") _ZOOM_SINGLE = re.compile(r"(?i)\bzoom\b[^\d]*(\d+)")支持ZOOM rows A-B区间与单行两种形式,A>B时会自动交换保证A<=B;若模型声称 ZOOM 却无法解析出行带,该题被置为UNREADABLE。
行带合并与切片:所有待放大行带经 merge_bands() 处理——先按pad(eager 为 12)向外扩、再裁剪到[1, max_row],相邻或重叠的带合并成一个,避免重复渲染。随后 zoom_renders() 按"行 r 覆盖字符[(r-1)*cols, r*cols)"的映射从 chunk 文本中切出对应切片,用 8x13 大字号字体重渲染,并从ZOOM_SIZES = (520, 784, 1040, 1568)中挑选能容纳该切片的最小方形尺寸;超长行带会被拆分到多页。
第二轮(放大图问答):消息流扩展为messages + [assistant(qa1), user(exp08-zoom 提示 + 带标签的放大图 + 待答问题列表)]。放大轮的提示词由 exp08-zoom.md 提供——它先声明"以下是您请求的行带的高分辨率重渲染,文本与原文一致,只是按新行宽重排",再要求模型结合放大图与已读内容、沿用原编号继续作答,读不出就回UNREADABLE。
合并打分:第二轮的answers2覆盖第一轮中所有触发 ZOOM 的问题(final[i] = answers2[i] or "UNREADABLE"),随后逐条计算 exact match 与 F1(见 squad.py 的exact_match/f1),并记录zoomed、zoom_band、anchor、abstained等元数据。
五、成本核算:eager 策略的度量方式
放大轮不是免费的,实验代码用 aggregate() 与 _phase_cost() 把两轮 usage 合并核算:
- token 汇总:
in/out/cache_w(写入缓存)/cache_r(读取缓存)/reasoning分桶累计,qa1与qa2两阶段分开记录(usage_rows)。 - 定价公式:输入按
(in + 1.25*cache_w + 0.1*cache_r) / 1e6 * price_in,输出按out / 1e6 * price_out——缓存写入按 1.25 倍、缓存读取按 0.1 倍折算,这是按主流 provider 的缓存计费结构建模的。 - 关键派生指标:
zoom_q(触发放大的题数)、zoom_rate(放大率)、no_zoom_pct(无需放大即回答的比例)、cost_zoom_usd(纯放大轮的增量成本),用于回答"eager 的宽余量放大到底多花多少钱、换来多少 F1"。 - 基线对照:代码 BASELINE 中记录了
img-6x10-sent基线的 f1/标准误/成本(例如gpt-5.5@50 为(0.850, 0.0508, 0.068)),输出汇总时给出d_f1与d_cost_usd差值。注意这是实验设计中的对照常量,最终三条件的对比结论需要以records.jsonl/summary.json实际运行结果为准。
实验入口main()(exp08_foveate.py)通过命令行参数--models、--lengths、--conditions、--qpc、--size、--workers等配置网格,最终把逐题记录写入records.jsonl、聚合结果写入summary.json与matrix.csv。运行方式为从 snapcompact 目录执行uv run exp08_foveate.py(docstring 首行注明)。
六、结论:eager 协议的设计要点
exp08-archive-eager.md 虽短,却是 foveated 两阶段读取链路中承上启下的关键一环,其设计可以提炼为三条可复用原则:
- 给模型一个可靠的"放弃"通道:
ZOOM rows A-B+UNREADABLE双兜底 + "guessing is penalized"的激励,把误读风险从"模型硬猜"转移到"harness 定点重渲染"这一确定性更高的路径上。 - 用行号坐标系让放大可执行:图像被声明为
{cols}×{rows}字符网格,模型只需估算垂直位置,代码即可按[(r-1)*cols, r*cols)精确切片,无需模型给出字符级定位。 - 策略参数全部显式化:放大阈值(eager vs conservative)、余量 pad(2 vs 12)、寻址方式(rows vs phrase)都被提炼为可配置的 PROTO 参数,从而能在一个网格里公平对比不同策略的 F1 与成本曲线。
该提示词是 packages/snapcompact/research 实验矩阵的一份子,它与 exp08-archive.md、exp08-archive-phrase.md、exp08-zoom.md 共同构成完整的放大协议族;研究结论反过来服务于 snapcompact 生产包的形状选择与压缩管线(README.md,架构总览见 docs/compaction.md)。
【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pi
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考