Skip to main content
A Knowledge Base (KB) is a named container of Documents that have been chunked, embedded, and indexed for semantic retrieval. Agents call search_knowledge_base(query, kb_id?) to surface the most relevant chunks for whatever they’re working on.
KBs ship with three concrete tables (KnowledgeBase, Document, DocumentChunk) plus a KnowledgeEdge layer that materializes the kNN graph for traversal queries (Apache AGE-compatible).

What a KB stores

Three KB scopes

The “Creative Insights” KB is a special account-scoped KB auto-built per tenant by the creative-analysis pipeline (one Document per analyzed creative).

Ingestion paths

POST /api/knowledge_base/<kb_id>/documents/ (multipart). Accepts PDF, DOCX, TXT, MD, HTML, JSON. Triggers ingest_document.delay(...):
  1. Fetch + parse → plain text.
  2. Chunk (default 800 tokens, 80-token overlap).
  3. Embed each chunk via text-embedding-3-large (3072-dim).
  4. Update Document.status from chunkingembeddingready.
Re-uploading a file with the same SHA256 is a no-op (idempotent).
OAuth-based ingestion of an entire Drive folder.
  1. User connects their Drive via the OAuth flow at /api/knowledge_base/google-drive/oauth/start/.
  2. Picks a folder. We watch it for changes via push notifications.
  3. New / updated files are downloaded, parsed, and ingested as Documents.
  4. Removed files mark their Documents as archived (kept for audit, excluded from retrieval).
The OAuth flow + watcher logic lives in knowledge_base/google_drive_oauth.py + knowledge_base/google_drive.py. Setup notes in knowledge_base/GOOGLE_DRIVE_SETUP.md.
Auto-built per tenant by the creative-analysis pipeline. Each CreativeAnalysis row materializes a Document in the tenant’s “Creative Insights” KB with the prose synthesis as the body. This means agents can search_knowledge_base("ugc problem-solution") and get hits across the user’s analyzed creatives without going through the bespoke creative-search endpoint.See Creative Analytics overview.
Any automation can write a Document into a KB via the add_to_kb action — useful for archiving Slack threads, capturing meeting notes via webhook, etc.

Retrieval

Agents call search_knowledge_base(query, kb_id=None, top_k=5):
  1. Embed the query with text-embedding-3-large.
  2. Cosine kNN over DocumentChunk.embedding, filtered by accessible KBs (scope rules).
  3. Return top-K chunks with { document_title, chunk_text, similarity, document_id, chunk_idx }.
If kb_id is omitted, search runs across all KBs the user can see (user-scope + account-scope for their tenant + public).

Graph traversal

KnowledgeEdge materializes the kNN graph. For each chunk we emit edges to its top-N nearest neighbors with cosine distance as edge weight. This enables:
  • Recursive CTE traversal — “find all chunks within 2 hops of X” via Postgres recursive CTE, no AGE required.
  • Apache AGE Cypher — when AGE is installed, the same graph is mirrored into AGE label/edge tables (managed by tasks.build_graph_edges). Agents can run Cypher for richer queries.
The dual-write pattern means KB graph queries work whether or not AGE is enabled — AGE is a performance accelerator, not a correctness dependency.

Costs

Per OpenAI pricing (May 2026):
  • Embedding: ~$0.13 per 1M tokens (text-embedding-3-large).
  • Average chunk: ~800 tokens. So ~$0.00010 per chunk.
  • A 100-page PDF (~50k tokens) → ~63 chunks → ~$0.0065 to ingest.
Document.cost_cents (planned) will track per-doc ingest cost so a per-KB rollup is trivial.

Endpoints

List KBs the caller can see (filtered by scope rules).
Create a new KB. Body: { name, description, scope, source_type }.
List documents in a KB. Paginated.
Upload a document (multipart file field) or post a URL to ingest.
Search across accessible KBs. Body: { query, kb_id?, top_k? }.
Begin the Google Drive OAuth flow.
OAuth callback — completes the connection and lets the user pick a folder.
All gated by shared.permissions.AgentSurfaceAllowed for write paths; reads honor the per-KB scope rules so a public KB is searchable by anyone authenticated.

Bob tool

Returns a JSON list of chunks with their similarity scores and source document titles. Houston, Space Bob, and Social Sally all have this tool — the same query routes to the same KBs from any agent.

Operations

POST /api/knowledge_base/documents/<doc_id>/reingest/ resets the document to pending and re-runs the chunk+embed pipeline. Useful when chunking parameters change.
python manage.py shell -c "from knowledge_base.tasks import build_graph_edges; build_graph_edges('<kb_id>')" recomputes KnowledgeEdge rows for one KB. Run after a large ingest to reflect the new chunks in graph queries.
python manage.py enable_pgvector runs CREATE EXTENSION IF NOT EXISTS vector;. The migration also includes a defensive RunSQL so this is rarely needed manually — but useful on managed Postgres where the migration’s RunSQL is rolled back.
python manage.py check surfaces:
  • agent_surface.W001OPENAI_API_KEY not set (KB ingest stores chunks without embeddings).
  • agent_surface.W002 — pgvector extension not enabled (search returns 503).

Where the code lives