Skip to main content

LLM providers

LLMs write text and interpret news. They never score players or decide a move. Core and the worker each have an llm_client that tries providers in order until one answers.

The short version
  • Default chain: Groq, then Gemini, then Ollama. Each gets one attempt per call.
  • Four features use LLMs: chat, rumor digest, trade notes and trade negotiation.
  • Lineups, waivers, VORP and trade evaluation are computed deterministically.

How does the fallback chain work?​

BehaviorDetail
OrderLLM_PROVIDER_PRIORITY, a comma-separated list of provider:model.
AttemptsOne per provider. There are no retries inside a provider.
Skipped whenThe provider is unknown, has no API key, or is over its local rate budget.
Timeouts15 s for Groq and Gemini. 100 s for Ollama, which can scale up from zero.
Local budgetsA sliding 60 s window per process. Defaults: Groq 30 requests, Gemini 15. Set GROQ_RPM_LIMIT or GEMINI_RPM_LIMIT to change them.
ExhaustedRaises LlmProviderChainExhaustedError. The chat endpoint returns HTTP 503.
TelemetryEach attempt records provider, model, call site, latency and error type in llm_call_metrics.

The two clients ship slightly different default models. Set LLM_PROVIDER_PRIORITY explicitly if you need both to match.

ProviderAuthNotes
GroqGROQ_API_KEYDefault first choice
GeminiGEMINI_API_KEYSecond choice
OllamaNoneRuns in the cluster and starts on demand through a KEDA proxy

Keys come from OpenBao as environment variables. Local development can fall back to the bao CLI.

Which features use an LLM?​

FeatureRuns inCall siteWhen
Chat answersCore API, POST /querychat_queryOn request
Rumor digestWorker, rumor_digest_bot.jsrumor_digestDaily 11:00 America/Chicago
Trade proposal notesWorker, trade_proposal.jstrade_proposal_packages, trade_proposal_pitchTrade scan, Wednesday and Friday 13:00
Trade negotiationWorker, trade_bot.jstrade_negotiationIncoming-trade handling
  • Chat removes Ollama from its chain, because the endpoint is synchronous and a cold start can take about 90 seconds. Override with CHAT_LLM_PROVIDER_PRIORITY.
  • Rumor digest is all-or-nothing. If any chunk fails, nothing is stored and the next run retries. See Rumor digest.
  • Trade features only draft and stage text. A person approves every offer. See the Safety model.

Where do prompts end and logic begin?​

PromptLives in
Chat system promptfantasy-core-pipeline, src/services/chat_service.py. It tells the model to answer only from the supplied JSON context.
Digest, trade proposal and negotiation promptsfantasy-browser-worker, src/bots/

The model's output is advisory. A rumor verdict is only an input to rumor_action_service, and a trade note never changes the evaluated terms.

Configuration​

VariablePurpose
LLM_PROVIDER_PRIORITY, CHAT_LLM_PROVIDER_PRIORITYChain order
GROQ_API_KEY, GEMINI_API_KEYProvider credentials
GROQ_RPM_LIMIT, GEMINI_RPM_LIMITLocal request budgets
LLM_REQUEST_TIMEOUT_SECONDS, OLLAMA_REQUEST_TIMEOUT_SECONDSTimeouts
LLM_HISTORY_CAPTURE_CONTENT, LLM_CONTENT_RETENTION_DAYSWhether to keep prompt text for the Activity page, and for how long

Where is the code?​

fantasy-core-pipeline: src/llm_client.py, src/services/chat_service.py. fantasy-browser-worker: src/lib/llm_client.js, src/bots/.