Tutorial

How to Add Live Web Search to a LangGraph Agent with Scavio

Add Scavio web search as a LangGraph tool node. Give your agent live search results with structured output, retry logic, and cost tracking per run.

LangGraph agents process multi-step reasoning through a state graph, but they cannot access live web data without a search tool. This tutorial adds Scavio as a LangGraph tool node so your agent can search the web mid-reasoning, incorporate fresh results, and cite sources -- all within the standard LangGraph execution model.

Prerequisites

  • Python 3.11+
  • langgraph >= 0.2.0 and langchain-core installed
  • A Scavio API key from https://scavio.dev
  • An OpenAI or Anthropic API key for the LLM node

Walkthrough

Step 1: Define the Scavio search tool for LangGraph

Create a LangChain-compatible tool that wraps the Scavio Search API. This tool follows the standard BaseTool interface so LangGraph can invoke it in any tool node.

Python
import httpx
from langchain_core.tools import tool
from typing import Optional

SCAVIO_API_KEY = "your-api-key"

@tool
def web_search(query: str, num_results: Optional[int] = 5) -> str:
    """Search the web for current information. Returns titles, URLs, and snippets.
    Use this when you need up-to-date facts, recent news, or live data."""
    with httpx.Client(timeout=15) as client:
        resp = client.post(
            "https://api.scavio.dev/api/v1/search",
            headers={"x-api-key": SCAVIO_API_KEY},
            json={"query": query, "num_results": num_results}
        )
        resp.raise_for_status()
        results = resp.json().get("results", [])

    if not results:
        return "No results found for this query."

    formatted = []
    for i, r in enumerate(results, 1):
        formatted.append(
            f"{i}. {r.get('title', 'No title')}\n"
            f"   URL: {r.get('url', '')}\n"
            f"   {r.get('description', '')[:200]}"
        )
    return "\n\n".join(formatted)

Step 2: Build the LangGraph state graph with a tool node

Create the agent graph with an LLM node and a tool node. The LLM decides when to call the search tool, and the tool node executes the call and returns results to the LLM.

Python
from langgraph.graph import StateGraph, MessagesState, START, END
from langgraph.prebuilt import ToolNode, tools_condition
from langchain_openai import ChatOpenAI

# LLM with tool binding
llm = ChatOpenAI(model="gpt-4o", temperature=0)
tools = [web_search]
llm_with_tools = llm.bind_tools(tools)

# Define the agent node
def agent_node(state: MessagesState):
    response = llm_with_tools.invoke(state["messages"])
    return {"messages": [response]}

# Build the graph
graph = StateGraph(MessagesState)
graph.add_node("agent", agent_node)
graph.add_node("tools", ToolNode(tools))

# Routing: agent -> tools -> agent (loop until done)
graph.add_edge(START, "agent")
graph.add_conditional_edges("agent", tools_condition)
graph.add_edge("tools", "agent")

# Compile
agent = graph.compile()

Step 3: Run the agent with search and track costs

Execute the agent, count how many search calls it makes, and calculate the Scavio API cost. Each search costs $0.005.

Python
from langchain_core.messages import HumanMessage

async def run_with_tracking(question: str) -> dict:
    search_calls = 0
    final_answer = ""

    result = await agent.ainvoke({
        "messages": [HumanMessage(content=question)]
    })

    for msg in result["messages"]:
        if hasattr(msg, "tool_calls") and msg.tool_calls:
            for tc in msg.tool_calls:
                if tc["name"] == "web_search":
                    search_calls += 1
        if hasattr(msg, "content") and msg.content and not hasattr(msg, "tool_calls"):
            final_answer = msg.content

    cost = search_calls * 0.005
    return {
        "answer": final_answer,
        "search_calls": search_calls,
        "cost_usd": cost
    }

# Usage
import asyncio
result = asyncio.run(run_with_tracking(
    "Compare the top 3 LangGraph alternatives in May 2026"
))
print(f"Search calls: {result['search_calls']}")
print(f"Cost: {result['cost_usd']:.3f}")
print(f"Answer: {result['answer'][:300]}...")

Python Example

Python
import asyncio
import httpx
from langchain_core.tools import tool
from langchain_core.messages import HumanMessage
from langgraph.graph import StateGraph, MessagesState, START, END
from langgraph.prebuilt import ToolNode, tools_condition
from langchain_openai import ChatOpenAI

