向量检索怎样按文档语言过滤召回结果
来源:17golang原创
时间:2026-10-21 01:08:59 172浏览 收藏
向量检索默认按 embedding 的相似度排序,但“相似”不等于“符合语言要求”。如果知识库同时包含中文、英文和多语言版本,直接扩大 topK 再在应用层筛选,常见结果是候选被过滤掉后数量不足,甚至让不同语言的版本互相竞争。更稳妥的做法是把语言当作规范化元数据,在向量检索时作为硬约束,再让相似度在约束范围内排序。
官方地址:https://qdrant.tech/
下面用 Qdrant 说明这种架构,重点不在某个数据库的 API 记忆,而在“字段怎么定义、过滤放在哪里、结果不足怎么办”这三个决策。
为什么不能只把语言写进查询文本
“请用中文回答”适合约束生成模型,“只检索中文文档”却是检索集合的约束。把 中文 追加到用户问题中,embedding 可能仍然把语义相近但语言不同的文档排在前面,因为语言信息未必在向量空间里形成可靠的硬边界。
应用层后过滤也有一个容易忽略的损失:假设系统先取 5 条,再丢掉其中 3 条英文文档,最终只剩 2 条中文结果。把 topK 调大可以缓解,但它不是保证;当目标语言占比很低、文档分布不均或相似度阈值较紧时,仍可能没有足够候选。

因此要先回答一个架构问题:语言是“希望结果尽量满足的偏好”,还是“结果必须满足的业务条件”。多语言客服知识库、合规文档和按地区发布的说明,通常属于后者;这时语言字段应该进入过滤条件,而不是只进入提示词。
入库时把语言设计成稳定的元数据
过滤能否可靠,首先取决于入库数据是否一致。建议每个文档分块至少保存 language、document_id 和 chunk_id,其中语言值采用有限且明确的编码,例如 zh-CN、zh-TW、en,不要一部分记录写“中文”、另一部分写“简体中文”。
{
"document_id": "manual-042",
"chunk_id": "manual-042-07",
"language": "zh-CN",
"text": "向量检索会先根据过滤条件缩小可参与排序的文档集合。"
}
上面的 JSON 是数据形状示例,保持严格 JSON 格式,不在其中插入注释。真正入库时要把同一套规范应用到所有分块:语言识别失败时不要悄悄写成默认语言,可以保存 und 或进入待处理队列;否则“未知”会被误当成“中文”,造成难以解释的召回偏差。
语言字段适合做精确匹配,而不是全文检索。Qdrant 文档将这类字段放在 payload 中,并建议为参与过滤的字段创建对应索引;对于语言代码这类离散字符串,使用 keyword 类型比把它当作普通文本拆词更符合意图。
用 keyword 索引在检索阶段过滤
先创建语言字段的 payload index,再在查询中把它放进过滤条件。索引最好在批量写入前建立;如果数据已经写入,新增索引可能还需要重建向量图,才能获得完整的过滤优化。
{
"field_name": "language",
"field_schema": "keyword"
}
查询时使用精确值:
{
"query": [0.12, -0.08, 0.44, 0.31],
"filter": {
"must": [
{"key": "language", "match": {"value": "zh-CN"}}
]
},
"limit": 8,
"with_payload": true
}
这里的关键不是把 limit 写成 8,而是让过滤条件在向量搜索范围内生效。这样返回的每个候选都先满足语言约束,再按照向量相似度竞争;如果还要加租户、产品线或时间范围,就把它们作为额外的结构化条件组合,而不是把这些值拼进自然语言查询。
如果应用使用 Go,可以把请求边界收敛在一个函数中,避免不同调用方自行拼写语言值:
package search
import (
"context"
"fmt"
"github.com/qdrant/go-client/qdrant"
)
func LanguageCondition(language string) (*qdrant.Filter, error) {
// 只允许已登记的语言代码,避免把用户输入直接变成过滤字段。
switch language {
case "zh-CN", "zh-TW", "en":
return &qdrant.Filter{
Must: []*qdrant.Condition{qdrant.NewMatch("language", language)},
}, nil
default:
return nil, fmt.Errorf("unsupported document language: %s", language)
}
}
func BuildRequest(ctx context.Context, language string) (*qdrant.Filter, error) {
// 统一入口让上层在空结果时可以识别是过滤条件导致的限制。
if err := ctx.Err(); err != nil {
return nil, err
}
return LanguageCondition(language)
}
示例只负责构造过滤对象,没有在本地连接 Qdrant,也没有假设某个查询结果。生产代码还应把语言代码作为内部枚举或配置值传入,并在请求取消时及时停止后续调用。
结果变少时先查过滤边界
加入语言条件后结果减少并不一定是索引故障。先把问题分成三类:第一,目标语言的数据本来就少;第二,语言字段缺失、大小写不一致或使用了错误别名;第三,过滤和向量搜索组合后候选集合太窄。

可以分别记录“过滤前可用文档数”“过滤后候选数”“最终返回数”和“未满足数量的请求比例”。这些是观测指标,不是向量库自动给出的统一字段;应用需要在检索适配层自行记录,才能区分标注问题和召回能力问题。
当结果不足时,降级策略要显式化。对必须满足语言的场景,应该返回少量结果或空结果,并提示知识库没有足够的目标语言内容;对语言只是偏好的场景,可以先按目标语言过滤,低于阈值时再扩大到同语系或全部语言,但必须把降级状态传给生成层,避免模型把跨语言资料误说成同语言原文。
不要用“扩大 topK 后再静默过滤”替代这个决策。它会把结果数量和延迟一起交给经验值,且无法解释为什么某次请求跨过了语言边界。
一张清单判断方案是否稳
- 语言值是否有固定字典,且所有分块遵守同一种大小写和地区码规则?
- 语言字段是否以精确匹配索引,而不是依赖全文分词或查询文本提示?
- 过滤是否发生在向量候选参与排序之前,还是只在应用层做事后删除?
- 目标语言没有足够内容时,系统是返回空结果、扩大范围,还是交给人工补充?这个选择是否可观测?
- 新增字段索引后,是否考虑已有向量图的重建成本和上线窗口?
如果语言是硬性业务约束,就把它放进检索过滤器;如果语言只是排序偏好,则可以做多路召回或重排,但不要把两种语义混在同一个字段里。稳定的元数据、正确的索引类型和明确的空结果策略,才是多语言向量检索可维护的边界。
常见问题
语言字段应该存语言名称还是代码?
优先存稳定代码,例如 zh-CN 或 en,展示名称可以在应用层映射。代码更容易做精确匹配,也便于后续增加地区或脚本维度。
只过滤中文,能保证返回内容全是中文吗?
只能保证“语言元数据为中文”的记录进入结果。若入库标注错误、一个分块混合多种语言,过滤器不会替你重新识别正文,所以标注质量仍是召回边界的一部分。
为什么加了过滤器后相似度看起来变低?
过滤把竞争集合缩小了,返回的是目标语言集合中的相似结果,不再是全库的前几名。应分别观察过滤前后候选规模和业务可用性,不要直接拿两个分数做结论。
参考资料
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
484 收藏
-
381 收藏
-
104 收藏
-
126 收藏
-
105 收藏
-
245 收藏
-
科技周边 · 人工智能 | 1小时前 | 人工智能 · 人工智能 Hugging Face Inference Providers OpenAI Chat Completions 路由 API 模型标识 HF_TOKEN442 收藏
-
243 收藏
-
474 收藏
-
419 收藏
-
400 收藏
-
314 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习