How to give your LangGraph agent Google search
A minimal LangGraph agent with a Google search tool: define the tool, bind it to a model, wire a ToolNode loop, and keep the token cost down with Markdown output.
SerpKite team 2 min read
Agents are only as current as the tools you give them. This tutorial wires Google search into a LangGraph agent in about 40 lines: one tool, one model node, one tool node, and a loop between them.
You’ll need Python 3.10+, a SerpKite API key (free, 2,500 credits on signup), and an API key for any chat model LangChain supports with tool calling.
pip install langgraph langchain serpkite
export SERPKITE_API_KEY=skt_live_...
1. The search tool
The tool asks for Markdown, so the model gets a compact, readable results page instead of a large JSON document. Markdown was about 66% smaller than pretty JSON in our measurement.
import os
from langchain_core.tools import tool
from serpkite import SerpKite, SerpKiteError
sk = SerpKite() # reads SERPKITE_API_KEY
@tool
def google_search(query: str, country: str = "us") -> str:
"""Search Google and return the results page as Markdown: organic
results with links, and People Also Ask. Use for anything recent
or anything you are not sure about."""
try:
return sk.search(query, country=country, format="markdown") # str
except SerpKiteError as e:
# e.code / e.message / e.request_id; failed calls are not billed.
return f"Search failed: {e.message}"
The docstring matters: it’s what the model reads when deciding whether to call the tool.
2. The graph
from langchain.chat_models import init_chat_model
from langgraph.graph import START, MessagesState, StateGraph
from langgraph.prebuilt import ToolNode, tools_condition
tools = [google_search]
# Any tool-calling chat model, e.g. "provider:model-name".
model = init_chat_model(os.environ["CHAT_MODEL"]).bind_tools(tools)
def agent(state: MessagesState):
return {"messages": [model.invoke(state["messages"])]}
graph = StateGraph(MessagesState)
graph.add_node("agent", agent)
graph.add_node("tools", ToolNode(tools))
graph.add_edge(START, "agent")
graph.add_conditional_edges("agent", tools_condition) # tool call → "tools", else end
graph.add_edge("tools", "agent")
app = graph.compile()
3. Run it
result = app.invoke({"messages": [("user", "What changed in Google's search results in 2026? Cite sources.")]})
print(result["messages"][-1].content)
The model calls google_search, reads the Markdown, and may search again with a refined query before answering with links from the results.
Keep costs predictable
Each search is 1 credit. Agents can loop, so create a dedicated API key for the agent and give it a monthly credit limit in the dashboard. The key stops at the limit instead of draining your balance.
Useful variations
- News only: call
sk.news(...)(/v1/news) instead ofsk.search(...)for anews_searchtool, withtime="week". - Read the pages: add
include_content=2to fetch the top two results as Markdown in the same call (+1 credit per page). Good for grounding; raise the timeout. - Structured output: use
format="compact"if a downstream node parses results rather than the model. - Local results: a
maps_searchtool onsk.maps(...)withlocationgives the agent businesses, ratings and hours.
Or skip the tool code
pip install langchain-serpkite gives you a ready-made SerpKiteSearch tool (Markdown, token-lean) and a SerpKiteRetriever for RAG; pass them straight to ToolNode. SerpKite also runs a remote MCP server at https://api.serpkite.com/v1/mcp with search, news, maps, scholar and webpage tools. LangGraph can load MCP tools through the MCP adapters, so you don’t write any tool code at all. See LangGraph and MCP for setup, or the Google Search API reference for every parameter.