Skip to content

Latest commit

Β 

History

27 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Agent Governance Hub

A lightweight, policy-driven governance framework for LLM agents with ReAct reasoning. Control agent behavior through declarative YAML policies and structured observabilityβ€”ensuring safe, compliant, and traceable AI operations.

Overview

Agent Governance Hub provides a policy-first architecture for governing LLM agents. Every action is evaluated against declarative policies before execution, with complete separation between policy enforcement and observability logging.

What makes this project unique: We investigate how governance becomes critical when agents make autonomous decisions about tool usage. Our RAG agent uses an LLM that independently decides whether to retrieve documents or answer directlyβ€”and governance policies control both the query permission AND the retrieval tool execution. This demonstrates real-world scenarios where AI agents need guardrails on their decision-making process, not just their final actions.

Key Features

  • πŸ”’ Policy Enforcement: Automatic evaluation before every agent action
  • πŸ“Š Separated Observability: Independent callbacks for governance and logging
  • πŸ€– ReAct Agent: OpenAI-powered reasoning with LangChain tool calling (gpt-3.5-turbo)
  • πŸ” Vector Retrieval: Built-in semantic search with Qdrant (in-memory) + HuggingFace embeddings
  • πŸ“ Structured Logging: Complete traceability of LLM decisions, tool usage, and policy evaluations
  • 🎯 Autonomous RAG Decision-Making: LLM independently decides when to use retrieval tools vs. direct answers
  • πŸ‘οΈ RAG Usage Visibility: Clear indicators showing whether the agent used RAG (πŸ”) or answered directly (πŸ’¬)
  • ⚑ FastAPI Integration: RESTful API for policy evaluation and agent orchestration
  • πŸ›‘οΈ Type Safety: Pydantic validation throughout the stack

Architecture

High-Level Flow

The architecture demonstrates governance at two critical decision points:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  User Query      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  GovernedRAGAgent                                    β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚ 1. Policy Check (ask_question action)       β”‚   β”‚
β”‚  β”‚    ↓ PolicyEngine.evaluate()                β”‚   β”‚
β”‚  β”‚    ↓ Decision: ALLOW/BLOCK                  β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                      β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚ 2. LLM Reasoning (ReAct pattern)            β”‚   β”‚
β”‚  β”‚    ↓ OpenAI GPT-3.5-turbo                   β”‚   β”‚
β”‚  β”‚    ↓ Decides: Direct Answer vs Tool Call    β”‚   β”‚
β”‚  β”‚    ⚠️ AUTONOMOUS DECISION - NOT CONTROLLED   β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                      β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚ 3. Tool Execution (if needed)               β”‚   β”‚
β”‚  β”‚    ↓ PolicyEnforcementCallback intercepts   β”‚   β”‚
β”‚  β”‚    ↓ Gets tool.policy_action metadata       β”‚   β”‚
β”‚  β”‚    ↓ PolicyEngine.evaluate(query_database)  β”‚   β”‚
β”‚  β”‚    ↓ VectorRetrievalTool executes           β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                      β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚ 4. Observability (throughout)               β”‚   β”‚
β”‚  β”‚    ↓ ObservabilityCallback logs all events  β”‚   β”‚
β”‚  β”‚    ↓ Timing, decisions, tool calls          β”‚   β”‚
β”‚  β”‚    ↓ Tracks: πŸ” RAG vs πŸ’¬ Direct mode      β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Final Answer    β”‚
β”‚  + Metadata      β”‚
β”‚  (RAG used?)     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Why This Matters: The LLM's autonomous decision-making (step 2) is the reason governance is critical. We can't predict when the agent will use tools, so we must:

  • Enforce policies at the tool execution layer (step 3)
  • Track which decision path was taken (step 4)
  • Provide visibility into agent behavior patterns

Core Components

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  YAML Policies (config/policies/default.yaml)      β”‚
β”‚  β€’ Declarative rules: allow/block/verify/flag      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                  β”‚
                  β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  PolicyEngine (governance/policy_engine.py)        β”‚
β”‚  β€’ Evaluates agent_id + action + context          β”‚
β”‚  β€’ First-match rule strategy                       β”‚
β”‚  β€’ Returns EvaluationResult with decision          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                  β”‚
                  β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  PolicyEnforcementCallback (agents/callbacks.py)   β”‚
β”‚  β€’ Intercepts tool calls before execution          β”‚
β”‚  β€’ Reads tool.policy_action metadata               β”‚
β”‚  β€’ Blocks execution if policy denies               β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                  β”‚
                  β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  VectorRetrievalTool (tools/vector_retrieval.py)   β”‚
β”‚  β€’ Metadata: policy_action = "query_database"      β”‚
β”‚  β€’ Executes Qdrant similarity search               β”‚
β”‚  β€’ Returns top-k relevant documents                β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                  β”‚
                  β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  ObservabilityCallback (agents/callbacks.py)       β”‚
