Chapter 8. Process batch inference jobs with Distributed Inference with llm-d
You can use batch inference with Distributed Inference with llm-d to process large volumes of inference requests asynchronously. Batch inference enables fire-and-forget job submission through the OpenAI-compatible /v1/batches and /v1/files API, with durable job state and priority-aware scheduling that protects real-time inference service level objectives (SLOs).
Batch inference for Distributed Inference with llm-d is a Technology Preview feature only. Technology Preview features are not supported with Red Hat production service level agreements (SLAs) and might not be functionally complete. Red Hat does not recommend using them in production. These features provide early access to upcoming product features, enabling customers to test functionality and provide feedback during the development process.
For more information about the support scope of Red Hat Technology Preview features, see Technology Preview Features Support Scope.
8.1. Batch inference for Distributed Inference with llm-d Copy linkLink copied to clipboard!
You can use batch inference with Distributed Inference with llm-d to submit large volumes of inference requests as asynchronous jobs and retrieve results later, without maintaining active connections. The batch inference subsystem persists jobs across gateway pod restarts and uses priority-aware scheduling to run batch workloads during low-utilization periods, protecting real-time inference service level objectives (SLOs) on shared GPU infrastructure.
When to use batch inference
Use batch inference for workloads where immediate responses are not required and you need to maximize throughput across a large volume of requests while meeting defined completion time targets.
Batch inference enables use cases including the following:
- Autonomous background agents performing multi-step reasoning and deep research
- Offline evaluations
- Dataset processing
- Embedding generation
- Large-scale model evaluation
All of these use cases follow the same workflow: upload a JSONL input file, create a batch job, monitor progress, and download results. The specific use case is determined by the content and structure of the JSONL input file you provide.
Batch inference provides the following benefits:
- Increases GPU infrastructure use by filling capacity during periods of lower interactive traffic
- Protects real-time inference SLOs by running batch workloads at lower priority without interfering with interactive traffic
- Enables cost-optimized processing by taking advantage of differential billing between batch and interactive workloads
Inference modes in Distributed Inference with llm-d
Distributed Inference with llm-d supports two inference modes that address different latency and throughput requirements:
- Real-time inference
- Synchronous request-response with latency on the order of seconds to minutes. Model servers process requests immediately. Use real-time inference for interactive applications such as chatbots, code completion, and live search.
- Batch inference
-
Asynchronous fire-and-forget job submission with latency on the order of hours. You can submit requests as batch jobs through the OpenAI-compatible
/v1/batchesAPI. Requests are processed in the background. Use batch inference for high-volume workloads that do not require immediate responses, such as embedding generation and model evaluation.
Batch inference architecture
The batch inference subsystem consists of the following components:
- Batch gateway API server
-
Exposes the OpenAI-compatible
/v1/batchesand/v1/filesendpoints. Receives batch job submissions, validates input files, and stores job metadata. The API server is deployed and managed by the Batch Gateway Operator. - Batch processor
Reads pending batch jobs from a queue, concurrently dispatches inference requests from each job to model servers through the internal ClusterIP gateway, and writes results to S3-compatible storage. The processor uses AIMD (additive-increase / multiplicative-decrease) adaptive concurrency control to dynamically adjust concurrent request limits based on success and failure signals, automatically backing off under load to protect interactive traffic. Retry logic with exponential backoff handles transient failures.
To maximize throughput, the processor sorts requests by system-prompt hash before dispatching, optimizing prefix cache reuse across the serving pool by keeping identical-prefix KV-cache entries hot. The processor integrates with Distributed Inference with llm-d’s intelligent request routing and flow control mechanisms, allowing batch workloads to benefit from prefix-cache-aware routing and automatic load balancing.
- Garbage collector
- Periodically cleans up completed, failed, and expired batch jobs based on configurable retention periods. Removes associated input and output files from storage.
The batch inference subsystem uses a pluggable storage architecture with two layers:
- A database layer for persisting batch metadata, including job state, request counts, and token usage
- An exchange layer for job queuing, priority queues, event channels, and in-flight job tracking
The available storage plugins are PostgreSQL for the database layer and Redis or Valkey for the exchange layer. The subsystem also requires S3-compatible storage or filesystem storage for batch input and output files.
OpenAI Batch API compatibility
The batch inference API is compatible with the OpenAI Batch API specification. You submit batch jobs by uploading a JSONL input file through the /v1/files endpoint and creating a batch job through the /v1/batches endpoint. The batch inference subsystem supports the /v1/chat/completions, /v1/completions, /v1/embeddings, /v1/responses, and /v1/moderations inference endpoints within batch requests.
Each line in the JSONL input file has one inference request with a unique custom_id that correlates the request to its result in the output file. The API server validates the input file format before scheduling the job.
By default, batches are limited to 50,000 requests and input files are limited to 200 MB. These limits are configurable. Optionally, you can apply a RateLimitPolicy on the external gateway to enforce per-user rate limiting for batch API requests.
Priority-aware dispatching for batch workloads
The batch gateway maintains an internal priority queue of jobs sorted by SLO deadline. Each job SLO is computed from its completion_window at creation time, so jobs with the nearest deadline are processed first.
You can use shared GPU infrastructure for both real-time and batch workloads without dedicated GPU pools for each workload type. To achieve this, configure the batch gateway to work with the flow control mechanism in Distributed Inference with Distributed Inference with llm-d. In this setup, the SLOs of real-time workloads are protected while batch workloads make progress toward completion by utilizing free GPU capacity. When dispatching inference requests, the batch processor sets flow control headers that communicate the job SLO deadline and priority band to the router. The priority band is determined by a configurable InferenceObjective CRD that you specify in the model gateway configuration. Batch workloads are typically assigned a lower priority band than interactive workloads, so that they are dispatched only when capacity is available.
Multi-tenancy
The batch inference subsystem supports multi-tenancy through the X-MaaS-Username header. Each user’s batch jobs and files are isolated. Authentication is delegated to the external gateway’s AuthPolicy, which validates bearer tokens in the Authorization header (Kubernetes ServiceAccount tokens or user tokens) and injects the authenticated username into the request headers for the batch gateway to use for tenant identification.
8.2. Configure batch inference for Distributed Inference with llm-d Copy linkLink copied to clipboard!
Additional resources
You can deploy and configure the batch inference subsystem for Distributed Inference with llm-d to enable asynchronous batch job submission on shared GPU infrastructure. The batch gateway is deployed through the AI Gateway component in the DataScienceCluster CR and configured with backing services, internal routing for model authorization, and external API routes for batch job submission.
Prerequisites
- Distributed Inference with llm-d is deployed with Inference Gateway on Red Hat OpenShift AI.
-
The batch gateway component is enabled in the
DataScienceClusterresource. - You have cluster administrator access.
- You have installed the OpenShift CLI (`oc`). For more information, see Installing the OpenShift CLI.
A Redis or Valkey instance is available for job queuing.
In disconnected environments, deploy Redis or Valkey cluster-locally.
A PostgreSQL instance is available for batch metadata storage.
In disconnected environments, deploy PostgreSQL cluster-locally.
S3-compatible storage, such as AWS S3, MinIO, or Ceph, is available for batch input and output files.
In disconnected environments, deploy MinIO or another S3-compatible storage service cluster-locally.
Procedure
Verify that the batch gateway component is enabled in the
DataScienceClusterresource:$ oc get datasciencecluster default-dsc -o yamlExpected output:
spec: components: aigateway: managementState: Managed batchGateway: managementState: ManagedIf the batch gateway component is not enabled, edit the
DataScienceClusterresource:$ oc edit datasciencecluster default-dscAdd or update the following configuration:
spec: components: aigateway: managementState: Managed batchGateway: managementState: ManagedSave the changes and wait for the
DataScienceClusterto reconcile. The operator creates the batch gateway namespace and deploys the Batch Gateway Operator.Create an internal ClusterIP gateway for batch processor inference routing.
The batch processor routes inference requests through this internal gateway to enforce model-level authorization while bypassing per-user token rate limits on the external gateway.
Save the following YAML to a file named
batch-internal-gateway.yaml:apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: batch-internal-gateway namespace: openshift-ingress annotations: networking.istio.io/service-type: ClusterIP spec: gatewayClassName: openshift-default listeners: - name: http port: 80 protocol: HTTP allowedRoutes: namespaces: from: Selector selector: matchLabels: llm-d.ai/gateway-route: "true"Apply the Gateway resource:
$ oc apply -f batch-internal-gateway.yamlImportantThe
networking.istio.io/service-type: ClusterIPannotation ensures the gateway is not externally accessible. The internal gateway uses HTTP only because traffic is cluster-internal.Create an
HTTPRouteto route batch processor inference requests to the model server through the internal gateway.The batch processor rewrites the request path to match the model server’s API and includes the user’s original authentication token.
Save the following YAML to a file named
batch-llm-route.yaml:apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: batch-llm-route namespace: <llmisvc_namespace> spec: parentRefs: - name: batch-internal-gateway namespace: openshift-ingress rules: - matches: - path: type: PathPrefix value: /<llmisvc_namespace>/<llmisvc_name>/v1/chat/completions filters: - type: URLRewrite urlRewrite: path: type: ReplacePrefixMatch replacePrefixMatch: /v1/chat/completions backendRefs: - group: inference.networking.k8s.io kind: InferencePool name: <inference_pool_name> port: 80 - matches: - path: type: PathPrefix value: /<llmisvc_namespace>/<llmisvc_name>/v1/completions filters: - type: URLRewrite urlRewrite: path: type: ReplacePrefixMatch replacePrefixMatch: /v1/completions backendRefs: - group: inference.networking.k8s.io kind: InferencePool name: <inference_pool_name> port: 80 - matches: - path: type: PathPrefix value: /<llmisvc_namespace>/<llmisvc_name>/v1/embeddings filters: - type: URLRewrite urlRewrite: path: type: ReplacePrefixMatch replacePrefixMatch: /v1/embeddings backendRefs: - group: inference.networking.k8s.io kind: InferencePool name: <inference_pool_name> port: 80 - matches: - path: type: PathPrefix value: /<llmisvc_namespace>/<llmisvc_name>/v1/responses filters: - type: URLRewrite urlRewrite: path: type: ReplacePrefixMatch replacePrefixMatch: /v1/responses backendRefs: - group: inference.networking.k8s.io kind: InferencePool name: <inference_pool_name> port: 80 - matches: - path: type: PathPrefix value: /<llmisvc_namespace>/<llmisvc_name>/v1/moderations filters: - type: URLRewrite urlRewrite: path: type: ReplacePrefixMatch replacePrefixMatch: /v1/moderations backendRefs: - group: inference.networking.k8s.io kind: InferencePool name: <inference_pool_name> port: 80where:
<llmisvc_namespace>-
Specifies the namespace where the
LLMInferenceServiceis deployed. <llmisvc_name>-
Specifies the name of the
LLMInferenceServiceresource. <inference_pool_name>-
Specifies the name of the
InferencePoolresource created by theLLMInferenceService.
Apply the HTTPRoute resource:
$ oc apply -f batch-llm-route.yamlCreate an
AuthPolicyfor the batch-llm-route to enforce model-level authorization:Save the following YAML to a file named
batch-llm-authpolicy.yaml:apiVersion: kuadrant.io/v1 kind: AuthPolicy metadata: name: batch-llm-authpolicy namespace: <llmisvc_namespace> spec: targetRef: group: gateway.networking.k8s.io kind: HTTPRoute name: batch-llm-route rules: authentication: "kubernetes-token": kubernetesTokenReview: audiences: - "https://kubernetes.default.svc" authorization: "llmisvc-access": kubernetesSubjectAccessReview: user: selector: auth.identity.user.username resourceAttributes: group: serving.kserve.io resource: llminferenceservices name: <llmisvc_name> namespace: <llmisvc_namespace> verb: get response: success: headers: "X-MaaS-Username": plain: selector: auth.identity.user.usernameApply the AuthPolicy resource:
$ oc apply -f batch-llm-authpolicy.yamlThe
AuthPolicyvalidates the user’s Kubernetes token and checks whether the user has permission togetthe specificLLMInferenceServiceresource usingSubjectAccessReview.Create a Kubernetes Secret with connection details for Redis, PostgreSQL, and S3-compatible storage.
Save the following YAML to a file named
batch-gateway-secrets.yaml:apiVersion: v1 kind: Secret metadata: name: batch-gateway-secrets namespace: <batch_gateway_namespace> type: Opaque stringData: redis-url: "redis://<redis_host>:<redis_port>/0" postgresql-url: "postgresql://<db_user>:<db_password>@<db_host>:<db_port>/<db_name>?sslmode=disable" s3-secret-access-key: "<s3_secret_key>"where:
<batch_gateway_namespace>- Specifies the namespace for the batch gateway deployment.
<redis_host>- Specifies the hostname or IP address of the Redis or Valkey instance.
<redis_port>- Specifies the port number of the Redis or Valkey instance (default: 6379).
<db_user>- Specifies the PostgreSQL username.
<db_password>- Specifies the PostgreSQL password.
<db_host>- Specifies the hostname or IP address of the PostgreSQL instance.
<db_port>- Specifies the port number of the PostgreSQL instance (default: 5432).
<db_name>- Specifies the name of the PostgreSQL database for batch metadata.
<s3_secret_key>Specifies the secret access key for S3-compatible storage.
NoteS3 configuration settings (region, endpoint, access key ID, and bucket name) are non-sensitive and are configured in the
LLMBatchGatewaycustom resource, not in this secret. Only the S3 secret access key belongs in the secret.Apply the Secret:
$ oc apply -f batch-gateway-secrets.yaml
Deploy infrastructure dependencies for the batch gateway.
The batch gateway requires Redis or Valkey for job queuing, PostgreSQL for metadata storage, and S3-compatible storage for batch files. Deploy these services before creating the
LLMBatchGatewaycustom resource.For production deployments, use managed services or deploy these components with appropriate persistence, backups, and high availability. For development or testing environments, you can deploy minimal instances using Helm charts or Kubernetes manifests.
NoteFor example deployment manifests for Redis, PostgreSQL, and MinIO, see the batch gateway RHOAI deployment guide.
Create an
LLMBatchGatewaycustom resource to deploy the batch gateway components.Save the following YAML to a file named
llm-batch-gateway.yaml:apiVersion: llm-d.ai/v1alpha1 kind: LLMBatchGateway metadata: name: batch-gateway namespace: <batch_gateway_namespace> spec: secretRef: name: batch-gateway-secrets dbBackend: postgresql fileStorage: s3: region: <s3_region> endpoint: <s3_endpoint> accessKeyId: <s3_access_key_id> prefix: <s3_bucket_name> usePathStyle: true autoCreateBucket: true apiServer: replicas: 1 processor: replicas: 1 globalInferenceGateway: url: http://batch-internal-gateway.openshift-ingress.svc.cluster.local/<llmisvc_namespace>/<llmisvc_name>/v1 requestTimeout: 5m maxRetries: 3 initialBackoff: 1s maxBackoff: 60s config: inferenceObjective: batch-workload gc: interval: 30m tls: enabled: true certManager: issuerName: selfsigned-issuer issuerKind: ClusterIssuer dnsNames: - batch-gateway-apiserver - batch-gateway-apiserver.<batch_gateway_namespace>.svc.cluster.local - localhostwhere:
<batch_gateway_namespace>- Specifies the namespace where the batch gateway is deployed.
<s3_region>-
Specifies the S3 region (for example,
us-east-1). <s3_endpoint>-
Specifies the S3 endpoint URL. For MinIO deployed in-cluster, use
http://minio.<batch_gateway_namespace>.svc.cluster.local:9000. <s3_access_key_id>- Specifies the S3 access key ID.
<s3_bucket_name>- Specifies the S3 bucket name for batch input and output files.
<llmisvc_namespace>-
Specifies the namespace of the
LLMInferenceService. <llmisvc_name>Specifies the name of the
LLMInferenceServiceresource.Apply the
LLMBatchGatewayresource:$ oc apply -f llm-batch-gateway.yamlThe Batch Gateway Operator deploys the batch-gateway-apiserver, batch-processor, and garbage-collector components. Component images are pinned by the operator from its deployment configuration.
NoteTo use filesystem storage instead of S3, replace the
fileStorage.s3section with:fileStorage: fs: basePath: /tmp/batch-gateway claimName: <your-pvc-name>The PersistentVolumeClaim must have
ReadWriteManyaccess mode.
Create an
HTTPRouteto route external batch API traffic to the batch-gateway-apiserver.Save the following YAML to a file named
batch-api-route.yaml:apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: batch-api-route namespace: <batch_gateway_namespace> spec: parentRefs: - name: <external_gateway_name> namespace: <gateway_namespace> rules: - matches: - path: type: PathPrefix value: /v1/batches - path: type: PathPrefix value: /v1/files backendRefs: - name: batch-gateway-apiserver port: 8000where:
<external_gateway_name>- Specifies the name of the external Kubernetes Gateway resource that receives incoming batch API requests.
<gateway_namespace>Specifies the namespace of the external gateway (typically
openshift-ingress).Apply the HTTPRoute resource:
$ oc apply -f batch-api-route.yamlApply an
AuthPolicyfor the batch API routes.Save the following YAML to a file named
batch-api-authpolicy.yaml:apiVersion: kuadrant.io/v1 kind: AuthPolicy metadata: name: batch-api-authpolicy namespace: <batch_gateway_namespace> spec: targetRef: group: gateway.networking.k8s.io kind: HTTPRoute name: batch-api-route rules: authentication: "kubernetes-token": kubernetesTokenReview: audiences: - "https://kubernetes.default.svc" response: success: headers: "X-MaaS-Username": plain: selector: auth.identity.user.usernameApply the AuthPolicy resource:
$ oc apply -f batch-api-authpolicy.yamlThe batch API
AuthPolicyperforms authentication only. Model-level authorization is enforced by thebatch-llm-authpolicyon the internal gateway when the processor forwards inference requests.
Apply a
RateLimitPolicyto enforce per-user rate limits on the batch API.Save the following YAML to a file named
batch-rate-limit-policy.yaml:apiVersion: kuadrant.io/v1 kind: RateLimitPolicy metadata: name: batch-rate-limit namespace: <batch_gateway_namespace> spec: targetRef: group: gateway.networking.k8s.io kind: HTTPRoute name: batch-api-route limits: "per-user": rates: - limit: 20 window: 1m counters: - auth.identity.user.usernameApply the RateLimitPolicy resource:
$ oc apply -f batch-rate-limit-policy.yamlCreate an
InferenceObjectiveat priority -1 for batch workloads.Save the following YAML to a file named
batch-inference-objective.yaml:apiVersion: llm-d.ai/v1alpha2 kind: InferenceObjective metadata: name: batch-workload namespace: <llmisvc_namespace> spec: priority: -1 poolRef: group: inference.networking.k8s.io kind: InferencePool name: <inference_pool_name>where:
<llmisvc_namespace>-
Specifies the namespace where the
InferencePoolis deployed. <inference_pool_name>Specifies the name of the
InferencePoolresource for the target model.Apply the InferenceObjective resource:
$ oc apply -f batch-inference-objective.yamlThe negative priority value (
priority: -1) means batch requests run at lower priority than interactive workloads and are the first to be dropped when the system reaches saturation, protecting real-time inference SLOs.
Verification
Verify that the batch gateway pods are running:
$ oc get pods -n <batch_gateway_namespace>The output shows pods for the batch-gateway-apiserver, batch-gateway-processor, and batch-gateway-gc components in
Runningstatus.Submit a test batch job to verify the subsystem is functioning:
Create a test JSONL input file:
$ cat > /tmp/test-batch.jsonl << 'EOF' {"custom_id": "test-1", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "<model_name>", "messages": [{"role": "user", "content": "Hello"}], "max_tokens": 10}} EOFUpload the file:
$ curl -s -X POST "https://<batch_gateway_url>/v1/files" \ -H "Authorization: Bearer <auth_token>" \ -F "file=@/tmp/test-batch.jsonl" \ -F "purpose=batch"Create a batch job by using the returned
file_id:$ curl -s -X POST "https://<batch_gateway_url>/v1/batches" \ -H "Authorization: Bearer <auth_token>" \ -H "Content-Type: application/json" \ -d '{ "input_file_id": "<file_id>", "endpoint": "/v1/chat/completions", "completion_window": "24h" }'Poll the batch status until it reaches
completed:$ curl -s "https://<batch_gateway_url>/v1/batches/<batch_id>" \ -H "Authorization: Bearer <auth_token>"A successful test batch job transitions through
validating,in_progress,finalizing, andcompletedstates.
8.3. Submit a batch inference job Copy linkLink copied to clipboard!
You can submit a batch inference job to process large volumes of inference requests asynchronously through the OpenAI-compatible /v1/batches and /v1/files API endpoints. Batch jobs persist across gateway pod restarts and do not require an active client connection after submission.
Prerequisites
- The batch inference subsystem is configured by a cluster administrator.
- You have an authentication token for the batch-gateway endpoint: a Kubernetes ServiceAccount token or a user token.
- A deployed Distributed Inference with llm-d model is available for inference.
- You have the batch-gateway API endpoint URL.
Procedure
Prepare a JSONL input file with one inference request per line.
Each line must be a valid JSON object with the following fields:
{"custom_id": "request-1", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "<model_name>", "messages": [{"role": "user", "content": "Summarize the benefits of container orchestration."}], "max_tokens": 256}} {"custom_id": "request-2", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "<model_name>", "messages": [{"role": "user", "content": "Explain Kubernetes networking."}], "max_tokens": 256}}where:
custom_id- Specifies a unique identifier for correlating this request with its result in the output file.
method-
Specifies the HTTP method. Must be
POST. url-
Specifies the inference endpoint path. Supported values are
/v1/chat/completions,/v1/completions,/v1/embeddings,/v1/responses, and/v1/moderations. bodySpecifies the request body, following the same schema as the corresponding synchronous inference endpoint.
NoteThis example shows chat completion requests. You can use this same workflow for different use cases such as embedding generation, offline evaluations, or dataset processing by adjusting the content and structure of your JSONL file. For example, use
/v1/embeddingsfor embedding generation or construct evaluation-specific prompts for offline model evaluation.Save this file locally, for example as
batch-input.jsonl.
Upload the input file to the batch gateway:
$ curl -s -X POST "https://<batch_gateway_url>/v1/files" \ -H "Authorization: Bearer <auth_token>" \ -F "file=@batch-input.jsonl" \ -F "purpose=batch"where:
<batch_gateway_url>- Specifies the URL of the batch-gateway-apiserver endpoint.
<auth_token>Specifies your Kubernetes ServiceAccount token or user token.
The response includes a
file_idthat you use to create the batch job:{ "id": "file-abc123", "object": "file", "purpose": "batch", "filename": "batch-input.jsonl", "bytes": 512, "created_at": 1719878400 }NoteFor additional file operations such as listing files, retrieving file metadata, or deleting files, see Section 8.4, “Batch inference API reference”.
Create a batch job by using the uploaded file:
$ curl -s -X POST "https://<batch_gateway_url>/v1/batches" \ -H "Authorization: Bearer <auth_token>" \ -H "Content-Type: application/json" \ -d '{ "input_file_id": "<file_id>", "endpoint": "/v1/chat/completions", "completion_window": "24h" }'where:
<file_id>Specifies the
idvalue from the file upload response.The response includes a
batch_idand shows the initial status asvalidating:{ "id": "batch-xyz789", "object": "batch", "endpoint": "/v1/chat/completions", "input_file_id": "file-abc123", "status": "validating", "created_at": 1719878400 }NoteThis example shows required parameters only. For optional parameters such as custom metadata or batch listing and filtering options, see Section 8.4, “Batch inference API reference”.
Poll the batch job status until it reaches
completed:$ curl -s "https://<batch_gateway_url>/v1/batches/<batch_id>" \ -H "Authorization: Bearer <auth_token>"where:
<batch_id>Specifies the
idvalue from the batch creation response.The batch job transitions through the following states:
validatingin_progressfinalizingcompleted. A completed batch response includesoutput_file_idand request counts:{ "id": "batch-xyz789", "object": "batch", "status": "completed", "input_file_id": "file-abc123", "output_file_id": "file-out456", "request_counts": { "total": 2, "completed": 2, "failed": 0 } }
Retrieve the batch results by downloading the output file:
$ curl -s "https://<batch_gateway_url>/v1/files/<output_file_id>/content" \ -H "Authorization: Bearer <auth_token>"where:
<output_file_id>Specifies the
output_file_idvalue from the completed batch response.The output is a JSONL file with one result per line, correlated by
custom_id:{"id": "response-1", "custom_id": "request-1", "response": {"status_code": 200, "body": {"choices": [{"message": {"role": "assistant", "content": "Container orchestration provides..."}}]}}} {"id": "response-2", "custom_id": "request-2", "response": {"status_code": 200, "body": {"choices": [{"message": {"role": "assistant", "content": "Kubernetes networking..."}}]}}}
Optional: Cancel a batch job:
$ curl -s -X POST "https://<batch_gateway_url>/v1/batches/<batch_id>/cancel" \ -H "Authorization: Bearer <auth_token>"You can cancel a batch job in the
validatingorin_progressstate. Jobs still queued in thevalidatingstate are cancelled immediately and transition directly tocancelled. Jobs already being processed in thein_progressstate transition throughcancellingtocancelledas the processor winds down. Requests that were already completed before cancellation are included in the output file.
Verification
-
Verify that the batch job completed successfully by checking the
statusfield in the batch response. A successful batch showsstatus: completedwithrequest_counts.failed: 0. -
Verify that the output file contains results for all input requests by comparing the number of lines in the output file with the
request_counts.totalvalue.
Additional resources
8.4. Batch inference API reference Copy linkLink copied to clipboard!
The batch inference subsystem for Distributed Inference with llm-d exposes OpenAI-compatible REST API endpoints for submitting and managing asynchronous batch inference jobs. This reference documents all available endpoints, parameters, response schemas, and error formats.
Consult this reference when you need to the following:
- Use optional parameters not covered in the basic workflow, such as metadata or filtering options
- Understand the complete Batch object schema and lifecycle states
- Troubleshoot API errors by reviewing status codes and error response formats
- Integrate batch inference into automated workflows or scripts
All requests require a bearer token in the Authorization header. Use a Kubernetes ServiceAccount token or a user token validated by the gateway AuthPolicy.
/v1/batches endpoints
The /v1/batches endpoints manage batch inference jobs.
| Field | Description |
|---|---|
| Request body | |
|
|
The ID of the uploaded JSONL input file. The file |
|
|
The inference endpoint to use for all requests in the batch. Supported values: |
|
|
The time window for batch completion. Accepts any valid Go duration string, such as |
|
| A map of key-value pairs for custom metadata. Maximum 16 pairs; keys up to 64 characters, values up to 512 characters. |
| Response |
A Batch object with |
| Field | Description |
|---|---|
| Path parameter | |
|
| The ID of the batch to retrieve. |
| Response | A Batch object with current status, request counts, and file IDs. |
| Field | Description |
|---|---|
| Query parameters | |
|
| Maximum number of batches to return. Default: 20, maximum: 100. |
|
| An integer offset for pagination. Returns batches starting from this position in the result set. |
| Response | A list of Batch objects for the authenticated user. |
| Field | Description |
|---|---|
| Path parameter | |
|
|
The ID of the batch to cancel. The batch must be in |
| Response |
A Batch object with |
/v1/files endpoints for batch inference
The /v1/files endpoints in the batch inference context manage JSONL input and output files.
| Field | Description |
|---|---|
| Form data | |
|
| The JSONL file to upload. Maximum size: 200 MB. |
|
|
Must be |
| Response |
A File object with |
| Field | Description |
|---|---|
| Query parameters | |
|
| Maximum number of files to return. Default: 20, maximum: 10,000. |
|
| An integer offset for pagination. Returns files starting from this position in the result set. |
| Response |
A list wrapper with |
| Field | Description |
|---|---|
| Path parameter | |
|
| The ID of the file to retrieve metadata for. |
| Response |
A File object with metadata including |
| Field | Description |
|---|---|
| Path parameter | |
|
| The ID of the file whose content to download. Use this to retrieve batch output files. |
| Response | The raw JSONL file content. |
| Field | Description |
|---|---|
| Path parameter | |
|
| The ID of the file to delete. |
| Response |
A deletion confirmation with the file ID and |
JSONL input format
Each line in the input JSONL file must be a valid JSON object with the following fields:
| Field | Type | Required | Description |
|---|---|---|---|
|
| string | Yes | A unique identifier for this request. Used to correlate the request with its result in the output file. |
|
| string | Yes |
The HTTP method. Must be |
|
| string | Yes |
The inference endpoint path. Supported values: |
|
| object | Yes |
The request body, following the same schema as the corresponding synchronous inference endpoint. Must include the |
Example input line:
{"custom_id": "req-001", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "<model_name>", "messages": [{"role": "user", "content": "What is Kubernetes?"}], "max_tokens": 100}}
JSONL output format
Each line in the output JSONL file contains the result for one input request:
| Field | Type | Description |
|---|---|---|
|
| string | A unique identifier for this response. |
|
| string |
The |
|
| object |
Contains |
|
| object or null |
If the request failed, contains |
Batch object schema
The Batch object represents a batch inference job and is returned by all /v1/batches endpoints.
This table shows principal Batch object fields. For the complete schema including all timestamp fields, usage statistics, and error details, see the OpenAI Batch API reference.
| Field | Type | Description |
|---|---|---|
|
| string | The unique identifier for the batch. |
|
| string |
Always |
|
| string | The inference endpoint used for this batch. |
|
| string | The ID of the input JSONL file. |
|
| string or null |
The ID of the output JSONL file. Available when the batch reaches |
|
| string or null | The ID of the error file containing failed requests. Available when the batch completes with errors. |
|
| string | The current lifecycle state of the batch. |
|
| object |
Contains |
|
| object or null | Custom key-value pairs set when creating the batch. |
|
| integer | Unix timestamp of batch creation. |
|
| integer or null | Unix timestamp when the batch started processing. |
|
| integer or null | Unix timestamp when the batch completed. |
|
| integer or null | Unix timestamp when the batch failed. |
|
| integer or null | Unix timestamp when the batch was cancelled. |
|
| integer or null | Unix timestamp when the batch expired. |
Batch lifecycle states
A batch job transitions through the following states:
| State | Description |
|---|---|
|
|
The input file is being validated. The batch transitions to |
|
| Individual inference requests are being processed by the batch processor. The batch remains in this state until all requests are completed or the batch is cancelled. |
|
| All requests have been processed. The output file is being assembled and uploaded to storage. |
|
|
The batch finished successfully. The |
|
|
The batch failed due to validation errors or unrecoverable processing errors. Check the |
|
|
The batch did not complete within the |
|
| A cancellation request has been received. The processor stops dispatching new requests. |
|
| The batch was cancelled. Requests completed before cancellation are included in the output file. |
Rate limits and scale limits
| Limit | Default value | Description |
|---|---|---|
| Maximum requests per batch | 50,000 | The default maximum number of inference request lines in a single JSONL input file. This limit is configurable. |
| Maximum input file size | 200 MB | The default maximum size of an uploaded JSONL input file. This limit is configurable. |
Optionally, you can apply a RateLimitPolicy on the external gateway to enforce per-user rate limiting for batch API requests. The rate limit value is defined in the policy configuration.
Additional resources