A simple, budget-controlled research agent that searches the web, scrapes and compresses sources, and generates markdown reports -- without running out of control.
~70 research questions for $1. Perfect for quick lookups where you need a fast answer to know where to dig deeper: which foods are on a specific diet, initial research on AI agent architectures, comparing tool options, etc.
This is a controlled research agent with:
- 💸 Budget enforcement (~$0.02 per run)
- 🔍 Web search + scraping + semantic compression
- 📊 Cost + usage tracking
Inspired by gpt-researcher, it uses a simple linear pipeline and exposes its capabilities over the Agent-to-Agent (A2A) protocol so any A2A-compatible client can invoke it.
The agent runs a four-step linear pipeline:
query
|
v
search -- web search via Tavily
|
v
scrape + compress -- fetch pages with Crawl4AI, compress via embeddings
|
v
assemble context -- join compressed pages, truncate if needed
|
v
generate report -- single LLM call to produce markdown report
Each step is a plain async function -- no graph framework, no multi-agent orchestration. The entire pipeline is ~165 lines of code.
ActGuard is integrated as a budget control and cost tracking layer. Every expensive operation in the pipeline -- LLM calls, web searches, and page scrapes -- is wrapped in an ActGuard budget guard. This prevents runaway API costs during research.
How it works:
- Each research run is started with a configurable cost limit (default: 500 units)
- Individual operations are tracked under named guards (
search,scrape,write_report) - If the budget is exceeded mid-run, ActGuard raises a
BudgetExceededErrorand the agent returns a graceful error instead of continuing to spend
To enable budget tracking, visit actguard.ai, create a free account, and add your ACTGUARD_API_KEY to .env. If unset, budget tracking is disabled.
| Library | Purpose |
|---|---|
| Tavily | Web search API optimized for AI agents. |
| Crawl4AI | Async web scraper with headless browser and markdown extraction. |
| OpenAI Embeddings | Semantic compression -- keeps only the chunks relevant to the query. |
| ActGuard | Budget control and cost tracking for AI agent operations. |
| A2A SDK | Agent-to-Agent protocol. Exposes the agent as a JSON-RPC endpoint. |
| LangChain OpenAI | OpenAI integration for LLM calls with structured output. |
| Streamlit | Chat UI for interactive research sessions. |
research-agent/
├── app/
│ ├── __init__.py
│ ├── __main__.py # Entry point -- starts the A2A server
│ ├── agent_executor.py # A2A AgentExecutor implementation
│ ├── config.py # Settings (env vars + defaults)
│ ├── a2a_auth.py # HMAC authentication middleware
│ ├── researcher/
│ │ ├── graph.py # Research pipeline (search → scrape → compress → report)
│ │ ├── prompts.py # LLM prompt templates
│ │ ├── schemas.py # Pydantic output models
│ │ ├── errors.py # Custom exceptions
│ │ └── actguard_client.py # ActGuard client initialization
│ └── services/
│ ├── llm.py # OpenAI async client
│ ├── search.py # Tavily search client
│ ├── scraper.py # Crawl4AI web scraper
│ └── embeddings.py # Semantic compression via embeddings
├── chat.py # Streamlit chat UI
├── scripts/
│ └── sign_request.py # Send HMAC-signed A2A requests (testing helper)
├── config/
│ └── a2a_auth.json # A2A authentication config
├── tests/
│ ├── test_client.py # Integration tests (A2A endpoints)
│ └── test_graph.py # Unit tests (pipeline execution)
├── .env.example
├── .gitignore
├── pyproject.toml
└── uv.lock
- Python 3.12+
- uv package manager
- An OpenAI API key
- A Tavily API key
- (Optional) An ActGuard account (free) for measuring agent cost
# 1. Clone the repo
git clone https://github.com/ActGuard/research-agent.git
cd research-agent
# 2. Copy the env template and fill in your API keys
cp .env.example .env
# 3. Install dependencies
uv sync
# 4. Start the agent server
uv run python -m appThe server starts on http://localhost:10000. Verify it's running:
curl http://localhost:10000/.well-known/agent.json| Variable | Default | Description |
|---|---|---|
OPENAI_API_KEY |
(required) | OpenAI API key |
TAVILY_API_KEY |
(required) | Tavily search API key |
A2A_HMAC_SECRET |
"" |
64-char hex string (256-bit) for signing A2A requests. Generate one with openssl rand -hex 32 |
ACTGUARD_API_KEY |
"" |
ActGuard API key for cost tracking. Create a free account at actguard.ai. Optional -- budget tracking is disabled if unset |
HOST |
localhost |
Server bind address |
PORT |
10000 |
Server port |
OPENAI_MODEL |
gpt-4o-mini |
Default OpenAI model |
MAX_SEARCH_RESULTS |
5 |
Tavily results per query |
MAX_SCRAPE_URLS |
5 |
Max pages to scrape per run |
MAX_CONTEXT_CHARS |
50000 |
Context truncation limit |
REPORT_FORMAT |
markdown |
Output format hint passed to the report writer |
Model & embedding overrides
| Variable | Default | Description |
|---|---|---|
MODEL_WRITE_REPORT |
OPENAI_MODEL |
Model used for report generation |
EMBEDDING_MODEL |
text-embedding-3-small |
Embedding model for semantic compression |
CHUNK_SIZE |
1000 |
Characters per chunk for embedding |
CHUNK_OVERLAP |
100 |
Overlap between chunks |
SIMILARITY_THRESHOLD |
0.75 |
Minimum similarity to keep a chunk |
For a conversational interface, run the Streamlit app directly -- no A2A server needed:
uv run streamlit run chat.pyThis opens a browser-based chat where you can ask research questions interactively. Use the sidebar to switch between demo users or clear the chat history.
Pass your research question as a command-line argument:
uv run python scripts/sign_request.py "What are the main approaches to quantum error correction?"Note: Queries are limited to 400 characters.
The script sends a signed A2A message/send JSON-RPC request to the running server and prints the response. A successful response looks like:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"status": { "state": "completed" },
"artifacts": [
{
"artifactId": "...",
"name": "Research Report",
"parts": [{ "text": "# Quantum Error Correction\n..." }]
}
]
}
}Unit tests (runs the pipeline directly -- requires API keys):
uv run pytest tests/test_graph.pyIntegration tests (requires a running server):
uv run python -m app & # start the server
uv run pytest tests/test_client.py- gpt-researcher -- inspiration for the research pipeline
- A2A protocol -- Agent-to-Agent interoperability spec
- Tavily -- search API for AI agents
- Crawl4AI -- async web scraper with headless browser
- ActGuard -- budget control for AI agents

