Snapcompact 位图帧中的角色来源溯源:oh-my-pi 的 exp06 零开销角色元数据实验设计
2026/9/12 17:24:40 网站建设 项目流程

Snapcompact 位图帧中的角色来源溯源:oh-my-pi 的 exp06 零开销角色元数据实验设计

【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pi

导读

在 oh-my-pi 的 snapcompact(面向视觉大模型的位图帧上下文压缩)研究线中,如何让视觉模型准确回答"这条信息来自哪一方(用户 / 助手 / 工具)",直接决定了压缩归档的可用性——如果模型无法分辨帧内消息的归属,即使内容识别再准,重建出来的上下文也是错乱的。本文围绕实验脚本 research/exp06_rolecolor.py 与其配套提示词 exp06-prov-image.md,完整解析这条"角色来源溯源(provenance)"评测协议的设计思路:它以字形颜色编码角色归属、以零字符开销写入元数据,并通过强制二选一(user/assistant/tool)的输出约束完成量化评测。读完本文,你将掌握:这个提示词逐字逐行在做什么、它如何与实验主流程衔接、另外两套对照条件(文本标签、无元数据)各自的作用,以及这套零开销元数据设计如何被上层生产代码(snapcompact.ts 中的sent/bw变体与角色色调逻辑)呼应。


一、实验背景:provenance(来源溯源)评测从何而来

1.1 snapcompact 的研究脉络

packages/snapcompact 的核心思路是:被压缩丢弃的对话历史经序列化后,以等宽像素字体的方式渲染成密集 PNG 帧,再由视觉模型直接"读"回。整个流程本地且确定性——不需要额外的 LLM 调用,无 API key,延迟仅限渲染本身;光栅化与 PNG 编码发生在原生代码(renderSnapcompactPng,见 crates/pi-natives)中。

既然帧里承载的是对话转录,而对话天然由三种角色(user / assistant / tool)的消息交织而成,那么压缩重建后必须回答一个关键问题:

帧里这段文本,究竟是用户说的、助手说的,还是工具返回的?

这就是 provenance(来源溯源)评测要量化的能力。仓库中一系列exp*实验脚本(research/)正是为此服务的评测工场,而 exp06_rolecolor.py 是其中把"角色元数据"当作自变量来研究的专线。

1.2 exp06 在实验编号中的位置

  • exp05 系列(exp05_anchors.py)研究锚点;
  • exp06 是**角色色彩(rolecolor)**专线:验证"用字形颜色编码消息归属"这一零字符开销方案是否可行、能否与"文本标签"方案(多花约 7 字符/条)在溯源准确率上打平;
  • exp07(exp07_readtax.py)则转入"读取税"问题:图像条件耗时被 CoT 转写主导,需用提示词协议(effort-lowlocate-then-answer等)削减。

可见 exp06 的 provenance 问题是一个独立的、可量化验证的研究对象。


二、逐字逐句解析 exp06-prov-image.md

该提示词(prompts/exp06-prov-image.md)的完整正文如下:

The attached image contains a conversation transcript rendered as a bitmap: monospace pixel font, {cols} characters per row, {rows} rows, read left-to-right then top-to-bottom. The transcript interleaves messages from three roles: user, assistant, and tool. {encoding} For each numbered question below, do NOT answer the question itself. Instead identify which role's message contains the answer to it. - Reply with exactly one word per line: user, assistant, or tool. - You must choose one of the three roles for every question, even if uncertain — never reply UNREADABLE. - Output a numbered list, one role per line, no commentary.

逐段功能拆解如下。

2.1 帧描述段(第 1~2 行):让模型建立位图"阅读坐标系"

The attached image contains a conversation transcript rendered as a bitmap: monospace pixel font, {cols} characters per row, {rows} rows, read left-to-right then top-to-bottom. The transcript interleaves messages from three roles: user, assistant, and tool. {encoding}
  • {cols}/{rows}是格式化占位符:由实验脚本在运行时以.format(cols=cols, rows=rows, encoding=ENCODING[cond])填入(见下方"运行时机"一节)。值来自capacity(FONT, args.size)——即当前字体在当前帧尺寸下能容纳的列数、行数。
  • 之所以要显式告知行列数,是因为位图没有天然的行列边界信息;明确"每行 N 字符、共 M 行、从左到右、从上到下"之后,模型才能把像素映射回文本网格,后续"定位到某条消息所在区域"才有坐标基础。
  • {encoding}是角色编码方式的说明插槽:它并非写死,而是由脚本按条件注入(ENCODING[cond]),保证模型知道当前这张图用的是哪种角色标记手段。这是该提示词最重要的设计点之一:同一个 provenance 提示词模板,通过一个占位符即可切换三种编码说明,从而在不改题面结构的前提下做条件对照。

