> ## Documentation Index
> Fetch the complete documentation index at: https://docs.modulex.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Knowledge node

> Retrieve from a knowledge base inside a workflow with the knowledge node. Full KnowledgeNodeConfig reference — provider, query, top-k, min-score, output format — plus managed-retrieval credit reservation, inputs/outputs, every error, and a worked example.

export const MediaEmbed = ({id, type = 'screenshot', caption = '', ext, ratio = '16 / 9'}) => {
  const isVideo = type === 'video' || type === 'app_video';
  const resolvedExt = ext || (isVideo ? 'mp4' : type === 'screenshot' ? 'webp' : 'svg');
  const src = 'https://media.modulex.dev/' + id + '.' + resolvedExt;
  const [status, setStatus] = useState('loading');
  const [isDev, setIsDev] = useState(false);
  const [inView, setInView] = useState(false);
  const boxRef = useRef(null);
  useEffect(() => {
    if (typeof window === 'undefined') return;
    const h = window.location.hostname;
    setIsDev(h === 'localhost' || h === '127.0.0.1' || h.endsWith('.mintlify.app'));
  }, []);
  useEffect(() => {
    if (inView) return;
    if (typeof IntersectionObserver === 'undefined') {
      setInView(true);
      return;
    }
    const el = boxRef.current;
    if (!el) return;
    const io = new IntersectionObserver(entries => {
      if (entries.some(e => e.isIntersecting)) {
        setInView(true);
        io.disconnect();
      }
    }, {
      rootMargin: '300px'
    });
    io.observe(el);
    return () => io.disconnect();
  }, [inView]);
  if (status === 'missing') {
    if (!isDev) return null;
    return <div style={{
      display: 'flex',
      flexDirection: 'column',
      justifyContent: 'center',
      gap: '0.4rem',
      padding: '1rem 1.25rem',
      margin: '1.25rem 0',
      width: '100%',
      aspectRatio: ratio,
      boxSizing: 'border-box',
      border: '1px dashed rgba(128,128,128,0.45)',
      borderRadius: '0.75rem',
      background: 'rgba(128,128,128,0.06)',
      color: 'currentColor',
      fontSize: '0.85rem',
      lineHeight: 1.45
    }}>
        <div style={{
      display: 'flex',
      alignItems: 'center',
      gap: '0.5rem',
      opacity: 0.75
    }}>
          <span aria-hidden="true">🎬</span>
          <code style={{
      fontSize: '0.75rem'
    }}>{id}</code>
          <span style={{
      fontSize: '0.65rem',
      textTransform: 'uppercase',
      letterSpacing: '0.04em',
      padding: '0.1rem 0.4rem',
      borderRadius: '0.4rem',
      background: 'rgba(128,128,128,0.18)'
    }}>
            {type}
          </span>
        </div>
        <div style={{
      opacity: 0.9
    }}>{caption || 'Media not uploaded yet.'}</div>
        <div style={{
      fontSize: '0.7rem',
      opacity: 0.5
    }}>
          Upload to R2 as <code>{id}.{resolvedExt}</code> — preview only, hidden in production.
        </div>
      </div>;
  }
  const mediaStyle = {
    display: status === 'loaded' ? 'block' : 'none',
    width: '100%',
    height: 'auto',
    borderRadius: '0.75rem'
  };
  const media = isVideo ? <video src={inView ? src : undefined} autoPlay loop muted playsInline preload="metadata" onLoadedData={() => setStatus('loaded')} onError={() => setStatus('missing')} style={mediaStyle} /> : <img src={inView ? src : undefined} alt={caption} onLoad={() => setStatus('loaded')} onError={() => setStatus('missing')} style={mediaStyle} />;
  return <figure style={{
    margin: '1.25rem 0'
  }}>
      <div ref={boxRef} style={status === 'loaded' ? {
    width: '100%'
  } : {
    width: '100%',
    aspectRatio: ratio,
    borderRadius: '0.75rem',
    background: 'rgba(128,128,128,0.06)'
  }}>
        {media}
      </div>
      {status === 'loaded' && caption ? <figcaption style={{
    marginTop: '0.5rem',
    textAlign: 'center',
    fontSize: '0.85rem',
    opacity: 0.7
  }}>
          {caption}
        </figcaption> : null}
    </figure>;
};

The `knowledge` node retrieves relevant chunks from a [knowledge base](/concepts/knowledge-rag) and writes the result into run state under the node's own id. It is how you add retrieval-augmented generation (RAG) to a workflow: search your connected documents for a query, then feed the retrieved context into a downstream [LLM node](/workflow-builder/nodes/llm) or [agent node](/workflow-builder/nodes/agent).

