☰
上下文工程实战:从检索到组装,让AI输出更精准
2026/10/16 7:51:41 网站建设 项目流程

1. 为什么“喂对信息”比“换个模型”更管用

这两年跟不少做AI应用的朋友聊,发现一个特别普遍的现象:模型一换再换,从这家换到那家,参数从7B一路加到几百B,结果业务效果该拉胯还是拉胯。钱花了不少,延迟还上去了。问题出在哪?十有八九不是模型不行,是喂给模型的东西不对。

“上下文工程”这个词最近被提得越来越多,说白了就是一门“让AI看到该看的东西”的手艺。它研究的不是怎么训练模型,而是怎么在推理阶段,把最相关、最精炼、最结构化的信息塞进那个有限的上下文窗口里。你可以把大模型想象成一个能力极强但记性有限的顾问——他聪明是真聪明,但你每次只能给他看几页纸,给错了,他再聪明也只能瞎猜。

这个内容适合谁看?如果你正在做RAG问答、智能客服、代码助手、文档分析这类应用,或者你只是单纯觉得“我明明把资料给它了,它怎么还是答非所问”,那这篇就是写给你的。我不打算讲一堆论文里的公式,而是把我在实际项目里踩过的坑、试出来的参数、以及那些文档里不会写的经验,一条条摊开来说。核心就一句话:上下文的质量,直接决定AI输出的上限,模型只是把这个上限兑现出来而已。

2. 上下文工程到底在解决什么问题

2.1 上下文窗口不是越大越好

很多人有个误区:既然模型支持128K甚至更长的上下文,那我就把整本手册、整个知识库全塞进去不就完了?实测下来,这么干通常有三个后果。第一,成本飙升,token是按量计费的,你塞十万token进去,每次调用都是真金白银。第二,延迟爆炸,长上下文的首token延迟能到好几秒,用户体验直接崩。第三,也是最反直觉的——信息越多,模型反而越容易抓不住重点。

这背后有个叫“迷失在中间”(Lost in the Middle)的现象:模型对上下文开头和结尾的信息记得比较牢,中间那一大段容易被忽略。你把关键答案埋在第五千字的位置,模型很可能视而不见。所以上下文工程的第一性原则不是“塞满”,而是“精选”。窗口大是给你留余地的,不是让你挥霍的。

2.2 上下文工程的四个核心动作

我把整个流程拆成四个动作,后面每个章节都会围绕它们展开。

  • 检索:从海量资料里把可能相关的内容捞出来。这一步决定了召回率,捞漏了后面全白搭。
  • 筛选与重排:捞出来的一堆里,哪些是真相关?按相关度排序,把最该看的放前面。
  • 压缩与结构化:把长文档压成要点,把散乱信息整理成模型好理解的格式。
  • 组装与预算分配:在有限的token预算里,决定系统提示、历史对话、检索内容、用户问题各占多少。

这四个动作环环相扣。我见过太多项目只做了第一步检索,后面三步全靠模型“自由发挥”,效果自然不稳定。下面逐个拆。

3. 检索环节:先把该捞的捞回来

3.1 分块策略决定了检索的天花板

检索的第一步是分块(Chunking)。文档不能整篇丢进去检索,得切成小块。切多大?这是第一个要命的参数。

切太小,比如按句切,每块只有一两句话,语义不完整,检索出来断章取义。切太大,比如按整章切,一块几千字,检索精度下降,还浪费token。我的经验值是300到800个token一块,块与块之间保留10%到20%的重叠。重叠是为了防止一个完整的语义被硬生生切断——比如一个答案跨在两块交界处,没有重叠就两边都捞不全。

但这不是死规矩。技术文档、法律条文这种结构清晰的,可以按标题层级切,一块就是一个完整小节。聊天记录、会议纪要这种口语化的,按对话轮次或时间窗口切更合适。我做过一个客服知识库的项目,最初按固定长度切,效果一般;后来改成按“问题-答案”对切,每块就是一个完整的FAQ,召回准确率直接上了一个台阶。分块的本质是让每一块都成为一个语义自洽的最小单元,这个原则比具体数字重要得多。