SCAVIO_API_KEY = "your-api-key"

@tool
def web_search(query: str, num_results: int = 5) -> str:
    """Search the web for current information."""
    with httpx.Client(timeout=15) as client:
        resp = client.post(
            "https://api.scavio.dev/api/v1/search",
            headers={"x-api-key": SCAVIO_API_KEY},
            json={"query": query, "num_results": num_results}
        )
        resp.raise_for_status()
        results = resp.json().get("results", [])
    return "\n".join(
        f"{i}. {r['title']} - {r['url']}" for i, r in enumerate(results, 1)
    ) or "No results found."

tools = [web_search]
llm = ChatOpenAI(model="gpt-4o", temperature=0).bind_tools(tools)

def agent_node(state: MessagesState):
    return {"messages": [llm.invoke(state["messages"])]}

graph = StateGraph(MessagesState)
graph.add_node("agent", agent_node)
graph.add_node("tools", ToolNode(tools))
graph.add_edge(START, "agent")
graph.add_conditional_edges("agent", tools_condition)
graph.add_edge("tools", "agent")
agent = graph.compile()

result = asyncio.run(agent.ainvoke({
    "messages": [HumanMessage(content="Top LangGraph alternatives May 2026")]
}))
print(result["messages"][-1].content[:500])

JavaScript Example

JavaScript
// LangGraph.js with Scavio search tool
import { ChatOpenAI } from "@langchain/openai";
import { tool } from "@langchain/core/tools";
import { StateGraph, MessagesAnnotation, START, END } from "@langchain/langgraph";
import { ToolNode } from "@langchain/langgraph/prebuilt";
import { z } from "zod";

const SCAVIO_API_KEY = "your-api-key";

const webSearch = tool(async ({ query }) => {
  const resp = await fetch("https://api.scavio.dev/api/v1/search", {
    method: "POST",
    headers: { "x-api-key": SCAVIO_API_KEY, "Content-Type": "application/json" },
    body: JSON.stringify({ query, num_results: 5 })
  });
  const data = await resp.json();
  return (data.results || []).map((r, i) => `${i + 1}. ${r.title} - ${r.url}`).join("\n") || "No results.";
}, {
  name: "web_search",
  description: "Search the web for current information",
  schema: z.object({ query: z.string() })
});

const tools = [webSearch];
const llm = new ChatOpenAI({ model: "gpt-4o", temperature: 0 }).bindTools(tools);

const agentNode = async (state) => {
  const response = await llm.invoke(state.messages);
  return { messages: [response] };
};

const shouldContinue = (state) => {
  const last = state.messages[state.messages.length - 1];
  return last.tool_calls?.length ? "tools" : END;
};

const graph = new StateGraph(MessagesAnnotation)
  .addNode("agent", agentNode)
  .addNode("tools", new ToolNode(tools))
  .addEdge(START, "agent")
  .addConditionalEdges("agent", shouldContinue)
  .addEdge("tools", "agent")
  .compile();

const result = await graph.invoke({ messages: [{ role: "user", content: "Top LangGraph alternatives May 2026" }] });
console.log(result.messages.at(-1).content.slice(0, 500));

Expected Output

JSON
Search calls: 2
Cost: $0.010
Answer: Based on current web results, the top 3 LangGraph alternatives in May 2026 are...

Related Tutorials

Frequently Asked Questions

Most developers complete this tutorial in 15 to 30 minutes. You will need a Scavio API key (free tier works) and a working Python or JavaScript environment.

Python 3.11+. langgraph >= 0.2.0 and langchain-core installed. A Scavio API key from https://scavio.dev. An OpenAI or Anthropic API key for the LLM node. A Scavio API key gives you 250 free credits per month.

Yes. The free tier includes 250 credits per month, which is more than enough to complete this tutorial and prototype a working solution.

Scavio has a native LangChain package (langchain-scavio), an MCP server, and a plain REST API that works with any HTTP client. This tutorial uses LangChain, but you can adapt to your framework of choice.

Start Building

Add Scavio web search as a LangGraph tool node. Give your agent live search results with structured output, retry logic, and cost tracking per run.