The node works against the ModuleX-managed store (`modulexdb`) and against external vector databases — Qdrant, Pinecone, Weaviate, and MongoDB Atlas. For the broader retrieval model — knowledge bases, ingest, managed vs BYOK — see [knowledge & RAG](/concepts/knowledge-rag). To pass a dynamic query into the node, use `{{node_id.field}}` references — the same reference system documented in [variables & references](/workflow-builder/variables-and-references) and [the workflow engine](/concepts/workflow-engine).

<MediaEmbed id="MX-MEDIA-3090" type="screenshot" caption={"the knowledge node configuration panel in the workflow builder"} />

## What the node does

When the engine compiles your workflow, the `knowledge` node becomes a single async step ([workflow engine](/concepts/workflow-engine)). At run time the node:

1. Resolves the search query. If `query_from_input` is `true`, it reads the query from common run-state fields (`query`, `question`, `input`, `user_input`, `message`); otherwise it resolves the `query` string, replacing every `{{...}}` token with its value from run state.
2. Coerces the resolved query to a string. If the query is empty, the node returns an empty result (`total_results: 0`) carrying an `error` of `Empty query` rather than failing the run.
3. Routes by `provider_type`. `modulexdb` runs against your native ModuleX knowledge base via the search service; any other value runs against the matching external provider adapter.
4. For a managed native knowledge base, reserves a retrieval credit before the search and records it on success — see [credit impact](#credit-impact).
5. Performs a vector (cosine-similarity) search, returning up to `top_k` chunks above `min_score`.
6. Formats the result per `output_format` (chunks, a context string, or both) and writes it into run state under the node's `id`.

<Note>
  The output of a knowledge node is always stored in run state under the node's `id` — for example a node with `id: "retrieve_1"` writes to `{{retrieve_1}}`, and its context string is `{{retrieve_1.context}}`. There is no `output_key` field on this node; reference results by node id.
</Note>

## Picking the knowledge base

You point the node at a knowledge base through a **credential**, not a knowledge-base id. Every native ModuleX knowledge base is created with a linked internal credential (the "native KB = credential" pattern), so `credential_id` resolves to the knowledge base behind it. For an external provider, `credential_id` is the stored credential for that vector store. See [managing credentials](/integrations/managing-credentials).

* **Managed native store (`modulexdb`)** — set `provider_type` to `modulexdb` (the default) and `credential_id` to the knowledge base's credential. The node resolves the linked knowledge base and searches it directly; embeddings are handled by the knowledge base's own configuration, so you do not set `embedding_config`. Managed retrieval is billed in credits. See [managed knowledge (modulexdb)](/platform/knowledge/managed) and [modulexdb (managed)](/integrations/knowledge-providers/modulexdb).
* **External provider** — set `provider_type` to `qdrant`, `pinecone`, `weaviate`, or `mongodb_atlas`, set `credential_id` to that provider's credential, and provide `collection_name` (required) plus an `embedding_config` so the node can embed the query before searching. External (BYOK) retrieval is **not** charged in credits. See [external knowledge providers](/platform/knowledge/external-providers) and [knowledge providers](/integrations/knowledge-providers/overview).

## Configuration (`KnowledgeNodeConfig`)

These fields live on the node's `knowledge_config`. In the builder you set them through the detail panel; over the API they appear inside the node definition (the builder also accepts a wrapped `{config: {...}}` form, which the backend normalizes to `knowledge_config`).

### Connection

<ParamField path="credential_id" type="string" required>
  The stored credential for the knowledge base or external vector store. Required. For a native ModuleX knowledge base this is the knowledge base's linked credential, which the node resolves to the knowledge base behind it. See [managing credentials](/integrations/managing-credentials).
</ParamField>

<ParamField path="provider_type" type="string (enum)" default="modulexdb">
  Which knowledge provider to query. One of `modulexdb`, `qdrant`, `pinecone`, `weaviate`, `mongodb_atlas`. Defaults to `modulexdb` (the managed native store). See [knowledge providers](/integrations/knowledge-providers/overview).
</ParamField>

### Query

<ParamField path="query" type="string" required>
  The search query. Required. Supports `{{node_id.field}}` references for a dynamic query built from upstream output — for example `{{intake_1.message}}`. The node resolves the template against run state before searching.
</ParamField>

<ParamField path="query_from_input" type="boolean" default="false">
  When `true`, the node ignores `query` and instead reads the query from run state, trying the fields `query`, `question`, `input`, `user_input`, then `message` in order (and, if that value is a dict, its `query` / `input` / `text` key). Use it when the run's top-level input is itself the search query. When `false` (the default), the node uses the resolved `query` field.
</ParamField>

### Retrieval settings

<ParamField path="top_k" type="integer" default="5">
  Maximum number of chunks to retrieve. Range 1–50. Higher values return more context (and cost more tokens downstream); lower values keep the context tight.
</ParamField>

<ParamField path="min_score" type="number" default="0.3">
  Minimum cosine-similarity score a chunk must reach to be included. Range 0.0–1.0. Chunks below this floor are dropped, so a strict threshold can return fewer than `top_k` results — or none. Raise it to favor precision; lower it to favor recall.
</ParamField>

<ParamField path="max_tokens" type="integer" default="2000">
  Token budget for the formatted context string. Range 100–10000. Only applies when `output_format` is `context` or `both`: the node appends chunks in score order until adding the next chunk would exceed this budget, then stops. Tokens are estimated as roughly 4 characters each. Has no effect on the raw `chunks` list.
</ParamField>

### Filtering

<ParamField path="filters" type="object">
  Provider-specific filter conditions applied to the search. Optional. The accepted shape depends on the provider; for native knowledge bases, document filtering is handled through `document_ids` (below).
</ParamField>

<ParamField path="document_ids" type="string[]">
  Restrict the search to specific document ids within the knowledge base. Optional. **Native (`modulexdb`) knowledge bases only** — ignored by external providers. Use it to scope retrieval to a known subset of documents.
</ParamField>

### Output

<ParamField path="output_format" type="string (enum)" default="context">
  How results are returned. One of:

  * `context` (default) — a single formatted context string ready to drop into a prompt, with chunks numbered and (optionally) labeled by source and score.
  * `chunks` — the raw list of matched chunks with their scores and metadata.
  * `both` — both the `context` string and the `chunks` list.

  See [outputs](#outputs) for the exact shape of each.
</ParamField>

<ParamField path="include_metadata" type="boolean" default="true">
  Include each chunk's metadata in the results. Optional; defaults to `true`. Applies to the `chunks` list.
</ParamField>

<ParamField path="include_source" type="boolean" default="true">
  Include the source document label in the formatted context string. Optional; defaults to `true`. When `true`, each chunk in the `context` output is prefixed with its source filename and score, for example `(Source: manual.pdf, Score: 0.83)`.
</ParamField>

### External-provider fields

<ParamField path="collection_name" type="string">
  The collection or index name on the external vector store. **Required for external providers** (`qdrant`, `pinecone`, `weaviate`, `mongodb_atlas`); a missing `collection_name` raises an error at run time. Ignored for `modulexdb`.
</ParamField>

<ParamField path="namespace" type="string">
  The namespace within the index, for providers that support one (for example Pinecone). Optional. Ignored for `modulexdb`.
</ParamField>

<ParamField path="embedding_config" type="EmbeddingConfig object">
  How to embed the query before searching. **Required for external providers** that do not embed internally (Qdrant, Pinecone, and similar) so query vectors match the vectors stored at ingest time. Not used for `modulexdb`, which embeds using the knowledge base's own configuration. See [the `embedding_config` object](#the-embedding-config-object).
</ParamField>

#### The `embedding_config` object

<ParamField path="embedding_config.integration_name" type="string" required>
  The integration name of the embedding provider, for example `openai` or `cohere`. Required when `embedding_config` is set.
</ParamField>

<ParamField path="embedding_config.provider_id" type="string" required>
  The provider identifier, for example `openai`. Required when `embedding_config` is set.
</ParamField>

<ParamField path="embedding_config.model_id" type="string" required>
  The embedding model id, for example `text-embedding-3-small`. Required when `embedding_config` is set. Use the same embedding model you used to ingest the external collection, so query and stored vectors are comparable.
</ParamField>

<ParamField path="embedding_config.credential_id" type="string">
  A specific stored credential for the embedding provider. Optional; if omitted, the organization's default credential for that integration is used. See [managing credentials](/integrations/managing-credentials).
</ParamField>

### Retry configuration

The `knowledge` node is retry-wrapped. You can attach a `retry_config` to the node definition itself (not inside `knowledge_config`) to control how a failed retrieval is retried. If you omit it, the engine applies its default retry policy. Errors are only retried when their type is in `retry_on_error_types`.

<ParamField path="retry_config.max_attempts" type="integer" default="3">
  Total attempts including the first. Range 1–10. `1` means no retry; `3` means the initial call plus 2 retries.
</ParamField>

<ParamField path="retry_config.initial_interval" type="number" default="1.0">
  Seconds to wait before the first retry. Range 0.1–60.
</ParamField>

<ParamField path="retry_config.backoff_factor" type="number" default="2.0">
  Multiplier applied to the delay between successive retries (exponential backoff). Range 1–5.
</ParamField>

<ParamField path="retry_config.retry_on_error_types" type="string[]" default="[&#x22;TimeoutError&#x22;, &#x22;ConnectionError&#x22;, &#x22;HTTPError&#x22;]">
  Exception type names that trigger a retry. Errors not in this list fail immediately.
</ParamField>

<Note>
  The node already catches retrieval exceptions internally and returns an empty result with an `error` field rather than raising (see [errors](#errors)). Because of that, `retry_config` mainly covers transient failures that surface as exceptions before the node's own handler — most retrieval problems show up as an `error` field on the node output, not as a retried failure. See [error handling & retries](/workflow-builder/error-handling-retries).
</Note>

## Inputs and outputs

### Inputs

The knowledge node has no fixed input fields. It builds its query from one of two sources:

* **`query` with references** — `{{node_id}}` for an entire upstream node output, `{{node_id.field}}` for a nested value via dot/bracket path (for example `{{intake_1.message}}`), or `{{input}}` for the run's top-level input. A reference that is the whole string keeps its native type and is then coerced to a string; a reference embedded in other text is string-substituted. See [variables & references](/workflow-builder/variables-and-references).
* **`query_from_input: true`** — the node reads the query directly from run state (`query`, `question`, `input`, `user_input`, `message`), ignoring the `query` field.

### Outputs

The node writes one value into run state under its `id`. The shape depends on `output_format`:

<ResponseField name="{node_id}" type="object">
  The retrieval result.

  <Expandable title="Result fields">
    <ResponseField name="total_results" type="integer">
      The number of chunks the search returned (after `min_score` filtering and the `top_k` cap), regardless of `output_format`.
    </ResponseField>

    <ResponseField name="context" type="string | null">
      The formatted context string. Present (non-null) when `output_format` is `context` or `both`; `null` when `output_format` is `chunks`. Chunks are concatenated in score order until the `max_tokens` budget is reached, each numbered `[1]`, `[2]`, … and — when `include_source` is `true` — prefixed with `(Source: <filename>, Score: <score>)`.
    </ResponseField>

    <ResponseField name="chunks" type="array | null">
      The list of matched chunks. Present (non-null) when `output_format` is `chunks` or `both`; `null` when `output_format` is `context`. Each chunk carries its `content`, `score`, source document info, and (when `include_metadata` is `true`) `metadata`.
    </ResponseField>

    <ResponseField name="error" type="string">
      Present only when retrieval could not be performed — for example `Empty query`, or the message of a caught retrieval exception. When `error` is set, `chunks` is `[]`, `context` is `""`, and `total_results` is `0`. See [errors](#errors).
    </ResponseField>
  </Expandable>
</ResponseField>

Downstream nodes read the context with `{{retrieve_1.context}}`, the raw matches with `{{retrieve_1.chunks}}`, or a specific match field such as `{{retrieve_1.chunks[0].content}}`. A common pattern is to feed `{{retrieve_1.context}}` straight into an [LLM node](/workflow-builder/nodes/llm) prompt.

## Streaming

A knowledge node streams at the **node level** over [SSE](/realtime/sse-streaming), like every workflow node. When the node finishes, the engine publishes a `node_update` event carrying the node's output. On the wire this event is flat and uses the keys `node` and `output` — for example `{type, node, output}` — not the typed model field names. The run then ends with a `done` event.

<Note>
  The realtime wire dicts differ from the typed event models: the `node_update` frame uses `node` and `output`, and `done` carries only a `message`. Parse each SSE frame as JSON and switch on its `type` field — there is no SSE `event:` line. Details on [SSE run streaming](/realtime/sse-streaming).
</Note>

## Credit impact

Retrieval credits depend on whether the knowledge base is **managed** or **BYOK**:

<CardGroup cols={2}>
  <Card title="Managed native (modulexdb)" icon="server">
    A native knowledge base whose embedding provider is ModuleX-managed (`modulexai`) is **billed in credits**. The node reserves one retrieval base credit before the search and records the base plus the query-embedding token cost on success. See [credits & metering](/billing/credits) and [managed knowledge (modulexdb)](/platform/knowledge/managed).
  </Card>

  <Card title="BYOK / external" icon="key">
    A bring-your-own-key knowledge base or external vector store (Qdrant, Pinecone, Weaviate, MongoDB Atlas) is **uncosted** — no ModuleX credits are charged for retrieval. You pay your provider directly. See [external knowledge providers](/platform/knowledge/external-providers).
  </Card>
</CardGroup>

How the reservation works for a managed native knowledge base:

1. Before embedding and searching, the node reserves one retrieval base credit (the managed-retrieval admission step).
2. On a successful search, it settles the base credit and records the query-embedding token cost.
3. On a search error, it releases the reservation so the credit is not consumed.

<Note>
  Inside a running workflow, the managed-retrieval gate is **best-effort**: a billing hiccup or credit exhaustion does **not** crash the workflow. This differs from the interactive [knowledge search API](/concepts/knowledge-rag), which rejects-before-write and returns a `DenialEnvelope` on the request itself. Workflow run, [Composer](/workflow-builder/composer), [Assistant](/assistant/overview), and the managed-knowledge surfaces are gated by the billing admission gate, which can return a `DenialEnvelope` as **402 / 403 / 429**. The flat envelope shape is `{code, layer, key, current, limit, reason}`. See [errors & status codes](/api-reference/errors) and [usage gating & limits](/billing/usage-gating).
</Note>

A retrieval base credit is one credit (`RETRIEVAL_BASE = 1`); at the managed-usage scale that is `$0.01` plus the query-embedding token cost. See [credits & metering](/billing/credits) for the credit unit and metering details.

## Errors

The knowledge node is defensive: it catches retrieval failures and returns an empty result with an `error` field instead of failing the run. The cases below describe how each surfaces.

<Accordion title="Empty query">
  If the resolved query is empty (no `query`, or `query_from_input` found nothing in run state), the node does not search. It returns `{chunks: [], context: "", total_results: 0, error: "Empty query"}` under its node id and the run continues. Check that your `{{...}}` reference resolves and that the upstream node ran first.
</Accordion>

<Accordion title="Missing knowledge_config">
  If a `knowledge` node has no `knowledge_config`, compilation fails with a configuration error (`Knowledge node <id> missing knowledge_config`). Ensure `credential_id` and `query` are set.
</Accordion>

<Accordion title="Credential or knowledge base not found">
  If `credential_id` does not match a credential in the current organization, or no knowledge base is linked to it, the node's retrieval raises and is caught: the output carries an `error` such as `Credential not found: <id>` or `No knowledge base linked to credential: <id>`, with empty `chunks`/`context`. Confirm the credential id and that the native knowledge base still exists. See [managing credentials](/integrations/managing-credentials).
</Accordion>

<Accordion title="External provider misconfiguration">
  For an external provider, a missing `collection_name` raises `collection_name is required for external provider: <type>`, caught and returned as the node's `error`. Provide `collection_name` and an `embedding_config` whose `model_id` matches the model used at ingest. See [external knowledge providers](/platform/knowledge/external-providers).
</Accordion>

<Accordion title="Embedding or search failure">
  A failure while embedding the query or running the search (provider error, network error, embedding-provider error) is caught and returned as the node's `error` with empty results; for a managed native knowledge base the reserved retrieval credit is released. The run continues with an empty context — guard downstream nodes for the empty case, or branch on `{{node_id.total_results}}` with a [conditional node](/workflow-builder/nodes/conditional).
</Accordion>

<Accordion title="Credit exhaustion mid-run (managed)">
  Because the managed-retrieval gate is best-effort inside a workflow, exhausted credits do not crash the run; retrieval may simply return empty. To avoid silent empty context, monitor credits and top up the [wallet](/billing/wallet) or upgrade your [plan](/billing/plans). On the interactive knowledge search API (not the workflow node), the same condition returns a `DenialEnvelope` (402/429) on the request. See [usage gating & limits](/billing/usage-gating).
</Accordion>

For the full taxonomy of error-envelope shapes and which surface emits each, see [errors & status codes](/api-reference/errors).

## Full example

A two-node RAG workflow: a `knowledge` node retrieves context for the user's question from a native ModuleX knowledge base, then an [LLM node](/workflow-builder/nodes/llm) answers using only that context. The first tab shows the knowledge node definition as it appears in a workflow over the API; the next tabs run the workflow end to end with the SDKs and read the node's output from run state.

<CodeGroup>
  ```json Knowledge node definition theme={null}
  {
    "id": "retrieve_1",
    "type": "knowledge",
    "name": "Retrieve product docs",
    "x": 320,
    "y": 160,
    "retry_config": {
      "max_attempts": 3,
      "initial_interval": 1.0,
      "backoff_factor": 2.0
    },
    "knowledge_config": {
      "credential_id": "a1b2c3d4-5e6f-4789-90ab-cdef01234567",
      "provider_type": "modulexdb",
      "query": "{{input.question}}",
      "top_k": 5,
      "min_score": 0.3,
      "max_tokens": 2000,
      "output_format": "context",
      "include_metadata": true,
      "include_source": true
    }
  }
  ```

  ```json LLM node that uses the retrieved context theme={null}
  {
    "id": "answer_1",
    "type": "llm",
    "name": "Answer from context",
    "x": 640,
    "y": 160,
    "llm_config": {
      "llm": {
        "integration_name": "modulexai",
        "provider_id": "openrouter",
        "model_id": "claude-sonnet-4.6",
        "temperature": 0.2
      },
      "system_prompt": "Answer the question using only the provided context. If the context does not contain the answer, say you do not know.",
      "user_prompt": "Context:\n{{retrieve_1.context}}\n\nQuestion: {{input.question}}"
    }
  }
  ```

  ```bash cURL theme={null}
  # Run a workflow whose first node is the retrieve_1 knowledge node
  curl -X POST https://api.modulex.dev/workflows/run \
    -H "Authorization: Bearer mx_live_xxxxxxxxxxxxxxxxxxxx" \
    -H "X-Organization-ID: org_4d2b18" \
    -H "Content-Type: application/json" \
    -d '{
          "workflow_id": "wf_7f3a9c",
          "input": {
            "question": "How do I rotate an API key?"
          }
        }'
  ```

  ```python Python theme={null}
  from modulex import ModuleX

  client = ModuleX(
      api_key="mx_live_xxxxxxxxxxxxxxxxxxxx",
      organization_id="org_4d2b18",
  )

  run = client.workflows.run(
      "wf_7f3a9c",
      input={"question": "How do I rotate an API key?"},
  )

  # retrieve_1 wrote its retrieval result under its node id
  print(run.state["retrieve_1"]["total_results"])  # -> 5
  print(run.state["retrieve_1"]["context"][:120])   # -> "[1] (Source: api-keys.md, Score: 0.84) ..."

  # answer_1 answered from that context
  print(run.state["answer_1"])
  ```

  ```javascript JavaScript theme={null}
  import { ModuleX } from "@modulex/sdk";

  const client = new ModuleX({
    apiKey: "mx_live_xxxxxxxxxxxxxxxxxxxx",
    organizationId: "org_4d2b18",
  });

  const run = await client.workflows.run("wf_7f3a9c", {
    input: { question: "How do I rotate an API key?" },
  });

  // retrieve_1 wrote its retrieval result under its node id
  console.log(run.state.retrieve_1.total_results); // -> 5
  console.log(run.state.retrieve_1.context.slice(0, 120)); // -> "[1] (Source: api-keys.md, Score: 0.84) ..."

  // answer_1 answered from that context
  console.log(run.state.answer_1);
  ```
</CodeGroup>

Every request authenticates with `Authorization: Bearer mx_live_…` plus `X-Organization-ID`. See [authentication](/api-reference/authentication) and the [run-a-workflow guide](/guides/run-a-workflow). To build and query a knowledge base end to end before wiring it into a workflow, see [build a RAG knowledge base](/guides/build-a-knowledge-base). To stream the run instead of waiting for the final state, see [SSE run streaming](/realtime/sse-streaming).

## Related

<CardGroup cols={2}>
  <Card title="Knowledge & RAG" icon="book-open" href="/concepts/knowledge-rag">
    The retrieval model: knowledge bases, ingest, managed vs BYOK, and how RAG works.
  </Card>

  <Card title="LLM node" icon="sparkles" href="/workflow-builder/nodes/llm">
    Feed `{{retrieve_1.context}}` into a model call to answer from your documents.
  </Card>

  <Card title="Knowledge providers" icon="plug" href="/integrations/knowledge-providers/overview">
    modulexdb, Qdrant, Pinecone, Weaviate, and MongoDB Atlas.
  </Card>

  <Card title="Variables & references" icon="braces" href="/workflow-builder/variables-and-references">
    How `{{node_id.field}}` references resolve against run state.
  </Card>
</CardGroup>
