Skip to main content

Knowledge

Overview

The Knowledge module provides unified semantic search across all knowledge sources in a project — documents and memory entries. A single endpoint searches across these sources simultaneously, ranks results by vector similarity, and returns an interleaved list tagged by source type.

Each result carries a source_type discriminant ("document" or "memory") so callers know where each piece of knowledge came from. This is the same search layer agents use internally for retrieval — see it wired into an agent in Agent with Persistent Memory — Step 8 (Create an agent with knowledge_config), and the Memory & Knowledge Engine deep dive for the full retrieval pipeline and its extension points.

The module follows SOAT's engine & algorithms pattern: the two stores, the unified search function, and injection are the engine; chunking and ranking are the algorithms, and ingestion rules are the seam for bringing your own extraction algorithm as a tool.

See the Permissions Reference for the IAM action strings for this module.

Data Model

KnowledgeResult

A KnowledgeResult is a discriminated union on source_type. All results share common fields; source-specific fields are only present for the matching type.

Common fields (all source types)

FieldTypeDescription
source_type"document" | "memory"Discriminant for the knowledge source type
contentstring|nullText content of the result
scorenumberRelevance ranking; only present when query is used — see Relevance scoring
similarity_scorenumberRaw cosine similarity (0–1); only present when query is used
created_atstringISO 8601 creation timestamp
updated_atstringISO 8601 last-updated timestamp

Document result (source_type: "document")

FieldTypeDescription
document_idstringPublic document ID (doc_ prefix)
file_idstringID of the underlying File record
project_idstringID of the owning project
pathstring|nullLogical path within the project (e.g. /reports/q1.txt)
filenamestringOriginal filename
sizenumberFile size in bytes
titlestring|nullDocument title (if set)
metadataobject|nullArbitrary JSON metadata, returned with keys in the exact casing they were written with — not converted between snake_case and camelCase like other fields
tagsobjectKey-value tags associated with the document

Memory result (source_type: "memory")

FieldTypeDescription
entry_idstringPublic memory entry ID (mem_entry_ prefix)
memory_idstringPublic ID of the parent memory (mem_ prefix)
memory_namestringHuman-readable name of the parent memory

Key Concepts

Search Modes

The POST /knowledge/search endpoint accepts the following filters. At least one must be provided.

ParameterTypeDescription
querystringSemantic search query — ranks results by vector similarity
memory_idsstring[]Search entries within these specific memories
memory_tagsstring[]Match entries by tag at entry granularity: returns entries whose parent memory's tags match or whose own per-entry tags match any of these patterns (supports glob: user*)
document_pathsstring[]Filter document results to paths starting with these prefixes
document_idsstring[]Filter document results to specific document IDs

When query is set, results include score and similarity_score and are ordered by descending score; min_score and limit apply additional controls. For a walkthrough, see Agent with Persistent Memory — Step 12 (Query the knowledge layer directly).

Which sources a request searches follows from its filters: document results are included whenever query, document_paths, or document_ids is passed; memory entries whenever memory_ids or memory_tags is passed. Passing a query together with a memory filter searches both sources at once — the result sets are merged and ranked together by descending similarity before limit is applied. memory_ids and memory_tags combine with union semantics.

memory_tags matches at entry granularity: an entry is returned when its parent memory's tags match the globs or when the entry's own tags match — see Memories — Entry-Level Tag Filtering.

Relevance scoring

Two fields come back on every result of a query search, and they are not the same contract:

FieldContract
scoreImplementation-defined relevance ranking, higher is better. The ordering it produces is the contract; the absolute value is not. Results are sorted by it and min_score filters on it.
similarity_scoreRaw cosine similarity (0–1) between the query embedding and the result. Pinned to that meaning — it is never redefined.

Today the ranking is single-signal, so the two are equal. That is an implementation detail, not a guarantee: a later hybrid ranking would fuse several signals into score while similarity_score keeps reporting the cosine value for debugging.

What this means in practice:

  • Compare, don't interpret. score is meaningful relative to other results in the same response. Do not persist it, compare it across releases, or show it to end users as a percentage.
  • min_score is a deployment-tuned knob, not a portable constant. It filters on score, so a threshold tuned against today's ranking is not guaranteed to select the same results after the ranking changes. Pin the value per deployment and re-tune it when you upgrade.
  • Need a stable number? Read similarity_score.

Injected knowledge is untrusted input

Retrieved knowledge is partly user-derived — a memory entry written by automatic extraction contains whatever the user said in the turn it was extracted from. The platform treats it as data, never as instruction, and enforces that in two places:

  • It is never injected with the system role. Agent knowledge injection delivers results as a user message inside a fenced <knowledge> block, preceded by a preamble framing the contents as reference material. The agent's own instructions remain the only system-authored input. Without this, a phrase a user said once could come back as a system-level instruction in every later generation — a persistent escalation path, not a one-turn prompt injection.
  • Extraction runs tool-less. The fact-extraction completion is a plain text completion with no tools and no knowledge injection of its own, so text quoted from a conversation cannot trigger an agent side effect while it is being turned into memory entries.

What this does not do: it does not make retrieved content safe to act on. A tool call an agent makes after reading injected knowledge is still authorized only by that agent's boundary policy and guardrails — the fencing lowers the chance a model treats retrieved text as an instruction, it does not authorize anything. Scope an agent's boundary policy on the assumption that anything in its reachable memories and documents may influence what it tries to do.

Project Scoping

project_id is optional. When omitted, the server resolves accessible projects from the caller's identity (API key project scope, admin wildcard, or the projects granted by the caller's policies).

Configuration

Environment VariableRequiredDescription
FILES_STORAGE_DIRYesDirectory where .txt files are stored (shared with Files)
EMBEDDING_PROVIDERYesEmbedding backend: ollama, openai, or bedrock
EMBEDDING_MODELYesModel name, e.g. qwen3-embedding:0.6b
EMBEDDING_DIMENSIONSYesVector dimensions — must match the model output, e.g. 1024
OLLAMA_BASE_URLNoOllama server URL, defaults to http://localhost:11434

Examples

Semantic search across documents and memories

soat search-knowledge \
--project-id proj_ABC \
--query "quarterly revenue" \
--memory-ids mem_xyz \
--limit 5

Path-scoped document retrieval (no query)

soat search-knowledge \
--project-id proj_ABC \
--document-paths /docs/products/