三种编码说明原文(来自 exp06_rolecolor.py 的ENCODING常量):

条件注入的 encoding 说明角色元数据载体
img-6x10-roleGlyph color encodes the author role: dark blue = user, dark green = assistant, dark red = tool. A message boundary is where the glyph color changes.字形颜色(色调通道)
img-6x10-tagbwEach message is preceded by a bracketed role tag rendered in the text: [user], [asst], or [tool].行内文本标签
img-6x10-nometaThe rendering does NOT visually indicate roles; glyph colors only cycle per sentence and carry no role information. Use your best guess.无(强制猜测)

注意第三种条件非常刻意:它明确告诉模型"图里没有任何角色信息,只能猜"。这就为溯源准确率提供了一个下限参照(provenance floor)

2.2 任务指令段(第 3~4 行):把"回答问题"改写成"定位来源角色"

For each numbered question below, do NOT answer the question itself. Instead identify which role's message contains the answer to it.
  • 这是 provenance 评测与常规 QA(如 exp06-qa-image.md)的根本区别:评分对象不是答案文本,而是答案所在消息的归属角色
  • "do NOT answer the question itself" 防止模型顺手把答案写出来而干扰逐行解析;它要求模型必须先把注意力放到"哪一段、属于谁"上。

2.3 输出格式约束段(第 5~9 行):强制闭合、可机读、零注释

- Reply with exactly one word per line: user, assistant, or tool. - You must choose one of the three roles for every question, even if uncertain — never reply UNREADABLE. - Output a numbered list, one role per line, no commentary.

三条约束逐条看:

  1. 每行一个词,且只能是user/assistant/tool三者之一:让输出天然可机读,无需额外解析容错。这与脚本侧parse_numbered的解析逻辑对接。
  2. 必须为每个问题选一个角色,不确定也绝不输出UNREADABLE:这是与常规 QA 提示词(如 qa-image.md 允许UNREADABLE)的最大差异。为什么逼模型"硬选"?因为溯源准确率按"答案所在消息的真实角色"计分,一旦允许UNREADABLE,模型会把所有没把握的问题全部甩给这个逃生舱,实验将拿不到任何区分度。硬选 + 随机正确率 1/3 的地板,使得高于 1/3 的准确率都具有统计意义。
  3. 编号列表、无任何评论:保证输出与问题编号一一对应,供脚本逐行对齐计分。

2.4 与常规 QA 提示词的区别小结

维度exp06-prov-image.mdexp06-qa-image.md(内容 QA)
任务指出答案所在消息的角色抽取答案文本
允许 UNREADABLE禁止(硬选)允许(读不清就报 UNREADABLE)
输出格式每行一个角色词每行一个短语/词
评分口径角色归属准确率(accuracy)内容 F1
元数据说明{encoding}插槽固定Glyph color encodes the author...说明

两者在同一张图上、同一组问题下并行运行,形成"内容能读对 + 归属能分对"的双维评测。


三、提示词在实验主流程中的运行时机

provenance 提示词不是孤立存在的,它被 exp06_rolecolor.py 的run_cell驱动,与内容 QA 在同一轮实验里先后执行。

3.1 三条件同构的评测网格

MODELS = {"gpt-5.5": (2.0, 16.0), "google/gemini-3.5-flash": (0.6, 4.0)} LENGTHS = (50, 150) CONDITIONS = ("img-6x10-role", "img-6x10-tagbw", "img-6x10-nometa")

评测网格 = 模型 × 归档长度 × 渲染条件。同一个 SQuAD 语料块,分别以三种方式渲染:

  • img-6x10-role:纯文本 + 逐字符角色色调(蓝=user、绿=assistant、红=tool),即"零字符开销元数据"主条件;
  • img-6x10-tagbw:纯文本前加[user]/[asst]/[tool]文本标签,黑底白字,即"文本等价物"对照;
  • img-6x10-nometa:无任何角色元数据(退化为sent变体),即溯源地板参照。

角色分配方式为轮询 + 确定性洗牌assign_roles,seed 固定):每三条连续段落恰好覆盖三种角色各一次,段落组内顺序由 rng 打乱。这样任何位置的任何一条消息都有近似均匀的角色先验,避免"角色与位置相关"的混淆变量。

3.2 分块逻辑:三条件共享同一分块边界

def build_chunks(paras: list[dict], budget: int) -> list[tuple[int, int]]: """Greedy consecutive passage ranges [a, b) whose TAGGED rendering fits budget.""" chunks, cur, cur_len = [], 0, 0 for i, p in enumerate(paras): add = 7 + len(p["ctx"]) + 1 # "[xxxx] " + ctx + " " if cur_len + add > budget and i > cur: chunks.append((cur, i)) cur, cur_len = i, 0 cur_len += add chunks.append((cur, len(paras))) return chunks

分块以**带标签(tagged)**文本的容量为准(预算 40716 字符,对应 6x10 字体的帧容量)。因此三种条件下,同一张图对应的段落集合完全一致、问题集完全一致,唯一差异就是元数据载体本身——这是干净对照实验的关键前提。代价是分块边界会与基线(纯文本恰好 40716 字符)略有偏移,问题集"高度重叠但并非逐字符相同",脚本注释里明确说明了这一点。

3.3 提问采样与溯源记录

def sample_questions(...): ... picked.append({ "q": " ".join(qa["question"].split()), "golds": sorted({a["text"] for a in qa["answers"]}), "pos_rel": (offsets[pi] - start) / (end - start), "pi": pi, # 记录来源段落下标 })

每个问题都记录了其来源段落下标pi,配合轮询角色分配结果,即可确定"正确答案所在消息的真实角色"——这就是 provenance 评分的 ground truth。同时pos_rel记录了答案在块内的相对位置,为后续 exp07 的"按区域定位"实验埋下伏笔。

3.4 提示词格式化与双评测调用

prov_messages = [ { "role": "user", "content": [ { "text": load_prompt("exp06-prov-image.md").format( cols=cols, rows=rows, encoding=ENCODING[cond] ) }, {"image_path": png}, {"text": q_block}, ], } ]
  • load_prompt("exp06-prov-image.md")读取提示词模板,.format(cols=..., rows=..., encoding=...)注入帧几何与编码说明;
  • 消息内容按「提示词文本 → 图片 → 编号问题块」的顺序组装;
  • cached(...)走实验框架的缓存(run.pyQA_CACHE/RESULTS),同一输入只调用一次供应商 API,支持断点续跑与复现;
  • 内容 QA 与 provenance QA 各走一次llm_complete,分别记录 usage(token 消耗),为成本-收益分析提供数据。

3.5 溯源答案的归一化

def norm_role(answer: str) -> str: a = answer.lower().strip(" \t.[]()\"'`*") if "assist" in a or a == "asst": return "assistant" if "user" in a or "human" in a: return "user" if "tool" in a or "function" in a: return "tool" return a

模型偶尔会输出asst(标签条件的原文)或human/function等变体,归一化函数把它们映射回三值角色空间,保证计分口径统一。注意输出约束本身(每行一个词)已经大幅压缩了归一化需求,这里只是兜底。


四、为什么用颜色编码角色:零字符开销的元数据设计

4.1 颜色即元数据

ROLE_HUES = {"user": 0.62, "assistant": 0.33, "tool": 0.02},再经colorsys.hls_to_rgb转为 RGB(render_role中逐字符上色)。角色信息不占用任何字符位,完全寄生于已有的字形像素。

对比文本标签方案:[user][asst][tool]每条消息多花恰好 7 个字符(脚本注释特意标注"all '[xxxx] ' = 7 chars"),在帧容量固定的前提下,标签会挤占真实内容的空间。而颜色方案的边际字符成本为零——这正是它被称为"zero-char metadata"的原因(见脚本 docstring)。

4.2 消息边界 = 颜色跳变

ENCODING里明确写了"A message boundary is where the glyph color changes"。也就是说,颜色通道同时承担了两层语义:归属(谁说的)分段(消息在哪里结束、下一条在哪里开始)。模型在溯源时只要发现颜色跳变,就能划出一条消息边界,再按颜色对应角色。

4.3 与生产代码sent/bw变体的呼应

这套"颜色 = 元数据"的思想在生产代码里以两种形态出现(packages/snapcompact/src/snapcompact.ts):

  • sent变体Ink: sent cycles six hues at sentence boundaries——在句边界循环六种色调,此时颜色编码的是句子边界(结构化信息);
  • bw变体:纯黑墨水,颜色通道全部让位给可读性,此时没有任何色调元数据。

实验里的img-6x10-role(角色色调)与img-6x10-nometa(退化为sent变体,颜色只按句子循环、不携带角色信息)恰好是"颜色承载语义元数据"与"颜色仅作装饰"的对照——实验结论直接影响生产变体选型:若角色色调能显著提升溯源准确率,未来帧格式可引入"角色色调"这类新 ink 变体;若收益不显著,则维持sent/bw两态即可。从源码结构看,Shape.variant目前只支持"sent" | "bw"两种取值(见 snapcompact.ts 中Shape接口),实验若验证角色色调有效,需要为该字段扩展取值。

4.4 饱和度随新鲜度衰减:被刻意省略的设计

脚本 docstring 特别说明:"Saturation-decay-by-recency was considered and deliberately omitted"——按消息新鲜度对旧消息降饱和度的方案被考虑过但刻意不做。理由有二:

  1. 当前评测问题没有覆盖"新近度"维度,衰减方案无评测目标可验证;
  2. 降饱和会破坏角色色调信号本身——provenance 任务测的就是色调,自毁变量等于自毁实验。

这个省略本身就是研究边界意识的体现:不引入无评测支撑的复杂度。


五、评测口径与可验证依据

5.1 计分方式

  • 内容 F1:常规 QA(img-6x10-roleimg-6x10-tagbw两种条件)走 exp06-qa-image.md / exp06-qa-image-tag.md,用 SQuAD 标准 F1 计分;
  • 溯源准确率:provenance QA(三种条件都跑)逐行解析输出,与消息真实角色比对,计 accuracy;nometa条件不跑内容 QA(内容评测与基线共享),只跑 provenance,以提供溯源地板。

5.2 与相邻实验的关系

实验文件角色/溯源相关要点
exp06 rolecolorexp06_rolecolor.py色调 vs 标签 vs 无元数据 的溯源对比
exp07 readtaxexp07_readtax.py削减图像条件下的 CoT 转写开销(no-transcribelocate-then-answer等协议)
exp08+exp08_foveate.py归档中段的"中央凹"降采样等

一个值得注意的衔接:exp06 记录下每个答案的pos_rel(块内相对位置),exp07 的"按行带定位再读取"协议与之形成互补——前者验证"能不能分对归属",后者验证"能不能低成本地只读相关区域"。

5.3 生产测试的呼应

test/snapcompact.test.ts 中有与形状/供应商相关的测试(如"maps provider APIs to their eval-winning shapes"、"provider image budgets stay permissive"等),验证生产侧的 shape 解析与预算逻辑,与实验侧的角色/形状选型形成"实验定调、测试守线"的闭环。


六、如何复现与延伸

6.1 运行实验

脚本头部以 PEP 723 声明运行环境(Python ≥ 3.10,依赖pillow),docstring 给出运行方式:

# 在 packages/snapcompact 目录下 uv run exp06_rolecolor.py

需要说明的适用前提:

  • 需要供应商 API key(脚本通过providers.pyload_env_key加载),MODELS字典里列出的是当时评测的模型与价格假设(如gpt-5.5google/gemini-3.5-flash);
  • 帧渲染依赖bdf.py(BDF 位图字体解析与渲染)与本地字体缓存CACHE
  • 结果与中间 PNG 均写入CACHE/RESULTS,通过cached()保证可复现、可断点续跑。

6.2 想换新条件怎么做

  • 新增角色编码方式:在CONDITIONS增加条件名,在ENCODING增加对应说明,在build_image/QA_PROMPT增加渲染与 QA 提示词分支;
  • 新增角色:扩展ROLESROLE_HUES(当前三角色对应三种色相,多于三种时色相间隔会被压缩,需重新验证可分辨性);
  • 换字体/帧尺寸:改FONT--sizecapacity()会自动重新计算列行数,提示词中的{cols}/{rows}随之更新。

6.3 延伸方向(基于实验注释的合理推断)

  • 若角色色调被验证显著有效,可扩展Shape.variant支持"角色色调"ink 变体(目前 snapcompact.ts 仅支持sent/bw);
  • 可引入"按新鲜度降饱和"的变体设计,但需先有覆盖新近度维度的评测任务;
  • 可结合 exp07 的定位协议,将"溯源"与"低成本定位读取"合并为一条更省 token 的读取管线。

七、小结

exp06-prov-image.md 是 snapcompact 角色溯源实验的核心测评契约:它以一段可格式化的帧描述(含{cols}/{rows}/{encoding}占位符)建立阅读坐标系与编码说明,以"不答问题、只判归属"的任务定义把内容 QA 改写成溯源 QA,以"每行一个角色词、禁止 UNREADABLE、编号输出"的约束保证机读性与统计有效性。它由 exp06_rolecolor.py 驱动,在同一分块、同一问题集下对比三种元数据载体(色调 / 文本标签 / 无),并把结论与生产代码的sent/bw变体设计、test/snapcompact.test.ts 的预算测试贯通起来。理解这份提示词,就理解了 oh-my-pi 如何用"零字符开销的视觉元数据"解决压缩上下文中的消息归属问题——这正是位图压缩方案能否在生产环境中安全落地的关键一环。

【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pi

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询