Pattern

How knowledge graphs are used across RossLabs projects

Five projects, one recurring pipeline. Not every stage runs everywhere, and one project skips vectors and graphs entirely.

The short version

Five stages recur across the projects that build a knowledge graph: ingest and chunk source material, embed it into a vector store, retrieve with a hybrid of dense vectors and lexical search then rerank, extract entities and relationships, and use that graph to shape the final retrieval. No project runs all five the same way, and one — Research — skips vectors and graphs entirely for plain lexical search. The graph only earns its cost when relationships between entities are the actual analysis product, not just the source text.

The pipeline in one view

Five stages, one paragraph each — about a two-minute read. The "each stage, for real" section below expands every one of these into the actual mechanism, with real numbers where the project write-ups give them.

1Ingest & chunk

Every pipeline starts by turning source material — Markdown notes, PDFs, decks, spreadsheets, or scraped articles — into units small enough to embed. The Personal LLM Wiki chunks wiki pages and selected tool docs, not the whole vault, and a maintainer script tracks stale, changed, and pending chunks so it only re-processes what changed. Atomize News Search runs parallel BullMQ workers to ingest and normalize thousands of RSS and HTML articles. The Market Research Platform parses PDF, DOCX, PPTX, and Excel through an isolated Node sidecar before chunking and embedding.

See the mechanism →
2Embed

Chunks become vectors, and the embedding model is as much a cost and privacy decision as a technical one. Local embedding keeps material off third-party servers; cloud embedding trades that for scale and, per Atomize News Search's own code comments, roughly 5x lower cost with better accuracy than the model it replaced. The Personal LLM Wiki embeds locally by default with Ollama's nomic-embed-text. Atomize News Search stores 1536-dimensional text-embedding-3-small vectors in pgvector with HNSW indexing. The Market Research Platform embeds locally with sentence-transformers into LanceDB.

See the mechanism →
3Hybrid retrieve + rerank

Pure vector search misses exact matches on names, IDs, and titles; pure keyword search misses paraphrase and context. Every project that goes past basic semantic search blends the two. The Personal LLM Wiki pairs dense vectors with SQLite FTS5/BM25. Atomize News Search runs a weighted blend of 70% vector and 30% keyword, plus cluster boosting when a query maps to a pre-computed trending cluster. The Market Research Platform's write-up describes semantic search only, with no lexical component mentioned.

See the mechanism →
4Entity & relationship extraction

This is where a knowledge graph actually gets built: extraction pulls entities and typed relationships out of retrieved text, and it's also where hallucination risk concentrates — LLMs reverse subject and object, and surface noise from minor mentions. Atomize AI verifies relationship directionality with a dedicated spaCy microservice reading grammatical dependencies, then filters entities through six-signal scoring before anything reaches the canonical graph. Atomize News Search extracts entities and relationships with gpt-5-nano at a low temperature for consistent structured output. The Personal LLM Wiki takes a different route: its graph edges are human-authored frontmatter relationships and wikilinks, not LLM output at all.

See the mechanism →
5Graph-aware retrieval

The payoff stage: retrieval that uses the graph, not just the vector index. The Personal LLM Wiki reranks with Personalized PageRank, boosting pages connected to the best vector hits while keeping vector and lexical relevance as the main signal. Atomize AI's progressive pyramid walks the graph from individual papers to cross-source clusters to emergent trends. Atomize News Search's "Fact-First" RAG extracts a verified timeline from the graph before the LLM is allowed to write a synthesis, closing off a common path to hallucination.

See the mechanism →

Each stage, for real

The paragraphs above are the map. These open into the actual thresholds, models, and numbers per project, drawn from each project's own write-up.

Ingest & chunk. Where each project's chunker actually runs, and what it skips.

The Personal LLM Wiki's source of truth stays in Markdown files with YAML frontmatter; the searchable stores are rebuilt from those files. Chunks come from wiki pages and selected tool/control docs specifically — raw source material and private notes are excluded from what gets chunked and embedded. The maintainer script can refresh only changed chunks and writes a tracker showing stale, changed, and pending material, so a re-index is incremental rather than a full rebuild.

