Dify 外部知识库集成 Milvus 实战指南

Dify 外部知识库集成 Milvus 实战指南

版本信息

  • Dify: 1.10.0
  • Milvus: 2.6.0-rc.1

🎯 集成概述

本文详细介绍如何将 Dify 与 Milvus 向量数据库集成,通过 Spring Boot 代理服务实现外部知识库功能。

🔄 集成架构

复制代码
Dify → Spring Boot API Proxy → Milvus Vector Database

🔧 API 代理服务开发

参考文档

官方外部知识库 API 文档

2.1 Controller 层实现

⚠️ 重要提示 : @RequestBody(required = false) 是必须的,否则 Dify 创建外部知识库时会出现 500 错误且难以排查。

java 复制代码
@RestController
@RequestMapping("/api")
public class MilvusController {

    private static final Logger logger = LoggerFactory.getLogger(MilvusController.class);

    // 生产环境请使用安全的 API 密钥管理方式
    private static final String VALID_API_KEY = "your-valid-api-key";

    @Autowired
    private MilvusService milvusService;

    @PostMapping("/retrieval")
    public ResponseEntity<?> retrieval(
        HttpServletRequest request, 
        @RequestBody(required = false) RetrievalRequest retrievalRequest
    ) {
        try {
            // 在 Dify 中创建外部知识库时,request body 为空
            if (retrievalRequest == null) {
                return ResponseEntity.ok(new RetrievalResponse());
            }

            // 执行 Milvus 搜索
            RetrievalResponse response = milvusService.search(retrievalRequest);
            return ResponseEntity.ok(response);

        } catch (Exception e) {
            logger.error("处理检索请求时发生错误", e);
            ErrorResponse errorResponse = new ErrorResponse(500, "内部服务器错误: " + e.getMessage());
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
        }
    }
}

2.2 Service 层实现

核心功能:

  1. 🧠 对查询文本进行 Embedding 编码
  2. 🔍 在 Milvus 中执行相似度搜索

⚠️ 关键注意事项: 返回的 JSON 中 metadata 不能为空,否则会出现召回测试有数据但工作流中无数据的问题!

java 复制代码
@Service
public class MilvusService {

    @Value("${milvus.host}")
    private String milvusHost;
    
    @Value("${milvus.port}")
    private int milvusPort;

    public RetrievalResponse search(RetrievalRequest request) {
        MilvusClientV2 client = null;
        
        try {
            // 建立 Milvus 连接
            client = MilvusConnectionUtil.connectStatic(milvusConfig);
            
            String collectionName = request.getKnowledge_id().trim();
            
            // 加载集合到内存
            client.loadCollection(LoadCollectionReq.builder()
                .collectionName(collectionName)
                .build());

            // 获取查询文本
            String query = request.getQuery();
            logger.debug("查询内容: {}", query);
            
            // 生成 Embedding 向量
            List<Float> embeddings = getEmbeddingByQwen(query);
            logger.debug("Embedding 向量长度: {}", embeddings.size());
            
            // 构建搜索参数
            FloatVec floatVec = new FloatVec(embeddings);
            List<BaseVector> baseVectors = Collections.singletonList(floatVec);
            
            // 执行向量搜索
            SearchResp searchResp = client.search(SearchReq.builder()
                .collectionName(collectionName)
                .data(baseVectors)
                .topK(request.getRetrieval_setting().getTop_k())
                .outputFields(Collections.singletonList("*"))
                .build()
            );
            
            logger.debug("搜索结果: {}", searchResp.toString());
            
            // 处理搜索结果
            List<List<SearchResp.SearchResult>> searchResults = searchResp.getSearchResults();
            List<RetrievalResponse.Record> records = new ArrayList<>();

            for (List<SearchResp.SearchResult> results : searchResults) {
                for (SearchResp.SearchResult result : results) {
                    RetrievalResponse.Record record = new RetrievalResponse.Record();
                    
                    // 解析元数据
                    JsonObject metaData = (JsonObject) result.getEntity().get("metadata");
                    
                    // 设置记录内容
                    record.setContent(metaData.get("text").getAsString());
                    record.setScore(result.getScore());
                    record.setTitle(metaData.get("title").getAsString());

                    // 构建元数据映射(确保不为空)
                    Map<String, Object> recordMetaData = new HashMap<>();
                    recordMetaData.put("path", metaData.get("url").getAsString());
                    recordMetaData.put("description", metaData.get("description").getAsString());
                    record.setMetadata(recordMetaData);

                    records.add(record);
                }
            }

            RetrievalResponse response = new RetrievalResponse();
            response.setRecords(records);
            return response;

        } catch (Exception e) {
            logger.error("Milvus 搜索失败", e);
            throw new RuntimeException("搜索失败: " + e.getMessage(), e);
        } finally {
            if (client != null) {
                try {
                    client.close();
                } catch (Exception e) {
                    logger.warn("关闭 Milvus 客户端连接时出错", e);
                }
            }
        }
    }
}

🚀 部署使用

3.1 创建外部 API 连接

在 Dify 管理界面中:

复制代码
知识库 → 外部知识库API → 添加新连接
参数
Name test
API Endpoint http://your-server-ip/api/retrieval
API Key •••••••••••••

3.2 创建外部知识库

在 Dify 中创建外部知识库时,需要指定外部知识库 ID,该 ID 应与 Milvus 中的 Collection Name 保持一致。


💡 最佳实践

✅ 成功要点

  • 确保 API 接口支持空 Body 请求
  • metadata 字段不能为空
  • 正确配置 Milvus 连接参数
  • 合理设置 Top-K 搜索参数

🔧 常见问题排查

  1. 500 错误 : 检查 @RequestBody(required = false)
  2. 工作流无数据: 检查 metadata 是否正确填充
  3. 连接失败: 验证 Milvus 服务状态和网络连通性

📝 总结

通过本文的集成方案,您可以成功将 Dify 与 Milvus 向量数据库连接,实现高效的外部知识库功能。这种架构既保证了系统的灵活性,又充分利用了 Milvus 的高性能向量检索能力。

💬 如有问题或建议,欢迎在评论区交流!

相关推荐
Hello eveybody2 小时前
什么是动态规划(DP)?(Python版)
python·动态规划
IT猿手2 小时前
MOEA/D(基于分解的多目标进化算法)求解46个多目标函数及一个工程应用,包含四种评价指标,MATLAB代码
开发语言·算法·matlab·多目标算法
野犬寒鸦2 小时前
从零起步学习并发编程 || 第九章:Future 类详解及CompletableFuture 类在项目实战中的应用
java·开发语言·jvm·数据库·后端·学习
南 阳2 小时前
Python从入门到精通day34
开发语言·python
前路不黑暗@2 小时前
Java项目:Java脚手架项目的统一模块的封装(四)
java·开发语言·spring boot·笔记·学习·spring cloud·maven
消失的旧时光-19433 小时前
第二十四课:从 Java 后端到系统架构——后端能力体系的最终总结
java·开发语言·系统架构
西门吹-禅3 小时前
文本搜索node js--meilisearch
开发语言·javascript·ecmascript
Anastasiozzzz3 小时前
G1垃圾回收流程详解
java·开发语言·算法
APIshop4 小时前
阿里巴巴中国站按图搜索1688商品(拍立淘)API 返回值说明
java·python·图搜索算法