langchain-cisco-aidefense
LangChain agent middleware for Cisco AI Defense, providing runtime security inspection of LLM inputs/outputs and tool/MCP calls.
Detects prompt injection, jailbreaks, PII leakage, toxic content, and unsafe tool usage — directly within the LangChain agent loop.
Installation
pip install langchain-cisco-aidefense
Middleware Overview
create_agent (LangChain LCEL) — four middleware classes
LLM Inspection (before_model / after_model)
| Middleware | Built on | Best for |
|---|---|---|
AIDefenseMiddleware |
ChatInspectionClient |
New integrations — lightweight, no global state |
AIDefenseAgentsecMiddleware |
agentsec LLMInspector |
When you need agentsec's retry/backoff machinery |
Tool / MCP Inspection (wrap_tool_call)
| Middleware | Built on | Best for |
|---|---|---|
AIDefenseToolMiddleware |
MCPInspectionClient |
New integrations — tool/MCP call inspection |
AIDefenseAgentsecToolMiddleware |
agentsec MCPInspector |
When you need agentsec's retry/backoff machinery |
create_react_agent (LangGraph prebuilt) — added in v1.1.0
| Symbol | Purpose |
|---|---|
AIDefenseHooks |
Provides pre_model_hook / post_model_hook for LLM inspection |
AIDefenseToolNode |
ToolNode subclass for tool call inspection |
create_aidefense_react_agent |
Drop-in replacement for create_react_agent |
Quick Start
pip install langchain-cisco-aidefense langchain-openai
from aidefense_langchain import AIDefenseMiddleware
from langchain.agents import create_agent
agent = create_agent(
model="openai:gpt-4.1",
tools=[get_weather],
middleware=[
AIDefenseMiddleware(
api_key="your-cisco-ai-defense-api-key",
region="us-west-2",
mode="enforce",
),
],
)
result = agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})
LLM Inspection
AIDefenseMiddleware (Recommended)
Uses ChatInspectionClient directly. Self-contained configuration, no global state, no monkey-patching.
from aidefense_langchain import AIDefenseMiddleware
from langchain.agents import create_agent
agent = create_agent(
model="openai:gpt-4.1",
tools=[get_weather],
middleware=[
AIDefenseMiddleware(
api_key="your-api-key",
region="us-west-2",
mode="enforce", # "enforce" | "monitor" | "off"
fail_open=True,
),
],
)
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
api_key |
str |
required | Cisco AI Defense API key |
region |
str |
"us-west-2" |
AI Defense region ("us-west-2", "eu-central-1", "ap-northeast-1") |
mode |
str |
"enforce" |
"enforce" (block), "monitor" (log only), "off" |
fail_open |
bool |
True |
Allow on inspection API errors |
timeout |
int |
30 |
Inspection timeout in seconds |
rules |
list |
None |
Rules to enable (e.g. ["PII", "Prompt Injection"]) |
user |
str |
None |
User identity for audit |
src_app |
str |
None |
Source application name |
on_violation |
callable |
None |
(InspectResponse, direction) -> None callback |
How it works
User message
|
v
+--------------------------------------------------+
| before_model hook |
| -> ChatInspectionClient.inspect_conversation() |
| -> if not safe and mode="enforce": jump_to=end |
+--------------------------------------------------+
|
v
LLM call
|
v
+--------------------------------------------------+
| after_model hook |
| -> ChatInspectionClient.inspect_conversation() |
| -> if not safe and mode="enforce": jump_to=end |
+--------------------------------------------------+
|
v
Agent response
AIDefenseAgentsecMiddleware
Uses agentsec's LLMInspector — gets retry with exponential backoff and fail-open semantics.
from aidefense_langchain import AIDefenseAgentsecMiddleware
from langchain.agents import create_agent
agent = create_agent(
model="openai:gpt-4.1",
tools=[get_weather],
middleware=[
AIDefenseAgentsecMiddleware(
mode="enforce",
api_key="your-api-key",
endpoint="https://us.api.inspect.aidefense.security.cisco.com",
retry_total=3,
retry_backoff=1.0,
),
],
)
Do not call
agentsec.protect()when using middleware. The middleware handles all inspection directly. Callingprotect()would activate monkey-patching on the underlying LLM SDK, causing every request to be inspected twice — once by the patched SDK and once by the middleware — doubling latency and API calls with no security benefit.
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
mode |
str |
"enforce" |
"enforce", "monitor", or "off" |
api_key |
str |
from state/env | AI Defense API key |
endpoint |
str |
from state/env | AI Defense API endpoint |
fail_open |
bool |
True |
Allow on inspection errors |
timeout_ms |
int |
from state | Timeout in milliseconds |
retry_total |
int |
1 |
Retry attempts |
retry_backoff |
float |
0.0 |
Backoff factor in seconds |
rules |
list |
None |
Inspection rules |
user |
str |
None |
User identity |
src_app |
str |
None |
Source application name |
on_violation |
callable |
None |
(Decision, direction) -> None callback |
Tool / MCP Inspection
AIDefenseToolMiddleware (Recommended for tools)
Uses MCPInspectionClient to inspect tool call requests (name + arguments) and tool call results.
from aidefense_langchain import AIDefenseMiddleware, AIDefenseToolMiddleware
from langchain.agents import create_agent
agent = create_agent(
model="openai:gpt-4.1",
tools=[search_db, send_email],
middleware=[
AIDefenseMiddleware(api_key="your-key", mode="enforce"),
AIDefenseToolMiddleware(api_key="your-key", mode="enforce"),
],
)
AIDefenseAgentsecToolMiddleware
Uses agentsec's MCPInspector with retry, backoff, and fail-open support.
from aidefense_langchain import AIDefenseAgentsecMiddleware, AIDefenseAgentsecToolMiddleware
agent = create_agent(
model="openai:gpt-4.1",
tools=[read_file, execute_query],
middleware=[
AIDefenseAgentsecMiddleware(mode="enforce", api_key="your-key"),
AIDefenseAgentsecToolMiddleware(mode="enforce", api_key="your-key"),
],
)
Tool Middleware Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
api_key |
str |
required / from env | Cisco AI Defense API key |
region |
str |
"us-west-2" |
AI Defense region (ChatClient variant only) |
mode |
str |
"enforce" |
"enforce", "monitor", or "off" |
fail_open |
bool |
True |
Allow on inspection API errors |
inspect_requests |
bool |
True |
Inspect tool call requests before execution |
inspect_responses |
bool |
True |
Inspect tool results after execution |
on_violation |
callable |
None |
Violation callback |
How tool inspection works
Tool call (from LLM)
|
v
+--------------------------------------------------+
| wrap_tool_call -- PRE-CALL inspection |
| -> MCPInspectionClient.inspect_tool_call() |
| -> if not safe and mode="enforce": return block |
+--------------------------------------------------+
|
v
Tool executes
|
v
+--------------------------------------------------+
| wrap_tool_call -- POST-CALL inspection |
| -> MCPInspectionClient.inspect_response() |
| -> if not safe and mode="enforce": return block |
+--------------------------------------------------+
|
v
Tool result returned to agent
This covers all tool types:
- LangChain tools (
@tooldecorated functions) - MCP tools registered via LangChain's MCP integration
- Any tool executed through the agent's tool node
Environment Variables
The middleware can also be configured via environment variables (used by from_env() class methods):
export AIDEFENSE_API_KEY=your-api-key
export AIDEFENSE_REGION=us-west-2
export AIDEFENSE_MODE=enforce
export AIDEFENSE_FAIL_OPEN=true
export AIDEFENSE_TIMEOUT=30
from aidefense_langchain import AIDefenseMiddleware
middleware = AIDefenseMiddleware.from_env()
Comparison
| Criteria | AIDefenseMiddleware |
AIDefenseAgentsecMiddleware |
|---|---|---|
| No global state / side effects | Yes | No (uses _state) |
| Self-contained config | Yes | Yes (pass explicitly) |
| Built-in retry + backoff | Via Config |
Custom |
| Built-in fail-open | In middleware | In inspector |
inspect_prompt / inspect_response |
Yes | No (inspect_conversation only) |
| Dependency footprint | Lighter (aidefense.runtime) |
Heavier (aidefense.runtime.agentsec) |
Recommendation: Use AIDefenseMiddleware for new projects. Use AIDefenseAgentsecMiddleware when you need agentsec's retry/backoff machinery.
Enforcement Modes
| Mode | Behavior |
|---|---|
enforce |
Block violations — agent returns a "blocked" message via jump_to: "end" |
monitor |
Log violations and invoke on_violation callback; never blocks |
off |
Skip inspection entirely |
Fail-Open Behavior
When fail_open=True (default) and the AI Defense inspection API is unreachable:
- The request is allowed to proceed
- A warning is logged
When fail_open=False:
- The request is blocked (or an exception is raised)
Examples
| # | File | Description |
|---|---|---|
| 1 | 01_chat_client_enforce.py |
ChatClient middleware — enforce mode (block violations) |
| 2 | 02_chat_client_monitor.py |
ChatClient middleware — monitor mode with violation callback |
| 3 | 03_chat_client_with_rules.py |
ChatClient middleware — specific rules (PII, Prompt Injection) |
| 4 | 04_agentsec_enforce.py |
Agentsec middleware — enforce mode with retry config |
| 5 | 05_composed_middleware.py |
AI Defense + custom logging middleware composed together |
| 6 | 06_side_by_side.py |
Same request through both middleware — side-by-side comparison |
| 7 | 07_tool_inspection_enforce.py |
Tool inspection — LLM + tool call inspection combined |
| 8 | 08_tool_inspection_agentsec.py |
Agentsec tool inspection — MCPInspector with retry |
| 9 | 09_callback_handler_create_react_agent.py |
create_react_agent with OpenAI — Options A & B |
| 10 | 10_azure_openai_create_react_agent.py |
create_react_agent with Azure OpenAI + macOS SSL fix |
create_react_agent Integration (v1.1.0)
LangGraph's create_react_agent does not expose before_model / after_model hooks,
so the middleware classes above cannot be used with it directly. v1.1.0 adds native
support via LangGraph's pre_model_hook, post_model_hook, and ToolNode.wrap_tool_call.
Requires langgraph >= 0.2.27.
Option A — Primitives (maximum control)
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langgraph.prebuilt import create_react_agent
from aidefense_langchain import AIDefenseHooks, AIDefenseToolNode, AIDefenseViolationError
@tool
def get_weather(city: str) -> str:
"""Return current weather for a city."""
return f"It's 72°F and sunny in {city}!"
hooks = AIDefenseHooks(api_key="<AIDEFENSE_API_KEY>", mode="enforce")
tool_node = AIDefenseToolNode([get_weather], api_key="<AIDEFENSE_API_KEY>", mode="enforce")
agent = create_react_agent(
model=ChatOpenAI(model="gpt-4o-mini"),
tools=tool_node,
pre_model_hook=hooks.pre_model_hook,
post_model_hook=hooks.post_model_hook,
)
try:
result = agent.invoke({"messages": [("user", "What's the weather in Seattle?")]})
print(result["messages"][-1].content)
except AIDefenseViolationError as e:
print(f"Blocked at '{e.direction}': {e}")
Option B — Convenience wrapper (minimum changes)
from aidefense_langchain import create_aidefense_react_agent, AIDefenseViolationError
agent = create_aidefense_react_agent(
model=ChatOpenAI(model="gpt-4o-mini"),
tools=[get_weather],
api_key="<AIDEFENSE_API_KEY>",
mode="enforce",
)
Violation handling
AIDefenseViolationError carries:
.direction—"input","output","tool '<name>' input", or"tool '<name>' output".response— the fullInspectResponsefrom the SDK (includesevent_id,severity,explanation)
In "monitor" mode, violations are logged and the optional on_violation callback is invoked,
but the agent continues:
violations = []
agent = create_aidefense_react_agent(
model=llm, tools=[get_weather],
api_key="<AIDEFENSE_API_KEY>",
mode="monitor",
on_violation=lambda resp, direction: violations.append(direction),
)
LangGraph V2.0 note:
create_react_agentis deprecated inlanggraph.prebuilt(LangGraph V1.0) and will move tolangchain.agentsin V2.0. Update your import when you upgrade.
Development
git clone https://github.com/cisco-ai-defense/ai-defense-langchain-middleware.git
cd ai-defense-langchain-middleware
pip install -e ".[dev,examples]"
pytest
License
Apache-2.0 — see LICENSE for details.
Metadata
Release files for langchain-cisco-aidefense 1.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| langchain_cisco_aidefense-1.1.1.tar.gz | 33.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| langchain_cisco_aidefense-1.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 66.1 kB
Release files / langchain_cisco_aidefense-1.1.1.tar.gz
| Download URL | langchain_cisco_aidefense-1.1.1.tar.gz |
|---|---|
| Size | 33.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
16a89db04c8160a756a65816f26e86a78c1e4930b65b3fe9997be4aced81eb8a
|
|
BLAKE2b-256 checksum How to use checksums |
1429b00c40272ec45f92764595fa3bdb0d4ee411c7dac5065ae3058f638c50c9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 14, 2026.
Transparency logRelease files / langchain_cisco_aidefense-1.1.1-py3-none-any.whl
| Download URL | langchain_cisco_aidefense-1.1.1-py3-none-any.whl |
|---|---|
| Size | 33.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
cd8480ffe8c30a8134ecfe7b2deae976e63009dc906538897bfa9d5c0b977128
|
|
BLAKE2b-256 checksum How to use checksums |
8caff4484dcf26cc091a7223bdd002d83c9bd3607b22a6070765fe531bb72086
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 14, 2026.
Transparency log