3.2 向量检索不是万能药

现在一提检索就是向量数据库,好像embedding一算就万事大吉。但纯向量检索有个硬伤:它擅长语义相似,不擅长精确匹配。用户问“订单号A12345的状态”,向量检索可能给你返回一堆讲“订单状态查询流程”的文档,就是找不到那个具体订单号。因为数字和专有名词在向量空间里区分度很低。

所以成熟的做法是混合检索:向量检索负责语义召回,关键词检索(比如BM25)负责精确匹配,两路结果合并后再重排。我一般会给关键词检索留30%左右的权重,具体看场景。如果用户query里经常出现编号、型号、人名这类实体,关键词那一路的权重还得往上调。

提示:混合检索的融合方式有两种,一种是加权求和,一种是倒数排名融合(RRF)。RRF对两路分数尺度不一致的情况更鲁棒,我一般优先用它,省得去调权重。

3.3 查询改写:别拿用户的原话直接去搜

用户的问题往往很口语、很模糊。“那个东西怎么弄来着”——你拿这句话去检索,神仙也捞不出对的。查询改写就是先把用户问题“翻译”成适合检索的形式。

常见的手法有三种。一是扩展:把“怎么退款”扩展成“退款流程、退款条件、退款到账时间”。二是分解:把“A和B有什么区别”拆成“A是什么”和“B是什么”两个子查询分别检索。三是假设文档生成:先让模型根据问题编一个“理想答案”,再拿这个答案去检索,因为答案和真实文档的语义更接近。这招在学术检索里效果很好,但会多一次模型调用,延迟敏感的场景要权衡。

我实测下来,查询改写对召回率的提升通常在10到25个百分点之间,是性价比极高的一步。但要注意别改过头,把用户的原始意图改没了。稳妥的做法是原始query和改写query都去检索,结果合并。

4. 筛选与重排:把最该看的排到最前面

4.1 重排模型是精度的守门员

检索捞回来比如20条,但上下文预算只够放5条。放哪5条?这就轮到重排(Rerank)出场了。向量检索用的是双塔结构,query和文档分别编码,速度快但精度有限。重排模型用的是交叉编码,把query和文档拼在一起过一遍模型,精度高得多,但慢,所以只适合对少量候选做精排。

我的标准流程是:向量+关键词混合检索召回50条,重排模型精排出前5到8条,再进上下文。重排这一步能把最相关的顶上来,实测对最终答案准确率的贡献非常明显。选重排模型时,别只看榜单分数,要看它在你的领域数据上的表现。通用榜单第一的模型,在你的垂直领域未必最好。

4.2 去重和多样性不能忘

重排之后还有个容易被忽略的步骤:去重。检索回来的内容经常高度重复,五条文档讲的是同一件事。全塞进去既浪费预算,又会让模型误以为这件事特别重要。我一般用语义相似度做去重,相似度超过0.9的只保留分数最高的那条。

另一个是多样性。有时候答案需要综合多个方面,如果检索结果全集中在某一个角度,模型就会答偏。可以用最大边际相关(MMR)这类算法,在相关性和多样性之间找平衡。简单说就是:选第一条要最相关,选第二条要既相关又和第一条不太一样,以此类推。

4.3 元数据过滤:用结构化信息砍掉噪音

很多文档自带元数据——时间、来源、类型、权限。这些信息在检索时是极好的过滤器。比如用户问“最新的政策”,你就该按时间倒序,把过期的直接过滤掉。用户问“技术方案”,你就该把会议纪要、闲聊记录排除在外。

我习惯在入库时就把元数据抽好、打好标签,检索时先做一轮硬过滤,再做语义检索。这样能大幅缩小检索范围,既提精度又降延迟。别小看这一步,很多项目效果差就是因为把一堆不相关的文档也扔进了检索池。

5. 压缩与结构化:让模型读得懂、读得快

5.1 上下文压缩的三种思路

检索回来的文档往往很长,直接塞进去占预算。压缩就是把它变短,但保留关键信息。三种思路,各有适用场景。

第一种是抽取式压缩:从原文里挑出最相关的句子,其余丢掉。优点是保真,不会引入错误;缺点是可能不连贯。适合事实性问答。

