feat(service): opt-in per-request model endpoint overrides (embed, VLM, LLM) - #2370
feat(service): opt-in per-request model endpoint overrides (embed, VLM, LLM)#2370jdye64 wants to merge 11 commits into
Conversation
Allow clients submitting a job via the Python SDK to override the model endpoints (embed NIM, caption/VLM NIM) the service uses, and the answer LLM on POST /v1/answer, instead of the cluster defaults baked in via retriever-service.yaml. Endpoint URLs, model names, and API keys stay server-owned by default. A new opt-in operator policy (pipeline_overrides.endpoint_overrides) gates the feature per stage with an optional URL-prefix allowlist. The override travels through a dedicated, audited PipelineSpec.endpoint_overrides field so the existing trust denylist on *_params stays intact. Co-authored-by: Jeremy Dyer <jdye64@gmail.com>
Co-authored-by: Jeremy Dyer <jdye64@gmail.com>
… instead of endpoints() Drop the dedicated ServiceIngestor.endpoints() fluent method. Each stage method now carries the endpoint URL for its own model: .embed() accepts embed_invoke_url/embed_model_name/embed_model_provider_prefix and .caption() accepts endpoint_url/model_name. These are peeled off and routed into the audited PipelineSpec.endpoint_overrides channel, keeping the server-side denylist/policy/worker machinery unchanged. A bare api_key without an accompanying endpoint override stays server-owned. Co-authored-by: Jeremy Dyer <jdye64@gmail.com>
…nt override Reranking was defined in the library/query paths but never wired into service mode. Add a rerank step to POST /v1/answer: when a rerank endpoint is available the answer path over-fetches top_k * refine_factor candidates, reranks them via the remote NIM, and keeps the best top_k before answer generation. The rerank endpoint / model / API key are server-owned (nim_endpoints.rerank_invoke_url / rerank_model_name / api_key) with a new behaviour section (rerank.enabled / refine_factor / max_length). Mirroring the LLM override pattern, clients may retarget the rerank deployment per-request (rerank_invoke_url / rerank_model_name / rerank_api_key) only when the operator enables pipeline_overrides.endpoint_overrides.rerank; the URL-prefix allowlist is enforced. Supplying a rerank override (or rerank: true) also enables reranking for that request. Helm: auto-wire nim_endpoints.rerank_invoke_url / rerank_model_name from the operator-managed llama-nemotron-rerank-vl-1b-v2 NIM and render the rerank section (enabled flips true when a rerank URL resolves). Co-authored-by: Jeremy Dyer <jdye64@gmail.com>
Greptile SummaryThis PR adds opt-in per-request model endpoint overrides for the embed NIM, caption/VLM NIM, LLM, and reranker in service mode, and wires the reranker into the
|
| Filename | Overview |
|---|---|
| nemo_retriever/src/nemo_retriever/common/policy.py | Adds EndpointOverridePolicy class and helpers; wires them into validate_pipeline_spec. _spec_has_only_endpoint_overrides is missing a result_schema guard. |
| nemo_retriever/src/nemo_retriever/service/service_ingestor.py | Adds _record_endpoint_overrides and rewrites embed()/caption(). The or short-circuit for alias keys may leave a second alias in params_dict. |
| nemo_retriever/src/nemo_retriever/service/routers/ingest.py | Adds LLM and rerank override fields to ServiceAnswerRequest; implements over-fetch + rerank on the answer path. Logic is correct. |
| nemo_retriever/src/nemo_retriever/service/services/pipeline_executor.py | Adds _apply_embed_endpoint_override / _apply_caption_endpoint_override; folds validated client overrides into server-owned base dicts correctly. |
| nemo_retriever/src/nemo_retriever/service/config.py | Adds RerankConfig, EndpointOverridesConfig, rerank_model_name; wires EndpointOverridePolicy into to_policy(). Well structured. |
| nemo_retriever/src/nemo_retriever/common/schemas/pipeline_spec.py | Adds EndpointOverrides Pydantic model; wires into PipelineSpec and updates is_empty() correctly. |
Reviews (4): Last reviewed commit: "Merge branch 'main' into cursor/per-requ..." | Re-trigger Greptile
Resolve configmap.yaml conflict by combining gatewaySvc from main with rerank endpoint parameters from the feature branch.
Summary
Lets clients override the default model endpoints on a per-request basis when submitting jobs / asking questions in service mode, instead of being locked to the hardcoded values in the operator's
retriever-service.yaml. Overrides are opt-in by the operator and travel over a dedicated, audited channel so the existing trust boundary stays intact. This PR also wires the reranker into service mode for the first time.Covered models: embed NIM and caption/VLM NIM (ingest pipeline), and the LLM and reranker (
/v1/answer).SDK ergonomics (ingest)
Each fluent stage method carries the endpoint URL for its own model — there is no separate
.endpoints(...)method:.embed(...)acceptsembed_invoke_url(orembedding_endpoint),embed_model_name(ormodel_name),embed_model_provider_prefix, optionalapi_key..caption(...)acceptsendpoint_url,model_name, optionalapi_key. Supplyingendpoint_urlalso unlocks the caption stage even when the cluster has no VLM configured.Under the hood these are peeled off and routed into
PipelineSpec.endpoint_overrides— a structured, audited field kept separate from the ordinary shape-params blocks so the server's denylist stays effective. A bareapi_keywith no accompanying endpoint override stays server-owned (dropped).Query / answer path (
POST /v1/answer)llm_api_base/llm_model/llm_api_key.top_k * refine_factorcandidates, reranks them via the remote NIM, and keeps the besttop_kbefore answer generation.rerank.enabled/rerank.refine_factor/rerank.max_length.nim_endpoints.rerank_invoke_url/rerank_model_name/api_key.rerank_invoke_url/rerank_model_name/rerank_api_key, plus arerank: true|falsetoggle. Supplying a rerank override (orrerank: true) enables reranking for that request.Server side
pipeline_overrides.endpoint_overridesgates each model type (embed,caption,llm,rerank) plus anallowed_url_prefixesallowlist.EndpointOverridePolicyvalidates client overrides (check_embed/caption/llm/rerank); requests are rejected with 403 when the operator hasn't opted in or the URL prefix is disallowed, and 400 for a bare API key.pipeline_executor.py; the answer route builds per-requestLiteLLMClient/ rerank calls so transient credentials never poison cached clients.Helm
Auto-wire
nim_endpoints.rerank_invoke_url/rerank_model_namefrom the operator-managedllama-nemotron-rerank-vl-1b-v2NIM (mirroring the caption auto-wiring), and render thereranksection —rerank.enabledflips true automatically when a rerank URL resolves. New values:serviceConfig.nimEndpoints.rerankInvokeUrl/rerankModelNameandserviceConfig.rerank.{enabled,refineFactor,maxLength}. Thepipeline_overrides.endpoint_overridesopt-in flags are set via the mountedretriever-service.yaml(not templated), consistent with the existing chart.Tests
tests/test_service_endpoint_overrides.py— schema, config→policy plumbing, policy accept/reject (URL-prefix allowlist, bare-key rejection), caption-stage unlock, worker merge, SDK routing via.embed()/.caption(), and the answer-path LLM and rerank overrides (server-default rerank, over-fetch, override applied/rejected/prefix-enforced, 400 when requested without an endpoint).tests/test_service_caption.py—.caption(endpoint_url=...)/model_nameroute intoendpoint_overridesrather than being rejected.tests/test_helm_rerank_endpoint.py— source-level +helm templateintegration coverage of the rerank auto-wiring (integration cases skip cleanly whenhelmis absent).All service/policy/config/rerank/helm test selections pass.