首页
/ caveman 中的 TOON 与 Pixel:两种可选上下文编码的选型、配置与源码剖析

caveman 中的 TOON 与 Pixel:两种可选上下文编码的选型、配置与源码剖析

2026-09-04 15:56:31作者:裴麒琰

TOON(Token-Oriented Object Notation)和 Pixel 是 caveman 提供的两种可选上下文编码:前者把结构化 JSON 重编码为紧凑文本,后者把文本渲染成 PNG 交给视觉模型阅读。本文基于 docs/technical/toon-and-pixel.md 的原始约定,结合 engine/compressors/engine/pixel/ 下的实现源码,完整讲清两者的启用条件、配置参数、CLI 用法、适配的输入形态与失效(fail-closed)行为,帮助你在代理会话中判断何时该开、何时绝不该开。

caveman pixel 渲染样例:一段密集文本被排布进单色像素风格的 PNG 页面

一、两者的共同前提:改变的是模型可见输入

在展开细节之前,先明确原文档给出的总纲:TOON 和 pixel 都会改变模型可见的输入字节,因此两者都不是 byte-safe(字节安全)的。它们只在输入形态和目标模型都匹配时才应使用。这一点在源码层面被明确落实:

  • TOON 被实现为无损重编码器(重编码后语义不变,但文本字节变了),其安全等级为 S4,见 toon.go 中的 ContentType()SafetyClass()
  • Pixel 包的文件头注释直接声明它是「S4 lossy transform」——把文本搬进图片块,改变了模型可见字节,因此转发前必须保证原始字节可通过 CCR(上下文恢复存储)找回,任何解析、渲染或存储错误都必须 fail closed 回退为直通(pass-through),见 doc.go

这一「改字节前先留后路」的原则是理解后文所有启用规则的关键。

二、TOON:面向均匀表格 JSON 的紧凑重编码

2.1 工作原理与示例

TOON 把结构化数据重编码为紧凑的文本形式,它对字段名一致的均匀对象数组收益最大。原文档给出的示例:

[
  {"name":"Ada","role":"engineer"},
  {"name":"Lin","role":"designer"}
]

这类数组会被 TOON 把重复的键提升到共享表头、行内只保留单元格值。编码器 toon_encode.go 中的 writeTOONArray 正是这样做的:对表格数组输出形如 [2]{name,role}: 的表头行(行数 + 字段名列表),随后每行输出以分隔符连接的标量值。原文档也明确提醒:确切语法由实现及其测试夹具定义,调用方应当使用编码器/解码器,而不是手工拼写 TOON——因为解码器是严格校验的(见 2.4 节)。

2.2 选择规则(Selection rules)

原文档规定了三条硬性选择规则,源码逐一印证:

  1. 只能显式请求或经特性开关启用,Detect 通用探测函数不会选中它。 这是最强的一条约束。toon.goNewTOON 的注释写明:该编码器「只能通过强制 Options.Type = "toon" 到达,Detect 永远不会路由到它」。
  2. 结果必须比原表示更小。 若重编码后不省,调用方应原样透传。编码器 encodeTOON 的返回契约是 ok=false 时调用方保持原始字节不变(toon_encode.go 的注释)。
  3. 绝不用于 tool-call 参数。 即使数据看起来结构相似,改写工具参数也可能改变程序行为,因此 TOON 只用于「作为上下文消费的数据」,而非可执行参数。

在 caveman 的配置体系中,TOON 的持久开关是 think.toon(默认 true,「当更小且受支持时允许 TOON」),对应环境变量 CAVEMAN_TOON;项目级 overlay 可以设置 think.toon。这些参数见 configuration.md

2.3 CLI 用法

TOON 的命令行入口:

caveman tools toon encode < data.json
caveman tools toon decode < data.toon

CLI 层的实现细节值得注意:packages/cli/src/index.tstoonConvert 通过 shell 调用 caveman-engine toon encode|decode 子命令,它是无状态的。这意味着:

  • encode 依赖 caveman-engine 二进制存在(通过 caveman setup 安装、设置 CAVEMAN_ENGINE_BIN 或自行构建);
  • decode 在引擎二进制缺失时会直接拒绝工作refusing to emit unconverted TOON as JSON),即宁可报错也不产出「看起来像 JSON」的错误输出——这延续了 TOON 全链路「拒绝而非猜测」的基调。

2.4 解码器的严格性

