各位做技术知识管理的老哥应该都有过这种体验团队Wiki用了几年页面数轻轻松松涨到几千写得越多越没人看。新人入职翻半天找不到入口老人想查某个决策背景又得从长篇大论里一点点刨。我之前带着几个人搞“人工精读”每人每天硬啃几十篇文档辛苦熬了两个月换来的是一堆进度滞后的表格一摞各写各的摘要以及所有人统一反馈“这事再干第二遍就辞职”。于是我把方向转向本地大模型结合一套自己定义的ODP架构重做了整套海量Wiki文档浓缩工作流。这套流程说白了就是解决一个问题让机器代替人做初读让人只做抽查和评审。它不追求把几千篇文章真的“读懂”而是把文档拆成可处理的结构单元分层蒸馏再拼装成标准化的浓缩Wiki页面。用下来至少把整理速度提升了一个数量级人工消耗降到原来的五分之一左右。这篇文章就把这套做法完整拆给大家看包括架构定义、每个阶段的实操细节、提示词设计、参数调优以及我踩过的坑。1. 为什么我最终放弃了“人工精读全体文档”1.1 海量Wiki真正吃人的地方过去我们处理文档的方式本质上是一种典型的瀑布式人工流程先列清单再分工认领然后一篇篇读最后写摘要。看起来井井有条实际跑起来处处是问题。首先人的精读速度是硬瓶颈。一篇技术文档如果涉及架构、接口、配置、故障复盘读一遍加做笔记至少需要二十分钟到半小时。一天就算集中八小时有效精读量也就十几篇。几千篇文档意味着几个人连续做小半年等做完的时候最早那一批文档早就过期了结论已经毫无参考意义。其次文档之间的关联信息被切碎了。Wiki里的知识从来不是一篇篇孤立的文章A文档里的方案可能引用了B文档里的设计决定C文档又记录了后来推翻方案的原因。人工精读往往只针对单篇内容“这篇写了什么”但很难回答“这篇和整个知识体系的关系是什么”。真正该浓缩的恰恰是这种关系而不是单纯每篇的复述。最后是个人表达习惯带来的偏差。同样一篇文档A同学写出来的摘要会有强烈的动手导向B同学则倾向于记录背景和备选方案。两个人写同一篇最后产物的结构、详略、取舍完全不一样。这种“摘要质量不可控”在做大批量整理时非常致命。1.2 本地部署是我的底线考虑到文档内容的安全要求我们一开始就把“数据必须留在本地”定成了不可妥协的条件。不是说不信任云端服务而是知识库里包含了大量内部系统的架构细节、历史故障复盘和敏感配置信息这些东西一旦因为某个调用参数写错而泄露出去风险完全不可接受。所以方案很快收敛到了本地部署大模型这条路。我当时的选型思路很简单用开源权重模型跑在本地推理框架上通过标准的本地接口调用。硬件条件不算夸张一台带独立显卡的机器就能跑起来。模型大小我选了大概7B到14B量级的版本兼顾生成质量跟推理速度。实测下来日常文档浓缩这类任务这个量级完全够用重要的是本地部署解决了一大半合规顾虑后面无论怎么扩展数据都在自己手里。1.3 重新定义“浓缩”这个目标真正做起来之前我干过一件很多人忽略的事把“浓缩”的定义写清楚。过去人工精读的产出经常是“摘要”但“摘要”这个词太模糊。是一篇三句话的概述还是把重点章节摘出来还是包含着决策背景的综述定义不清干活的人就只能自由发挥。我后来把浓缩文档的目标拆成四个维度背景这篇文章为什么存在解决什么问题出现于什么阶段。变更核心结论是什么和旧方案/旧做法有什么不同。影响影响哪些系统、哪些流程、哪些角色需要谁采取动作。操作该做什么怎么做相关配置或命令是什么。凡是浓缩产出都围绕这四类信息来组织。这样一来评价一份浓缩稿好不好就有了相对客观的标准。这套维度定义也为后面ODP架构中“Distill”阶段的提示词设计提供了最直接的框架。换句话说我是先明确“浓缩是什么”再去设计工作流而不是先有工具再回头找用途。2. ODP架构我如何拆解“文档浓缩”这件事2.1 ODP三层到底在做什么ODP是我自己给这套流程起的缩写分别对应三个职责明确的阶段Organize组织、Distill蒸馏、Polish打磨。整个流水线以批次为单位对Wiki页面做处理每一层各管一段层级之间通过标准化的中间产物衔接。第一层是Organize。这个阶段的任务不是“理解内容”而是“把一篇Wiki变成模型能稳定处理的结构化单元”。我会对原始页面做HTML或Markdown解析抽取出标题层级、段落、列表、表格、代码块、引用块。然后按照标题树把内容切割成若干块每个块限制在一个合理的大小范围内块与块之间保留少量重叠避免语义被切断。紧接着给每个页面生成一个“结构概要”就是这个页面有哪些标题层级、大致包含哪些块、哪块可能是重点为后面蒸馏提供导航信息。第二层是Distill。这一层朴素理解就是“让大模型干活”。我会把前面切出来的块和结构概要分批喂给本地部署的大模型让它基于特定的浓缩维度生成初稿。这个阶段刻意分成多个子任务来做每个块先做单块浓缩再跨块做合并与冲突检测最后统一生成页面级浓缩稿。这样做的目的是让模型每次都只处理它能hold住的信息量而不是一上来就面对整篇长文。第三层是Polish。这一层负责把蒸馏出来的结果改写成正式Wiki页面。包括统一排版、重新组织标题、补上原文引用链、生成交叉链接以及把模型写得口语化或啰嗦的部分收紧。这里的核心逻辑是“模型初稿允许有冗余但最终产物必须精炼”。2.2 为什么选了“流水线”而不是“全量直接问”有些朋友看到这里可能会说现在模型上下文已经能做到128K甚至更多直接把整篇文档丢给模型生成摘要不行吗我试过效果不尽如人意。最大的问题是长上下文下的“焦点漂移”。当你把几十个页面的内容拼在一起喂给模型时模型确实一个字都没有漏掉但它对较早内容与较后内容的关注度并不均等往往开头的部分被过度展开中间混杂的定义被一带而过最后出现的细节反而被当成重点。我也调过各种提示词试图纠正效果都很有限。这就像让一个人从几十页材料里写摘要正常人也会出现印象偏差本地部署的这个量级模型更是如此。第二问题是评估困难。全量输入时模型提到某个结论你却很难核实这结论到底来自哪一段原文。一旦生成内容出现低级错误排查起来非常痛苦。ODP把“原文”和“蒸馏结论”之间的关系拆成小块对应关系每个结论都能回溯到具体的块审查成本大幅降低。第三是扩展性。流水线的每一层都能独立替换和优化。发现切割效果不好只改Organize就行模型生成的摘要条理不清楚只调Distill的提示词就行。全量模式就没有这种灵活性一个问题触发全链路返工。2.3 增量更新与状态管理设计ODP架构一开始我就考虑了“只处理变化的部分”。内部Wiki是活的旧文档会被修订新文档不断产生。如果每次全套重跑光算力都很浪费。我的做法是给每个页面建一份处理记录记录里存三个信息页面内容的哈希值、最后一次处理时间、浓缩产物的版本号。每次启动批处理时先扫描Wiki目录计算各页面的新哈希值跟处理记录比对只有哈希值变化或从来没处理过的页面才进入ODP链路。这个设计听起来简单却省掉了大量重复计算。实际运行一段时间后每天需要重新处理的页面可能只有新增的几篇整个系统可以做到“近乎实时”的同步。还有一个小细节由于把页面切成了多个块块本身也会有自己的哈希。如果某篇大文档只改了其中一个章节其实只需要重新蒸馏对应的块而不需要整篇重做。块级哈希进一步压缩了计算量代价是实现稍微复杂一点但非常值得。3. 实操从原始Wiki到浓缩Wiki的完整落地3.1 环境准备与基础配置本地部署这块我的软硬件组合很简单。一台跑着Linux的工作站带一块显存稍大的独立显卡主要跑本地推理服务。推理服务选的是兼容OpenAI接口格式的本地框架这样我的代码可以完全按照标准接口来写以后换别的推理后端也几乎不需要改业务代码。模型方面选的是一般开源基座模型微调过的通用对话版本量化后跑在本地。选7B到14B这个区间是权衡过的更小的模型生成质量不稳定更大的模型推理速度会明显下降维基文档浓缩这种任务并不需要特别强的复杂推理能力这个区间性价比最高。上下文长度配置为8192足够覆盖大多数单块输入的需求。处理脚本我用Python写的。主要的运行流程是一个循环扫描目录、读取文档、解析结构、切块、分批调模型、收拢结果、回写文件。调度上我没有上复杂的任务队列就是写了一个带断点续跑功能的批处理脚本处理到一半崩了也能从上次进度继续这对长耗时任务来说很重要。3.2 Organize阶段标题树、切块与优先级Organize是整个ODP架构的地基这一层做得不好后面两层再漂亮也白搭。我的解析思路是先把每篇Wiki页面转成结构化数据模型然后基于模型切块。第一步是解析标题层级构建目录树。我一般用两层到三层的标题结构作为骨架。骨架决定了切块的边界一个二级标题下的内容作为一个基本大块如果这个基本大块长度超过阈值就按三级标题继续切三级标题下内容还是太长再按段落边界硬分。切块时有几个参数值得具体说说。块长度上限我设为1500个token左右重叠区域设为128个token。这个数值不是拍脑袋定的它考虑了两点一是块长度必须显著小于模型的上下文窗口给提示词和输出留足空间二是重叠区的作用是让前后块之间保留“接缝记忆”避免某个句子被拦腰截断后前后两块都看不懂它。如果是不含代码块说明的普通叙事文本我会把重叠调小一些如果文档大量使用列表和表格重叠就稍大一点。切完块之后我会给每一块打一个简单优先级。规则很粗糙但很实用标题里出现“变更”“故障”“配置”“命令”“架构”等词的块优先级高纯背景介绍类的块优先级低。后面蒸馏的时候高优先级块先处理低优先级块如果时间不够可以延后或简化。这个优先级机制保证在有限的算力内最重要的内容总是最先被浓缩。最后生成结构概要格式大致如下page_summary { title: 内部任务调度系统架构说明, h1_count: 1, h2_sections: [ {title: 整体架构, block_ids: [b1, b2], priority: high}, {title: 调度策略, block_ids: [b3], priority: high}, {title: 扩展阅读, block_ids: [b4], priority: low}, ] }这个结构概要会被传给Distill阶段让模型对全篇结构有概念再针对每个块做细节提炼。3.3 Distill阶段提示词设计与分块蒸馏Distill层的核心是提示词设计和子任务拆分。先说子任务拆分。我把它分成三个小步骤单块蒸馏、跨块合并、页面级合成。单块蒸馏相对简单就是把一个块的内容连同基本的浓缩维度要求一起丢给模型。提示词模板类似下面这种写法你是内部知识库的浓缩编辑。下面是一个技术文档片段请按照四个维度进行浓缩 - 背景这段在讲什么背景为什么会出现这个内容 - 变更相比常规做法或旧方案有什么关键差异 - 影响会影响谁会影响哪些系统或流程 - 操作具体怎么做涉及什么参数或命令 要求 1. 只概括原文有的信息不补充原文没有的结论 2. 表述保持简洁每条不超过三行 3. 如果片段内有明显的信息冲突单独列出“存疑点” 片段内容 {{block_content}}单块蒸馏的输出是结构化的片段笔记。处理完一个页面所有块后进入跨块合并。这一步把该页面各块的笔记放在一起让模型找一找有没有重复表述、有没有互相矛盾的地方并把涉及同一主题的零散信息合并。跨块合并的提示词很简短但非常关键我会明确要求“保留信息来源块编号”。也就是说合并后的每一条内容后面必须跟一个或几个原始块ID。这个设计是后边做溯源审查的基础没有它Polish阶段基本没法判断哪句话是从原文来的。页面级合成就是把合并后的结果再整理成一篇通顺完整的浓缩稿。到这里模型生成的还是一堆按维度分组的要点并不算是漂亮的Wiki页面。它更像一个“内容素材库”准确、有出处、覆盖全面但缺乏统一的叙述结构和排版。这部分就由下一层Polish接着处理。我实测下来把蒸馏拆成三步跑比一次性让模型输出完整页面效果好不少尤其是对那种内容跨度大的文档。模型分阶段处理时每步注意力集中在小范围信息上生成内容的幻觉率明显下降。代价是调用次数多一些但这些调用都很短实际耗时仍然可以接受。3.4 Polish阶段结构化回写与交叉索引Polish阶段是我认为最容易被新手低估的一环。很多人做自动摘要拿到模型输出就直接贴回Wiki结果页面排版混乱、标题不统一、引用链缺失内容虽然对了体验却很差。我的Polish流程包含三个子步骤。第一是标题体系重建。根据模型的输出内容重新生成一套标准的浓缩文档标题结构。一般固定成“背景”“核心变更”“影响范围”“操作指南”“存疑点”五段式。这样无论原文长什么样最终浓缩稿的阅读惯性都是一致的。新人看任何一篇浓缩稿都像是在同一个模子里出来的学习成本大大降低。第二是内容收敛与语言收紧。模型生成的初稿经常存在“过度解释”的问题会把一个已经说清楚的观点换个方式再说一遍。Polish阶段会做一遍压缩删掉重复表述、把口语化表达改成书面表达、把过长的条目拆成列表。这一步可以用更严格的提示词再过一遍模型但我建议至少在初期安排人做一次抽查因为语言风格的“度”很难完全靠规则控制。第三是交叉索引生成。这一步我主要靠代码处理不依赖模型。脚本会扫描浓缩稿中出现的系统名词、页面标题关键词自动匹配Wiki里其他相关页面然后生成“参见XXX页面”的链接。这解决了人工整理时最容易忽略的问题——文档之间的关联关系。一篇调度系统的浓缩稿如果能把相关故障复盘、配置手册、依赖组件页面都链起来才算真正发挥了“浓缩中枢”的价值。Polish阶段的最终输出就是可以发布到Wiki的新页面同时在页面底部自动附加一段元数据标明处理时间、对应原文版本哈希、参与蒸馏的模型和提示词版本号。这样同一张浓缩页面被人改了之后还能追溯原貌。4. 参数调优、质量评估与迭代方法4.1 我调过的几个关键参数整套流程跑起来之后真正的调优工作才刚开始。我从实际体验里挑几个影响最大的参数讲。温度这是最容易出效果的参数。蒸馏任务本质上需要“照着原文说话”温度太高模型容易自由发挥把原文没有的推论讲得头头是道温度太低又容易复读原文缺少归纳。我最终落在0.1到0.3这个区间。做普通背景归纳时用0.2涉及冲突检测时会临时降到0.1。Top-p我顺手设置成0.9没有花太多心思调。这个参数和温度共同决定采样的随机性不是核心矛盾。如果你用的是推理框架的默认值一般问题不大。块长度与重叠这是Organize阶段的灵魂参数。块太长模型接收到太多无关信息浓缩结果容易走偏块太短跨块合并的压力大而且容易丢失上下文。我最后锁定的块长上限是1500个token重叠128个token针对的是我们内部文档平均长度和复杂度的场景。批处理并发数本地推理有一个特点并发太高会导致显存溢出并发太低又浪费算力。我按显存余量把并发数控制在2到4之间。这个数字跟具体显卡有关唯一建议是不要为了速度把显存用满推理服务还需要一些余量做KV Cache稍不留神就会OOM。4.2 质量评估不能光靠手感浓缩稿的质量不能只看“模型输出感觉不错”。我做过一阵子抽检专门设计了一套简单有效的评估方式。我以周为单位从当周新生成的浓缩稿里随机抽5%左右人工对照原文做评审。评审有两个核心维度信息完整性和结论可回溯性。信息完整性是看原文里重要的技术决策、配置变更、操作命令是否都被浓缩稿覆盖结论可回溯性就是随机挑浓缩稿里的某条结论看能不能根据标注的块编号在原文里找到对应依据。这两项反映的问题很直接。如果我频繁发现“原文有重要内容但浓缩稿没有覆盖”那问题多半出在Organize的切块优先级上如果经常出现“浓缩稿写了结论但原文对不上”那多半是Distill阶段的提示词约束不够。用这种把质量问题映射到具体阶段的方法迭代方向会非常清晰。4.3 一个提示词的迭代实例我记得早期有一版提示词要求模型“提炼这份文档的重要内容”输出结果非常泛大段大段复述原文的引言和背景真正有价值的技术细节却被带过了。后来我改成“提取变更、故障、命令、配置项及其影响”效果立刻不一样。原因很简单“重要”这个词对模型来说太抽象但“变更”“配置项”这些具体词模型是能理解和定位的。下一版我继续加了限制“所有操作类信息必须保留可执行的完整性比如具体路径、参数值。”这又是一次明显的质量提升。因为模型默认会把“具体怎么做的细节”压缩成一句抽象的话但这个细节恰恰是浓缩文档最有价值的地方。类似这种迭代本质上是在不断对齐“我们心里认为的重点”和“模型理解的重点”。5. 常见问题与排错实录5.1 重复生成、重复表述怎么处理ODP流程里最常见的质量问题不是错误而是重复。同一篇文档中某个结论在多个章节被反复强调单块蒸馏和跨块合并都会把它们分别提取出来最后Polish就会收到好几条信息几乎相同的内容。我的解决思路有两层。第一层是跨块合并时在提示词里明确加一句“如果多块提到同一个事实只保留描述最完整的一条其余合并去重”。第二层是在Polish阶段用代码做一次字符串相似度去重把相似度超过阈值的长句合并。两层叠加之后重复问题基本被压住了。5.2 分块导致语义断裂有一篇文档讲的是一个完整的处理流程步骤之间用编号列表组织但由于列表太长被切进了两个块。结果模型在第二块里看到的开头是“步骤4验证结果”完全不知道“验证什么”生成出来的浓缩内容就成了“验证结果需要通知相关方”这种没头没尾的话。这个问题的根因是切块时机撞上了强依赖上下文的结构单元。后面我在切块逻辑里加了一个规则编号列表、表格、代码块等结构化内容默认作为一个整体处理即便超过块长上限也不从中间硬切而是整体放入下一个块。这样会导致个别块偏长但避免语义断裂整体收益更大。5.3 推理速度慢怎么办刚开始跑全量处理的时候几千篇文档排队跑速度让人着急。我优化了三个点效果明显。第一是块级哈希增量处理把大量未变更页面直接跳过第二是降低低优先级块的蒸馏迭代次数对背景介绍类块只做一轮生成不做跨块合并第三是把过长的页面在Distill阶段拆成两次独立会话避免单个请求输入过长拖慢推理。这三招之后日常增量更新的耗时降到分钟级别只有首次全量处理时才需要夜间长跑。5.4 常见问题速查表现象可能原因处理建议浓缩稿重复表述较多跨块合并去重约束不足提示词增加去重指令叠加相似度去重结论与原文对不上温度过高或原文存在多义表述温度下调到0.1-0.2提示词要求标注信息来源块关键配置项被省略提示词未强调可执行细节补齐“保留路径、参数、命令”指令某篇文章迟迟处理不完单块过长或并发抢占显存检查标题切块降低推理并发数增量更新不触发页面哈希比对失败检查解析阶段是否跳过了元数据变更的页面6. 收尾想补充的几条经验6.1 保留原始文档的版本链条浓缩稿本质上是“转述”它不应该代替原始文档而应该是通往原始文档的引导。我在实践里坚持了一个原则任何浓缩页面都必须保留指向原文的链接和版本号。原文可能被修改浓缩稿是基于某个特定版本生成的如果版本对不上后续读者按图索骥就可能得出错误结论。有了版本链条就算浓缩稿过期也能快速判断它是否还值得参考。6.2 人工需要参与的位置比想象中少这套流程落地后我发现人工需要深度参与的地方集中在三个阶段提示词与切块策略的初始设计、每周的质量抽检、以及每月的规则迭代。日常运行完全不需要人盯。真要说“告别人工精读”省下来的不是所有阅读行为而是把“逐字读全文”这种高成本动作换成了“抽样审结论”这种低成本动作。一个人的判断力被用在最关键的点上而不是耗在重复劳动中。6.3 这套东西后续还能怎么扩展ODP架构本身可以沿用到很多别的场景。把Wiki输入换成产品需求文档能自动生成需求摘要换成客服对话记录能提炼高频问题换成研发故障报告能输出复盘要点。只要“先组织、再蒸馏、后打磨”的逻辑不变换任何内容类型都说得通。我现在已经在尝试把浓缩产出的结构数据导出成知识图谱的基础节点进一步挖掘文档之间的潜在关联。至少对我来说这一步已经从“提效工具”变成了“重新理解知识库的方式”。