Skip to main content
Version: latest

Retrieve and answer

Use SearchEngine when your application needs retrieved entities or chunks. Use build_agent when you want the system to search, combine evidence, and return a cited answer. The direct-search example needs no agent LLM; the agent examples do.

Prerequisites​

Install the storage, embedding, and extraction extras. The agent layer needs the agents extra:

pip install 'agentic-graphrag[neo4j,extract]'
# For the agent layer:
pip install 'agentic-graphrag[agents]'

Each code block on this page is complete. It opens a graph with DEFAULT_SCHEMA, adds two sentences, and closes the graph at the end. The agent examples read LLM_BASE_URL, LLM_MODEL_ID, and LLM_API_KEY from the environment or from .env.

Search directly​

SearchEngine searches entity labels that exist in your graph. The example below ingests its data with DEFAULT_SCHEMA, so its labels match. If you ingested with another schema, pass that schema's labels in entity_labels.

import asyncio

from agrag.retrieval.recipes import HYBRID
from agrag.retrieval.search_engine import SearchEngine
from agrag.common.data_models import DEFAULT_SCHEMA
from agrag.embedding import build_embedder
from agrag.graphdb import build_graph_store
from agrag.ingestion import Graph
from agrag.ingestion.extract import GlinerExtractor


async def main() -> None:
graph_store = build_graph_store("neo4j")
embedder = build_embedder("ibm-granite/granite-embedding-small-english-r2")
graph = await Graph.open(
schema=DEFAULT_SCHEMA,
graph_store=graph_store,
embedder=embedder,
extractor=GlinerExtractor(),
)
try:
await graph.add(text="Aspirin treats headaches. Ibuprofen also treats headaches.")
engine = SearchEngine(
graph_store=graph_store,
embedder=embedder,
entity_labels=[entity.label for entity in DEFAULT_SCHEMA.entities],
)

results = await engine.search("What treats headaches?", HYBRID)

for result in results:
print(f"{result.item} (score={result.score:.3f})")
finally:
await graph_store.close()


asyncio.run(main())

An empty result is not an error. Check that the search labels match the schema used for ingestion, then confirm that the graph has indexed the documents. See Troubleshoot common errors for other causes.

Answer with an agent​

import asyncio
import hashlib

from agrag.agents.build import build_agent
from agrag.agents.settings import AgentLLMSettings
from agrag.retrieval.search_engine import SearchEngine
from agrag.common.data_models import DEFAULT_SCHEMA
from agrag.common.data_models.document import Document, DocumentFamily, SourceFormat
from agrag.embedding import build_embedder
from agrag.graphdb import build_graph_store
from agrag.ingestion import Graph
from agrag.ingestion.extract import GlinerExtractor

TEXT = "Aspirin treats headaches. Ibuprofen also treats headaches."
DOCUMENT_KEY = "headache-notes"


async def main() -> None:
graph_store = build_graph_store("neo4j")
embedder = build_embedder("ibm-granite/granite-embedding-small-english-r2")
graph = await Graph.open(
schema=DEFAULT_SCHEMA,
graph_store=graph_store,
embedder=embedder,
extractor=GlinerExtractor(),
)
try:
await graph.add(documents=[Document(
text=TEXT,
title="Headache notes",
uri="notes://headache",
document_key=DOCUMENT_KEY,
source_format=SourceFormat.TXT,
family=DocumentFamily.PROSE,
content_hash=hashlib.sha256(TEXT.encode()).hexdigest(),
loader_name="manual",
char_count=len(TEXT),
)])
agent = build_agent(
graph_store=graph_store,
embedder=embedder,
scope=frozenset({DOCUMENT_KEY}),
project_id="headache-research",
agent_id="research-agent",
llm_settings=AgentLLMSettings.from_openai_compatible_env(),
)

result = await agent.ainvoke({
"task_name": "headache-treatment",
"question": "What treats headaches?",
})

print(result["answer"])
finally:
await graph_store.close()


asyncio.run(main())

The result contains the answer, fetched evidence, citation validation, and task event sequence. The agent stores task state under the supplied project_id, agent_id, and task_name.

The agent uses the supplied document keys as its read scope. It does not search outside that scope.

Set the document scope​

Pass the exact document keys the agent may read as a set of strings. The scope is fixed when the agent is built and applies to discovery, fetch, and citation checks.

import asyncio
import hashlib

from agrag.agents.build import build_agent
from agrag.agents.settings import AgentLLMSettings
from agrag.common.data_models import DEFAULT_SCHEMA
from agrag.common.data_models.document import Document, DocumentFamily, SourceFormat
from agrag.embedding import build_embedder
from agrag.graphdb import build_graph_store
from agrag.ingestion import Graph
from agrag.ingestion.extract import GlinerExtractor

TEXT = "Aspirin treats headaches. Ibuprofen also treats headaches."
DOCUMENT_KEY = "headache-notes"


async def main() -> None:
graph_store = build_graph_store("neo4j")
embedder = build_embedder("ibm-granite/granite-embedding-small-english-r2")
graph = await Graph.open(
schema=DEFAULT_SCHEMA,
graph_store=graph_store,
embedder=embedder,
extractor=GlinerExtractor(),
)
try:
await graph.add(documents=[Document(
text=TEXT,
title="Headache notes",
uri="notes://headache",
document_key=DOCUMENT_KEY,
source_format=SourceFormat.TXT,
family=DocumentFamily.PROSE,
content_hash=hashlib.sha256(TEXT.encode()).hexdigest(),
loader_name="manual",
char_count=len(TEXT),
)])
agent = build_agent(
graph_store=graph_store,
embedder=embedder,
scope=frozenset({DOCUMENT_KEY}),
project_id="headache-research",
agent_id="research-agent",
llm_settings=AgentLLMSettings.from_openai_compatible_env(),
)
finally:
await graph_store.close()


asyncio.run(main())

Set the scope when your application builds the agent. The tools enforce the scope. The model cannot see or change it.

Use the standalone SearchEngine API for recipes and graph retrieval methods. The task-scoped agent uses evidence discovery and fetch operations rather than the legacy retrieval tools described in earlier releases.

Available recipes​

RecipeMethodsBFSReranker
ENTITYentityNoNone
CHUNKchunkNoNone
HYBRIDentity, chunkNoNone
HYBRID_RERANKEDentity, chunkNocross_encoder
GRAPH_EXPANDentityYesNone
THEMATICcommunityNoNone

Configuration​

Set environment variables with the RETRIEVAL_ prefix:

RETRIEVAL_ENTITY_LABELS='["Drug","Condition"]'
RETRIEVAL_ENTITY_TOP_K=10
RETRIEVAL_CHUNK_TOP_K=10
RETRIEVAL_TRAVERSAL_DEPTH=2

RETRIEVAL_ENTITY_LABELS (or the entity_labels argument) names the schema entity labels that entity search runs against. Ingestion creates one native vector index per label, so search needs the labels themselves.