graphwalk 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- graphwalk/__init__.py +46 -0
- graphwalk/agent_docs/SKILL.md +33 -0
- graphwalk/agent_docs/guide.md +188 -0
- graphwalk/cli.py +654 -0
- graphwalk/config.py +344 -0
- graphwalk/core/__init__.py +35 -0
- graphwalk/core/errors.py +55 -0
- graphwalk/core/hashing.py +27 -0
- graphwalk/core/merge.py +152 -0
- graphwalk/core/model.py +196 -0
- graphwalk/core/redact.py +20 -0
- graphwalk/decisions/__init__.py +30 -0
- graphwalk/decisions/base.py +182 -0
- graphwalk/decisions/fake.py +116 -0
- graphwalk/decisions/jev.py +245 -0
- graphwalk/decisions/llm_decider.py +173 -0
- graphwalk/embeddings/__init__.py +6 -0
- graphwalk/embeddings/base.py +28 -0
- graphwalk/embeddings/fake.py +41 -0
- graphwalk/embeddings/fastembed_embedder.py +54 -0
- graphwalk/embeddings/openai_compatible.py +69 -0
- graphwalk/eval/__init__.py +29 -0
- graphwalk/eval/agent.py +502 -0
- graphwalk/eval/calibration.py +73 -0
- graphwalk/eval/datasets/__init__.py +1 -0
- graphwalk/eval/datasets/cache.py +26 -0
- graphwalk/eval/datasets/fanoutqa.py +159 -0
- graphwalk/eval/datasets/hotpotqa.py +100 -0
- graphwalk/eval/datasets/metaqa.py +115 -0
- graphwalk/eval/datasets/rog.py +201 -0
- graphwalk/eval/datasets/twowiki.py +72 -0
- graphwalk/eval/evidence.py +359 -0
- graphwalk/eval/ingest_eval.py +330 -0
- graphwalk/eval/metrics.py +97 -0
- graphwalk/eval/per_question.py +48 -0
- graphwalk/eval/query_writer.py +274 -0
- graphwalk/eval/runner.py +348 -0
- graphwalk/eval/suite.py +295 -0
- graphwalk/eval/systems.py +900 -0
- graphwalk/eval/text_qa.py +347 -0
- graphwalk/eval/types.py +61 -0
- graphwalk/guide.py +17 -0
- graphwalk/index.py +349 -0
- graphwalk/ingest/__init__.py +46 -0
- graphwalk/ingest/cache.py +55 -0
- graphwalk/ingest/chunking.py +135 -0
- graphwalk/ingest/extraction.py +273 -0
- graphwalk/ingest/normalize.py +293 -0
- graphwalk/ingest/pipeline.py +565 -0
- graphwalk/ingest/resolution.py +175 -0
- graphwalk/ingest/routing.py +443 -0
- graphwalk/ingest/sources.py +176 -0
- graphwalk/ingest/spend.py +23 -0
- graphwalk/ingest/triples.py +369 -0
- graphwalk/llm/__init__.py +7 -0
- graphwalk/llm/base.py +39 -0
- graphwalk/llm/fake.py +36 -0
- graphwalk/llm/litellm_backend.py +121 -0
- graphwalk/llm/litellm_import.py +21 -0
- graphwalk/locate/__init__.py +26 -0
- graphwalk/locate/dense.py +122 -0
- graphwalk/locate/documents.py +109 -0
- graphwalk/locate/graph.py +243 -0
- graphwalk/locate/model.py +66 -0
- graphwalk/providers.py +145 -0
- graphwalk/py.typed +0 -0
- graphwalk/server/__init__.py +1 -0
- graphwalk/server/app.py +330 -0
- graphwalk/server/auth.py +230 -0
- graphwalk/server/service.py +547 -0
- graphwalk/server/settings.py +111 -0
- graphwalk/stores/__init__.py +7 -0
- graphwalk/stores/base.py +183 -0
- graphwalk/stores/migrate.py +64 -0
- graphwalk/stores/networkx_store.py +325 -0
- graphwalk/stores/sqlite_store.py +475 -0
- graphwalk/traversal/__init__.py +39 -0
- graphwalk/traversal/batching.py +58 -0
- graphwalk/traversal/config.py +135 -0
- graphwalk/traversal/engine.py +729 -0
- graphwalk/traversal/entry.py +309 -0
- graphwalk/traversal/escalation.py +59 -0
- graphwalk/traversal/prefilter.py +65 -0
- graphwalk/traversal/prompts.py +206 -0
- graphwalk/traversal/sampling.py +50 -0
- graphwalk/traversal/scoring.py +21 -0
- graphwalk/traversal/trace.py +187 -0
- graphwalk-0.1.0.dist-info/METADATA +151 -0
- graphwalk-0.1.0.dist-info/RECORD +92 -0
- graphwalk-0.1.0.dist-info/WHEEL +4 -0
- graphwalk-0.1.0.dist-info/entry_points.txt +3 -0
- graphwalk-0.1.0.dist-info/licenses/LICENSE +177 -0
graphwalk/__init__.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""graphwalk: fast, probabilistic question answering over knowledge graphs.
|
|
2
|
+
|
|
3
|
+
When to use it and how: ``graphwalk.guide()`` (or ``graphwalk guide`` on the command
|
|
4
|
+
line). The public API is what this module exports. Everything else (``graphwalk.traversal``,
|
|
5
|
+
``graphwalk.ingest``, ...) is internal and may change between minor versions.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from importlib.metadata import version
|
|
9
|
+
|
|
10
|
+
from graphwalk.core.errors import DocumentNotFoundError, GraphwalkError, StaleLocationError
|
|
11
|
+
from graphwalk.core.model import Edge, Neighbor, Node, Provenance
|
|
12
|
+
from graphwalk.guide import guide
|
|
13
|
+
from graphwalk.index import Index, WalkResult
|
|
14
|
+
from graphwalk.ingest.pipeline import IngestConfig, IngestReport
|
|
15
|
+
from graphwalk.ingest.sources import FileSource, SourceDocument, TextSource
|
|
16
|
+
from graphwalk.ingest.triples import ImportReport
|
|
17
|
+
from graphwalk.locate.documents import FileDocuments, StoredDocuments
|
|
18
|
+
from graphwalk.locate.model import Location, Passage
|
|
19
|
+
from graphwalk.traversal.config import TraversalConfig
|
|
20
|
+
|
|
21
|
+
__version__ = version("graphwalk")
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
"DocumentNotFoundError",
|
|
25
|
+
"Edge",
|
|
26
|
+
"FileDocuments",
|
|
27
|
+
"FileSource",
|
|
28
|
+
"GraphwalkError",
|
|
29
|
+
"ImportReport",
|
|
30
|
+
"Index",
|
|
31
|
+
"IngestConfig",
|
|
32
|
+
"IngestReport",
|
|
33
|
+
"Location",
|
|
34
|
+
"Neighbor",
|
|
35
|
+
"Node",
|
|
36
|
+
"Passage",
|
|
37
|
+
"Provenance",
|
|
38
|
+
"SourceDocument",
|
|
39
|
+
"StaleLocationError",
|
|
40
|
+
"StoredDocuments",
|
|
41
|
+
"TextSource",
|
|
42
|
+
"TraversalConfig",
|
|
43
|
+
"WalkResult",
|
|
44
|
+
"__version__",
|
|
45
|
+
"guide",
|
|
46
|
+
]
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: graphwalk
|
|
3
|
+
description: Answer questions over an existing knowledge graph (triples, RDF, CSV/JSONL edge lists) by walking it hop by hop with a fast classifier, getting entity answers with a confidence and the path taken; escalate low-confidence queries to an LLM. Use when a user has a knowledge graph and wants cheap, fast multi-hop lookups with a per-answer confidence, and can accept lower accuracy than an LLM writing the query. Not for best-accuracy KG-QA (have an LLM write the query from the relations near the entity), QA over documents (use RAG), or constrained/superlative questions.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# graphwalk
|
|
7
|
+
|
|
8
|
+
Run `graphwalk guide` (or `python -c "import graphwalk; print(graphwalk.guide())"`)
|
|
9
|
+
for the full guide: when to use it, the measured trade-offs, recipes, and API.
|
|
10
|
+
|
|
11
|
+
Short version:
|
|
12
|
+
|
|
13
|
+
1. Check fit first. graphwalk answers from the graph's nodes. It is 6× cheaper and
|
|
14
|
+
~4× faster than an LLM writing the query, and gives an informative confidence, but
|
|
15
|
+
is ~15 F1 points less accurate on curated graphs of any schema size. It loses to
|
|
16
|
+
multi-step RAG on documents. It does no filtering, ranking, or set intersection.
|
|
17
|
+
2. Import: `graphwalk import kg.nt --graph kg.db` (also `.csv`, `.tsv`, `.jsonl`). No
|
|
18
|
+
key is needed. Give nodes readable names and types.
|
|
19
|
+
3. Query from Python:
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
from graphwalk import Index
|
|
23
|
+
|
|
24
|
+
# walks with TraversalConfig.kgqa() by default
|
|
25
|
+
async with Index.open("kg.db", node_types=[...], escalate_below=0.9) as index:
|
|
26
|
+
result = await index.walk(question)
|
|
27
|
+
result.best.names, result.best.path, result.confidence, result.escalated
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
4. Treat `result.confidence` as a ranking signal. Validate the threshold on 50–100
|
|
31
|
+
labeled questions from the user's own graph before trusting it.
|
|
32
|
+
5. Keys: `OPENROUTER_API_KEY` (Jev decisions; the LLM for escalation). Without Jev,
|
|
33
|
+
use `GRAPHWALK_DECISION_FALLBACK=llm`; its confidence is not calibrated.
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# graphwalk: guide for coding agents
|
|
2
|
+
|
|
3
|
+
graphwalk answers questions over a knowledge graph by walking it. Each hop is a
|
|
4
|
+
classification decision: the current node's relations (plus STOP) are the options, and
|
|
5
|
+
a fast decision model (Jev) returns a probability for each. A walk's answer comes with a
|
|
6
|
+
confidence, so unsure walks can be re-run ("escalated") with a slower LLM decider.
|
|
7
|
+
|
|
8
|
+
This guide says when graphwalk is the right tool, when it is not, and how to use it.
|
|
9
|
+
Every claim below comes from a measured experiment. The `docs/results-*.md` files in the
|
|
10
|
+
repository hold the tables, CIs, and caveats. Samples are small (50–300 questions per
|
|
11
|
+
setting, mostly one seed), so treat the numbers as directions, not guarantees.
|
|
12
|
+
|
|
13
|
+
## Decide first: is graphwalk the right tool?
|
|
14
|
+
|
|
15
|
+
| Your situation | Use | Evidence |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| An **agent** that already explores a knowledge graph with low-level tools (`neighbors`, a relation list) | **Also give it `walk`** (the MCP server does). The agent calls `walk` first, then checks or continues with `neighbors`. | A8b: a strong agent with `walk` cost 25% less (95% CI 7–45%) at equal F1 (0.75 vs 0.71, n=30, WebQSP); with a cheap agent, F1 was equal and the cost a wash. Text search over the same facts tied on F1 |
|
|
18
|
+
| A knowledge graph you already have (triples, RDF), **any schema size**, and you want the best accuracy | **Have an LLM write the query** from the relations around the question's entity (fetch them with one adjacency query; for a whole large schema, it fits a 1M-token context too). | A6: Freebase, 5,419 relations in one graph: 0.66 vs 0.49 F1 for walking |
|
|
19
|
+
| The same, but **cost or latency matters more than ~15 F1 points**, or you need a **per-answer confidence** | **graphwalk `walk`**: 6× cheaper and ~4× faster than the LLM path writer, with a confidence that ranks its answers | A6; A2 (AUROC 0.92 on WebQSP) |
|
|
20
|
+
| A **noisy graph extracted from text** (inconsistent relation names, edges in either direction) | graphwalk `walk` beats LLM-written paths, but every method is weak here; prefer RAG over the source text | E2b: 3–5× the F1 of LLM-written paths at 1/20–1/35 the cost, absolute F1 0.18–0.25 |
|
|
21
|
+
| A graph with a **small, clean schema** (≲ 50 self-describing relations) | **Have an LLM write the query** (a relation path, Cypher, SPARQL). It is more accurate, and here also cheaper than walking with escalation. | E2: MetaQA 3-hop 0.955 vs 0.887 F1; A2: WebQSP 0.76 vs 0.54 F1 |
|
|
22
|
+
| You want a **cheap first pass that knows when it's wrong**, and to pay for a strong model only on hard queries | **`walk` with `escalate_below`**, but expect modest savings: escalating to an LLM-written path matched its accuracy for ~19% less on Freebase (A6, offline), and on MetaQA the path writer alone is cheaper | A1, A6 |
|
|
23
|
+
| **Compositional questions with constraints** ("the earliest...", "which X that also Y", superlatives, comparisons) | **Not graphwalk.** It follows one relation path from the topic entity and does no filtering, ranking, or intersection. Use a dedicated KG-QA method or LLM-written queries with filters. | A2: CWQ hits@1 ≈ 0.28 for every system tried, vs ≈ 0.63–0.69 published |
|
|
24
|
+
| **Questions over documents** (no curated graph) | **Multi-step RAG**, not graphwalk. Building a graph from text loses dates, order, and qualifiers. | M7, E4: RAG wins by 10–19 F1 points |
|
|
25
|
+
| Retrieval over documents where questions **chain through named entities** ("the director of the film X...") | graphwalk `locate(mode="hybrid")` as the retriever, then read the text | E1: +18 points recall over dense on 2Wiki; ties on HotpotQA; −5 on FanOutQA |
|
|
26
|
+
| Broad or list-style questions over documents | Plain dense retrieval | E1 |
|
|
27
|
+
| As an add-on to an existing multi-step RAG loop | Don't, unless your reader model is expensive. It cuts LLM rounds by 16–21% but not error, and its own calls cost more than the rounds saved at cheap-reader prices. | E7 |
|
|
28
|
+
|
|
29
|
+
Rules of thumb:
|
|
30
|
+
|
|
31
|
+
- **The graph must hold the answer.** graphwalk's answers are nodes. If facts live in
|
|
32
|
+
free text, attributes, or qualifiers the graph lacks, no walk finds them.
|
|
33
|
+
- **Jev buys cost, speed, and confidence, not accuracy.** An LLM deciding each hop is
|
|
34
|
+
as accurate or better (+0.06 F1 at 3 hops). Jev is 3–4× cheaper, 7–10× faster per
|
|
35
|
+
decision, and its confidence separates right from wrong answers (AUROC 0.92–0.97 on
|
|
36
|
+
MetaQA 2–3 hop and WebQSP; weaker, 0.64–0.71, on MetaQA 1-hop, 2Wiki, and CWQ). The
|
|
37
|
+
LLM decider's confidence barely does (0.50–0.69).
|
|
38
|
+
- **Walking is fast; the model calls dominate.** graphwalk adds ~10 ms per walk on
|
|
39
|
+
typical nodes and ~0.1–0.5 s at nodes with 20k neighbors (SQLite, 1.4M edges).
|
|
40
|
+
|
|
41
|
+
## Install and keys
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install 'graphwalk[embeddings]' # or, from a clone: uv sync --extra embeddings
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Extras: `embeddings` (local fastembed embedder: prefilter and dense `locate`), `llm`
|
|
48
|
+
(LiteLLM: text ingestion, the LLM decider, escalation), `mcp` (the MCP server), `eval`.
|
|
49
|
+
|
|
50
|
+
Keys come from the environment:
|
|
51
|
+
|
|
52
|
+
- Decisions (Jev): `OPENROUTER_API_KEY` (model `typesafe/jev-1.13`) or `TYPESAFE_API_KEY`
|
|
53
|
+
with `GRAPHWALK_DECISION_PROVIDER=typesafe`.
|
|
54
|
+
- LLM (escalation, ingestion): `OPENROUTER_API_KEY`, or `OPENAI_API_KEY` /
|
|
55
|
+
`ANTHROPIC_API_KEY` / `XAI_API_KEY` with `GRAPHWALK_LLM_PROVIDER`.
|
|
56
|
+
- No Jev access: `GRAPHWALK_DECISION_FALLBACK=llm` makes the chat model decide. It works,
|
|
57
|
+
but it is slower and its confidence is not calibrated, so escalation thresholds mean
|
|
58
|
+
little with it.
|
|
59
|
+
|
|
60
|
+
Importing triples needs no key at all.
|
|
61
|
+
|
|
62
|
+
## Recipe 1: question answering over an existing knowledge graph
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
graphwalk import kg.nt --graph kg.db # .nt, .csv, .tsv, .jsonl, or a|b|c .txt
|
|
66
|
+
graphwalk query kg.db "Where was the director of Inception born?" --escalate-below 0.9
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
(`query` walks with `TraversalConfig.kgqa()` by default; flags such as `--hop-mode` or
|
|
70
|
+
`--strategy` override single settings.)
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
import asyncio
|
|
74
|
+
from graphwalk import Index, TraversalConfig
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
async def main() -> None:
|
|
78
|
+
async with Index.open(
|
|
79
|
+
"kg.db",
|
|
80
|
+
traversal=TraversalConfig.kgqa(), # the default; shown for clarity
|
|
81
|
+
node_types=["person", "film", "place"], # your graph's types, for the type hint
|
|
82
|
+
escalate_below=0.9,
|
|
83
|
+
) as index:
|
|
84
|
+
await index.import_triples("kg.nt") # once; idempotent
|
|
85
|
+
result = await index.walk("Where was the director of Inception born?")
|
|
86
|
+
if result.best is None:
|
|
87
|
+
print("no answer") # entities not linked, or nothing reached
|
|
88
|
+
else:
|
|
89
|
+
print(result.best.names, result.confidence, result.escalated, result.cost_usd)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
asyncio.run(main())
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
- `TraversalConfig.kgqa()` is the configuration measured in the experiments (greedy
|
|
96
|
+
relation hops, typed options, answer-type hint, depth ≤ 4), and what `Index`, the CLI,
|
|
97
|
+
and the MCP server walk with unless given another. A bare `TraversalConfig()` (beam
|
|
98
|
+
search over individual neighbors) is a low-level default for `Traverser`, not a
|
|
99
|
+
measured setting.
|
|
100
|
+
- `result.best.names` is a **set** of entities (a relation hop moves to all its
|
|
101
|
+
targets). `result.best.path` is the list of hops taken; show it to users as the
|
|
102
|
+
justification.
|
|
103
|
+
- `result.confidence` is `exp(score)`, the length-normalized path probability. Treat it
|
|
104
|
+
as a ranking signal. 0.9 was the best default threshold on MetaQA; on a graph with a
|
|
105
|
+
different shape, check it on 50–100 labeled questions before relying on it.
|
|
106
|
+
- `escalate_below` re-walks unsure queries with the LLM decider (needs the `llm` extra
|
|
107
|
+
and an LLM key), or with `fallback_decider=` if you pass one. `result.cost_usd`
|
|
108
|
+
includes both walks.
|
|
109
|
+
- Start entities are found by matching names in the question. If you already know them
|
|
110
|
+
(from your own entity linker or the user's selection), call the CLI with
|
|
111
|
+
`--start <node id>` (repeatable).
|
|
112
|
+
|
|
113
|
+
Triples formats: CSV/TSV with a header (`subject,relation,object`, aliases
|
|
114
|
+
`head/source/s`, `predicate/type/p`, `tail/target/o`, plus optional `subject_type`,
|
|
115
|
+
`object_type`, `subject_name`, `object_name`); JSONL with the same keys; N-Triples
|
|
116
|
+
(`rdfs:label` becomes the name, `rdf:type` the type, literals become `literal` nodes).
|
|
117
|
+
Give nodes readable names and types: decisions are made from names, relation names,
|
|
118
|
+
and types, not from opaque ids.
|
|
119
|
+
|
|
120
|
+
## Recipe 2: locate passages in documents (experimental)
|
|
121
|
+
|
|
122
|
+
Only when your questions chain through named entities (see the table). Otherwise use
|
|
123
|
+
dense retrieval or multi-step RAG.
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
from graphwalk import Index
|
|
127
|
+
|
|
128
|
+
async with Index.open("docs.db") as index: # inside async code; needs [llm,embeddings]
|
|
129
|
+
await index.ingest("docs/") # LLM extraction; costs money; idempotent
|
|
130
|
+
for location in await index.locate("Who directed ...?", k=5, mode="hybrid"):
|
|
131
|
+
passage = await index.read(location, context=200)
|
|
132
|
+
print(location.path, passage.text) # answer from the text, not the graph
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Recipe 3: give an agent the graph (MCP)
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
pip install 'graphwalk[mcp,llm]'
|
|
139
|
+
graphwalk mcp --db kg.db # stdio; keys from the environment
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Tools: `walk` (answers with confidence and path), `locate` and `read` (documents),
|
|
143
|
+
`neighbors` and `get_node` (explore), `status`, `ingest` and `ingest_status`. The server
|
|
144
|
+
also serves this guide as the resource `graphwalk://guide`.
|
|
145
|
+
|
|
146
|
+
Set `GRAPHWALK_ESCALATE_BELOW=0.9` (after checking it on your graph) to escalate unsure
|
|
147
|
+
walks. The server's instructions then state the threshold, and every `walk` result
|
|
148
|
+
reports the threshold it used, so the agent knows which answers cleared it. Escalated
|
|
149
|
+
answers carry the LLM decider's confidence, which is not calibrated, so the agent
|
|
150
|
+
should verify them with `neighbors`.
|
|
151
|
+
|
|
152
|
+
## API surface
|
|
153
|
+
|
|
154
|
+
Public names are those exported from `graphwalk` (anything else may change):
|
|
155
|
+
`Index`, `WalkResult`, `TraversalConfig`, `ImportReport`, `IngestConfig`,
|
|
156
|
+
`IngestReport`, `Location`, `Passage`, `Node`, `Edge`, `Neighbor`, `Provenance`,
|
|
157
|
+
`FileSource`, `TextSource`, `SourceDocument`, `FileDocuments`, `StoredDocuments`,
|
|
158
|
+
`GraphwalkError`, `DocumentNotFoundError`, `StaleLocationError`, `guide`.
|
|
159
|
+
|
|
160
|
+
`Index` methods: `open(path, **kwargs)`, `import_triples(path)`, `walk(query)`,
|
|
161
|
+
`ingest(source)`, `locate(query, k, mode=)`, `read(location, context=)`,
|
|
162
|
+
`neighbors(node)`, `close()`. All I/O methods are async.
|
|
163
|
+
|
|
164
|
+
CLI: `graphwalk import`, `query`, `ingest`, `locate`, `migrate`, `mcp`, `guide`.
|
|
165
|
+
|
|
166
|
+
## Performance
|
|
167
|
+
|
|
168
|
+
- Per query: one Jev call per hop (~0.3–0.5 s each) plus graphwalk's overhead.
|
|
169
|
+
MetaQA walks cost $0.05–0.15 per 1,000 queries; Freebase subgraph walks ≈ $0.2.
|
|
170
|
+
- SQLite: imports ~9k triples/s; a 1.4M-edge graph is ~1.1 GB on disk. Listing a
|
|
171
|
+
node's edges takes <0.1 ms (56 ms at a 20k-neighbor hub).
|
|
172
|
+
- Walk overhead, excluding model calls: ~8 ms on typical nodes; 0.1 s (relation hops)
|
|
173
|
+
to 0.2 s (entity hops) from a 20k-neighbor hub. With an embedder, the first visit to a
|
|
174
|
+
hub embeds its neighbors' names (seconds with a local CPU model; cached after), so
|
|
175
|
+
prefer relation hops (`TraversalConfig.kgqa()`) on graphs with big hubs.
|
|
176
|
+
|
|
177
|
+
## Common mistakes
|
|
178
|
+
|
|
179
|
+
- Using graphwalk to answer questions over documents. Use RAG; use `locate` only as a
|
|
180
|
+
retriever.
|
|
181
|
+
- Expecting constraint handling ("first", "largest", "both A and B"). graphwalk doesn't
|
|
182
|
+
filter, rank, or intersect answer sets; do that in your own code, or pick another tool.
|
|
183
|
+
- Comparing confidence across deciders. Only Jev's confidence was found informative.
|
|
184
|
+
- Passing a bare `TraversalConfig()` to `Index` or `Traverser` for KG-QA. Use
|
|
185
|
+
`TraversalConfig.kgqa()` (the `Index` default) and override single fields.
|
|
186
|
+
- Assuming the escalation threshold transfers. Check it on your own graph.
|
|
187
|
+
- Opaque node ids as names (`Q42`, `m.0abc`). Import names (`rdfs:label` or the name
|
|
188
|
+
columns) so the decider can read the options.
|