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

# DocumentQA

> Answer caller questions against your documents using RAG

`DocumentQA` answers caller questions against documents using retrieval-augmented generation (RAG). It operates in one of two modes:

* **Server mode (default):** Documents are uploaded to the Guava server and questions are answered server-side. Intended for simple use cases with few documents.
* **Local mode:** Bring your own vector store and generation model for full control over the RAG pipeline. Guava provides ready-made backends for ChromaDB, LanceDB, pgvector, and Pinecone.

## Constructor

<Tabs>
  <Tab title="Python">
    ```python signature theme={null}
    from guava.helpers.rag import DocumentQA

    DocumentQA(
        store=None,             # VectorStore for local mode; omit for server mode
        documents=None,         # str or list[str] — documents to index
        ids=None,               # list[str] — stable IDs for upsert/delete
        chunk_size=5000,        # max chars per chunk (local mode only)
        chunk_overlap=200,      # overlap between chunks (local mode only)
        instructions=None,      # system instruction override
        *,
        generation_model=None,  # GenerationModel (required for local mode)
        namespace=None,         # server-mode namespace for concurrent instances
    )
    ```

    | Parameter | Type | Required | Default | Description |
    | - | - | - | - | - |
    | `store` | `VectorStore \| None` | No | `None` | Vector store for local mode. When omitted, server mode is used automatically. |
    | `documents` | `list[str] \| str \| None` | No | `None` | Documents to index at construction time. Accepts a single string or a list. |
    | `ids` | `list[str] \| None` | No | `None` | Caller-provided IDs for each document, enabling later `upsert_document` / `delete_document`. Length must match `documents` if provided. |
    | `chunk_size` | `int` | No | `5000` | Maximum characters per chunk (local mode only). |
    | `chunk_overlap` | `int` | No | `200` | Overlap between consecutive chunks in characters (local mode only). |
    | `instructions` | `str \| None` | No | `None` | System instruction for the generation model. Overrides the built-in default. |
    | `generation_model` | `GenerationModel \| None` | Local mode | `None` | Generation model for producing answers. Required when `store` is provided. |
    | `namespace` | `str \| None` | Server mode | `None` | Stable string to scope this instance's documents on the server. |
  </Tab>

  <Tab title="TypeScript">
    ```typescript signature theme={null}
    import { DocumentQA } from "@guava-ai/guava-sdk/helpers";

    // Server mode only — local mode (VectorStore backends) is Python-only.
    new DocumentQA({
      documents?,    // string | string[] — documents to index
      ids?,          // string[] — stable IDs for upsert/delete
      instructions?, // string — system instruction override
      namespace?,    // string — required for concurrent instances
    })
    ```

    | Parameter | Type | Required | Description |
    | - | - | - | - |
    | `documents` | `string \| string[]` | No | Documents to index at construction time. Accepts a single string or an array. |
    | `ids` | `string[]` | No | Caller-provided IDs for each document, enabling later `upsertDocument` / `deleteDocument`. Length must match `documents` if provided. |
    | `instructions` | `string` | No | System instruction for the generation model. Overrides the built-in default. |
    | `namespace` | `string` | Concurrent instances | Stable string to scope this instance's documents on the server. |

    <Note>
      Local mode (bring-your-own vector store and generation model) is Python-only. In TypeScript, `DocumentQA` always runs in server mode.
    </Note>
  </Tab>
</Tabs>

<Warning>
  **namespace requirement:** In server mode, `namespace` is required when running multiple `DocumentQA` instances concurrently — even across different files. Without a namespace, concurrent instances may interfere with each other's document stores.
</Warning>

## Methods

