Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/test-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,14 @@ jobs:
- name: Install dependencies
run: npm install

- name: Increase AIO limit for Redpanda
- name: Increase AIO limit for envoy shadowing
if: needs.setup.outputs.envoy-shadowing == 'true'
run: |
# Redpanda uses Linux AIO. With 6 brokers each needing ~10000 events,
# we exceed the default limit of 65536. Increase it.
sudo sysctl -w fs.aio-max-nr=1048576

- name: Increase AIO limit for redpanda migrator
if: needs.setup.outputs.redpanda-migrator == 'true'
run: |
# Redpanda uses Linux AIO. Increase limit to support multiple brokers.
Expand Down
21 changes: 21 additions & 0 deletions ai-agents/langchain-agent/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Redpanda AI Gateway - OIDC credentials
REDPANDA_CLIENT_ID=your-client-id
REDPANDA_CLIENT_SECRET=your-client-secret
REDPANDA_GATEWAY_ID=d6b3mk93mouc73cortj0

# Gateway URL
REDPANDA_GATEWAY_URL=https://ai-gateway.d6b2mdhdvf8ruqkbl2mg.clusters.rdpa.co

# OIDC issuer (discovery URL is {issuer}/.well-known/openid-configuration)
# REDPANDA_ISSUER=https://auth.prd.cloud.redpanda.com

# OIDC audience for the token request
# REDPANDA_AUDIENCE=cloudv2-production.redpanda.cloud

# LLM model (routed through gateway)
REDPANDA_MODEL=google/gemini-3-flash-preview

# LangSmith tracing (optional)
LANGSMITH_API_KEY=your-langsmith-api-key
LANGSMITH_PROJECT=redpanda-agent
LANGSMITH_TRACING=true
11 changes: 11 additions & 0 deletions ai-agents/langchain-agent/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.env
.env.local
__pycache__/
*.pyc
*.pyo
*.egg-info/
dist/
build/
.venv/
venv/
.ruff_cache/
272 changes: 272 additions & 0 deletions ai-agents/langchain-agent/README.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
= Build a LangGraph Agent with the Redpanda AI Gateway
:description: Build a ReAct agent using LangGraph that connects to the Redpanda AI Gateway for unified LLM access and MCP tool calling.
:page-layout: lab
:page-categories: Agentic Data Plane
:page-cloud: true
:page-topic-type: lab
:learning-objective-1: Build and run a LangGraph ReAct agent that connects to the Redpanda AI Gateway
:learning-objective-2: Authenticate with the AI Gateway using the OIDC client_credentials flow
:learning-objective-3: Configure LangGraph to route LLM requests through the AI Gateway's OpenAI-compatible interface
// Set image path for GitHub rendering
ifndef::env-site[]
:imagesdir: ../../docs/modules/ai-agents/images/
endif::[]

Build a Python agent using https://langchain-ai.github.io/langgraph/[LangGraph^] that connects to the Redpanda AI Gateway for unified LLM access and MCP tool calling, with optional https://www.langchain.com/langsmith[LangSmith^] tracing.

After completing this lab, you will be able to:

* [ ] {learning-objective-1}
* [ ] {learning-objective-2}
* [ ] {learning-objective-3}

== What you'll explore

* *AI Gateway as a unified LLM interface*: The gateway provides an OpenAI-compatible API that routes to any upstream model provider (such as Google Gemini), handling provider-specific authentication and request translation.
* *OIDC authentication*: Authenticate with the gateway using a Redpanda Cloud service account and the OAuth 2.0 `client_credentials` grant.
* *Dynamic MCP tool discovery*: Use the gateway's MCP endpoint to discover and call tools at runtime, without hard-coding tool definitions.

== Prerequisites

* Python 3.12 or later
* https://python-poetry.org/[Poetry^] for dependency management
* A Redpanda Cloud account with:
** A cluster that has the AI Gateway enabled
** A service account with permissions to access the cluster
* (Optional) A https://www.langchain.com/langsmith[LangSmith^] API key for tracing

== Get the lab files

Clone the repository and navigate to the lab directory:

[,bash]
----
git clone https://github.com/redpanda-data/redpanda-labs.git
cd redpanda-labs/ai-agents/langchain-agent
----

== Set up the project

. Install the project dependencies:
+
[,bash]
----
poetry install
----

. Copy the example environment file and fill in your credentials:
+
[,bash]
----
cp .env.example .env.local
----

. Edit `.env.local` with your Redpanda Cloud service account credentials:
+
[source,env]
----
REDPANDA_CLIENT_ID=<your-client-id>
REDPANDA_CLIENT_SECRET=<your-client-secret>
REDPANDA_GATEWAY_ID=<your-gateway-id>
REDPANDA_GATEWAY_URL=<your-gateway-url>
----
+
You can find these values in the https://cloud.redpanda.com[Redpanda Cloud console^].

== Run the agent

Start the agent:

[,bash]
----
poetry run redpanda-agent
----

The agent opens a terminal UI where you can interact with it. The agent authenticates with the AI Gateway using your service account credentials, discovers available MCP tools, and displays a chat prompt. From there, your requests are routed through the gateway to the configured LLM provider.

