按 1000 字符切块喂 bge-m3,单块中文约 900 token,而部署的 max_seq 只有 512,服务端静默截断,后半段内容没进向量,检索时尾部信息永远召回不到。
真正麻烦的地方在于,几个原因的现象几乎一样。分块单位与模型最大长度不一致;服务端截断不报错,客户端以为全部入向量;中文的字符与 token 比例远高于英文;长表格块被整体塞进一条。
先统计所有块的长度分布
python -c "import tiktoken;e=tiktoken.get_encoding('cl100k_base');print(sorted(len(e.encode(l)) for l in open('chunks.txt'))[-5:])"
再往下按 480 token 重新切分并留 32 的重叠
python rechunk.py --tokenizer cl100k --max-tokens 480 --overlap 32 --in docs/ --out chunks2/
给超长块加一条告警,禁止静默通过
python -c "print('warn when tokens > 500')"
等前面都确认过,再重建索引后对比尾部问题的召回
python eval_recall.py --before old.json --after new.json
中途换过一次思路,把范围缩到最小的那一层,反而快了。
别只看报错消失,验证要多做一步。所有块的长度都在 512 以内,尾部信息相关的提问能进入前 5,索引条数比原来多了约三成。
补一句。分块长度要以 embedding 模型的实际上限为准,字符数只能当粗略参考,入库前一定要用 tokenizer 复核。拖得越久,排查成本越高,因为现场状态会被后续操作覆盖。
