For the complete documentation index, see llms.txt. Markdown versions of all docs pages are available by appending .md to any docs URL.
Audio models
Verified : Code examples on this page have been automatically tested and verified.Serve self-hosted audio models such as Voxtral with an AgentgatewayModel, and record the usage and cost of transcription requests.
Serve self-hosted audio models like Voxtral Small through agentgateway with an AgentgatewayModel resource.
About
An AgentgatewayModel declares one client-facing model and attaches it to a Gateway listener. The listener recognizes the OpenAI-compatible audio endpoints. It reads the model from each request, routes the request to the matching model, and records the operation, usage, and cost. You do not create an AgentgatewayBackend or an HTTPRoute.
| API path | gen_ai.operation.name | Usage and cost |
|---|---|---|
/v1/audio/transcriptions | transcription | The audio duration is read from the usage.seconds, usage.prompt_audio_seconds, or top-level duration field of the response. |
/v1/audio/translations | transcription | Same as transcriptions. |
/v1/audio/speech | speech | None. The response is binary audio with no usage fields, so the request has no usage and no cost. |
Transcription and translation requests send the audio file as multipart form data. Agentgateway reads the model form field, and rewrites it when a model transformation maps it to a different upstream name. The other form fields, such as the uploaded file, are forwarded unchanged.
For more information about the AgentgatewayModel API, see Serve a model.
Usage and cost
The audio duration is available as llm.audioSeconds in CEL expressions and as gen_ai.usage.audio_seconds in access logs and traces. To price it, set a perAudioMinute rate in USD per minute for the model in the model cost catalog. The audio cost is the duration in minutes multiplied by the rate.
The built-in catalog includes per-minute rates for some OpenAI transcription models, such as whisper-1. For a self-hosted model such as Voxtral, add your own rate. Key the rate by the provider id and the model name that clients request. For example, the following catalog entry prices the Voxtral model in this guide at $0.004 per minute of audio.
{
"providers": {
"openai": {
"models": {
"mistralai/Voxtral-Small-24B-2507": {
"rates": { "perAudioMinute": "0.004" }
}
}
}
}
}For how to load a catalog into the proxy, see Configure a catalog as a ConfigMap. With this rate, a transcription that reports usage.seconds: 90 costs $0.006. The access log entry includes the following fields.
gen_ai.operation.name=transcription gen_ai.provider.name=openai gen_ai.request.model=mistralai/Voxtral-Small-24B-2507 agw.ai.usage.cost.total=0.006 gen_ai.usage.audio_seconds=90
Alternative: Route audio on an AgentgatewayBackend
You can also route the audio paths through an HTTPRoute to an AgentgatewayBackend that maps each path to a route type in policies.ai.routes. Prefer an AgentgatewayModel for new configurations, because it recognizes the audio endpoints without a routes map, URL rewrites, or an HTTPRoute.
On an AgentgatewayBackend, set the audio paths to Detect to record the same operation, usage, and cost. The Passthrough route type forwards the request and response without parsing them, so it records no usage or cost and applies no LLM policies. For more information about route types, see Multiple endpoints.
Before you begin
- Install and set up an agentgateway proxy.
- Verify that the
AgentgatewayModelAPI is enabled. The API is enabled by default. For the steps, see Verify the AgentgatewayModel feature. - Make sure that your cluster has a node with an NVIDIA GPU and the NVIDIA device plugin or GPU Operator, so that
nvidia.com/gpuis schedulable. The Voxtral Small example in this guide requests one GPU. Without one, the pod staysPending, and the wait in step 1 times out.
Set up and expose your audio model
Step 1: Deploy the audio model (self-hosted)
Deploy the audio model inside your cluster (e.g., Voxtral Small via vLLM) and expose it via a Service.
Deploy Voxtral Small using the official vLLM OpenAI-compatible image.
kubectl apply -f- <<EOF apiVersion: apps/v1 kind: Deployment metadata: name: voxtral-vllm namespace: agentgateway-system spec: replicas: 1 selector: matchLabels: app: voxtral-vllm template: metadata: labels: app: voxtral-vllm spec: containers: - name: voxtral-vllm image: vllm/vllm-openai:latest args: - "vllm" - "serve" - "mistralai/Voxtral-Small-24B-2507" - "--tokenizer_mode" - "mistral" - "--config_format" - "mistral" - "--load_format" - "mistral" - "--tool-call-parser" - "mistral" - "--enable-auto-tool-choice" ports: - containerPort: 8000 name: http resources: limits: nvidia.com/gpu: "1" requests: nvidia.com/gpu: "1" --- apiVersion: v1 kind: Service metadata: name: voxtral-service namespace: agentgateway-system spec: selector: app: voxtral-vllm ports: - port: 80 targetPort: 8000 protocol: TCP EOFThe deployment uses:
vllm/vllm-openai:latest— the official vLLM OpenAI-compatible server imagevllm serve mistralai/Voxtral-Small-24B-2507with Mistral-specific configuration- Port
8000internally (vLLM default) exposed as port80on the Service - NVIDIA GPU reservation (1 GPU)
Wait for the pod to be ready.
kubectl wait --for=condition=ready pod \ -l app=voxtral-vllm \ -n agentgateway-system \ --timeout=300s
Step 2: Verify the model is responding
Verify that the model is responding by listing the models that it serves. The voxtral-service Service is a ClusterIP Service, so send the request from a pod inside the cluster.
kubectl run curl-audio --rm -i --restart=Never \
-n agentgateway-system \
--image=curlimages/curl -- \
curl -s http://voxtral-service.agentgateway-system.svc.cluster.local:80/v1/modelsIn the output, you see a JSON response listing the model.
Step 3: Enable LLM serving on a listener
Add the AgentgatewayModel route kind to the http listener on the agentgateway-proxy Gateway, and verify that the listener supports it. Follow the steps in Enable LLM serving on a listener. The gateway then serves both LLM models and ordinary HTTPRoute traffic on the same port. The model in the next step references the http listener name in parentRefs.sectionName.
Step 4: Create the AgentgatewayModel
Create an AgentgatewayModel that serves the Voxtral model on the http listener.
kubectl apply -f- <<EOF
apiVersion: agentgateway.dev/v1alpha1
kind: AgentgatewayModel
metadata:
name: voxtral-small
namespace: agentgateway-system
spec:
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: agentgateway-proxy
sectionName: http
match:
model: mistralai/Voxtral-Small-24B-2507
provider: OpenAI
baseURL: http://voxtral-service.agentgateway-system.svc.cluster.local/v1
EOFExample output:
agentgatewaymodel.agentgateway.dev/voxtral-small created
Review the following table to understand this configuration. For more information, see the API docs.
| Setting | Description |
|---|---|
parentRefs | Attaches the model to the http listener of the agentgateway-proxy Gateway. |
match.model | The model name that clients send. vLLM serves the model under its Hugging Face name, so clients request mistralai/Voxtral-Small-24B-2507. Without match, the model matches metadata.name, which cannot contain / or uppercase letters. |
provider | OpenAI, because vLLM exposes OpenAI-compatible audio APIs. |
baseURL | The in-cluster address of the Voxtral Service. The path replaces the OpenAI /v1 base path, so keep /v1 to send transcriptions to the /v1/audio/transcriptions path that vLLM serves. |
Step 5: Send audio transcription requests
Create a sample WAV file to transcribe. If you already have an audio file, use its path in the following requests instead.
mkdir -p testdata python3 -c " import wave w = wave.open('testdata/sample-audio.wav', 'wb') w.setnchannels(1); w.setsampwidth(2); w.setframerate(16000) w.writeframes(b'\x00\x00' * 16000) w.close() "Save the gateway address in an environment variable.
export INGRESS_GW_ADDRESS=$(kubectl get svc -n agentgateway-system agentgateway-proxy -o=jsonpath="{.status.loadBalancer.ingress[0]['hostname','ip']}") echo $INGRESS_GW_ADDRESSSend a transcription request through the gateway.
curl http://$INGRESS_GW_ADDRESS/v1/audio/transcriptions \ -F model=mistralai/Voxtral-Small-24B-2507 \ -F file=@./testdata/sample-audio.wav | jqExample output. The sample file is one second of silence, so the text is empty. vLLM reports the audio duration in
usage.seconds.{ "text": "", "usage": { "type": "duration", "seconds": 1 } }Check the proxy access log. The entry records the
transcriptionoperation and the audio duration. The entry includes a cost only if your model catalog has aperAudioMinuterate for the model, as described in Usage and cost.kubectl logs deploy/agentgateway-proxy -n agentgateway-system | grep audio/transcriptions | tail -1Example output:
info request gateway=agentgateway-system/agentgateway-proxy listener=http ... http.method=POST http.path=/v1/audio/transcriptions http.status=200 protocol=llm gen_ai.operation.name=transcription gen_ai.provider.name=openai gen_ai.request.model=mistralai/Voxtral-Small-24B-2507 gen_ai.usage.audio_seconds=1 ...
Note
Supported audio formats: WAV, FLAC, OGG and AU (via libsndfile). These formats are natively supported by the vLLM audio processing pipeline.
Cleanup
You can remove the resources that you created in this guide.kubectl delete agentgatewaymodel voxtral-small -n agentgateway-system
kubectl delete svc voxtral-service -n agentgateway-system
kubectl delete deployment voxtral-vllm -n agentgateway-systemTo stop the listener from serving LLM traffic, remove the AgentgatewayModel entry from allowedRoutes.kinds. Do not delete the agentgateway-proxy Gateway, because other guides use it.