β”‚  β€’ Logs LLM reasoning steps                        β”‚
β”‚  β€’ Tracks tool execution timing                    β”‚
β”‚  β€’ Records policy evaluation results               β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Quick Start

Prerequisites

  • Python 3.11+
  • Poetry (dependency management)
  • OpenAI API key

Installation

# Clone repository
git clone https://github.com/MiguelBarriosAl/agent-governance-hub.git
cd agent-governance-hub

# Install dependencies
poetry install

# Configure OpenAI API key
echo "OPENAI_API_KEY=your-api-key-here" > .env

# Run the demo
poetry run python main.py

# Run tests
poetry run pytest -v

Demo Output

The demo showcases governed RAG with autonomous LLM decision-making:

Query: What information do you have about machine learning?
------------------------------------------------------------
πŸ” RAG | Answer: I found some information about machine learning:
Machine learning models require large amounts of training data...
Decision: allow (R007)

Query: Hello! How are you?
------------------------------------------------------------
πŸ’¬ Direct | Answer: Hello! I'm here and ready to assist you. How can I help you today?
Decision: allow (R007)

Query: Find details about vector databases
------------------------------------------------------------
πŸ” RAG | Answer: Vector databases store data as high-dimensional vectors...
Decision: allow (R007)

Key Observations:

  • πŸ” RAG Mode: The LLM autonomously decided to use the vector retrieval tool for technical questions
  • πŸ’¬ Direct Mode: The LLM answered the greeting directly without tool usage
  • βœ… Governance Applied: Both the ask_question action and query_database tool calls were evaluated by policies

What This Demonstrates: This simple demo reveals the complexity of governing autonomous agents. The LLM makes real-time decisions about when to use RAG, and our governance framework must control:

  1. Whether the agent can process the query (ask_question policy)
  2. Whether the agent can execute retrieval tools (query_database policy)
  3. Complete observability of which path the LLM chose

This two-layer governance is critical in production systems where AI agents have multiple tools and make autonomous decisions about when to use them.

Usage Examples

1. Define Policies (YAML)

version: "1.0"
policies:
  - agent_id: "retriever"
    description: "Rules for RAG agent with vector retrieval"
    rules:
      - id: "R007"
        action: "ask_question"
        decision: "allow"
        conditions: {}
        reason: "Users can ask questions to the agent"

      - id: "R008"
        action: "query_database"
        decision: "allow"
        conditions: {}
        reason: "Agent can query the vector database for information"

      - id: "R003"
        action: "delete_data"
        decision: "block"
        conditions: {}
        reason: "Destructive operations are forbidden"

2. Create a Tool with Policy Metadata

from langchain.tools import BaseTool
from langchain.pydantic_v1 import BaseModel, Field

class VectorRetrievalTool(BaseTool):
    name: str = "vector_retrieval"
    description: str = "Search the vector database for documents"
    
    # Policy metadata - governance callback uses this
    policy_action: str = "query_database"
    
    def _run(self, query: str) -> str:
        # Execute search
        results = self.vectorstore.similarity_search(query, k=3)
        return format_results(results)

3. Use the Governed Agent

from pathlib import Path
from governance.policy_loader import PolicyLoader
from governance.policy_engine import PolicyEngine
from governance.models import DecisionType
from pipelines.document_pipeline import DocumentPipeline
from agents.rag_agent import GovernedRAGAgent

# Step 1: Load governance policies
loader = PolicyLoader(Path("config/policies"))
policies = loader.load_all_policies()
engine = PolicyEngine(policies=policies, default_decision=DecisionType.BLOCK)

# Step 2: Setup document pipeline (separate from agent)
pipeline = DocumentPipeline(collection_name="my_documents")
pipeline.load_documents(Path("data/docs"))

# Step 3: Create governed agent with pre-loaded vector store
agent = GovernedRAGAgent(
    name="retriever",
    policy_engine=engine,
    vector_manager=pipeline.get_vector_manager(),
    llm_model="gpt-3.5-turbo",
    temperature=0.0
)

# Step 4: Query the agent - LLM decides RAG vs Direct
result = agent.ask("What is machine learning?")

# Result includes answer + governance metadata + RAG usage
print(f"{result['answer']}")
print(f"Decision: {result['decision']} (rule: {result['rule_id']})")
print(f"Used RAG: {result['used_rag']}")  # True if vector retrieval was used
print(f"Tools: {result['tools_used']}")   # List of tools the LLM invoked

Architecture Explanation:

  • Separation of Concerns: Document loading happens in DocumentPipeline, not the agent
  • Policy-First: Engine with default_decision=BLOCK denies everything not explicitly allowed
  • Autonomous Decision: The LLM independently chooses when to use RAGβ€”governance tracks this
  • Observable Behavior: Every result includes metadata about what the agent actually did

4. Structured Logging Output

