For the complete documentation index, see llms.txt. Markdown versions of all docs pages are available by appending .md to any docs URL.
Serve a model
Expose an LLM model to clients with an AgentgatewayModel resource, including wildcard matching and provider credentials.
Expose an LLM model to clients with an AgentgatewayModel resource.
About
An AgentgatewayModel declares one client-facing model and attaches it to a Gateway listener. Agentgateway derives the LLM routing from the models that attach to a listener, so you do not create an AgentgatewayBackend or an HTTPRoute.
In this guide, you enable the API, turn on LLM serving for a listener, and expose three kinds of models: an exact match, a wildcard match, and a model that authenticates to its provider with a Kubernetes Secret.
For more information, see About models.
Before you begin
Set up an agentgateway proxy.
Deploy the httpbun mock LLM. This guide routes to httpbun so that you do not need a provider API key. To use a real provider instead, remove the
baseURLfield from each model and follow API keys.Enable the
AgentgatewayModelAPI on the control plane. The API is experimental and disabled by default, so it is not available in a standard installation.helm upgrade -i -n agentgateway-system agentgateway oci://cr.agentgateway.dev/charts/agentgateway \ --version 0.0.0-latest-dev \ --reuse-values \ --set controller.image.pullPolicy=Always \ --set agentgatewayModels.enabled=true \ --waitThis command uses the nightly development build, because the
AgentgatewayModelAPI is not yet in a released chart.Verify that the API is enabled. The command returns
truewhen the feature gate is set.kubectl get deploy agentgateway -n agentgateway-system \ -o jsonpath='{.spec.template.spec.containers[0].env[?(@.name=="AGW_ENABLE_AGENTGATEWAY_MODELS")].value}'
Enable LLM serving on a listener
A listener serves LLM traffic only when it allows the AgentgatewayModel route kind. In this guide, you add the route kind to the http listener on the agentgateway-proxy Gateway that you created during setup. The gateway then serves both LLM models and ordinary HTTPRoute traffic on the same port.
Update the listener to allow both
HTTPRouteandAgentgatewayModelresources.kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: agentgateway-proxy namespace: agentgateway-system spec: gatewayClassName: agentgateway listeners: - name: http port: 80 protocol: HTTP allowedRoutes: namespaces: from: All kinds: - group: gateway.networking.k8s.io kind: HTTPRoute - group: agentgateway.dev kind: AgentgatewayModel EOFReview the following table to understand this configuration.
Field Value Description allowedRoutes.kindsAgentgatewayModelandHTTPRouteAdding AgentgatewayModelenables the listener’s built-in LLM paths, such as/v1/chat/completionsand/v1/models. KeepingHTTPRoutelets your existing routes continue to work. After you setallowedRoutes.kinds, the listener accepts only the kinds that you list, so include every kind that you need.listeners[0].namehttpModels reference this name in parentRefs.sectionName.Verify that the listener now supports both kinds.
kubectl get gateway agentgateway-proxy -n agentgateway-system \ -o jsonpath='{.status.listeners[0].supportedKinds}'Example output:
[{"group":"gateway.networking.k8s.io","kind":"HTTPRoute"},{"group":"agentgateway.dev","kind":"AgentgatewayModel"}]Save the gateway address in an environment variable, if you have not already.
export INGRESS_GW_ADDRESS=$(kubectl get svc -n agentgateway-system agentgateway-proxy -o=jsonpath="{.status.loadBalancer.ingress[0]['hostname','ip']}") echo $INGRESS_GW_ADDRESS
The listener now serves LLM traffic, but it has no models yet, so every LLM request returns a model_not_found error.
Serve an exact model
When you omit spec.match, the model matches metadata.name exactly. Clients request this model as gpt-4.
Create the model.
kubectl apply -f- <<EOF apiVersion: agentgateway.dev/v1alpha1 kind: AgentgatewayModel metadata: name: gpt-4 namespace: agentgateway-system spec: parentRefs: - group: gateway.networking.k8s.io kind: Gateway name: agentgateway-proxy sectionName: http provider: OpenAI baseURL: http://httpbun.default.svc.cluster.local:3090/llm EOFReview the following table to understand this configuration. For more information, see the API docs.
Field Value Description parentRefsGateway Attaches the model to the httplistener. OmitsectionNameto attach to every eligible listener on the Gateway.providerOpenAIThe provider that serves this model. httpbun implements the OpenAI-compatible API. baseURLhttp://httpbun.default.svc.cluster.local:3090/llmOverrides the provider address and base path prefix, so requests go to httpbun’s /llm/chat/completionsendpoint instead of OpenAI. Remove this field to use the real provider.Send a request for the model.
curl -X POST http://$INGRESS_GW_ADDRESS/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-4", "messages": [{"role": "user", "content": "Hello!"}], "httpbun": {"content": "Hello from the mock LLM"} }'Example output:
{"model":"gpt-4","usage":{"prompt_tokens":3,"completion_tokens":4,"total_tokens":7},"choices":[{"message":{"content":"Hello from the mock LLM","role":"assistant"},"finish_reason":"stop","index":0}],"object":"chat.completion"}Request a model that does not exist. Agentgateway returns an OpenAI-compatible error.
curl -X POST http://$INGRESS_GW_ADDRESS/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{"model": "does-not-exist", "messages": []}'Example output:
{"error":{"message":"Model not found","type":"invalid_request_error","code":"model_not_found"}}
Serve a family of models with a wildcard
Use spec.match.model to match more than one model name. The provider does not recognize the client-facing prefix, so pair the wildcard with a model transformation that rewrites the name before the request leaves the gateway.
Create a model that matches any name that starts with
openai/.kubectl apply -f- <<EOF apiVersion: agentgateway.dev/v1alpha1 kind: AgentgatewayModel metadata: name: openai-models namespace: agentgateway-system spec: parentRefs: - group: gateway.networking.k8s.io kind: Gateway name: agentgateway-proxy sectionName: http match: model: openai/* provider: OpenAI baseURL: http://httpbun.default.svc.cluster.local:3090/llm policies: transformations: - field: model expression: 'llmRequest.model.stripPrefix("openai/")' EOFReview the following table to understand this configuration. For more information, see the API docs.
Field Value Description modelopenai/*Matches any model name that starts with openai/. Wildcards must be*, a suffix such asopenai/*, or a prefix such as*-latest.fieldmodelThe field in the provider request body to rewrite, as part of a transformation policy. expressionllmRequest.model.stripPrefix("openai/")Removes the client-facing prefix, so the provider receives gpt-5-minirather thanopenai/gpt-5-mini.Request a model through the wildcard. The response shows the transformed model name.
curl -X POST http://$INGRESS_GW_ADDRESS/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "openai/gpt-5-mini", "messages": [{"role": "user", "content": "Hello!"}], "httpbun": {"content": "Hello from the mock LLM"} }'Example output. Note that
modelisgpt-5-mini, notopenai/gpt-5-mini.{"model":"gpt-5-mini","usage":{"prompt_tokens":3,"completion_tokens":4,"total_tokens":7},"choices":[{"message":{"content":"Hello from the mock LLM","role":"assistant"},"finish_reason":"stop","index":0}],"object":"chat.completion"}
Authenticate to the provider
Real providers require credentials. Use spec.policies.auth to read them from a Kubernetes Secret.
Create a Secret that holds the provider API key. By default, agentgateway reads the
Authorizationkey.kubectl apply -f- <<EOF apiVersion: v1 kind: Secret metadata: name: openai-secret namespace: agentgateway-system type: Opaque stringData: Authorization: $OPENAI_API_KEY EOFCreate a model that references the Secret.
kubectl apply -f- <<EOF apiVersion: agentgateway.dev/v1alpha1 kind: AgentgatewayModel metadata: name: gpt-5-mini namespace: agentgateway-system spec: parentRefs: - group: gateway.networking.k8s.io kind: Gateway name: agentgateway-proxy sectionName: http provider: OpenAI policies: auth: secretRef: name: openai-secret EOFReview the following table to understand this configuration. For more information, see the API docs.
Field Value Description secretRefopenai-secretThe Secret to read the credential from. Set secretRef.keyto read a key other thanAuthorization.Agentgateway writes the credential to the
Authorizationheader with aBearerprefix. Usepolicies.auth.locationto write it somewhere else, such as a custom header or query parameter.
Verify model discovery
Every public model on a listener appears in the OpenAI-compatible discovery endpoint. The endpoint requires no configuration.
curl -s http://$INGRESS_GW_ADDRESS/v1/modelsExample output:
{
"data": [
{"id": "gpt-4", "object": "model", "created": 1785166485, "owned_by": "openai"},
{"id": "gpt-5-mini", "object": "model", "created": 1785166485, "owned_by": "openai"},
{"id": "openai/*", "object": "model", "created": 1785166485, "owned_by": "openai"}
],
"object": "list"
}Wildcard models are listed by their match pattern. Models with visibility: Internal are excluded.
Troubleshooting
Requests return model_not_found
What’s happening:
Every request fails with the following error, even for a model you created.
{"error":{"message":"Model not found","type":"invalid_request_error","code":"model_not_found"}}Why it’s happening:
The model did not attach to the listener, or it is not reachable by clients. Common causes include the following.
- The
AgentgatewayModelAPI is not enabled on the control plane. - The listener does not allow the
AgentgatewayModelroute kind. - The
parentRefsfield does not match the Gateway name orsectionName. - The model is in a different namespace than the Gateway, and the listener restricts
allowedRoutes.namespaces. - The model sets
visibility: Internal, so clients cannot request it directly.
How to fix it:
Confirm that the API is enabled. If the following command returns no output, repeat the Helm step in Before you begin.
kubectl get deploy agentgateway -n agentgateway-system \ -o jsonpath='{.spec.template.spec.containers[0].env[?(@.name=="AGW_ENABLE_AGENTGATEWAY_MODELS")].value}'Check how many routes attached to the listener. This count includes every
AgentgatewayModelthat attached, whether public or internal.kubectl get gateway agentgateway-proxy -n agentgateway-system \ -o jsonpath='{.status.listeners[0].attachedRoutes}'List the models that clients can reach. If a model is missing here but the
attachedRoutescount includes it, the model isInternal.curl -s http://$INGRESS_GW_ADDRESS/v1/models
Warning
The AgentgatewayModel resource does not yet report status. The status.parents field stays empty even when a model serves traffic correctly, so you cannot use kubectl describe agmodel to debug attachment. Use the checks in this section instead.
Cleanup
Note
Remove the resources you created in this guide only if you do not plan to continue to Route across models with virtual models.
kubectl delete agentgatewaymodel gpt-4 openai-models gpt-5-mini -n agentgateway-system
kubectl delete secret openai-secret -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.