fix(agent): answer follow-up questions instead of asking to clarify

The planner falls back to CLARIFY whenever no keyword matches and the model
plan is unavailable or malformed. Mid-conversation that produced a dead end:
a follow-up such as "如果我要报销,一般需要查哪几个文件?" was answered with a
clarification request even though the previous turn had established context.

When a non-media request carries a conversationId and a contextVersion above
zero (i.e. at least one turn has completed), route CLARIFY to KNOWLEDGE_QA
with a grounded knowledge search.

Tradeoff: this also suppresses the deliberate CLARIFY for explicitly vague
phrasing ("你看着办", "帮我处理一下") from the second turn onward, which will
now run a knowledge search instead of asking back. Blank input is still
rejected earlier by requireQuestion.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-25 23:58:30 +08:00
co-authored by Claude Opus 5
parent 73712994c6
commit 7b014765d6
2 changed files with 25 additions and 0 deletions
@@ -26,6 +26,10 @@ import java.time.OffsetDateTime;
import java.util.List;
import java.util.UUID;
import static org.dromara.aihr.agent.AihrAgentDto.Intent.KNOWLEDGE_QA;
import static org.dromara.aihr.agent.AihrAgentDto.ResponseStyle.GROUNDED;
import static org.dromara.aihr.agent.AihrAgentDto.Tool.KNOWLEDGE_SEARCH;
@Service
@RequiredArgsConstructor
public class AihrAgentOrchestrator {
@@ -58,6 +62,12 @@ public class AihrAgentOrchestrator {
throw new ServiceException("附件不能为空", 400);
}
plan = planner.plan(request.question(), media);
if (!media && plan.intent() == Intent.CLARIFY
&& request.contextVersion() != null && request.contextVersion() > 0
&& request.conversationId() != null && !request.conversationId().isBlank()) {
plan = new AgentPlan(KNOWLEDGE_QA, request.question().trim(), KNOWLEDGE_SEARCH,
false, false, GROUNDED);
}
principal = principalResolver.current();
response = media
? executeMedia(plan, request, file, principal)
@@ -87,6 +87,21 @@ class AihrAgentOrchestratorTest {
assertEquals(0, query.callCount);
}
@Test
void clarificationAfterACompletedTurnUsesConversationAwareKnowledge() {
var query = new CapturingQueryService(response("通常需要查报销制度和费用标准。", null, false));
var service = orchestrator(query);
var followUp = new AgentRequest(
"如果我要报销,一般需要查哪几个文件?", "conversation_1", 1L, "P1", null, false);
var result = service.handle(followUp);
assertEquals(KNOWLEDGE_QA, result.intent());
assertEquals(followUp.question(), query.lastRequest.queryText());
assertEquals(AgentStatus.COMPLETED, result.status());
assertEquals(1, query.callCount);
}
@Test
void unavailableDataIsNotReportedAsNoTasks() {
var query = new CapturingQueryService(response(