在单个编码会话内,总输入长度(前缀 + 追加)从一个智能体步骤到下一个是如何变化的——当它缩小时,那是计数抖动还是一次真正的上下文压缩?
在单个编码会话内,总输入长度(前缀 + 追加)从一个智能体步骤到下一个是如何变化的——当它缩小时,那是计数抖动还是一次真正的上下文压缩?
All steps
| Metric | Claude | Codex |
|---|---|---|
| Steps | 137,629 | 210,221 |
| Positive (growth) % | 99.60% | 96.56% |
| Negative (reduction) % | 0.39% | 3.43% |
| Micro % | 0.06% | 1.08% |
| Ordinary % | 0.09% | 1.73% |
| Major reduction % | 0.24% | 0.62% |
| Avg positive growth | 1,719 | 1,838 |
User-initiated steps
| Metric | Claude | Codex |
|---|---|---|
| Steps | 16,927 | 17,033 |
| Positive (growth) % | 98.21% | 68.63% |
| Negative (reduction) % | 1.71% | 31.32% |
| Micro % | 0.37% | 12.47% |
| Ordinary % | 0.57% | 18.09% |
| Major reduction % | 0.77% | 0.76% |
| Avg positive growth | 1,527 | 2,742 |
Tool-initiated steps
| Metric | Claude | Codex |
|---|---|---|
| Steps | 120,702 | 193,188 |
| Positive (growth) % | 99.79% | 99.03% |
| Negative (reduction) % | 0.21% | 0.97% |
| Micro % | 0.02% | 0.07% |
| Ordinary % | 0.03% | 0.29% |
| Major reduction % | 0.16% | 0.61% |
| Avg positive growth | 1,746 | 1,783 |
上下文几乎总是逐步骤增长(论文的 tab:context_growth_and_compaction)。在所有步骤中,窗口在 99.60% 的 Claude 步骤和 96.56% 的 Codex 步骤上增长——新的用户输入、工具结果以及输出全都叠加到先前的上下文之上——每个增长的步骤增加约 ~1.7k–1.8k 个 token。缩减很罕见,且呈现提供商特性:对 Claude 而言,负值只占极小的 0.39%,且偏向 major(0.24%,真正的压缩),而 Codex 减少的频率约高出 ~9×(3.43%),且大多落在无害的 micro/ordinary 区间。这一分布还按触发器集中:Codex 的缩减堆积在用户触发步骤上(其中 31.3% 的步骤缩小,对比工具触发的 0.97%),而两个提供商的工具触发步骤都有约 99% 的时间在增长。
trace 中的每一行是一个智能体步骤。本实验按顺序遍历一个会话的各个步骤,记录每个步骤的总输入长度(prefix_tokens + newly_append_tokens)变化——正的 delta 表示窗口在增长,负的 delta 表示在缩小——并把每一次下降归入三个桶之一。
方法与假设:
prefix_tokens + newly_append_tokens(缓存的前缀加上新追加的输入)。每个步骤的指标是该数量相对于同一会话中上一个被看到的步骤的有符号 delta。user_message 或一个 tool_result(该步骤的触发器)——且该会话此前已被看到过时,才会发出一个增长事件。previous 步骤是按 trace 顺序为该会话最后观察到的任意步骤,与其触发器无关。会话内的步骤按 ingestion 顺序排序(round_pk = 文件顺序),即迁移到 DuckDB 之前的扫描所用的同一行顺序定序。artifacts/utils/growth.py,可在 CLI 覆盖):
≤ 1024 个 token(计数抖动);≥ 50000 个 token(一次真正的上下文压缩);all、user 与 tool_result——依据当前步骤的触发器,并按 scope(merged 加上每个提供商)切分。trace_facts overview summary 共用增长 helper(build_growth_stats、reduction_bucket、CSV writer)。这是一个**混合式(hybrid)**实验:trace DuckDB 负责单遍 ingest,而 Python 负责按会话的定序与增长分桶。
iter_growth_events_from_db(con) —— 唯一的数据加载代码。两条按 ingestion 顺序的查询(步骤标量 ORDER BY round_pk,以及每个步骤在 event_index = 1 处的第一个 timing event,用于取触发器类型和时间戳),在 Python 中借助一个 last_by_session map 遍历,为每个合格的步骤发出一个增长事件——精确复现旧的逐行 JSONL 扫描。_epoch_us_to_iso(...) —— 时间戳以整数 epoch-microseconds 拉取(native/wasm 一致),并重建为规范的 …Z ISO 字符串,因此时间戳列与迁移到 DuckDB 之前的输出逐比特一致。build_growth_stats(...) / reduction_bucket(...) / write_summary_csv(...) /
write_events_csv(...) —— artifacts/utils/growth.py 中未改动的共享 helper。write_filtered_events_csv(...) —— 稳定排序后的 reduction / micro-reduction 下钻。数据层位于 artifacts/utils/trace_db.py(参见 artifacts/utils/DB_SCHEMA.md)。
# default merged trace (materialized to a temp DuckDB cache on first use)
uv run python artifacts/session/total_input_growth/analyze.py
# a specific trace
uv run python artifacts/session/total_input_growth/analyze.py -i trace/sample.jsonl
# a prebuilt DB (run_all.py's build-db step passes this), into a chosen dir
uv run python artifacts/session/total_input_growth/analyze.py --db /tmp/trace.duckdb -o /tmp/out
旋钮:--micro-reduction-max-tokens / --major-reduction-min-tokens 重新调校缩减桶,
--no-drilldowns 只写 summary,--limit-events 在稳定排序后对每个下钻设上限,
而 --summary-csv / --events-csv / --reductions-csv / --micro-csv 覆盖各自的路径。
total_input_growth_summary.csv —— 按 (scope, trigger) 的增长/缩减桶计数及 delta 统计。total_input_growth.md —— 论文 float tab:context_growth_and_compaction 的 GFM 镜像
(Claude vs Codex,按步骤触发器),渲染在网页详情页上。total_input_growth_events.csv —— 每一个同会话的增长事件,按 trace 顺序。total_input_reductions.csv —— 仅 negative-delta 事件(全部三个缩减桶)。total_input_micro_reductions.csv —— 仅 micro-reduction 事件。无图。