Studio: bump llama-server prefill timeout to 300s + warm RAG embedder when RAG turns on
This commit is contained in:
parent
5351822ff8
commit
38e22c15d7
4 changed files with 57 additions and 2 deletions
|
|
@ -4203,9 +4203,12 @@ class LlamaCppBackend:
|
|||
# without triggering a retry storm. Cancel during both
|
||||
# prefill and streaming is handled by the watcher thread
|
||||
# which closes the response, unblocking any httpx read.
|
||||
# 300 s headroom for large models (30B+) re-prefilling after
|
||||
# a tool call that returned a long result (e.g. RAG chunks
|
||||
# with images) — prior 120 s was tripping on Gemma-4-31B.
|
||||
prefill_timeout = httpx.Timeout(
|
||||
connect = 30,
|
||||
read = 120.0,
|
||||
read = 300.0,
|
||||
write = 10,
|
||||
pool = 10,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -435,6 +435,32 @@ def get_rag_defaults(
|
|||
return _load_rag_defaults()
|
||||
|
||||
|
||||
@router.post("/warmup")
|
||||
def warmup_rag_embedder(
|
||||
current_subject: str = Depends(get_current_subject),
|
||||
) -> dict:
|
||||
"""Preload the configured default embedder so the first retrieval is warm.
|
||||
|
||||
Called from the frontend when the user enables the RAG pill — moves the
|
||||
cold-load latency (Qwen3-VL-Embedding-2B is ~4 GB) out of the first
|
||||
chat-completion path, where a 30s+ load can race the llama-server
|
||||
prefill timeout.
|
||||
"""
|
||||
from utils.rag.config import resolve_embedder
|
||||
|
||||
defaults = _load_rag_defaults()
|
||||
model_name = defaults.embedding_model or resolve_embedder(
|
||||
defaults.mode,
|
||||
defaults.chunking_strategy,
|
||||
)
|
||||
try:
|
||||
embeddings.get_embedder(model_name)
|
||||
except Exception as exc: # noqa: BLE001
|
||||
logger.warning("RAG warmup failed for %s: %s", model_name, exc)
|
||||
return {"ok": False, "model": model_name, "error": str(exc)}
|
||||
return {"ok": True, "model": model_name}
|
||||
|
||||
|
||||
@router.put("/defaults", response_model = RagDefaults)
|
||||
def set_rag_defaults(
|
||||
payload: UpdateRagDefaultsRequest,
|
||||
|
|
|
|||
|
|
@ -657,6 +657,17 @@ export const useChatRuntimeStore = create<ChatRuntimeStore>((set, get) => ({
|
|||
nextState.ragToolEnabled = true;
|
||||
saveBool(CHAT_RAG_TOOL_ENABLED_KEY, true);
|
||||
}
|
||||
// After hydration, if RAG is on (persisted or just migrated),
|
||||
// warm the embedder so the first message doesn't pay the
|
||||
// cold load inline.
|
||||
if (
|
||||
nextState.ragToolEnabled === true ||
|
||||
(nextState.ragToolEnabled === undefined && state.ragToolEnabled)
|
||||
) {
|
||||
void import("@/features/rag/api/rag-api")
|
||||
.then((m) => m.warmupRagEmbedder())
|
||||
.catch(() => {});
|
||||
}
|
||||
return nextState;
|
||||
});
|
||||
} catch {
|
||||
|
|
@ -869,8 +880,16 @@ export const useChatRuntimeStore = create<ChatRuntimeStore>((set, get) => ({
|
|||
return { toolsEnabled };
|
||||
}),
|
||||
setRagToolEnabled: (ragToolEnabled) =>
|
||||
set(() => {
|
||||
set((state) => {
|
||||
saveBool(CHAT_RAG_TOOL_ENABLED_KEY, ragToolEnabled);
|
||||
// Warmup on off→on transitions: kick the backend to preload the
|
||||
// embedder so the user's first RAG-using message doesn't pay the
|
||||
// cold-start (~30s for Qwen3-VL-Embedding-2B) inline. Fire-and-forget.
|
||||
if (ragToolEnabled && !state.ragToolEnabled) {
|
||||
void import("@/features/rag/api/rag-api")
|
||||
.then((m) => m.warmupRagEmbedder())
|
||||
.catch(() => {});
|
||||
}
|
||||
return { ragToolEnabled };
|
||||
}),
|
||||
setCodeToolsEnabled: (codeToolsEnabled) =>
|
||||
|
|
|
|||
|
|
@ -304,6 +304,13 @@ export async function setRagDefaults(
|
|||
return parseJsonOrThrow<RagDefaults>(response);
|
||||
}
|
||||
|
||||
/** Preload the configured embedder on the backend. Long-running (cold
|
||||
* load can take 30s+). Fire-and-forget: failure is non-fatal because
|
||||
* the first real query will lazy-load again. */
|
||||
export async function warmupRagEmbedder(): Promise<void> {
|
||||
await authFetch("/api/rag/warmup", { method: "POST" });
|
||||
}
|
||||
|
||||
// --- Search ---
|
||||
|
||||
export async function search(req: SearchRequest): Promise<SearchHit[]> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue