Skip to main content

LLM Tool Use

RetriCo includes a tool-calling layer that lets an LLM query the knowledge graph via structured function calls. The LLM receives the graph schema as context, produces structured tool calls, and each call is translated into a parameterized Cypher query.

This powers the tool-based retrieval strategy, but can also be used directly for custom integrations.

Built-in Graph Tools

Seven graph query tools are provided out of the box:

ToolDescription
search_entityFind an entity by label, optionally filtered by entity_type
list_entitiesList entities with filters on entity_type and arbitrary properties
get_entity_relationsGet relations for an entity, filter by relation_type, target_entity_type, min_score, and property filters
get_neighborsK-hop neighbor traversal, filter by entity_type, relation_type, and property filters
get_subgraphRetrieve a subgraph around a set of entities
get_chunks_for_entityGet source text chunks where an entity is mentioned
find_shortest_pathShortest path between two entities, optionally restricted to a relation type

Property Filters

Tools that accept filters support a filters array for arbitrary property conditions:

# "List all organizations in Cambridge founded after 2020"
# The LLM would call list_entities with:
{
"entity_type": "organization",
"filters": [
{"property": "location", "operator": "eq", "value": "Cambridge"},
{"property": "founded_year", "operator": "gte", "value": 2020},
],
"limit": 20,
}

Supported filter operators: eq, neq, gt, gte, lt, lte, contains, starts_with.


Relational (Chunk/Document) Tools

When a relational store (SQLite, PostgreSQL, or Elasticsearch) is configured, three additional tools become available:

ToolDescription
search_chunksFull-text search over stored text chunks
get_chunkRetrieve a single text chunk by its ID
query_recordsStructured query with filtering, sorting, and pagination
# "Get all chunks from document doc_001 sorted by index"
# The LLM would call query_records with:
{
"table": "chunks",
"filters": [
{"field": "document_id", "operator": "eq", "value": "doc_001"},
],
"sort_by": "index",
"sort_order": "asc",
"limit": 50,
}

Using Relational Tools with the Tool Retriever

The tool retriever automatically includes relational tools when a relational store is available. The LLM agent can combine graph queries and chunk searches in a single session:

from retrico import RetriCoSearch

builder = RetriCoSearch(name="tool_with_chunks")
builder.chunk_store(type="sqlite", sqlite_path="chunks.db")
builder.tool_retriever(
api_key="sk-...",
model="gpt-4o-mini",
entity_types=["person", "organization", "location"],
relation_types=["WORKS_AT", "BORN_IN"],
max_tool_rounds=5,
)
builder.reasoner(api_key="sk-...", model="gpt-4o-mini")
executor = builder.build()
ctx = executor.run({"query": "What did Einstein publish about relativity?"})

The agent can call search_entity to find Einstein in the graph, get_entity_relations to find related concepts, and search_chunks to find source passages — all in one agentic loop.


Using complete_with_tools()

For direct programmatic use outside the retrieval pipeline:

from retrico.llm.openai_client import OpenAIClient
from retrico.llm.tools import build_graph_schema_prompt, tool_call_to_cypher, GRAPH_TOOLS

client = OpenAIClient(api_key="sk-...", model="gpt-4o-mini")

# Build a schema prompt so the LLM knows what's in the graph
schema_prompt = build_graph_schema_prompt(
entity_types=["person", "organization", "location"],
relation_types=["WORKS_AT", "BORN_IN", "COLLABORATED_WITH"],
property_keys={"organization": ["founded_year", "location", "revenue"]},
)

# Send user query with graph tools
result = client.complete_with_tools(
messages=[
{"role": "system", "content": schema_prompt},
{"role": "user", "content": "Find companies in Cambridge founded after 2020"},
],
# tools=GRAPH_TOOLS is the default; pass custom tools or GRAPH_TOOLS + custom
)

# Translate each tool call to Cypher and execute
for tc in result["tool_calls"]:
cypher, params = tool_call_to_cypher(tc["name"], tc["arguments"])
print(f"Cypher: {cypher}")
print(f"Params: {params}")
# Execute against your graph store...

Cypher Translation

tool_call_to_cypher() converts each tool call into a parameterized Cypher query:

from retrico.llm.tools import tool_call_to_cypher

# search_entity
cypher, params = tool_call_to_cypher("search_entity", {"label": "Einstein"})
# -> "MATCH (e:Entity) WHERE toLower(e.label) = toLower($label) RETURN e"
# -> {"label": "Einstein"}

# list_entities with property filters
cypher, params = tool_call_to_cypher("list_entities", {
"entity_type": "organization",
"filters": [
{"property": "location", "operator": "eq", "value": "Cambridge"},
{"property": "founded_year", "operator": "gte", "value": 2020},
],
})
# -> "MATCH (e:Entity) WHERE toLower(e.entity_type) = toLower($entity_type)
# AND e.location = $f_0_location AND e.founded_year >= $f_1_founded_year
# RETURN e LIMIT $limit"

# find_shortest_path with relation filter
cypher, params = tool_call_to_cypher("find_shortest_path", {
"source_entity_id": "id-a",
"target_entity_id": "id-b",
"relation_type": "COLLABORATED_WITH",
"max_depth": 3,
})
# -> "MATCH (src:Entity), (tgt:Entity) WHERE src.id = $source_id AND tgt.id = $target_id
# MATCH p = shortestPath((src)-[:`COLLABORATED_WITH`*..3]-(tgt)) RETURN p"

Custom Tools

Add your own tools by defining a tool schema and registering a Cypher translator:

from retrico.llm.tools import GRAPH_TOOLS, register_tool_translator

# Define a custom tool
my_tool = {
"type": "function",
"function": {
"name": "count_by_type",
"description": "Count entities grouped by entity_type.",
"parameters": {
"type": "object",
"properties": {},
"required": [],
},
},
}

# Register a Cypher translator for it
register_tool_translator("count_by_type", lambda args: (
"MATCH (e:Entity) RETURN e.entity_type AS type, count(*) AS count ORDER BY count DESC",
{},
))

# Use combined tools
result = client.complete_with_tools(
messages=[...],
tools=GRAPH_TOOLS + [my_tool],
)

Using Relational Tools Directly

Dispatch relational tool calls manually outside a pipeline:

from retrico.llm.tools import RELATIONAL_TOOLS, execute_relational_tool
from retrico.store.relational.sqlite_store import SqliteRelationalStore

store = SqliteRelationalStore(path="chunks.db")

# Full-text search
results = execute_relational_tool("search_chunks", {"query": "relativity", "top_k": 5}, store)

# Get a specific chunk
results = execute_relational_tool("get_chunk", {"chunk_id": "chunk-001"}, store)

# Structured query with filters
results = execute_relational_tool("query_records", {
"table": "chunks",
"filters": [{"field": "document_id", "operator": "eq", "value": "doc_001"}],
"sort_by": "index",
"limit": 20,
}, store)

Combine graph and relational tool definitions for any LLM:

from retrico.llm.tools import GRAPH_TOOLS, RELATIONAL_TOOLS

all_tools = GRAPH_TOOLS + RELATIONAL_TOOLS
result = client.complete_with_tools(messages=[...], tools=all_tools)