<Tabs>
  <Tab title="Python">
    **`ask(question: str, k: int = 5) -> str`** — Retrieve relevant chunks and generate an answer. In server mode, `k` is ignored (the server uses full document context).

    **`upsert_document(key: str, text: str) -> None`** — Add or replace a document by key. Stale chunks from a previously longer document are deleted automatically.

    **`add_document(text: str) -> None`** — Add a document without specifying a key. In server mode, uses a content-derived key (SHA-256 hash).

    **`delete_document(key: str) -> None`** — Delete a previously upserted document by key.

    **`clear() -> None`** — Remove all documents from the store.
  </Tab>

  <Tab title="TypeScript">
    **`ask(question: string): Promise<string>`** — Generate an answer to the question from the indexed documents.

    **`upsertDocument(key: string, text: string): Promise<void>`** — Add or replace a document by key.

    **`addDocument(text: string): Promise<void>`** — Add a document without specifying a key. Uses a content-derived key (SHA-256 hash).

    **`deleteDocument(key: string): Promise<void>`** — Delete a previously upserted document by key.

    **`clear(): Promise<void>`** — Remove all documents from the store.
  </Tab>
</Tabs>

## Available VectorStore Backends (Local Mode)

<Tabs>
  <Tab title="Python">
    | Class | Import | Install | Default Embedding |
    | - | - | - | - |
    | `ChromaVectorStore` | `guava.helpers.chromadb` | `pip install 'guava-sdk[chromadb]'` | Built-in `all-MiniLM-L6-v2` (no API needed) |
    | `LanceDBStore` | `guava.helpers.lancedb` | `pip install 'guava-sdk[lancedb]'` | Required — pass an `EmbeddingModel` (`GenAIEmbedding`, `OpenAIEmbedding`, `PineconeInferenceEmbedding`, or a custom subclass) |
    | `PgVectorStore` | `guava.helpers.pgvector` | `pip install 'guava-sdk[pgvector]'` | Required — pass an `EmbeddingModel` (`GenAIEmbedding`, `OpenAIEmbedding`, `PineconeInferenceEmbedding`, or a custom subclass) |
    | `PineconeVectorStore` | `guava.helpers.pinecone` | `pip install 'guava-sdk[pinecone]'` | `multilingual-e5-large` via Pinecone Inference |

    Embedding and generation provider extras: `pip install 'guava-sdk[genai]'` (Google Gemini) or `pip install 'guava-sdk[openai]'` (OpenAI). See the [Vector Stores](/sdk-reference/vector-stores) reference for full constructor details and backend-specific options.
  </Tab>

  <Tab title="TypeScript">
    Vector store backends are Python-only. See the [Vector Stores](/sdk-reference/vector-stores) reference for details.
  </Tab>
</Tabs>

## Examples

