Skip to content

fix(pipeline): bound embed batches by UTF-8 byte count, not character count #244

Description

@smileygames

purpose

planEmbeddingBatches の予算軸を UTF-16 code unit から UTF-8 バイト数へ移す。#241 が根拠にした tokens <= chars は成り立っておらず、実測で破れている。

observation(2026-08-15 00:30 JST cron、#242 deploy 後)

Failed to batch-embed diffs for Liplus-Project/neuron-graph-rag@92eb94dcb88c5e7494bc3b69377249e08601d99f
  chunk offset 0: 3030: Max context reached 68736 tokens but model supports only 60000
項目
file 数 16(#240 の file 予算により 44 から分割済み)
batch chunk offset 0 のみ = 1 batch
planner が課金した文字数 <= 60,000(MAX_EMBEDDING_BATCH_CHARS
実測 token 68,736

したがって tokens / chars >= 1.146トークン数が文字数を超えている。

#242 が deploy されていることは確認済み: file 数が 44 -> 16 に変わり、token 実測値も過去(85,920 / 60,678 / 64,413)と異なる新しい値になっている。旧コードが動いている可能性は排除される。

原因

#241 / #242 が置いた前提はこれ。

every token of a BPE or SentencePiece vocabulary spans at least one character of the input
⟹ tokens(input) <= input.length + SPECIAL_TOKENS_PER_INPUT

byte_fallback で破れる。 語彙に無い文字は UTF-8 バイト列へ分解され、1 文字が複数 token になる。日本語 1 文字(3 バイト)は最大 3 token。実測の 1.146 倍という超過は、内容の一部がこの経路に落ちていることと整合する。

方針:バイト数で縛る

1 token は最低 1 バイトを消費する。 byte_fallback が最も細かい分解であり、それ以下には割れない。したがって

1 batch の合計 UTF-8 バイト数 <= 60,000 - (special token 分)
  ⟹ 合計 token 数 <= 60,000  (無条件に成立)

#241 が求めた「校正しない、構成上正しい」という性質を保ったまま、軸を 1 つ下げるだけで直る。文字数軸が満たせなかったのは、文字と token の対応が 1:1 以上であるという前提が偽だったためであり、バイトと token の対応にはその問題が無い。

コスト: 日本語主体の入力では 1 文字 3 バイトのため、文字数軸に比べ約 3 倍保守的になる。batch 数が増える。これは正しさの代金として受け入れる。#240 の file 予算(DIFF_SUBREQUESTS_PER_FILE = 3 は 1 batch あたり 3 file 以上を前提に amortised cost を見積もっている)との整合を確認すること。

constraints

target files

  • src/pipeline/embedding.ts — 予算軸をバイト数へ
  • src/pipeline/embedding.test.ts — 契約テストの更新、非 ASCII を含む回帰ケース
  • src/pipeline/embed-diff.test.ts — 分割ケースの期待値
  • src/poller.tsDIFF_SUBREQUESTS_PER_FILE の前提が変わる場合
  • docs/0-requirements.md / docs/0-requirements.ja.md

acceptance

  • 1 batch の合計 UTF-8 バイト数が上限を超えない
  • 1fb0f6b397c1ff333d698fe58a862b9583b463fe(18 file)と 92eb94dcb88c5e7494bc3b69377249e08601d99f(44 file)が embed に成功する
  • neuron-graph-rag の forward watermark が 2026-08-11T15:33:02Z を越えて前進する
  • 非 ASCII を含む実測相当(1 batch あたり 68,736 token 級)の回帰テストが追加されている
  • fix(poller): cap diff-path files per run against the subrequest budget [poller, pipeline, docs, tests] #240 の file 予算が破綻していない

経緯

#236(token 予算・推定器)、#238(subrequest / file 予算)、#241(文字数軸)に続く 4 周目。#236 の受け入れ条件「watermark が boundary commit を越える」は一度も満たされていない。3 回とも、境界の根拠が実測より楽観的だったことが原因である。今回はバイト数という測定可能な下界を使うため、同じ形での再発は起きない。

Metadata

Metadata

Assignees

Labels

bug動いていない、壊れているready本文が実装開始できる形まで収束している状態。ただし更新は継続可能review-pending実装フェーズ完了。orchestration (brake eval / review / merge / close) 待ち

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions