fix: defer faiss imports during startup#7400
fix: defer faiss imports during startup#7400Aster-amellus wants to merge 8 commits intoAstrBotDevs:masterfrom
Conversation
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- Several modules now hide
FaissVecDBimports behindTYPE_CHECKINGbut still use bareFaissVecDBannotations (e.g. insparse_retrieveranddashboard/utils), which will raiseNameErrorat runtime unlessfrom __future__ import annotationsis enabled; either add the future import or quote these annotations for consistency withkb_helper/kb_db_sqlite. - In
dashboard/utils.generate_tsne_visualization, consider keeping a local, runtime-only import ofFaissVecDB(similar to_ensure_vec_db) if you want to retain concrete typing for tools while still avoiding eager faiss import, rather than relying purely on aTYPE_CHECKING-guarded import.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Several modules now hide `FaissVecDB` imports behind `TYPE_CHECKING` but still use bare `FaissVecDB` annotations (e.g. in `sparse_retriever` and `dashboard/utils`), which will raise `NameError` at runtime unless `from __future__ import annotations` is enabled; either add the future import or quote these annotations for consistency with `kb_helper`/`kb_db_sqlite`.
- In `dashboard/utils.generate_tsne_visualization`, consider keeping a local, runtime-only import of `FaissVecDB` (similar to `_ensure_vec_db`) if you want to retain concrete typing for tools while still avoiding eager faiss import, rather than relying purely on a `TYPE_CHECKING`-guarded import.
## Individual Comments
### Comment 1
<location path="astrbot/core/knowledge_base/retrieval/sparse_retriever.py" line_range="79" />
<code_context>
chunks = []
for kb_id in kb_ids:
- vec_db: FaissVecDB = kb_options.get(kb_id, {}).get("vec_db")
+ vec_db: FaissVecDB | None = kb_options.get(kb_id, {}).get("vec_db")
if not vec_db:
continue
</code_context>
<issue_to_address>
**issue (bug_risk):** FaissVecDB is only imported under TYPE_CHECKING, so this runtime type annotation will fail with NameError.
Because FaissVecDB only exists under TYPE_CHECKING, this annotation must not be evaluated at runtime. Please either quote the type (e.g. "FaissVecDB" | None), enable `from __future__ import annotations` in this module, or change the import so FaissVecDB is available at runtime.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| chunks = [] | ||
| for kb_id in kb_ids: | ||
| vec_db: FaissVecDB = kb_options.get(kb_id, {}).get("vec_db") | ||
| vec_db: FaissVecDB | None = kb_options.get(kb_id, {}).get("vec_db") |
There was a problem hiding this comment.
issue (bug_risk): FaissVecDB is only imported under TYPE_CHECKING, so this runtime type annotation will fail with NameError.
Because FaissVecDB only exists under TYPE_CHECKING, this annotation must not be evaluated at runtime. Please either quote the type (e.g. "FaissVecDB" | None), enable from __future__ import annotations in this module, or change the import so FaissVecDB is available at runtime.
There was a problem hiding this comment.
Code Review
This pull request introduces a whisper_device configuration for local Whisper deployments, enabling support for CPU and MPS (Apple Silicon) with automatic fallback logic. Additionally, it refactors multiple modules to prevent the eager loading of the faiss library by moving imports into TYPE_CHECKING blocks or local scopes, ensuring a faster and more robust startup process. Feedback includes a suggestion to safely handle potential None values for vec_db in the retrieval manager to avoid attribute errors and a recommendation to further defer heavy imports like torch and whisper within the Whisper provider to prevent startup failures when dependencies are missing.
There was a problem hiding this comment.
Pull request overview
This PR aims to prevent macOS startup crashes by ensuring faiss/FaissVecDB are not imported during AstrBot startup unless the knowledge base functionality is actually used.
Changes:
- Deferred
FaissVecDBimports to runtime use sites and moved type-only imports behindTYPE_CHECKING. - Added a smoke regression test to ensure startup imports don’t eagerly load
faiss. - Extended Whisper(Local) configuration with a
whisper_deviceoption (cpu/mps) and updated related dashboard metadata/tests.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| astrbot/core/knowledge_base/kb_helper.py | Lazily imports FaissVecDB inside _ensure_vec_db and updates annotations to avoid startup-time imports. |
| astrbot/core/knowledge_base/kb_db_sqlite.py | Moves FaissVecDB import behind TYPE_CHECKING and uses string annotations to avoid eager loading. |
| astrbot/core/knowledge_base/retrieval/manager.py | Avoids eager FaissVecDB import and adjusts rerank selection logic to rely on runtime attributes. |
| astrbot/core/knowledge_base/retrieval/sparse_retriever.py | Moves FaissVecDB import behind TYPE_CHECKING to reduce startup import chain pressure. |
| astrbot/dashboard/utils.py | Removes eager FaissVecDB import (type-only under TYPE_CHECKING) to prevent dashboard import chain from loading faiss. |
| astrbot/core/provider/sources/whisper_selfhosted_source.py | Adds device resolution (whisper_device) and passes the resolved device to whisper.load_model. |
| astrbot/core/config/default.py | Adds whisper_device default/config metadata for Whisper(Local). |
| dashboard/src/i18n/locales/zh-CN/features/config-metadata.json | Adds UI metadata strings for whisper_device. |
| dashboard/src/i18n/locales/en-US/features/config-metadata.json | Adds UI metadata strings for whisper_device. |
| dashboard/src/i18n/locales/ru-RU/features/config-metadata.json | Adds UI metadata strings for whisper_device. |
| tests/test_smoke.py | Adds regression check asserting faiss is not loaded after critical startup imports. |
| tests/test_whisper_selfhosted_source.py | Adds unit tests covering Whisper(Local) device selection behavior. |
| ) -> None: | ||
| super().__init__(provider_config, provider_settings) | ||
| self.set_model(provider_config["model"]) | ||
| self.device = str(provider_config.get("whisper_device", "cpu")).strip().lower() | ||
| self.model = None |
There was a problem hiding this comment.
The PR description is scoped to deferring faiss imports during startup, but this change set also introduces a new Whisper config field (whisper_device) and related behavior/logging (plus UI metadata updates). Please update the PR description to include this additional feature, or split it into a separate PR to keep the change focused and easier to review/revert independently.
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Motivation / 动机
Fixes the startup crash described in #7343.
On macOS, enabling local
Whisper(Local)could cause AstrBot to crash during startup becausefaisswas importedeagerly through the knowledge base and dashboard import chain, even when the user was not actively using the knowledge
base.
This PR fixes the startup-time crash by deferring
faissimports to runtime use sites.Modifications / 改动点
FaissVecDBimports from startup paths to runtime use sitesFaissVecDBimports behindTYPE_CHECKINGfaissduring AstrBot startup unless the knowledge base is actually usedModified files:
astrbot/core/knowledge_base/kb_helper.pyastrbot/core/knowledge_base/kb_db_sqlite.pyastrbot/core/knowledge_base/retrieval/manager.pyastrbot/core/knowledge_base/retrieval/sparse_retriever.pyastrbot/dashboard/utils.pytests/test_smoke.pyThis is NOT a breaking change. / 这不是一个破坏性变更。
Screenshots or Test Results / 运行截图或测试结果
Validation performed locally on macOS(Macbook Air M4, 16G):
Notes:
actively used in the same process on macOS.
Screenshots or Test Results / 运行截图或测试结果
Checklist / 检查清单
😊 If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
/ 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。
[ x ] 👀 My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
/ 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”。
[ x ] 🤓 I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in
requirements.txtandpyproject.toml./ 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到
requirements.txt和pyproject.toml文件相应位置。[ x ] 😮 My changes do not introduce malicious code.
/ 我的更改没有引入恶意代码。
Summary by Sourcery
Defer FAISS-related imports to runtime usage and add configurable device selection for the local Whisper provider, improving macOS startup stability and Whisper behavior.
Bug Fixes:
Enhancements:
Tests: