How to Do Graph Engineering With Opus 5 (Exact Config Inside)

Graph memory has one killer cost: every episode you ingest runs an extraction call, and naive setups run that at full frontier rates. Opus 5 shipped the exact levers that kill that bill.
Inside: the extraction config that bills at $0.50 instead of $5, the effort split between ingest and query, and the full routing.
Build it right and a temporal graph costs less to feed than a vector store costs to embed.
Here's the full setup 👇
Why graphs and Opus 5 fit together
A knowledge graph gives your agent memory that survives compaction: entities, relationships, and timestamps it can traverse instead of re-reading.
The catch has always been the build cost.
Every conversation and document you feed in runs an extraction pass, and at frontier rates that adds up fast.
Opus 5 changes the math on exactly that step:
The result: the one operation that made graph memory expensive is now the cheapest thing Opus 5 does.
The core split: cheap extraction, careful traversal
Graph engineering has two model-facing jobs, and they want opposite settings. Getting this split right is the whole skill.
Run extraction at max effort and you burn frontier tokens on mechanical work.
Run traversal at low effort and your multi-hop answers get lazy.
The bill and the quality both live in this one decision.
The extraction config (copy this)
Keep the schema and instructions as an identical prefix on every episode so the cache actually hits:
import anthropic
client = anthropic.Anthropic()
# Stable prefix: identical every call = $0.50/M cache reads
EXTRACTION_SYSTEM = """Extract a knowledge graph from the text.
Return JSON only:
{
"entities": [{"name", "type", "description"}],
"edges": [{"source", "target", "relation", "valid_from"}]
}
Rules:
- Canonical names only (resolve "Buzz Aldrin" = "Edwin Aldrin")
- Every edge needs a valid_from date if the text implies one
- Never invent relations not stated in the text
"""
def extract(episode_text, occurred_at):
return client.messages.create(
model="claude-opus-5",
max_tokens=2000,
system=[{
"type": "text",
"text": EXTRACTION_SYSTEM,
"cache_control": {"type": "ephemeral"}, # cache the prefix
}],
messages=[{"role": "user", "content":
f"reference_time: {occurred_at}\n\n{episode_text}"}],
extra_headers={"effort": "low"}, # mechanical work, low effort
)Three details that decide the bill:
The traversal config (the other half)
When the agent answers a real question, flip both settings:
## Graph routing (CLAUDE.md)
Ingestion (writing to the graph):
- Model: Opus 5, effort low
- Always cache the extraction schema prefix
- Batch historical backfills, never run them synchronously
Traversal (querying the graph):
- Model: Opus 5, effort high (max for deep multi-hop)
- Force a retrieval step: pull the relevant subgraph first,
then reason only over those facts
- Every answer cites the specific edges it used
Never:
- Run extraction at high effort (burns tokens on mechanics)
- Run traversal at low effort (lazy multi-hop answers)
- Change effort mid-session (it invalidates your cache)That last rule is a real trap on Opus 5: effort is part of the prompt-cache key.
Flip it mid-conversation and the next turn re-reads your entire context at full uncached price.
Set ingestion and traversal as separate sessions, not one session toggling effort.
Wiring it into Claude Code
Graphiti ships an MCP server, so Claude Code reads and writes the graph with no glue code.
Point extraction at the cheap setting right in the config:
{
"mcpServers": {
"graphiti": {
"command": "uvx",
"args": ["graphiti-mcp"],
"env": {
"NEO4J_URI": "bolt://localhost:7687",
"NEO4J_PASSWORD": "${NEO4J_PASSWORD}",
"MODEL_NAME": "claude-opus-5",
"MODEL_EFFORT": "low"
}
}
}
}Neo4j runs in one Docker container for a dev graph.
Now Claude Code has memory that survives every compaction, every restart, and every new session, and the extraction feeding it bills at cache-read rates.
The bill, worked out
A realistic shape: backfilling 5,000 episodes, each ~800 tokens of text against a ~600-token cached schema prefix.
Naive (full rate, no cache, high effort):
5,000 × 1,400 tokens × $5/M = $35.00 input
plus heavy reasoning output at $25/M
Opus 5 done right (cached prefix, low effort, batched):
schema: 600 tokens × $0.50/M cache read
text: 800 tokens × $2.50/M batch input
= roughly $10.30 input, output minimal at low effortSame graph, built for under a third of the naive cost, and the batch backfill runs while you sleep. Feeding a temporal graph is now cheaper than embedding the same corpus into a vector store.
Common mistakes
The 20-minute setup
The frontier got cheaper and the graph got a cache. Most people will run extraction at max effort and wonder why their memory layer costs more than their model. Split the jobs, cache the schema, batch the backfill, and a temporal graph becomes the cheapest upgrade your agent can get.
Thanks for reading!



