LangGraph agents excel at multi-step reasoning but hallucinate when they lack access to current information. Adding a web search tool node gives the agent live data grounding so it can verify facts, find sources, and build research outputs from real search results. The Scavio API integrates as a tool node that returns structured JSON including organic results, AI Overviews, and People Also Ask data. This tutorial shows how to define a search tool, wire it into a LangGraph graph, and build a research agent that queries multiple keywords and synthesizes findings.
Prerequisites
- Python 3.10+ installed
- langgraph and langchain-core installed
- A Scavio API key from scavio.dev
- Basic familiarity with LangGraph graph definitions
Walkthrough
Step 1: Define the search tool
Create a tool function that calls the Scavio API and returns structured results for the agent.
import os, requests
from langchain_core.tools import tool
API_KEY = os.environ["SCAVIO_API_KEY"]
@tool
def web_search(query: str) -> str:
"""Search the web and return top results."""
resp = requests.post("https://api.scavio.dev/api/v1/search",
headers={"x-api-key": API_KEY},
json={"platform": "google", "query": query})
results = resp.json().get("organic_results", [])[:5]
return "\n".join(f"{r['title']}: {r.get('snippet','')}" for r in results)Step 2: Build the graph
Create a LangGraph StateGraph with an agent node and a tool node for search.
from langgraph.graph import StateGraph, MessagesState
from langgraph.prebuilt import ToolNode
tools = [web_search]
tool_node = ToolNode(tools)
def agent(state: MessagesState):
# Your LLM call here with tools bound
# Returns messages with potential tool calls
pass
graph = StateGraph(MessagesState)
graph.add_node("agent", agent)
graph.add_node("tools", tool_node)
graph.add_edge("agent", "tools")
graph.add_edge("tools", "agent")
graph.set_entry_point("agent")Step 3: Add research logic
Configure the agent to run multiple searches and synthesize findings.
def research(topic, num_queries=3):
app = graph.compile()
initial = {"messages": [{
"role": "user",
"content": f"Research '{topic}'. Search {num_queries} related queries, then summarize findings with sources."
}]}
result = app.invoke(initial)
return result["messages"][-1].content
findings = research("best vector databases 2026")
print(findings)Step 4: Test the search tool independently
Verify the search tool returns good data before running the full graph.
result = web_search.invoke("best vector databases 2026")
print(result[:500])Python Example
import os, requests
API_KEY = os.environ["SCAVIO_API_KEY"]
def search(query):
resp = requests.post("https://api.scavio.dev/api/v1/search",
headers={"x-api-key": API_KEY},
json={"platform": "google", "query": query})
return resp.json().get("organic_results", [])[:5]
for r in search("best vector databases 2026"):
print(f"{r['title']}: {r.get('snippet','')[:80]}")JavaScript Example
const H = {"x-api-key": process.env.SCAVIO_API_KEY, "Content-Type": "application/json"};
async function search(query) {
const r = await fetch("https://api.scavio.dev/api/v1/search", {
method: "POST", headers: H,
body: JSON.stringify({platform: "google", query})
});
return (await r.json()).organic_results || [];
}
search("best vector databases 2026").then(rs =>
rs.slice(0,5).forEach(r => console.log(r.title))
);Expected Output
A LangGraph agent with a search tool node that queries live SERP data, runs multi-step research, and synthesizes findings with source citations.