1 准备工作
1.1 依赖和环境
ubuntu22.04
JDK8
maven 3.6.3
ollama
1.2 数据准备

// 1获取HetuKV私有知识文档
String filePath = "/VDB/HetuKV_RAG_Test.md";
StringBuilder content = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
String line;
while ((line = reader.readLine()) != null) {
content.append(line).append("\n");
}
} catch (IOException e) {
e.printStackTrace();
return;
}
// 获取整个文件内容并按#分割
String text = content.toString();
String[] segments = text.split("#");
1.3 准备 LLM 和 Embeddings 模型
// 实例化工具类
DeepSeekClient apiClient = new DeepSeekClient(
"Your DeepSeek API Key");
// 构建请求体
List<String> messages = new ArrayList<>();
messages.add("你好");
JSONObject requestBody = apiClient.chat("deepseek-chat", messages,false);
// 发送请求并获取响应
try {
String response = apiClient.sendRequest(requestBody);
// 解析响应
DeepSeekResponse parsedResponse = apiClient.parseResponse(response);
System.out.println("Parsed Response: " + parsedResponse.content);
} catch (IOException e) {
e.printStackTrace();
}
nomic-embed-text
嵌入模型生成文本嵌入。HetuVDB提供了对ollama接口API的封装类。
// 输入参数示例
String ip = "your IP";
int port = 11434;
String model = "nomic-embed-text";
String input = "这是一个测试句子";
try {
EmbedResponse embedResponse = new OllamaEmbeddingUtils().embed(ip, port, model, input);
System.out.println(embedResponse);
float[] floats = embedResponse.getEmbeddings().get(0);
System.out.println(Arrays.toString(floats));
} catch (IOException e) {
e.printStackTrace();
}
生成一个测试嵌入,并打印其维度和嵌入向量(只截取了一部分)。
768
[0.008433551, 0.060538568, -0.15399724, 0.018865598, 0.0091602765, 0.016291345, 0.05111419, -0.018628616, -0.038147576, -0.033492282, -0.098604344, 0.0067264084, 0.023402072, -0.0049559334, -0.007166973, -0.07849371, -0.031152047, -0.038216475, -0.068336934, 0.095721535, 0.0046433937, 0.031166036, -0.032429334, -0.00805019, 0.1079416, -0.0011236112, 0.038522687, 0.061783068, -0.012630016, -0.0059412066, 0.020410854, -0.018237721, -0.014239253, 0.0013444505, 0.019328492, -0.014417462, 0.04224368, 0.011871055, 0.054475706, 0.031483572, -0.013881395, 0.030970223, 0.033263147, -0.015748387, 0.05927272, -0.01088858, 0.042979363, 0.040499695,
2 将数据载入HetuVDB
2.1 创建Hetu对象、创建并定义向量索引。
int flags = Hetu.HE_O_CREATE | Hetu.HE_O_TRUNCATE | Hetu.HE_O_VOLUME_CREATE | Hetu.HE_O_VOLUME_TRUNCATE;
Hetu he = new Hetu("he://.//dev/nvme2n1", "testRAG", flags);
if (!he.checkVectorIndexExists()) {
he.IndexCreate(1000000, 32, 128, 20, 768, SimilarityMetric.EUCLIDEAN, false);
}
Hetu对象的参数依次为:
DEVICE_URL -String类型,分为两部分:服务器地址+实际路径。
DB_NAME -String类型,表示数据库的名字。
标志位 -用户创建数据库时的操作。
IndexCreate函数的参数依次为:
initialItemSize -int类型,用于确定索引的初始大小,会自动扩容。
m -int类型,节点在层次结构的每个层级所能拥有的最大边数或连接数。
efConstruction -int类型,索引构建过程中考虑的候选节点数量。
ef -int类型,搜索过程中评估的邻居数量。
dimensions -int类型,向量的维度,即每个向量的特征数量。
distanceName -String类型,距离度量的名称,用于计算向量之间的相似性或距离,常见的有
l2
(欧几里得距离)、cosine
(余弦相似度)、ip
(内积)等。useGpu -布尔类型,是否使用GPU加速。如果设置为
true
,则在构建和搜索过程中利用GPU资源以提高性能。
2.2 插入数据
遍历文本segment,创建 Embeddings,然后将数据插入 HetuVDB。
String ip = "your ip";
int port = 11434;
String model = "nomic-embed-text";
for (String segment : segments) {
if (!segment.isEmpty()) {
OllamaEmbeddingUtils.EmbedResponse embedResponse = new OllamaEmbeddingUtils().embed(ip, port, model, segment);
float[] vector = embedResponse.getEmbeddings().get(0);
he.Vadd(segment, vector);
}
}
3 构建RAG
3.1 为查询检索数据
让我们指定一个关于 HetuVDB 的常见问题。
String question = "我想要了解HetuKV卷的概念以及在使用过程中出现的-102代码code错误";
在HetuVDB中搜索该问题,并检索语义前4个匹配项。
float[] questionVector = new OllamaEmbeddingUtils().embed(ip, port, model, question).getEmbeddings().get(0);
Map<String, float[]> nearestSegment = he.VfindNearest(questionVector, 4);
for (Map.Entry<String, float[]> entry : nearestSegment.entrySet()) {
System.out.println(entry.getKey());
}
让我们看看查询的搜索结果:
**HetuKV 库**
HetuKV有专门的嵌入式库,提供了一系列的函数及其相关的类型、结构和常量。
**HetuKV 键/值项(item)**
一个item包含一个键、一个值,以及键和值数据块的关联长度。HetuKV假定键和值是数据的二进制块。
**HetuKV 事务 (Transaction)**
一个隔离的操作序列,可以被丢弃或原子性地与数据存储合并。
**HetuKV 卷 (Volume)**
一个或多个块设备或固定大小文件捆绑成单个卷(由HetuKV管理),为数据存储提供单个大型存储结构。不允许创建包含一个或多个HetuKV目录的卷。
3.2 使用DeepSeek获取RAG响应
将检索到的文档直接加入到用户问题的集合里面。
使用 DeepSeek 提供的deepseek-chat 模型,根据提示生成响应。
DeepSeekClient apiClient = new DeepSeekClient(
"Your DeepSeek API Key");
List<String> messages = new ArrayList<>();
messages.add(question);
for (Map.Entry<String, float[]> entry : nearestSegment.entrySet()) {
messages.add(entry.getKey());
}
JSONObject requestBody = apiClient.chat("deepseek-chat", messages, false);
try {
String response = apiClient.sendRequest(requestBody);
DeepSeekClient.DeepSeekResponse parsedResponse = apiClient.parseResponse(response);
System.out.println("Parsed Response: " + parsedResponse.getContent());
} catch (IOException e) {
e.printStackTrace();
}
查看DeepSeek的返回信息:
### HetuKV 卷的概念
在 HetuKV 中,**卷(Volume)** 是一个或多个块设备或固定大小文件的集合,这些设备或文件被捆绑在一起,形成一个单一的存储结构。HetuKV 使用卷来管理数据存储,卷为数据存储提供了一个大型的、连续的存储空间。卷的设计允许 HetuKV 在多个设备或文件之间进行数据分布和管理,从而提高存储的灵活性和性能。
#### 关键点:
1. **卷的组成**:卷可以由一个或多个块设备(如硬盘分区)或固定大小的文件组成。这些设备或文件被 HetuKV 视为一个整体,形成一个逻辑上的存储单元。
2. **存储结构**:卷为 HetuKV 提供了一个大型的存储结构,HetuKV 可以在卷中存储键/值对、事务日志等数据。
3. **卷的管理**:HetuKV 负责管理卷中的数据分布、读写操作以及数据的持久化。卷的管理是透明的,用户只需要通过 HetuKV 提供的 API 来操作数据,而不需要直接管理底层的存储设备或文件。
4. **卷的限制**:HetuKV 不允许创建包含一个或多个 HetuKV 目录的卷。这意味着卷是独立的存储单元,不能嵌套或包含其他 HetuKV 管理的目录结构。
### 错误代码 -102
在使用 HetuKV 的过程中,可能会遇到错误代码 **-102**。这个错误代码通常表示某种与卷相关的操作失败。具体的错误原因可能包括以下几种情况:
1. **卷初始化失败**:在创建或打开卷时,HetuKV 可能无法正确初始化卷。这可能是由于底层存储设备或文件不可用、权限不足、文件损坏等原因导致的。
2. **卷空间不足**:如果卷的存储空间不足,HetuKV 可能无法继续写入数据,从而导致操作失败并返回错误代码 -102。
3. **卷损坏**:如果卷的底层存储设备或文件损坏,HetuKV 可能无法正确读取或写入数据,从而导致操作失败。
4. **卷配置错误**:如果卷的配置参数不正确(例如,卷的大小设置错误),HetuKV 可能无法正确管理卷,从而导致操作失败。
### 解决方法
当遇到错误代码 -102 时,可以尝试以下步骤来排查和解决问题:
1. **检查卷的存储设备或文件**:确保卷所使用的块设备或文件是可用的,并且具有正确的权限。如果使用的是文件作为卷,确保文件没有被损坏或删除。
2. **检查卷的空间**:使用 HetuKV 提供的工具或 API 检查卷的剩余空间。如果空间不足,可以考虑扩展卷的大小或清理不必要的数据。
3. **检查卷的配置**:确保卷的配置参数(如大小、路径等)是正确的。如果配置错误,可以尝试重新创建卷或调整配置。
4. **查看日志**:HetuKV 通常会记录详细的日志信息。查看日志可以帮助你更准确地定位问题的根源。
5. **联系支持**:如果问题无法通过上述步骤解决,可以联系 HetuKV 的支持团队,提供详细的错误信息和日志,以便进一步排查问题。
### 总结
HetuKV 的卷是一个重要的存储管理单元,它通过将多个块设备或文件捆绑在一起,提供了一个大型的存储结构。错误代码 -102 通常与卷的操作失败有关,可能由卷初始化失败、空间不足、卷损坏或配置错误等原因引起。通过检查存储设备、卷空间、配置参数以及查看日志,可以帮助你解决这个问题。
至此,我们成功地利用 HetuVDB 和 DeepSeek 搭建了一条 RAG 管道!
3.3 DeepSeek未构建RAG对比
我们还是使用同一个问题:"我想要了解HetuKV卷的概念以及在使用过程中出现的-102代码code错误"
DeepSeek的回答如下:
HetuKV 卷的概念
HetuKV 是一种分布式键值存储系统,通常用于大规模数据存储和高并发访问场景。卷(Volume) 在 HetuKV 中指的是存储数据的逻辑单元,类似于传统文件系统中的分区或卷。每个卷可以独立管理,具有自己的存储空间和数据分布策略。
主要特点:
分布式存储:数据分布在多个节点上,支持高可用性和扩展性。
高并发访问:支持大量并发读写操作。
数据分片:通过分片(Sharding)将数据分散到不同节点,提升性能。
副本机制:通过数据副本提高容错能力。
-102 代码错误
在使用 HetuKV 时,-102 错误代码 通常表示某种类型的操作失败,具体含义需参考 HetuKV 的官方文档或源码。常见原因包括:
网络问题:节点间通信失败。
资源不足:如内存或磁盘空间不足。
配置错误:配置文件参数设置不当。
数据不一致:副本间数据不一致导致操作失败。
权限问题:操作权限不足。
解决方法
检查网络:确保节点间网络通畅。
查看日志:通过日志定位具体错误。
资源监控:检查系统资源使用情况,必要时释放资源。
验证配置:确保配置文件正确。
数据一致性检查:使用工具检查并修复数据不一致问题。
权限检查:确认操作权限是否足够。
总结
HetuKV 的卷是逻辑存储单元,支持分布式存储和高并发访问。-102 错误通常表示操作失败,可能由网络、资源、配置、数据一致性或权限问题引起。通过检查网络、日志、资源、配置、数据一致性和权限,可以逐步解决问题。
总结:通过以上对比可以明显看到,使用HetuVDB与DeepSeek构建RAG生成内容的质量得到显著提升,而且更加准确、全面和可信。这种技术组合为构建高质量的私有知识库提供了强大的支持。
在后续的文章我们将陆续展示如何在蓬莱硬件环境中部署DeepSeek R1。
网址:https://www.penglaitech.cn/
邮箱:business@penglaitech.cn
地址:广东省深圳市宝安区宝兴路6号海纳百川总部大厦A座1501
电话:0755-26406747 (工作日 9:00-18:30)