@ashes_born/graph-rag-ts
v0.1.7
Published
Reference implementation of a chunked GraphRAG engine: markdown-aware ingestion, Leiden community detection, hybrid vector+keyword retrieval and evidence-grounded answers (Bun + TypeScript).
Downloads
563
Readme
graphrag-ts
TypeScript GraphRAG for Markdown corpora. Build a knowledge graph, detect communities, and answer with evidence-backed retrieval.
Why this project exists
Traditional vector RAG is good at similarity search, but it is limited when you need cross-document structure, entity relationships, and global context. This repository implements a GraphRAG-style pipeline in TypeScript so you can index Markdown content and retrieve answers from a graph-backed knowledge base without a Python runtime or a custom product framework.
The project is designed for practical backend use:
- ingest Markdown files and split them into chunks
- extract entities, edges, and claims
- store graph data in PostgreSQL via Prisma
- detect communities and build community summaries
- support incremental ingestion with SHA-256 diffing and cascade document pruning
- differential community summary updates (0 LLM cost for unchanged communities)
- fuse vector, keyword, and topology-based recall for retrieval
- generate answers from evidence instead of raw model output alone
What it gives you
- a readable GraphRAG reference implementation in TypeScript
- database-backed persistence for entities, claims, edges, and communities
- full and incremental builds (
buildIncrementalRAG/startIncrementalBuild/deleteRAGDocument) - namespace-aware builds for multi-tenant or multi-corpus usage
- hybrid retrieval that combines semantic, keyword, and graph signals
- deterministic fallback behavior when model-based chunking fails
- a small public API that is easy to embed in an application service
Core pipeline
flowchart LR
MD[Markdown files] --> SPLIT[Chunking and slicing]
SPLIT --> GRAPH[Entity + edge + claim graph]
GRAPH --> COMM[Community detection]
COMM --> SUMMARY[Community summaries]
Q[User query] --> INTENT[Intent parsing]
INTENT --> HYBRID[Hybrid recall: vector + keyword + community]
HYBRID --> EVIDENCE[Evidence aggregation]
EVIDENCE --> ANSWER[Grounded answer]The implementation matches this flow in the codebase:
src/build/handles slicing, graph construction, and community detectionsrc/retrieval/handles query parsing, ranking, evidence selection, and answer generationprisma/schema.prismadefines the persisted GraphRAG tablessrc/index.tsexposes the main runtime injection and public API
Quick start
# install dependencies
pnpm install
# generate Prisma client
pnpm run db:generate
# copy environment variables
cp .env.example .env
# apply the schema
pnpm run db:push
# run tests
bun test
# run the demo
bun run examples/demo.tsRequirements
Before running the project, make sure you have:
- pnpm 10+
- Bun 1.1+
- PostgreSQL with pgvector enabled
- a chat model for slicing and judging
- an embedding model compatible with OpenAI-style APIs
Runtime configuration
This repo expects configuration to be provided by the caller. The model loader reads environment variables from src/build/modelLoader.ts.
DATABASE_URL="postgresql://user:pass@localhost:5432/graphrag?schema=public"
RAG_SLICE_API_KEY="your-slice-key"
RAG_SLICE_MODEL="deepseek-chat"
RAG_SLICE_BASE_URL="https://api.deepseek.com/"
RAG_JUDGE_API_KEY="your-judge-key"
RAG_JUDGE_MODEL="deepseek-chat"
RAG_JUDGE_BASE_URL="https://api.deepseek.com/"
RAG_EMBED_API_KEY="your-embedding-key"
RAG_EMBED_MODEL="local-embedding-model"
RAG_EMBED_BASE_URL="http://127.0.0.1:1234/v1"Typical runtime injection pattern:
import { PrismaClient } from '@prisma/client';
import {
injectGraphRAG,
GraphRAGRetrievalService,
startBuild,
createBuildRegistry,
} from '@ashes_born/graph-rag-ts';
await injectGraphRAG({
database: {
client: new PrismaClient({ datasourceUrl: process.env.DATABASE_URL }),
},
models: [
{
type: 'slice',
baseURL: process.env.RAG_SLICE_BASE_URL!,
model: process.env.RAG_SLICE_MODEL!,
apiKey: process.env.RAG_SLICE_API_KEY!,
},
{
type: 'judge',
baseURL: process.env.RAG_JUDGE_BASE_URL!,
model: process.env.RAG_JUDGE_MODEL!,
apiKey: process.env.RAG_JUDGE_API_KEY!,
},
{
type: 'embedding',
baseURL: process.env.RAG_EMBED_BASE_URL!,
model: process.env.RAG_EMBED_MODEL!,
apiKey: process.env.RAG_EMBED_API_KEY!,
},
],
});
const registry = createBuildRegistry();
const buildId = startBuild(
[{ title: 'sample.md', content: 'Alice works with Bob at Acme Corp.' }],
registry,
'demo-namespace',
);
const service = new GraphRAGRetrievalService();
const result = await service.retrieve({
query: 'Who works with Alice?',
topK: 5,
});
console.log(result.answer);Public API
This repo exposes a compact API surface that matches the implementation (available via root package or subpaths like @ashes_born/graph-rag-ts/incremental):
Ingestion & Incremental APIs
startBuild(...)/startIncrementalBuild(...): starts an async full/incremental build job and returns a build IDbuildRAG(...)/buildIncrementalRAG(...): runs full/incremental pipeline and returnsBuildSummarydeleteRAGDocument(...): cascades deletion of a document, its chunks, graph edges, and claimsdiffDocuments(...)/computeCommunityFingerprint(...): incremental comparison and topological fingerprint utilitiescreateBuildRegistry(): tracks build lifecycle stateGraphRAGRetrievalService: executes hybrid retrieval and evidence-grounded answer generationinjectGraphRAG(...): injects Prisma, model config, and optional defaultsregisterChatAdapter(provider, adapter)/registerEmbeddingAdapter(provider, adapter): register custom LangChain models (e.g. Anthropic, Ollama, Google GenAI)
Custom LangChain Model Adapters
You can register any LangChain-compatible model via the adapter layer:
import { registerChatAdapter, registerEmbeddingAdapter } from '@ashes_born/graph-rag-ts';
import { ChatAnthropic } from '@langchain/anthropic';
import { OllamaEmbeddings } from '@langchain/ollama';
// Register custom chat adapter
registerChatAdapter('anthropic', ({ config, isSlice }) => {
return new ChatAnthropic({
anthropicApiKey: config.apiKey,
modelName: config.model,
});
});
// Register custom embedding adapter
registerEmbeddingAdapter('ollama', ({ config }) => {
return new OllamaEmbeddings({
baseUrl: config.baseURL,
model: config.model,
});
});injectModelConfigs(...): initializes model adapters from config objectsinjectPrismaClient(...): installs the shared Prisma client
Repository layout:
src/build/: chunking, graph construction, community detection, registrysrc/retrieval/: query parsing, recall, ranking, evidence selection, answer generationsrc/namespace/: namespace scoping and isolationsrc/config/: default retrieval/build tuning valuesexamples/: demo and benchmark scriptsdocs/: architecture and comparison notes
Tuning and defaults
The project supports global runtime defaults via injectGraphRAG(...), and request-level overrides via the retrieve(...) options object. The production defaults live in src/config/defaults.ts.
await injectGraphRAG({
retrievalDefaults: {
topK: 8,
vectorChildTopK: 12,
keywordSearchLimit: 24,
evidenceChildLimit: 40,
rrfK: 80,
},
buildDefaults: {
maxChunkSize: 800,
chunkOverlapRatio: 0.1,
},
});Example per-request tuning:
const result = await service.retrieve({
query: 'Who is Irene Adler?',
topK: 6,
options: {
vectorChildTopK: 20,
keywordSearchLimit: 30,
evidenceChildLimit: 50,
rrfK: 80,
},
});These knobs control the retrieval window and ranking behavior:
topK: community-level candidate countvectorChildTopK: child chunks returned by vector searchkeywordSearchLimit: keyword-matched child chunksevidenceChildLimit: evidence merge caprrfK: reciprocal rank fusion sensitivitymaxChunkSizeandchunkOverlapRatio: deterministic chunking fallback
Demo and benchmark
# demo build + retrieval
bun run examples/demo.ts
# benchmark recall metrics
bun run demo:benchmarkThe benchmark script evaluates retrieval quality against generated Markdown corpora and reports real metrics for the persisted GraphRAG namespace. It is intended to validate the actual build and retrieval pipeline instead of relying on mocked behavior.
Documentation
- docs/architecture.md: architecture and data flow
- docs/en-US.md: English user guide
- docs/zh-CN.md: Chinese user guide
- docs/comparison.md: comparison notes
- CONTRIBUTING.md: contribution guide
Contributing
Contributions are welcome through issues and pull requests. The project is organized around small, testable modules, so the most useful changes usually fit into one of these areas:
- graph construction quality
- retrieval quality and ranking
- namespace isolation
- model-loading robustness
- documentation and examples
License
MIT
