docugraph 0.1.0__tar.gz → 0.2.0__tar.gz
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.
- docugraph-0.2.0/.github/workflows/bench.yml +79 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/.github/workflows/ci.yml +1 -1
- {docugraph-0.1.0 → docugraph-0.2.0}/.github/workflows/docker-publish.yml +11 -3
- {docugraph-0.1.0 → docugraph-0.2.0}/.github/workflows/release.yml +9 -3
- {docugraph-0.1.0 → docugraph-0.2.0}/PKG-INFO +42 -1
- {docugraph-0.1.0 → docugraph-0.2.0}/README.md +37 -0
- docugraph-0.2.0/benchmarks/retrieval/MANIFEST.json +13 -0
- docugraph-0.2.0/benchmarks/retrieval/baselines/bge-small-en-v1.5.json +2669 -0
- docugraph-0.2.0/benchmarks/retrieval/corpus.jsonl +36 -0
- docugraph-0.2.0/benchmarks/retrieval/queries.jsonl +21 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/docs/configuration.md +1 -1
- {docugraph-0.1.0 → docugraph-0.2.0}/pyproject.toml +7 -1
- docugraph-0.2.0/src/docugraph/evals/__init__.py +12 -0
- docugraph-0.2.0/src/docugraph/evals/arms.py +111 -0
- docugraph-0.2.0/src/docugraph/evals/compare.py +106 -0
- docugraph-0.2.0/src/docugraph/evals/dataset.py +210 -0
- docugraph-0.2.0/src/docugraph/evals/metrics.py +123 -0
- docugraph-0.2.0/src/docugraph/evals/runner.py +169 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/src/docugraph/interfaces/cli.py +176 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/src/docugraph/retrieval/hybrid_search.py +7 -3
- {docugraph-0.1.0 → docugraph-0.2.0}/src/docugraph/storage/vector_store.py +122 -21
- docugraph-0.2.0/tests/integration/test_bench_runner.py +126 -0
- docugraph-0.2.0/tests/unit/test_bench_dataset.py +133 -0
- docugraph-0.2.0/tests/unit/test_bench_metrics.py +95 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/tests/unit/test_hybrid_graph_status.py +7 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/uv.lock +3 -3
- {docugraph-0.1.0 → docugraph-0.2.0}/.dockerignore +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/.github/dependabot.yml +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/.github/workflows/live-provider-smoke.yml +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/.github/workflows/live-reranker.yml +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/.gitignore +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/.pre-commit-config.yaml +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/.python-version +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/LICENSE +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/NOTICE +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/claude-integration/README.md +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/claude-integration/hooks/docugraph-auto-index.sh +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/claude-integration/hooks/docugraph-auto-search.sh +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/claude-integration/hooks/docugraph-post-compact.sh +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/claude-integration/hooks/docugraph-pre-compact.sh +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/claude-integration/hooks/docugraph-rule-check.sh +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/claude-integration/hooks/docugraph-session-end.sh +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/claude-integration/hooks/docugraph-session-start.sh +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/claude-integration/install.sh +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/claude-integration/settings.json +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/claude-integration/skills/architecture/SKILL.md +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/claude-integration/skills/context/SKILL.md +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/claude-integration/skills/docs/SKILL.md +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/claude-integration/skills/index/SKILL.md +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/claude-integration/skills/recall/SKILL.md +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/claude-integration/skills/remember/SKILL.md +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/docker/Dockerfile +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/docker/docker-compose.yml +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/docker-compose.yml +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/docs/SECURITY.md +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/docs/quickstart.md +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/examples/crawl_and_search.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/examples/index_local_repo.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/examples/mcp_client_example.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/scripts/live_provider_smoke.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/src/docugraph/__init__.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/src/docugraph/_version.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/src/docugraph/agents/__init__.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/src/docugraph/agents/coding_agent.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/src/docugraph/agents/tools/__init__.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/src/docugraph/agents/tools/graph_query.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/src/docugraph/agents/tools/memory_ops.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/src/docugraph/agents/tools/search_code.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/src/docugraph/agents/tools/search_docs.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/src/docugraph/core/__init__.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/src/docugraph/core/config.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/src/docugraph/core/embeddings.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/src/docugraph/core/llm.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/src/docugraph/core/models.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/src/docugraph/ingestion/__init__.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/src/docugraph/ingestion/api_docs.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/src/docugraph/ingestion/chunker.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/src/docugraph/ingestion/crawler.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/src/docugraph/ingestion/git_indexer.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/src/docugraph/ingestion/local_files.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/src/docugraph/interfaces/__init__.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/src/docugraph/interfaces/mcp_server.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/src/docugraph/retrieval/__init__.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/src/docugraph/retrieval/context_builder.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/src/docugraph/retrieval/reranker.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/src/docugraph/storage/__init__.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/src/docugraph/storage/graph_store.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/src/docugraph/storage/memory_store.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/tests/e2e/__init__.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/tests/e2e/test_cli.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/tests/e2e/test_hooks.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/tests/e2e/test_mcp_server.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/tests/e2e/tools_snapshot.json +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/tests/integration/__init__.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/tests/integration/test_graph_store_init.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/tests/integration/test_memory_store.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/tests/unit/__init__.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/tests/unit/test_chunker.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/tests/unit/test_cloud_provider_sdks.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/tests/unit/test_docs_consistency.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/tests/unit/test_embeddings.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/tests/unit/test_event_loop_acquisition.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/tests/unit/test_graph_embedder_adapter.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/tests/unit/test_graphiti_llm_client.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/tests/unit/test_llm_preflight.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/tests/unit/test_models.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/tests/unit/test_no_model_ids_in_source.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/tests/unit/test_reranker.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/tests/unit/test_vector_store.py +0 -0
- {docugraph-0.1.0 → docugraph-0.2.0}/tests/unit/test_version.py +0 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# The retrieval benchmark, run against the real embedder, weekly and on demand.
|
|
2
|
+
#
|
|
3
|
+
# Fast CI proves the harness with a deterministic fake embedder
|
|
4
|
+
# (tests/integration/test_bench_runner.py) and never downloads weights. What
|
|
5
|
+
# that leaves unexercised is the thing the benchmark exists for: the numbers
|
|
6
|
+
# on the shipped model. This job runs `docugraph bench run` on the real
|
|
7
|
+
# bge-small-en-v1.5 (~130 MB, cached between runs) and holds the result
|
|
8
|
+
# against the committed baseline with `docugraph bench compare`, which exits 1
|
|
9
|
+
# when nDCG@10 -- overall or in any single failure-mode category -- drops by
|
|
10
|
+
# more than the tolerance.
|
|
11
|
+
#
|
|
12
|
+
# The baseline under benchmarks/retrieval/baselines/ is committed, per
|
|
13
|
+
# embedding model, and regenerated deliberately: when the dataset or the
|
|
14
|
+
# retrieval stack changes on purpose, a human reruns the benchmark, reads the
|
|
15
|
+
# delta table, and commits the new baseline with the change that moved it.
|
|
16
|
+
# Until a baseline exists for the model, this job fails -- a comparison
|
|
17
|
+
# against nothing proving nothing would be green that means "checked nothing"
|
|
18
|
+
# (the live-reranker header has the longer form of this argument).
|
|
19
|
+
#
|
|
20
|
+
# Reranking arms are not measured here: the cross-encoder is ~2.3 GB and has
|
|
21
|
+
# its own opt-in workflow; run `docugraph bench run --rerank` locally when a
|
|
22
|
+
# reranker change needs numbers.
|
|
23
|
+
name: Retrieval benchmark
|
|
24
|
+
|
|
25
|
+
on:
|
|
26
|
+
# Manual: Actions -> Retrieval benchmark -> Run workflow.
|
|
27
|
+
workflow_dispatch:
|
|
28
|
+
schedule:
|
|
29
|
+
# Weekly, Monday 06:17 UTC. An off-hour minute, deliberately: scheduled
|
|
30
|
+
# workflows on :00 queue behind everyone else's.
|
|
31
|
+
- cron: "17 6 * * 1"
|
|
32
|
+
|
|
33
|
+
env:
|
|
34
|
+
FASTEMBED_CACHE_PATH: /home/runner/.cache/fastembed
|
|
35
|
+
|
|
36
|
+
jobs:
|
|
37
|
+
bench:
|
|
38
|
+
name: bench run · compare to baseline
|
|
39
|
+
runs-on: ubuntu-latest
|
|
40
|
+
steps:
|
|
41
|
+
- name: Checkout repository
|
|
42
|
+
uses: actions/checkout@v4
|
|
43
|
+
|
|
44
|
+
- name: Set up Python
|
|
45
|
+
uses: actions/setup-python@v5
|
|
46
|
+
with:
|
|
47
|
+
python-version: '3.12'
|
|
48
|
+
|
|
49
|
+
- name: Install uv
|
|
50
|
+
uses: astral-sh/setup-uv@v4
|
|
51
|
+
|
|
52
|
+
- name: Sync dependencies
|
|
53
|
+
run: uv sync --all-extras
|
|
54
|
+
|
|
55
|
+
- name: Cache embedding model
|
|
56
|
+
uses: actions/cache@v4
|
|
57
|
+
with:
|
|
58
|
+
path: /home/runner/.cache/fastembed
|
|
59
|
+
key: fastembed-bge-small-en-v1.5
|
|
60
|
+
|
|
61
|
+
- name: Run benchmark
|
|
62
|
+
run: uv run docugraph bench run --json bench-report.json
|
|
63
|
+
|
|
64
|
+
- name: Compare against committed baseline
|
|
65
|
+
run: |
|
|
66
|
+
baseline="benchmarks/retrieval/baselines/bge-small-en-v1.5.json"
|
|
67
|
+
if [ ! -f "$baseline" ]; then
|
|
68
|
+
echo "::error::No committed baseline at $baseline. Run 'docugraph bench run --json' locally and commit the report as the baseline; a compare against nothing is not a gate."
|
|
69
|
+
exit 1
|
|
70
|
+
fi
|
|
71
|
+
uv run docugraph bench compare "$baseline" bench-report.json
|
|
72
|
+
|
|
73
|
+
- name: Upload report
|
|
74
|
+
if: always()
|
|
75
|
+
uses: actions/upload-artifact@v4
|
|
76
|
+
with:
|
|
77
|
+
name: bench-report
|
|
78
|
+
path: bench-report.json
|
|
79
|
+
if-no-files-found: ignore
|
|
@@ -165,7 +165,7 @@ jobs:
|
|
|
165
165
|
python3 - <<'PY'
|
|
166
166
|
import json, pathlib, sys
|
|
167
167
|
|
|
168
|
-
EXPECTED = "0.1.
|
|
168
|
+
EXPECTED = "0.1.1" # the version this repo publishes; pinned deliberately
|
|
169
169
|
raw = pathlib.Path("/tmp/handshake.jsonl").read_text()
|
|
170
170
|
|
|
171
171
|
# stdout carries the JSON-RPC stream and nothing else. A stray line
|
|
@@ -12,7 +12,6 @@ on:
|
|
|
12
12
|
|
|
13
13
|
env:
|
|
14
14
|
REGISTRY: ghcr.io
|
|
15
|
-
IMAGE_NAME: ${{ github.repository }}
|
|
16
15
|
|
|
17
16
|
jobs:
|
|
18
17
|
build-and-push:
|
|
@@ -25,6 +24,15 @@ jobs:
|
|
|
25
24
|
- name: Checkout repository
|
|
26
25
|
uses: actions/checkout@v4
|
|
27
26
|
|
|
27
|
+
# ghcr.io requires a lowercase repository path, and `github.repository`
|
|
28
|
+
# keeps the owner's case. Expressions have no lowercase function, so it
|
|
29
|
+
# is done in the shell. `docker/metadata-action` lowercases the `images:`
|
|
30
|
+
# input itself, but the tags built by hand below are not, so they all read
|
|
31
|
+
# the same resolved value.
|
|
32
|
+
- name: Resolve image name
|
|
33
|
+
id: image
|
|
34
|
+
run: echo "name=${REGISTRY}/${GITHUB_REPOSITORY,,}" >> "$GITHUB_OUTPUT"
|
|
35
|
+
|
|
28
36
|
# The arm64 half of the multi-platform build runs under emulation on the
|
|
29
37
|
# amd64 runners, which requires QEMU registered with binfmt. Without this
|
|
30
38
|
# step the arm64 build fails.
|
|
@@ -45,7 +53,7 @@ jobs:
|
|
|
45
53
|
id: meta
|
|
46
54
|
uses: docker/metadata-action@v5
|
|
47
55
|
with:
|
|
48
|
-
images: ${{
|
|
56
|
+
images: ${{ steps.image.outputs.name }}
|
|
49
57
|
tags: |
|
|
50
58
|
# The tag as pushed (v1.2.3)
|
|
51
59
|
type=ref,event=tag
|
|
@@ -78,7 +86,7 @@ jobs:
|
|
|
78
86
|
file: ./docker/Dockerfile
|
|
79
87
|
target: development
|
|
80
88
|
push: true
|
|
81
|
-
tags: ${{
|
|
89
|
+
tags: ${{ steps.image.outputs.name }}:dev
|
|
82
90
|
labels: ${{ steps.meta.outputs.labels }}
|
|
83
91
|
cache-from: type=gha
|
|
84
92
|
cache-to: type=gha,mode=max
|
|
@@ -80,12 +80,18 @@ jobs:
|
|
|
80
80
|
|
|
81
81
|
env:
|
|
82
82
|
REGISTRY: ghcr.io
|
|
83
|
-
IMAGE_NAME: ${{ github.repository }}
|
|
84
83
|
|
|
85
84
|
steps:
|
|
86
85
|
- name: Checkout repository
|
|
87
86
|
uses: actions/checkout@v4
|
|
88
87
|
|
|
88
|
+
# ghcr.io requires a lowercase repository path, and `github.repository`
|
|
89
|
+
# keeps the owner's case. Expressions have no lowercase function, so it
|
|
90
|
+
# is done in the shell.
|
|
91
|
+
- name: Resolve image name
|
|
92
|
+
id: image
|
|
93
|
+
run: echo "name=${REGISTRY}/${GITHUB_REPOSITORY,,}" >> "$GITHUB_OUTPUT"
|
|
94
|
+
|
|
89
95
|
# linux/amd64 only. Building arm64 means running it under emulation, which
|
|
90
96
|
# needs a QEMU step registered with binfmt -- the step that used to sit
|
|
91
97
|
# here. It is a post-release item: add both back once an arm64 image has
|
|
@@ -117,8 +123,8 @@ jobs:
|
|
|
117
123
|
target: production
|
|
118
124
|
push: true
|
|
119
125
|
tags: |
|
|
120
|
-
${{
|
|
121
|
-
${{
|
|
126
|
+
${{ steps.image.outputs.name }}:${{ steps.version.outputs.version }}
|
|
127
|
+
${{ steps.image.outputs.name }}:latest
|
|
122
128
|
cache-from: type=gha
|
|
123
129
|
cache-to: type=gha,mode=max
|
|
124
130
|
platforms: linux/amd64
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: docugraph
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Documentation RAG for coding agents: vector search, knowledge graph, agent memory, and an MCP server — torch-free local embeddings via fastembed
|
|
5
|
+
Project-URL: Homepage, https://github.com/CJ-coding-apps/docugraph
|
|
6
|
+
Project-URL: Repository, https://github.com/CJ-coding-apps/docugraph
|
|
7
|
+
Project-URL: Issues, https://github.com/CJ-coding-apps/docugraph/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/CJ-coding-apps/docugraph/releases
|
|
5
9
|
Author-email: Jim Cuttler <jimcuttler@gmail.com>
|
|
6
10
|
License: Apache-2.0
|
|
7
11
|
License-File: LICENSE
|
|
@@ -74,6 +78,7 @@ Code and other MCP clients. The CLI is for out-of-band index bootstrapping
|
|
|
74
78
|
- **Agent memory**: persistent, repository/branch-scoped key-value store
|
|
75
79
|
- **Optional reranking**: local multilingual cross-encoder (BAAI/bge-reranker-v2-m3), opt-in
|
|
76
80
|
- **Torch-free**: default embeddings and reranking run on ONNX — no PyTorch in the dependency tree
|
|
81
|
+
- **Measured retrieval**: a committed adversarial benchmark scores every search mode per failure category, with a regression gate (`docugraph bench`)
|
|
77
82
|
|
|
78
83
|
## Quick start
|
|
79
84
|
|
|
@@ -304,6 +309,42 @@ required**. However, Graphiti performs entity extraction with an **LLM**, so
|
|
|
304
309
|
OpenAI/Anthropic key). Without one, the graph tools degrade gracefully with a
|
|
305
310
|
clear message; vector and keyword search are unaffected.
|
|
306
311
|
|
|
312
|
+
## Retrieval benchmark
|
|
313
|
+
|
|
314
|
+
Retrieval quality is measured, not asserted. `benchmarks/retrieval/` commits a
|
|
315
|
+
hand-authored documentation corpus for a fictional SDK plus graded relevance
|
|
316
|
+
judgments, built adversarially around seven failure modes: exact-token lookups
|
|
317
|
+
(error codes, parameter names), paraphrase queries with no lexical overlap,
|
|
318
|
+
keyword-stuffed distractor pages, near-sibling semantic distractors, version-
|
|
319
|
+
pinned questions, acronym/synonym gaps, and "X without Y" constraint queries.
|
|
320
|
+
Each query records the trap it sets in a `design_note`, and a manifest pins the
|
|
321
|
+
dataset by hash — editing it is a deliberate act that invalidates baselines.
|
|
322
|
+
|
|
323
|
+
```bash
|
|
324
|
+
# Score every arm (vector-only, BM25-only, LanceDB-native hybrid, RRF, weighted)
|
|
325
|
+
# against a temporary store built from the committed corpus:
|
|
326
|
+
docugraph bench run --json report.json
|
|
327
|
+
|
|
328
|
+
# Hold a report against a committed baseline; exits 1 when nDCG@10 drops by
|
|
329
|
+
# more than the tolerance, overall or in any single category:
|
|
330
|
+
docugraph bench compare benchmarks/retrieval/baselines/bge-small-en-v1.5.json report.json
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
Reported metrics are recall@1/5/10, MRR@10, and nDCG@10 (graded, linear gain),
|
|
334
|
+
macro-averaged overall and per category. The per-category table is the point:
|
|
335
|
+
a fusion change that wins on average while losing exact-code lookup shows up
|
|
336
|
+
as the regression it is. Baselines are per embedding model and live in
|
|
337
|
+
`benchmarks/retrieval/baselines/`; the `Retrieval benchmark` workflow re-runs
|
|
338
|
+
the suite weekly against the committed baseline.
|
|
339
|
+
|
|
340
|
+
Honest scope: the corpus is small and purpose-built, so scores are comparable
|
|
341
|
+
across docugraph changes — not with BEIR or any external leaderboard. The
|
|
342
|
+
first thing this benchmark caught predates it: before v0.2.0 no FTS index was
|
|
343
|
+
ever created, so "keyword" search silently returned vector results and
|
|
344
|
+
RRF fused the vector ranking with itself. The benchmark's `fts` arm and the
|
|
345
|
+
hybrid arm's refuse-to-score-on-fallback check exist so that class of silent
|
|
346
|
+
degradation cannot come back unnoticed.
|
|
347
|
+
|
|
307
348
|
### KuzuDB version
|
|
308
349
|
|
|
309
350
|
`kuzu` is pinned to `==0.11.3` in `pyproject.toml` (reached through
|
|
@@ -16,6 +16,7 @@ Code and other MCP clients. The CLI is for out-of-band index bootstrapping
|
|
|
16
16
|
- **Agent memory**: persistent, repository/branch-scoped key-value store
|
|
17
17
|
- **Optional reranking**: local multilingual cross-encoder (BAAI/bge-reranker-v2-m3), opt-in
|
|
18
18
|
- **Torch-free**: default embeddings and reranking run on ONNX — no PyTorch in the dependency tree
|
|
19
|
+
- **Measured retrieval**: a committed adversarial benchmark scores every search mode per failure category, with a regression gate (`docugraph bench`)
|
|
19
20
|
|
|
20
21
|
## Quick start
|
|
21
22
|
|
|
@@ -246,6 +247,42 @@ required**. However, Graphiti performs entity extraction with an **LLM**, so
|
|
|
246
247
|
OpenAI/Anthropic key). Without one, the graph tools degrade gracefully with a
|
|
247
248
|
clear message; vector and keyword search are unaffected.
|
|
248
249
|
|
|
250
|
+
## Retrieval benchmark
|
|
251
|
+
|
|
252
|
+
Retrieval quality is measured, not asserted. `benchmarks/retrieval/` commits a
|
|
253
|
+
hand-authored documentation corpus for a fictional SDK plus graded relevance
|
|
254
|
+
judgments, built adversarially around seven failure modes: exact-token lookups
|
|
255
|
+
(error codes, parameter names), paraphrase queries with no lexical overlap,
|
|
256
|
+
keyword-stuffed distractor pages, near-sibling semantic distractors, version-
|
|
257
|
+
pinned questions, acronym/synonym gaps, and "X without Y" constraint queries.
|
|
258
|
+
Each query records the trap it sets in a `design_note`, and a manifest pins the
|
|
259
|
+
dataset by hash — editing it is a deliberate act that invalidates baselines.
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
# Score every arm (vector-only, BM25-only, LanceDB-native hybrid, RRF, weighted)
|
|
263
|
+
# against a temporary store built from the committed corpus:
|
|
264
|
+
docugraph bench run --json report.json
|
|
265
|
+
|
|
266
|
+
# Hold a report against a committed baseline; exits 1 when nDCG@10 drops by
|
|
267
|
+
# more than the tolerance, overall or in any single category:
|
|
268
|
+
docugraph bench compare benchmarks/retrieval/baselines/bge-small-en-v1.5.json report.json
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Reported metrics are recall@1/5/10, MRR@10, and nDCG@10 (graded, linear gain),
|
|
272
|
+
macro-averaged overall and per category. The per-category table is the point:
|
|
273
|
+
a fusion change that wins on average while losing exact-code lookup shows up
|
|
274
|
+
as the regression it is. Baselines are per embedding model and live in
|
|
275
|
+
`benchmarks/retrieval/baselines/`; the `Retrieval benchmark` workflow re-runs
|
|
276
|
+
the suite weekly against the committed baseline.
|
|
277
|
+
|
|
278
|
+
Honest scope: the corpus is small and purpose-built, so scores are comparable
|
|
279
|
+
across docugraph changes — not with BEIR or any external leaderboard. The
|
|
280
|
+
first thing this benchmark caught predates it: before v0.2.0 no FTS index was
|
|
281
|
+
ever created, so "keyword" search silently returned vector results and
|
|
282
|
+
RRF fused the vector ranking with itself. The benchmark's `fts` arm and the
|
|
283
|
+
hybrid arm's refuse-to-score-on-fallback check exist so that class of silent
|
|
284
|
+
degradation cannot come back unnoticed.
|
|
285
|
+
|
|
249
286
|
### KuzuDB version
|
|
250
287
|
|
|
251
288
|
`kuzu` is pinned to `==0.11.3` in `pyproject.toml` (reached through
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"dataset": "docugraph-retrieval-bench",
|
|
3
|
+
"version": "0.1.0-pilot",
|
|
4
|
+
"description": "Hand-authored adversarial documentation corpus (fictional 'Quorva' SDK) with graded relevance judgments across seven retrieval failure modes. Pilot scale; see the benchmark README section for authoring rules.",
|
|
5
|
+
"counts": {
|
|
6
|
+
"corpus": 36,
|
|
7
|
+
"queries": 21
|
|
8
|
+
},
|
|
9
|
+
"sha256": {
|
|
10
|
+
"corpus.jsonl": "6318b464c188eccd62a4f6eea8c457e7c63780d1d3b7d3e6a0728795955ea5ca",
|
|
11
|
+
"queries.jsonl": "afcc08a10c73d350244fd13c2006a047aa82d18a4be4fbfc2323cb3741979344"
|
|
12
|
+
}
|
|
13
|
+
}
|