Building an AI Research Agent with Keiro Research API

Learn how to build an autonomous AI research agent that uses Keiro's research and search endpoints to investigate topics, synthesize findings, and produce reports.

12 min readKeiro Team

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 CallCountCost (Keiro Pro)
/research4~$0.0005
/search-pro4~$0.0005
Gap-filling /search2~$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.

Ready to build something?

Join developers using Keiro — 10× cheaper with superior performance.

Get started