CrewAI tool
Wrap Krawl as a CrewAI tool — let an in-Crew analyst delegate deep, cited research without paying token costs in-loop.
A CrewAI agent can delegate deep-research work out of the main loop by
calling a KrawlResearchTool that streams /research SSE and returns the
final cited markdown.
Working file: docs/cookbook/crewai-tool.py.
Install
pip install crewai httpx
export KRAWL_API_KEY=krawl_demo_xxx
export OPENAI_API_KEY=sk-... # CrewAI's default LLMcurl
The raw SSE stream the tool consumes:
curl -N -X POST https://api.krawl.sh/research \
-H "Content-Type: application/json" \
-H "X-API-Key: $KRAWL_API_KEY" \
-d '{"query": "Compare EigenLayer and Symbiotic", "mode": "deep"}'The event: result SSE frame carries the final markdown field.
Python
import json, os, httpx
from crewai import Agent, Crew, Task
from crewai.tools import BaseTool
class KrawlResearchTool(BaseTool):
name: str = "krawl_research"
description: str = "Deep, cited research. Input: a single question."
def _run(self, query: str) -> str:
with httpx.stream(
"POST",
"https://api.krawl.sh/research",
headers={
"X-API-Key": os.environ["KRAWL_API_KEY"],
"Content-Type": "application/json",
"Accept": "text/event-stream",
},
json={"query": query, "mode": "deep"},
timeout=600,
) as resp:
event = None
for line in resp.iter_lines():
if not line:
continue
if line.startswith("event: "):
event = line.removeprefix("event: ").strip()
elif line.startswith("data: ") and event == "result":
return json.loads(line.removeprefix("data: ")).get("markdown", "")
return ""
analyst = Agent(
role="Senior research analyst",
goal="Answer with cited primary sources.",
backstory="You delegate factual lookups to krawl_research.",
tools=[KrawlResearchTool()],
)
task = Task(
description="Compare EigenLayer and Symbiotic in 2026.",
expected_output="200-400 words with at least 5 [n] citations.",
agent=analyst,
)
Crew(agents=[analyst], tasks=[task]).kickoff()Node
CrewAI is Python-only. For Node, wrap the same /research SSE call in a
LangChain Tool or a
plain async function, and call it from any Node agent runtime:
async function krawlResearch(query: string): Promise<string> {
const r = await fetch("https://api.krawl.sh/research", {
method: "POST",
headers: {
"X-API-Key": process.env.KRAWL_API_KEY!,
"Content-Type": "application/json",
Accept: "text/event-stream",
},
body: JSON.stringify({ query, mode: "deep" }),
});
const reader = r.body!.getReader();
const dec = new TextDecoder();
let buf = "", evt = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
buf += dec.decode(value, { stream: true });
for (const line of buf.split("\n")) {
if (line.startsWith("event: ")) evt = line.slice(7).trim();
if (line.startsWith("data: ") && evt === "result") {
return JSON.parse(line.slice(6)).markdown ?? "";
}
}
buf = buf.endsWith("\n") ? "" : buf.slice(buf.lastIndexOf("\n") + 1);
}
return "";
}Notes
- The tool blocks the calling agent for the entire run. For long jobs use
POST /research/asyncinstead and poll/tasks/{id}. - Set
mode: "quick"(~10s) for cheap pre-flight checks andmode: "deep"(~90s) for the cited synthesis. - Source filtering, cost ceilings, output schemas, and webhooks are all supported on the same request body — see API Reference.
LangChain BaseRetriever
Use Krawl as a LangChain BaseRetriever — drop-in replacement for a vector-store retriever when your chain wants live, multi-source web/X/crypto search instead of a static corpus.
Benchmarks
Krawl's published scores on FRAMES, SimpleQA, and FinSearchComp, plus the Krawl Crypto Research Bench — methodology, leaderboard, and scoring code.