# Practical and Useful Patterns with ADK
## 🔌 Apply Cross-Cutting Concerns to All Agents at Once with Plugins
Setting up callbacks on every individual agent is tedious. ADK **Plugins** let you register once at the Runner level and apply security, logging, and rate limiting across all agents, tools, and LLM calls! 🎯
## 📌 Title
Plugins
## 🔗 URL
## 🧩 Overview
Plugins are cross-agent modules that operate at the Runner level. Unlike agent-specific callbacks, **a single registration applies to every agent, tool, and LLM call** in your application. They're ideal for cross-cutting concerns like security guardrails, logging, and rate limiting.
Plugins execute **before** agent-level callbacks, making them perfect for global policy enforcement.
ADK ships with built-in plugins: Reflect and Retry Tools, BigQuery Analytics, Context Filter, Global Instruction, and Logging Plugin.
## 🛠 How to Use
Import `BasePlugin` from `google.adk.plugins.base_plugin` and `InMemoryRunner` from `google.adk.runners`. Define `SecurityGuardPlugin` as a subclass of `BasePlugin`, initializing with `name="security_guard"`. Its `before_model_callback` method extracts user input from `llm_request.contents[-1].parts[0].text`, checks for injection via `detect_injection()`, and returns a rejection `LlmResponse` if detected. Its `before_tool_callback` method checks `is_authorized( and returns an error dictionary if access is denied. Both return `None` to continue when no issue is found. Finally, create an `InMemoryRunner` with `plugins=[SecurityGuardPlugin()]` to apply this guard to all agents automatically.
## 🏗 Practical Usage
**"Gemini as a Judge" pattern for injection detection:**
`InjectionDetectorPlugin` extends `BasePlugin` with `name="injection_detector"` and stores `self.judge_model = "gemini-flash-lite"` as its judge model. In `before_model_callback`, it extracts user input from `llm_request.contents[-1].parts[0].text` and passes it to `judge_with_flash_lite()` for fast injection detection. If the verdict is `"INJECTION"`, it calls `audit_log()` and returns a rejection `LlmResponse` to block the request. Otherwise, it returns `None`.
`RateLimitPlugin` extends `BasePlugin` with `name="rate_limiter"`, accepting a `max_calls_per_minute` parameter (default 60). It tracks call timestamps in ` and in `before_model_callback`, filters out entries older than 60 seconds. If the count meets or exceeds `self.max_calls`, it returns an `LlmResponse` with a rate limit message. Otherwise, it appends the current timestamp and returns `None`.
Finally, an `InMemoryRunner` is created with `plugins=[InjectionDetectorPlugin(), RateLimitPlugin(max_calls_per_minute=30)]` to combine multiple plugins for the production app.
## 💡 Use Cases
- 🛡️ **Security guardrails**: Centralized injection detection and PII protection across all agents
- 📊 **Unified logging**: Aggregate execution logs from all agents with the BigQuery Analytics plugin
- ⏱️ **Rate limiting**: Control API call frequency to prevent cost explosions
- 🔄 **Auto-retry**: Intelligent tool failure retries with the Reflect and Retry Tools plugin
- 📝 **Global instructions**: Inject shared policies or instructions into every agent
## ⚠️ Caveats
- Plugins execute **before** agent-level callbacks — be aware of precedence
- Returning a value from a plugin skips both the operation and any corresponding agent-level callback
- Since plugins apply to all agents, use Callbacks for agent-specific logic
- Error handling is available via `on_model_error_callback` / `on_tool_error_callback` hooks
- Available in Python v1.7.0+, TypeScript v0.2.5+, Go v0.4.0+, Java v0.3.0+
## ✨ Closing
Plugins deliver "write once, apply everywhere" for cross-cutting concerns. Delegate security, logging, and rate limiting to Plugins, and keep agent-specific logic in Callbacks. This separation improves both maintainability and security!
#
ADK# #
AIAgent#