TypeScript GraphRAG for Markdown corpora. Build a knowledge graph, detect communities, and answer with evidence-backed retrieval.
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:
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.prisma defines the persisted GraphRAG tablessrc/index.ts exposes the main runtime injection and public API# 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.ts
Before running the project, make sure you have:
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);
This repo exposes a compact API surface that matches the implementation:
startBuild(...): starts an async build job and returns a build IDcreateBuildRegistry(): tracks build lifecycle stateGraphRAGRetrievalService: executes hybrid retrieval and evidence-grounded answer generationinjectGraphRAG(...): injects Prisma, model config, and optional defaultsinjectModelConfigs(...): initializes model adapters from config objectsinjectPrismaClient(...): installs the shared Prisma clientRepository 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 notesThe 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 sensitivitymaxChunkSize and chunkOverlapRatio: deterministic chunking fallback# demo build + retrieval
bun run examples/demo.ts
# benchmark recall metrics
bun run demo:benchmark
The 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.
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:
MIT
TypeScript
99.6%
TypeScript GraphRAG for Markdown corpora. Build a knowledge graph, detect communities, and answer with evidence-backed retrieval.
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:
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.prisma defines the persisted GraphRAG tablessrc/index.ts exposes the main runtime injection and public API# 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.ts
Before running the project, make sure you have:
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);
This repo exposes a compact API surface that matches the implementation:
startBuild(...): starts an async build job and returns a build IDcreateBuildRegistry(): tracks build lifecycle stateGraphRAGRetrievalService: executes hybrid retrieval and evidence-grounded answer generationinjectGraphRAG(...): injects Prisma, model config, and optional defaultsinjectModelConfigs(...): initializes model adapters from config objectsinjectPrismaClient(...): installs the shared Prisma clientRepository 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 notesThe 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 sensitivitymaxChunkSize and chunkOverlapRatio: deterministic chunking fallback# demo build + retrieval
bun run examples/demo.ts
# benchmark recall metrics
bun run demo:benchmark
The 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.
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:
MIT
TypeScript
99.6%