mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-13 03:13:41 +08:00
fix(wiki): resolve an agent's own knowledge base before shared ones
This commit is contained in:
parent
b0d9bde664
commit
c6d51f8ced
@ -61,12 +61,12 @@ public class WikiContextService {
|
||||
return "";
|
||||
}
|
||||
|
||||
List<WikiKnowledgeBaseEntity> kbs = kbService.listByAgentId(agentId);
|
||||
if (kbs.isEmpty()) {
|
||||
WikiKnowledgeBaseEntity primaryKb = kbService.resolvePrimaryKb(agentId);
|
||||
if (primaryKb == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
Long kbId = kbs.get(0).getId();
|
||||
Long kbId = primaryKb.getId();
|
||||
List<PageSearchResult> hits = hybridRetriever.search(kbId, userMessage, "hybrid", 5);
|
||||
if (hits.isEmpty()) {
|
||||
return "";
|
||||
|
||||
@ -112,6 +112,32 @@ public class WikiKnowledgeBaseService {
|
||||
.orderByDesc(WikiKnowledgeBaseEntity::getUpdateTime));
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the single knowledge base an agent's wiki tools should operate on.
|
||||
* <p>
|
||||
* Prefers a KB explicitly bound to the agent; a shared (agent-less) KB is
|
||||
* only used as a fallback when the agent has no bound KB of its own. This
|
||||
* matters because {@link #listByAgentId} also returns shared KBs, and a
|
||||
* shared KB with a more recent {@code update_time} would otherwise win the
|
||||
* {@code get(0)} pick over the agent's own KB. Within each tier the most
|
||||
* recently updated KB wins. Returns {@code null} when the agent can reach
|
||||
* no knowledge base at all.
|
||||
*/
|
||||
public WikiKnowledgeBaseEntity resolvePrimaryKb(Long agentId) {
|
||||
List<WikiKnowledgeBaseEntity> kbs = listByAgentId(agentId);
|
||||
if (kbs.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if (agentId != null) {
|
||||
for (WikiKnowledgeBaseEntity kb : kbs) {
|
||||
if (agentId.equals(kb.getAgentId())) {
|
||||
return kb;
|
||||
}
|
||||
}
|
||||
}
|
||||
return kbs.get(0);
|
||||
}
|
||||
|
||||
public WikiKnowledgeBaseEntity getById(Long id) {
|
||||
return kbMapper.selectById(id);
|
||||
}
|
||||
|
||||
@ -817,8 +817,8 @@ public class WikiTool {
|
||||
// ==================== Helpers ====================
|
||||
|
||||
private Long resolveKbId(Long agentId) {
|
||||
List<WikiKnowledgeBaseEntity> kbs = kbService.listByAgentId(agentId);
|
||||
return kbs.isEmpty() ? null : kbs.get(0).getId();
|
||||
WikiKnowledgeBaseEntity kb = kbService.resolvePrimaryKb(agentId);
|
||||
return kb == null ? null : kb.getId();
|
||||
}
|
||||
|
||||
private JSONArray resolveSourceFiles(String sourceRawIdsJson) {
|
||||
|
||||
@ -48,7 +48,7 @@ class WikiContextServiceTest {
|
||||
|
||||
WikiKnowledgeBaseEntity kb = new WikiKnowledgeBaseEntity();
|
||||
kb.setId(42L);
|
||||
when(kbService.listByAgentId(any())).thenReturn(List.of(kb));
|
||||
when(kbService.resolvePrimaryKb(any())).thenReturn(kb);
|
||||
|
||||
service = new WikiContextService(kbService, pageService, hybridRetriever, properties);
|
||||
}
|
||||
|
||||
@ -0,0 +1,67 @@
|
||||
package vip.mate.wiki.service;
|
||||
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import vip.mate.wiki.model.WikiKnowledgeBaseEntity;
|
||||
import vip.mate.wiki.repository.WikiKnowledgeBaseMapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link WikiKnowledgeBaseService#resolvePrimaryKb(Long)}.
|
||||
*
|
||||
* <p>{@code listByAgentId} returns both the agent's own KBs and shared
|
||||
* (agent-less) KBs, ordered by {@code update_time} descending. A naive
|
||||
* {@code get(0)} pick therefore hands back whichever KB was touched most
|
||||
* recently — which can be an unrelated shared KB. {@code resolvePrimaryKb}
|
||||
* must still return the KB actually bound to the agent.
|
||||
*/
|
||||
class WikiKnowledgeBaseServiceTest {
|
||||
|
||||
private final WikiKnowledgeBaseMapper kbMapper = mock(WikiKnowledgeBaseMapper.class);
|
||||
private final WikiKnowledgeBaseService service = new WikiKnowledgeBaseService(
|
||||
kbMapper, null, null, null, null, null);
|
||||
|
||||
private static WikiKnowledgeBaseEntity kb(long id, Long agentId) {
|
||||
WikiKnowledgeBaseEntity entity = new WikiKnowledgeBaseEntity();
|
||||
entity.setId(id);
|
||||
entity.setAgentId(agentId);
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("prefers the agent's bound KB even when a shared KB was updated more recently")
|
||||
void prefersBoundKbOverNewerSharedKb() {
|
||||
// listByAgentId order is update_time DESC: two shared KBs precede the bound one.
|
||||
when(kbMapper.selectList(any())).thenReturn(List.of(
|
||||
kb(900L, null),
|
||||
kb(800L, null),
|
||||
kb(100L, 7L)));
|
||||
|
||||
assertThat(service.resolvePrimaryKb(7L)).isNotNull();
|
||||
assertThat(service.resolvePrimaryKb(7L).getId()).isEqualTo(100L);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("falls back to the most recent shared KB when the agent has no bound KB")
|
||||
void fallsBackToSharedKbWhenNoneBound() {
|
||||
when(kbMapper.selectList(any())).thenReturn(List.of(
|
||||
kb(900L, null),
|
||||
kb(800L, null)));
|
||||
|
||||
assertThat(service.resolvePrimaryKb(7L).getId()).isEqualTo(900L);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("returns null when the agent can reach no knowledge base")
|
||||
void returnsNullWhenNoKb() {
|
||||
when(kbMapper.selectList(any())).thenReturn(List.of());
|
||||
|
||||
assertThat(service.resolvePrimaryKb(7L)).isNull();
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user