From eb64556636bd2bee50ea4bb12704f1f20bed6e39 Mon Sep 17 00:00:00 2001 From: matevip Date: Mon, 4 May 2026 20:54:44 +0800 Subject: [PATCH] fix(wiki): skip per-turn retrieval for continuation messages + drop weak tail hits --- .../java/vip/mate/wiki/WikiProperties.java | 16 +++++++++ .../mate/wiki/service/WikiContextService.java | 36 +++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/mateclaw-server/src/main/java/vip/mate/wiki/WikiProperties.java b/mateclaw-server/src/main/java/vip/mate/wiki/WikiProperties.java index 8a3df9f1..cf3b4c00 100644 --- a/mateclaw-server/src/main/java/vip/mate/wiki/WikiProperties.java +++ b/mateclaw-server/src/main/java/vip/mate/wiki/WikiProperties.java @@ -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 */ diff --git a/mateclaw-server/src/main/java/vip/mate/wiki/service/WikiContextService.java b/mateclaw-server/src/main/java/vip/mate/wiki/service/WikiContextService.java index e366276c..d40c2fa1 100644 --- a/mateclaw-server/src/main/java/vip/mate/wiki/service/WikiContextService.java +++ b/mateclaw-server/src/main/java/vip/mate/wiki/service/WikiContextService.java @@ -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 CONTINUATION_TOKENS = Set.of( + "继续", "继续吧", "继续做", "继续输出", "继续完成", "请继续", + "好的", "好", "嗯", "嗯嗯", "是的", "对", "对的", + "ok", "okay", "go on", "next", "continue", "yes", "yeah", "sure", "y" + ); + /** * Build relevant wiki context for the current user message. *

@@ -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 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("\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, " +