Agentic RAG LangGraph
What it does
A retriever pulls context for the question. A grader decides whether the results are actually relevant and sufficient. If they are not, it suggests a better query and the loop retrieves again, up to a few times, until the context is good enough or the system concludes the answer is not available. An answerer then responds only from vetted context, so the model stops answering confidently from irrelevant results. Swap the retriever for your own vector store or search server.
The cast · 3 agents
Judge whether the retrieved passages actually answer the question. Return an object with a 'sufficient' boolean, the reasoning, and — if not sufficient — a sharper query to try next. Be strict: loosely related is not sufficient.
Answer the question using only the vetted context. Cite which passage each claim rests on. If the loop ended without sufficient context, say plainly that the answer is not available rather than guessing.
Retrieve context for the question. On the first pass use the question itself; if the grader has suggested a sharper query, use that instead. Return the passages you found.
Flow
Interface
Depends on · 1 MCP server
io.github.brave/brave-search-mcpnot in the registry yetsearch# Generated by @socketcat/compiler for target: langgraph
# blueprint: com.socketcat/agentic-rag v1.0.0 schema: socketcat.dev/blueprint/v0
# This code is yours. Edit it freely. The socketcat_runtime helper is optional and can be vendored.
from typing import TypedDict
from langgraph.graph import StateGraph, START, END
import socketcat_runtime as _rt
class State(TypedDict, total=False):
question: object
answer: object
__loop_0: object
docs: object
grade: object
def node_LoopHeader_0(state):
return {}
def node_LoopTick_1(state):
return {"__loop_0": state.get("__loop_0", 0) + 1}
def node_Nop_2(state):
return {}
def node_AgentInvoke_3(state):
return _rt.run_agent("retriever", state, {"grade":"grade","question":"question"}, "docs")
def node_AgentInvoke_4(state):
return _rt.run_agent("grader", state, {"docs":"docs","question":"question"}, "grade")
def node_AgentInvoke_5(state):
return _rt.run_agent("answerer", state, {"docs":"docs","question":"question"}, "answer")
def route_LoopHeader_0(state):
count = state.get("__loop_0", 0)
return "exit" if (_rt.cond("grade.sufficient == true", state) or count >= 3) else "loop"
def build():
b = StateGraph(State)
b.add_node("LoopHeader_0", node_LoopHeader_0)
b.add_node("LoopTick_1", node_LoopTick_1)
b.add_node("Nop_2", node_Nop_2)
b.add_node("AgentInvoke_3", node_AgentInvoke_3)
b.add_node("AgentInvoke_4", node_AgentInvoke_4)
b.add_node("AgentInvoke_5", node_AgentInvoke_5)
b.add_edge(START, "AgentInvoke_3")
b.add_conditional_edges("LoopHeader_0", route_LoopHeader_0, {"loop": "AgentInvoke_3", "exit": "Nop_2"})
b.add_edge("LoopTick_1", "LoopHeader_0")
b.add_edge("Nop_2", "AgentInvoke_5")
b.add_edge("AgentInvoke_3", "AgentInvoke_4")
b.add_edge("AgentInvoke_4", "LoopTick_1")
b.add_edge("AgentInvoke_5", END)
return b.compile()
INPUTS = ["question"]
OUTPUTS = ["answer"]
if __name__ == "__main__":
_rt.main(build, INPUTS, OUTPUTS)
▸blueprint.json (the portable format)
{
"id": "com.socketcat/agentic-rag",
"flow": {
"type": "sequence",
"blocks": [
{
"max": 3,
"type": "loop",
"until": "grade.sufficient == true",
"blocks": [
{
"in": {
"grade": "grade",
"question": "question"
},
"out": "docs",
"use": "retriever",
"type": "agent"
},
{
"in": {
"docs": "docs",
"question": "question"
},
"out": "grade",
"use": "grader",
"type": "agent"
}
]
},
{
"in": {
"docs": "docs",
"question": "question"
},
"out": "answer",
"use": "answerer",
"type": "agent"
}
]
},
"tags": [
"rag",
"retrieval",
"evaluator-optimizer",
"grading"
],
"title": "Agentic RAG",
"agents": {
"grader": {
"model": {
"hint": "reasoning"
},
"title": "Grader",
"output": {
"type": "object",
"required": [
"sufficient"
],
"properties": {
"newQuery": {
"type": "string"
},
"sufficient": {
"type": "boolean"
}
}
},
"instructions": "Judge whether the retrieved passages actually answer the question. Return an object with a 'sufficient' boolean, the reasoning, and — if not sufficient — a sharper query to try next. Be strict: loosely related is not sufficient."
},
"answerer": {
"model": {
"hint": "reasoning"
},
"title": "Answerer",
"instructions": "Answer the question using only the vetted context. Cite which passage each claim rests on. If the loop ended without sufficient context, say plainly that the answer is not available rather than guessing."
},
"retriever": {
"model": {
"hint": "fast"
},
"title": "Retriever",
"tools": [
"search.web"
],
"instructions": "Retrieve context for the question. On the first pass use the question itself; if the grader has suggested a sharper query, use that instead. Return the passages you found."
}
},
"estate": {
"docs": {
"type": "array",
"description": "The current retrieved context."
},
"grade": {
"type": "object",
"description": "The grader's verdict, including a 'sufficient' flag and a suggested query."
}
},
"$schema": "socketcat.dev/blueprint/v0",
"authors": [
{
"url": "https://socketcat.com",
"name": "SocketCat"
}
],
"license": "MIT",
"servers": [
{
"ref": "io.github.brave/brave-search-mcp",
"alias": "search"
}
],
"summary": "Retrieves context, grades whether it answers the question, rewrites the query and retries when it doesn't, then generates.",
"targets": [
"langgraph",
"*"
],
"version": "1.0.0",
"interface": {
"inputs": {
"question": {
"type": "string",
"description": "The question to answer from retrieved context."
}
},
"outputs": {
"answer": {
"type": "string",
"description": "The answer grounded in vetted context, or an honest 'not found'."
}
}
},
"extensions": {
"dev.langgraph": {
"checkpointer": "memory"
}
},
"description": "A retriever pulls context for the question. A grader decides whether the results are actually relevant and sufficient. If they are not, it suggests a better query and the loop retrieves again, up to a few times, until the context is good enough or the system concludes the answer is not available. An answerer then responds only from vetted context, so the model stops answering confidently from irrelevant results. Swap the retriever for your own vector store or search server."
}More in Core patterns
Browse all →Supervisor Team
A supervisor decides who works next — a researcher who searches or a coder who edits the repo — and assembles the result when the work is done.