Web search for AI agents, in one line. No dependencies.
pip install keirolabs-api
export KEIRO_API_KEY=keiro_... # free key, 750 credits: https://keirolabs.cloudfrom keirolabs import search
search("latest llama release")
# [{"title": ..., "url": ..., "snippet": ..., "content": ...}, ...]Wrap your OpenAI or Anthropic client. The model searches when it needs to, and you get a normal response back.
from openai import OpenAI
from keirolabs import wrap
client = wrap(OpenAI())
client.chat.completions.create(
model="gpt-4.1",
messages=[{"role": "user", "content": "What did Nvidia report this quarter?"}],
)from anthropic import Anthropic
client = wrap(Anthropic())Any client with the OpenAI chat completions API should work, such as OpenRouter or Groq (tested on Groq). Your own tools keep working: if the model calls one of them, you get the response back as usual. The model gets up to 3 searches per call (max_steps). Sync clients only for now (OpenAI(), Anthropic(), not the async ones). Streaming calls (stream=True) go straight to the model without search.
Searches, reads the pages, and returns the passages most likely to answer the question, packed into your token budget.
from keirolabs import context
prompt = f"""Answer using these sources.
{context("who won the 2022 world cup", max_tokens=1500)}
Question: who won the 2022 world cup?"""It runs on Keiro deep search, which scores 96.5% on SimpleQA.
Change one import. The methods and response keys match Tavily's.
- from tavily import TavilyClient
+ from keirolabs.compat import TavilyClientsearch, get_search_context, qna_search and extract are supported. Differences: score comes from the result's rank, domain filters are applied after the search (so you can get fewer results than you asked for), and images is always empty. A Tavily key is ignored: pass a Keiro key or set KEIRO_API_KEY.
from keirolabs import search, deep, answer, md, tool, run_tool
search("query", mode="lite") # cheapest: $0.10 per 1,000 on paid plans
search("query", mode="fast") # fast live results
search("query", mode="content") # full page markdown for each result
deep("query", budget=2000) # ranked evidence + confidence
answer("query") # {"answer": ..., "sources": [...]}
md("https://example.com") # any page as clean text
tool() # web_search tool for OpenAI-style APIs
tool("anthropic") # ...or Anthropic, "gemini", "json"
run_tool(args) # run a model's web_search call, get the tool result textUse a client object for a different key, base URL or timeout:
from keirolabs import Keiro
k = Keiro(api_key="keiro_...", timeout=60)
k.search("query")Errors raise keirolabs.KeiroError with .status (401 bad key, 402 out of credits, 429 rate limited).
Results are lists of dicts. The full API response (credits used, latency) is on .raw.
Free: 750 credits at signup. Lite costs 1 credit on free, and $0.10 per 1,000 searches on paid plans. Pricing.
MIT license.