在 Java 中,向量数据库(以 Milvus 为例)与大模型的配合是实现 "增强大模型能力" 的核心方案,主要用于解决大模型 "知识时效性差"、"上下文长度有限"、"幻觉生成" 等问题。其核心逻辑是:用 Milvus 存储大模型生成的向量数据(如文本嵌入),通过向量相似性搜索为大模型提供精准上下文,再让大模型基于该上下文生成回答。
一、核心原理:向量数据库与大模型的协作流程
-
数据预处理与向量生成
将原始数据(如文档、图片、音频)通过大模型(或专门的嵌入模型)转换为高维向量(Embedding)。例如:用 BERT 将 "Java 是一种编程语言" 转换为 768 维向量。 -
向量存储与索引
将生成的向量及对应原始数据(或元信息)存入 Milvus,Milvus 通过向量索引(如 IVF_FLAT、HNSW)实现高效的相似性搜索(毫秒级返回 TopK 结果)。 -
查询与增强生成
当用户提问时:- 先用相同的嵌入模型将问题转换为向量;
- 在 Milvus 中搜索与问题向量最相似的 TopN 向量,获取对应的原始数据(作为 "上下文知识");
- 将 "问题 + 上下文知识" 输入大模型(如 GPT、LLaMA),让大模型基于外部知识生成准确回答。
二、环境准备
1. 基础依赖
-
Milvus 服务:安装并启动 Milvus(参考Milvus 官方文档),获取服务地址(如
localhost:19530)。 -
Java 开发环境:JDK 11+,Maven/Gradle。
-
依赖库:
- Milvus Java SDK(用于操作 Milvus);
- 大模型 / 嵌入模型客户端(如 OpenAI SDK、Hugging Face Java 客户端,或通过 HTTP 调用 API)。
Maven 依赖示例:
<!-- 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>
三、具体实现步骤(以 "文档问答系统" 为例)
步骤 1:初始化 Milvus 客户端
首先创建 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);
}
}
步骤 2:创建 Milvus 集合(存储向量与元数据)
需要定义集合的 Schema,包含:
- 向量字段(存储嵌入向量,维度需与嵌入模型一致,如 BERT 的 768 维);
- 主键字段(唯一标识);
- 元数据字段(如原始文本、文档 ID 等,用于后续提取上下文)。
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("向量索引创建成功");
}
}
步骤 3:用大模型生成向量并插入 Milvus
需要将原始文档(如 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());
}
}
步骤 4:查询时搜索相似向量并调用大模型生成回答
用户提问后,流程如下:
- 生成问题的向量;
- 在 Milvus 中搜索 TopN 相似向量,获取对应的文档片段;
- 将问题 + 文档片段作为上下文,调用大模型生成回答。
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();
}
}
步骤 5:整合流程(完整示例)
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();
}
}
四、关键注意事项
- 向量维度一致性:嵌入模型生成的向量维度必须与 Milvus 集合中定义的维度完全一致(如示例中若用
text-embedding-ada-002,维度为 1536,需修改VECTOR_DIM)。 - 索引选择:
- 追求精度:用
IVF_FLAT(精确但速度中等); - 追求速度:用
HNSW(近似但速度快,适合高维向量)。
- 追求精度:用
- 文档分块策略:原始文档需拆分(如每 200 字一段),避免长度超过嵌入模型的输入限制(如 GPT 模型通常支持 2048 tokens)。
- 大模型选择:
- 嵌入模型:开源可选
sentence-transformers(Java 可通过 JNI 调用或 HTTP 服务),闭源可选 OpenAI/Anthropic 的 API; - 生成模型:开源可选 LLaMA(需本地部署),闭源可选 GPT-4、Claude 等。
- 嵌入模型:开源可选
五、应用场景
- 智能问答:基于企业内部文档回答员工问题(如 "公司年假政策是什么?");
- 推荐系统:通过用户行为向量与物品向量的相似性推荐内容;
- 图像检索:将图片转换为向量,搜索相似图片(需配合图像嵌入模型)。
通过这种方式,大模型可以结合外部知识库生成更准确、更具时效性的回答,解决了其原生的知识局限问题。
1234

被折叠的 条评论
为什么被折叠?



