前言
在 spring ai 中,advisor api 本质上就是对话调用链上的拦截器。它位于用户 prompt 和大模型调用之间,可以在请求发出前对 prompt 做增强,也可以在响应返回后做处理。
用 advisor 实现向量数据库的 rag 检索,核心是 questionansweradvisor。这个内置拦截器的工作方式很直接:拦截用户 prompt,在绑定的 vectorstore 中执行相似度搜索,把检索到的文档片段拼进 prompt 的 {question_answer_context} 占位符,再交给模型生成答案。
根据检索范围的固定还是动态,有两种实现方式。两者都通过 defaultadvisors 注册,区别只在调用时是否额外传入过滤参数。
方式一:全局共用一份知识库
questionansweradvisor 在构建时就绑定了 vectorstore,注册为 defaultadvisors 后,每次对话自动走同一个检索逻辑,对整个向量库执行相似度搜索。
@configuration
public class ragconfig {
@bean
public questionansweradvisor questionansweradvisor(vectorstore vectorstore) {
return questionansweradvisor.builder(vectorstore)
.searchrequest(searchrequest.builder()
.topk(4)
.similaritythreshold(0.8)
.build())
.build();
}
@bean
public chatclient chatclient(chatmodel chatmodel,
questionansweradvisor questionansweradvisor) {
return chatclient.builder(chatmodel)
.defaultadvisors(questionansweradvisor) // 全局注册
.build();
}
}
调用时不需要在每次 prompt() 里重复指定任何东西:
string answer = chatclient.prompt()
.user("spring ai 的 advisor 是什么?")
.call()
.content();
topk 控制返回的文档片段数量,similaritythreshold 是相似度得分下限。两者的配合逻辑是:先按阈值过滤低质量候选,再取前 k 个。similaritythreshold 设为 0.8 意味着只接受相似度 80 分以上的文档片段。
这种方式适合所有对话共享同一套知识的场景,配置最简单,但无法按用户或业务类型收窄检索范围。
方式二:每次对话动态过滤
同样注册为 defaultadvisors,但允许在运行时通过 filter_expression 参数覆盖或细化检索范围。过滤表达式采用类似 sql 的语法,可移植于所有 vectorstore 实现。
@bean
public chatclient chatclient(chatmodel chatmodel, vectorstore vectorstore) {
questionansweradvisor qaadvisor = questionansweradvisor.builder(vectorstore)
.searchrequest(searchrequest.builder()
.topk(4)
.build())
.build();
return chatclient.builder(chatmodel)
.defaultadvisors(qaadvisor) // 同样注册为默认 advisor
.build();
}
调用时传入过滤条件:
string answer = chatclient.prompt()
.user("我的订单有什么问题?")
.advisors(a -> a.param(
questionansweradvisor.filter_expression,
"user_id == '12345' && type == 'order'"))
.call()
.content();
底层会先通过元数据字段缩小候选集,再在候选集内执行向量相似度计算。如果同时在 advisor 构建时设置了基础过滤表达式,运行时传入的表达式优先级更高,会覆盖构建时的配置。
这种方式适合多租户、多业务线、需要权限隔离的场景,同一份向量库可以为不同对话提供不同范围的检索结果。
两种方式的核心区别
两种实现都使用了 defaultadvisors,questionansweradvisor 都是通过 chatclient.builder().defaultadvisors(...) 注册的。区别只在于调用时是否额外传入运行时参数来收窄检索范围。
| 维度 | 方式一:全局共用 | 方式二:动态过滤 |
|---|---|---|
| defaultadvisors | 有 | 有 |
| 检索范围 | 整个向量库 | 过滤后的子集 |
| 调用时的 advisors() | 不传 | 传 filter_expression |
| 隔离能力 | 无 | 按用户/租户/业务类型隔离 |
| 适用场景 | 统一知识库问答 | 多租户、多业务线、权限控制 |
方式一是“注册后就固定”,方式二是“注册后每次还能改”。
一个配置层面的细节
questionansweradvisor 的默认 similaritythreshold 是 0.0,意味着接受所有匹配结果,不管相似度多低。在生产环境中,这通常不是想要的行为。设置一个合理的阈值,可以让模型在检索不到相关内容时更诚实地表示“不知道”,而不是基于弱相关片段给出看似自信的错误回答。
阈值和 topk 的交互也需要留意:高阈值配高 topk,如果没有任何文档越过阈值线,模型会退回使用自己的知识库回答;阈值越低,越多的低质量匹配会进入 prompt,可能干扰模型判断。
以上就是spring ai拦截器实现rag检索的两种方式的详细内容,更多关于spring ai拦截器实现rag检索的资料请关注代码网其它相关文章!
发表评论