feat(fam-edge): 启动时预热 Ollama,避免兜底触发时冷启动等 1-2 分钟

排查"Ollama 模型没有常驻内存":systemd 里 OLLAMA_KEEP_ALIVE=-1 其实一直配置
正确,但这个环境变量只保证"加载过之后不因为空闲被换出",不负责启动时主动
预加载。查 model_calls 表,ollama provider 从来没有一条调用记录——因为它是
问答链路最后一级兜底,前面 NVIDIA/Gemini 一直调用成功,从未真正轮到它,
自然也就从未被加载进内存过。

新增 OllamaAdapter.warm_up():送一条 num_predict=1 的最小请求强制模型加载,
超时给够 180s(冷启动实测能到 1-2 分钟)。app.py 启动时在后台线程调用,不
阻塞主服务启动;找不到 ollama 配置或预热失败都只记警告,不影响服务本身。

实测部署验证:重启后 36 秒完成预热,ollama ps 显示 qwen2.5:7b 已加载,
expires_at 显示不过期(keep_alive=-1 生效)——真正需要兜底的那一刻不会再有
冷启动延迟。

新增 test_ollama_adapter.py 4 个用例覆盖预热成功/HTTP失败/异常不上抛/超时
时长。
This commit is contained in:
ericwyuan
2026-08-23 09:33:49 +08:00
parent bdf561a415
commit 63b28663f1
3 changed files with 116 additions and 0 deletions

View File

@@ -33,6 +33,32 @@ class OllamaAdapter(BaseModelAdapter):
enabled=cb_cfg.get('enabled', False) # 本地模型默认不启用
)
def warm_up(self) -> bool:
"""启动时主动送一次最小请求,把模型强制加载进内存。
背景OLLAMA_KEEP_ALIVE=-1systemd 环境变量已配置)只保证"一旦加载过
就不再因为空闲被换出"但不会在服务启动时主动预加载——Ollama 现在只在
问答链路最末位兜底(前面 NVIDIA/Gemini 一直成功的话永远轮不到它),
实测 model_calls 表里从来没有一条 ollama 记录,说明模型从未被加载过。
真正需要兜底的那一刻才现加载,用户会等上首次冷启动的 ~1-2 分钟
(见 README 6.2 冷启动实测数据)。启动时主动预热一次,之后就一直
常驻内存,兜底真正触发时不再有冷启动延迟。
"""
try:
resp = requests.post(
f"{self.base_url}/api/generate",
json={"model": self.model_name, "prompt": "hi", "stream": False,
"options": {"num_predict": 1}},
timeout=180, # 冷启动可能到 1-2 分钟,给足时间
)
if resp.status_code == 200:
logger.info(f"Ollama 模型预热完成: {self.model_name}")
return True
logger.warning(f"Ollama 预热失败: HTTP {resp.status_code} {resp.text[:200]}")
except Exception as e:
logger.warning(f"Ollama 预热异常(不影响服务启动,问答兜底时会正常现加载): {e}")
return False
def health_check(self) -> bool:
"""GET /api/tags检查模型是否可用"""
try: