Link Search Menu Expand Document
Start for Free

Deploying the Voicebox Service

Page Contents
  1. Background
  2. Frame Stores
    1. Choosing a Backend
    2. Local Disk
    3. Amazon S3
      1. Example
    4. Azure Blob
      1. Example
  3. Tuning the Agent
  4. Health and Readiness Probes

Applies to: Launchpad v4.0.0+ · Voicebox Service v1.0.0+

Upgrading from an earlier Launchpad release requires a configuration change in every deployment. See the 4.0.0 release notes for the steps.

A practical guide for operating the Voicebox Service: how it stores the results it computes, which storage backend to choose, what to tune, and what to watch.

For a quickstart — pulling the image and running the service — see Running the Voicebox Service. For the vbx-config.json file and the supported LLM providers, see Voicebox Configuration File.

Background

The Voicebox Service produces frames: the tabular results of the queries it runs against Stardog to answer a conversation turn. It persists them so a later turn can reuse a previous result without re-querying Stardog.

Conversation memory is separate from frames. Launchpad resends the conversation lineage on every turn, so the server holds no per-conversation memory between turns. The practical upshot is that frames are an optimization, not a source of truth. If a frame is missing — disk full, object expired, volume lost — nothing is corrupted.

This is the main way v1.x differs from the v0.x service, which kept no frames and recomputed every result.

Frame Stores

The backend is selected with VOICEBOX_FRAME_STORE_BACKEND. Every backend writes frames as snappy-compressed Parquet, one object per frame, in the same layout: {prefix}/{conversation_id}/{frame_id}.parquet.

Choosing a Backend

  local (default) s3 azure
Frames live on the container’s own disk an S3 bucket an Azure Blob container
Persistent volume required not needed not needed
Replicas exactly one multiple multiple
Expiring old frames built-in sweeper, on a TTL bucket lifecycle rule, which you configure Blob lifecycle rule, which you configure
Credentials none standard AWS credential chain connection string, account key, SAS token, or an Entra identity
Suited to a single-node deployment, or evaluation a deployment already running in AWS a deployment already running in Azure

The deciding constraint is usually replica count. local pins the service to a single instance, because the store is that instance’s own disk and a second replica would read an empty one. The s3 and azure backends remove both the volume requirement and the single-instance limit.

Local Disk

The default. Frames are written under the frame store path, which defaults to /var/lib/voicebox/frames.

Mount a writable volume at that path. Without one, frames land in the container’s writable layer and vanish on restart — the service still works, it just re-fetches from Stardog every time.

  • Docker (named volume): Mount it at the frame store path. The image pre-creates that directory owned by the non-root container user, and a named volume inherits that ownership, so no extra steps are needed. Prefer a named volume over a bind mount.
  • Kubernetes: Use a single-replica deployment with a ReadWriteOnce persistent volume mounted at the frame store path, a Recreate update strategy, and a security context that makes the mount writable by the non-root container user.

Two behaviors are specific to this backend:

  • Eviction is built in. A background sweeper deletes frames older than the TTL and reaps orphaned .tmp files after an hour. No external cron or cleanup job is needed. The sweeper does not run on the s3 or azure backends, where expiry is the storage service’s own lifecycle rule.
  • Disk-full is non-fatal. When the volume fills, the user still gets their answer; the frame just isn’t written and the service logs a warning. Recover by growing the volume or lowering the TTL.
Environment Variable Default Notes
VOICEBOX_FRAME_STORE_LOCAL_PATH /var/lib/voicebox/frames Mount the volume here.
VOICEBOX_FRAME_STORE_LOCAL_TTL_DAYS 7 Lower on a small volume to reclaim disk faster; raise for longer-lived conversations. Must be > 0 while the sweeper is enabled.
VOICEBOX_FRAME_STORE_SWEEPER_ENABLED true Set to false to disable the background eviction sweeper entirely.
VOICEBOX_FRAME_STORE_SWEEP_INTERVAL_SECONDS half the TTL How often a sweep runs. Leave unset unless you need a specific cadence.
VOICEBOX_FRAME_STORE_LARGE_FRAME_WARN_MB 10 Lower for earlier oversized-frame warnings; 0 disables them.

Sizing. Rough disk need is avg frame size × frames per turn × turns per day × TTL days. 20 GB is a comfortable start for a small team at the 7-day default. The service periodically logs volume telemetry, which you can use to trend real usage and resize from data.

Amazon S3

Set VOICEBOX_FRAME_STORE_BACKEND=s3.

Environment Variable Default Notes
VOICEBOX_FRAME_STORE_S3_BUCKET not set Required for this backend. The service fails to start without it.
VOICEBOX_FRAME_STORE_S3_PREFIX voicebox/frames Key prefix within the bucket. Bucket-relative.

Credentials and region are not Voicebox settings. The service uses the standard AWS credential chain, so on EKS an IAM role for the service account is usually all that is needed, and the bucket region is taken from the usual AWS environment such as AWS_REGION. Configure both the way you would for any other AWS client in your deployment.

Configure expiry with an S3 lifecycle rule on the bucket. The built-in sweeper does not run on this backend, so without a lifecycle rule frames accumulate indefinitely.

Example

A complete environment file for a service running on AWS, using Bedrock for the LLM and S3 for frames.

# The JSON configuration file, as in any deployment
VBX_CONFIG_FILE=/voicebox-config/vbx-config.json

# Frames in S3 rather than on local disk
VOICEBOX_FRAME_STORE_BACKEND=s3
VOICEBOX_FRAME_STORE_S3_BUCKET=my-voicebox-frames

# The region the LLM is served from
BEDROCK_REGION=us-west-2

# The region the bucket is in, read by the AWS client rather than by Voicebox.
# Omit it and the credentials below if the pod assumes an IAM role.
AWS_REGION=us-west-2
AWS_ACCESS_KEY_ID=<access_key_id>
AWS_SECRET_ACCESS_KEY=<secret_access_key>

with the matching vbx-config.json:

{
  "default_llm_config": {
    "llm_provider": "bedrock",
    "llm_name": "us.anthropic.claude-haiku-4-5-20251001-v1:0",
    "max_tokens": 16000
  }
}

BEDROCK_REGION and AWS_REGION are separate settings and do not have to match. The first selects where the model is served from, the second where the bucket lives.

No volume is mounted and no replica limit applies, so the service can be scaled like any other stateless deployment.

Azure Blob

Set VOICEBOX_FRAME_STORE_BACKEND=azure.

Environment Variable Default Notes
VOICEBOX_FRAME_STORE_AZURE_CONTAINER not set Required for this backend. The service fails to start without it.
VOICEBOX_FRAME_STORE_AZURE_ACCOUNT not set Storage account name, expanded to https://<account>.blob.core.windows.net. Required unless a connection string is set.
VOICEBOX_FRAME_STORE_AZURE_PREFIX voicebox/frames Blob name prefix within the container.
VOICEBOX_FRAME_STORE_AZURE_CONNECTION_STRING not set Carries its own endpoint and key. The simplest single-value option.
VOICEBOX_FRAME_STORE_AZURE_ACCOUNT_KEY not set Shared account key, paired with the account name.
VOICEBOX_FRAME_STORE_AZURE_SAS_TOKEN not set A scoped, expiring alternative to the account key.

Credentials resolve in that order: connection string, then account key, then SAS token, then the ambient Azure identity. Leaving all of them unset is the no-secrets path, which picks up a service principal from the environment, AKS workload identity, a managed identity, or a developer’s az login session. The startup log records which one was used, so a silent fall-through to the wrong credential is visible rather than mysterious.

One thing about the storage account is worth getting right up front, because it is not obvious once you hit it: the role on the container must be a data-plane role, such as Storage Blob Data Contributor. Control-plane roles like Owner and Contributor grant no access to blob data at all — an account that looks fully permissioned in the portal can still return 403.

Either kind of account works. An account with hierarchical namespace enabled (Azure Data Lake Storage Gen2) serves the same Blob API, and lifecycle rules apply there too, so no separate configuration is needed. Voicebox has been verified against an account without it.

Configure expiry with an Azure Blob Lifecycle Management rule, using daysAfterModificationGreaterThan for the age condition. One difference from S3 catches most people out: the rule’s prefixMatch starts with the container name, so for container frames and the default prefix the value is frames/voicebox/frames, not voicebox/frames. Blob soft delete must also be off, or deleted frames are retained anyway.

Azure evaluates lifecycle rules asynchronously, and the first pass can take up to 48 hours. Do not conclude a rule is broken because nothing disappeared overnight.

Example

An environment file for a service running in Azure, storing frames in a Blob container.

# The JSON configuration file, as in any deployment
VBX_CONFIG_FILE=/voicebox-config/vbx-config.json

# Frames in Azure Blob rather than on local disk
VOICEBOX_FRAME_STORE_BACKEND=azure
VOICEBOX_FRAME_STORE_AZURE_ACCOUNT=myvoiceboxstorage
VOICEBOX_FRAME_STORE_AZURE_CONTAINER=frames

# Omit this and the service uses the ambient Azure identity instead,
# such as a workload or managed identity
VOICEBOX_FRAME_STORE_AZURE_ACCOUNT_KEY=<account_key>

Tuning the Agent

These apply to every backend. Most deployments only touch these; leave the rest at their defaults.

Environment Variable Default When to change
VOICEBOX_CODE_EXEC_TIMEOUT_SECONDS 30 How long the service may spend analyzing query results while answering a question, in seconds. Raise if large result sets are timing out during analysis; must be >= 1.
VOICEBOX_QUERY_EXEC_TIMEOUT_SECONDS 60 Timeout applied to each query the service runs against Stardog, in seconds. Raise for slow queries on large databases; set to 0 to apply no Voicebox timeout, so the Stardog endpoint’s own configured query timeout governs.
VOICEBOX_QUERY_MAX_RESULTS 100000 Maximum rows a single query may return, applied as the query LIMIT. Lower it to reduce memory use and frame sizes on wide result sets; must be >= 1.
VOICEBOX_RECURSION_LIMIT not set Maximum number of steps the agent may take to answer one question. Unset uses the built-in default (35). Raise for complex, multi-step questions that report running out of steps; must be >= 1.
VOICEBOX_FRAME_STORE_CACHE_SIZE 100 Frames held in each instance’s in-memory read cache. Raise to cut reads against the store on long conversations, at the cost of memory.

Health and Readiness Probes

  • Liveness: GET /system/health (returns 204).
  • Readiness: GET /system/storage-ready (200 when the frame path is writable, 503 otherwise).

Keep the disk-writability check on readiness, not liveness, so a transient full disk pulls the instance from traffic instead of restarting it into a crash loop.

On the s3 and azure backends, /system/storage-ready always returns 200 with "checked": false in the body. That means the check does not apply here, not that the bucket or container was verified. Do not treat a healthy readiness probe as evidence that the store is reachable.

The service does check the store once, at startup, and logs the result: look for frame_store.startup_check_ok, or frame_store.startup_check_failed with a reason such as a missing bucket, denied access, or an unreachable endpoint. The check is advisory and never blocks startup.