fix: 兼容旧模型内联思考标签
- 在结构化 reasoning 为空时解析正文开头的 think/thinking 标签 - 将思考与正文映射为现有流式事件并覆盖 Agent 与 Bot 链路 - 补充跨分片和旁路条件测试
This commit is contained in:
@@ -32,6 +32,7 @@ import tech.easyflow.core.runtime.ChatAssistantAccumulator;
|
||||
import tech.easyflow.core.runtime.ChatRuntimeContext;
|
||||
import tech.easyflow.core.runtime.ChatRuntimeManager;
|
||||
import tech.easyflow.core.runtime.ChatRuntimeMessage;
|
||||
import tech.easyflow.core.runtime.LegacyThinkingTagParser;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.math.BigInteger;
|
||||
@@ -176,6 +177,59 @@ public class AgentRunServiceDraftAndHitlTest {
|
||||
Assert.assertEquals("正文增量", payload.get("delta"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证旧模型写入 content 的思考标签即使跨增量拆分,也会转换为结构化思考事件。
|
||||
*
|
||||
* @throws Exception 反射调用失败时抛出
|
||||
*/
|
||||
@Test
|
||||
public void handleRuntimeEventShouldSplitLegacyThinkingTagsAcrossDeltas() throws Exception {
|
||||
AgentRunService service = new AgentRunService();
|
||||
setField(service, "agentRunRegistry", new AgentRunRegistry());
|
||||
RecordingChatSseEmitter emitter = new RecordingChatSseEmitter();
|
||||
StringBuilder answer = new StringBuilder();
|
||||
ChatAssistantAccumulator assistantAccumulator = new ChatAssistantAccumulator();
|
||||
LegacyThinkingTagParser parser = new LegacyThinkingTagParser();
|
||||
AtomicBoolean finished = new AtomicBoolean(false);
|
||||
|
||||
for (String delta : List.of("<thi", "nk>先分析</thi", "nk>\n最终回答")) {
|
||||
AgentRuntimeEvent event = AgentRuntimeEvent.of(AgentRuntimeEventType.MESSAGE_DELTA);
|
||||
event.getPayload().put("text", delta);
|
||||
invoke(service, "handleRuntimeEvent",
|
||||
legacyRuntimeEventParameterTypes(),
|
||||
event, "request-legacy-thinking", emitter, answer, assistantAccumulator,
|
||||
parser, chatContext(), finished, false);
|
||||
}
|
||||
|
||||
AgentRuntimeEvent completed = AgentRuntimeEvent.of(AgentRuntimeEventType.COMPLETED);
|
||||
completed.getPayload().put("text", "<think>先分析</think>\n最终回答");
|
||||
invoke(service, "handleRuntimeEvent",
|
||||
legacyRuntimeEventParameterTypes(),
|
||||
completed, "request-legacy-thinking", emitter, answer, assistantAccumulator,
|
||||
parser, chatContext(), finished, false);
|
||||
|
||||
StringBuilder reasoning = new StringBuilder();
|
||||
StringBuilder content = new StringBuilder();
|
||||
for (ChatEnvelope<?> envelope : emitter.envelopes) {
|
||||
if (envelope.getDomain() != ChatDomain.LLM) {
|
||||
continue;
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> payload = (Map<String, Object>) envelope.getPayload();
|
||||
if (envelope.getType() == ChatType.THINKING) {
|
||||
reasoning.append(payload.get("delta"));
|
||||
} else if (envelope.getType() == ChatType.MESSAGE) {
|
||||
content.append(payload.get("delta"));
|
||||
}
|
||||
}
|
||||
|
||||
Assert.assertEquals("先分析", reasoning.toString());
|
||||
Assert.assertEquals("\n最终回答", content.toString());
|
||||
Assert.assertEquals("\n最终回答", answer.toString());
|
||||
Assert.assertTrue(emitter.envelopes.stream().anyMatch(envelope ->
|
||||
envelope.getDomain() == ChatDomain.SYSTEM && envelope.getType() == ChatType.DONE));
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证自动上下文压缩事件会作为业务状态发送给前端。
|
||||
*
|
||||
@@ -809,6 +863,12 @@ public class AgentRunServiceDraftAndHitlTest {
|
||||
ChatRuntimeContext.class, AtomicBoolean.class, boolean.class};
|
||||
}
|
||||
|
||||
private Class<?>[] legacyRuntimeEventParameterTypes() {
|
||||
return new Class<?>[]{AgentRuntimeEvent.class, String.class, ChatSseEmitter.class, StringBuilder.class,
|
||||
ChatAssistantAccumulator.class, LegacyThinkingTagParser.class,
|
||||
ChatRuntimeContext.class, AtomicBoolean.class, boolean.class};
|
||||
}
|
||||
|
||||
private AgentRunRegistry.AgentRunContext runContext(String requestId, String sessionId, boolean persistChatlog) {
|
||||
return new AgentRunRegistry.AgentRunContext(
|
||||
requestId,
|
||||
|
||||
Reference in New Issue
Block a user