<Tabs>
  <Tab title="Python">
    ```python document_qa_examples.py theme={null}
    from guava.helpers.rag import DocumentQA

    # Server mode (default) — documents stored and queried on Guava's server
    qa = DocumentQA(documents=[policy_text, faq_text], namespace="policy_faq")
    answer = qa.ask("What is the deductible?")

    # Server mode — multiple concurrent instances (use namespace to isolate)
    dental = DocumentQA(documents=dental_docs, namespace="dental")
    restaurant = DocumentQA(documents=restaurant_docs, namespace="restaurant")
    dental.ask("What is the copay?")       # only searches dental docs
    restaurant.ask("Do you have vegan options?")  # only searches restaurant docs

    # Local mode — Gemini (guava-sdk[genai])
    from google import genai
    from guava.helpers.lancedb import LanceDBStore
    from guava.helpers.genai import GenAIEmbedding, GenAIGeneration

    client = genai.Client(vertexai=True, project="my-project", location="us-central1")
    store = LanceDBStore("gs://my-bucket/lancedb", embedding_model=GenAIEmbedding(client=client))
    qa = DocumentQA(store=store, generation_model=GenAIGeneration(client=client))
    qa.upsert_document("policy", my_text)
    answer = qa.ask("What is the deductible?")

    # Local mode — OpenAI (guava-sdk[openai])
    import openai
    from guava.helpers.lancedb import LanceDBStore
    from guava.helpers.openai import OpenAIEmbedding, OpenAIGeneration

    openai_client = openai.OpenAI()  # or AzureOpenAI / custom base_url
    store = LanceDBStore("./lancedb_data", embedding_model=OpenAIEmbedding(client=openai_client))
    qa = DocumentQA(store=store, generation_model=OpenAIGeneration(client=openai_client))
    qa.upsert_document("policy", my_text)
    answer = qa.ask("What is the deductible?")

    # Wiring into an Agent
    import guava
    from guava import Agent

    agent = Agent(name="Support", organization="Acme Corp", purpose="Answer customer questions.")
    document_qa = DocumentQA(documents=some_text)

    @agent.on_question
    def on_question(call: guava.Call, question: str) -> str:
        return document_qa.ask(question)
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript document_qa_examples.ts theme={null}
    import * as guava from "@guava-ai/guava-sdk";
    import { DocumentQA } from "@guava-ai/guava-sdk/helpers";

    // Server mode — documents stored and queried on Guava's server
    const qa = new DocumentQA({ documents: [policyText, faqText], namespace: "policy_faq" });
    const answer = await qa.ask("What is the deductible?");

    // Server mode — multiple concurrent instances (use namespace to isolate)
    const dental = new DocumentQA({ documents: dentalDocs, namespace: "dental" });
    const restaurant = new DocumentQA({ documents: restaurantDocs, namespace: "restaurant" });
    await dental.ask("What is the copay?");            // only searches dental docs
    await restaurant.ask("Do you have vegan options?"); // only searches restaurant docs

    // Note: Local mode (LanceDB, ChromaDB, pgvector, Pinecone) is Python-only.

    // Wiring into an Agent
    const agent = new guava.Agent({
      name: "Support",
      organization: "Acme Corp",
      purpose: "Answer customer questions.",
    });
    const documentQA = new DocumentQA({ documents: [someText] });

    agent.onQuestion(async (_call: guava.Call, question: string) => {
      return documentQA.ask(question);
    })
    ```
  </Tab>
</Tabs>

## Incremental Document Management

<Tabs>
  <Tab title="Python">
    Use `ids` to assign stable keys to documents at construction time, then use `upsert_document`, `delete_document`, and `clear` to manage documents without re-creating the `DocumentQA` instance.

    ```python document_management.py theme={null}
    from guava.helpers.rag import DocumentQA

    # Load initial documents with stable IDs
    qa = DocumentQA(
        documents=[policy_v1, faq_v1, terms_v1],
        ids=["policy", "faq", "terms"],
        namespace="insurance",
    )

    # Later: policy was updated — replace it in-place
    qa.upsert_document("policy", policy_v2)

    # Add a new document without a pre-assigned ID
    qa.add_document(new_bulletin_text)

    # Remove a document that's no longer relevant
    qa.delete_document("terms")

    # Wipe everything and start fresh
    qa.clear()
    ```
  </Tab>

  <Tab title="TypeScript">
    Use `ids` to assign stable keys to documents at construction time, then use `upsertDocument`, `deleteDocument`, and `clear` to manage documents without re-creating the `DocumentQA` instance.

    ```typescript document_management.ts theme={null}
    import { DocumentQA } from "@guava-ai/guava-sdk/helpers";

    // Load initial documents with stable IDs
    const qa = new DocumentQA({
      documents: [policyV1, faqV1, termsV1],
      ids: ["policy", "faq", "terms"],
      namespace: "insurance",
    });

    // Later: policy was updated — replace it in-place
    await qa.upsertDocument("policy", policyV2);

    // Add a new document without a pre-assigned ID
    await qa.addDocument(newBulletinText);

    // Remove a document that's no longer relevant
    await qa.deleteDocument("terms");

    // Wipe everything and start fresh
    await qa.clear();
    ```
  </Tab>
</Tabs>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.