每周一道 Agent 面试题:现在市面上的 Embedding Model 怎么选择(3)——输入越长越好吗,模型与 chunk 应该怎样配合
开场
前两篇完成了候选筛选和业务评测。接下来要讨论的是:Embedding Model 支持的输入越长,chunk 是不是也应该切得越长?
很多模型会把最大输入长度写在显眼位置。看到 8K、16K 甚至更长的输入上限,很容易产生一个直觉:模型能处理更多文本,给它更完整的内容,检索效果应该更好。
实际效果未必如此。假设一份员工手册包含差旅申请、交通标准、住宿标准、例外审批和报销流程。把整章内容放进一个长 chunk,确实能避免切分破坏上下文。但用户问“特殊地区住宿费能否上浮”时,这个向量同时编码了大量无关内容,真正关键的“特殊地区”和“上浮条件”只占很小一部分。
如果把住宿标准和特殊地区规则单独切成一个较短的 chunk,语义可能更集中,也更容易与查询对齐。
模型的最大输入长度回答“最多能放多少”,chunk 设计回答“放多少更适合检索”。两者相关,但不能混为一谈。
1、先区分最大输入长度与有效输入长度
讨论输入长度时,需要先区分两个概念:最大输入长度和有效输入长度。
最大输入长度是模型的技术上限,表示模型一次最多能够接收多少 token。超过这个长度后,输入可能被截断、报错,或者由 SDK 按预设规则处理。它回答的是:“这段文本能不能完整送进模型?”
有效输入长度不是模型厂商统一公布的固定参数,而是一个与具体任务有关的工程概念。它表示在当前文档和检索场景中,一段文本被压缩成向量后,模型仍能较好保留关键语义,并与相关查询稳定对齐的长度范围。它回答的是:“这段文本虽然能送进模型,但生成的向量还能不能有效表达其中的关键信息?”
因此,输入未超过最大长度,不代表它一定处于有效长度范围内。
Embedding Model 通常会把一段文本压缩成固定维度的向量。无论输入是一句话还是几千 token,输出向量通常仍是 768、1024 等固定维度。文本越长,同一个向量需要承载的主题、实体和关系就越多。
如果长文本始终围绕一个稳定主题展开,增加上下文可能有助于补充条件和关系;如果其中包含多个相互独立的主题,向量就会混合这些语义。当查询只对应其中一小部分时,关键内容在整个向量中的区分度可能下降,相似度和排名也会受到影响。
所以,评估输入长度要分成两个层次:先检查文本是否超过最大输入长度而被截断,再检查未超过上限的文本是否因过长导致核心语义被稀释。
2、先检查是否发生硬截断
假设模型最多接收 512 token,而系统中的 chunk 经常达到 800 token。如果 SDK 默认保留前 512 token,后面的内容不会参与向量计算。问题答案恰好位于 chunk 尾部时,在原文和切分结果中都能看到答案,向量中却没有这部分信息。
排查时不能只看字符数。不同模型使用不同 tokenizer,中文、英文、代码和特殊符号的 token 计算方式不同。同样长度的字符串,实际 token 数可能差别很大。
至少要确认:
- 模型文档声明的最大 token 数;
- SDK 是否自动截断;
- 截断发生在头部、尾部还是按其他规则处理;
- 是否会返回警告或错误;
- 查询和文档是否使用相同长度限制;
- 当前 chunk 的平均、P95 和最大 token 数。
只看平均长度说明不了问题。即使大多数 chunk 很短,少量表格或长段落超出上限,也可能导致相关内容持续漏检。
可以在编码前记录 token 数,统计超过阈值的 chunk,并抽查这些 chunk 中的答案是否位于被截断区域。这个检查比直接换模型更快,也更容易确认根因。
3、再检查长文本是否稀释核心语义
排除硬截断后,还要判断 chunk 是否因为包含过多主题,降低了核心语义的区分度。这里的“语义稀释”不是某段内容完全消失,而是多个主题、实体和条件被压进同一个向量后,模型更容易表达整体主题,却不容易突出其中的局部规则。
例如,一个 chunk 同时包含差旅申请、交通标准、住宿上限、特殊地区补贴、票据要求和异常审批。用户询问“公司差旅有哪些规定”时,这个长片段可能很合适,因为问题本身比较宽泛。但用户询问“高原地区住宿标准能否上浮”时,检索需要对齐的是“高原地区”“住宿标准”和“上浮条件”,而不是宽泛的“差旅”主题。
此时,长 chunk 可能因为包含“员工、差旅、费用、审批”等高频内容而显得相关,却无法突出真正决定答案的条件。另一个只保留住宿标准、特殊地区范围和上浮规则的片段,内容更少,但查询与证据的对应关系更直接,正确结果的排名可能更稳定。
可以先收集一组“正确答案确实存在于 chunk 中,但排名持续靠后”的问题,再检查排在前面的结果。如果这些结果都与查询属于同一大类,却没有包含具体条件,问题可能不在于模型不理解主题,而在于长片段把多个相近规则混在了一起。
排查时应固定模型、查询文本和检索参数,只调整 chunk。可以按规则边界拆分原始片段,并确保每个新片段保留必要的标题、适用对象、条件和结论。例如,不要只留下“可以上浮”,而应保留“高原等特殊地区的住宿标准经过审批后可以上浮”。然后重点比较:
- 正确证据能否从 Top 10 进入更靠前的位置;
- 具体条件类问题的排名是否更稳定;
- 宽泛主题类问题是否因为切分过细而下降;
- 返回结果是否被多个内容相近的短片段占满。
如果缩短 chunk 后,细粒度问题明显改善,而宽泛问题基本不受影响,可以认为原片段存在语义稀释。如果拆分后仍然无法区分相近规则,则要继续检查查询表达、模型接入方式或模型本身的区分能力。如果正确片段排名提高后却缺少回答问题所需的前置条件,说明切分过细,需要补回必要的上下文。
因此,长文本本身不是问题,多个独立语义被放进同一个片段才是问题。chunk 的判断标准不应是固定 token 数,而是它能否独立表达一个完整、集中且可用于回答问题的语义单元。
4、查询和文档的长度通常不对称
用户查询往往只有十几个字,文档 chunk 却可能包含几百个 token。检索时,模型需要把一个简短问题与长文本中的局部语义对齐。
查询越短,表达的信息越少,歧义也可能越大。例如“报销标准”可能指差旅、餐饮、通信或采购。文档 chunk 如果同时包含多个主题,模型可能只根据“报销”“费用”等宽泛词语判断相关性,无法定位用户真正关心的规则。
可以从两个方向改进。
一是让 chunk 更聚焦。保留理解内容所需的标题、适用对象和前置条件,但不要把多个相互独立的规则放进同一个片段。这样即使查询较短,也能减少同主题内容之间的干扰。
二是结合会话上下文改写查询,补全省略的信息。改写的目的不是替用户增加新条件,而是把上下文中已经明确的信息带回当前问题。可以使用下面这个简单提示词:
根据会话上下文,将用户当前的问题改写成一条能够独立用于文档检索的查询。保留用户原意,只补充上下文中已经明确的信息,不推测或添加新的条件。如果当前问题已经完整,直接返回原问题。只输出改写后的查询。
例如:
会话上下文:用户正在咨询员工国内差旅的住宿费用。
当前问题:报销标准是多少?
改写结果:员工国内差旅住宿费用的报销标准是多少?
如果上下文没有说明费用类型,就不能直接补成“住宿费用”,否则查询改写会引入用户没有表达的条件。实际使用时还要保留原始查询,分别测试原查询和改写查询的检索结果,避免改写后的表达偏离用户意图。
有些模型还要求查询和文档使用不同的前缀或任务指令。例如,查询侧需要标记为检索问题,文档侧需要标记为候选内容。如果接入方式不正确,模型对两类输入的区分可能受到影响,其表现也容易被误判为 chunk 过长或查询过短。因此,开始长度实验前,应先确认输入格式符合模型要求。
5、chunk 应该按什么边界切
固定字符数切分实现简单,却不一定符合文档结构。
制度文档更适合按标题、条款和列表切分,产品手册可以按功能模块和操作步骤切分,表格则要尽量保留表头、行列关系和所属章节。
一个好的 chunk 通常具备三个特点:
- 能够独立表达一个相对完整的含义;
- 包含理解该内容所需的标题和必要条件;
- 不混入过多与当前主题无关的信息。
这三个目标会互相牵制。片段太短,条件和结论可能被拆开;片段太长,核心语义可能被稀释。overlap 能缓解边界问题,但代替不了合理结构。overlap 设得太大,还会生成大量重复片段,让相似内容占据候选结果。
6、标题、路径和元数据要不要放进文本
很多 chunk 一旦脱离上下文,就看不出它属于什么主题。
例如,正文只有“经理批准后可以执行”,如果没有“特殊差旅审批流程”这个标题,向量很难表达完整含义。把文档标题、章节标题或路径加入 chunk,往往能让语义更完整。
但标题信息也不能堆得太多。每个片段都加入很长的企业名称、文档名称和多层路径,可能让这些重复词主导向量。
可以测试以下方案:
- 只编码正文;
- 编码章节标题和正文;
- 编码文档标题、章节标题和正文;
- 标题进入向量文本,其他信息保留为元数据;
- 查询时先使用元数据过滤,再做向量检索。
不同文档类型适合的方案可能不同。制度条款通常需要标题补充上下文,较短的产品 FAQ 可能不需要额外拼接。
7、表格为什么特别容易出问题
表格的含义不只来自单元格中的文字,还依赖表名、表头、行列位置、单位以及单元格之间的对应关系。普通段落即使去掉排版,大部分语义仍然存在;表格一旦被简单地展开成连续文本,内容虽然没有丢失,原来的关系却可能已经无法还原。
例如:
| 人员类型 | 交通标准 | 住宿上限 |
|---|---|---|
| 普通员工 | 高铁二等座 | 500 元 |
| 管理人员 | 高铁一等座 | 800 元 |
如果解析结果只是:
普通员工 高铁二等座 500 元 管理人员 高铁一等座 800 元
模型能够识别“普通员工”“管理人员”“500 元”和“800 元”,但未必能稳定判断哪个金额属于哪类人员。用户询问“普通员工住宿上限是多少”时,两个金额都出现在同一个片段中,向量检索可能只能判断它与“员工住宿标准”相关,却无法准确表达行与列之间的关系。
表格在解析和切分过程中,常见问题有以下几类。
第一,表头与数据行分离。解析程序可能只保留单元格内容,或者切分时把表头放进上一个 chunk,把数据行放进下一个 chunk。此时“500 元”仍然存在,但模型不知道它表示住宿上限、交通补贴还是其他费用。
第二,多级表头和合并单元格展开后,原本的继承关系可能丢失。例如,“国内差旅”下面还有“交通标准”和“住宿标准”两个子列,解析后如果只保留第二级表头,模型可能不知道这些字段的适用范围。纵向合并的“普通员工”如果只在第一行出现,后续空白行也可能无法继承人员类型。
第三,数值与单位、条件分开。单独的金额、比例和天数往往含义不完整。“500”可能表示元、公里或人数;“上浮 20%”还需要知道适用地区、审批条件和计算基准。如果单位写在表头中,条件写在表格下方的备注中,简单按行切分就可能只保留数值。
第四,备注和例外规则被忽略。表格主体可能写“住宿上限 500 元”,表格下方又注明“高原等特殊地区经审批后可以上浮”。如果数据行与备注进入不同 chunk,用户查询特殊地区标准时,系统可能只召回基础金额,遗漏真正决定答案的例外条件。
第五,整张表被放进一个长 chunk。这样可以保留完整结构,但表格较大时,同一片段中会出现大量相似的人员类别、字段和数值。模型容易识别表格的整体主题,却难以突出某一行的具体条件,还可能触发前面提到的硬截断和语义稀释。
简单表格可以按行转成完整语句,并为每行补充表名和表头。例如:
员工国内差旅标准:普通员工可乘坐高铁二等座,住宿上限为 500 元。
员工国内差旅标准:管理人员可乘坐高铁一等座,住宿上限为 800 元。
复杂表格不一定适合逐行拆分。某些规则需要跨行比较,或者依赖多级表头和统一备注,可以按人员类型、地区或费用类别分组。每个分组都应保留表名、相关表头、单位、适用条件和必要备注,同时把原始表格位置保存在元数据中,方便后续定位和展示。
检查表格解析效果时,不能只确认文字有没有被提取出来,还要用具体问题验证回答所需的人员、字段、条件、单位和值是否出现在同一个 chunk 中。例如,查询“普通员工在特殊地区的住宿上限能否上浮”时,对应片段至少要同时包含人员类型、住宿上限、特殊地区和上浮条件。任一关系在解析或切分时断开,表格内容看似完整,检索仍然可能失败。
8、怎样设计模型与 chunk 的组合实验
初次比较模型时,为了控制变量,应固定 chunk,只替换模型。完成模型初筛后,再进入模型与 chunk 的组合实验,以免模型和切分方案同时变化,无法判断效果来自哪里。
组合实验不需要覆盖大量方案。可以选择两到三个候选模型,为每个模型准备少量有代表性的切分方式。例如,分别测试 256 token 配合较小 overlap、512 token 配合中等 overlap、保留标题的结构化切分,以及适合完整定义或连续条款的较长片段。具体参数应根据文档结构设置,不必为了增加实验数量随意组合。
可以把实验结果整理成二维表格,让每个模型分别测试每种 chunk 方案。除了比较整体 Recall@K 和 MRR,还要按问题类型观察结果。细粒度条件问题、宽泛主题问题和依赖完整上下文的问题,对 chunk 长度的要求可能不同,只看一个整体分数容易掩盖局部变化。
实验首先要确认模型是否因为输入上限发生截断,再观察缩短 chunk 后,细粒度条件的检索排名是否提高,以及较长片段是否更适合需要完整上下文的问题。还要检查加入标题后片段语义是否更明确、overlap 增加后是否出现过多重复结果,以及不同方案对向量数量、索引规模和编码成本的影响。
不要一次测试几十种组合。更稳妥的做法是先根据文档类型和已有失败案例提出少量方案,再用代表性测试集验证。这样既能控制实验成本,也更容易解释每次调整带来的变化。
9、一个具体排查案例
用户问:“试用期员工出差是否可以乘坐高铁一等座?”系统返回正式员工标准。
先看原文,确认表格中确实有针对试用期员工的限制;再看解析文本,确认对应行没有丢失。检查 chunk 后发现,人员类型和交通标准被切到了两个片段里,任何一个向量都没有完整表达这条规则。
调整切分后,把表头、人员类型和交通标准放进同一片段,正确证据开始出现在 Top 10,但排名仍不稳定。继续删减片段中的无关内容后,正确证据进入 Top 3。
这个案例没有更换模型,效果仍有明显改善,因为原来的语义单元不完整。
反过来,如果多个合理 chunk 方案都无法让模型区分“试用期员工”和“正式员工”,而其他候选模型可以稳定区分,才有更充分的理由更换模型。
10、面试时怎样回答“输入越长越好吗”
面试时可以这样回答:
不一定。最大输入长度只是模型能够接收的上限。chunk 超过上限会被截断;即使未超过上限,片段包含多个主题时也可能稀释核心语义。选型时我会先固定 chunk 比较模型,再选择少量候选模型与不同 chunk 方案做组合实验,同时观察召回、排名、重复结果、索引规模和编码成本。
这段回答同时交代了技术限制、检索效果和实验方法,比只说“长文本会稀释语义”更具体。
11、chunk 调整还会带来哪些工程影响
chunk 变小后,单个片段包含的 token 数会下降,但总 chunk 数量和需要生成的向量数量通常会上升。chunk 变大时,向量数量可能减少,单次编码的文本却会更长,关键语义也可能被稀释。因此,比较不同切分方案时,除了记录平均和 P95 token 数,还要同时观察总 chunk 数量和向量数量,才能判断调整对数据规模的实际影响。
数据规模变化会继续影响索引构建。向量数量增加后,全量编码耗时、索引文件大小和内存占用都可能上升。即使新的切分方案改善了召回效果,如果全量文档重新编码需要较长时间,或者索引规模超出当前资源范围,也未必适合直接上线。这些工程指标需要与 Recall@K、MRR 等检索指标一起比较。
查询阶段也会受到影响。chunk 越小,同一段原文可能被拆成多个内容相近的片段,单次查询返回的重复结果可能增加,进入重排阶段的文本总量也会随之变化。如果多个候选片段反复表达相同内容,最终上下文虽然占用了更多 token,真正用于回答问题的有效信息比例却可能下降。因此,实验中还要检查候选结果的重复片段比例、重排阶段处理的文本总量,以及最终上下文中有效信息所占的比例。
例如,chunk 从 512 token 缩短到 256 token 后,Recall@5 可能提高,但向量数量可能接近翻倍。系统文档规模较大时,编码、存储和重排成本也会明显增加。这时可以尝试结构化切分,减少不必要的 overlap,避免为了缩短 chunk 生成大量重复片段,再根据检索质量和工程成本选择折中方案。
切分规则改变还会影响文档更新和上线迁移。通常需要重新切分文档并生成全部向量,不能只替换一项配置。上线前应估算全量重新编码、索引构建和数据切换所需的时间,并将这部分成本纳入方案比较,而不是只看离线评测分数。
12、这一问题中最常见的误区
模型输入上限经常被直接当成推荐 chunk 长度。两者含义不同:上限只说明不能超过多少,并没有告诉你最佳长度。
另一种省事的做法,是让所有文档共用一套切分规则。制度、表格、FAQ、代码和产品手册的结构差别很大,可以采用不同策略,但评测结果和索引元数据必须能够追踪来源。
overlap 也不是越大越好。重叠过多会让相似片段占据候选结果,既降低结果多样性,也增加索引成本。
只看召回同样不够。短 chunk 可能更容易命中,却缺少必要条件,生成模型拿到后仍然无法回答。
还有一种归因错误:模型和 chunk 同时变化,效果提高后就直接归因于其中一项调整。更稳妥的顺序是先固定 chunk 比较模型,再对少量候选做组合实验。
目标不是找出一个适用于所有文档的统一数字,而是在语义完整、检索区分度和工程成本之间取得平衡。
13、面对不同文档类型时怎样快速判断
FAQ 的单条问答通常已经比较完整,可以直接作为 chunk,不需要很大的 overlap。制度文档更依赖上下文,应保留标题、适用对象、条件和例外;条款过长时,再按语义段落拆分。
产品手册适合按功能模块、操作步骤和故障场景切分,避免把概述、配置和排障混在一个片段中。代码与 API 文档则要尽量保持函数、参数、返回值和示例之间的关系,按字符数硬切很容易破坏结构。
表格可以转成带表头的行级文本,或按逻辑分组处理,同时把原始位置保存在元数据里。
这些只是初始假设,仍然需要通过业务问题验证。文档结构决定初始切分方向,测试集用来验证这种切分是否真的提高了检索质量。
下篇预告
模型与 chunk 已经调整,检索效果仍然不好,下一步应该做什么?是继续换一个更强的通用模型,还是直接准备微调数据?
下一篇会讨论:《每周一道 Agent 面试题:现在市面上的 Embedding Model 怎么选择(4)——效果不好时,应该调系统、换模型还是微调》。
我们会沿着原文、解析、切分、向量化、检索、重排和生成的完整链路定位问题,再判断不同失败类型应该由哪一层解决。
结束语
模型支持更长输入,只说明能力边界,并没有给出 chunk 的推荐长度。
每个片段既要包含回答问题所需的条件,又要保持相对集中的语义。具体怎样切,要结合文档结构、查询方式和模型特点,通过实验确定。
因此,模型长度和 chunk 大小不能分开讨论,应把两者作为组合方案评测。下一篇将讨论:效果仍不达标时,问题是不是出在模型,以及什么时候才值得微调。