purpose
Workers AI の batch embed が拒否する量は、入力の合計ではなく batch 件数 × batch 内の最長入力 である可能性が高い。#236 / #241 / #244 は 3 回とも合計を縛っており、縛る対象そのものが違っていた。境界の形を変える。
observation
0411f101(#244 の UTF-8 バイト版)が 8 時間前から 100% traffic で稼働中。それでも 2026-08-15 09:30 JST の cron で同じ失敗が出る。
Failed to batch-embed diffs for Liplus-Project/neuron-graph-rag@1fb0f6b397c1ff333d698fe58a862b9583b463fe
chunk offset 0: 3030: Max context reached 60678 tokens but model supports only 60000
18 file が chunk offset 0 の 1 batch。そして 60,678 という報告値が #242 の前から一度も変わっていない。推定トークン軸・文字数軸・バイト数軸の 3 つを通しても同一である以上、batch の組み方が変わっていないことになる。
報告値を件数で割ると全て整数になる
| commit |
batch 件数 |
報告値 |
商 |
1fb0f6b397c1ff333d698fe58a862b9583b463fe |
18 |
60,678 |
3,371 |
bdf8b62bfc8cc88944d342ab0cefc1f544edfa5c |
17 |
64,413 |
3,789 |
92eb94dcb88c5e7494bc3b69377249e08601d99f |
20 |
85,920 |
4,296 |
92eb94dcb88c5e7494bc3b69377249e08601d99f |
16 |
68,736 |
4,296 |
検算: 18 × 3,371 = 60,678 / 17 × 3,789 = 64,413 / 20 × 4,296 = 85,920 / 16 × 4,296 = 68,736。
決定的なのは最後の 2 行。同一 commit を異なる件数で投げて、1 件あたりの商が 4,296 で一致している。 報告値が実トークンの合計であれば、4 件減らして商が変わらないためには除外された 4 件が全て同一トークン数である必要があり、偶然としては苦しい。
推論
エンドポイントは batch 内の入力を最長のものに padding し、消費コンテキストを 件数 × padding 後の長さ として数えていると考えられる。
charged = batch_size × max_over_inputs(tokens(input))
これが正しければ、これまでの 3 回が効かなかった理由が全て説明される。合計をどれだけ正確に縛っても、課金式に合計は現れないため。
確からしさ: 4 観測からの推論であり、確定ではない。確認方法は下記。
確認方法
同一内容の入力を件数だけ変えて投げ、報告値が件数に比例するかを見る。比例すれば padding モデルが確定する。小さな入力 1 件と大きな入力 1 件を混ぜた batch が、大きい方の 2 倍で課金されるかを見るのが最短。
正しい境界の形
batch_size × max_over_inputs(utf8ByteLength(input) + TOKEN_OVERHEAD_PER_INPUT) <= WORKERS_AI_BATCH_CONTEXT_LIMIT
トークン数の上界としてバイト数を使う点(#244)は維持する。破れていたのは上界そのものではなく、合計を縛っていたことである。
1fb0f6b で検算すると、最長入力が約 3,371 トークン相当なので 1 batch は 17 件まで。18 件で超えていた。
設計上の帰結(合計軸には無かった性質)
- 最大の入力が batch 全体の単価を決める。 小さい入力を並べても安くならない。大きい入力が 1 件混ざれば、全件がその長さで課金される
- したがってサイズの近いものをまとめるほど効率が上がる。極端に大きい 1 件は単独 batch にするのが最適
- ただし現在の
planEmbeddingBatches は連続範囲 {start, end} を返し、呼び出し側が files 配列を同じ境界で切ることで位置対応を保っている。サイズ順にまとめるには入力の並べ替えが必要で、この interface では表現できない。範囲ではなく index 集合を返す形への変更が要るかどうかを判断すること
- 並べ替えを行わない素朴な実装でも上記の境界式は満たせる。効率と実装量の判断は実装側に委ねる
constraints
target files
src/pipeline/embedding.ts — 境界式、必要なら planner の返り値形式
src/pipeline/embed-diff.ts — 並べ替えを行う場合の呼び出し側
src/pipeline/embedding.test.ts / src/pipeline/embed-diff.test.ts
src/poller.ts — DIFF_SUBREQUESTS_PER_FILE の前提が動く場合
docs/0-requirements.md / docs/0-requirements.ja.md
acceptance
経緯
#236(推定トークン合計)、#241 → #242(文字数合計)、#244(バイト数合計)に続く 4 度目の修正。前 3 回は「上界の取り方が実測より楽観」という同じ形の失敗だったが、本 issue はそれとは別で、縛る量の選択そのものが誤っていたという診断である。合計を縛る限り、上界をいくら厳しくしても課金式に届かない。
#236 の受け入れ条件は一度も満たされていない。
purpose
Workers AI の batch embed が拒否する量は、入力の合計ではなく
batch 件数 × batch 内の最長入力である可能性が高い。#236 / #241 / #244 は 3 回とも合計を縛っており、縛る対象そのものが違っていた。境界の形を変える。observation
0411f101(#244 の UTF-8 バイト版)が 8 時間前から 100% traffic で稼働中。それでも 2026-08-15 09:30 JST の cron で同じ失敗が出る。18 file が
chunk offset 0の 1 batch。そして 60,678 という報告値が #242 の前から一度も変わっていない。推定トークン軸・文字数軸・バイト数軸の 3 つを通しても同一である以上、batch の組み方が変わっていないことになる。報告値を件数で割ると全て整数になる
1fb0f6b397c1ff333d698fe58a862b9583b463febdf8b62bfc8cc88944d342ab0cefc1f544edfa5c92eb94dcb88c5e7494bc3b69377249e08601d99f92eb94dcb88c5e7494bc3b69377249e08601d99f検算:
18 × 3,371 = 60,678/17 × 3,789 = 64,413/20 × 4,296 = 85,920/16 × 4,296 = 68,736。決定的なのは最後の 2 行。同一 commit を異なる件数で投げて、1 件あたりの商が 4,296 で一致している。 報告値が実トークンの合計であれば、4 件減らして商が変わらないためには除外された 4 件が全て同一トークン数である必要があり、偶然としては苦しい。
推論
エンドポイントは batch 内の入力を最長のものに padding し、消費コンテキストを
件数 × padding 後の長さとして数えていると考えられる。これが正しければ、これまでの 3 回が効かなかった理由が全て説明される。合計をどれだけ正確に縛っても、課金式に合計は現れないため。
確からしさ: 4 観測からの推論であり、確定ではない。確認方法は下記。
確認方法
同一内容の入力を件数だけ変えて投げ、報告値が件数に比例するかを見る。比例すれば padding モデルが確定する。小さな入力 1 件と大きな入力 1 件を混ぜた batch が、大きい方の 2 倍で課金されるかを見るのが最短。
正しい境界の形
トークン数の上界としてバイト数を使う点(#244)は維持する。破れていたのは上界そのものではなく、合計を縛っていたことである。
1fb0f6bで検算すると、最長入力が約 3,371 トークン相当なので 1 batch は 17 件まで。18 件で超えていた。設計上の帰結(合計軸には無かった性質)
planEmbeddingBatchesは連続範囲{start, end}を返し、呼び出し側が files 配列を同じ境界で切ることで位置対応を保っている。サイズ順にまとめるには入力の並べ替えが必要で、この interface では表現できない。範囲ではなく index 集合を返す形への変更が要るかどうかを判断することconstraints
MAX_EMBEDDING_BATCH_BYTESを合計に対して適用する形)は退役させる。合計軸を残したまま件数×最長を足すと、効かない条件が残るutf8ByteLengthとTOKEN_OVERHEAD_PER_INPUT(fix(pipeline): bound embed batches by UTF-8 byte count, not character count #244)は維持DIFF_SUBREQUESTS_PER_FILE = 3の前提(1 batch あたりの最小 file 数)が動く。fix(pipeline): bound embed batches by UTF-8 byte count, not character count #244 の時点で余裕は 75 中 74 まで詰まっているdocs/0-requirements.md/docs/0-requirements.ja.md)を同一 PR で更新するtarget files
src/pipeline/embedding.ts— 境界式、必要なら planner の返り値形式src/pipeline/embed-diff.ts— 並べ替えを行う場合の呼び出し側src/pipeline/embedding.test.ts/src/pipeline/embed-diff.test.tssrc/poller.ts—DIFF_SUBREQUESTS_PER_FILEの前提が動く場合docs/0-requirements.md/docs/0-requirements.ja.mdacceptance
batch_size × max(入力コスト)が上限を超えない1fb0f6b(20 file、うち 18 が indexable)と92eb94d(44 file)が embed に成功するneuron-graph-ragの forward watermark が2026-08-11T15:33:02Zを越えて前進する経緯
#236(推定トークン合計)、#241 → #242(文字数合計)、#244(バイト数合計)に続く 4 度目の修正。前 3 回は「上界の取り方が実測より楽観」という同じ形の失敗だったが、本 issue はそれとは別で、縛る量の選択そのものが誤っていたという診断である。合計を縛る限り、上界をいくら厳しくしても課金式に届かない。
#236 の受け入れ条件は一度も満たされていない。