Skip to content

Commit daef07a

Browse files
JosephTian876claude
andcommitted
fix(kb): resolve kb_id path parameter in dashboard retrieve endpoint
`POST /api/v1/knowledge-bases/{kb_id}/retrieve` identifies the knowledge base with the `kb_id` path parameter, and the route already forwards it as `service.retrieve({"kb_id": kb_id, **body})`. However `retrieve()` only ever read `kb_names`, which that route never supplies, so every request from the WebUI retrieval panel failed with "缺少参数 kb_names 或格式错误". `kb_names` is still honoured when present, keeping the legacy `POST /api/kb/retrieve` endpoint working unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 76bcb1d commit daef07a

2 files changed

Lines changed: 93 additions & 0 deletions

File tree

‎astrbot/dashboard/services/knowledge_base_service.py‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -769,6 +769,15 @@ async def retrieve(self, data: object) -> dict[str, Any]:
769769
if not query:
770770
raise KnowledgeBaseServiceError("缺少参数 query")
771771
kb_manager = self.get_kb_manager()
772+
if not kb_names:
773+
# The REST route identifies the knowledge base with the kb_id path
774+
# parameter, so resolve it into the kb_names the manager expects.
775+
kb_id = payload.get("kb_id")
776+
if kb_id:
777+
kb_helper = await kb_manager.get_kb(kb_id)
778+
if not kb_helper:
779+
raise KnowledgeBaseServiceError("知识库不存在")
780+
kb_names = [kb_helper.kb.kb_name]
772781
if not kb_names or not isinstance(kb_names, list):
773782
raise KnowledgeBaseServiceError("缺少参数 kb_names 或格式错误")
774783

‎tests/unit/test_knowledge_base_service_contract.py‎

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77
from astrbot.core.provider.provider import EmbeddingProvider
88
from astrbot.dashboard.api.knowledge_bases import (
99
list_knowledge_bases,
10+
retrieve_knowledge_base,
1011
)
1112
from astrbot.dashboard.schemas import (
1213
KnowledgeBaseRequest,
14+
KnowledgeBaseRetrieveRequest,
1315
)
1416
from astrbot.dashboard.services.knowledge_base_service import (
1517
KnowledgeBaseService,
@@ -254,6 +256,88 @@ async def test_create_kb_raises_when_embedding_provider_is_missing():
254256
await service.create_kb({"kb_name": "Test KB"})
255257

256258

259+
@pytest.mark.asyncio
260+
async def test_retrieve_resolves_kb_id_from_path_parameter():
261+
kb = make_kb("kb-1", "Docs")
262+
kb_manager = MagicMock()
263+
kb_manager.get_kb = AsyncMock(return_value=SimpleNamespace(kb=kb))
264+
kb_manager.retrieve = AsyncMock(return_value={"results": [{"chunk_id": "c-1"}]})
265+
service = make_service(kb_manager)
266+
267+
result = await service.retrieve({"kb_id": "kb-1", "query": "hello", "top_k": 3})
268+
269+
kb_manager.get_kb.assert_awaited_once_with("kb-1")
270+
kb_manager.retrieve.assert_awaited_once_with(
271+
query="hello",
272+
kb_names=["Docs"],
273+
top_m_final=3,
274+
)
275+
assert result == {
276+
"results": [{"chunk_id": "c-1"}],
277+
"total": 1,
278+
"query": "hello",
279+
}
280+
281+
282+
@pytest.mark.asyncio
283+
async def test_retrieve_route_passes_kb_id_to_service():
284+
kb = make_kb("kb-1", "Docs")
285+
kb_manager = MagicMock()
286+
kb_manager.get_kb = AsyncMock(return_value=SimpleNamespace(kb=kb))
287+
kb_manager.retrieve = AsyncMock(return_value={"results": []})
288+
service = make_service(kb_manager)
289+
290+
response = await retrieve_knowledge_base(
291+
"kb-1",
292+
KnowledgeBaseRetrieveRequest(query="hello"),
293+
_auth=object(),
294+
service=service,
295+
)
296+
297+
assert response["status"] == "ok"
298+
kb_manager.retrieve.assert_awaited_once_with(
299+
query="hello",
300+
kb_names=["Docs"],
301+
top_m_final=5,
302+
)
303+
304+
305+
@pytest.mark.asyncio
306+
async def test_retrieve_still_accepts_explicit_kb_names():
307+
kb_manager = MagicMock()
308+
kb_manager.get_kb = AsyncMock()
309+
kb_manager.retrieve = AsyncMock(return_value={"results": []})
310+
service = make_service(kb_manager)
311+
312+
await service.retrieve({"query": "hello", "kb_names": ["Docs", "Notes"]})
313+
314+
kb_manager.get_kb.assert_not_awaited()
315+
kb_manager.retrieve.assert_awaited_once_with(
316+
query="hello",
317+
kb_names=["Docs", "Notes"],
318+
top_m_final=5,
319+
)
320+
321+
322+
@pytest.mark.asyncio
323+
async def test_retrieve_raises_when_kb_id_is_unknown():
324+
kb_manager = MagicMock()
325+
kb_manager.get_kb = AsyncMock(return_value=None)
326+
service = make_service(kb_manager)
327+
328+
with pytest.raises(KnowledgeBaseServiceError, match="知识库不存在"):
329+
await service.retrieve({"kb_id": "missing", "query": "hello"})
330+
331+
332+
@pytest.mark.asyncio
333+
async def test_retrieve_raises_when_no_knowledge_base_is_specified():
334+
kb_manager = MagicMock()
335+
service = make_service(kb_manager)
336+
337+
with pytest.raises(KnowledgeBaseServiceError, match="缺少参数 kb_names 或格式错误"):
338+
await service.retrieve({"query": "hello"})
339+
340+
257341
@pytest.mark.asyncio
258342
async def test_create_kb_raises_when_embedding_provider_is_invalid():
259343
kb_manager = MagicMock()

0 commit comments

Comments
 (0)