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:
| Tool | Description |
|---|---|
search_entity | Find an entity by label, optionally filtered by entity_type |
list_entities | List entities with filters on entity_type and arbitrary properties |
get_entity_relations | Get relations for an entity, filter by relation_type, target_entity_type, min_score, and property filters |
get_neighbors | K-hop neighbor traversal, filter by entity_type, relation_type, and property filters |
get_subgraph | Retrieve a subgraph around a set of entities |
get_chunks_for_entity | Get source text chunks where an entity is mentioned |
find_shortest_path | Shortest 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:
| Tool | Description |
|---|---|
search_chunks | Full-text search over stored text chunks |
get_chunk | Retrieve a single text chunk by its ID |
query_records | Structured 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)