Arena¶
src.domains.arena.endpoints
¶
REST API endpoints for stateless LLM testing in the arena.
The arena provides a lightweight query interface for testing models without creating conversations or storing history. Useful for quick model comparisons, experimentation, and benchmarking.
Key Features: - Stateless: No conversation history or message storage. - Streaming: Real-time token generation via Server-Sent Events. - KB-aware: Automatically injects relevant context from attached Knowledge Bases. - Customizable: Supports temperature, top_p, and custom instructions. The output budget is not a request parameter: the backend derives it from the context window the model runs in (see docs/guides/conversations.md).
Architecture
┌──────────────┐ │ POST /arena/ │ │ {llm_id}/query│ └───────┬──────┘ │ (1) Validate llm_id + payload (ArenaQueryPayload) ↓ ┌──────────────┐ │ ArenaService │ ← get_prompting_strategy(param_size) │.query_llm_ │ ← build_agent_system_prompt() + KB context │ stream() │ ← AgentRunner (stateless) → ChatOpenAI(base_url) └───────┬──────┘ │ (2) Yield tokens via StreamingResponse ↓ ┌──────────────┐ │ Client │ ← Receives text/plain stream └──────────────┘
Use Cases
- Model comparison: Query 2+ models with identical prompt, compare outputs.
- Quick testing: Test custom prompts without creating conversations.
- Benchmarking: Measure generation speed and quality for different models.
Endpoints
- POST /arena/{llm_id}/query → Stream stateless response for given question.
Example
POST /arena/42/query { "question": "Explain quantum entanglement in simple terms.", "temperature": 0.7, "top_p": 0.9, "custom_prompt": "Use analogies suitable for a 10-year-old." } Response: StreamingResponse(text/plain) → "Imagine two magic coins..."
get_arena_service(db=Depends(get_db))
¶
Dependency injection provider for ArenaService.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
db
|
Session
|
Database session injected by FastAPI. |
Depends(get_db)
|
Returns:
| Type | Description |
|---|---|
ArenaService
|
Configured ArenaService instance with database access. |
Source code in backend/src/domains/arena/endpoints.py
query_arena(llm_id, payload, service=Depends(get_arena_service))
async
¶
Stream stateless LLM response without conversation history.
Queries a model with a single question, no context from previous messages. Useful for quick testing, benchmarking, and model comparison. Automatically injects KB context if the model has a Knowledge Base attached.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
llm_id
|
int
|
Database ID of the LLM to query. |
required |
payload
|
ArenaQueryPayload
|
Query request with question, temperature, top_p, custom_prompt. |
required |
service
|
ArenaService
|
ArenaService instance injected by FastAPI. |
Depends(get_arena_service)
|
Returns:
| Name | Type | Description |
|---|---|---|
StreamingResponse |
Real-time token stream (text/plain). |
Raises:
| Type | Description |
|---|---|
HTTPException
|
404 if llm_id not found, 500 on model loading or generation errors. |
Example
POST /arena/42/query { "question": "What is the Heisenberg uncertainty principle?", "temperature": 0.7, "top_p": 0.9, "custom_prompt": "Explain like I'm 5 years old." } Response: StreamingResponse → "Imagine you have a tiny ball..."
Source code in backend/src/domains/arena/endpoints.py
src.domains.arena.schemas
¶
Pydantic validation schemas for arena stateless queries.
Defines request schemas for the arena domain, validating query parameters and generation settings for stateless LLM testing.
Example
from src.domains.arena.schemas import ArenaQueryPayload
query = ArenaQueryPayload( question="What is quantum computing?", temperature=0.7, top_p=0.9, custom_prompt="Use simple language" )
ArenaQueryPayload
¶
Bases: BaseModel
Request schema for stateless arena queries with generation parameters.
Validates user input for arena LLM queries, enforcing ranges for sampling parameters and ensuring non-empty questions. Includes optional custom instructions for specialized prompting.
Attributes:
| Name | Type | Description |
|---|---|---|
question |
str
|
The question/prompt to send to the model (trimmed; may be empty only when images or documents are attached). |
images |
Optional[List[str]]
|
Optional base64 data-URL images attached to the question (vision models). |
attachments |
Optional[List[str]]
|
Local filesystem paths of documents/folders attached to the question. |
temperature |
Optional[float]
|
Sampling temperature (0.0=deterministic, 2.0=creative, default=0.1). |
top_p |
Optional[float]
|
Nucleus sampling threshold (0.0-1.0, default=0.5). |
max_new_tokens |
Optional[int]
|
Accepted and ignored -- the output budget comes from the model's context window, not from the client. |
custom_prompt |
Optional[str]
|
Optional additional instructions appended to system prompt. |
Example
payload = ArenaQueryPayload( ... question="Explain relativity", ... temperature=0.7, ... top_p=0.9, ... custom_prompt="Use analogies" ... )
validate_question_or_attachments()
¶
Ensure the turn carries text, at least one image, or a document.
Image-only asks are valid vision-model turns (mirrors conversations,
136 C) and a document-only ask is a valid "what does this say?" turn¶
(#492); a fully empty ask is still rejected.
Returns:
| Type | Description |
|---|---|
|
The payload with a trimmed question. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If question is empty/whitespace and nothing is attached. |
Source code in backend/src/domains/arena/schemas.py
src.domains.arena.services
¶
Business logic for stateless arena LLM queries with KB-aware prompting.
The arena is "conversation minus state": a single-model, no-history streaming
query. Since the LangChain refactor it shares the conversation AgentRunner
but runs it statelessly (thread_id=None, no checkpointer, no summarization).
Pipeline:
1. Validate the question and fetch the LLM.
2. Pick a prompting strategy (param_size-based) and, if the model has a KB
attached, retrieve top-k chunks (hybrid pgvector search via kb_utils).
3. Build a real system prompt (size-adaptive + custom + KB context) and stream
the answer as raw token text via the shared agent runner.
The A/B "duel" is orchestrated entirely on the frontend (N parallel calls to this endpoint); the runner's engine guard serializes them on the single-model engine, so model swaps don't thrash the subprocess.
ArenaService(db)
¶
Service layer for arena stateless query processing.
Initialize arena service with database session.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
db
|
SQLAlchemy database session for repository access. |
required |
Source code in backend/src/domains/arena/services.py
query_llm_stream(llm_id, payload)
async
¶
Query an LLM in stateless arena mode and stream response tokens (raw text).
Raises:
| Type | Description |
|---|---|
InvalidInputException
|
empty question. |
ModelNotFoundException
|
|
KnowledgeBase * Exception
|
KB retrieval failure. |
Generation/model-load failures are NOT raised here — the runner yields the
[ERROR_MESSAGE_SYSTEM] sentinel inline (unified with conversation).
Source code in backend/src/domains/arena/services.py
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 | |