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

# Building a RAG Chat System

> A step-by-step tutorial to build a Retrieval-Augmented Generation chat system using Jinba Flow — from knowledge base setup to deploying a live chat interface

Build a fully functional AI chat system that answers questions using your own documents. This tutorial walks you through every step: creating a knowledge base, building a RAG workflow, and deploying it as a chat interface.

## What You'll Build

A chat system that:

1. Accepts a user question (via chat, API, or AI assistant)
2. Searches your knowledge base for relevant information
3. Uses an AI model to generate an accurate answer grounded in your documents
4. Returns the answer with source references

```mermaid theme={null}
flowchart LR
    Q["💬 User Question"] --> S["🔍 Vector Search<br/>Knowledge Base"]
    S --> C["📋 Context<br/>Assembly"]
    C --> G["🤖 AI Generation<br/>with Context"]
    G --> A["✅ Grounded<br/>Answer"]
```

## Prerequisites

* A Jinba Flow account ([Sign up here](https://flow.jinba.io/))
* Documents to upload — PDFs, DOCX, or text files you want your chat to reference
* Basic familiarity with [Jinba Flow concepts](/en/pages/basics/core-concepts) — Flows, Steps, and Tools

<Note>
  No coding experience is required. You can build the entire system using the chat panel or graph editor. The YAML manifests shown below are for reference and can be copied directly.
</Note>

## Architecture Overview

Before we start building, here's how all the pieces fit together:

```mermaid theme={null}
flowchart TB
    subgraph input["Chat Input"]
        A1["Jinba App Chat"]
        A2["REST API"]
        A3["MCP / AI Assistant"]
    end

    subgraph flow["Jinba Flow — RAG Pipeline"]
        B1["Receive Question<br/>INPUT_TEXT"]
        B2["Search Knowledge Base<br/>JINBA_VECTOR_SEARCH"]
        B3["Generate Answer<br/>OPENAI_INVOKE or ANTHROPIC_INVOKE"]
    end

    subgraph kb["Knowledge Backend"]
        C1["Jinba Knowledge Base"]
        C2["Pinecone"]
        C3["Azure AI Search"]
    end

    A1 & A2 & A3 --> B1
    B1 --> B2
    B2 --> C1
    B2 -.-> C2
    B2 -.-> C3
    C1 & C2 & C3 --> B3
    B3 --> A1 & A2 & A3
```

<Tip>
  This tutorial uses **Jinba Knowledge Base** as the primary backend. For other backends, see [Alternative Backends](#alternative-backends) near the end.
</Tip>

***

## Part 1: Set Up Your Knowledge Base

### Step 1: Create a Knowledge Base

<Steps>
  <Step title="Navigate to Storage">
    In your workspace sidebar, click **Storage**, then select the **Knowledge Bases** tab.

    <img src="https://mintcdn.com/carnot/ULP1fkXhkWwugjih/en/pages/tutorials/images/create-kb-storage.png?fit=max&auto=format&n=ULP1fkXhkWwugjih&q=85&s=575c1eb782b96fe94c494e9555fa0921" alt="Storage Knowledge Bases screen" width="253" height="395" data-path="en/pages/tutorials/images/create-kb-storage.png" />
  </Step>

  <Step title="Create a New Knowledge Base">
    Click **Create Knowledge Base**. Enter a descriptive name (for example, "Product Documentation" or "Company FAQ").

    <img src="https://mintcdn.com/carnot/ULP1fkXhkWwugjih/en/pages/tutorials/images/create-kb-button.png?fit=max&auto=format&n=ULP1fkXhkWwugjih&q=85&s=4348e3adbb7d6022347ce2308097472a" alt="Create knowledge base button" width="184" height="41" data-path="en/pages/tutorials/images/create-kb-button.png" />
  </Step>

  <Step title="Note Your Knowledge Base ID">
    After creation, open your new knowledge base and confirm it appears in the list. In this tutorial, the example knowledge base is named **RAG Tutorial KB**.

    <img src="https://mintcdn.com/carnot/ULP1fkXhkWwugjih/en/pages/tutorials/images/kb-created.png?fit=max&auto=format&n=ULP1fkXhkWwugjih&q=85&s=21bfc98af7e3b368519e4991a4017e50" alt="Knowledge base created" width="398" height="286" data-path="en/pages/tutorials/images/kb-created.png" />
  </Step>
</Steps>

### Step 2: Upload Documents

<Steps>
  <Step title="Open Your Knowledge Base">
    Click on your newly created knowledge base from the Storage page.
  </Step>

  <Step title="Upload Files">
    Click **Add files** to open the upload dialog. Select your PDFs, DOCX, Markdown, or text files from your computer.

    <img src="https://mintcdn.com/carnot/ULP1fkXhkWwugjih/en/pages/tutorials/images/upload-files-kb.png?fit=max&auto=format&n=ULP1fkXhkWwugjih&q=85&s=5f2dacbcdc0cf0d947862eff861ab52b" alt="Uploading files to knowledge base" width="609" height="763" data-path="en/pages/tutorials/images/upload-files-kb.png" />
  </Step>

  <Step title="Wait for Processing">
    Files are automatically processed through the following pipeline:

    | Stage         | What Happens                                  |
    | ------------- | --------------------------------------------- |
    | **Parsing**   | Text is extracted from your documents         |
    | **Chunking**  | Documents are split into searchable chunks    |
    | **Embedding** | Chunks are converted to vector embeddings     |
    | **Indexing**  | Vectors are stored for fast similarity search |

    Wait until all files show **Ready** status.

    <img src="https://mintcdn.com/carnot/ULP1fkXhkWwugjih/en/pages/tutorials/images/file-processing-status.png?fit=max&auto=format&n=ULP1fkXhkWwugjih&q=85&s=9c445cd368e59cddc8aeed5e52257f73" alt="File processing status" width="1645" height="445" data-path="en/pages/tutorials/images/file-processing-status.png" />
  </Step>
</Steps>

<Warning>
  Processing may take a few minutes depending on file size. Do not proceed until your files show a completed status.
</Warning>

### Step 3: Store Your Credentials

Before building the flow, store the required secrets in your workspace.

<Steps>
  <Step title="Navigate to Credentials">
    Go to your [workspace credentials](/en/pages/credentials/index) page.
  </Step>

  <Step title="Add Secrets">
    Add the following secrets:

    | Secret Name         | Value                               | Purpose                                   |
    | ------------------- | ----------------------------------- | ----------------------------------------- |
    | `JINBA_API_TOKEN`   | Your Jinba API token                | Authenticates vector search               |
    | `KNOWLEDGE_BASE_ID` | Your knowledge base ID from Step 1  | Identifies which knowledge base to search |
    | `ANTHROPIC_API_KEY` | Your Anthropic API key *(optional)* | For Claude-based generation               |

    <Note>
      If you do not have an OpenAI API key, you can still use `OPENAI_INVOKE` with [Jinba API credit](/en/pages/tools/ai/openai).
    </Note>
  </Step>
</Steps>

***

## Part 2: Build the RAG Flow

Now let's create the workflow that powers the chat system.

### The Complete Manifest

You can paste this directly into the [YAML Coding Panel](/en/pages/basics/manifest):

```yaml theme={null}
# Step 1: Receive the user's question
- id: user_question
  name: Receive Question
  tool: INPUT_TEXT
  input:
    - name: value
      value: ""

# Step 2: Search the knowledge base for relevant content
- id: search_knowledge
  name: Search Knowledge Base
  tool: JINBA_VECTOR_SEARCH
  config:
    - name: token
      value: "{{secrets.JINBAFLOW_WS_API_KEY}}"
  input:
    - name: query
      value: "{{steps.user_question.result}}"
    - name: knowledgeBaseId
      value: YOUR_KB_ID_HERE
    - name: topK
      value: 5
    - name: threshold
      value: 0.3
  needs:
    - user_question

# Step 3: Generate an answer using the retrieved context
- id: generate_answer
  name: Generate Answer
  tool: OPENAI_INVOKE
  config:
    - name: version
      value: gpt-4o
  input:
    - name: prompt
      value: |
        ## Instructions
        You are a helpful assistant. Answer the user's question based ONLY
        on the provided context. If the context doesn't contain the answer,
        say "I don't have enough information to answer that question."

        Always cite which source document(s) your answer comes from.

        ## Context (from knowledge base)
        {{steps.search_knowledge.results | dump}}

        ## User Question
        {{steps.user_question.result}}

        Please provide a clear, concise answer based on the context above.
  needs:
    - search_knowledge

# Step 4: Output the answer
- id: output_answer
  name: Output Answer
  tool: OUTPUT_TEXT
  input:
    - name: value
      value: "{{steps.generate_answer.result.content}}"
  needs:
    - generate_answer
```

<Tip>
  Fastest path: paste the full YAML manifest above. If you prefer building flows visually, you can also add the four nodes manually in the editor and configure them one by one.
</Tip>

### Alternative: Build the Flow Manually in the Editor

If you want to learn how each node is assembled visually, follow this manual path instead of pasting YAML.

<Steps>
  <Step title="Add the Input Text node">
    Open the node picker, search for **Input Text**, and add it as the first node in the graph.

    <img src="https://mintcdn.com/carnot/ULP1fkXhkWwugjih/en/pages/tutorials/images/manual-add-input-text.png?fit=max&auto=format&n=ULP1fkXhkWwugjih&q=85&s=24c5ffe8071705e11ecb542436f280d2" alt="Manual build - add input text node" width="916" height="632" data-path="en/pages/tutorials/images/manual-add-input-text.png" />

    After adding it, rename the node to **Receive Question** so it matches the tutorial manifest.

    <img src="https://mintcdn.com/carnot/ULP1fkXhkWwugjih/en/pages/tutorials/images/manual-configure-input-text.png?fit=max&auto=format&n=ULP1fkXhkWwugjih&q=85&s=2687049d79a66bf480a2efef06757d2d" alt="Manual build - configure receive question" width="1875" height="942" data-path="en/pages/tutorials/images/manual-configure-input-text.png" />
  </Step>

  <Step title="Add and configure the Vector Search node">
    Click the **+** connector under the first node, search for **Vector Search**, and add the `JINBA_VECTOR_SEARCH` node.

    <img src="https://mintcdn.com/carnot/ULP1fkXhkWwugjih/en/pages/tutorials/images/manual-add-vector-search.png?fit=max&auto=format&n=ULP1fkXhkWwugjih&q=85&s=29998108a99ca1a58a870b061b6f9d8f" alt="Manual build - add vector search node" width="919" height="627" data-path="en/pages/tutorials/images/manual-add-vector-search.png" />

    Then configure it with:

    * **Token**: `JINBAFLOW_WS_API_KEY` secret
    * **Query**: `{{steps.user_question.result}}`
    * **Knowledge Base ID**: your knowledge base ID
    * **Top K**: `5`
    * **Threshold**: `0.3`

          <img src="https://mintcdn.com/carnot/ULP1fkXhkWwugjih/en/pages/tutorials/images/manual-configure-vector-search.png?fit=max&auto=format&n=ULP1fkXhkWwugjih&q=85&s=4e5e3a92047932c174d836544c51052c" alt="Manual build - configure vector search node" width="1898" height="971" data-path="en/pages/tutorials/images/manual-configure-vector-search.png" />
  </Step>

  <Step title="Add and configure the OpenAI Invoke node">
    Add an **Invoke** node and choose `OPENAI_INVOKE`.

    <img src="https://mintcdn.com/carnot/ULP1fkXhkWwugjih/en/pages/tutorials/images/manual-add-openai-invoke.png?fit=max&auto=format&n=ULP1fkXhkWwugjih&q=85&s=6584a31f518d12676ff49850bafd8723" alt="Manual build - add openai invoke node" width="908" height="607" data-path="en/pages/tutorials/images/manual-add-openai-invoke.png" />

    Set the model version to `gpt-4o`, then paste the same prompt shown in the YAML example so the model answers only from retrieved knowledge base context.

    <img src="https://mintcdn.com/carnot/ULP1fkXhkWwugjih/en/pages/tutorials/images/manual-configure-openai-invoke.png?fit=max&auto=format&n=ULP1fkXhkWwugjih&q=85&s=e7d391f06bcbe17b7f31dd876ab10929" alt="Manual build - configure openai invoke node" width="1871" height="948" data-path="en/pages/tutorials/images/manual-configure-openai-invoke.png" />
  </Step>

  <Step title="Add and configure the Output Text node">
    Add an **Output Text** node as the final step.

    <img src="https://mintcdn.com/carnot/ULP1fkXhkWwugjih/en/pages/tutorials/images/manual-add-output-text.png?fit=max&auto=format&n=ULP1fkXhkWwugjih&q=85&s=d0d7bf90ae40481e1f918c87a8743719" alt="Manual build - add output text node" width="904" height="590" data-path="en/pages/tutorials/images/manual-add-output-text.png" />

    Rename it to **Output Answer**, and set its value to:

    ```text theme={null}
    {{steps.generate_answer.result.content}}
    ```

    <img src="https://mintcdn.com/carnot/ULP1fkXhkWwugjih/en/pages/tutorials/images/manual-configure-output-text.png?fit=max&auto=format&n=ULP1fkXhkWwugjih&q=85&s=5379a89fd2d35ecdf7d32a790697a5d6" alt="Manual build - configure output text node" width="1870" height="938" data-path="en/pages/tutorials/images/manual-configure-output-text.png" />
  </Step>
</Steps>

### Step-by-Step Walkthrough

#### Step 1: Receive Question (`INPUT_TEXT`)

```yaml theme={null}
- id: user_question
  name: Receive Question
  tool: INPUT_TEXT
  input:
    - name: value
      value: ""
```

The `INPUT_TEXT` tool creates an input parameter for the flow. When executed manually, it shows a text box. When called via API, this becomes a parameter in the request body. Learn more about [input tools](/en/pages/tools/files/input).

#### Step 2: Search Knowledge Base (`JINBA_VECTOR_SEARCH`)

```yaml theme={null}
- id: search_knowledge
  name: Search Knowledge Base
  tool: JINBA_VECTOR_SEARCH
  config:
    - name: token
      value: "{{secrets.JINBAFLOW_WS_API_KEY}}"
  input:
    - name: query
      value: "{{steps.user_question.result}}"
    - name: knowledgeBaseId
      value: YOUR_KB_ID_HERE
    - name: topK
      value: 5
    - name: threshold
      value: 0.3
  needs:
    - user_question
```

This step performs semantic search — finding content by meaning, not just keywords.

| Parameter   | Value | Why                                |
| ----------- | ----- | ---------------------------------- |
| `topK`      | 5     | Returns the 5 most relevant chunks |
| `threshold` | 0.3   | Filters out low-relevance results  |

The `needs: [user_question]` ensures the search waits for the user's question before executing. See [Step Module Options](/en/pages/basics/step-options) for more details.

<Tip>
  Start with `topK: 5` and `threshold: 0.3`. If answers lack context, increase `topK`. If irrelevant content appears, increase `threshold`. See the [Vector Search reference](/en/pages/tools/jinba/vector_search) for more guidance.
</Tip>

#### Step 3: Generate Answer (LLM)

```yaml theme={null}
- id: generate_answer
  name: Generate Answer
  tool: OPENAI_INVOKE
  config:
    - name: version
      value: gpt-4o
  input:
    - name: prompt
      value: |
        ## Instructions
        You are a helpful assistant. Answer the user's question based ONLY
        on the provided context. If the context doesn't contain the answer,
        say "I don't have enough information to answer that question."

        Always cite which source document(s) your answer comes from.

        ## Context (from knowledge base)
        {{steps.search_knowledge.results | dump}}

        ## User Question
        {{steps.user_question.result}}

        Please provide a clear, concise answer based on the context above.
  needs:
    - search_knowledge
```

The `| dump` filter serializes the search results into the prompt so the LLM can read all retrieved chunks and their sources. Learn more about [Variables & Templates](/en/pages/basics/variables).

#### Step 4: Output Answer (`OUTPUT_TEXT`)

```yaml theme={null}
- id: output_answer
  name: Output Answer
  tool: OUTPUT_TEXT
  input:
    - name: value
      value: "{{steps.generate_answer.result.content}}"
  needs:
    - generate_answer
```

The `OUTPUT_TEXT` step captures the final answer as the flow's output, making it available when calling the flow via API or chat.

<AccordionGroup>
  <Accordion title="Using Anthropic Claude instead of OpenAI">
    Replace the generation step with:

    ```yaml theme={null}
    - id: generate_answer
      name: Generate Answer
      tool: ANTHROPIC_INVOKE
      config:
        - name: version
          value: claude-3-5-sonnet-20241022
        - name: token
          value: "{{secrets.ANTHROPIC_API_KEY}}"
      input:
        - name: prompt
          value: |
            ... (same prompt as above)
      needs:
        - search_knowledge
    ```

    See the [Anthropic tool reference](/en/pages/tools/ai/anthropic) for details.
  </Accordion>

  <Accordion title="Using Google Gemini instead of OpenAI">
    Replace the generation step with:

    ```yaml theme={null}
    - id: generate_answer
      name: Generate Answer
      tool: GEMINI_INVOKE
      config:
        - name: version
          value: gemini-1.5-flash
        - name: token
          value: "{{secrets.GEMINI_API_KEY}}"
      input:
        - name: prompt
          value: |
            ... (same prompt as above)
      needs:
        - search_knowledge
    ```

    See the [Gemini tool reference](/en/pages/tools/ai/gemini) for details.
  </Accordion>
</AccordionGroup>

### Test Your Flow

<Steps>
  <Step title="Execute the Flow">
    Build the four-step flow in the editor, then click the **Run** button in the top right.

    <img src="https://mintcdn.com/carnot/ULP1fkXhkWwugjih/en/pages/tutorials/images/flow-editor-rag.png?fit=max&auto=format&n=ULP1fkXhkWwugjih&q=85&s=4fa71a1d0f99fda1bd01dce7969a2cc7" alt="RAG flow in graph editor" width="1919" height="996" data-path="en/pages/tutorials/images/flow-editor-rag.png" />
  </Step>

  <Step title="Enter a Test Question">
    When prompted, enter a question that your uploaded documents should be able to answer.

    <img src="https://mintcdn.com/carnot/ULP1fkXhkWwugjih/en/pages/tutorials/images/flow-run-input.png?fit=max&auto=format&n=ULP1fkXhkWwugjih&q=85&s=55576aa6617da2825d1fc321040c4455" alt="Run dialog with test question" width="809" height="351" data-path="en/pages/tutorials/images/flow-run-input.png" />
  </Step>

  <Step title="Review Results">
    Check the execution results. The answer should reference information from your knowledge base.

    <img src="https://mintcdn.com/carnot/ULP1fkXhkWwugjih/en/pages/tutorials/images/flow-execution-result.png?fit=max&auto=format&n=ULP1fkXhkWwugjih&q=85&s=71d2582e0d807df4b1ea055059c7a8ea" alt="Execution result" width="621" height="359" data-path="en/pages/tutorials/images/flow-execution-result.png" />
  </Step>
</Steps>

***

## Part 3: Deploy as a Chat Interface

Your RAG flow works. Now make it accessible to users.

<CardGroup cols={3}>
  <Card title="Jinba App Chat" icon="comments">
    Best for: End users who need a ready-made chat UI
  </Card>

  <Card title="REST API" icon="code">
    Best for: Custom applications and integrations
  </Card>

  <Card title="MCP Tool" icon="robot">
    Best for: AI assistant integration
  </Card>
</CardGroup>

### Option A: Jinba App Chat (Recommended)

Deploy your RAG flow as a chat connector in Jinba App for the simplest end-user experience.

<Steps>
  <Step title="Publish Your Flow">
    In the flow editor, click the **Publish** button. A dialog will ask **"Who will trigger this workflow?"**:

    <img src="https://mintcdn.com/carnot/ULP1fkXhkWwugjih/en/pages/tutorials/images/publish-flow-button.png?fit=max&auto=format&n=ULP1fkXhkWwugjih&q=85&s=aa1111704154eef0eccafcdeede5f642" alt="Publish flow" width="307" height="56" data-path="en/pages/tutorials/images/publish-flow-button.png" />

    | Option        | Description                            | When to choose                                |
    | ------------- | -------------------------------------- | --------------------------------------------- |
    | **My team**   | Simple interface anyone can use        | ✅ Choose this for the chat UI path (Option A) |
    | **Engineers** | Call it from code via API              | Choose this for the API path (Option B)       |
    | **Automatic** | Runs on schedule or when events happen | Choose this for scheduled/event-driven flows  |

    Select **My team** and click **Continue →**.

    <img src="https://mintcdn.com/carnot/ULP1fkXhkWwugjih/en/pages/tutorials/images/publish-trigger-dialog.png?fit=max&auto=format&n=ULP1fkXhkWwugjih&q=85&s=7eaece720e39dd9dfe28f0e102a63fbc" alt="Trigger type selection" width="539" height="431" data-path="en/pages/tutorials/images/publish-trigger-dialog.png" />
  </Step>

  <Step title="Understand the Jinba Flow → Jinba App Relationship">
    After selecting "My team", an education screen appears explaining that **Jinba Flow** (where you build) and **Jinba App** (where your team uses it) are separate products:

    * **Separate products, by design** — Jinba Flow is the builder; Jinba App is the chat interface your team uses
    * **Enterprise-grade security** — Jinba App has its own authentication and access controls
    * **Simple for your team** — No code, no complexity — just a familiar chat interface

    Click **Got it, continue** to proceed to the MCP setup.

    <img src="https://mintcdn.com/carnot/ULP1fkXhkWwugjih/en/pages/tutorials/images/flow-app-education.png?fit=max&auto=format&n=ULP1fkXhkWwugjih&q=85&s=40c6ecb5af9111c4c3ae4ed745bbc298" alt="Flow and App relationship screen" width="532" height="696" data-path="en/pages/tutorials/images/flow-app-education.png" />
  </Step>

  <Step title="Enable MCP and Connect to Jinba App">
    The **Create an MCP** dialog appears. This shows a preview of how your flow will appear as a chat tool:

    * A chat preview showing `@your_flow_name` with a description
    * A **Demo** button to preview the chat experience
    * An **Enable MCP for this flow** toggle

          <img src="https://mintcdn.com/carnot/ULP1fkXhkWwugjih/en/pages/tutorials/images/create-mcp-dialog.png?fit=max&auto=format&n=ULP1fkXhkWwugjih&q=85&s=1b051bc42524ebabfbd2b52511759a96" alt="Create MCP dialog" width="527" height="376" data-path="en/pages/tutorials/images/create-mcp-dialog.png" />

    <Warning>
      You **must** turn on the **Enable MCP for this flow** toggle. This is what creates the connection between Jinba Flow and Jinba App — the "Connect with Jinba App" button only appears after you enable it.
    </Warning>

    Once enabled, additional options appear:

    * **Workspace Token** — used for authentication
    * **Connection Snippet** — JSON config for MCP clients (Claude Desktop, Cursor, etc.)
    * **Connect with Jinba App** button — click this to open the connector in Jinba App

    <Tip>
      Enabling MCP also lets AI assistants (Claude, Cursor, etc.) call this flow as a tool — you get both Jinba App chat **and** MCP tool access with a single toggle.
    </Tip>

    See [Publish](/en/pages/basics/publish) for details.
  </Step>

  <Step title="Configure MCP Connection Settings">
    After enabling MCP, you'll be taken to the **MCP → Connect** tab. This page has several important sections:

    1. **Your Token** — your workspace authentication token (keep this secret)
    2. **1-Click Connect** — click **Connect** to instantly link this flow to Jinba App
    3. **Visibility** — defaults to "Unlisted" (only users in your access rules can use it). Change to "Listed" if you want all workspace members to see it
    4. **Access Scope Settings** — configure who can access this tool using JWT claims (e.g., email whitelist)
    5. **MCP Configuration JSON Snippet** — copy this to use the flow in external MCP clients (Claude Desktop, Cursor, etc.)

           <img src="https://mintcdn.com/carnot/ULP1fkXhkWwugjih/en/pages/tutorials/images/mcp-connect-tab.png?fit=max&auto=format&n=ULP1fkXhkWwugjih&q=85&s=e935a9ea40352850789e06dbdb14401d" alt="MCP Connect tab" width="1670" height="1053" data-path="en/pages/tutorials/images/mcp-connect-tab.png" />

    <Warning>
      You **must** click the **1-Click Connect** button to make the flow available as a tool in Jinba App. Without this step, the tool won't appear in Jinba App even though MCP is enabled.
    </Warning>

    <Tip>
      Add your team members' emails to the **Access Scope Settings** so they can also use this tool. Click **+ Add Rule** to add more email rules.
    </Tip>
  </Step>

  <Step title="Chat with Your RAG System">
    Open [Jinba App](https://app.jinba.io/) and start a new chat:

    1. Click **New Chat**
    2. Click the **connectors** icon (⚙️) at the bottom of the chat input
    3. In the "Search agents and connectors..." dropdown, find your workspace's **MCP connector** (e.g., "Tutorial Demonstrations MCP ... 1 tool")
    4. Click into the MCP connector to see your **RAG Chat Demo** tool listed
    5. Select the tool — it appears as a tag in the chat input bar
    6. Type your question and press Enter

           <img src="https://mintcdn.com/carnot/ULP1fkXhkWwugjih/en/pages/tutorials/images/jinba-app-connector-select.png?fit=max&auto=format&n=ULP1fkXhkWwugjih&q=85&s=09d13f33065bdec5d3cf1a4bbe88cec2" alt="Connector selection" width="418" height="269" data-path="en/pages/tutorials/images/jinba-app-connector-select.png" />

    The tool runs automatically — you'll see the **Arguments** (your `user_question`) and **Result** (the RAG response content) in an expandable section, followed by the AI's formatted answer.

    <img src="https://mintcdn.com/carnot/ULP1fkXhkWwugjih/en/pages/tutorials/images/jinba-app-chat-rag.png?fit=max&auto=format&n=ULP1fkXhkWwugjih&q=85&s=1436648a50fc55ad2658e8e6ff396b46" alt="Chat with RAG in Jinba App" width="793" height="922" data-path="en/pages/tutorials/images/jinba-app-chat-rag.png" />

    <Tip>
      You can also use **Auto Select** mode — Jinba App will automatically choose the right tool based on your question, so you don't need to manually select the connector each time.
    </Tip>

    See [Jinba Flow Connectors](/en/pages/jinba_app/connectors/jinbaflow) for the full guide.
  </Step>
</Steps>

<Tip>
  You can also create a [Jinba App Agent](/en/pages/jinba_app/agents/overview) that bundles this connector with custom instructions.
</Tip>

### Option B: REST API

Expose your RAG flow as an API endpoint for custom applications.

<Steps>
  <Step title="Publish Your Flow">
    Follow the same publish steps as above, but select **Engineers** in the "Who will trigger this workflow?" dialog instead. This optimizes the flow for API access.
  </Step>

  <Step title="Get Your API Key">
    After publishing, navigate to your flow's settings to find the auto-generated API key.

    <img src="https://mintcdn.com/carnot/ULP1fkXhkWwugjih/en/pages/tutorials/images/api-key-location.png?fit=max&auto=format&n=ULP1fkXhkWwugjih&q=85&s=60d8cb59e5faa22595866439488ba4d5" alt="API key location" width="1914" height="951" data-path="en/pages/tutorials/images/api-key-location.png" />
  </Step>

  <Step title="Call the API">
    ```bash theme={null}
    curl -X POST https://api.jinba.dev/api/v2/external/flows/{flow-id}/published-run \
      -H "Authorization: Bearer YOUR_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "args": [
          {"name": "user_question", "value": "What is your return policy?"}
        ],
        "mode": "sync"
      }'
    ```

    **Python example:**

    ```python theme={null}
    import requests

    response = requests.post(
        "https://api.jinba.dev/api/v2/external/flows/{flow-id}/published-run",
        headers={
            "Authorization": "Bearer YOUR_API_KEY",
            "Content-Type": "application/json"
        },
        json={
            "args": [
                {"name": "user_question", "value": "What is your return policy?"}
            ],
            "mode": "sync"
        }
    )
    answer = response.json()
    print(answer)
    ```

    See the full [API reference](/en/pages/basics/api) for async mode, error handling, and more.
  </Step>
</Steps>

### Option C: MCP Tool (AI Assistant Integration)

Make your RAG flow available as a tool for AI assistants like Claude Desktop.

<Steps>
  <Step title="Publish as MCP">
    Publish your flow with MCP enabled. Navigate to the **MCP** tab in your workspace settings.

    <img src="https://mintcdn.com/carnot/ULP1fkXhkWwugjih/en/pages/tutorials/images/mcp-connect-tab.png?fit=max&auto=format&n=ULP1fkXhkWwugjih&q=85&s=e935a9ea40352850789e06dbdb14401d" alt="MCP configuration" width="1670" height="1053" data-path="en/pages/tutorials/images/mcp-connect-tab.png" />
  </Step>

  <Step title="Configure Your AI Assistant">
    Add the Jinba Flow MCP server to your AI assistant's configuration:

    ```json theme={null}
    {
      "mcpServers": {
        "jinbaflow": {
          "command": "npx",
          "args": [
            "-y",
            "supergateway",
            "--streamableHttp",
            "https://api.jinba.io/api/v2/workspaces/YOUR_WORKSPACE_ID/mcp",
            "--header",
            "Authorization: Bearer YOUR_TOKEN"
          ]
        }
      }
    }
    ```

    See the [MCP guide](/en/pages/basics/mcp) for the full setup process.
  </Step>

  <Step title="Use from Your AI Assistant">
    Your RAG flow now appears as a tool. The AI assistant can invoke it to answer questions using your knowledge base.
  </Step>
</Steps>

***

## Part 4: Advanced Patterns

### Multi-Step RAG with Query Refinement

For complex questions, add a refinement step that improves search results:

```yaml theme={null}
- id: user_question
  name: Receive Question
  tool: INPUT_TEXT
  input:
    - name: value
      value: ""

- id: initial_search
  name: Initial Search
  tool: JINBA_VECTOR_SEARCH
  config:
    - name: token
      value: "{{secrets.JINBAFLOW_WS_API_KEY}}"
  input:
    - name: query
      value: "{{steps.user_question.result}}"
    - name: knowledgeBaseId
      value: YOUR_KB_ID_HERE
    - name: topK
      value: 10
  needs:
    - user_question

- id: refine_query
  name: Refine Query
  tool: OPENAI_INVOKE
  config:
    - name: version
      value: gpt-4o
  input:
    - name: prompt
      value: |
        Based on the initial search results, generate a more specific search query.

        Original Question: {{steps.user_question.result}}

        Initial Results:
        {{steps.initial_search.results | dump}}

        Generate a refined search query that will find more specific information.
        Output ONLY the refined query, nothing else.
  needs:
    - initial_search

- id: refined_search
  name: Refined Search
  tool: JINBA_VECTOR_SEARCH
  config:
    - name: token
      value: "{{secrets.JINBAFLOW_WS_API_KEY}}"
  input:
    - name: query
      value: "{{steps.refine_query.result.content}}"
    - name: knowledgeBaseId
      value: YOUR_KB_ID_HERE
    - name: topK
      value: 5
    - name: threshold
      value: 0.4
  needs:
    - refine_query

- id: final_answer
  name: Generate Final Answer
  tool: OPENAI_INVOKE
  config:
    - name: version
      value: gpt-4o
  input:
    - name: prompt
      value: |
        Answer the user's question using the refined search results.

        Question: {{steps.user_question.result}}

        Refined Search Results:
        {{steps.refined_search.results | dump}}

        Provide a detailed, accurate answer with source citations.
  needs:
    - refined_search

- id: output_answer
  name: Output Answer
  tool: OUTPUT_TEXT
  input:
    - name: value
      value: "{{steps.final_answer.result.content}}"
  needs:
    - final_answer
```

### Handling No Results Found

Use [conditional execution](/en/pages/basics/step-options) to handle cases where the knowledge base has no relevant content:

```yaml theme={null}
- id: check_results
  name: Check Results
  tool: PYTHON_SANDBOX_RUN
  input:
    - name: code
      value: |
        results = {{steps.search_knowledge.result}}
        has_results = len(results.get('results', [])) > 0
        print(has_results)
    - name: data_type
      value: STRING
  needs:
    - search_knowledge

- id: generate_answer
  name: Generate Answer
  tool: OPENAI_INVOKE
  config:
    - name: version
      value: gpt-4o
  input:
    - name: prompt
      value: |
        ... standard RAG prompt with context ...
  needs:
    - check_results
  when: "'{{steps.check_results.result}}' == 'True'"

- id: no_results_response
  name: No Results Response
  tool: PYTHON_SANDBOX_RUN
  input:
    - name: code
      value: |
        result = "I couldn't find relevant information in the knowledge base to answer your question. Please try rephrasing your question or contact support for assistance."
    - name: data_type
      value: STRING
  needs:
    - check_results
  when: "'{{steps.check_results.result}}' == 'False'"
```

### Keeping Your Knowledge Base Updated

Create a scheduled flow that automatically updates your knowledge base with new documents:

```yaml theme={null}
- id: fetch_new_docs
  name: fetch_new_docs
  tool: PYTHON_SANDBOX_RUN
  input:
    - name: code
      value: |
        new_docs = [
            "https://example.com/updated-faq.pdf",
            "https://example.com/new-product-guide.pdf"
        ]
        result = new_docs
    - name: data_type
      value: STRING

- id: add_to_kb
  name: Add to Knowledge Base
  tool: JINBA_KNOWLEDGE_BASE_FILE_ADD
  forEach: "{{steps.fetch_new_docs.result}}"
  config:
    - name: token
      value: "{{secrets.JINBAFLOW_WS_API_KEY}}"
  input:
    - name: knowledgeBaseId
      value: YOUR_KB_ID_HERE
    - name: file
      value: "{{item}}"
    - name: executionMode
      value: "SYNCHRONOUS"
    - name: chunkerSettings
      value:
        chunkSize: 512
        chunkOverlap: 128
```

You can [schedule this flow](/en/pages/basics/scheduling) to run daily or weekly.

***

## Alternative Backends

The primary tutorial uses Jinba Knowledge Base, but two additional backends are available for teams with specific requirements.

### When to Choose Each Backend

```mermaid theme={null}
flowchart TD
    Start["Which backend<br/>should I use?"] --> Q1{"Enterprise with<br/>Azure ecosystem?"}
    Q1 -->|Yes| Azure["☁️ Azure AI Search<br/>Enterprise"]
    Q1 -->|No| Q2{"Need metadata<br/>filtering, namespaces,<br/>or reranking?"}
    Q2 -->|Yes| Pinecone["🌲 Pinecone"]
    Q2 -->|No| Q3{"Want simplest<br/>possible setup?"}
    Q3 -->|Yes| Jinba["⚡ Jinba Knowledge Base"]
    Q3 -->|No| Pinecone
```

| Feature                 | Jinba Knowledge Base        | Pinecone                     | Azure AI Search                         |
| ----------------------- | --------------------------- | ---------------------------- | --------------------------------------- |
| **Setup complexity**    | ⭐ Simplest                  | ⭐⭐ Moderate                  | ⭐⭐⭐ Advanced                            |
| **External dependency** | None                        | Pinecone account             | Azure subscription                      |
| **Document upload**     | UI + API                    | API only                     | Azure portal / ADLS                     |
| **Metadata filtering**  | ❌                           | ✅ Rich filter syntax         | ✅ OData filters                         |
| **Namespace isolation** | ❌                           | ✅                            | ✅ Indexes                               |
| **Reranking**           | ❌                           | ✅ Built-in models            | ✅ Semantic ranker                       |
| **Indexer / pipeline**  | Automatic                   | Manual                       | ✅ Built-in indexers                     |
| **Cost**                | Included in Jinba plan      | Separate Pinecone billing    | Azure billing                           |
| **Best for**            | Most use cases, quick start | Advanced search requirements | Enterprise / Azure-native organizations |

### Alternative A: Pinecone

If you need metadata filtering, namespace isolation, or reranking, use [Pinecone](/en/pages/tools/search/pinecone) as your vector backend.

#### Pinecone RAG Manifest

Replace the search step with Pinecone:

```yaml theme={null}
- id: search_pinecone
  name: Search Pinecone
  tool: PINECONE_QUERY
  config:
    - name: apiKey
      value: "{{secrets.PINECONE_API_KEY}}"
  input:
    - name: indexName
      value: my-knowledge-base
    - name: query
      value: "{{steps.user_question.result}}"
    - name: topK
      value: 5
    - name: includeMetadata
      value: true
    - name: rerankModel
      value: bge-reranker-v2-m3
    - name: rerankTopN
      value: 3
  needs:
    - user_question
```

Then adjust the generation step to use Pinecone's output format:

```yaml theme={null}
- id: generate_answer
  name: Generate Answer
  tool: OPENAI_INVOKE
  config:
    - name: version
      value: gpt-4o
  input:
    - name: prompt
      value: |
        You are a helpful assistant. Answer based on the provided context.

        ## User Question
        {{steps.user_question.result}}

        ## Relevant Documentation
        {{steps.search_pinecone.result.matches | dump}}

        Answer accurately based on the documentation above.
  needs:
    - search_pinecone
```

See the full [Pinecone tool reference](/en/pages/tools/search/pinecone) for index creation and document upsert.

### Alternative B: Azure AI Search (Enterprise)

For enterprise organizations already using the Azure ecosystem, Jinba Flow supports **Azure AI Search** as an external knowledge base backend. This option provides advanced indexing, semantic ranking, and integration with Azure Data Lake Storage Gen2.

<Warning>
  Azure AI Search integration is an **enterprise feature**. Contact your Jinba administrator or the Jinba sales team to enable this for your workspace.
</Warning>

#### How It Works

Azure AI Search integration operates differently from the built-in knowledge base:

1. **Documents are stored in Azure** — uploaded to Azure Data Lake Storage Gen2
2. **Indexing is handled by Azure** — Azure AI Search indexers process and index documents
3. **Search queries go through Azure** — either directly or via Azure API Management (APIM)
4. **Results flow back to Jinba Flow** — where the LLM generates answers

```mermaid theme={null}
flowchart LR
    Upload["📄 Upload Document"] --> ADLS["Azure Data Lake<br/>Storage Gen2"]
    ADLS --> Indexer["Azure AI Search<br/>Indexer"]
    Indexer --> Index["Azure AI Search<br/>Index"]
    Query["🔍 User Query"] --> Index
    Index --> Results["📋 Search Results"]
    Results --> LLM["🤖 LLM Generation"]
```

#### Setup Overview

<Steps>
  <Step title="Configure Azure Connection">
    In your workspace settings, navigate to the **External Knowledge Base** configuration. You can connect in two modes:

    | Mode            | When to Use                                                      |
    | --------------- | ---------------------------------------------------------------- |
    | **APIM Mode**   | Routes through Azure API Management — recommended for production |
    | **Direct Mode** | Connects directly to Azure AI Search — simpler for development   |
  </Step>

  <Step title="Set Up Azure Resources">
    Ensure you have:

    * An Azure AI Search service with an index configured
    * Azure Data Lake Storage Gen2 for document storage
    * API keys or APIM subscription keys
    * An indexer configured to process uploaded documents
  </Step>

  <Step title="Upload Documents">
    Upload documents through the Jinba workspace UI. Files are automatically sent to Azure Data Lake Storage, and the configured indexer processes them into the search index.
  </Step>

  <Step title="Search in Your Flow">
    The search step uses the External Knowledge Base configuration from your workspace. The exact tool and parameters depend on your enterprise deployment.
  </Step>
</Steps>

#### Key Configuration Options

| Setting             | Description                           |
| ------------------- | ------------------------------------- |
| **Endpoint URL**    | Azure AI Search or APIM endpoint      |
| **API Key**         | Authentication key                    |
| **Index API Path**  | Path for index operations             |
| **Search API Path** | Path for search queries               |
| **ADLS API Path**   | Path for file storage operations      |
| **Indexer Name**    | Indexer to trigger after file uploads |

<Note>
  Connection settings can be configured per workspace through the UI, with environment variables as fallbacks.
</Note>

#### Azure AI Search Advantages

* **Semantic ranking**: Azure's built-in semantic ranker improves result relevance
* **Hybrid search**: Combine vector search with keyword search
* **Built-in indexers**: Automatically extract and index content from various file formats
* **Enterprise compliance**: Data stays within your Azure tenant
* **Azure ecosystem integration**: Works well with other Azure services such as Azure OpenAI

***

## Tuning & Best Practices

### Chunking Configuration

When adding files, tune chunk parameters for your content:

| Content Type        | Chunk Size | Overlap | Why                           |
| ------------------- | ---------- | ------- | ----------------------------- |
| FAQ / Short answers | 256–512    | 64      | Precise, focused retrieval    |
| Technical docs      | 512–1024   | 128     | Balance precision and context |
| Long-form content   | 1024–2048  | 256     | Maintain narrative context    |

### Similarity Threshold Guide

| Threshold | Behavior                                 | Use When                       |
| --------- | ---------------------------------------- | ------------------------------ |
| 0.7–1.0   | Very strict, near-exact matches only     | Precise factual lookups        |
| 0.4–0.7   | High relevance, closely related          | Most Q\&A use cases            |
| 0.2–0.4   | Moderate, may include tangential results | Exploratory or broad questions |
| 0.0–0.2   | Very broad, many results                 | Not recommended for production |

### Prompt Engineering Tips

1. **Be explicit about grounding**: Tell the LLM to answer only from the provided context
2. **Request citations**: Ask the LLM to reference source filenames
3. **Handle uncertainty**: Instruct the LLM to say "I don't know" when context is insufficient
4. **Set the tone**: Add persona instructions for your use case (formal, casual, technical)

***

## What's Next?

<CardGroup cols={2}>
  <Card title="Knowledge Base Docs" icon="database" href="/en/pages/basics/knowledge">
    Deep dive into knowledge base management, chunking, and RAG patterns
  </Card>

  <Card title="Vector Search Reference" icon="magnifying-glass" href="/en/pages/tools/jinba/vector_search">
    Full parameter reference and advanced search examples
  </Card>

  <Card title="Pinecone Reference" icon="database" href="/en/pages/tools/search/pinecone">
    External vector database with filtering and reranking
  </Card>

  <Card title="API Reference" icon="code" href="/en/pages/basics/api">
    Complete guide to calling flows via REST API
  </Card>

  <Card title="MCP Integration" icon="plug" href="/en/pages/basics/mcp">
    Connect flows to AI assistants via MCP
  </Card>

  <Card title="Jinba App Agents" icon="robot" href="/en/pages/jinba_app/agents/overview">
    Wrap your RAG flow in an agent for enhanced chat
  </Card>
</CardGroup>
