在 Java 中,向量数据库(以 Milvus 为例)与大模型的配合是实现 "增强大模型能力" 的核心方案,主要用于解决大模型 "知识时效性差"、"上下文长度有限"、"幻觉生成" 等问题。其核心逻辑是:用 Milvus 存储大模型生成的向量数据(如文本嵌入),通过向量相似性搜索为大模型提供精准上下文,再让大模型基于该上下文生成回答。
查询与增强生成
当用户提问时:
localhost:19530
)。依赖库:
Maven 依赖示例:
```cobol
<!-- Milvus Java SDK --><dependency> <groupId>io.milvus</groupId> <artifactId>milvus-sdk-java</artifactId> <version>2.3.4</version> <!-- 需与Milvus服务版本兼容 --></dependency> <!-- 用于调用OpenAI API(生成向量和回答) --><dependency> <groupId>com.theokanning.openai-gpt3-java</groupId> <artifactId>client</artifactId> <version>0.18.0</version></dependency> <!-- JSON处理 --><dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.15.2</version></dependency>
```
首先创建 Milvus 连接,用于后续操作集合(Collection):
import io.milvus.client.MilvusClient;import io.milvus.client.MilvusServiceClient;import io.milvus.param.ConnectParam; public class MilvusUtils { // 初始化Milvus客户端 public static MilvusClient getMilvusClient() { ConnectParam connectParam = ConnectParam.newBuilder() .withHost("localhost") // Milvus服务地址 .withPort(19530) // 端口(默认19530) .build(); return new MilvusServiceClient(connectParam); }}
需要定义集合的 Schema,包含:
import io.milvus.param.collection.*;import io.milvus.grpc.DataType; public class CollectionManager { private static final String COLLECTION_NAME = "document_embeddings"; // 集合名称 private static final int VECTOR_DIM = 768; // 向量维度(与嵌入模型一致) // 创建集合 public static void createCollection(MilvusClient client) { // 检查集合是否已存在,存在则删除(示例用) if (client.hasCollection(HasCollectionParam.newBuilder().withCollectionName(COLLECTION_NAME).build())) { client.dropCollection(DropCollectionParam.newBuilder().withCollectionName(COLLECTION_NAME).build()); } // 定义Schema FieldType idField = FieldType.newBuilder() .withName("id") // 主键字段名 .withDataType(DataType.Int64) // 数据类型 .withPrimaryKey(true) // 设为主键 .withAutoID(true) // 自动生成ID .build(); FieldType vectorField = FieldType.newBuilder() .withName("embedding") // 向量字段名 .withDataType(DataType.FloatVector) // 浮点向量 .withDimension(VECTOR_DIM) // 向量维度 .build(); FieldType textField = FieldType.newBuilder() .withName("original_text") // 原始文本字段(元数据) .withDataType(DataType.VarChar) // 字符串类型 .withMaxLength(2048) // 最大长度 .build(); // 创建集合 CreateCollectionParam createParam = CreateCollectionParam.newBuilder() .withCollectionName(COLLECTION_NAME) .addFieldType(idField) .addFieldType(vectorField) .addFieldType(textField) .withConsistencyLevel(ConsistencyLevelEnum.STRONG) // 一致性级别 .build(); client.createCollection(createParam); System.out.println("集合创建成功:" + COLLECTION_NAME); } // 创建向量索引(加速搜索) public static void createIndex(MilvusClient client) { IndexType indexType = IndexType.IVF_FLAT; // 常用索引类型(平衡速度与精度) String indexParam = "{\"nlist\": 1024}"; // 索引参数(nlist:聚类数量) CreateIndexParam createIndexParam = CreateIndexParam.newBuilder() .withCollectionName(COLLECTION_NAME) .withFieldName("embedding") // 对向量字段创建索引 .withIndexType(indexType) .withIndexParam(indexParam) .build(); client.createIndex(createIndexParam); System.out.println("向量索引创建成功"); }}
需要将原始文档(如 PDF、TXT)拆分为片段(避免长度过长),再用嵌入模型(如 OpenAI 的text-embedding-ada-002
)生成向量,最后插入 Milvus。
import com.theokanning.openai.embedding.Embedding;import com.theokanning.openai.embedding.EmbeddingRequest;import com.theokanning.openai.service.OpenAiService;import io.milvus.param.InsertParam;import io.milvus.response.InsertResponse;import java.util.ArrayList;import java.util.List; public class VectorGenerator { private static final String OPENAI_API_KEY = "your_openai_api_key"; // 替换为实际API Key private static final OpenAiService openAiService = new OpenAiService(OPENAI_API_KEY); // 生成文本的嵌入向量(调用OpenAI嵌入模型) public static List<Float> generateEmbedding(String text) { EmbeddingRequest request = EmbeddingRequest.builder() .model("text-embedding-ada-002") // 嵌入模型 .input(text) .build(); List<Embedding> embeddings = openAiService.createEmbeddings(request).getData(); return embeddings.get(0).getEmbedding(); // 返回向量(1536维,与示例中768维不同,需统一) } // 插入文档片段及向量到Milvus public static void insertDocuments(MilvusClient client, List<String> documentChunks) { List<List<Float>> vectors = new ArrayList<>(); List<String> texts = new ArrayList<>(); // 生成所有片段的向量 for (String chunk : documentChunks) { vectors.add(generateEmbedding(chunk)); texts.add(chunk); } // 构造插入数据 InsertParam insertParam = InsertParam.newBuilder() .withCollectionName(CollectionManager.COLLECTION_NAME) .addField("embedding", vectors) // 向量字段 .addField("original_text", texts) // 原始文本字段 .build(); InsertResponse response = client.insert(insertParam); System.out.println("插入成功,行数:" + response.getInsertCount()); // 插入后加载集合(使数据可搜索) client.loadCollection(LoadCollectionParam.newBuilder() .withCollectionName(CollectionManager.COLLECTION_NAME) .build()); }}
用户提问后,流程如下:
import com.theokanning.openai.completion.CompletionRequest;import io.milvus.param.SearchParam;import io.milvus.response.SearchResultsWrapper;import java.util.List; public class QAService { private static final OpenAiService openAiService = new OpenAiService(VectorGenerator.OPENAI_API_KEY); // 搜索与问题相似的文档片段 public static List<String> searchSimilarDocs(MilvusClient client, String query, int topK) { // 生成问题的向量 List<Float> queryVector = VectorGenerator.generateEmbedding(query); // 构造搜索参数 SearchParam searchParam = SearchParam.newBuilder() .withCollectionName(CollectionManager.COLLECTION_NAME) .withFieldName("embedding") // 搜索向量字段 .withQueryVectors(List.of(queryVector)) // 问题向量 .withTopK(topK) // 返回前topK个结果 .withMetricType(MetricType.L2) // 距离度量(L2:欧氏距离) .withParams("{\"nprobe\": 10}") // 搜索参数(nprobe:探测聚类数量,影响精度与速度) .addOutField("original_text") // 需要返回的元数据字段 .build(); // 执行搜索 SearchResultsWrapper resultsWrapper = new SearchResultsWrapper(client.search(searchParam).getData()); List<String> similarDocs = new ArrayList<>(); // 提取结果中的原始文本 for (int i = 0; i < resultsWrapper.getRowCount(0); i++) { String text = resultsWrapper.getFieldData(0, i, "original_text", String.class); similarDocs.add(text); } return similarDocs; } // 调用大模型生成回答(结合问题与搜索到的文档) public static String generateAnswer(String query, List<String> contextDocs) { // 构造提示词(将上下文与问题结合) StringBuilder prompt = new StringBuilder(); prompt.append("基于以下信息回答问题:\n"); for (String doc : contextDocs) { prompt.append("- ").append(doc).append("\n"); } prompt.append("问题:").append(query).append("\n回答:"); // 调用大模型(如GPT-3.5) CompletionRequest request = CompletionRequest.builder() .model("gpt-3.5-turbo-instruct") .prompt(prompt.toString()) .maxTokens(512) // 最大回答长度 .temperature(0.7) // 随机性(0-1,越低越确定) .build(); return openAiService.createCompletion(request).getChoices().get(0).getText(); }}
public class Main { public static void main(String[] args) { // 1. 初始化Milvus客户端 MilvusClient client = MilvusUtils.getMilvusClient(); // 2. 创建集合和索引 CollectionManager.createCollection(client); CollectionManager.createIndex(client); // 3. 准备文档片段(示例:Java相关文档) List<String> documentChunks = List.of( "Java是一种跨平台的编程语言,由Sun Microsystems于1995年推出。", "Java的特点包括面向对象、平台无关性(通过JVM实现)、安全性等。", "Java开发工具包(JDK)包含编译器(javac)、运行时环境(JRE)等工具。" ); // 4. 插入文档向量到Milvus VectorGenerator.insertDocuments(client, documentChunks); // 5. 模拟用户提问并生成回答 String userQuery = "Java的特点有哪些?"; List<String> contextDocs = QAService.searchSimilarDocs(client, userQuery, 2); // 搜索前2个相似文档 String answer = QAService.generateAnswer(userQuery, contextDocs); System.out.println("用户问题:" + userQuery); System.out.println("回答:" + answer); // 关闭客户端 client.close(); }}
text-embedding-ada-002
,维度为 1536,需修改VECTOR_DIM
)。索引选择:
IVF_FLAT
(精确但速度中等);HNSW
(近似但速度快,适合高维向量)。大模型选择:
sentence-transformers
(Java 可通过 JNI 调用或 HTTP 服务),闭源可选 OpenAI/Anthropic 的 API;通过这种方式,大模型可以结合外部知识库生成更准确、更具时效性的回答,解决了其原生的知识局限问题。
原网址: 访问
创建于: 2025-09-04 23:31:58
目录: default
标签: 无
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
最新评论