Repository navigation
v0.57.1 — 启动耗时 50s→8s、修复被掩盖的循环导入
概述
v0.57.0 之后继续追可用性,修了两个问题:CLI 启动要等几十秒,以及一个被导入顺序掩盖的循环导入。
启动耗时
litellm 单次导入实测约 34 秒(连带 openai / httpx / pydantic 的大量子模块),
它原本在 litellm_singleton 模块顶层导入。导入链:
src.main → cli_handlers → workflow.cli_handler → workflow
→ experience_bank → core.experience_bank → enterprise_ltm
→ litellm_singleton → litellm
结果是 clawd --version 也要等几十秒。四处改为惰性(PEP 562 保持
from ... import 兼容):
| 文件 | 改法 |
|---|---|
src/llm/litellm_singleton/__init__.py |
顶层不 import litellm |
src/__init__.py |
公开符号按需导入,__version__ 仍即时 |
src/agent/__init__.py |
整个 Agent 栈按需导入 |
src/main.py |
cli_handlers / cost_estimator 移入使用点 |
实测:import src 6.8s → 1.6s;import src.main 50.9s → ~8s。
import src.cli.entrypoint仍有 ~20s:剩余成本来自src.core.__init__
与src.llm.__init__的急切再导出,需把约 60 个再导出惰性化,属独立工程。
被掩盖的循环导入(P0)
惰性化后暴露:
src.utils → diff_utils → src.core.__init__ → core.telemetry
→ tracing_utils → src.rag.__init__ → rag.text_indexer
→ from ..utils import get_logger ← utils 尚未完成初始化
受影响的是以 from src.utils import ... 作为进程第一个导入的任何调用方,
包括 CodeGraph.build 的 ProcessPoolExecutor 子进程 —— 实测抛
BrokenProcessPool。
修复两步:
src/utils/__init__.py在from . import ...之前只提前绑定get_logger。
不能把整行 logger 导入提前:随后导入.debug子模块会把utils.debug
覆盖成模块对象,调用时报TypeError: 'module' object is not callable
(第一版修复踩了这个坑,全量测试 56 红)。core/args_parser.py/evolution.py/memory_guard.py改为直接从
..utils.logger导入。
静态可达性
惰性导出会让 scripts/reachability.py(AST 建图)看不见这些模块,
生产可达数从 429 掉到 427。在两个 __init__ 中加 TYPE_CHECKING 块显式列出
来源模块:运行时零成本,静态 AST 仍可见。实测恢复 429。
确定性测试
tests/performance/test_rag_pressure.py 原断言
inc_duration < scan_duration * 0.2 依赖墙钟,在满载机器上随机失败
(全量跑红、单独跑绿,已复现)。改为统计 SymbolExtractor.extract
调用次数,断言增量扫描重解析数为 0 —— 确定性且更贴近该优化的真实语义。
验证
ruff --select F821,F811 → All checks passed
scripts/import_sweep.py → 0 缺陷(639 模块)
scripts/reachability.py → 429(恢复)
pytest tests/ -q → 3042 passed / 0 failed
pytest 受影响子集 → 892 passed
from src.utils import get_logger(首导入)→ OK
CodeGraph.build → OK(子进程不再 BrokenProcessPool)
🤖 Generated with Claude Code