原文档一句话「解码器拒绝畸形输入,而不是发明缺失的结构」,在 toon_decode.go 中可以找到完整的实现证据:

  • 缩进必须为偶数:TOON 以 2 个空格为一层缩进,奇数缩进直接判非法(scanTOONLines);
  • 行数声明必须兑现:表头 [N]{...}: 声明了 N 行,解码器要求恰好有 N 个物理行跟随,且每行的单元格数必须等于字段数,否则拒绝;
  • 容量防滥用:解码器在分配数组容量之前先校验 n > 剩余行数 即拒绝——注释说明这是防止「一个极小的不可信输入要求分配 GB 级内存」;
  • 字段名必须是安全键:字段名需匹配 ^[A-Za-z_][A-Za-z0-9_.-]*$safeTOONKey),解码时对重复字段、未知结构一律返回失败。

2.5 适配与不适配的输入

原文档的适用性清单,可对照源码中的判定逻辑:

适合 TOON 的输入(对应 tabularRows 的判定条件,toon_encode.go):

  • 对象组成的均匀数组;
  • 重复的字段名(每行字段名与顺序必须完全一致);
  • 标量单元格值(null / bool / number / string;单元格内含对象或数组即不合格);
  • 数据是作为上下文消费,而非可执行参数。

应避免 TOON 的场景

  • 不规则的嵌套对象(任一行结构偏离即整体回退为原样透传);
  • 本来就紧凑的数据(「必须更小」的硬规则会挡住它);
  • 键顺序或字节表示重要的输入(注意 asTOONValue 对对象键会做排序toon_encode.go);
  • tool-call 参数(行为安全的硬禁区)。

工程上还有一个可观测点:toon_eligible.go 中的 tabularEligibility 会递归统计「数组元素落在均匀扁平对象数组中的比例」,用于量化一段数据有多「表格化」,供上层决策与评测使用。

三、Pixel:把文本渲染成 PNG 交给视觉模型

3.1 机制与风险

Pixel 把文本转换为视觉模型可阅读的 PNG 图片,能降低稠密源码类素材的文本 token 输入,但引入光学识别与视觉排版风险——这正是它被定为 S4 有损变换的原因。渲染产物样例见文首配图 pixel-sample.png:一整页密集文本被排布进固定几何的像素网格。

Pixel 包是从 pxpipe 移植而来(doc.go 注明移植来源与 MIT 许可),并有意做了三处本地化:PNG 字节来自 Go 标准库编码器(测试比较解码后的像素而非 PNG 字节流)、token 估算改用 caveman 离线的 engine/tokens 计数器、且不做实时的 count_tokens 探测。

3.2 启用方式:单会话与持久配置

原文档给出的单会话启用命令:

caveman wrap --pixel <agent>

CLI 的 --pixel 标志在 index.ts 的合法标志集中注册;cli-reference.md 中进一步说明:--pixel 为「列入模型清单的模型」启用有损的文本转图像上下文传输。

Pixel 还有一个关键约束:要求显式模型允许清单。原文档给出的配置示例:

{
  "think": {
    "pixel": {
      "models": ["model-name"],
      "density": "balanced"
    }
  }
}

对照 configuration.md 的完整参数表:

配置项 默认值 取值 说明
think.pixel.models [] 模型名数组 允许接收 pixel 上下文的模型
think.pixel.density balanced conservative, balanced, max pixel 打包密度

注意 think.pixel.models 默认是空数组,即默认任何模型都不接收 pixel 上下文——与「不允许从模型名推断支持」的原则一致。同时原文档提示:项目 overlay 不能修改 pixel 设置configuration.md),防止被检入的项目文件悄悄启用这种更具侵入性的变换。环境覆盖方面,CAVE_PIXEL_MODELSCAVE_PIXEL_DENSITY 分别对应上述两项,适合临时会话使用。

3.3 密度档位:conservative / balanced / max

原文档说明:density 支持 conservativebalancedmax 三档,密度越高,塞进单张图的文本越多,小字号对模型越难读。density.go 中给出了每档的具体几何参数,可以直接读出「密度」的工程含义:

档位 单元格水平推进 行距 墨色 层数
conservative 5px 8px 单色 1
balanced(默认) 4px 6px 三色斑马纹 1
max 4px 6px 三色斑马纹 2(叠加层)

