这期课程笔记其实源于一次很现实的需求团队里有人每天要啃几十页技术方案问我能不能用大模型自动把每份文档压成三百字以内的要点。我试了一圈本以为无非就是把文本扔给模型说一句“帮我总结一下”真正动手才发现文本概括这件事表面上是Prompt问题背后其实是文档切分、上下文窗口、事实一致性、结果评估一整条链路。这篇就是课时7的复盘整理面向正在入门LLM的开发者尤其是接下来要做文档摘要、会议纪要抽取、资料归纳这类功能的人。课程本身是录播形式的但我在本地把每个示例都重跑了一遍顺便补了几个生产环境里更常见的坑。这篇笔记不会从头讲Transformer而是直接从“用大模型做文本概括”这个任务出发讲清楚原理、策略、代码和评估作为课时7的学习记录也当作一份可直接复用的实操清单。1. 为什么说“文本概括”是LLM最容易被低估的能力1.1 传统摘要方法的瓶颈在接触LLM之前文本概括在传统NLP里基本有两种做法抽取式和生成式。抽取式也就是拿句子打分排序把最重要的句子原样拼到一起。常用的算法包括TF-IDF和TextRank。TextRank的想法挺直观它把每个句子当成一个节点句子之间用相似度建边然后跑PageRank迭代得分高的句子就当成摘要。这种方法实现的成本很低但问题非常明显第一选出来的句子都是原文的碎片没有上下文衔接读起来经常前言不搭后语第二它只能判断“哪些句子看起来重要”判断不了“哪些信息是用户真正需要的”第三对跨越多个段落的隐性主线几乎无能为力。早期也有一些生成式方案比如基于序列到序列的模型训练一个“读原文——生成摘要”的翻译式网络。这类模型的效果在当时已经算不错但泛化能力差换个领域效果就崩而且生成的摘要长度不受控经常出现重复片段。即便到了基于预训练模型做微调的阶段想要让一个摘要系统在特定领域落地仍然需要准备大量“原文—参考摘要”配对数据人力成本非常高。1.2 LLM改变了什么LLM把这件事的复杂度一下拉低了。原因在于预训练阶段模型已经读过海量文本掌握了“信息压缩”和“语义改写”的能力。我们不再需要为每个领域单独训练一个摘要模型只需要通过Prompt告诉模型“你要扮演什么角色、输入是什么、输出成什么样”它就能在零样本或少样本条件下完成概括。这里有一个容易被忽略的技术点注意力机制让模型在做生成时能够同时“看到”原文里的关键片段而不是像传统模型那样只能依赖局部窗口。这意味着模型在做概括时有能力把文章开头埋的伏笔和结尾的结论关联起来这是抽取式算法做不到的。不过“有能力”不代表“每次都会做”。LLM的概括质量高度依赖任务描述是否清晰以及文本以什么形式喂给模型。这也就引出了开发者在用LLM做文本概括时真正要花心思的地方不是模型选哪个而是文本怎么给指令怎么写结果怎么验。提示不要把文本概括想成“压缩文件”。它更像是“按需提炼”——用户要的不是内容变短而是把符合目标的那部分信息以更紧凑的形式保留下来。想清楚这个定位后面的Prompt设计和策略选择都会顺很多。2. 三种典型概括场景与策略选择直接总结、分块汇总、多文档归纳2.1 单文档中等长度文本一次Prompt搞定面对一篇几千字以内的文章比如一篇技术博客、一份项目周报、一段产品说明最直接的做法是把整段文本一次性喂给模型然后让模型输出摘要。这种策略适合上下文窗口足够、Token成本可控的情况。实际操作中我觉得最需要注意的是Prompt里必须同时给出三个约束长度约束、格式约束、内容重点约束。举一个我常用的模板请阅读以下文本写一段中文摘要。 要求 1. 字数控制在150字以内 2. 以“核心结论”开头接下来按重要程度列出要点 3. 只使用原文中出现的信息不要补充任何背景知识 4. 保持客观中性语气。 文本内容 {{输入文本}}这个模板里“只使用原文中出现的信心”这句话在减少摘要幻觉上有非常明显的作用。后面第4节我会展开讲。2.2 超长文档分块之后再做Map-Reduce长文档是文本概括里最容易翻车的场景。几十页的PDF、几百页的行业报告直接把全文塞进Prompt里轻则超出上下文限制重则模型在长文本中“迷失”摘要质量断崖式下降。核心原因有两个。第一是Token上限这是硬约束。第二是注意力退化研究表明模型对长上下文的中间部分关注度明显偏低也就是说你把一本两百页的文档喂进去模型很可能只记住开头和结尾的内容中间的细节直接丢失。所以对超长文档要采用Map-Reduce式的处理思路。Map阶段把文本切分成多个块每块单独生成一个局部摘要Reduce阶段把所有的局部摘要拼接起来再做一次全局摘要。这个过程很像处理一个超大的数据文件时先分片再合并。这里的操作细节很关键直接影响最终效果尤其是三个参数块大小、重叠窗口、首轮摘要粒度的把握。我通常把块大小设置在1500到2000字左右重叠窗口设置在100到200字既能保证每块语义相对完整又不会让块与块之间的衔接信息丢失。2.3 多文档/多来源信息先抽要点再逐层归并还有一类场景不是单篇文档太长而是信息分散在多份来源里比如同题材的多篇新闻、一批客户的反馈邮件、若干个调研访谈记录。这个时候概括的重点不是压缩某一段文本而是跨文档做信息整合。我推荐的做法是两阶段第一个阶段对每个文档分别生成结构化要点每个要点尽量带上来源编号比如“文档1提到某功能加载耗时3秒”第二个阶段把所有要点聚到一起按主题或时间线做归并最终生成一份综述。这个设计看起来多了一次调用成本更高但换来的好处非常明显来源可追溯。一旦最终摘要里出现某条关键结论你能顺着编号回溯到原始文档这在真实项目里几乎是刚需。三种场景的对照如下场景类型文本规模推荐策略关键参数/操作主要风险单文档中等长度3000字以内一次Prompt明确长度、格式、重点摘要幻觉、信息丢失超长单文档数千字至数百页分块Map-Reduce块大小、重叠窗口主题断裂、局部信息遗漏多文档归并多篇来源分层归纳来源编号、主题聚类重复信息、关键结论缺失这里需要强调场景判断不要在代码里写死“超过多少字就分块”而是先看文本的结构。如果一篇长文本身有清晰的小标题按小标题切块通常比按字符数硬切效果更好因为语义边界更自然。3. 一个可运行的文本概括Pipeline从清洗到二次汇总3.1 整体流程与代码骨架我在课时7的实战环节里搭了一个通用Pipeline步骤是文本清洗 - 分块 - 首轮提取 - 二次汇总 - 结构化输出。这个流程不依赖具体模型理论上所有有通用对话能力的LLM都能跑。下面是核心代码骨架我用的是通用的大模型接口风格你换成任何一家的SDK只需要改调用那几行import re def clean_text(raw: str) - str: 清洗原始文本去HTML标签、多余空白、页眉页脚痕迹 text re.sub(r[^], , raw) text re.sub(r\s, , text) # 这里可以继续追加规则比如去除“第X页/共Y页”等页码信息 return text.strip() def chunk_by_paragraphs(text: str, max_chars: int 1500, overlap: int 150): 优先按段落聚合到达目标大小时切块并保留重叠部分 paragraphs [p.strip() for p in text.split(\n) if p.strip()] chunks, current [], for para in paragraphs: if len(current) len(para) max_chars: current para \n else: # 保留上一块的末尾部分作为重叠 tail current[-overlap:] if len(current) overlap else current chunks.append(current.strip()) current tail para \n if current.strip(): chunks.append(current.strip()) return chunks def summarize_chunk(chunk: str, client, prompt_template: str) - str: 单块摘要按模板拼接后调用LLM prompt prompt_template.replace({{输入文本}}, chunk) resp client.chat.completions.create( modelyour-model, messages[{role: user, content: prompt}], temperature0.3, ) return resp.choices[0].message.content.strip() def map_reduce_summarize(chunks, client, first_round_tpl, reduce_tpl): Map-Reduce式总摘要 partial_summaries [] for idx, chunk in enumerate(chunks): partial summarize_chunk(chunk, client, first_round_tpl) partial_summaries.append(f[片段{idx1}]\n{partial}) combined \n\n.join(partial_summaries) final_prompt reduce_tpl.replace({{分段摘要}}, combined) final_resp client.chat.completions.create( modelyour-model, messages[{role: user, content: final_prompt}], temperature0.2, ) return final_resp.choices[0].message.content.strip()第一轮Prompt和第二轮Prompt建议用两套模板不要共用。第一轮的侧重点是“从片段中提炼要点”第二轮的侧重点是“跨片段整合去重找出主线”。把职责分开最终摘要的结构会清楚很多。第一轮模板参考请阅读下面的文本片段提取出所有关键信息。 要求每条信息用一句话表达按重要程度排序只保留原文明确提到的内容。 文本片段 {{输入文本}}第二轮模板参考下面是一些文档片段的摘要请综合它们生成一份总摘要。 要求 1. 总摘要不超过300字 2. 合并重复要点删除细节性举例 3. 如果各片段对同一话题的描述存在差异保留最普遍的说法 4. 只基于给定的分段摘要不要补充原文之外的信息。 分段摘要 {{分段摘要}}3.2 为什么要按段落聚合而不是按字数硬切很多第一次做分块的同学会写一个简单逻辑每500个字切一刀。这么做虽然省事但很容易把一段完整的论述拦腰截断。比如文档里出现“这个问题有两个原因其一……其二……”如果切在“其二”之前第一块只有“其一”第二块只剩“其二”模型两边都看不到完整逻辑生成的摘要自然就会丢掉一半信息。按段落聚合能缓解这个问题。段落在大多数文本里本身就是最小的语义单元以段落为单位往块里装块与块之间的语义边界会更自然。如果段落实在太长再对单个段落做二次切分也不迟。重叠窗口的作用同样不可小觑。它是为了解决“切块边界上的信息断层”而设计的。两段内容之间往往存在承上启下的句子这些句子只保留在一个块里会让另一个块丢失语境。重叠窗口等于给模型多喂了一点“上一块的尾部信息”代价是多消耗一些Token但这个钱省不得。3.3 Token成本估算与并发控制文本概括在真实项目里的成本大头不在模型推理本身而在“反复调用”。每次调用都在生成Token中文文本的Token换算是很多新手容易估算错的点。一个大致经验中文每1个汉字约等于0.6到1个Token具体数值要看分词方式。按保守估算一篇5000字的纯中文文档文本本身就要消耗约4000到6000个Token再加上分块后的重叠和两轮调用的输出Token总消耗会明显上浮。所以做长文本概括时最好先对文本长度做个粗判再决定是否走Map-Reduce。如果文档只有2000字直接一次调用往往比分块后两次调用便宜一半以上只有超过上下文窗口舒适区时才需要考虑分块。并发控制也要提前想好。批量给一批PDF做摘要时如果循环里不加节流很容易触发模型服务的频率限制。稳妥的做法是使用信号量控制同时进行的请求数比如每次最多并发5个同时加上失败自动重试。重试时建议用指数退避而不是固定间隔否则负载高的时候依然可能会连续撞限。4. 实测中最容易翻车的三类问题幻觉、忠实性、风格漂移4.1 摘要幻觉模型编造了原文没有的内容我先投个票文本概括中最危险的问题不是“摘要质量差”而是“模型编造了看起来很像原文内容的信息”。因为质量差至少一眼能看出来幻觉往往是带着自信的语气输出错误结论如果没有对照原文读者可能直接采信。我实测时遇到过这样一个例子。原文是一篇关于存储系统性能调优的文章里面说“在高并发写入场景下延迟升高了15%”模型生成的摘要却写成了“系统存在严重性能瓶颈需要更换存储架构”。后半句是模型自己补的结论原文根本没提“严重瓶颈”和“更换架构”。这种摘要一旦被当作汇报材料误导性极强。幻觉的成因主要有三个模型过度补全、Prompt里给了太多先验暗示、以及模型把训练阶段学到的相似文档内容混进了生成结果。对应到规避手段上我总结了三条经验强制信息边界在Prompt里明确写“只使用原文中出现的信息”并加上一句“如果原文没有相关信息直接跳过不要补充”降低温度把生成温度调到0.2甚至0.1减少无关词汇的随机采样幻觉出现的频率会显著下降做摘要回读校验把生成的摘要重新喂给模型让它判断摘要里的每条结论在原文里是否能找到依据。这一步多消耗一次调用但能把一大批幻觉拦截在交付之前。4.2 关键信息丢失模型留了次要内容丢了主线结论另一个高频问题是“该丢的没丢该留的没留”。模型倾向于保留那些看起来“信息量密集”的句子而不是保留真正贯穿全文的主线。比如一篇项目复盘文档主线是“项目上线延期了20天原因是测试资源不足”但模型生成的摘要里反而把“会议讨论了三轮”这种过程性细节写进去了主线结论却模糊了。这个问题靠调Prompt措辞很难根治更有效的方式是在Prompt里明确“目标读者”和“摘要用途”。同一个文本写给管理层看的摘要和写给执行层看的摘要重点本来就不同。比如这样写请为“项目经理”总结下面文本的核心信息。 注意重点提炼影响进度、成本、风险的内容弱化日常讨论过程。让模型明确知道“为谁总结”比空泛地要求“提炼重点”有效得多。这也是为什么抽象概括任务必须先定义使用场景场景越具体模型选择信息的准确率越高。4.3 风格漂移技术文档被总结成了营销文案还有一种没被足够重视的问题风格漂移。当原文是一篇严谨的技术文档模型生成的摘要却出现了“极大地提升了”“显著优化了”这类带宣传色彩的表达或者反过来把一篇产品宣传稿总结得像说明书一样枯燥。风格漂移的根源在于模型预训练语料里各种风格都有你不指定风格它就按概率抽样。解法很简单在Prompt里规定语言风格并给一两个示例。比如“请使用中性客观的技术描述风格不要使用夸张形容词”。如果项目对风格要求很高建议准备两三个Few-Shot示例哪怕只是简短的一对“原文—摘要”样例都能把风格拉回正轨。注意如果你做的是金融、医疗等领域的摘要功能风格漂移不只是美观问题很可能是合规问题。摘要中“必须客观、不得夸大”这类约束最好直接写进系统提示词不能只依赖用户输入。4.4 长文本Map-Reduce带来的特殊坑用Map-Reduce做长文档概括时还有一个分布式系统里非常眼熟的问题第一轮每块摘要都在“局部视角”下生成块与块之间没有全局信息最终汇总可能会丢失跨块的主线。我在测试一篇多章节的研究报告时遇到过每个章节的片段摘要看起来都是对的但汇总之后整份摘要缺少了第一章里提出的核心观点因为第一章内容比较铺垫性在局部摘要阶段就被模型筛掉了。缓解思路是让第一轮Prompt带上“记录背景信息”的意识。也就是说分块摘要不要只追求“精简”还要保留每个块里与背景、目标、核心术语相关的信息。第二轮归并时再根据主题做压缩。另外如果原文档有目录或者小标题可以把结构信息单独拿出来先让模型基于目录生成一个文档框架再按框架去填充每个部分的内容。这种做法对超长结构化文档的效果比单纯Map-Reduce稳定得多。5. 怎么证明概括得好ROUGE指标与人工评估的实际取舍5.1 ROUGE指标能做什么不能做什么开发阶段需要一个自动化的方式来评估效果ROUGE是最常用的指标。它的核心思想是比较模型生成的摘要与人工参考摘要之间词级别的重合度。ROUGE-N看n-gram重合ROUGE-L看最长公共子序列的重合。数值越高说明生成摘要与参考摘要越接近。ROUGE适合做回归测试和批量验证改了一版Prompt之后同一批测试文档上的ROUGE分数变化趋势能帮你快速判断这版改动是变好还是变差。但它的问题也很明显——它对“用词不同但语义相同”的摘要完全无能为力。模型可能用完全不同的表达提炼了同样几个核心观点ROUGE分数依然很低。所以ROUGE只能当“底线指标”不能当“质量指标”。5.2 更靠谱的评估方式分层评估维度把质量评估拆成几个独立维度是比一个综合评分更合理的方式。我在实际项目里常用五维度评分忠实性摘要中的每条信息是否都能在原文找到依据相关性摘要是否覆盖了任务真正需要的重点流畅性语句是否自然连贯没有因果断裂简洁性信息密度是否足够有没有冗余可控性是否遵循了字数、格式、风格等约束。每个维度按1到5打分汇总后就能直观看出一个摘要系统的问题出在哪个环节。如果“忠实性”长期低分优先处理幻觉相关策略如果“相关性”很低问题大概率出在场景定义不够清晰如果“简洁性”不足可以调高第二轮归并时的压缩力度。5.3 上线前的人工抽检自动化指标和人工评估的关系我的建议是“自动化跑全量人工看样本”。开发阶段用ROUGE辅助调参验收阶段让人工抽检至少30条覆盖不同来源、不同长度的结果。这个抽检不是为了找茬而是为了发现自动化指标发现不了的问题比如摘要是否让人读起来舒服、结构是否清晰。我在某个内部工具上做验收时请了三个不参与开发的同事分别对每篇摘要做“是否能直接对外使用”的判断结果发现有一类问题之前完全没注意到摘要中使用了一连串指代不明的代词比如“该方案”“此观点”在脱离了完整上下文之后很难对应到具体对象。这是LLM做多轮压缩时很常见的问题Prompt里加一句“摘要必须能在没有原文的情况下独立理解避免使用悬空的代词”就能大幅改善。所以文本概括的评估不是一次性的动作而是一个持续建立“样本集、指标集、纠偏手段”的循环。哪怕模型升级了Sample集也得定期补充新的文档类型否则评估结果很难反映真实使用情况。写在最后的一点实操体会课时7的内容到这基本算是复盘完了但我还是想多说一句文本概括最核心的能力不是模型而是“任务拆解”。同样是“概括”两个字放在单文档、超长文档、多文档三个场景里做法完全不同同样是“输出摘要”给管理层、给执行层、给外部客户重点也完全不同。搭Pipeline之前先把这些问题想清楚能省掉后面大量的返工。另外一个小技巧分享一下我在处理会议纪要类的概括任务时会先让模型按时间戳把内容切成分段再分别提炼每个时间段的结论。第一次切分时用“按发言段落划分”第二次才做语义概括效果比直接全场概括好很多。原理和分块策略一样先把复杂文本拆成边界清晰的片段模型在每一个局部更容易找到关键信息。这个办法不止适用于会议纪要凡是时间线、事件线清晰的文本都可以借鉴。