Los agentes de LangGraph procesan el razonamiento de varios pasos a través de un gráfico de estado, pero no pueden acceder a datos web en vivo sin una herramienta de búsqueda. Este tutorial agrega Scavio como un nodo de herramienta LangGraph para que su agente pueda buscar en la web a mitad de razonamiento, incorporar resultados nuevos y citar fuentes, todo dentro del modelo de ejecución estándar de LangGraph.
Requisitos previos
- Python 3.11+
- langgraph >= 0.2.0 y langchain-core instalado
- Una clave API de Scavio de https://scavio.dev
- Una clave OpenAI o Anthropic API para el nodo LLM
Guia paso a paso
Paso 1: Definir la herramienta de búsqueda Scavio para LangGraph
Cree una herramienta compatible con LangChain que incluya la API de búsqueda de Scavio. Esta herramienta sigue la interfaz estándar de BaseTool para que LangGraph pueda invocarla en cualquier nodo de herramienta.
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)Paso 2: Construya el gráfico de estado de LangGraph con un nodo de herramienta
Cree el gráfico de agente con un nodo LLM y un nodo de herramienta. El LLM decide cuándo llamar a la herramienta de búsqueda y el nodo de la herramienta ejecuta la llamada y devuelve los resultados al LLM.
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()Paso 3: Ejecute el agente con costos de búsqueda y seguimiento
Ejecute el agente, cuente cuántas llamadas de búsqueda realiza y calcule el costo de la API de Scavio. Cada búsqueda cuesta $0,005.
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]}...")Ejemplo en 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])Ejemplo en 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));Salida esperada
Search calls: 2
Cost: $0.010
Answer: Based on current web results, the top 3 LangGraph alternatives in May 2026 are...