报错是这么冒出来的。调用自建 embedding 接口做离线入库,两万条里有三百多条返回的向量全是 0,接口状态码却是 200,服务是 FastAPI 加 sentence-transformers 3.0。
中间走过弯路,把「某几条超过模型最大长度,被静默截成空」当成主因,改完现象没变。
真正麻烦的地方在于,几个原因的现象几乎一样。输入被清洗成空串,模型对空输入返回零向量。少数情况下是批处理里 padding 逻辑写错,短句被整段截掉。
少数情况下是并发写入时张量被复用,后到的请求覆盖了结果。
上来先统计零向量的条数与原始文本
python -c "import numpy as np,json;rows=[json.loads(l) for l in open('emb.jsonl')];print(sum(1 for r in rows if not np.any(r['v'])))"
随后把对应原文捞出来看长度分布
python -c "import json;rows=[json.loads(l) for l in open('emb.jsonl')];print([len(r['t']) for r in rows if not any(r['v'])][:10])"
然后加长度校验,空文本直接跳过不入库
python -c "t=open('a.txt').read();print(len(t.strip()))"
服务端对空输入显式返回 400
curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/embed -H 'content-type: application/json' -d '{"inputs":[""]}'
恢复的判定其实很直接。零向量条数降为零,入库前空文本占比也被统计出来,接口对空输入返回 400 而不是 200。
提醒一点。零向量入库不会报错,但会让检索永远命中不相关内容,宁可在写库前拦下也不要靠事后排查。这类问题最好一次改到位,反复小改反而容易把原因搅混。
