新所得库 - 长文向量化踩坑记:用“摘要”替代“全文”,终结 NoneType

新所得库 - 长文向量化踩坑记:用“摘要”替代“全文”,终结 NoneType

结论先行:向量化时用了全文,大文档/长网页超出嵌入模型上限 → 返回 None → 触发 'NoneType' object is not subscriptable。修复为用 LLM 生成的压缩摘要(compress_content)做向量化,并加“无摘要则截取前 1000 字”的兜底,两条上传链路(upload-file / upload-url)已统一修复并通过回归。


一、问题是如何被发现的(现象 → 复现)

  • 日志表象:解析成功、向量化开始,但随后报错:'NoneType' object is not subscriptable

  • 触发条件:当文件或网页正文极长(数万字符)时更易复现

  • 关键矛盾:上游已经产出 compress_content(摘要),但向量化入参仍然使用原始全文

这是“看上去更全面,实际更脆弱”的典型陷阱:高信息量≠高可用性。


二、根因定位(从现象到契约)

  1. 嵌入模型输入上限
    大文本直接丢给嵌入接口,超长即截断或直接失败;部分实现超限返回 None,向量下游取值即触发 'NoneType'

  2. 链路不一致

    • 内容处理链:LLMService.process_file_content 生成 compress_content(摘要与标签)✅

    • 向量化链:仍用 html_content / file_text_content 全文
      两条链路没有对齐

  3. 缺少兜底策略
    当摘要缺失或生成失败时,向量化没有降级,导致失败不可控。


三、修复方案(统一策略 + 可回退)

3.1 统一“向量化输入”为摘要优先

  • 原则始终优先用 compress_content 做嵌入,它是“可控长度的高信息密度表示”。

3.2 兜底策略

  • 若没有摘要或摘要过短:使用原文前 1000 字(可通过配置项调整),在保证代表性的同时控制长度。

3.3 关键代码对比

修复前(节选)

# upload-file / upload-url 均类似
vectorize_success = await vectorize_file_content(
    nk_id=nk_id,
    file_content=file_text_content_or_html,  # ❌ 使用全文
    file_name=filename,
    company_code=company_code,
    user_id=user_id
)

修复后(节选)

# 1) 预处理后拿到 compress_content(LLM 摘要)
compress_content = result.summary or ""

# 2) 选择向量化入参(摘要优先,缺省退 1000 字)
content_for_embedding = (
    compress_content if len(compress_content) > 0
    else (file_text_content_or_html[:1000] if file_text_content_or_html else "")
)

# 3) 日志打点:可观测输入长度,便于排查
logger.info(f"[Vectorize] {filename} content_len={len(content_for_embedding)}")

# 4) 向量化
vectorize_success = await vectorize_file_content(
    nk_id=nk_id,
    file_content=content_for_embedding,      # ✅ 使用摘要/兜底
    file_name=filename,
    company_code=company_code,
    user_id=user_id
)

统一后,upload-fileupload-url 的语义一致,排障成本大幅下降。


四、验证与结果(事实闭环)

  • 长文/长网页:不再触发 NoneType,向量化成功率显著提升

  • 日志观测content_len 落在预期范围内(通常 < 1200)

  • RAG 检索:可稳定召回摘要关联片段,不再因超限失败导致空检索


五、风险与防线(把坑填平)

  1. 摘要失败风险:仍可能出现 LLM 侧异常

    • 处理:兜底切片(前 1000 字)+ 失败重试(指数退避)

  2. 摘要信息损失:过度压缩可能漏关键信息

    • 处理:摘要长度可配置(如 600/800/1200 字),按业务类别动态阈值

  3. 可观测性:没有数据就没有改进

    • 处理:统一日志字段:source_typeraw_lensummary_lenembed_lencost_msmodel_nameerr_code


六、我们学到了什么(可复用的方法论)

  • 链路一致性优先:内容处理与向量化的输入语义必须对齐;一个用摘要,一个用全文,是隐蔽的不一致源。

  • 摘要是工程而非装饰:在 RAG 管道里,摘要不仅是“字段”,而是稳定性的第一道闸门

  • 为失败设计:兜底策略(截断/降级/重试)要写进“第一版”,否则问题只会在流量上来后集中爆炸。

  • 可观测即可改进:标准化日志字段,让每次失败都有“坐标”。


七、建议的提交说明(可直接使用)

fix(rag): 统一向量化输入为摘要,长文不再触发 NoneType

- upload-file / upload-url 改为优先使用 compress_content 进行向量化
- 当摘要缺失/异常时,降级为原文前 1000 字
- 新增日志:raw_len/summary_len/embed_len,便于排查与观测
- 回归验证:大文档/长网页不再出现 'NoneType' object is not subscriptable

八、后续优化路线(前瞻)

  • 动态切片 + 语义融合:对无摘要场景,按句/段落滑窗嵌入并聚合,提升代表性

  • 领域化摘要提示词:让摘要对齐检索目标(问答/事实/流程),减少信息“压没了”的风险

  • 批处理与限流:嵌入服务加批量接口和 QPS 控制,避免峰时抖动


一句话收尾:
信息密度 要服务 资源边界;在向量化这一步,“可控的高密度摘要”永远优于“失控的长篇大论”。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夏驰和徐策

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值