Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions astrbot/core/provider/sources/xinference_rerank_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,7 @@ async def rerank(
top_n: int | None = None,
) -> list[RerankResult]:
if not self.model:
logger.error("Xinference rerank model is not initialized.")
return []
raise RuntimeError("Xinference rerank model is not initialized")
try:
response = await self.model.rerank(documents, query, top_n)
results = response.get("results", [])
Expand All @@ -110,9 +109,12 @@ async def rerank(
for result in results
]
except Exception as e:
# An empty list reads as a legitimate empty rerank to the caller,
# which would overwrite the fused candidates with nothing (#10000).
# Propagate so the retrieval manager keeps the unreranked results.
logger.error(f"Xinference rerank failed: {e}")
logger.debug(f"Xinference rerank failed with exception: {e}", exc_info=True)
return []
raise

async def terminate(self) -> None:
"""关闭客户端会话"""
Expand Down
38 changes: 38 additions & 0 deletions tests/test_xinference_rerank_source.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""Regression tests for the Xinference rerank provider failure contract (#10000).

The provider used to swallow upstream failures and return an empty list,
which the retrieval manager read as a legitimate empty rerank result and
used to overwrite the fused candidates. Failures now propagate so the
manager can fall back to the unreranked results.
"""

from unittest.mock import AsyncMock, Mock

import pytest

from astrbot.core.provider.sources.xinference_rerank_source import (
XinferenceRerankProvider,
)


@pytest.fixture
def provider() -> XinferenceRerankProvider:
instance = XinferenceRerankProvider.__new__(XinferenceRerankProvider)
instance.model = Mock()
return instance


@pytest.mark.asyncio
async def test_rerank_failure_propagates_instead_of_empty_list(provider):
provider.model.rerank = AsyncMock(side_effect=RuntimeError("upstream down"))

with pytest.raises(RuntimeError, match="upstream down"):
await provider.rerank(query="q", documents=["a", "b"])


@pytest.mark.asyncio
async def test_uninitialized_model_raises_instead_of_empty_list(provider):
provider.model = None

with pytest.raises(RuntimeError, match="not initialized"):
await provider.rerank(query="q", documents=["a"])
Loading