The Market Research Platform ingests PDF, DOCX, PPTX, Excel, and URLs (the latter via a Node parser sidecar). Document parsing — PyMuPDF, docling, python-docx/pptx, openpyxl, and pytesseract OCR — is isolated in that sidecar, separate from the FastAPI backend that runs the LangGraph orchestration and writes chunks into LanceDB. SQLite holds project state alongside the vector store.

Atomize News Search's ingestion engine is a parallel scraper on BullMQ workers, built to ingest and normalize thousands of articles from RSS and HTML sources at once. Atomize AI's own write-up doesn't detail its ingestion mechanics beyond "processes research papers" through its model router — that detail isn't specified in the source.

Embed. Local vs. cloud embedding, and the real numbers behind that choice.

The Personal LLM Wiki's default path is fully local: Ollama's nomic-embed-text embeds chunks into a gitignored .vector/embeddings.json. On Mac and iOS, the companion Obsidian plugin can instead run entirely on-device with transformers.js and a local ONNX nomic-embed-text-v1.5 model, comparing the query embedding against that same embeddings file — no Python process required for query-time embedding on those platforms.

Atomize News Search uses OpenAI's text-embedding-3-small to generate 1536-dimensional vectors for every ingested article and incoming query, stored in PostgreSQL + pgvector. Code comments in the project cite the choice as "5x cheaper" than the prior ada-002 model while offering "better accuracy." HNSW indexing on top of pgvector is credited with a 5-20x speedup on similarity search versus an unindexed scan.

The Market Research Platform embeds locally with sentence-transformers into a LanceDB vector store — no cloud embedding call in the default path. Generation is separate from embedding here: the default model is a local Ollama qwen2.5:14b-instruct, with Anthropic available as an optional cloud model for drafting, not for embedding.

Atomize AI's write-up describes pgvector similarity search connecting related entities across documents for its progressive pyramid, but doesn't name the embedding model itself — not specified in the source.

Hybrid retrieve + rerank. The weights behind the blend, where they're stated.

The Personal LLM Wiki's SQLite sidecar (wiki.db) stores page metadata, chunks, aliases, graph edges, and FTS5 rows in one place. FTS5/BM25 adds exact and keyword strength that dense vectors miss, especially for named entities, page IDs, and title-like queries. The Obsidian plugin exposes this as three modes: Quick (file/alias lookup from the local index), Facet (frontmatter filters like type:entity or status:sprout), and Semantic (?query into the vector layer). On desktop, Semantic mode can shell out to vault_vector.py for the full hybrid-plus-graph stack; on Mac or iOS it can instead run the on-device ONNX model described above.

Atomize News Search's Hybrid Search fetches up to 50–200 candidate articles per query, weighting pgvector (OpenAI embeddings) at 70% for conceptual similarity and PostgreSQL full-text search at 30% for exact matches on proper nouns a pure vector search could miss. An orchestrator query router dynamically switches between vector and keyword search based on detected intent, and if a query maps to an existing pre-computed trending cluster, articles from that cluster get injected into the results before final blended ranking.

The Market Research Platform's write-up describes semantic search across ingested sources via LanceDB, with no BM25 or lexical weighting mentioned — treated here as vector-only unless the project's own documentation says otherwise; that's not confirmed one way or the other in the source. Atomize AI isn't described as running a distinct hybrid-retrieval stage at all — its retrieval-shaping happens later, at the graph and pyramid stage below.

Entity & relationship extraction. 9,556 entities, a 55ms grammar check, and a graph that doesn't get to grow unsupervised.

Atomize AI scores every extracted entity on six signals: mention frequency, source-tier diversity, recency-weighted velocity, relationship density in the graph, citation depth in source articles, and an LLM-rated significance score gated by structural checks. The scoring runs nightly across the corpus. The first full-corpus run scored 9,556 entities; roughly 40% landed below the auto-accept threshold and went to an admin review queue, where they can be promoted, rejected, or merged. Those decisions feed back as labeled data that retrains the threshold weights weekly. Without this gate, the project's own write-up states the graph "drifts toward a soup of every name and concept that ever appeared in any article" — the classification gate makes that drift answerable to evidence instead.