第二种是生成式压缩:让模型把长文档改写成简短摘要。优点是流畅连贯;缺点是有引入幻觉的风险,摘要可能偏离原意。适合需要综合理解的场景。

第三种是结构化压缩:把非结构化文本转成表格、列表、键值对。比如把一段产品介绍压成“型号/价格/参数”三行。模型对结构化信息的理解效率远高于大段散文。我特别推荐这一种,尤其在信息本身就有结构的时候。

注意:压缩是有损的,压得太狠会丢关键细节。我的做法是保留原文的引用锚点,模型如果觉得摘要不够,可以顺着锚点去取原文。这样兼顾了效率和完整性。

5.2 提示词的结构化组装

上下文不只是检索内容,还包括系统提示、对话历史、用户问题。这些部分怎么排布,直接影响模型表现。

我的默认排布顺序是:系统指令放最前,然后是检索到的参考资料,接着是对话历史,最后是用户当前问题。为什么这么排?因为模型对开头和结尾最敏感。系统指令是“宪法”,必须放开头让它时刻遵守;用户问题是“当前任务”,放结尾让它立刻响应;参考资料夹在中间,作为依据。

参考资料内部也要标清楚。我习惯给每条资料编号,并注明来源,让模型引用时能对上号。格式上,用清晰的分隔符把不同部分隔开,别让模型分不清哪是资料哪是指令。这一点在防提示注入时也特别重要——用户输入里如果混了“忽略以上指令”这种话,清晰的分隔能降低被带偏的风险。

5.3 token预算怎么分

这是最实操的一环。假设你的模型上下文窗口是8K token,怎么分?

部分建议占比说明
系统指令10%到15%固定不变,可缓存
对话历史20%到30%只保留最近几轮,老的做摘要
检索资料40%到50%核心依据,按重排顺序放
用户问题5%到10%通常很短
输出预留10%到15%给模型生成答案留空间

这个比例不是死的。如果任务复杂、需要多轮推理,对话历史可以多留;如果是单轮问答,检索资料可以多占。关键是心里要有这本账,别让某一部分悄悄吃掉了预算。我见过系统提示写了三千字的项目,检索资料根本没地方放,效果能好才怪。

6. 实操过程:从零搭一条上下文流水线

6.1 整体架构与数据流

我把整条流水线画成一条数据流,方便你对照自己的项目。

用户提问进来,先做查询改写,得到原始query和改写query。两路query分别走向量检索和关键词检索,各召回一批候选。候选合并后做去重,再送进重排模型精排。精排后的top结果做压缩和结构化处理。同时,对话历史做滚动摘要,只保留最近几轮原文加更早的摘要。最后,系统指令、压缩后的资料、历史摘要、用户问题按预算组装成最终prompt,送进模型。

这条链路里,每一步都有可调参数。下面挑几个关键的说。

6.2 关键参数的计算与选择

分块大小:我一般从500 token起步,重叠100 token。然后拿一批真实问题去测召回率,如果发现答案经常跨块,就加大重叠;如果检索噪音多,就减小块大小。

召回数量:混合检索每路召回20到30条,合并后去重,通常剩30到50条进重排。召回太少会漏,太多重排压力大。这个数要结合你的重排模型吞吐来定。

重排保留数:进上下文的资料条数,我一般控制在5到8条。太少信息不足,太多稀释注意力。如果单条资料很短,可以适当多放几条。

历史轮数:保留最近3到5轮原文,更早的做摘要。摘要长度控制在200字以内。这样既保留了上下文连贯性,又不至于挤占资料空间。

这些数字都是起点,不是终点。每个项目的数据分布不同,必须用真实数据去调。我习惯建一个小评测集,几十条问题加标准答案,每次调参跑一遍,看准确率变化。没有评测集就调参,等于闭着眼睛开车。

6.3 一个可复现的组装示例

下面是一个组装后的prompt长什么样,我用伪代码示意结构,你可以直接套。

