优化返回逻辑

This commit is contained in:
luke 2025-06-23 18:00:49 +08:00
parent e6cf18fa45
commit bf2363b7ce
3 changed files with 72 additions and 4 deletions

View File

@ -1,6 +1,7 @@
package com.knowledge.base.application.service; package com.knowledge.base.application.service;
import com.knowledge.base.infrastructure.south.llm.LLMServiceFactory; import com.knowledge.base.infrastructure.south.llm.LLMServiceFactory;
import com.knowledge.base.infrastructure.util.http.FilteredSseOutputAdapter;
import com.knowledge.base.infrastructure.util.http.SseOutputAdapter; import com.knowledge.base.infrastructure.util.http.SseOutputAdapter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -24,10 +25,11 @@ public class LLMAppServiceImpl implements LLMAppService {
@Override @Override
public SseEmitter ask(String llmToken, String question, Map<String, Object> params) throws Exception { public SseEmitter ask(String llmToken, String question, Map<String, Object> params) throws Exception {
SseEmitter emitter = new SseEmitter(0L); // 不超时 SseEmitter emitter = new SseEmitter(0L); // 不超时
SseOutputAdapter writer = new SseOutputAdapter(emitter);
try { try {
llmServiceFactory.current().streamAnswer(llmToken, question, params, writer); FilteredSseOutputAdapter adapter = new FilteredSseOutputAdapter(emitter);
llmServiceFactory.current().streamAnswer(llmToken, question, params, adapter);
adapter.flushLastChunk(); // 收尾发一次 sources
emitter.complete(); emitter.complete();
} catch (Exception e) { } catch (Exception e) {
log.error("LLM调用异常", e); log.error("LLM调用异常", e);

View File

@ -0,0 +1,66 @@
package com.knowledge.base.infrastructure.util.http;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class FilteredSseOutputAdapter implements WriterAdapter {
private final SseEmitter emitter;
private static final ObjectMapper mapper = new ObjectMapper();
private Map<String, Object> lastChunk = new HashMap<>();
public FilteredSseOutputAdapter(SseEmitter emitter) {
this.emitter = emitter;
}
@Override
public void writeLine(String line) throws IOException {
if (line == null || line.isBlank()) return;
if (line.startsWith("data:")) {
line = line.substring(5).trim();
}
try {
Map<String, Object> original = mapper.readValue(line, Map.class);
Map<String, Object> filtered = new HashMap<>();
// 累积 textResponse
if (original.containsKey("textResponse")) {
filtered.put("textResponse", original.get("textResponse"));
lastChunk.put("textResponse", original.get("textResponse"));
}
// 如果含有 sources延迟输出合并到最后一条 textResponse
if (original.containsKey("sources")) {
lastChunk.put("sources", original.get("sources"));
return; // 暂不发送
}
if (!filtered.isEmpty()) {
String payload = mapper.writeValueAsString(filtered);
emitter.send("data: " + payload + "\n\n");
}
} catch (Exception e) {
log.warn("SSE数据解析失败{}", line, e);
}
}
public void flushLastChunk() {
if (lastChunk.isEmpty()) return;
try {
String finalJson = mapper.writeValueAsString(lastChunk);
emitter.send("data: " + finalJson + "\n\n");
} catch (Exception e) {
log.warn("flush 最后一条 SSE 失败", e);
}
}
}

View File

@ -21,9 +21,9 @@ public class SseOutputAdapter implements WriterAdapter {
} }
// 如果 line "data: " 开头则去除该前缀 // 如果 line "data: " 开头则去除该前缀
if (line.startsWith("data: ")) { if (line.startsWith("data:")) {
log.debug("[LLM-SSE] line received: {}", line); log.debug("[LLM-SSE] line received: {}", line);
line = line.substring(6).trim(); line = line.substring(5).trim();
} }
// 发送单行 SSE 事件 // 发送单行 SSE 事件