fix(wiki): skip per-turn retrieval for continuation messages + drop weak tail hits

This commit is contained in:
matevip 2026-05-04 20:54:44 +08:00
parent 2e0ff8f90f
commit eb64556636
2 changed files with 52 additions and 0 deletions

View File

@ -133,6 +133,22 @@ public class WikiProperties {
/** 混合搜索默认模式keyword / semantic / hybrid */
private String searchDefaultMode = "hybrid";
/**
* Minimum trimmed char length for a user message before per-turn wiki
* retrieval kicks in. Short messages like "继续" / "" / "OK" carry no
* semantic signal and the retriever falls back to whichever pages happen
* to dominate the index, polluting the prompt with off-topic content.
*/
private int relevantContextMinQueryLength = 3;
/**
* Relative score floor for relevant-wiki hits. A hit is dropped when its
* score is below {@code topHit.score * this ratio}, so a single strong
* match does not drag in low-relevance tail pages alongside it. Set to
* 0 to disable.
*/
private double relevantContextMinRelativeScore = 0.5;
// ==================== RFC-031: Light processing tiers ====================
/** Whether to auto-dispatch a LIGHT_ENRICH job after heavy ingest completes */

View File

@ -9,6 +9,8 @@ import vip.mate.wiki.model.WikiKnowledgeBaseEntity;
import vip.mate.wiki.model.WikiPageEntity;
import java.util.List;
import java.util.Locale;
import java.util.Set;
/**
* Wiki context service builds context for agent conversation injection.
@ -26,6 +28,18 @@ public class WikiContextService {
private final HybridRetriever hybridRetriever;
private final WikiProperties properties;
/**
* Continuation / acknowledgement tokens. When the user message reduces to
* one of these the per-turn retrieval is skipped these queries carry no
* topical signal and the retriever otherwise returns whichever pages
* dominate the index, derailing the conversation onto unrelated content.
*/
private static final Set<String> CONTINUATION_TOKENS = Set.of(
"继续", "继续吧", "继续做", "继续输出", "继续完成", "请继续",
"好的", "", "", "嗯嗯", "是的", "", "对的",
"ok", "okay", "go on", "next", "continue", "yes", "yeah", "sure", "y"
);
/**
* Build relevant wiki context for the current user message.
* <p>
@ -37,6 +51,16 @@ public class WikiContextService {
return "";
}
// Skip retrieval for continuation / acknowledgement turns observed
// in production: a user reply of "继续" produced top-5 hits dominated
// by the wiki KB's most-cited pages and rerouted four parallel
// multi-agent tasks onto unrelated topics.
String trimmed = userMessage.trim();
if (trimmed.length() < properties.getRelevantContextMinQueryLength()
|| CONTINUATION_TOKENS.contains(trimmed.toLowerCase(Locale.ROOT))) {
return "";
}
List<WikiKnowledgeBaseEntity> kbs = kbService.listByAgentId(agentId);
if (kbs.isEmpty()) {
return "";
@ -48,6 +72,18 @@ public class WikiContextService {
return "";
}
// Drop tail hits that score far below the top hit so a single strong
// match isn't accompanied by 4 weakly-related pages.
double minRel = properties.getRelevantContextMinRelativeScore();
if (minRel > 0 && hits.size() > 1) {
double topScore = hits.get(0).score();
double floor = topScore * minRel;
hits = hits.stream().filter(h -> h.score() >= floor).toList();
if (hits.isEmpty()) {
return "";
}
}
StringBuilder sb = new StringBuilder("<wiki-relevant>\n");
sb.append("[Relevant wiki pages for this query. Use wiki_read_page(slug) for full content. " +
"When using information from these pages in your answer, always cite the source page title, " +