优化返回逻辑
This commit is contained in:
parent
e6cf18fa45
commit
bf2363b7ce
@ -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);
|
||||||
|
|||||||
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -23,7 +23,7 @@ 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 事件
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user