Knowledge Graph

advanced20 minknowledge-graph.ts

You want facts about people, places and organizations pulled out of text and stored as a graph you can traverse.

What it shows

  • Extract entities and relations with LLMEntityExtractor
  • Store them in SQLiteGraphAdapter and walk neighbours and multi-hop paths
  • Derive new edges with GraphInferenceEngine

The code

knowledge-graph.ts
import { createLLMBackend } from '@cogitator-ai/core';
import {
  GraphInferenceEngine,
  LLMEntityExtractor,
  SQLiteGraphAdapter,
  unwrap,
} from '@cogitator-ai/memory';
import type { GraphNode } from '@cogitator-ai/types';

const apiKey = process.env.GOOGLE_API_KEY;
if (!apiKey) throw new Error('Set GOOGLE_API_KEY');

const google = createLLMBackend('google', { providers: { google: { apiKey } } });

const paragraphs = [
  'Marie Curie was a Polish-born physicist who worked at the University of Paris. She won the Nobel Prize twice.',
  'Pierre Curie was a French physicist and husband of Marie Curie. Together they discovered polonium and radium.',
  'Irene Joliot-Curie, daughter of Marie and Pierre Curie, worked at the Radium Institute in Paris.',
];

const agentId = 'kg-agent';
const extractor = new LLMEntityExtractor(google, {
  model: 'gemini-3.5-flash-lite',
  minConfidence: 0.6,
});
const graph = new SQLiteGraphAdapter({ path: ':memory:' });
await graph.initialize();

const nodes = new Map<string, GraphNode>();
for (const text of paragraphs) {
  const { entities, relations } = await extractor.extract(text, {
    agentId,
    existingEntities: [...nodes.values()].map((node) => node.name),
  });

  for (const entity of entities) {
    const key = entity.name.toLowerCase();
    if (nodes.has(key)) continue;
    const node = unwrap(
      await graph.addNode({
        agentId,
        type: entity.type,
        name: entity.name,
        aliases: entity.aliases ?? [],
        description: entity.description,
        properties: {},
        confidence: entity.confidence,
        source: 'extracted',
      })
    );
    nodes.set(key, node);
  }

  for (const relation of relations) {
    const source = nodes.get(relation.sourceEntity.toLowerCase());
    const target = nodes.get(relation.targetEntity.toLowerCase());
    if (!source || !target) continue;
    await graph.addEdge({
      agentId,
      sourceNodeId: source.id,
      targetNodeId: target.id,
      type: relation.type,
      label: relation.label,
      weight: 1,
      bidirectional: false,
      properties: {},
      confidence: relation.confidence,
      source: 'extracted',
    });
  }
}

const stats = unwrap(await graph.getGraphStats(agentId));
console.log(`${stats.nodeCount} nodes, ${stats.edgeCount} edges`, stats.nodesByType);

const marie = nodes.get('marie curie');
if (marie) {
  for (const { node, edge } of unwrap(await graph.getNeighbors(marie.id))) {
    console.log(`Marie Curie —${edge.type}— ${node.name}`);
  }
  const reachable = unwrap(
    await graph.traverse({ agentId, startNodeId: marie.id, maxDepth: 2, direction: 'both' })
  );
  console.log('Within 2 hops:', reachable.visitedNodes.map((node) => node.name).join(', '));
}

const inference = new GraphInferenceEngine(graph);
const inferred = await inference.infer(agentId);
console.log(`Inferred ${inferred.length} new relations`);
await inference.materialize(inferred);

await graph.close();

Run it

install · bash
pnpm add @cogitator-ai/core @cogitator-ai/memory @cogitator-ai/types better-sqlite3
EnvironmentGOOGLE_API_KEY
run · bash
GOOGLE_API_KEY=your-key npx tsx knowledge-graph.ts

Or run the full example from a clone of the repository (keys in .env):

repository · bash
npx tsx examples/memory/04-knowledge-graph.ts

Learn more