Atomize AI also deployed a spaCy NLP microservice on Railway ($5/month) that analyzes grammatical dependencies — subject-verb-object structure — to verify relationship directionality before it's trusted. It responds in 55ms and is built to solve the "who acquired whom" problem: distinguishing "Google acquired DeepMind" from the reverse. Relationships it verifies receive a 20% confidence boost in the graph. One corpus run produced a graph with 50 entities and 124 typed connections (relationships like owns, integrates, develops, and regulates).

Atomize News Search extracts people, companies, and their relationships with gpt-5-nano, configured at a low temperature (0.1) for consistent, structured JSON output — the goal is edges like "OpenAI owns ChatGPT." Worth flagging rather than resolving: the project's own model breakdown lists gpt-5-nano as the extraction model, but the rationale text next to it still describes gpt-4o-mini's cost/accuracy tradeoff — an inconsistency in the source write-up, not a claim being made here about which model actually runs in production.

The Personal LLM Wiki runs no LLM extraction step for its graph at all. Authored frontmatter relationships and wikilinks are parsed into graph edges directly — a deliberate contrast to the two projects above. There's no hallucination risk on the edges, because nothing infers them; the tradeoff is that the graph only grows where a human actually links two notes.

Graph-aware retrieval. PageRank, a pyramid, and a timeline the model isn't allowed to skip.

The Personal LLM Wiki's search can use Personalized PageRank to boost pages connected to the best vector hits, while preserving vector and lexical relevance as the main signals — not replacing them. Draft or low-confidence pages stay searchable but are downweighted at rerank, not excluded. Personal-only and investment-scoped material is excluded from general professional queries unless the query explicitly asks for that scope; the project's own write-up is explicit that this is a retrieval-quality boundary, not a cryptographic privacy boundary. Worker agents reach all of this through one read-only command, tools/scripts/llmwiki; maintenance operations — ingest, edit, embed, promote, supersede — stay reserved for trusted maintainer sessions.

Atomize AI's knowledge graph feeds a progressive pyramid that layers findings from individual papers (base) through cross-source thematic clusters (middle) to emergent meta-level trends (apex), with pgvector similarity connecting related entities across documents so a user can navigate the hierarchy without losing provenance back to source articles. A LangSmith integration with five evaluators — factuality, coherence, relevance, business impact, and format adherence — scores each synthesis run, and those scores feed back into model-selection and prompt decisions.

Atomize News Search's "Fact-First" RAG extracts concrete Timeline Events from retrieved articles before generation runs. The synthesis model (gpt-5-nano) is then prompted with both the timeline and the supporting articles, instructed to base the insight on the timeline and cite specific entities, and required to output a JSON validation report tracking which articles were used versus ignored and why. The graph and the timeline function as a check on the model here, not just an index into it.

Where each stage lives

Same five stages, one row each, against the four projects that build a graph. A dash means the project's own write-up doesn't describe that stage — not confirmed absent, just not stated.

When a graph isn't built

Every stage above costs something — extra models, extra latency, an ongoing review queue. Two of the five source projects show what it looks like to stop short of a graph on purpose.

Research, the token-efficient research knowledge base, uses none of this. No vector store, no embeddings, no graph. It's built on SQLite FTS5 full-text search, source-tier scoring (four tiers: T1 official docs and peer-reviewed work down to T4 forums and personal blogs), and an optional sympy symbolic-verification pass for math claims. Its own write-up states that FTS5 keeps full-text search on thousands of notes in the low milliseconds — fast enough that the semantic-recall problem a vector store solves never comes up. The four-tier scoring does the trust work a verified relationship graph would otherwise do, just applied to whole sources instead of extracted entities.

The Market Research Platform is a milder version of the same call: its write-up describes semantic search across ingested sources, with no entity or relationship graph at any point. It's built as a workspace a human operates — upload, search, review, decide — rather than an autonomous agent, and the documents never leave the analyst's own hardware. Skipping the graph here isn't about scale; it's that the product is a human making a judgment call with good search under them, not an automated relationship claim.

Read together, the pattern is: build the graph when relationships between entities are the actual analysis product — who owns whom, how two ideas connect, which claim depends on which source. Skip it when the product is trustworthy retrieval of textual claims and fast lexical search already gets there, because a graph nobody reasons over is just extra latency and an extraction pipeline to keep honest.