fix(ai-chat): 优化引用文档ID处理支持字符串数组类型

- 将数据库中 referenced_doc_ids 字段从 BIGINT[] 修改为 VARCHAR(255)[]
- 在实体类 AiChatMessage 中将 referencedDocIds 类型改为 String[] 并添加自定义类型处理器
- 新增 PostgresArrayTypeHandler 用于处理 PostgreSQL varchar 数组与 Java String[] 的映射
- 修改查询时 project_id 和 timeline_node_id 的过滤表达式,使用字符串匹配避免类型错误
- AiChatServiceImpl 中保存消息时改用字符串数组保存引用文档ID
- KbDocumentVO 新增 fileUrl 字段映射数据库中对应字段
- 数据库映射文件 AiDocumentMapper.xml 增加 file_url 字段映射
This commit is contained in:
2026-03-30 18:59:52 +08:00
parent 0b011bf1a7
commit 8008d367e8
7 changed files with 81 additions and 9 deletions

View File

@@ -134,9 +134,14 @@ public class AiChatServiceImpl implements AiChatService {
() -> {
// 保存助手消息
int responseTime = (int) (System.currentTimeMillis() - startTime);
// 提取引用的文档ID列表
String[] docIds = retrievedDocs.stream()
.map(doc -> doc.getMetadata().getOrDefault("doc_id", "").toString())
.filter(id -> !id.isEmpty())
.toArray(String[]::new);
Long messageId = saveMessage(finalSessionId, userId, request.getProjectId(),
request.getTimelineNodeId(), "assistant",
fullResponse.toString(), JSON.toJSONString(referencedDocs));
fullResponse.toString(), docIds);
// 发送完成消息
sendEvent(emitter, "complete", Map.of(
@@ -334,7 +339,7 @@ public class AiChatServiceImpl implements AiChatService {
*/
private Long saveMessage(String sessionId, Long userId, Long projectId,
Long timelineNodeId, String role, String content,
String referencedDocIds) {
String[] referencedDocIds) {
// 获取当前最大序号
Integer maxIndex = chatHistoryMapper.selectMaxMessageIndex(sessionId);
int nextIndex = (maxIndex != null ? maxIndex : 0) + 1;

View File

@@ -41,10 +41,11 @@ public class RagRetriever {
*/
public List<Document> vectorSearch(String query, Long projectId, int topK) {
try {
// project_id 在 metadata 中是字符串类型,需要用字符串比较
SearchRequest searchRequest = SearchRequest.builder()
.query(query)
.topK(topK)
.filterExpression("project_id == " + projectId + " && status == 'active'")
.filterExpression("project_id == '" + projectId + "' && status == 'active'")
.build();
List<Document> results = vectorStore.similaritySearch(searchRequest);
@@ -68,12 +69,13 @@ public class RagRetriever {
public List<Document> vectorSearchWithTimeline(String query, Long projectId,
Long timelineNodeId, int topK) {
try {
// project_id 和 timeline_node_id 在 metadata 中是字符串类型
SearchRequest searchRequest = SearchRequest.builder()
.query(query)
.topK(topK)
.filterExpression("project_id == " + projectId +
" && timeline_node_id == " + timelineNodeId +
" && status == 'active'")
.filterExpression("project_id == '" + projectId +
"' && timeline_node_id == '" + timelineNodeId +
"' && status == 'active'")
.build();
List<Document> results = vectorStore.similaritySearch(searchRequest);