15:29:07 | INFO | agents.rag_agent | Processing user query | agent=retriever
15:29:07 | INFO | agents.rag_agent | Policy evaluation for query | decision=allow | rule_id=R007
15:29:07 | INFO | agents.callbacks | LLM reasoning started | model=gpt-3.5-turbo
15:29:08 | INFO | agents.callbacks | Agent action decided | tool=vector_retrieval
15:29:08 | INFO | agents.callbacks | Tool execution requested by LLM | tool=vector_retrieval
15:29:08 | INFO | agents.callbacks | Tool execution completed | elapsed_ms=12.32
15:29:09 | INFO | agents.rag_agent | Query processed successfully | elapsed_ms=2100.16

Project Structure

agent-governance-hub/
β”œβ”€β”€ agents/                    # Agent execution logic
β”‚   β”œβ”€β”€ base_agent.py          # Abstract base with policy evaluation
β”‚   β”œβ”€β”€ rag_agent.py           # ReAct RAG agent with OpenAI
β”‚   β”œβ”€β”€ vector_store_manager.py # Manages embeddings and vectorstore
β”‚   β”œβ”€β”€ tool_manager.py        # Configures tools and AgentExecutor
β”‚   β”œβ”€β”€ execution_coordinator.py # Executes with governance callbacks
β”‚   β”œβ”€β”€ callbacks.py           # Separated callbacks
β”‚   β”‚   β”œβ”€β”€ PolicyEnforcementCallback
β”‚   β”‚   └── ObservabilityCallback
β”‚   └── prompts.py             # LLM prompt templates
β”œβ”€β”€ pipelines/                 # Setup and preparation logic
β”‚   └── document_pipeline.py   # Document loading (separate from agent)
β”œβ”€β”€ tools/                     # LangChain tools with policy metadata
β”‚   └── vector_retrieval.py    # Vector search tool
β”œβ”€β”€ governance/                # Policy engine core
β”‚   β”œβ”€β”€ models.py              # Pydantic models (Policy, Rule, DecisionType)
β”‚   β”œβ”€β”€ policy_loader.py       # YAML loading & validation
β”‚   └── policy_engine.py       # Rule evaluation logic
β”œβ”€β”€ config/                    # Configuration
β”‚   β”œβ”€β”€ settings.py            # Application settings
β”‚   └── policies/              # YAML policy files
β”‚       └── default.yaml       # Default governance rules
β”œβ”€β”€ data/docs/                 # Sample documents for vector search
β”œβ”€β”€ tests/                     # Test suite (11 passing tests)
β”‚   β”œβ”€β”€ agents/                # Agent tests
β”‚   └── governance/            # Policy tests (11 tests)
β”œβ”€β”€ main.py                    # Clean demo showing RAG decision-making (69 lines)
β”œβ”€β”€ pyproject.toml             # Dependencies (Poetry)
└── .env                       # API keys (gitignored)

Key Design Decisions:

  • pipelines/ handles setup; agents/ handles execution (clear separation)
  • ExecutionCoordinator tracks tool usage to provide RAG visibility
  • main.py kept minimal and readable (69 lines) to demonstrate architecture clearly

Policy System

Decision Types

  • allow: Action proceeds without restrictions
  • block: Action is rejected immediately
  • verify: Requires human approval (future: integration with approval workflows)
  • flag: Action proceeds but is logged for audit

Conditions

Add dynamic conditions to rules:

- id: "R005"
  action: "analyze"
  decision: "verify"
  conditions:
    max_tokens: 4000  # Only verify if exceeds threshold
  reason: "Large analysis requires human oversight"

Roadmap

Immediate Priorities

  • Observability Integration: Connect structured logs to monitoring platforms (Datadog, Grafana, Prometheus)
  • Metrics Dashboard: Export key metrics (policy violations, RAG usage rate, tool execution time, LLM token consumption)
  • Production Monitoring: Add alerting for governance failures, blocked actions, and abnormal agent behavior patterns

Future Enhancements

  • Add more sophisticated policy conditions (regex patterns, context-aware rules)
  • Implement VERIFY decision workflow (human-in-the-loop)
  • Add policy versioning and A/B testing
  • Multi-agent orchestration with shared governance
  • Policy analytics dashboard (Streamlit/Gradio)
  • Performance benchmarks for policy evaluation overhead

Contributing

Contributions are welcome! Please follow these guidelines:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feat/new-feature)
  3. Write tests for new functionality (maintain >90% coverage)
  4. Ensure all tests pass (poetry run pytest -v)
  5. Update documentation as needed
  6. Submit a pull request with clear description

Development Setup

# Install dev dependencies
poetry install --with dev

# Run linter
poetry run ruff check .

# Format code
poetry run black .

# Type checking
poetry run mypy agents/ governance/

About

A lightweight, open-source governance middleware for LLM agents. Includes a policy engine (YAML rules) and runtime guardrails to audit, evaluate, and control agent behavior with metrics and observability. Built with FastAPI, LangChain, and Prometheus for modern AgentOps and AI Governance workflows.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages