From f31a071546c5d2f821a36bd6e7cbfd243b2dc67f Mon Sep 17 00:00:00 2001 From: whatevertogo Date: Mon, 30 Mar 2026 08:41:31 +0800 Subject: [PATCH 1/3] fix: preserve explicit rerank api paths --- astrbot/core/config/default.py | 2 +- .../provider/sources/vllm_rerank_source.py | 27 ++++++++++++++++++- .../en-US/features/config-metadata.json | 2 +- .../ru-RU/features/config-metadata.json | 2 +- .../zh-CN/features/config-metadata.json | 2 +- docs/en/use/knowledge-base.md | 2 ++ docs/zh/use/knowledge-base.md | 2 ++ 7 files changed, 34 insertions(+), 5 deletions(-) diff --git a/astrbot/core/config/default.py b/astrbot/core/config/default.py index 846b1a350e..fc4b313564 100644 --- a/astrbot/core/config/default.py +++ b/astrbot/core/config/default.py @@ -1826,7 +1826,7 @@ class ChatProviderTemplate(TypedDict): "rerank_api_base": { "description": "重排序模型 API Base URL", "type": "string", - "hint": "AstrBot 会在请求时在末尾加上 /v1/rerank。", + "hint": "纯域名地址会自动补 /v1/rerank;带路径或完整 rerank 端点的地址保持原样。", }, "rerank_api_key": { "description": "API Key", diff --git a/astrbot/core/provider/sources/vllm_rerank_source.py b/astrbot/core/provider/sources/vllm_rerank_source.py index edd8a54913..7e816152c0 100644 --- a/astrbot/core/provider/sources/vllm_rerank_source.py +++ b/astrbot/core/provider/sources/vllm_rerank_source.py @@ -1,3 +1,5 @@ +from urllib.parse import urlsplit + import aiohttp from astrbot import logger @@ -13,6 +15,19 @@ provider_type=ProviderType.RERANK, ) class VLLMRerankProvider(RerankProvider): + @staticmethod + def _resolve_rerank_endpoint(base_url: str) -> str: + normalized = base_url.strip().removesuffix("/") + if normalized.endswith("/rerank"): + return normalized + if normalized.endswith("/v1"): + return f"{normalized}/rerank" + + parsed = urlsplit(normalized if "://" in normalized else f"//{normalized}") + if not parsed.path or parsed.path == "/": + return f"{normalized}/v1/rerank" + return normalized + def __init__(self, provider_config: dict, provider_settings: dict) -> None: super().__init__(provider_config, provider_settings) self.provider_config = provider_config @@ -20,12 +35,14 @@ def __init__(self, provider_config: dict, provider_settings: dict) -> None: self.auth_key = provider_config.get("rerank_api_key", "") self.base_url = provider_config.get("rerank_api_base", "http://127.0.0.1:8000") self.base_url = self.base_url.rstrip("/") + self.endpoint_url = self._resolve_rerank_endpoint(self.base_url) self.timeout = provider_config.get("timeout", 20) self.model = provider_config.get("rerank_model", "BAAI/bge-reranker-base") h = {} if self.auth_key: h["Authorization"] = f"Bearer {self.auth_key}" + logger.info(f"[vLLM Rerank] Using API URL: {self.endpoint_url}") self.client = aiohttp.ClientSession( headers=h, timeout=aiohttp.ClientTimeout(total=self.timeout), @@ -46,10 +63,18 @@ async def rerank( payload["top_n"] = top_n assert self.client is not None async with self.client.post( - f"{self.base_url}/v1/rerank", + self.endpoint_url, json=payload, ) as response: + response.raise_for_status() response_data = await response.json() + if isinstance(response_data, dict) and "error" in response_data: + error = response_data["error"] + if isinstance(error, dict): + code = error.get("code", "unknown") + message = error.get("message", "Unknown rerank API error") + raise ValueError(f"Rerank API error {code}: {message}") + raise ValueError(f"Rerank API error: {error}") results = response_data.get("results", []) if not results: diff --git a/dashboard/src/i18n/locales/en-US/features/config-metadata.json b/dashboard/src/i18n/locales/en-US/features/config-metadata.json index 9ae8672826..f8de9413f0 100644 --- a/dashboard/src/i18n/locales/en-US/features/config-metadata.json +++ b/dashboard/src/i18n/locales/en-US/features/config-metadata.json @@ -1075,7 +1075,7 @@ }, "rerank_api_base": { "description": "Rerank Model API Base URL", - "hint": "AstrBot appends /v1/rerank to the request URL." + "hint": "AstrBot appends /v1/rerank only when the API Base URL has no path; URLs with paths or a full rerank endpoint are preserved as-is." }, "rerank_api_key": { "description": "API Key", diff --git a/dashboard/src/i18n/locales/ru-RU/features/config-metadata.json b/dashboard/src/i18n/locales/ru-RU/features/config-metadata.json index 0aa5c791ac..ffc55ae7cd 100644 --- a/dashboard/src/i18n/locales/ru-RU/features/config-metadata.json +++ b/dashboard/src/i18n/locales/ru-RU/features/config-metadata.json @@ -1076,7 +1076,7 @@ }, "rerank_api_base": { "description": "Base URL API модели Rerank", - "hint": "AstrBot добавляет /v1/rerank к URL запроса." + "hint": "AstrBot добавляет /v1/rerank только если API Base URL не содержит пути; URL с путями или полный rerank endpoint сохраняются без изменений." }, "rerank_api_key": { "description": "API Key", diff --git a/dashboard/src/i18n/locales/zh-CN/features/config-metadata.json b/dashboard/src/i18n/locales/zh-CN/features/config-metadata.json index c04138402e..5a245337ac 100644 --- a/dashboard/src/i18n/locales/zh-CN/features/config-metadata.json +++ b/dashboard/src/i18n/locales/zh-CN/features/config-metadata.json @@ -1077,7 +1077,7 @@ }, "rerank_api_base": { "description": "重排序模型 API Base URL", - "hint": "AstrBot 会在请求时在末尾加上 /v1/rerank。" + "hint": "纯域名地址会自动补 /v1/rerank;带路径或完整 rerank 端点的地址保持原样。" }, "rerank_api_key": { "description": "API Key", diff --git a/docs/en/use/knowledge-base.md b/docs/en/use/knowledge-base.md index b1f9e1dc12..ac76c26a96 100644 --- a/docs/en/use/knowledge-base.md +++ b/docs/en/use/knowledge-base.md @@ -22,6 +22,8 @@ A reranker model can improve the precision of final retrieval results to some ex Similar to configuring the embedding model, open the service provider page, click "Add Service Provider", and select Reranker. For more information about reranker models, please refer to online resources. +For vLLM and other HTTP rerank services, when `rerank api base` only contains the host, AstrBot automatically appends `/v1/rerank`. If the URL already contains a path or is already a full rerank endpoint, AstrBot preserves it as-is. + ## Creating a Knowledge Base AstrBot supports multiple knowledge base management. During chat, you can **freely specify which knowledge base to use**. diff --git a/docs/zh/use/knowledge-base.md b/docs/zh/use/knowledge-base.md index d79336c251..638e9ca7f3 100644 --- a/docs/zh/use/knowledge-base.md +++ b/docs/zh/use/knowledge-base.md @@ -23,6 +23,8 @@ 和嵌入模型的配置类似,打开服务提供商页面,点击新增服务提供商,选择重排序。有关重排序模型的更多信息请参考网络。 +如果使用 vLLM 或其他兼容 HTTP Rerank 接口的服务,当 `rerank api base` 只填写域名时,AstrBot 会自动补上 `/v1/rerank`;如果填写的是带路径的地址或完整的 rerank 端点,AstrBot 会保持原样。 + ## 创建知识库 AstrBot 支持多知识库管理。在聊天时,您可以**自由指定知识库**。 From eda21a37c43078547aa20200ab998bc220442136 Mon Sep 17 00:00:00 2001 From: whatevertogo Date: Mon, 30 Mar 2026 08:48:59 +0800 Subject: [PATCH 2/3] fix: validate rerank api base inputs --- astrbot/core/config/default.py | 2 +- .../provider/sources/vllm_rerank_source.py | 19 +++++++++++++++++-- .../en-US/features/config-metadata.json | 2 +- .../ru-RU/features/config-metadata.json | 2 +- .../zh-CN/features/config-metadata.json | 2 +- docs/en/use/knowledge-base.md | 2 +- docs/zh/use/knowledge-base.md | 2 +- 7 files changed, 23 insertions(+), 8 deletions(-) diff --git a/astrbot/core/config/default.py b/astrbot/core/config/default.py index fc4b313564..43720c86eb 100644 --- a/astrbot/core/config/default.py +++ b/astrbot/core/config/default.py @@ -1826,7 +1826,7 @@ class ChatProviderTemplate(TypedDict): "rerank_api_base": { "description": "重排序模型 API Base URL", "type": "string", - "hint": "纯域名地址会自动补 /v1/rerank;带路径或完整 rerank 端点的地址保持原样。", + "hint": "纯域名地址会自动补 /v1/rerank;带路径或完整 rerank 端点的地址保持原样。带路径时请包含 http:// 或 https://。", }, "rerank_api_key": { "description": "API Key", diff --git a/astrbot/core/provider/sources/vllm_rerank_source.py b/astrbot/core/provider/sources/vllm_rerank_source.py index 7e816152c0..9bb30a6eee 100644 --- a/astrbot/core/provider/sources/vllm_rerank_source.py +++ b/astrbot/core/provider/sources/vllm_rerank_source.py @@ -23,7 +23,17 @@ def _resolve_rerank_endpoint(base_url: str) -> str: if normalized.endswith("/v1"): return f"{normalized}/rerank" - parsed = urlsplit(normalized if "://" in normalized else f"//{normalized}") + has_scheme = "://" in normalized + parsed = urlsplit(normalized if has_scheme else f"//{normalized}") + if not has_scheme: + if parsed.path not in ("", "/"): + raise ValueError( + "VLLM Rerank API Base URL must include a scheme when a path is provided: " + f"{base_url!r}" + ) + normalized = f"http://{normalized}" + parsed = urlsplit(normalized) + if not parsed.path or parsed.path == "/": return f"{normalized}/v1/rerank" return normalized @@ -66,7 +76,6 @@ async def rerank( self.endpoint_url, json=payload, ) as response: - response.raise_for_status() response_data = await response.json() if isinstance(response_data, dict) and "error" in response_data: error = response_data["error"] @@ -75,6 +84,12 @@ async def rerank( message = error.get("message", "Unknown rerank API error") raise ValueError(f"Rerank API error {code}: {message}") raise ValueError(f"Rerank API error: {error}") + response.raise_for_status() + if not isinstance(response_data, dict): + raise ValueError( + "Unexpected rerank API response format: " + f"{type(response_data).__name__}" + ) results = response_data.get("results", []) if not results: diff --git a/dashboard/src/i18n/locales/en-US/features/config-metadata.json b/dashboard/src/i18n/locales/en-US/features/config-metadata.json index f8de9413f0..1adcabaeff 100644 --- a/dashboard/src/i18n/locales/en-US/features/config-metadata.json +++ b/dashboard/src/i18n/locales/en-US/features/config-metadata.json @@ -1075,7 +1075,7 @@ }, "rerank_api_base": { "description": "Rerank Model API Base URL", - "hint": "AstrBot appends /v1/rerank only when the API Base URL has no path; URLs with paths or a full rerank endpoint are preserved as-is." + "hint": "AstrBot appends /v1/rerank only when the API Base URL has no path; URLs with paths or a full rerank endpoint are preserved as-is. Include http:// or https:// when a path is provided." }, "rerank_api_key": { "description": "API Key", diff --git a/dashboard/src/i18n/locales/ru-RU/features/config-metadata.json b/dashboard/src/i18n/locales/ru-RU/features/config-metadata.json index ffc55ae7cd..d46fd82c33 100644 --- a/dashboard/src/i18n/locales/ru-RU/features/config-metadata.json +++ b/dashboard/src/i18n/locales/ru-RU/features/config-metadata.json @@ -1076,7 +1076,7 @@ }, "rerank_api_base": { "description": "Base URL API модели Rerank", - "hint": "AstrBot добавляет /v1/rerank только если API Base URL не содержит пути; URL с путями или полный rerank endpoint сохраняются без изменений." + "hint": "AstrBot добавляет /v1/rerank только если API Base URL не содержит пути; URL с путями или полный rerank endpoint сохраняются без изменений. Если указан путь, добавьте http:// или https://." }, "rerank_api_key": { "description": "API Key", diff --git a/dashboard/src/i18n/locales/zh-CN/features/config-metadata.json b/dashboard/src/i18n/locales/zh-CN/features/config-metadata.json index 5a245337ac..a7b418281e 100644 --- a/dashboard/src/i18n/locales/zh-CN/features/config-metadata.json +++ b/dashboard/src/i18n/locales/zh-CN/features/config-metadata.json @@ -1077,7 +1077,7 @@ }, "rerank_api_base": { "description": "重排序模型 API Base URL", - "hint": "纯域名地址会自动补 /v1/rerank;带路径或完整 rerank 端点的地址保持原样。" + "hint": "纯域名地址会自动补 /v1/rerank;带路径或完整 rerank 端点的地址保持原样。带路径时请包含 http:// 或 https://。" }, "rerank_api_key": { "description": "API Key", diff --git a/docs/en/use/knowledge-base.md b/docs/en/use/knowledge-base.md index ac76c26a96..e7bc364f79 100644 --- a/docs/en/use/knowledge-base.md +++ b/docs/en/use/knowledge-base.md @@ -22,7 +22,7 @@ A reranker model can improve the precision of final retrieval results to some ex Similar to configuring the embedding model, open the service provider page, click "Add Service Provider", and select Reranker. For more information about reranker models, please refer to online resources. -For vLLM and other HTTP rerank services, when `rerank api base` only contains the host, AstrBot automatically appends `/v1/rerank`. If the URL already contains a path or is already a full rerank endpoint, AstrBot preserves it as-is. +For vLLM and other HTTP rerank services, when `rerank api base` only contains the host, AstrBot automatically appends `/v1/rerank`. If the URL already contains a path or is already a full rerank endpoint, AstrBot preserves it as-is. When a path is provided, include `http://` or `https://`. ## Creating a Knowledge Base diff --git a/docs/zh/use/knowledge-base.md b/docs/zh/use/knowledge-base.md index 638e9ca7f3..8ac1bea4cc 100644 --- a/docs/zh/use/knowledge-base.md +++ b/docs/zh/use/knowledge-base.md @@ -23,7 +23,7 @@ 和嵌入模型的配置类似,打开服务提供商页面,点击新增服务提供商,选择重排序。有关重排序模型的更多信息请参考网络。 -如果使用 vLLM 或其他兼容 HTTP Rerank 接口的服务,当 `rerank api base` 只填写域名时,AstrBot 会自动补上 `/v1/rerank`;如果填写的是带路径的地址或完整的 rerank 端点,AstrBot 会保持原样。 +如果使用 vLLM 或其他兼容 HTTP Rerank 接口的服务,当 `rerank api base` 只填写域名时,AstrBot 会自动补上 `/v1/rerank`;如果填写的是带路径的地址或完整的 rerank 端点,AstrBot 会保持原样。填写带路径的地址时,请包含 `http://` 或 `https://`。 ## 创建知识库 From 54c5766e4b9309f3a52eb10da5815dd49841a994 Mon Sep 17 00:00:00 2001 From: whatevertogo Date: Mon, 30 Mar 2026 08:54:33 +0800 Subject: [PATCH 3/3] refactor: simplify rerank api base initialization --- astrbot/core/provider/sources/vllm_rerank_source.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/astrbot/core/provider/sources/vllm_rerank_source.py b/astrbot/core/provider/sources/vllm_rerank_source.py index 9bb30a6eee..5eaf6a30eb 100644 --- a/astrbot/core/provider/sources/vllm_rerank_source.py +++ b/astrbot/core/provider/sources/vllm_rerank_source.py @@ -43,9 +43,8 @@ def __init__(self, provider_config: dict, provider_settings: dict) -> None: self.provider_config = provider_config self.provider_settings = provider_settings self.auth_key = provider_config.get("rerank_api_key", "") - self.base_url = provider_config.get("rerank_api_base", "http://127.0.0.1:8000") - self.base_url = self.base_url.rstrip("/") - self.endpoint_url = self._resolve_rerank_endpoint(self.base_url) + base_url = provider_config.get("rerank_api_base", "http://127.0.0.1:8000") + self.endpoint_url = self._resolve_rerank_endpoint(base_url) self.timeout = provider_config.get("timeout", 20) self.model = provider_config.get("rerank_model", "BAAI/bge-reranker-base")