mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-13 03:13:41 +08:00
feat(wiki): instrument compile / relation / retrieval with WikiMetrics
This commit is contained in:
parent
4f96a46900
commit
6f0ead162e
@ -8,11 +8,13 @@ import vip.mate.wiki.WikiProperties;
|
||||
import vip.mate.wiki.dto.PageSearchResult;
|
||||
import vip.mate.wiki.dto.RelatedPageResult;
|
||||
import vip.mate.wiki.dto.WikiPageLite;
|
||||
import vip.mate.wiki.metrics.WikiMetrics;
|
||||
import vip.mate.wiki.model.WikiChunkEntity;
|
||||
import vip.mate.wiki.model.WikiPageEntity;
|
||||
import vip.mate.wiki.repository.WikiPageMapper;
|
||||
import vip.mate.wiki.retrieval.SnippetExtractor;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -32,6 +34,7 @@ public class HybridRetriever {
|
||||
private final WikiEmbeddingService embeddingService;
|
||||
private final WikiProperties properties;
|
||||
private final WikiPageMapper pageMapper;
|
||||
private final WikiMetrics metrics;
|
||||
|
||||
@Autowired(required = false)
|
||||
private WikiRelationService relationService;
|
||||
@ -42,12 +45,14 @@ public class HybridRetriever {
|
||||
WikiChunkService chunkService,
|
||||
WikiEmbeddingService embeddingService,
|
||||
WikiProperties properties,
|
||||
WikiPageMapper pageMapper) {
|
||||
WikiPageMapper pageMapper,
|
||||
WikiMetrics metrics) {
|
||||
this.pageService = pageService;
|
||||
this.chunkService = chunkService;
|
||||
this.embeddingService = embeddingService;
|
||||
this.properties = properties;
|
||||
this.pageMapper = pageMapper;
|
||||
this.metrics = metrics;
|
||||
}
|
||||
|
||||
public enum Mode { KEYWORD, SEMANTIC, HYBRID }
|
||||
@ -79,6 +84,8 @@ public class HybridRetriever {
|
||||
public List<PageSearchResult> search(Long kbId, String query, String modeStr, int topK) {
|
||||
Mode mode = parseMode(modeStr);
|
||||
|
||||
long startNanos = System.nanoTime();
|
||||
|
||||
List<RankedItem> semantic = List.of();
|
||||
List<RankedItem> keyword = List.of();
|
||||
|
||||
@ -107,7 +114,11 @@ public class HybridRetriever {
|
||||
|
||||
// Batch-fetch page info (N+1 fix)
|
||||
List<Long> topIds = fused.stream().limit(topK).map(ri -> ri.pageId).toList();
|
||||
if (topIds.isEmpty()) return List.of();
|
||||
if (topIds.isEmpty()) {
|
||||
metrics.recordRetrieval(mode.name().toLowerCase(),
|
||||
Duration.ofNanos(System.nanoTime() - startNanos), 0);
|
||||
return List.of();
|
||||
}
|
||||
|
||||
Map<Long, WikiPageLite> liteMap = pageMapper.selectBatchLite(topIds)
|
||||
.stream().collect(Collectors.toMap(WikiPageLite::id, p -> p));
|
||||
@ -142,6 +153,8 @@ public class HybridRetriever {
|
||||
snippet != null ? snippet : lite.summary(),
|
||||
ri.matchedBy, reason, ri.score));
|
||||
}
|
||||
metrics.recordRetrieval(mode.name().toLowerCase(),
|
||||
Duration.ofNanos(System.nanoTime() - startNanos), results.size());
|
||||
return results;
|
||||
}
|
||||
|
||||
|
||||
@ -14,10 +14,12 @@ import org.springframework.stereotype.Service;
|
||||
import vip.mate.agent.prompt.PromptLoader;
|
||||
import vip.mate.wiki.job.WikiJobStep;
|
||||
import vip.mate.wiki.job.WikiModelRoutingService;
|
||||
import vip.mate.wiki.metrics.WikiMetrics;
|
||||
import vip.mate.wiki.model.WikiChunkEntity;
|
||||
import vip.mate.wiki.model.WikiPageEntity;
|
||||
import vip.mate.wiki.repository.WikiChunkMapper;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@ -43,6 +45,7 @@ public class WikiCompileService {
|
||||
private final WikiPageService pageService;
|
||||
private final WikiCitationService citationService;
|
||||
private final ObjectMapper objectMapper;
|
||||
private final WikiMetrics metrics;
|
||||
|
||||
/**
|
||||
* Optional. When wired we use the routing chain (stepModels[CREATE_PAGE]
|
||||
@ -91,12 +94,16 @@ public class WikiCompileService {
|
||||
int cap = (maxEvidenceChunks == null || maxEvidenceChunks <= 0)
|
||||
? 8 : Math.min(20, maxEvidenceChunks);
|
||||
|
||||
long startNanos = System.nanoTime();
|
||||
|
||||
// 1. Retrieve evidence chunks via semantic search (hybrid retriever).
|
||||
List<HybridRetriever.ChunkHit> hits = hybridRetriever.searchChunks(kbId, topic, cap);
|
||||
if (hits.isEmpty()) {
|
||||
// Structured "nothing matched" result rather than throw — lets the
|
||||
// tool surface respond with a clean message instead of a stack trace.
|
||||
log.info("[WikiCompile] No evidence chunks for topic='{}' kbId={}", topic, kbId);
|
||||
metrics.recordCompileStage("no_evidence", kbId,
|
||||
Duration.ofNanos(System.nanoTime() - startNanos));
|
||||
return CompileResult.noEvidence();
|
||||
}
|
||||
|
||||
@ -186,6 +193,8 @@ public class WikiCompileService {
|
||||
}
|
||||
if (overviewService != null) overviewService.rebuild(kbId);
|
||||
|
||||
metrics.recordCompileStage("compile_page", kbId,
|
||||
Duration.ofNanos(System.nanoTime() - startNanos));
|
||||
return new CompileResult(persisted.getId(), resolvedSlug, title, evidenceChunkIds.size(), created);
|
||||
}
|
||||
|
||||
|
||||
@ -3,11 +3,13 @@ package vip.mate.wiki.service;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import vip.mate.wiki.dto.*;
|
||||
import vip.mate.wiki.metrics.WikiMetrics;
|
||||
import vip.mate.wiki.model.WikiPageEntity;
|
||||
import vip.mate.wiki.relation.RelationSignalStrategy;
|
||||
import vip.mate.wiki.repository.WikiPageCitationMapper;
|
||||
import vip.mate.wiki.repository.WikiPageMapper;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -23,15 +25,18 @@ public class WikiRelationService {
|
||||
private final WikiPageMapper pageMapper;
|
||||
private final WikiPageService pageService;
|
||||
private final WikiPageCitationMapper citationMapper;
|
||||
private final WikiMetrics metrics;
|
||||
|
||||
public WikiRelationService(List<RelationSignalStrategy> signals,
|
||||
WikiPageMapper pageMapper,
|
||||
WikiPageService pageService,
|
||||
WikiPageCitationMapper citationMapper) {
|
||||
WikiPageCitationMapper citationMapper,
|
||||
WikiMetrics metrics) {
|
||||
this.signals = signals;
|
||||
this.pageMapper = pageMapper;
|
||||
this.pageService = pageService;
|
||||
this.citationMapper = citationMapper;
|
||||
this.metrics = metrics;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -41,6 +46,8 @@ public class WikiRelationService {
|
||||
WikiPageEntity seed = pageService.getBySlug(kbId, seedSlug);
|
||||
if (seed == null) return List.of();
|
||||
|
||||
long startNanos = System.nanoTime();
|
||||
|
||||
Map<Long, Double> totalScores = new HashMap<>();
|
||||
Map<Long, List<String>> signalHits = new HashMap<>();
|
||||
|
||||
@ -62,6 +69,13 @@ public class WikiRelationService {
|
||||
.map(Map.Entry::getKey)
|
||||
.toList();
|
||||
|
||||
// Reports both compute duration and the candidate-set size.
|
||||
// Cache hit/miss is reported once a relation cache layer is wired up;
|
||||
// until then every call is a cold compute by definition.
|
||||
metrics.recordRelationCompute(kbId, totalScores.size(),
|
||||
Duration.ofNanos(System.nanoTime() - startNanos));
|
||||
metrics.recordRelationCacheHit(false);
|
||||
|
||||
if (topIds.isEmpty()) return List.of();
|
||||
Map<Long, WikiPageLite> liteMap = pageMapper.selectBatchLite(topIds)
|
||||
.stream().collect(Collectors.toMap(WikiPageLite::id, l -> l));
|
||||
|
||||
Loading…
Reference in New Issue
Block a user