两个 fail-closed 细节值得注意:

  • 未知或非法的密度值一律落到 conservativenormalizeLevel);环境变量 CAVE_PIXEL_DENSITY 未设置时默认 balanced,假值(0/false/off 等)映射为 conservative
  • 解析出的渲染参数还要经过「地板值」钳制(applyDensityFloors):斑马纹行距不低于 5px、单色不低于 6px,确保任何配置都不会把字号压到模型无法识别的程度。

3.4 模型兼容性:为什么「能看图片」不够

原文档的核心论断:仅有视觉能力是不够的,因为图片尺寸、细节设置、供应商 token 计费和文本识别质量各不相同,所以 caveman 不会从模型名推断支持。源码层面这体现为显式的前缀匹配白名单,而非能力推断:

  • applicability.goAllowedModelBases 读取 CAVE_PIXEL_MODELS(或配置项),未设置时使用内置默认基底列表;Allowed 对模型名先剥掉 [...] 变体标签,再做精确匹配或 base- 前缀匹配——没有命中清单的模型一律不进入 pixel 路径
  • 密度解析 ResolveDensity 也执行 fail-closed:未被识别为「密度可用」的模型,无论请求哪一档,都回落到 conservative 几何参数(density.go),并且 hi-res 画布只授予被显式识别的高分辨率模型族。

3.5 恢复机制:CCR 兜底 + 收益闸门

原文档 Recovery 一节的三句话对应源码中的三道保障:

  1. 「原始文本在发出 pixel 输出之前先存入 CCR」——这是 engine/pixel/doc.go 的硬性要求:调用方必须在转发变换后的字节前保证原始字节可经 CCR 找回,任何存储失败都要 fail closed 回退到原始文本留在请求中;
  2. 「图片上下文应带清晰的恢复引用,以便工具在需要字符级细节时取回精确源」——这保证模型在图片里看不清某个字时,仍可通过工具链取回逐字符原文;
  3. 此外还有原文档未展开、但源码明确存在的收益闸门gate.goEvalCompressionProfitability 会把「渲染成图后的预估 token 数(含 10% 安全边际)」与「原文本 token 数」对比,并计入 prompt 缓存的创建/读取费率差(1.25 / 0.10),只有图片侧总成本低于文本侧时才判定为「盈利」——也就是说,即使模型在白名单里,不划算的短文本也不会走 pixel 路径。

四、证据边界:更小的本地表示 ≠ 更低的供应商成本

原文档最后的 Evidence boundary 一节是对任何「省 token」宣传的清醒约束,值得原样保留:

  • 更小的本地表示不能推出更低的供应商成本,因为供应商对图片输入和结构化文本输入的计费方式不同;
  • 一个成立的「更便宜」声明需要针对确切模型的供应商 usage 数据或有文档记录的 benchmark;
  • 「质量等价」同样需要超出「可恢复性」之外的任务级评测。

Pixel 源码中的 token 数字也自我标注为本地估算:doc.go 写明「The token reductions from this package are local estimates only」;gate.goImageCostSafetyMargin = 1.10 就是给本地估算留出的保守边际。评估这两项编码是否划算时,请以你所在供应商对目标模型的实计 usage 为准,而不是仓库内的估算值。

五、小结:一张启用决策表

维度 TOON Pixel
变换性质 无损重编码(字节变化) S4 有损变换(文本→图片)
默认是否启用 不经过 Detect,必须显式/开关启用(think.toon 模型白名单默认空,默认完全关闭
启用方式 caveman toon encode|decodethink.toon / CAVEMAN_TOON caveman wrap --pixelthink.pixel.models / CAVE_PIXEL_MODELS
硬前提 结果必须更小;禁用于 tool-call 参数 模型显式白名单 + 原始文本先入 CCR + 收益闸门盈利
参数调节 无(分隔符固定 ,,编码失败即透传) density: conservative / balanced / max,非法值落 conservative
失败行为 拒绝畸形输入,不猜测结构 解析/渲染/存储任一失败都回退直通原文

两者共同的工程哲学是:能力可以更强,但启用必须显式;任何一步不确定,就回退到原始文本。理解这一点后,你在自己的代理会话中配置这两个开关时,就已经掌握了 caveman 上下文编码的核心决策框架。更多参数上下文可继续查阅 cli-reference.mdconfiguration.mdagent-wrapping.md

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
527
590
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
904
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
889
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.52 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
981
502
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384