基于RAG+SimpleVectorStore的Tool Calling预筛选方案
技术成熟:Java生态有完善的轻量向量化模型和向量计算工具,无需额外依赖;资源可控:模型+50个工具向量总内存占用<100MB,完全适配本地部署;集成简单:与Spring AI无缝整合,不改变原有Tool封装逻辑(仅新增向量匹配层)。
基于RAG+SimpleVectorStore的Tool Calling预筛选方案
一、方案核心思路
通过RAG(检索增强生成) 机制,将所有工具的元数据(名称、描述、适用场景、参数等)存入SimpleVectorStore向量库;用户提问后,先将问题转为向量,与向量库中的工具向量做相似度匹配,筛选出TopN最相关的工具,再将这些工具传给大模型做Tool Calling,从而减少上下文占用,提升调用准确性。
二、具体实现步骤
1. 定义工具元数据结构
为每个工具设计结构化的元数据(需包含向量检索所需的核心特征),示例:
@Data
public class ToolMetadata {
/** 工具唯一标识 */
private String toolId;
/** 工具名称(与Spring AI的Function名称一致) */
private String toolName;
/** 工具描述(核心:适用场景+功能) */
private String toolDesc;
/** 适用问题关键词(如“干部简历”“考核结果”) */
private String keywords;
/** 工具参数说明(简化版,避免冗余) */
private String params;
}
关键:toolDesc和keywords需简洁且覆盖工具核心能力,作为向量检索的文本依据。
2. 初始化SimpleVectorStore(工具向量库)
将所有工具的元数据转为Document对象(Spring AI的文档模型),存入SimpleVectorStore:
(1)配置Embedding模型(用于工具元数据向量化)
沿用之前的Embedding配置(如阿里云text-embedding-v2),确保工具描述和用户问题使用同一Embedding模型:
@Configuration
public class EmbeddingConfig {
@Bean
public EmbeddingModel embeddingModel() {
return new OpenAiEmbeddingModel(
new OpenAiApi("https://dashscope.aliyuncs.com/compatible-mode/v1", "sk-xxx"),
OpenAiEmbeddingModel.Options.builder().withModel("text-embedding-v2").build()
);
}
@Bean
public SimpleVectorStore toolVectorStore(EmbeddingModel embeddingModel) {
return new SimpleVectorStore(embeddingModel);
}
}
(2)加载工具元数据到向量库
编写初始化类,将所有工具的元数据转为Document并入库(可通过配置文件/数据库加载工具列表):
@Component
@Slf4j
public class ToolVectorStoreInitializer implements CommandLineRunner {
@Autowired
private SimpleVectorStore toolVectorStore;
@Autowired
private EmbeddingModel embeddingModel;
// 模拟工具列表(实际可从配置/数据库读取)
private List<ToolMetadata> getToolList() {
return Arrays.asList(
ToolMetadata.builder()
.toolId("1")
.toolName("getCadreResume")
.toolDesc("查询干部的基本简历信息,包括学历、工作经历、任职情况")
.keywords("干部简历、基本信息、学历、工作经历")
.params("cadreId:干部ID(必填)")
.build(),
ToolMetadata.builder()
.toolId("2")
.toolName("getCadreAssessment")
.toolDesc("查询干部的年度考核结果、民主测评情况")
.keywords("干部考核、测评结果、年度考核")
.params("cadreId:干部ID(必填),year:考核年份(选填)")
.build()
// 更多工具...
);
}
@Override
public void run(String... args) throws Exception {
List<ToolMetadata> toolList = getToolList();
List<Document> toolDocs = toolList.stream().map(tool -> {
// 将工具元数据转为Document(content为检索文本,metadata存工具属性)
String content = tool.getToolDesc() + " " + tool.getKeywords();
Map<String, Object> metadata = new HashMap<>();
metadata.put("toolId", tool.getToolId());
metadata.put("toolName", tool.getToolName());
metadata.put("params", tool.getParams());
return new Document(content, metadata);
}).collect(Collectors.toList());
// 存入SimpleVectorStore
toolVectorStore.add(toolDocs);
log.info("工具向量库初始化完成,共加载{}个工具", toolList.size());
}
}
3. 实现工具筛选服务
编写服务类,接收用户问题,检索向量库并返回最相关的工具列表:
@Service
public class ToolRetrievalService {
@Autowired
private SimpleVectorStore toolVectorStore;
/**
* 根据用户问题筛选TopN相关工具
* @param userQuestion 用户问题
* @param topN 返回数量(如Top3)
* @return 筛选后的工具元数据列表
*/
public List<ToolMetadata> retrieveRelevantTools(String userQuestion, int topN) {
// 构建检索请求(设置相似度阈值,过滤低相关工具)
SearchRequest request = SearchRequest.query(userQuestion)
.withTopK(topN)
.withSimilarityThreshold(0.7f); // 相似度≥0.7才保留
// 从向量库检索相关Document
List<Document> retrievedDocs = toolVectorStore.similaritySearch(request);
// 转换为ToolMetadata返回
return retrievedDocs.stream().map(doc -> {
Map<String, Object> metadata = doc.getMetadata();
return ToolMetadata.builder()
.toolId(metadata.get("toolId").toString())
.toolName(metadata.get("toolName").toString())
.toolDesc(doc.getContent())
.params(metadata.get("params").toString())
.build();
}).collect(Collectors.toList());
}
}
4. 集成Tool Calling流程
在对话服务中,先调用工具筛选服务,再将筛选后的工具传给大模型做Tool Calling:
(1)定义Spring AI的Function工具(与元数据中的工具对应)
@Component
public class CadreTools {
@Tool("getCadreResume")
@Description("查询干部的基本简历信息")
public String getCadreResume(@Parameter(description = "干部ID") String cadreId) {
// 实际业务逻辑:调用接口/数据库查询简历
return "干部ID:" + cadreId + ",简历信息:本科,10年工作经验,现任XX部门主任";
}
@Tool("getCadreAssessment")
@Description("查询干部的年度考核结果")
public String getCadreAssessment(
@Parameter(description = "干部ID") String cadreId,
@Parameter(description = "考核年份") String year) {
// 实际业务逻辑:查询考核结果
return "干部ID:" + cadreId + "," + year + "年考核结果:优秀";
}
// 更多工具方法...
}
(2)对话服务中集成筛选+Tool Calling
@Service
public class CadreChatService {
@Autowired
private OpenAiChatModel chatModel;
@Autowired
private ToolRetrievalService toolRetrievalService;
@Autowired
private CadreTools cadreTools;
public String chat(String userQuestion) {
// 步骤1:检索最相关的Top3工具
List<ToolMetadata> relevantTools = toolRetrievalService.retrieveRelevantTools(userQuestion, 3);
// 步骤2:将筛选后的工具转为Spring AI的ToolSpec(仅传递相关工具)
List<ToolSpec> toolSpecs = relevantTools.stream()
.map(tool -> {
// 根据toolName匹配CadreTools中的方法(可通过反射/映射实现)
Method toolMethod = Arrays.stream(CadreTools.class.getMethods())
.filter(m -> m.getAnnotation(Tool.class).value().equals(tool.getToolName()))
.findFirst().orElse(null);
return toolMethod != null ? ToolSpec.builder(toolMethod, cadreTools).build() : null;
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
// 步骤3:构建对话请求,仅传入筛选后的工具
ChatResponse response = chatModel.call(
new ChatRequest(
PromptTemplate.create(userQuestion).createMessage(),
ToolCallRequest.builder().toolSpecs(toolSpecs).build()
)
);
return response.getResult().getOutput().getContent();
}
}
三、优化与注意事项
- 相似度阈值调优:根据实际测试调整
similarityThreshold(如0.6~0.8),平衡召回率和精准度; - 工具元数据优化:
toolDesc需避免冗余,聚焦“问题场景+功能”(如“查询干部简历”而非“该工具用于通过干部ID查询其学历、工作经历等简历信息”); - 缓存机制:对高频问题的工具筛选结果缓存(如Redis),减少重复向量检索;
- 动态更新工具库:若工具新增/修改,需同步更新
SimpleVectorStore(可通过定时任务/事件触发); - 多轮对话适配:若多轮对话中工具调用需上下文,可将历史筛选结果纳入检索参考。
四、方案优势
- 减少上下文占用:仅传递用户问题相关的工具,避免所有工具描述挤占token;
- 提升调用准确性:通过向量匹配筛选最相关工具,降低大模型选错工具的概率;
- 轻量易实现:基于
SimpleVectorStore无需额外依赖,适合中小规模工具集(若工具超100个,可替换为Milvus/PGVector)。
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)