问题管理
概述
在当前的功能模块中,我们已经完成了多个核心功能,包括数据库设计、用户登录、知识库管理、文件拆分、片段向量化、命中率测试、文档管理以及片段管理。这些功能为存储、管理和处理数据提供了坚实的基础。
接下来,我们将实现 问题管理 功能,该功能旨在为片段指定问题,为大模型推理提供参考依据。通过问题管理,用户可以更高效地组织和利用知识库中的信息,提高系统的智能化水平。
已完成的核心功能
- 数据库设计:提供结构化的支持,确保片段数据的高效存储与管理。
- 用户登录:确保数据访问和操作的安全性,防止未经授权的访问。
- 知识库管理:支持知识库的创建、更新和删除,方便用户维护知识库内容。
- 文件拆分:将上传的文件拆分为多个片段,便于内容的精细化管理。
- 片段向量化:通过向量化技术,将片段内容转换为可计算的向量,便于进行相似度计算。
- 命中率测试:通过计算用户查询与片段的相似度,评估系统的匹配效果。
- 文档管理:实现对不同文档内容的管理,支持多文档的高效处理。
- 片段管理:实现对不同文档片段的管理,支持片段的增删改查操作。
问题管理功能
功能介绍
问题管理功能主要用于给知识库中的片段指定相关问题。这些问题将作为大模型推理的参考依据,提升系统的智能化和响应准确性。通过问题管理,用户可以为每个片段关联一个或多个问题,便于后续的数据分析和处理。
接口设计
1. 创建问题
请求方式:
POST
URL:
http://localhost:3000/api/dataset/{datasetId}/problem
请求负载:
["office hour"]
响应示例:
{ "message": null, "data": ["444834872039501824"], "code": 200 }
2. 获取问题列表
请求方式:
GET
URL:
http://localhost:3000/api/dataset/{datasetId}/problem/{pageNo}/{pageSize}
响应示例:
{ "message": null, "data": { "size": 10, "total": 2, "records": [ { "tenant_id": "0", "creator": "", "update_time": 1731132193047, "deleted": 0, "create_time": 1731132193047, "dataset_id": "443309276048408576", "id": "444831888056446976", "content": "class time", "hit_num": 0, "updater": "" }, { "tenant_id": "0", "creator": "", "update_time": 1731132904550, "deleted": 0, "create_time": 1731132904550, "dataset_id": "443309276048408576", "id": "444834872039501824", "content": "office hour", "hit_num": 0, "updater": "" } ], "current": 1 }, "code": 200 }
3. 关联问题与段落
请求方式:
PUT
URL:
http://localhost:3000/api/dataset/{datasetId}/document/{documentId}/paragraph/{paragraphId}/problem/{problemId}/association
请求负载:
{}
响应示例:
{ "message": null, "data": null, "code": 200 }
4. 取消关联问题与段落
请求方式:
PUT
URL:
http://localhost:3000/api/dataset/{datasetId}/document/{documentId}/paragraph/{paragraphId}/problem/{problemId}/un_association
响应示例:
{ "message": null, "data": null, "code": 200 }
5. 批量添加问题与段落的关联
请求方式:
POST
URL:
http://localhost:3000/api/dataset/{datasetId}/problem/_batch
请求负载:
{ "problem_id_list": ["444831888056446976", "444834872039501824"], "paragraph_list": [ { "paragraph_id": "443662146835439616", "document_id": "443662133182980096" } ] }
响应示例:
{ "message": null, "data": null, "code": 200 }
6. 删除单个问题
请求方式:
DELETE
URL:
http://localhost:3000/api/dataset/{datasetId}/problem/{problemId}
响应示例:
{ "message": null, "data": null, "code": 200 }
7. 批量删除问题
请求方式:
DELETE
URL:
http://localhost:3000/api/dataset/{datasetId}/problem/_batch
请求负载:
["445226726791389184", "445226726791389185"]
响应示例:
{ "message": null, "data": null, "code": 200 }
8. 根据问题 ID 获取关联的段落
请求方式:
GET
URL:
http://localhost:3000/api/dataset/{datasetId}/problem/{problemId}/paragraph
响应示例:
{ "message": null, "data": [{ "id": "443662143056371712" }], "code": 200 }
代码实现
以下是问题管理功能的代码实现,包括 API 控制器和服务层。
API 控制器
@RequestPath("/api/dataset")
public class ApiDatasetController {
@Post("/{datasetId}/problem")
public ResultVo createProblem(Long datasetId, HttpRequest request) {
String bodyString = request.getBodyString();
List<String> problems = JsonUtils.parseArray(bodyString, String.class);
return Aop.get(MaxKbProblemService.class).create(datasetId, problems);
}
@Delete("/{datasetId}/problem/_batch")
public ResultVo deleteProblemBatch(Long datasetId, HttpRequest request) {
String bodyString = request.getBodyString();
List<Long> problems = JsonUtils.parseArray(bodyString, Long.class);
return Aop.get(MaxKbProblemService.class).delete(datasetId, problems);
}
@Get("/{datasetId}/problem/{pageNo}/{pageSize}")
public ResultVo pageDatasetProbleam(Long datasetId, Integer pageNo, Integer pageSize) {
return Aop.get(MaxKbProblemService.class).page(datasetId, pageNo, pageSize);
}
@Get("/{datasetId}/problem/{problemId}/paragraph")
public ResultVo listParagraphByProblemId(Long datasetId, Long problemId) {
return Aop.get(MaxKbProblemService.class).listParagraphByProblemId(datasetId, problemId);
}
@Put("/{datasetId}/document/{documentId}/paragraph/{paragraphId}/problem/{problemId}/association")
public ResultVo association(Long datasetId, Long documentId, Long paragraphId, Long problemId) {
return Aop.get(MaxKbProblemService.class).association(datasetId, documentId, paragraphId, problemId);
}
@Put("/{datasetId}/document/{documentId}/paragraph/{paragraphId}/problem/{problemId}/un_association")
public ResultVo unAssociation(Long datasetId, Long documentId, Long paragraphId, Long problemId) {
return Aop.get(MaxKbProblemService.class).unAssociation(datasetId, documentId, paragraphId, problemId);
}
@Post("/{datasetId}/problem/_batch")
public ResultVo addProblems(Long datasetId, HttpRequest request) {
String bodyString = request.getBodyString();
ProbrolemCreateBatch batchRequest = JsonUtils.parse(bodyString, ProbrolemCreateBatch.class);
return Aop.get(MaxKbProblemService.class).addProblems(datasetId, batchRequest);
}
@Delete("/{datasetId}/problem/{problemId}")
public ResultVo deleteProblem(Long datasetId, Long problemId) {
return Aop.get(MaxKbProblemService.class).delete(datasetId, problemId);
}
}
服务层实现
package com.litongjava.maxkb.service;
import java.util.ArrayList;
import java.util.List;
import com.jfinal.kit.Kv;
import com.litongjava.db.TableInput;
import com.litongjava.db.TableResult;
import com.litongjava.db.activerecord.Db;
import com.litongjava.db.activerecord.Record;
import com.litongjava.kit.RecordUtils;
import com.litongjava.maxkb.constant.TableNames;
import com.litongjava.maxkb.model.MaxKbParagraphId;
import com.litongjava.maxkb.model.ProbrolemCreateBatch;
import com.litongjava.maxkb.model.ResultPage;
import com.litongjava.model.page.Page;
import com.litongjava.model.result.ResultVo;
import com.litongjava.table.services.ApiTable;
import com.litongjava.tio.utils.snowflake.SnowflakeIdUtils;
public class MaxKbProblemService {
/**
* 创建问题
*
* @param datasetId 数据集ID
* @param problems 问题内容列表
* @return 结果VO
*/
public ResultVo create(Long datasetId, List<String> problems) {
List<Long> ids = new ArrayList<>();
List<Record> records = new ArrayList<>();
for (String string : problems) {
long id = SnowflakeIdUtils.id();
records.add(Record.by("id", id)
.set("content", string)
.set("dataset_id", datasetId)
.set("hit_num", 0));
ids.add(id);
}
Db.batchSave(TableNames.max_kb_problem, records, 2000);
return ResultVo.ok(ids);
}
/**
* 分页获取问题列表
*
* @param datasetId 数据集ID
* @param pageNo 页码
* @param pageSize 页大小
* @return 结果VO
*/
public ResultVo page(Long datasetId, Integer pageNo, Integer pageSize) {
TableInput tableInput = TableInput.create()
.setPageNo(pageNo)
.setPageSize(pageSize);
TableResult<Page<Record>> page = ApiTable.page(TableNames.max_kb_problem, tableInput);
int totalRow = page.getData().getTotalRow();
List<Record> list = page.getData().getList();
List<Kv> kvs = RecordUtils.recordsToKv(list, false);
ResultPage<Kv> resultPage = new ResultPage<>(pageNo, pageSize, totalRow, kvs);
return ResultVo.ok(resultPage);
}
/**
* 批量删除问题
*
* @param datasetId 数据集ID
* @param ids 问题ID列表
* @return 结果VO
*/
public ResultVo delete(Long datasetId, List<Long> ids) {
ApiTable.deleteByIds(TableNames.max_kb_problem, ids);
ApiTable.deleteByIds(TableNames.max_kb_problem_paragraph_mapping, "problem_id", ids);
return ResultVo.ok();
}
/**
* 删除单个问题
*
* @param datasetId 数据集ID
* @param problemId 问题ID
* @return 结果VO
*/
public ResultVo delete(Long datasetId, Long problemId) {
ApiTable.delById(TableNames.max_kb_problem, problemId);
ApiTable.delById(TableNames.max_kb_problem_paragraph_mapping, "problem_id", problemId);
return ResultVo.ok();
}
/**
* 根据问题ID列出关联的段落
*
* @param datasetId 数据集ID
* @param problemId 问题ID
* @return 结果VO
*/
public ResultVo listParagraphByProblemId(Long datasetId, Long problemId) {
List<Kv> datas = new ArrayList<>();
TableInput tableInput = TableInput.by("dataset_id", datasetId)
.set("problem_id", problemId)
.columns("paragraph_id as id");
TableResult<List<Record>> tableResult = ApiTable.list(TableNames.max_kb_problem_paragraph_mapping, tableInput);
List<Record> records = tableResult.getData();
if (records != null) {
datas = RecordUtils.recordsToKv(records, false);
}
return ResultVo.ok(datas);
}
/**
* 关联问题与段落
*
* @param datasetId 数据集ID
* @param documentId 文档ID
* @param paragraphId 段落ID
* @param problemId 问题ID
* @return 结果VO
*/
public ResultVo association(Long datasetId, Long documentId, Long paragraphId, Long problemId) {
long id = SnowflakeIdUtils.id();
Record record = Record.by("id", id)
.set("dataset_id", datasetId)
.set("document_id", documentId)
.set("paragraph_id", paragraphId)
.set("problem_id", problemId);
boolean save = Db.save(TableNames.max_kb_problem_paragraph_mapping, record);
if (save) {
return ResultVo.ok();
} else {
return ResultVo.fail();
}
}
/**
* 取消关联问题与段落
*
* @param datasetId 数据集ID
* @param documentId 文档ID
* @param paragraphId 段落ID
* @param problemId 问题ID
* @return 结果VO
*/
public ResultVo unAssociation(Long datasetId, Long documentId, Long paragraphId, Long problemId) {
Record record = Record.by("dataset_id", datasetId)
.set("document_id", documentId)
.set("paragraph_id", paragraphId)
.set("problem_id", problemId);
boolean ok = Db.delete(TableNames.max_kb_problem_paragraph_mapping, record);
if (ok) {
return ResultVo.ok();
} else {
return ResultVo.fail();
}
}
/**
* 批量添加问题与段落的关联
*
* @param datasetId 数据集ID
* @param batchRequest 批量请求对象
* @return 结果VO
*/
public ResultVo addProblems(Long datasetId, ProbrolemCreateBatch batchRequest) {
List<MaxKbParagraphId> paragraphList = batchRequest.getParagraph_list();
List<Long> problemIdList = batchRequest.getProblem_id_list();
List<Record> mappings = new ArrayList<>();
for (MaxKbParagraphId maxKbParagraphId : paragraphList) {
Long documentId = maxKbParagraphId.getDocument_id();
Long paragraphId = maxKbParagraphId.getParagraph_id();
for (Long problemId : problemIdList) {
long id = SnowflakeIdUtils.id();
Record record = Record.by("id", id)
.set("dataset_id", datasetId)
.set("document_id", documentId)
.set("paragraph_id", paragraphId)
.set("problem_id", problemId);
mappings.add(record);
}
}
Db.batchSave(TableNames.max_kb_problem_paragraph_mapping, mappings, 2000);
return ResultVo.ok();
}
}
关键功能解析
创建问题:
- 接收问题内容列表,通过雪花算法生成唯一 ID,并保存到
max_kb_problem
表中。 - 返回创建成功的所有问题 ID。
- 接收问题内容列表,通过雪花算法生成唯一 ID,并保存到
分页获取问题列表:
- 根据提供的页码和页大小,从
max_kb_problem
表中分页查询问题。 - 返回包含问题详细信息的分页结果。
- 根据提供的页码和页大小,从
关联问题与段落:
- 在
max_kb_problem_paragraph_mapping
表中插入关联记录,实现问题与段落的关联。 - 关联成功返回成功响应,失败则返回失败信息。
- 在
取消关联问题与段落:
- 根据提供的关联信息,从
max_kb_problem_paragraph_mapping
表中删除对应的记录。 - 取消关联成功返回成功响应,失败则返回失败信息。
- 根据提供的关联信息,从
批量添加问题与段落的关联:
- 接收批量问题 ID 和段落列表,生成对应的关联记录,并批量插入到
max_kb_problem_paragraph_mapping
表中。 - 返回操作成功的响应。
- 接收批量问题 ID 和段落列表,生成对应的关联记录,并批量插入到
删除单个问题:
- 根据问题 ID,从
max_kb_problem
表中删除对应的问题记录。 - 同时删除与该问题关联的段落记录,确保数据一致性。
- 返回操作成功的响应。
- 根据问题 ID,从
批量删除问题:
- 接收问题 ID 列表,批量删除
max_kb_problem
表中的问题记录。 - 同时批量删除与这些问题关联的段落记录。
- 返回操作成功的响应。
- 接收问题 ID 列表,批量删除
根据问题 ID 获取关联的段落:
- 根据提供的问题 ID,从
max_kb_problem_paragraph_mapping
表中查询关联的段落 ID。 - 返回关联段落的列表。
- 根据提供的问题 ID,从
前端示例
总结
通过上述问题管理功能的全面实现,系统能够更高效地管理知识库中的问题与片段的关联关系,为大模型推理提供精准的参考依据。这不仅提升了系统的智能化水平,也为用户提供了更加便捷的数据管理工具。