Skip to content

Configuration

Roles and providers

graphwalk uses models in three roles:

Role Providers Default
Decision (each hop, entity routing) Jev via OpenRouter or TypeSafe; any model with token probabilities at an OpenAI-compatible endpoint; a chat model's stated scores; or your own (deciders) Jev via OpenRouter, typesafe/jev-1.13
LLM (escalation, text extraction) OpenRouter, OpenAI, Anthropic, x.ai OpenRouter, openai/gpt-6-luna
Embedding (type prefilter, dense locate) fastembed (local), OpenAI, OpenRouter fastembed, BAAI/bge-small-en-v1.5

Keys and base URLs use the conventional variables (OPENROUTER_API_KEY, OPENAI_API_KEY, ANTHROPIC_API_KEY, XAI_API_KEY, TYPESAFE_API_KEY, each with a *_BASE_URL). Everything else is GRAPHWALK_*; the full list is in .env.example.

Precedence, highest first: explicit arguments, request headers (remote MCP sessions), the environment, defaults. Keys are held as secrets and never appear in logs, traces, or error messages.

from graphwalk import Index
from graphwalk.config import resolve_config

config = resolve_config({"llm_provider": "anthropic", "escalate_below": 0.9})
index = Index.open("kg.db", config=config)

Choosing the decider

GRAPHWALK_DECIDER is jev (default), logprob, or llm; see deciders for what each measured and how to bring your own.

Variable Meaning
GRAPHWALK_DECIDER jev, logprob (token probabilities), or llm (stated scores)
GRAPHWALK_DECIDER_MODEL logprob: model id at the endpoint (default qwen/qwen3.8-27b on OpenRouter)
GRAPHWALK_DECIDER_BASE_URL logprob: OpenAI-compatible API root with /v1 (default OpenRouter)
GRAPHWALK_DECIDER_API_KEY logprob at your own endpoint, if it needs one
GRAPHWALK_DECIDER_MAX_RPM logprob: request rate limit
GRAPHWALK_DECISION_FALLBACK With jev and no Jev key: logprob or llm decides instead (default off)
GRAPHWALK_ESCALATION_DECIDER What escalated walks use: llm (default) or logprob

The llm decider makes the chat model score each option; the scores become the distribution. It is as accurate as Jev or better (+0.06 F1 at 3 hops on MetaQA), but 3–4× more expensive, 7–10× slower per decision, and its confidence is barely informative (AUROC 0.50–0.69): stated scores are not probabilities. Prefer logprob. Traces mark every decider by its model id (logprob:, llm-decider:).

On a remote MCP server, GRAPHWALK_DECIDER_BASE_URL sent as a header is honored only if it matches GRAPHWALK_ALLOWED_BASE_URLS, and GRAPHWALK_DECIDER_API_KEY is a secret like the provider keys.

Escalation

escalate_below (or GRAPHWALK_ESCALATE_BELOW, or --escalate-below) re-walks a query whose confidence is below the threshold with the escalation decider (GRAPHWALK_ESCALATION_DECIDER: the chat model's stated scores by default, or logprob), or with fallback_decider= if you pass one to Index. result.escalated says which walks were redone, and result.cost_usd includes both.

Traversal settings

Index, the CLI, and the MCP server walk with TraversalConfig.kgqa(): greedy relation hops, typed options, an answer-type hint, at most 4 decisions. That is the configuration measured in the experiments. Override single fields with TraversalConfig.kgqa(max_depth=3, ...) or the CLI flags (--strategy, --hop-mode, --max-depth, ...). A bare TraversalConfig() is a low-level default, not a measured setting.

Storage

A .db path is SQLite (one transactional file: nodes, edges, provenance, ingestion ledger, and document text; write-ahead logging, so it can be read while it is written). Any other path is NetworkX JSON, meant for tests and small graphs; graphwalk migrate graph.json graph.db converts it. A 1.4M-edge graph is about 1.1 GB of SQLite, and listing a node's edges takes under 0.1 ms.