> For the complete documentation index, see [llms.txt](https://docs.graphlit.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.graphlit.dev/tutorials/knowledge-graph.md).

# Knowledge Graph

⏱️ **Time to Complete:** 20 minutes\
🎯 **Level:** Intermediate\
💻 **Language:** TypeScript

## What You'll Build

A knowledge graph that automatically extracts:

* ✅ Entities (people, organizations, places, events, products)
* ✅ Relationships between entities
* ✅ Queryable structure from unstructured content
* ✅ Multi-hop reasoning across sources

[**📁 Knowledge graph example app**](https://github.com/graphlit/graphlit-samples/tree/main/nextjs/chat-graph)

***

## Why Knowledge Graphs Matter

**Traditional search**: "Find documents mentioning Sarah"\
**Knowledge graph**: "Find all interactions between Sarah Chen at Acme Corp and our Sales team, including meetings, emails, and Slack conversations"

**The difference:**

* ✅ Entity recognition (Sarah Chen = person, Acme Corp = organization)
* ✅ Relationship tracking (Sarah works at Acme, spoke with Sales)
* ✅ Semantic understanding (group related mentions across sources)
* ✅ Structured queries on unstructured data

**Real-world example**: [Zine](https://www.zine.ai) uses knowledge graphs to answer "Who from Acme Corp have we talked to?" across Slack, email, meetings, and CRM notes.

***

## Prerequisites

* Complete the [Quickstart tutorial](/getting-started/quickstart.md)
* Graphlit project with API credentials configured in `.env`
* `npm install graphlit-client dotenv`

{% hint style="info" %}
Need Python or .NET examples? Open **Ask Graphlit** in the Developer Portal (or visit [ask.graphlit.dev](https://ask.graphlit.dev)) for autogenerated samples tailored to your SDK.
{% endhint %}

***

## Step 1: Extract Entities from Content

Create a workflow, ingest content, and extract entities - all in one script:

```typescript
import { Graphlit } from 'graphlit-client';
import {
  SpecificationTypes,
  ModelServiceTypes,
  OpenAiModels,
  FilePreparationServiceTypes,
  EntityExtractionServiceTypes,
  ObservableTypes,
} from 'graphlit-client/dist/generated/graphql-types';

const graphlit = new Graphlit();

const SAMPLE_NOTE = `
Met with Sarah Chen, CTO at Acme Corp, at their San Francisco office.
She's evaluating our API for their 800-user deployment.

Key attendees:
- Sarah Chen (CTO, Acme Corp)
- Mike Rodriguez (VP Engineering, Acme Corp)
- Alex Kim (Solutions Engineer, our team)

They need CRM integration and mentioned Salesforce as their current tool.
Looking to deploy by Q4 2025. Budget approved for Enterprise tier.

Follow-up: Technical demo scheduled for next Tuesday in Acme's office.
`;

async function main() {
  console.log('⚙️ Creating extraction workflow...');

  // 1️⃣ Configure the LLM that performs entity extraction
  const extractionSpec = await graphlit.createSpecification({
    name: 'Knowledge Graph Extraction',
    type: SpecificationTypes.Extraction,
    serviceType: ModelServiceTypes.OpenAi,
    openAI: {
      model: OpenAiModels.Gpt5_400K,
      temperature: 0,  // Deterministic for consistent extraction
    },
  });

  // 2️⃣ Build a workflow that prepares documents and extracts entities
  const workflow = await graphlit.createWorkflow({
    name: 'Entity Extraction Workflow',
    preparation: {
      jobs: [
        {
          connector: {
            type: FilePreparationServiceTypes.Document,
          },
        },
      ],
    },
    extraction: {
      jobs: [
        {
          connector: {
            type: EntityExtractionServiceTypes.ModelText,
            modelText: {
              specification: { id: extractionSpec.createSpecification.id },
              tokenThreshold: 32,
            },
            extractedTypes: [
              ObservableTypes.Person,
              ObservableTypes.Organization,
              ObservableTypes.Place,
              ObservableTypes.Event,
              ObservableTypes.Product,
              ObservableTypes.Software,
              ObservableTypes.Repo,
            ],
          },
        },
      ],
    },
  });

  console.log('✅ Workflow created:', workflow.createWorkflow.id);

  // 3️⃣ Ingest content with the workflow (extraction happens automatically)
  console.log('📄 Ingesting content...');
  const content = await graphlit.ingestText(
    SAMPLE_NOTE,
    'Sales Call Notes',
    undefined,
    undefined,
    undefined,
    undefined,
    true, // Wait for processing to finish
    { id: workflow.createWorkflow.id },
  );

  console.log('✅ Content ready:', content.ingestText.id);

  // 4️⃣ List extracted entities
  console.log('\n🔍 Extracted entities:');
  const observables = await graphlit.queryObservables();
  const results = observables.observables?.results ?? [];

  const format = (type: ObservableTypes) =>
    results
      .filter((entry) => entry?.type === type)
      .map((entry) => entry?.observable.name)
      .filter(Boolean) as string[];

  console.log('👥 People:', format(ObservableTypes.Person));
  console.log('🏢 Organizations:', format(ObservableTypes.Organization));
  console.log('📍 Places:', format(ObservableTypes.Place));
  console.log('🛠️ Products/Software:', [
    ...format(ObservableTypes.Product),
    ...format(ObservableTypes.Software),
  ]);

  return content.ingestText.id;
}

main().catch((error) => {
  console.error(error);
  process.exit(1);
});
```

**What happens:**

* Creates extraction specification (GPT-5, temperature 0 for deterministic results)
* Creates workflow with entity extraction
* Ingests sample text with the workflow
* Automatically extracts entities (people, organizations, places, etc.)
* Lists all extracted entities

Run: `npx tsx extract-entities.ts`

***

## Step 2: Explore Relationships in the Graph

Query content and visualize the entity relationships:

```typescript
import { Graphlit } from 'graphlit-client';

const graphlit = new Graphlit();

async function main() {
  // Query content by name (realistic production pattern)
  const contents = await graphlit.queryContents({ name: 'Sales Call Notes' });

  const contentId = contents.contents?.results?.[0]?.id;
  if (!contentId) {
    console.error('Content not found. Run Step 1 first.');
    process.exit(1);
  }

  console.log('🕸️ Exploring knowledge graph...\n');

  // Get the graph for this content
  const graph = await graphlit.queryContentsGraph({
    contents: [{ id: contentId }],
  });

  const nodes = (graph.contents?.graph?.nodes ?? []).filter(
    (node): node is NonNullable<typeof node> => Boolean(node),
  );
  const edges = (graph.contents?.graph?.edges ?? []).filter(
    (edge): edge is NonNullable<typeof edge> => Boolean(edge),
  );

  const nodeById = new Map(nodes.map((node) => [node.id, node]));

  console.log('🕸️ Relationships in this document:');
  edges.forEach((edge) => {
    const from = nodeById.get(edge.from);
    const to = nodeById.get(edge.to);
    if (!from || !to) return;
    const relation = edge.relation ? ` —${edge.relation}→ ` : ' → ';
    console.log(`${from.name}${relation}${to.name}`);
  });
}

main().catch((error) => {
  console.error(error);
  process.exit(1);
});
```

This renders the knowledge graph for a document. Each node represents a person, organization, or event; edges capture relationships Graphlit inferred (e.g., "Sarah Chen → worksFor → Acme Corp").

***

## Step 3: Find Every Document Mentioning an Entity

```typescript
import { Graphlit } from 'graphlit-client';
import { ObservableTypes } from 'graphlit-client/dist/generated/graphql-types';

const graphlit = new Graphlit();

async function findContentForPerson(personName: string) {
  const observables = await graphlit.queryObservables();
  const matches = observables.observables?.results?.filter(
    (entry) =>
      entry?.type === ObservableTypes.Person &&
      entry.observable.name?.toLowerCase() === personName.toLowerCase(),
  );

  if (!matches?.length) {
    console.log(`No entities found for ${personName}`);
    return;
  }

  const { id } = matches[0]!.observable;
  const related = await graphlit.queryContents({
    observations: [
      {
        type: ObservableTypes.Person,
        observable: { id },
      },
    ],
  });

  const docs = related.contents?.results ?? [];
  console.log(`
📚 Documents mentioning ${personName}:`);
  docs.forEach((doc) => console.log(`- ${doc?.name} (${doc?.id})`));
}

findContentForPerson('Sarah Chen').catch((error) => {
  console.error(error);
  process.exit(1);
});
```

Filtering by `observations` lets you answer questions like "Show me every asset where Sarah Chen appears" or "Find all notes referencing Salesforce".

***

## Production Patterns

### Batch Ingestion + Polling

```typescript
// Query for your extraction workflow by name
const workflows = await graphlit.queryWorkflows({ name: 'Entity Extraction Workflow' });
const workflowId = workflows.workflows?.results?.[0]?.id;

// Ingest multiple files
const batch = await graphlit.ingestBatch(
  ['https://example.com/questionnaire.pdf', 'https://example.com/demo-notes.docx'],
  { id: workflowId },
);

// Poll until processing completes
await Promise.all(
  batch.ingestBatch.ids.map(async ({ id }) => {
    let done = false;
    while (!done) {
      const status = await graphlit.isContentDone(id);
      done = Boolean(status.isContentDone?.result);
      if (!done) await new Promise((r) => setTimeout(r, 1500));
    }
  }),
);
```

### Build Collections from Entities

```typescript
const observables = await graphlit.queryObservables();
const organizations = observables.observables?.results?.filter(
  (entry) => entry?.type === ObservableTypes.Organization,
);

if (organizations?.length) {
  const collection = await graphlit.createCollection({
    name: `${organizations[0]!.observable.name} Knowledge Base`,
  });

  const related = await graphlit.queryContents({
    observations: [
      {
        type: ObservableTypes.Organization,
        observable: { id: organizations[0]!.observable.id },
      },
    ],
  });

  const ids = (related.contents?.results ?? [])
    .filter(Boolean)
    .map((item) => ({ id: item!.id }));

  if (ids.length) {
    await graphlit.addContentsToCollections(ids, [{ id: collection.createCollection.id }]);
  }
}
```

### Keep Graph Conversations Focused

```typescript
// Query for the organization entity by name
const observables = await graphlit.queryObservables({
  filter: {
    types: [ObservableTypes.Organization],
    name: 'Acme Corp'
  }
});
const targetOrganizationId = observables.observables?.results?.[0]?.observable.id;

// Create conversation filtered to that organization
const conversation = await graphlit.createConversation({
  name: 'Acme Corp CRM Review',
  filter: {
    observations: targetOrganizationId
      ? [
          {
            type: ObservableTypes.Organization,
            observable: { id: targetOrganizationId },
          },
        ]
      : undefined,
  },
});

const response = await graphlit.promptConversation(
  'Summarize our interactions with Acme Corp this quarter.',
  conversation.createConversation.id,
);

console.log(response.promptConversation.message?.message);
```

***

## Real-World Examples

### 1. Customer 360

* Aggregate Slack, email, and meeting notes per account
* Surface key contacts + topics before every call
* Feed a sales agent that remembers context across teams

### 2. Incident Response Watchtower

* Track mentions of outages across Sentry, Slack, and PagerDuty
* Connect incidents to affected services and owners
* Push summaries to on-call staff in real time

### 3. Market Intelligence Radar

* Monitor competitor names across research docs and news
* Attach relationships between mentions, products, and regions
* Drive alerts when new entities (people or products) appear

***

## Next Steps

* [**Knowledge Graph Use Cases**](/api-guides/use-cases/knowledge-graph.md) – Deep-dive patterns for extraction, enrichment, and queries
* [**Context Engineering**](/tutorials/context-engineering.md) – Feed knowledge graph insights into retrieval

***

## Full Example: Production Agent

See the complete Next.js agent in [graphlit-samples](https://github.com/graphlit/graphlit-samples/tree/main/nextjs/chat-graph):

* Visual knowledge-graph explorer with streaming chat
* Entity filtering and relationship queries in the UI
* Production-ready environment configuration and error handling

***

**Build agents that understand your data model. Build with Graphlit.**
