| Pattern | How it works | When to use |
|---|---|---|
| A: Proxy-based | Runtime calls a Synth proxy URL; Synth performs live candidate selection and injects the prompt | Simplest integration; you want Synth to own selection |
| B: Retrieval + JIT apply | Runtime fetches candidates via APIs, picks the best, and applies it just-in-time before each request | You control selection logic; you call the LLM directly |
Pattern A: Proxy-based serving
Your rollout loop sends LLM requests to a Synth proxy URL. The proxy:- Selects the current best candidate (or assigns one for exploration)
- Injects the candidate prompt as the system message
- Forwards the request to your configured LLM provider
- Returns the response with headers (
x-gepa-rollout-id,x-gepa-candidate-id) for reward attribution
Pattern B: Retrieval + JIT apply
Your rollout loop fetches candidates from Synth, picks the best (or your own logic), and applies the prompt yourself before calling the LLM directly. Flow:- Create an online session (same as Pattern A)
- Poll session state for
best_candidate_id(or list candidates and choose) - Fetch the candidate payload via
session.get_candidate(candidate_id)orsession.list_candidates() - Extract prompt text from the candidate (
candidate_content,artifact_payload, or nested fields) - Call your LLM with that prompt as the system message
- Report rewards via
session.update_reward(...)withcandidate_idandrollout_id
- You call the LLM directly (no proxy in the path)
- You want custom selection logic (e.g., A/B by user segment, fallback rules)
- You need to cache or preload candidates
- Your infra cannot route through a Synth proxy
Retrieval APIs
List candidates for a session
GET /api/v1/systems/{system_id}/candidates
For online sessions, system_id is the session_id returned when you create the session.
Query params: job_id, algorithm, mode, status, limit, cursor, sort, include.
Response:
Get a single candidate
GET /api/v1/candidates/{candidate_id}GET /api/v1/offline/jobs/{job_id}/candidates/{candidate_id}
Returns the full candidate payload including candidate_content, artifact_payload, or nested prompt structures.
Session state (best candidate)
GET /api/v1/online/sessions/{session_id}
Returns live state including:
best_candidate_id— the backend’s current bestbest_reward/best_objective_value— associated scorecandidates— summary list withcandidate_id,avg_reward,rollout_count
best_candidate_id to fetch the prompt via get_candidate() when using Pattern B.
SDK usage (Pattern B)
GEPA online
MIPRO online
MiproOnlineSession exposes the same retrieval methods: list_candidates(), list_candidates_async(), get_candidate(), get_candidate_async(). Use session_id as the system identifier when calling the REST APIs directly.
Reward attribution
For Pattern B, you must trackrollout_id and candidate_id yourself and pass them to update_reward() so the backend can attribute rewards correctly. The backend uses this to update per-candidate statistics and propose new candidates.
Next steps
- GEPA Online API — session lifecycle, proxy behavior, reward format
- GEPA Online Banking77 — proxy-based walkthrough
- Continual Learning (MIPRO) — MIPRO online overview