Introduction
AI research agents represent one of the most exciting applications of LLMs in 2026. These agents autonomously investigate topics by searching the web, reading sources, forming hypotheses, and synthesizing findings into coherent reports. In this tutorial, we build a complete research agent using Keiro's research and search APIs.
What Makes a Research Agent Different
A simple RAG pipeline performs one search and one generation step. A research agent is different in several key ways:
- Multi-step investigation: The agent decides what to search for based on what it has already found
- Source evaluation: The agent assesses source quality and relevance
- Gap identification: The agent identifies gaps in its knowledge and searches for more information
- Synthesis: The agent produces a structured report, not just a one-paragraph answer
Architecture
Our research agent follows this loop:
- Plan: Break the research question into sub-questions
- Search: Use Keiro to find information for each sub-question
- Evaluate: Assess whether enough information has been gathered
- Synthesize: Produce a final report with citations
Implementation
Step 1: The Research Agent Class
import requests
from openai import OpenAI
import json
class ResearchAgent:
def __init__(self, keiro_api_key: str, openai_api_key: str):
self.keiro_key = keiro_api_key
self.keiro_base = "https://kierolabs.space/api"
self.llm = OpenAI(api_key=openai_api_key)
self.findings = []
self.sources = []
def keiro_search(self, query: str) -> list:
"""Search the web using Keiro."""
resp = requests.post(f"{self.keiro_base}/search-pro", json={
"apiKey": self.keiro_key,
"query": query
})
return resp.json().get("results", [])
def keiro_research(self, query: str) -> dict:
"""Deep research using Keiro's research endpoint."""
resp = requests.post(f"{self.keiro_base}/research", json={
"apiKey": self.keiro_key,
"query": query
})
return resp.json()
def keiro_crawl(self, url: str) -> str:
"""Extract full content from a URL."""
resp = requests.post(f"{self.keiro_base}/web-crawler", json={
"apiKey": self.keiro_key,
"url": url
})
return resp.json().get("content", "")
Step 2: The Planning Phase
def plan_research(self, topic: str) -> list[str]:
"""Break a research topic into sub-questions."""
response = self.llm.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": (
"You are a research planning assistant. Given a research topic, "
"break it into 3-5 specific sub-questions that would comprehensively "
"cover the topic. Return as a JSON array of strings."
)},
{"role": "user", "content": f"Research topic: {topic}"}
],
response_format={"type": "json_object"}
)
result = json.loads(response.choices[0].message.content)
return result.get("questions", result.get("sub_questions", []))
Step 3: The Investigation Loop
def investigate(self, topic: str) -> dict:
"""Run the full research investigation."""
print(f"[Agent] Planning research on: {topic}")
# Phase 1: Plan
sub_questions = self.plan_research(topic)
print(f"[Agent] Identified {len(sub_questions)} sub-questions")
# Phase 2: Research each sub-question
for i, question in enumerate(sub_questions, 1):
print(f"[Agent] Investigating ({i}/{len(sub_questions)}): {question}")
# Use Keiro's research endpoint for the main investigation
research_data = self.keiro_research(question)
if research_data.get("summary"):
self.findings.append({
"question": question,
"summary": research_data["summary"],
"sources": research_data.get("sources", [])
})
self.sources.extend(research_data.get("sources", []))
# Supplement with targeted search for specific details
search_results = self.keiro_search(question)
for result in search_results[:3]:
self.sources.append({
"title": result.get("title", ""),
"url": result.get("url", "")
})
# Phase 3: Check for gaps
gaps = self.identify_gaps(topic)
if gaps:
print(f"[Agent] Found {len(gaps)} knowledge gaps, investigating further...")
for gap in gaps:
additional = self.keiro_search(gap)
for result in additional[:2]:
self.findings.append({
"question": gap,
"summary": result.get("content", result.get("snippet", "")),
"sources": [{"title": result.get("title", ""), "url": result.get("url", "")}]
})
# Phase 4: Synthesize
print("[Agent] Synthesizing final report...")
report = self.synthesize(topic)
return report
Step 4: Gap Identification
def identify_gaps(self, topic: str) -> list[str]:
"""Identify gaps in the current research."""
findings_summary = "\n".join([
f"- {f['question']}: {f['summary'][:200]}" for f in self.findings
])
response = self.llm.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": (
"Review the research findings and identify any significant gaps. "
"Return a JSON array of 0-3 follow-up questions to fill the gaps. "
"Return an empty array if the research is comprehensive."
)},
{"role": "user", "content": (
f"Topic: {topic}\n\nFindings so far:\n{findings_summary}"
)}
],
response_format={"type": "json_object"}
)
result = json.loads(response.choices[0].message.content)
return result.get("gaps", result.get("questions", []))
Step 5: Report Synthesis
def synthesize(self, topic: str) -> dict:
"""Synthesize all findings into a final report."""
all_findings = "\n\n".join([
f"## {f['question']}\n{f['summary']}" for f in self.findings
])
# Deduplicate sources
seen_urls = set()
unique_sources = []
for s in self.sources:
url = s.get("url", "")
if url and url not in seen_urls:
seen_urls.add(url)
unique_sources.append(s)
response = self.llm.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": (
"You are a research report writer. Synthesize the provided research "
"findings into a comprehensive, well-structured report. Include an "
"executive summary, key findings, and conclusions. Cite sources."
)},
{"role": "user", "content": (
f"Topic: {topic}\n\nResearch Findings:\n{all_findings}"
)}
]
)
return {
"topic": topic,
"report": response.choices[0].message.content,
"sources": unique_sources,
"sub_questions_investigated": len(self.findings)
}
Running the Agent
if __name__ == "__main__":
agent = ResearchAgent(
keiro_api_key="your-keiro-api-key",
openai_api_key="your-openai-api-key"
)
result = agent.investigate(
"What is the current state of artificial general intelligence research "
"and which companies are closest to achieving it?"
)
print("\n" + "=" * 80)
print("RESEARCH REPORT")
print("=" * 80)
print(result["report"])
print(f"\nSources ({len(result['sources'])}):")
for s in result["sources"]:
print(f" - {s.get('title', 'N/A')}: {s.get('url', '')}")
Why Keiro's Research Endpoint Is a Game-Changer
Notice how the agent uses Keiro's /research endpoint as the primary investigation tool. Without it, you would need to:
- Make multiple search calls per sub-question
- Crawl the top results to get full content
- Use an LLM to summarize each source
- Manage all this orchestration yourself
Keiro's /research endpoint does all of this in a single API call, saving you both code complexity and LLM token costs.
Cost Analysis
For a typical research investigation with 4 sub-questions:
| API Call | Count | Cost (Keiro Pro) |
|---|---|---|
| /research | 4 | ~$0.0005 |
| /search-pro | 4 | ~$0.0005 |
| Gap-filling /search | 2 | ~$0.00025 |
| OpenAI GPT-4o (planning + synthesis) | 4 calls | ~$0.08 |
| Total | ~$0.08 |
A comprehensive research report for 8 cents. The Keiro API costs are effectively negligible — the LLM is the expensive part.
Extending the Agent
You can extend this agent in several ways:
- Add a verification step that fact-checks claims against additional sources
- Use /batch-research to investigate all sub-questions in parallel (free with Keiro)
- Add a feedback loop where the user can ask follow-up questions
- Store research results using /memory-search for future reference
Conclusion
Building an AI research agent with Keiro is remarkably straightforward. The /research endpoint handles the heavy lifting of multi-source investigation, while /search-pro provides targeted lookups for specific details. The result is an agent that can produce comprehensive research reports at negligible cost.
Start building your research agent at kierolabs.space. The Pro plan gives you 200,000 requests for $24.99/month.