== Explore the lab

Key technical components include the agent architecture, authentication flow, and dynamic tool discovery.

=== Architecture

The agent uses the following architecture:

[,text]
----
Python Agent (LangGraph)
|
|-- OIDC client_credentials flow --> Redpanda Cloud IdP --> Bearer token
|
|-- ChatOpenAI (base_url=<gateway-url>/v1)
| |
| +-- OpenAI-compatible API via gateway
|
|-- MCP tools via gateway (<gateway-url>/mcp/)
| |
| +-- tool_search --> discovers available tools dynamically
| +-- AgentMiddleware --> injects and executes discovered tools
|
|-- LangSmith tracing (optional)
----

=== How the AI Gateway works

The AI Gateway is a multi-tenant platform where each user configures their own gateway instance. The gateway translates upstream provider responses into the OpenAI chat completions format, so clients interact with a standard interface regardless of the underlying model provider.

Every request to the gateway requires two headers:

[cols="1,2,2"]
|===
| Header | Value | Purpose

| `Authorization`
| `Bearer <oidc_token>`
| OIDC authentication

| `rp-aigw-id`
| `<your-gateway-id>`
| Identifies the gateway instance
|===

Because the gateway speaks the OpenAI format, you use `ChatOpenAI` from `langchain-openai`:

[,python]
----
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
base_url=f"{gateway_url}/v1",
api_key="not-used", # Auth is via OIDC Bearer token
model="google/gemini-3-flash-preview",
default_headers={
"Authorization": f"Bearer {token}",
"rp-aigw-id": gateway_id,
},
)
----

=== OIDC authentication

Authentication is against the *Redpanda Cloud OIDC identity provider*, not the gateway itself. The gateway validates the resulting tokens.

The `GatewayAuth` class uses OIDC discovery to resolve the token endpoint automatically from the issuer:

[,text]
----
https://auth.prd.cloud.redpanda.com/.well-known/openid-configuration
----

It fetches this discovery document on the first token request, then uses a `client_credentials` grant with the audience `cloudv2-production.redpanda.cloud`:

[,python]
----
auth = GatewayAuth() # uses REDPANDA_ISSUER env var or default
token = await auth.get_token()
----

NOTE: The AI agent is responsible for refreshing tokens before they expire. `GatewayAuth` handles this automatically with a 30-second buffer before expiry.

=== Dynamic MCP tool discovery

The gateway's MCP endpoint uses a two-level tool discovery pattern:

. `list_tools()` returns a small set of static tools, including `tool_search`.
. Calling `tool_search` discovers additional tools available on the gateway (such as `redpanda-docs:ask_redpanda_question`).
. The set of discovered tools can change at any time because they are not static.

The agent uses LangChain's `AgentMiddleware` to inject dynamically discovered tools at runtime:

[,python]
----
from langchain.agents import create_agent

graph = create_agent(
model=llm,
tools=static_tools, # For example, [tool_search]
middleware=[middleware], # MCPGatewayMiddleware
)
----

The `MCPGatewayMiddleware` provides two hooks:

* `awrap_model_call`: Injects discovered tools into the model's tool list before each LLM call.
* `awrap_tool_call`: Intercepts calls to discovered tools and executes them through the MCP `ClientSession.call_tool()` method.

NOTE: MCP tool names like `redpanda-docs:ask_redpanda_question` contain colons, which are not valid in OpenAI tool names. The middleware sanitizes names by replacing invalid characters with hyphens and maintains a mapping to the original MCP name.

=== MCP transport

Use `streamable_http` as the transport:

[,python]
----
client = MultiServerMCPClient({
"gateway": {
"transport": "streamable_http",
"url": f"{gateway_url}/mcp/",
"headers": { ... },
},
})
----

=== Enable LangSmith tracing (optional)

To enable tracing, set these environment variables in your `.env.local` file:

[source,env]
----
LANGSMITH_API_KEY=<your-langsmith-api-key>
LANGSMITH_PROJECT=redpanda-agent
LANGSMITH_TRACING=true
----

LangGraph auto-detects these variables and traces all LLM and tool calls.

=== Project structure

[cols="1,2"]
|===
| File | Purpose

| `src/agent/auth.py`
| OIDC token management using `authlib`

| `src/agent/gateway.py`
| `ChatOpenAI` configured for the AI Gateway

| `src/agent/tools.py`
| MCP tool loading and `AgentMiddleware` for dynamic discovery

| `src/agent/graph.py`
| LangGraph agent graph

| `src/agent/main.py`
| Terminal UI entry point
|===

=== Key dependencies

[cols="1,2"]
|===
| Package | Purpose

| `langchain-openai`
| Gateway uses OpenAI format regardless of upstream provider

| `langchain-mcp-adapters`
| MCP client and tool conversion

| `authlib`
| OIDC `client_credentials` with token caching
|===

== Clean up

Stop the agent by pressing kbd:[Ctrl+C] in the terminal.

ifdef::env-site[]
== Next steps

* https://docs.redpanda.com/redpanda-cloud/ai-agents/ai-gateway/[Learn more about the AI Gateway^]
endif::[]
Loading