压缩包不大,AI文档解析服务为什么还是爆了内存?
上传入口已经限制了文件大小,解析服务却仍然可能被一份“小文件”拖住。
因为入口看到的是压缩后的字节,解析器面对的是展开后的内容。再往后,还有文本解码、对象构建、分块、索引和模型调用。
先做一个很小的教学实验:把64KiB重复文本压成ZIP,再查看压缩文件和展开内容的大小。这个样本只有一份小文本,不需要制造巨型文件,也不需要把服务压垮。
from io import BytesIO
from zipfile import ZipFile, ZIP_DEFLATED
raw = b"A" * 65536
buf = BytesIO()
with ZipFile(buf, "w", compression=ZIP_DEFLATED) as z:
z.writestr("sample.txt", raw)
packed = buf.getvalue()
assert len(packed) < len(raw)
with ZipFile(BytesIO(packed)) as z:
assert z.getinfo("sample.txt").file_size == 65536
文件小,只说明传输成本较小。资源预算要跟着内容经过的每一层走。

只检查ZIP里记录的file_size,够不够
可以用声明的展开大小做快速预检,但预检不能替代实际读取限制。文件损坏、成员数量过多、嵌套内容和后续解析开销,都需要自己的处理规则。
一个更具体的验收要求是:在超过允许的展开字节数之前停止继续交付内容,并返回可辨识的错误;已经生成的中间结果不能被标为解析成功。
下面演示单个成员的计数读取。它只返回字节数,不把全部内容拼进内存,适用于说明“运行中也要计量”的机制:
def count_bounded(stream, limit):
if limit < 0:
raise ValueError("limit必须非负")
total = 0
while True:
# 最多多读1字节,以区分恰好到上限和超过上限。
chunk = stream.read(min(8192, limit - total + 1))
if not chunk:
return total
total += len(chunk)
if total > limit:
raise ValueError("展开内容超过预算")
with ZipFile(BytesIO(packed)) as z:
with z.open("sample.txt") as member:
assert count_bounded(member, 65536) == 65536
把预算改成65535,就应该拒绝这个样本。恰好等于上限与多一个字节,都要有独立用例。
这段代码控制的是交付给调用方的展开字节计数。它不保证底层解压器的CPU、内部缓冲或解析器对象开销都被同一个数字限制。真正接收不可信文件的服务,还需要进程级内存、执行时间、输入大小与并发限制。
假设每个成员都不大,整个压缩包却有很多成员。若每个成员都重新获得完整预算,总开销仍然可能超出任务允许范围。
因此要区分单成员上限与任务总上限。读取下一个成
一百个“小成员”,也可能绕过单文件上限员时,它能使用的预算应受到“任务剩余预算”约束。成员数量、嵌套深度、可接受格式也要提前约定。
如果产品不支持嵌套压缩包,遇到嵌套成员就明确拒绝,别让解析器递归展开到哪里算哪里。如果要把内容写到磁盘,还需处理路径约束与隔离目录;本例使用内存小样本,不执行文件提取。
| 测试样本 | 重点检查 |
|---|---|
| 展开后恰好等于上限 | 正常完成,边界不误拒 |
| 展开后超过一字节 | 明确拒绝,中间产物不可用 |
| 多个各自合法的小成员 | 任务累计预算仍然生效 |
| 损坏或无法解析的归档 | 返回真实错误,释放资源 |
| 多个任务同时解析 | 单任务限额与进程总预算协调 |
AI链路里还有一笔经常没算进去的成本
文档展开成功后,可能被切成很多片段,再并行生成向量或交给模型处理。压缩字节、文本字节、字符数和模型token数是不同的量,不能用一个固定比例通吃所有语言和文件。
可以把预算拆成几道可观察的门:接收字节、展开总量、可接受页数或记录数、分块数量、下游调用次数。每个阶段记录已消耗预算和退出原因。

对用户而言,最糟糕的体验之一是页面显示“处理中”,后台早就失败,任务又被自动重试。测试应检查失败能否传播到任务状态,重试是否沿用合理的预算策略,临时文件和已占用配额是否释放。
不要用一次正常文件处理的内存峰值,推断任意文件都安全。先在隔离环境里用小预算、小样本验证边界;再按真实解析器和部署配置做受控容量测试。
让AI辅助生成解析代码时,可以明确要求它列出每阶段预算、超限后的状态、中间产物的清理规则。随后用确定性的反例检查这些规则确实执行。
验收文档导入,下次除了问“这个文件能不能读”,还可以再问:它最多能让系统做多少工作,超过以后会停在哪里?
- 点赞
- 收藏
- 关注作者
评论(0)