mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-15 20:08:18 +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 "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
List<WikiKnowledgeBaseEntity> kbs = kbService.listByAgentId(agentId);
|
WikiKnowledgeBaseEntity primaryKb = kbService.resolvePrimaryKb(agentId);
|
||||||
if (kbs.isEmpty()) {
|
if (primaryKb == null) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
Long kbId = kbs.get(0).getId();
|
Long kbId = primaryKb.getId();
|
||||||
List<PageSearchResult> hits = hybridRetriever.search(kbId, userMessage, "hybrid", 5);
|
List<PageSearchResult> hits = hybridRetriever.search(kbId, userMessage, "hybrid", 5);
|
||||||
if (hits.isEmpty()) {
|
if (hits.isEmpty()) {
|
||||||
return "";
|
return "";
|
||||||
|
|||||||
@ -112,6 +112,32 @@ public class WikiKnowledgeBaseService {
|
|||||||
.orderByDesc(WikiKnowledgeBaseEntity::getUpdateTime));
|
.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) {
|
public WikiKnowledgeBaseEntity getById(Long id) {
|
||||||
return kbMapper.selectById(id);
|
return kbMapper.selectById(id);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -817,8 +817,8 @@ public class WikiTool {
|
|||||||
// ==================== Helpers ====================
|
// ==================== Helpers ====================
|
||||||
|
|
||||||
private Long resolveKbId(Long agentId) {
|
private Long resolveKbId(Long agentId) {
|
||||||
List<WikiKnowledgeBaseEntity> kbs = kbService.listByAgentId(agentId);
|
WikiKnowledgeBaseEntity kb = kbService.resolvePrimaryKb(agentId);
|
||||||
return kbs.isEmpty() ? null : kbs.get(0).getId();
|
return kb == null ? null : kb.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
private JSONArray resolveSourceFiles(String sourceRawIdsJson) {
|
private JSONArray resolveSourceFiles(String sourceRawIdsJson) {
|
||||||
|
|||||||
@ -48,7 +48,7 @@ class WikiContextServiceTest {
|
|||||||
|
|
||||||
WikiKnowledgeBaseEntity kb = new WikiKnowledgeBaseEntity();
|
WikiKnowledgeBaseEntity kb = new WikiKnowledgeBaseEntity();
|
||||||
kb.setId(42L);
|
kb.setId(42L);
|
||||||
when(kbService.listByAgentId(any())).thenReturn(List.of(kb));
|
when(kbService.resolvePrimaryKb(any())).thenReturn(kb);
|
||||||
|
|
||||||
service = new WikiContextService(kbService, pageService, hybridRetriever, properties);
|
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