资讯动态

文件不上传,AI 照常干活:本地处理+云端推理的文档问答实践

发布时间:2026/10/13 13:54:11 来源:尧图企业网站定制
这两年我观察到一件挺拧巴的事AI 工具越好用用户交出去的文件就越多。你想让 AI 帮你分析合同、整理会议纪要、从报表里捞数字几乎第一件事都是“上传文件”。上传之后到底是方便还是隐患很多人其实没细想过。之前我接了一个内部文档处理的小项目对方给出的硬性要求是“原始文件不能离开本地环境但必须用上对话式 AI 的分析能力”。那会儿市面上主流玩法全是传文件我折腾了一阵最后搭出来的方案恰好就是现在大家常说的第三条路文件不出本地AI 照常干活。这套思路和完整实操过程今天一并写下来给正在隐私和便利之间纠结的人做个参考。1. 为什么 AI 越好用文件越不得不交出去1.1 AI 不是天生就要文件是“看懂”内容需要路径很多人以为 AI 对话框天生就会读 PDF、Word其实不是。模型本身是无状态的你每次提问它都相当于第一次认识你。要让 AI 准确回答你文档里的内容唯一的办法就是把相关内容“喂”到它的上下文窗口里。面对一份几十页的合同你不能整本丢进去一是窗口装不下二是不必要的文字会稀释回答的准确性所以主流做法是先解析文档、切片、做向量化再由系统检索出最相关的片段塞进 prompt 里让模型回答。这套流程就是很多人听过的 RAG检索增强生成。也就是说AI 要处理文件核心是“内容必须经过模型”。上传只是最省事的一种让内容抵达模型的方式但绝不是唯一方式。过去大家不提别的路是因为本地缺少能读懂文件的小模型也缺少好用的文档解析工具只能把文件整包发给云端服务。现在情况不太一样了。1.2 上传成为默认方案有技术原因也有成本原因从产品角度看把“上传文件”做成默认功能几乎零成本。服务器端的模型天然接收服务端文件用户传完文档平台方解析、切片、召回、推理一条链路全在自家机房完成体验顺畅用户也省心。风险却几乎全由用户承担文件传上去之后它会被谁看到、会不会被用于模型训练、保存多久后删除这些细节普通用户根本无从验证。更现实的问题是文件一旦离开本地就很难“撤回”。哪怕对方承诺删除它可能已经被多级缓存、日志系统、备份任务复制了好几份。就算模型服务商有删除机制你也没有办法证明删除真的发生更没法确认模型是不是已经“记住”了你的内容。对于合同、竞标方案、客户名单、个人简历这类敏感材料这种不可控性是很要命的。1.3 风险不是“会不会泄露”而是“泄露之后你毫无办法”我在实际项目中反复跟人强调一个观点评估数据风险不要只问“会不会泄密”要问“如果泄密了你能不能追溯到责任人”。上传文件给在线 AI相当于把追责能力也交了出去。你连文件被谁访问过都不知道出了问题只能干着急。这些年行业数据安全的要求越来越严。很多公司内部信息被要求分级管理个人隐私数据更不能随便流到外部服务。可业务部门又想用 AI 提效于是“一边用 AI 一边违反管理规定”的情况非常普遍。大部分人不是不担心风险而是觉得没得选只能在“效率”和“安全”之间二选一。这条第三条路本质就是不想再做这个选择题。2. 两条老路的代价你我都踩过2.1 路线A全部上云方便是真方便失控也是真失控全上云这条路最典型的就是把文件拖进各种在线 AI 工具让它总结、问答、改写。优点是体验极好模型能力强能看图、能读表格、能听懂口语几乎不需要学习成本。我自己也常用这种方式处理不敏感的材料比如公开文章、行业报告、会议记录初稿。但它的代价同样明显。首先是控制权丧失文件到了云端存储、流转、使用方式都不由你决定。其次是留存时间不明不少平台会保留用户上传内容用于优化模型哪怕你只是临时用一下它也可能在服务器上躺几个月。最后是费用问题按量计费的在线 AI面对高频、大批量的文档问答费用很快会累积成负担。这些痛点在稍微正规一点的企业内部几乎都会被放大。2.2 路线B全部本地安全是真安全门槛也是真门槛另一条老路是把模型直接部署在本地机器上所有计算不出门。这条路线最大的优点是数据主权牢牢握在自己手里网络断了一切照跑没有任何第三方能看到内容。对保密要求极高的场景这是唯一能接受的选择。但自己跑过模型的人都知道它有多麻烦。普通笔记本跑一个小尺寸模型回答质量跟云端大模型差距明显尤其在复杂推理、长文档总结这种任务上几乎没法比。想要好效果就得买大显存显卡一台机器成本就够请人做很久的人工分析。此外模型更新、依赖维护、量化调优、多人并发访问……每一个都是坑。对个人用户来说这条路基本劝退对中小企业来说又显得性价比太低。2.3 之前没得选现在为什么突然有了第三条路过去这两条路之间确实没有中间解但现在情况变了。一是本地轻量模型和向量化模型越来越成熟普通 CPU 或入门级显卡就能跑中文效果也够用二是云端推理的成本比前几年降了非常多单独发一小段文本给大模型做生成费用可以忽略不计三是文档解析、切片、脱敏这类工程组件已经非常成熟拼出一条“本地处理、云端推理”的链路并不难。路线数据控制权模型能力部署门槛成本适用场景全部上云低高极低按量递增公开、低敏感资料全部本地高中低很高硬件投入大绝密、离线场景本地加工云端推理中高高中低且可控内部文档、个人隐私材料第三条路不是把“全部本地”和“全部上云”简单折中而是把风险点从“整份文件外传”变成“必要片段外传”把控制权和便利性同时保住。3. 第三条路文件不出本地AI 照常工作3.1 用一句话讲清这条新路子一句话版本在本地完成文件的解析、切片、向量化、检索和脱敏只把“脱敏后的相关片段问题”发送给云端大模型做最终回答原始文件自始至终没离开过你的硬盘。我习惯用一个管家的例子来解释你有个贴身管家想请外面的资深专家给意见但不想把家底文件直接给专家看。管家先自己读完全部文件挑出与问题相关的几页把里面的人名、电话、地址涂掉再抄成一张便签交给专家。专家只看到便签看不到你的档案柜。这套方案里的“管家”就是本地代码“专家”就是云端大模型“便签”就是脱敏后的检索片段。3.2 本地加工这一步具体做了什么实操链路由六个环节组成。第一步是文件解析。PDF、Word、Excel、图片都在本机处理把内容提取成纯文本。如果遇到扫描版 PDF就本地跑 OCR图片表格也可以通过结构化解析尽量还原。这一步最关键的是不把原始文件发出去也不在本地之外产生副本。第二步是切片。长文档不能整篇喂给模型需要切成一块块长短合适的片段好让后续检索更精准。切片质量直接决定 AI 能不能找到答案。第三步是向量化。用本地 embedding 模型把每个片段变成向量存进本地向量数据库。这一步相当于给每段内容建了个索引方便以后按语义找相关内容。第四步是检索。用户提问时在本地把问题向量化和库里所有片段做相似度计算找出最相关的几个片段。整个过程没有任何外发请求。第五步是脱敏。对检索出的片段做规则扫描把手机号、身份证、银行卡号等常见的敏感信息替换成占位符。需要脱敏到什么程度取决于你手里的数据类型后面我会专门写。第六步才是云端推理。把脱敏后的片段拼进 prompt连同用户问题一起发给云端大模型让它基于片段给出答案。云端永远拿不到你的完整文档只能看到一小段已经被处理过的上下文。3.3 这条路也有边界别把它想成“绝对安全”这条第三条路比“全部上云”安全得多但绝不是“绝对安全”。严格说发送给云端的那一小段文本仍然是数据出境只是从“全部家当”变成了“摘抄的一页纸”。如果你的材料敏感度极高、密级极重就连片段都不能外发那还得回到全程本地生成的路线。这个底线做技术方案的人心里必须清楚。另外多轮对话会带来上下文累积。用户连续追问系统可能把多轮检索到的不同片段都放进上下文敏感信息被带出的概率会随之上升。所以方案里要加状态控制每轮只允许带上最新检索结果历史对话重新做脱敏再回填并且设置最大上下文长度防止越问越多。成本方面由于发送给远端的是小段文本token 耗费远低于整份文档上传费用完全可以忽略。提示所谓“第三条路”在工程上并不神秘就是“本地私有化处理 云端通用推理”的混合架构。它既解决了数据管控问题又保留了高质量模型的分析能力。4. 实操记录搭一个本地优先的文档问答系统4.1 工具选型与为什么这么选这套系统我建议用 Python 来搭生态最全踩坑最少。本地向量库用一个轻量级开源实现就行不需要单独部署服务直接在项目目录下持久化。embedding 模型我用的是 bge-small-zh-v1.5 这类中文向量模型维度低、速度快在文档检索场景表现够用。云端模型就用你熟悉的任意商业大模型开放接口前提是它提供标准 chat 协议便于替换。选这些组件前我对比过几个方案。一开始想用重量级的向量数据库服务结果发现单机文档问答根本不需要那种规模反而多了一个常驻进程部署复杂度直线上升。后来换成嵌入式向量库进程内读写十页的文档从解析到入库不到两秒省心很多。 embedding 模型也纠结过大模型还是小模型实测发现 bge-small 这类小型模型足以应付合同条款、会议纪要这种语义明确的中文文本速度比大模型快出好几倍没必要上重模型。4.2 完整流程与关键代码下面这段代码覆盖了解析、切片、向量化和入库是整个系统的第一步。需要提前安装好 PDF 解析库、向量化库和向量库依赖。import re from pypdf import PdfReader from sentence_transformers import SentenceTransformer # 本地解析 PDF提取纯文本 reader PdfReader(合同样本.pdf) full_text \n.join(page.extract_text() or for page in reader.pages) # 按固定长度切片带 50 字重叠避免切断关键信息 def split_text(text: str, size: int 400, overlap: int 50): chunks [] start 0 while start len(text): end start size chunks.append(text[start:end]) start end - overlap # 过滤掉纯空白和过短的无效片段 return [c.strip() for c in chunks if len(c.strip()) 30] chunks split_text(full_text) print(f共切出 {len(chunks)} 个片段) # 本地向量化 embedder SentenceTransformer(bge-small-zh-v1.5) vectors embedder.encode(chunks, normalize_embeddingsTrue) print(向量化完成)解析 PDF 时务必处理空页我发现不少扫描件会带几页空白直接拼进文本会污染后续切片。固定长度切片只是一个基础策略如果你面对的文档结构很有规律按段落切会更好这个细节第五部分再展开。然后是入库和检索。向量库用持久化模式保存到本地目录这样重启后不需要重复向量化。检索时把用户问题和片段都在本地做向量取相似度最高的前几个片段。import chromadb # 初始化本地向量库持久化到项目目录 client chromadb.PersistentClient(path./local_db) collection client.get_or_create_collection( namedocs, metadata{hnsw:space: cosine} ) # 入库 ids [fchunk_{i} for i in range(len(chunks))] collection.add( idsids, documentschunks, embeddings[v.tolist() for v in vectors] ) # 检索 def retrieve(query: str, top_k: int 3): q_vec embedder.encode([query], normalize_embeddingsTrue).tolist() result collection.query(query_embeddingsq_vec, n_resultstop_k) return result[documents][0] related retrieve(合同中的付款条件是什么) for i, doc in enumerate(related): print(f--- 片段 {i 1} ---) print(doc)这里有个关键点embedding 模型一定要和入库用同一个不能这次用 a 模型、下次用 b 模型否则向量空间不一致检索效果会崩塌。我的做法是把 embedding 模型单独封装成一个全局实例避免重复加载也避免换错模型。接下来是脱敏和远端生成。脱敏正则覆盖了手机号、身份证、银行卡号实际使用时可再按业务补充邮箱、地址、项目代号等模式。import os import requests # 敏感信息脱敏 def mask_sensitive(text: str) - str: # 常见手机号 text re.sub(r(?!\d)1[3-9]\d{9}(?!\d), [手机号], text) # 18 位身份证号 text re.sub(r\b\d{17}[\dXx]\b, [身份证], text) # 16-19 位银行卡号 text re.sub(r\b\d{16,19}\b, [银行卡], text) return text safe_chunks [mask_sensitive(c) for c in related] context \n---\n.join(safe_chunks) # 调用远端大模型只发送脱敏后的片段 resp requests.post( https://your-api-endpoint.example.com/v1/chat/completions, headers{Authorization: fBearer {os.environ[API_KEY]}}, json{ model: your-remote-model, messages: [ { role: system, content: 你是一个文档问答助手。请只根据提供的片段回答问题不要编造不存在的信息如果片段没有相关内容直接说不知道。 }, { role: user, content: f资料片段\n{context}\n\n问题{query} } ], temperature: 0.2, stream: False }, timeout30 ) data resp.json() print(data[choices][0][message][content])注意 system prompt 里那句“只根据片段回答、不要编造”不是摆设。大模型被丢进片段后如果没有任何约束它会自由发挥把片段之外的信息也混进来。我实际测试过加这句和没加回答的严谨度差很远。另外请求超时设为 30 秒比较合适模型生成慢时不会把主流程卡死。4.3 参数怎么定实测效果如何几个核心参数我直接给经验值。切片大小建议 300 到 500 字太短容易把一句话拆得七零八落太长则一个片段里可能混入多个无关主题检索召回反而下降。重叠 50 字是为了避免关键句恰好被切到边界。top_k 取 3 到 5太少答案可能不全太多会把噪音塞进上下文让回答变得啰嗦。我用一份 10 页的中文 PDF 做过完整测试从解析到向量化入库大约 2 秒一轮提问检索1 到 2 秒云端生成回答5 到 15 秒不等。整体体验已经接近全上云工具的流畅度但整个过程原始文件没离开过本地机器远端接口只收到不超过几千字的内容调用费用几乎可以忽略。5. 踩坑记录与排查清单5.1 切片和检索最容易翻车的两个环节切片时如果用固定字符长度很容易把表格里的数字列切断或者把合同的“甲方/乙方”上下文切断。我的经验是按结构先分块比如 PDF 先按章节标题切分再对超长块做滑动窗口。纯文本场景下至少要在句号、换行后面切别硬按字符数一刀切。扫描件 PDF 是另一个大坑。直接调文本提取接口出来的是一堆乱码或空白。这种情况下必须先做 OCR把图片转成文字再做后续流程。别指望跳过这步。表格类内容更麻烦普通文本提取会把单元格顺序打乱建议对表格单独处理比如提取成 Markdown 表格再作为独立片段入库。检索召回率不足时不要只调大 top_k先检查是不是切片把关键句切碎了或者 embedding 模型和文档领域不匹配。5.2 脱敏做到什么程度才算“够”正则脱敏能挡住格式固定的敏感信息但挡不住所有情况。比如人名、公司名、项目代号这类非结构化信息正则根本处理不了。我的做法是正则规则覆盖格式类信息再配合关键词表过滤业务敏感词最后定期抽检脱敏结果。抽检很重要——不抽检你永远不知道哪一类敏感信息漏了过去。还有一个很多人忽略的地方用户问题本身可能泄露敏感信息。比如有人问“李总在 XX 项目里的付款安排”问题里就带了人名和项目名。所以在把用户问题也放进远端请求之前同样要过一遍脱敏。系统提示词里也要明确告诉模型回答时不要复述片段中的号码和标识能让人少很多麻烦。5.3 合规与审计必须从一开始就考虑第三条路并不是把文件“完全不出门”当作卖点而是把“出门的内容”控制在最小必要范围内。但任何外部 API 调用都会留下日志如果你所在行业对数据外发有明确要求一定要在系统里加上审计功能记录每次发送给远端的片段长度、请求时间、用户身份以及脱敏前后对照摘要。出了事能追溯比任何技术承诺都有效。另外不要对用户承诺“绝对安全”。我在项目汇报里写的是“原始文件不出本地单次外发仅脱敏片段”而不是“数据完全不出网”。前者是真实可验证的事实后者是谎言。如果客户或老板坚持要求完全不出网那就得把云端推理替换成本地模型推理虽然回答质量会降一档但这是唯一合规的选择。5.4 快速排查速查表症状可能原因处理办法检索到的片段明显不对切片把句子切断 / embedding 模型不符改用结构化切片确认向量化模型一致扫描 PDF 解析出来是乱码没有做 OCR增加本地 OCR 步骤云端回答胡编系统提示没约束强制“只根据片段回答不知道就直说”脱敏后仍有敏感信息规则覆盖不全加关键词表定期抽检首次问答很慢embedding 初始化 建库耗时把 embedding 模型常驻内存入库流程异步化多轮对话越答越偏上下文累积了多个片段限制上下文长度每轮重新脱敏6. 最后再分享一点我的实际体会我把这套系统用了大概一个季度最大的感受是它不是一个“妥协方案”反而更像一个“正确方案”。大部分文档问答场景并不需要把整份文件都塞给模型只需要最相关的几百个字。既然如此何必整包上传让本地把脏活累活干完云端只做最后一步思考两边都轻松。安全性提升了成本降下来了体验也没有明显折扣。最后分享一个小技巧拿到一批文档先别急着入库先写个脚本批量扫描一遍文件里的敏感字段对每份文档做一个“敏感级别”标记。极高级别的文件直接走全本地推理普通级别的走混合链路公开资料才考虑直接上云。这样分类处理既省心又稳妥。文件上传这件事以后真的不应该是唯一选项。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