[系统指令] 你是一个严谨的问答助手。只依据下方【参考资料】回答, 资料中没有的信息,明确说“资料未提及”,不要编造。 回答时用[编号]标注依据来源。 [参考资料] [1] 来源:产品手册v2.3 退款需在签收后7天内发起,到账时间为3到5个工作日。 [2] 来源:客服FAQ 退款申请入口在“我的订单”页面,点击对应订单的“申请退款”。 [3] 来源:财务说明 退款原路返回,若原支付方式失效,需联系客服人工处理。 [对话历史摘要] 用户此前询问过订单A12345的物流状态,已告知预计明日送达。 [用户问题] 那这个订单怎么退款?

这个结构里,系统指令明确了边界和引用要求,参考资料带编号和来源,历史做了摘要,用户问题在最后。模型拿到这样的输入,基本不会跑偏。你可以把这段直接改成你项目里的模板。

7. 常见问题与排查技巧实录

7.1 效果不稳定的排查顺序

效果时好时坏,先别急着换模型。按这个顺序查:先看检索,把每次实际进上下文的资料打出来看,是不是该有的没检索到,或者检索到一堆不相关的。再看重排,是不是把最相关的排到了后面。然后看压缩,是不是把关键信息压没了。最后才看模型和提示词。八成的问题出在前三步,模型背了很多不该背的锅。

7.2 常见问题速查表

现象可能原因排查动作
答非所问检索没召回对的资料检查分块和查询改写
答案不完整资料被截断或压缩过度检查分块重叠和压缩比例
引用错乱资料编号不清或来源缺失检查组装格式
忽略中间资料关键信息埋在中间把最相关的排到最前
重复啰嗦检索结果高度重复加去重步骤
编造信息资料不足但没约束强化系统指令的边界
响应慢上下文太长或重排太多压缩上下文,减少重排候选
成本高token浪费在无关内容做元数据过滤和压缩

7.3 几个文档里不会写的坑

第一个坑:别用同一个embedding模型做检索和重排。有些团队图省事,检索和重排用同一个模型,效果打折。重排要用专门的交叉编码模型,这是两码事。

第二个坑:对话历史别无限累积。我见过一个项目,把用户所有历史对话都塞进去,跑到后面上下文全是历史,资料没地方放。历史一定要做滚动摘要,老的压掉。

第三个坑:系统指令别写太长。有人把系统指令写成一篇小作文,几千字,结果模型光读指令就累了,还挤占资料空间。系统指令要精炼,把最关键的约束说清楚就行,细节靠资料补充。

第四个坑:评测集要覆盖边界情况。只测常见问题,调出来的参数在边界情况上会翻车。要专门准备一批“资料里没有答案”“问题很模糊”“需要综合多条资料”的测试用例。

第五个坑:缓存能省大钱。系统指令和固定资料这部分,很多模型支持提示缓存,重复调用时这部分不计费或打折。把不变的内容放前面,能显著降成本。这个细节很多人不知道,白白多花钱。

8. 上下文工程的边界与取舍

做久了会发现,上下文工程不是越复杂越好。每加一个环节,就多一份延迟和一份出错的可能。小项目、简单问答,可能分块加向量检索就够了,硬上重排和压缩反而拖慢响应。大项目、复杂推理,才值得把整条流水线搭起来。

我的判断标准是:先跑通最简版本,用评测集量化效果,再针对短板加环节。短板在召回就加查询改写和混合检索,短板在精度就加重排,短板在成本就加压缩和缓存。每一步都要有数据支撑,别凭感觉堆技术。

还有一点,上下文工程和模型能力是互补的。模型本身推理能力越强,对上下文的容错就越高,你的工程压力就越小。所以选模型时,别只看价格,要看它在你的任务上“读懂上下文”的能力。有些模型便宜但需要你把上下文喂得特别干净,综合算下来未必划算。

最后分享一个我常用的自检习惯:每次线上出问题,第一件事就是把那次请求的完整上下文dump出来,从头到尾读一遍。十次里有八次,读完就找到原因了——要么资料没进去,要么进去的是错的,要么格式乱得模型没法读。上下文工程说到底就是个体力活加细心活,把每一次“喂进去的东西”都当回事,效果自然就稳了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询