Broadie: Opinionated framework for building and serving AI agents with build on LangGraph + LangServe.
Project description
Broadie
Opinionated AI Agent Framework for Reducing Hallucination
Broadie is a production-ready framework for building AI agents with LangGraph and LangServe. It drastically reduces hallucination through structured contracts between agents, LLMs, and tools using Pydantic models.
🎯 Philosophy
Broadie is opinionated by design. We believe AI agents should:
- Use strict Pydantic schemas to enforce structured outputs and reduce hallucination
- Define clear contracts between agents, LLMs, and tools
- Leverage built-in memory and persistence for stateful conversations
- Support agent-to-agent (a2a) communication through a central registry
- Provide easy deployment with minimal configuration
This opinionated approach reduces hallucination by a huge margin compared to free-form text generation.
🚀 Installation
# Install broadie
pip install broadie
# For development
pip install broadie[dev]
Google Cloud Authentication
This project requires access to Google Cloud Vertex AI. You must set up Application Default Credentials (ADC).
-
In your Google Cloud project, create or select a service account with permissions to use Vertex AI (e.g.
roles/aiplatform.user). -
Generate a JSON key for that service account and download it to your machine:
gcloud iam service-accounts keys create key.json \ --iam-account=YOUR_SA_NAME@YOUR_PROJECT.iam.gserviceaccount.com
-
Export the path to this JSON file so that libraries inside the container or locally can find it:
export GOOGLE_APPLICATION_CREDENTIALS="/absolute/path/to/key.json"
-
(Optional) Set your GCP project and region explicitly:
gcloud config set project YOUR_PROJECT_ID gcloud config set ai/region us-central1
-
Verify that authentication works:
gcloud auth application-default print-access-token
Once this is done, you can run:
broadie serve agents/phishing.py:agent
and the Vertex AI integration will have the required credentials.
📚 Quick Examples
Simple Agent
import asyncio
from broadie import create_agent
# Create a basic agent
simple_agent = create_agent(
name="simple_helper",
instruction="Be a helpful assistant, respond appropriately to user messages",
)
async def main():
response = await simple_agent.run("Hello, can you help me with something?")
print(response)
asyncio.run(main())
Run this example:
# Direct execution
python simple_agent.py
# Using broadie CLI
broadie chat examples/simple.py:simple_agent
# Serve as API endpoint (includes built-in playground)
broadie serve examples/simple.py:simple_agent --port 8000
Agent with Tools
import asyncio
from pydantic import BaseModel, Field
from broadie import create_agent, tool, ToolResponse
# Define a custom tool using ToolResponse
@tool("lookup_weather", description="Get weather information for a location")
def lookup_weather(location: str) -> ToolResponse:
"""Look up weather for a given location."""
return ToolResponse.success(
message=f"Weather lookup completed for {location}",
data={"location": location, "temperature": "22°C", "condition": "sunny"},
meta={"source": "weather_api", "lookup_type": "current"}
)
# Define structured output using Pydantic
class WeatherOutput(BaseModel):
summary: str = Field(..., description="Human-readable weather summary")
location: str = Field(..., description="The location queried")
temperature: str = Field(..., description="Current temperature")
recommendation: str = Field(..., description="What the user should do based on weather")
# Create agent with tool and structured output
weather_agent = create_agent(
name="weather_assistant",
instruction="Help users with weather information and provide recommendations",
tools=[lookup_weather],
output_schema=WeatherOutput
)
async def main():
response = await weather_agent.run("What's the weather like in Boston?")
print(response)
asyncio.run(main())
Run this example:
# Direct execution
python weather_agent.py
# Using broadie CLI
broadie chat examples/weather_agent.py:weather_agent
# Serve as API endpoint (includes built-in playground)
broadie serve examples/weather_agent.py:weather_agent --port 8000
Advanced Agent with ToolResponse
This example demonstrates how broadie reduces hallucination by enforcing strict contracts between agents, tools, and LLMs using Pydantic models and ToolResponse:
import asyncio
from enum import Enum
from pydantic import BaseModel, Field
from broadie import create_agent, create_sub_agent, tool, ToolResponse
# Define enums for structured responses - this prevents LLM hallucination
class Verdict(str, Enum):
malicious = "malicious"
suspicious = "suspicious"
benign = "benign"
unknown = "unknown"
class EnrichmentResult(BaseModel):
indicator: str
type: str
verdict: Verdict
class ThreatIntelOutput(BaseModel):
summary: str = Field(..., description="Human-readable summary of the threat analysis")
enrichments: list[EnrichmentResult] = Field(..., description="List of enriched indicators with verdicts")
# Tool using ToolResponse - enforces structured output contract
@tool("lookup_ip", description="Look up IP reputation in a threat intel database")
def lookup_ip(ip: str) -> ToolResponse:
"""Look up IP reputation using ToolResponse pattern."""
reputation = "malicious" if ip.startswith("192.") else "clean"
return ToolResponse.success(
message=f"IP {ip} reputation lookup completed",
data={"ip": ip, "reputation": reputation},
meta={"source": "threat_intel_db", "lookup_type": "ip"}
)
@tool("lookup_domain", description="Check domain reputation in DNS and threat feeds")
def lookup_domain(domain: str) -> ToolResponse:
"""Check domain reputation using ToolResponse pattern."""
category = "phishing" if "phish" in domain else "benign"
return ToolResponse.success(
message=f"Domain {domain} reputation lookup completed",
data={"domain": domain, "category": category},
meta={"source": "dns_threat_feeds", "lookup_type": "domain"}
)
# Create specialized subagent
indicator_enricher = create_sub_agent(
name="indicator_enricher",
prompt="Given an IP or domain, enrich it with threat intel context.",
output_schema=EnrichmentResult,
tools=[lookup_ip, lookup_domain],
)
# Main threat intelligence agent
threat_intel_agent = create_agent(
name="threat_intel",
instruction="You are a threat intelligence assistant. Analyze indicators and produce structured enrichment.",
output_schema=ThreatIntelOutput,
tools=[lookup_ip, lookup_domain],
subagents=[indicator_enricher],
channels=[{ # Built-in Slack integration
"type": "slack",
"target": "#threat-feed",
"instructions": "Summarize in Slack blocks"
}]
)
async def main():
email_message = "Hello user, please reset your password here: http://bad-link.com"
result = await threat_intel_agent.run(email_message)
print(result)
asyncio.run(main())
Run this example:
# Direct execution
python examples/standard.py
# Using broadie CLI
broadie chat examples/standard.py:phish_guardian
# Serve as API endpoint (includes built-in playground)
broadie serve examples/standard.py:phish_guardian --port 8000
The ToolResponse pattern ensures that tools return structured data that the LLM cannot hallucinate or modify - the contract is enforced at the type level.
📡 Configuring Channels
To enable Slack and email notifications from your agents, you need to set the following environment variables:
Slack Configuration
# Slack Bot Configuration
SLACK_BOT_TOKEN=xoxb-your-bot-token-here
SLACK_SIGNING_SECRET=your-signing-secret-here
How to get Slack credentials:
- Bot Token: Create a Slack app at api.slack.com/apps, go to "OAuth & Permissions" and install the app to get your bot token
- Signing Secret: Found in your Slack app settings under "Basic Information" → "App Credentials"
Email/SMTP Configuration
# SMTP Configuration
SMTP_HOST=smtp.sendgrid.net
SMTP_PORT=587
SMTP_USE_TLS=true
SMTP_USERNAME=apikey
SMTP_PASSWORD=your-sendgrid-api-key
EMAIL_FROM=alerts@yourdomain.com
How to get SendGrid credentials:
- Sign up at sendgrid.com
- Create an API key in Settings → API Keys
- Use
apikeyas the username and your API key as the password - Verify your sender email address in SendGrid
Once configured, your agents will automatically send notifications to the specified channels when they complete their tasks.
📊 Tracing and Observability
broadie integrates with LangSmith (by LangChain) for comprehensive tracing and observability of your agents. This allows you to monitor agent performance, debug issues, and view detailed execution traces.
LangSmith Configuration
# LangSmith Tracing Configuration
LANGCHAIN_TRACING_V2=true
LANGCHAIN_ENDPOINT=https://api.smith.langchain.com
LANGCHAIN_API_KEY=your-langsmith-api-key
LANGCHAIN_PROJECT=broadie
Environment Variables:
- LANGCHAIN_TRACING_V2: Set to
trueto enable LangSmith tracing (default:false) - LANGCHAIN_ENDPOINT: LangSmith API endpoint (default:
https://api.smith.langchain.com) - LANGCHAIN_API_KEY: Your LangSmith API key for authentication (required for tracing)
- LANGCHAIN_PROJECT: Project name to organize your traces (default:
broadie)
How to get LangSmith credentials:
- Sign up at smith.langchain.com (FREE tier available)
- Create a new project or use an existing one
- Go to Settings → API Keys and create a new API key
- Set the environment variables above with your credentials
Viewing traces and tools:
- Visit smith.langchain.com and navigate to your project
- View detailed traces showing agent execution, tool calls, and LLM interactions
- Monitor performance metrics, token usage, and execution times
- Debug issues by examining failed runs and error traces
- Analyze tool usage patterns and optimize agent performance
Once configured, all agent runs will be automatically traced and visible in the LangSmith dashboard.
🏗️ Core Architecture
The Contract System
broadie enforces contracts between three key components:
- Agent Contract: Defines what the agent can do, its tools, and expected outputs
- LLM Contract: Structured via Pydantic schemas to prevent hallucination
- Tool Contract: Type-safe tool definitions with clear input/output schemas
# This contract prevents the LLM from hallucinating invalid data structures
from pydantic import BaseModel, Field
from broadie import create_agent
from typing import List
class UserProfile(BaseModel):
name: str = Field(..., min_length=1, max_length=100)
age: int = Field(..., ge=0, le=150)
email: str = Field(..., description="it contains an @ symbol")
preferences: List[str] = Field(default_factory=list)
agent = create_agent(
name="user_manager",
output_schema=UserProfile, # Enforces structure
instruction="Extract user information from text"
)
Built-in Memory & Persistence (WIP)
Every agent has persistent memory by design:
from broadie import create_agent
# Memory is automatic - no configuration needed
agent = create_agent(name="assistant", instruction="Remember our conversations")
# Conversations are automatically persisted across runs
response1 = await agent.run("My name is Alice", thread_id="user_123")
response2 = await agent.run("What's my name?", thread_id="user_123") # Remembers Alice
Agent-to-Agent (A2A) Communication (WIP)
broadie includes a central registry for agent discovery and communication:
# Register your agent
await agent.register_to_registry()
# Discover other agents
available_agents = await discover_agents(capabilities=["data_analysis"])
# Communicate with other agents
result = await agent.delegate_to("data_analyst", "Analyze this dataset")
🛠️ CLI Tools
Chat with Your Agent
# Interactive chat session
broadie chat examples/standard.py:phish_guardian
# Chat with specific configuration
broadie chat examples/standard.py:phish_guardian --thread user123
Serve Your Agent
# Expose agent via HTTP API (includes built-in playground)
broadie serve examples/standard.py:phish_guardian --port 8000
# Serve with registry registration
broadie serve examples/standard.py:phish_guardian --register --host 0.0.0.0
# Disable playground in production
PLAYGROUND_ENABLED=false broadie serve examples/standard.py:phish_guardian --port 8000
Playground
The playground is built into the serve command and provides a web interface to test your agents:
# Serve with playground enabled (default)
broadie serve examples/standard.py:phish_guardian --port 8000
# Disable playground for production (recommended)
PLAYGROUND_ENABLED=false broadie serve examples/standard.py:phish_guardian --port 8000
Note: Always disable the playground in production environments by setting PLAYGROUND_ENABLED=false.
🚀 Easy Deployment (WIP)
Deploy your agents with minimal configuration:
# Initialize project structure
broadie init my_project
# Deploy to production
broadie deploy --config production.yaml
# Scale horizontally
broadie scale --replicas 3
🔧 Upcoming Features
- Multi-model Support: Google VertexAI, OpenAI, Anthropic, and custom providers
- Monitoring: Prometheus metrics, structured logging, health checks
- Security: Enterprise authentication, authorization, audit logging
📞 Support
For questions, issues, or contributions:
Email: scientific-computing@broadinstitute.org
🤝 Contributing
broadie is developed by the Broad Institute. We welcome contributions! See our contributing guidelines for details.
Built with ❤️ by the Broad Institute
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file broadie-2.0.6.tar.gz.
File metadata
- Download URL: broadie-2.0.6.tar.gz
- Upload date:
- Size: 40.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.10.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dc38b40bb224fdc3a7f43e22442c9295c443861b83359f6150e45f91887a89d8
|
|
| MD5 |
1141bf8bfd22078ef86440b851568381
|
|
| BLAKE2b-256 |
78de383c9aa49e2e58f7ef2d0ca20094804056d439a26de7380dd926e972259a
|
File details
Details for the file broadie-2.0.6-py3-none-any.whl.
File metadata
- Download URL: broadie-2.0.6-py3-none-any.whl
- Upload date:
- Size: 39.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.10.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ff6337cc869502015672ba2fbf61fa506d22721b72d84be4ffe822222944d3b6
|
|
| MD5 |
fcb1631bb78520579f224d295a3a17f6
|
|
| BLAKE2b-256 |
116c9473d92c24ac9e482c9574668a79368e87090bab4d019b8ead7567f70a90
|