Polyphemus (Development)
Polyphemus is the model-serving service used for adversarial generation workloads. It proxies generation requests to Vertex AI and exposes authenticated REST endpoints.
Runtime and deployment notes
- Runtime baseline: Python
>=3.12 - Router module:
apps/polyphemus/src/rhesis/polyphemus/routers/services.py - Request schemas:
apps/polyphemus/src/rhesis/polyphemus/schemas/schemas.py - Docker image: API-only service image. PyTorch is not bundled in the Polyphemus container; model weights and serving runtime live behind Vertex AI.
- Dependency shape: Polyphemus depends on backend core only. The SDK, Penelope, Garak, and model-serving stacks live outside the runtime image.
Building the Docker image
Build the Polyphemus image from the repository root. The Dockerfile depends on
monorepo paths outside apps/polyphemus, so using apps/polyphemus as the build
context will fail.
The image uses a two-stage build: the builder installs dependencies with
uv sync --no-dev, and the runtime stage copies only the API service and
required backend package files. The builder copies uv and uvx from
mirror.gcr.io/astral/uv:0.11.19 for reproducible and reliable Docker builds.
Keep the uv tag and registry mirror aligned with the Dockerfile when
upgrading service image builds.
API endpoints
Polyphemus exposes two primary generation endpoints:
| Endpoint | Purpose | Auth |
|---|---|---|
POST /generate | Single generation request | Bearer token required |
POST /generate_batch | Batch generation for multiple requests | Bearer token required |
/generate_batch accepts up to 50 items per call (MAX_BATCH_SIZE).
Request fields
Both endpoints use the same GenerateRequest shape. Batch requests wrap multiple GenerateRequest objects under requests.
| Field | Type | Default | Description |
|---|---|---|---|
messages | Message[] | Required | Chat messages with role and content |
model | string | null | polyphemus-default | Public alias resolved by the service |
temperature | float | null | 0.7 | Values less than or equal to 0 are reset to 0.7 |
max_tokens | int | null | Not sent | Passed to vLLM only when provided |
top_p | float | null | 1.0 | Must be greater than 0 and less than or equal to 1 |
top_k | int | null | Not sent | Negative values are ignored |
json_schema | object | null | Not sent | Enables structured output and test-generation hardening |
The service retries transient Vertex AI failures (429, 500, 502, 503, 504) up to three attempts with exponential backoff.
Environment configuration
Polyphemus reads Vertex AI target configuration from environment variables:
| Variable | Required | Description |
|---|---|---|
POLYPHEMUS_ENDPOINT_ID | Yes | Vertex AI endpoint identifier |
POLYPHEMUS_PROJECT_ID | Yes | GCP project ID for endpoint invocation |
POLYPHEMUS_LOCATION | No | Vertex AI region (defaults to us-central1) |
POLYPHEMUS_DEFAULT_MODEL | For default alias | Internal Vertex/vLLM model backing the polyphemus-default alias |
POLYPHEMUS_OPUS_MODEL | For opus alias | Internal Vertex/vLLM model backing the polyphemus-opus alias |
POLYPHEMUS_BATCH_CONCURRENCY | No | Maximum concurrent Vertex calls per batch request (defaults to 10) |
VLLM_LOGGING_LEVEL | No | vLLM container log verbosity for Vertex serving (for example, DEBUG, INFO) |
If required variables are missing, the service returns HTTP 400 with configuration error details.
Authentication and rate limits
Polyphemus accepts two Bearer-token formats:
| Token type | Format | Typical caller |
|---|---|---|
| Rhesis API token | rh-* | SDK users, scripts, and notebooks |
| Delegation JWT | JWT | Backend service-to-service calls |
API tokens are validated through the backend token store and require an active, verified user. Delegation JWTs are validated by the Polyphemus delegation-token validator. Rate limiting uses the authenticated user identity when available.
Batch rate limiting counts the HTTP request, not every item inside requests.
Deployment region variable mapping (v0.2.8+)
Region configuration uses two separate variables depending on context:
| Context | Variable | Source | Where it is consumed |
|---|---|---|---|
| GitHub Actions CI/CD workflow | REGION | secrets.REGION (falls back to us-central1) | .github/workflows/polyphemus.yml |
| Running Polyphemus service | POLYPHEMUS_LOCATION | Set to $REGION by the CI workflow | apps/polyphemus/src/rhesis/polyphemus/routers/services.py |
| Vertex model deployment script | GCP_REGION | Set directly in the local environment (not mapped from REGION) | apps/polyphemus/model_deployment/config.py |
The workflow maps REGION → POLYPHEMUS_LOCATION automatically for service deployments.
The model deployment script reads GCP_REGION independently; when running it locally you must
export GCP_REGION yourself (see apps/polyphemus/model_deployment/.env.example).
vLLM logging level (v0.2.9+)
When deploying Polyphemus to Vertex AI, you can control serving container verbosity with
VLLM_LOGGING_LEVEL.
If set, deployment injects VLLM_LOGGING_LEVEL into the serving container environment.
Polyphemus deployment separates the lightweight API container from the Vertex AI serving container. Configure vLLM logging on the Vertex deployment, not by installing PyTorch or model runtime dependencies into the Polyphemus API image.
Request hardening and adversarial primer
Polyphemus enforces adversarial behavior on the server side before forwarding a request to Vertex AI. This keeps SDK, platform, and direct API callers aligned even if they assemble messages differently.
The hardening path is:
- The service validates that at least one non-system message has content.
- It resolves the public model alias (
polyphemus-defaultorpolyphemus-opus). - It injects an adversarial primer into the system message if that primer is not already present.
- It builds the Vertex AI
rawPredictrequest body.
Structured-output requests and direct conversation requests are handled slightly differently:
| Request shape | System-message handling | User-message handling |
|---|---|---|
json_schema present | Primer is inserted after /no_think and before schema instructions | User content receives the adversarial attack prefix |
No json_schema | Conversational primer is prepended to the system message | User content is unchanged |
| No system message | A new system message is inserted | Same behavior as above for the request shape |
The injection is idempotent: if the primer text is already present, Polyphemus does not add it again.
Product callers do not need to add their own adversarial primer. Add domain-specific instructions in the normal system prompt and let the service enforce the shared hardening layer.
Batch request and response format
Batch execution is partially tolerant: one failed item does not fail the whole
HTTP request. The failed item returns an error field, and the service logs
the exception at error level with stack trace details for operators.
Batch concurrency is capped by POLYPHEMUS_BATCH_CONCURRENCY to avoid overwhelming the shared HTTP pool or Vertex quota. The default is 10.