---
title: सहायक
description: >-
  आपके डॉक्स पर आधारित एक इन-पेज सहायक — सुझाए गए प्रश्न, कस्टम निर्देश, रिट्रीवल आकार, Vercel AI Gateway से लेकर किसी भी OpenAI-संगत एंडपॉइंट तक के प्रदाता एडाप्टर, और इसके लिए आवश्यक सर्वर आउटपुट।
---

एक ऐसा सहायक जोड़ें जो पाठकों के प्रश्नों का उत्तर एक इन-पेज चैट पैनल में दे, जो एक स्ट्रीमिंग सर्वर एंडपॉइंट और [AI SDK](https://ai-sdk.dev) द्वारा समर्थित हो। यह ऑप्ट-इन है, और जब तक आप इसे चालू नहीं करते तब तक स्टैटिक डॉक्स पूरी तरह स्टैटिक ही रहते हैं:

```ts blume.config.ts lineNumbers
ai: {
  assistant: {
    enabled: true,
  },
}
```

कुछ और लिखे बिना, उत्तर `openai/gpt-5.5` से [Vercel AI Gateway](#adapters) के माध्यम से स्ट्रीम होते हैं। किसी [एडाप्टर](#adapters) के साथ कोई भिन्न मॉडल या प्रदाता चुनें।

## सुझाए गए प्रश्न [#suggested-questions]

खाली अवस्था में कुछ शुरुआती प्रॉम्प्ट जोड़ें। प्रत्येक एक क्लिक करने योग्य सुझाव के रूप में प्रस्तुत होता है — किसी एक पर क्लिक करके उसे भेजें — और लेबल के साथ एक वैकल्पिक [Lucide आइकन](/docs/content/components#icon) दिखता है:

```ts blume.config.ts lineNumbers
ai: {
  assistant: {
    enabled: true,
    suggestions: [
      { label: "What is Blume?", icon: "rocket" },
      { label: "How do I write a docs page?", icon: "file-text" },
      { label: "How do I configure the theme?", icon: "settings" },
    ],
  },
}
```

`label` वह प्रश्न है जो पूछा जाता है; `icon` वैकल्पिक है। `suggestions` को अनसेट (या खाली) छोड़ दें और पैनल एक सादे इनपुट के साथ खुलेगा।

## कस्टम निर्देश [#custom-instructions]

`instructions` के साथ अपना स्वयं का सिस्टम-प्रॉम्प्ट टेक्स्ट जोड़ें — पहचान, भाषा, लहजा, या कुछ और जिसे सहायक को ध्यान में रखना चाहिए:

```ts blume.config.ts lineNumbers
ai: {
  assistant: {
    enabled: true,
    instructions:
      "You are Bloomy, the Acme docs assistant. Answer in the language the question was asked in, and keep answers under three paragraphs.",
  },
}
```

आपका टेक्स्ट अंतर्निहित निर्देशों को प्रतिस्थापित करने के बजाय उनके **साथ जोड़ा जाता है**: अंतर्निहित हिस्से में [ग्राउंडिंग](#grounding) अनुबंध होता है — केवल पुनःप्राप्त पृष्ठों से उत्तर दें, उन्हें Markdown लिंक के रूप में उद्धृत करें — जिस पर चैट पैनल के उद्धरण निर्भर करते हैं, इसलिए आप जो भी जोड़ें, वह बरकरार रहता है।

## ग्राउंडिंग [#grounding]

सहायक **आपके डॉक्स पर आधारित** है। प्रत्येक प्रश्न के लिए यह सबसे प्रासंगिक पृष्ठ पुनःप्राप्त करता है — उसी लेक्सिकल [Orama](/docs/configuration/search) इंडेक्स का उपयोग करते हुए जो ऑन-पेज खोज को शक्ति देता है — और उन्हें मॉडल के सिस्टम प्रॉम्प्ट में इंजेक्ट करता है, ताकि उत्तर मॉडल के अपने ज्ञान के बजाय आपकी सामग्री से आएँ। सहायक को निर्देश दिया जाता है कि वह केवल पुनःप्राप्त पृष्ठों से उत्तर दे, बताए कि कब कोई बात कवर नहीं है, और जिन पृष्ठों से उसने सामग्री ली है उन्हें उद्धृत करे।

पाठक जिस पृष्ठ पर वर्तमान में है, उसे सबसे पहले संदर्भ में जोड़ा जाता है और उसका उपयोग रिट्रीवल को उस पृष्ठ की भाषा तक सीमित करने के लिए किया जाता है, ताकि उत्तर वहीं प्रासंगिक रहें जहाँ पाठक डॉक्स में हैं। रिट्रीवल अनुरोध के समय बिल्ड में समाहित एक स्नैपशॉट से चलता है, इसलिए यह आपके [search](/docs/configuration/search) प्रदाता की परवाह किए बिना काम करता है — तब भी जब `search: false` हो — और इसे किसी कॉन्फ़िगरेशन की आवश्यकता नहीं होती।

ग्राउंडिंग **[Inkeep](#inkeep)** को छोड़कर हर एडाप्टर के लिए चालू है, जो अपने डैशबोर्ड में आपके द्वारा इंडेक्स की गई सामग्री पर अपना स्वयं का रिट्रीवल चलाता है।

## रिट्रीवल आकार [#retrieval-size]

एक प्रश्न कितना दस्तावेज़ीकरण साथ ले जाता है, यह सबसे बड़ा कारक है कि पाठक को पहले शब्द के लिए कितनी देर प्रतीक्षा करनी पड़ती है: मॉडल एक टोकन उत्सर्जित करने से पहले हर इंजेक्ट किए गए वर्ण को पढ़ता है। किसी होस्टेड फ्रंटियर मॉडल पर यह अदृश्य होता है, लेकिन सेल्फ-होस्टेड बैकएंड पर यह हावी हो जाता है। `retrieval` इसका आकार तय करता है:

```ts blume.config.ts lineNumbers
ai: {
  assistant: {
    enabled: true,
    retrieval: {
      maxResults: 3, // fewer pages retrieved per question
      excerptChars: 1200, // shorter excerpt from each one
      contextBudget: 3000, // smaller total injection
    },
  },
}
```

| विकल्प          | डिफ़ॉल्ट | विवरण                                         |
| --------------- | -------- | --------------------------------------------- |
| `maxResults`    | `6`      | प्रति प्रश्न पुनःप्राप्त किए गए दस्तावेज़।    |
| `excerptChars`  | `2000`   | प्रत्येक पुनःप्राप्त पृष्ठ से रखे गए वर्ण।    |
| `contextBudget` | `10000`  | सभी अंशों को मिलाकर, कुल इंजेक्ट किए गए वर्ण। |

ये तीनों आपस में विनिमेय नहीं हैं। `contextBudget` पूरे इंजेक्शन की सीमा तय करता है, `excerptChars` तय करता है कि किसी एक लंबे पृष्ठ में उसका अंश कितनी गहराई तक पहुँचता है — इसे तब बढ़ाएँ जब एक ही पृष्ठ में पूरा उत्तर हो और अंश उसे काट दे — और `maxResults` सीमित करता है कि रिट्रीवल कितने पृष्ठ जोड़ता है। पाठक जिस पृष्ठ को देख रहा है, उसे पुनःप्राप्त पृष्ठों के ऊपर इंजेक्ट किया जाता है, इसलिए एक उत्तर `maxResults` से अधिकतम एक पृष्ठ अधिक उद्धृत कर सकता है।

डिफ़ॉल्ट मान किसी होस्टेड मॉडल के लिए उपयुक्त हैं। जब आप अपने स्वयं के हार्डवेयर से सेवा दे रहे हों और टाइम-टू-फ़र्स्ट-टोकन रिकॉल से अधिक मायने रखता हो, तो इन्हें कम करें; उत्तर दोनों ही स्थितियों में आधारित रहते हैं, और सहायक को निर्देश दिया जाता है कि खाली जगह भरने के बजाय यह बताए कि कब कोई बात कवर नहीं है।

## बाहरी एंडपॉइंट [#external-endpoint]

क्या आपके पास पहले से AI के लिए एक API बैकएंड है? पैनल को उस पर इंगित करें और डॉक्स बिल्ड को स्टैटिक बनाए रखें:

```ts blume.config.ts lineNumbers
ai: {
  assistant: {
    enabled: true,
    endpoint: "https://api.example.com/v1/docs/ask",
  },
}
```

Blume वही `POST` बॉडी भेजता है जो उसका अंतर्निहित रूट भेजता है:

```json
{
  "messages": [{ "role": "user", "content": "How do I deploy?" }],
  "page": { "path": "/deployment" }
}
```

एक सफल प्रतिक्रिया लौटाएँ जिसकी बॉडी एक सादी UTF-8 टेक्स्ट स्ट्रीम हो। यदि एंडपॉइंट किसी अन्य ओरिजिन पर है, तो CORS के साथ डॉक्स ओरिजिन को अनुमति दें: `OPTIONS` और `POST` स्वीकार करें, `content-type` अनुरोध हेडर की अनुमति दें, और प्रीफ़्लाइट तथा स्ट्रीम की गई प्रतिक्रिया दोनों पर CORS हेडर लौटाएँ। `endpoint` सेट होने पर, Blume चैट UI तो जनरेट करता है लेकिन कोई सर्वर रूट, ग्राउंडिंग स्नैपशॉट, प्रदाता निर्भरता, या प्रदाता-सीक्रेट चेतावनी नहीं; रिट्रीवल, प्रमाणीकरण, दर सीमन, मॉडल एक्सेस, और उद्धरण आपके बैकएंड के अधीन होते हैं। इसके साथ सेट किए गए किसी एडाप्टर को अनदेखा कर दिया जाता है।

## क्रॉस-ओरिजिन कॉलर [#cross-origin-callers]

जनरेट किया गया एंडपॉइंट इन-पेज सहायक को उसके अपने ओरिजिन पर उत्तर देता है। इसे किसी अन्य साइट से भी कॉल करने के लिए — मान लीजिए, एक मार्केटिंग पृष्ठ जिसमें एक आस्क बॉक्स है — उस साइट के ओरिजिन को `cors` में सूचीबद्ध करें:

```ts blume.config.ts lineNumbers
ai: {
  assistant: {
    enabled: true,
    cors: ["https://www.example.com"],
  },
}
```

तब यह रूट ब्राउज़र के `OPTIONS` प्रीफ़्लाइट का उत्तर देता है और हर प्रतिक्रिया पर एक सूचीबद्ध ओरिजिन का नाम देता है — स्ट्रीम किया गया उत्तर और त्रुटि स्टेटस दोनों पर, ताकि कॉलर अस्वीकृत बॉडी को प्रदाता की विफलता से अलग पहचान सके। जो ओरिजिन सूचीबद्ध नहीं हैं उन्हें कोई हेडर नहीं मिलता और वे ब्राउज़र के सेम-ओरिजिन नियम के अधीन रहते हैं। प्रत्येक प्रविष्टि को उसके ओरिजिन तक सीमित कर दिया जाता है, इसलिए `https://www.example.com/docs/` और `https://www.example.com` का एक ही अर्थ है। किसी भी पृष्ठ को यह रूट कॉल करने देने के लिए, ओरिजिन के बजाय `"*"` सूचीबद्ध करें।

कॉलर वही `POST` बॉडी भेजता है जिसका वर्णन [बाहरी एंडपॉइंट](#external-endpoint) अनुबंध करता है और वही टेक्स्ट स्ट्रीम वापस पढ़ता है। इसे `content-type: application/json` हेडर के साथ JSON के रूप में भेजें:

```ts
const response = await fetch("https://docs.example.com/api/ask", {
  body: JSON.stringify({
    messages: [{ role: "user", content: "How do I deploy?" }],
  }),
  headers: { "content-type": "application/json" },
  method: "POST",
});
```

कंटेंट टाइप मायने रखता है: Astro की क्रॉस-साइट अनुरोध जाँच ऐसे क्रॉस-ओरिजिन `POST` को, जिसमें कोई कंटेंट टाइप न हो या `text/plain` जैसा फ़ॉर्म-सदृश टाइप हो, रूट चलने से पहले ही 403 के साथ अस्वीकार कर देती है, और उस प्रतिक्रिया पर कोई CORS हेडर नहीं होता, इसलिए ब्राउज़र इसे किसी स्टेटस के बजाय एक नेटवर्क त्रुटि के रूप में रिपोर्ट करता है। प्रीफ़्लाइट उन सभी अनुरोध हेडरों की अनुमति देता है जो कॉलर माँगता है, इसलिए अपने स्वयं के हेडर जोड़ने वाले किसी फ़ेच रैपर को किसी अतिरिक्त कॉन्फ़िगरेशन की आवश्यकता नहीं होती।

`cors` केवल जनरेट किए गए रूट को प्रभावित करता है; किसी बाहरी `endpoint` के साथ CORS उस बैकएंड का काम है, और दोनों को सेट करना एक कॉन्फ़िग त्रुटि है। एंडपॉइंट दोनों ही स्थितियों में अप्रमाणित रहता है, इसलिए [दर सीमन](#rate-limiting) संबंधी सलाह क्रॉस-ओरिजिन ट्रैफ़िक पर भी लागू होती है।

## सर्वर आउटपुट आवश्यक [#server-output-required]

Blume का अंतर्निहित सहायक बैकएंड एक सर्वर रूट (`POST /api/ask`) है, इसलिए यह स्टैटिक बिल्ड पर नहीं चल सकता। सर्वर आउटपुट पर स्विच करने के लिए `blume/deploy` से एक होस्ट एडाप्टर नामित करें:

```ts blume.config.ts lineNumbers
import { vercel } from "blume/deploy";

export default defineConfig({
  deployment: vercel(),
});
```

सहायक सक्षम और बिना बाहरी `endpoint` वाला स्टैटिक बिल्ड तुरंत विफल हो जाता है और एक संदेश देता है जो आपसे एक होस्ट एडाप्टर सेट करने को कहता है। एडाप्टर के लिए [Deployment](/docs/deployment) देखें।

## एडाप्टर [#adapters]

`provider` उस बैकएंड को चुनता है जो उत्तर देता है। इसका मान एक **एडाप्टर** होता है: `blume/ai` से एक्सपोर्ट किया गया एक छोटा फ़ंक्शन, जो उस बैकएंड के अपने विकल्प लेता है और एक सादा डिस्क्रिप्टर लौटाता है जिसे Blume जनरेट किए गए रूट में लिखता है। प्रत्येक एडाप्टर अपना मॉडल, वह env वेरिएबल जिससे उसकी कुंजी पढ़ी जाती है, [रीज़निंग](#reasoning) को वह कैसे मैप करता है, और उसे किस प्रदाता SDK की आवश्यकता है — ये सब स्वयं तय करता है, इसलिए बैकएंडों के बीच सामंजस्य बिठाने के लिए फ़ील्ड का कोई साझा सेट नहीं होता:

```ts blume.config.ts lineNumbers
import { defineConfig } from "blume";
import { openrouter } from "blume/ai";

export default defineConfig({
  ai: {
    assistant: {
      enabled: true,
      provider: openrouter({ model: "anthropic/claude-sonnet-4-5" }),
    },
  },
});
```

| एडाप्टर | किससे उत्तर देता है | API कुंजी env वेरिएबल | इंस्टॉल करने के लिए SDK |
| --- | --- | --- | --- |
| [`gateway()`](#vercel-ai-gateway) (डिफ़ॉल्ट) | Vercel AI Gateway के माध्यम से एक `provider/model` स्ट्रिंग | `AI_GATEWAY_API_KEY` | कोई नहीं — Blume के साथ आता है |
| [`openrouter()`](#openrouter) | कोई भी [OpenRouter](https://openrouter.ai) मॉडल | `OPENROUTER_API_KEY` | `@openrouter/ai-sdk-provider` |
| [`llmgateway()`](#llmgateway) | कोई भी [LLMGateway](https://llmgateway.io) मॉडल | `LLMGATEWAY_API_KEY` | `@ai-sdk/openai-compatible` |
| [`inkeep()`](#inkeep) | एक [Inkeep](https://inkeep.com) QA मॉडल | `INKEEP_API_KEY` | `@ai-sdk/openai-compatible` |
| [`openaiCompatible()`](#openai-compatible-endpoints) | जो भी आपका एंडपॉइंट प्रदान करता है | आपके द्वारा नामित `apiKeyEnv` | `@ai-sdk/openai-compatible` |

ये SDK वैकल्पिक पीयर निर्भरताएँ हैं, इसलिए अपने प्रोजेक्ट में वही जोड़ें जिसकी आपके एडाप्टर को आवश्यकता है (उदा. `npm install @openrouter/ai-sdk-provider`)। यदि वह अनुपस्थित है, तो `blume build` Vite चलने से पहले ही रुक जाता है और पैकेज तथा उसे इंस्टॉल करने वाले कमांड का नाम बताता है, और [`blume doctor`](/docs/cli/doctor) भी इसकी रिपोर्ट करता है।

एडाप्टर जो डिस्क्रिप्टर लौटाता है वह सादा डेटा होता है — उसका प्रकार, उसके विकल्प, वह जिन env वेरिएबल को पढ़ता है, और उसे जिस SDK की आवश्यकता है — इसलिए जनरेट किया गया रूट (और [इजेक्ट किया गया](/docs/configuration/customization#eject) रूट भी) इसे लिटरल के रूप में इनलाइन करता है और प्रदाता SDK को नाम से इम्पोर्ट करता है। अनुरोध के समय कुछ भी `blume.config.ts` को नहीं पढ़ता, और किसी रूट में कभी कोई सीक्रेट नहीं लिखा जाता: एडाप्टर कुंजी रखने वाले env वेरिएबल का **नाम** लेते हैं, और रूट उसका मान Astro के [`getSecret()`](https://docs.astro.build/en/guides/environment-variables/#retrieving-secrets-programmatically) के माध्यम से पढ़ता है, इसलिए प्रत्येक डिप्लॉयमेंट एडाप्टर उसे अपने तरीके से उपलब्ध कराता है: Node, Vercel, और Netlify पर एनवायरनमेंट वेरिएबल, और Cloudflare पर Worker की [बाइंडिंग](https://docs.astro.build/en/guides/integrations-guide/cloudflare/#environment-variables-and-secrets)।

### Vercel AI Gateway [#vercel-ai-gateway]

डिफ़ॉल्ट। `model` एक `provider/model` स्ट्रिंग है, इसलिए आप इसे बदलकर मॉडल स्विच करते हैं (`openai/gpt-5.5`, `anthropic/claude-sonnet-4-5`, इत्यादि), और कोई प्रदाता SDK इंस्टॉल करने की आवश्यकता नहीं होती। गेटवे आपके एनवायरनमेंट से `AI_GATEWAY_API_KEY` पढ़ता है और जब आप Vercel पर डिप्लॉय करते हैं तो यह स्वतः जुड़ जाता है, जहाँ यह डिप्लॉयमेंट के OIDC टोकन से भी प्रमाणीकरण कर सकता है:

```ts blume.config.ts lineNumbers
import { defineConfig } from "blume";
import { gateway } from "blume/ai";

export default defineConfig({
  ai: {
    assistant: {
      enabled: true,
      provider: gateway({ model: "anthropic/claude-sonnet-4-5" }),
    },
  },
});
```

`provider` को अनसेट छोड़ना `gateway({ model: "openai/gpt-5.5" })` के समान है।

### OpenRouter [#openrouter]

[OpenRouter](https://openrouter.ai) पर कोई भी मॉडल, उसके समर्पित AI SDK प्रदाता के माध्यम से:

```ts blume.config.ts lineNumbers
import { defineConfig } from "blume";
import { openrouter } from "blume/ai";

export default defineConfig({
  ai: {
    assistant: {
      enabled: true,
      provider: openrouter({
        model: "anthropic/claude-sonnet-4-5",
        reasoning: "none",
      }),
    },
  },
});
```

### LLMGateway [#llmgateway]

[LLMGateway](https://llmgateway.io) पर कोई भी मॉडल, उसके OpenAI-संगत एंडपॉइंट के माध्यम से:

```ts blume.config.ts lineNumbers
import { defineConfig } from "blume";
import { llmgateway } from "blume/ai";

export default defineConfig({
  ai: {
    assistant: {
      enabled: true,
      provider: llmgateway({ model: "openai/gpt-5.5" }),
    },
  },
});
```

जब आप LLMGateway स्वयं चलाते हैं, तो `baseUrl` प्रीसेट एंडपॉइंट (`https://api.llmgateway.io/v1`) को ओवरराइड करता है।

### Inkeep [#inkeep]

[Inkeep](https://inkeep.com) उस सामग्री से उत्तर देता है जिसे आपने Inkeep डैशबोर्ड में इंडेक्स किया है — यह अपना स्वयं का रिट्रीवल चलाता है — इसलिए Blume इसे **बिना ग्राउंडिंग के** छोड़ देता है: इस साइट के पृष्ठों का कोई स्नैपशॉट इंजेक्ट नहीं किया जाता, और [रिट्रीवल आकार](#retrieval-size) के विकल्प लागू नहीं होते। इसके पास कोई रीज़निंग नियंत्रण भी नहीं है, इसलिए यह एडाप्टर कोई `reasoning` नहीं लेता:

```ts blume.config.ts lineNumbers
import { defineConfig } from "blume";
import { inkeep } from "blume/ai";

export default defineConfig({
  ai: {
    assistant: {
      enabled: true,
      provider: inkeep({ model: "inkeep-qa-expert" }),
    },
  },
});
```

`baseUrl` प्रीसेट एंडपॉइंट (`https://api.inkeep.com/v1`) को ओवरराइड करता है।

### OpenAI-संगत एंडपॉइंट [#openai-compatible-endpoints]

OpenAI API का उपयोग करने वाला कोई भी एंडपॉइंट `openaiCompatible()` के माध्यम से काम करता है — उसका `baseUrl`, वह जो `model` प्रदान करता है, और उसकी कुंजी रखने वाला env वेरिएबल प्रदान करें। किसी सामान्य एंडपॉइंट के लिए इनमें से किसी का भी कोई प्रीसेट नहीं होता, इसलिए तीनों आवश्यक हैं; `name` वह प्रदाता नाम है जिसे AI SDK रिपोर्ट करता है, और इसका डिफ़ॉल्ट `openai-compatible` है:

```ts blume.config.ts lineNumbers
import { defineConfig } from "blume";
import { openaiCompatible } from "blume/ai";

export default defineConfig({
  ai: {
    assistant: {
      enabled: true,
      provider: openaiCompatible({
        baseUrl: "https://my-gateway.example.com/v1",
        apiKeyEnv: "MY_GATEWAY_API_KEY",
        model: "gpt-4o",
        name: "my-gateway",
      }),
    },
  },
});
```

### हर एडाप्टर द्वारा लिए जाने वाले विकल्प [#options-every-adapter-takes]

**`apiKeyEnv`** किसी एडाप्टर को उसके डिफ़ॉल्ट के बजाय किसी भिन्न env वेरिएबल की ओर इंगित करता है — `gateway({ apiKeyEnv: "DOCS_GATEWAY_KEY" })` `AI_GATEWAY_API_KEY` के बजाय उस वेरिएबल को पढ़ता है, और `blume dev`/`build` पर अनुपस्थित-सीक्रेट चेतावनी भी उसी की जाँच करती है। जब तक कुंजी सेट नहीं होती, डिप्लॉय किया गया रूट `503` और उस वेरिएबल का नाम बताने वाले एक संदेश के साथ उत्तर देता है। रूट किसी अनुरोध बॉडी को केवल 64 KB तक पढ़ता है और इससे बड़ी किसी भी बॉडी का उत्तर `413` के साथ देता है।

**`headers`** हर कॉल के साथ स्टैटिक अनुरोध हेडर भेजता है — उदाहरण के लिए, किसी साझा बैकएंड हेतु कॉलर की पहचान बताने वाला एक हेडर, ताकि उसकी अपनी ऑब्ज़र्वेबिलिटी या दर सीमन आपके डॉक्स को अन्य ट्रैफ़िक से अलग पहचान सके:

```ts blume.config.ts lineNumbers
provider: openaiCompatible({
  baseUrl: "https://llm.internal.example.com/v1",
  apiKeyEnv: "INTERNAL_LLM_API_KEY",
  model: "gpt-4o",
  headers: { "X-Caller-Id": "docs" },
}),
```

मान जनरेट किए गए रूट में जैसे हैं वैसे ही लिखे जाते हैं, इसलिए सीक्रेट्स को `headers` में रखने के बजाय `apiKeyEnv` में रखें। API कुंजी का `Authorization` हेडर पहले लागू होता है, इसलिए कोई कस्टम हेडर उसे विस्थापित नहीं कर सकता।

**`providerOptions`** बाकी सब कुछ सीधे AI SDK के [`providerOptions`](https://ai-sdk.dev/docs/foundations/prompts#provider-options) तक पहुँचाता है, SDK के अपने स्वरूप में — पहले प्रदाता के अनुसार, फिर विकल्प के अनुसार कुंजीबद्ध — इसलिए किसी नए मॉडल नियंत्रण को कभी भी अपने अलग Blume फ़ील्ड की आवश्यकता नहीं होती:

```ts blume.config.ts lineNumbers
provider: gateway({
  model: "openai/gpt-5.5",
  providerOptions: { openai: { textVerbosity: "low" } },
}),
```

Blume केवल उन्हीं विकल्पों को मैप करता है जिनका वह नाम लेता है (`model`, `reasoning`, `apiKeyEnv`, `headers`) और `providerOptions` को ज्यों का त्यों अग्रेषित करता है, इसलिए इसे JSON होना चाहिए — इसे रूट में इनलाइन किया जाता है — और इसमें वही कुंजी होनी चाहिए जिसकी आधारभूत प्रदाता अपेक्षा करता है (गेटवे के पीछे किसी OpenAI मॉडल के लिए `openai`, OpenRouter पर `openrouter`)। सहायक को सक्षम करने से इन-पेज आइलैंड के लिए React भी चालू हो जाता है — देखें [Customization](/docs/configuration/customization#interactive-islands)।

## रीज़निंग [#reasoning]

रीज़निंग मॉडल उत्तर देने से पहले सोचते हैं, और डिफ़ॉल्ट रूप से वे कितना सोचते हैं यह मॉडल के अनुसार भिन्न होता है। आधारित डॉक्स प्रश्नोत्तर के लिए पुनःप्राप्त अंश ही उत्तर साथ लाते हैं, इसलिए उस सोच का अधिकांश हिस्सा वह विलंब है जिसकी पाठक प्रतीक्षा करता है। किसी एडाप्टर का `reasoning` विकल्प तय करता है कि मॉडल कितना तर्क करे: `"none"`, `"minimal"`, `"low"`, `"medium"`, `"high"`, या `"xhigh"`:

```ts blume.config.ts lineNumbers
provider: gateway({ model: "openai/gpt-5.5", reasoning: "none" }),
```

प्रत्येक एडाप्टर इस स्तर को अपने बैकएंड के स्वयं के रीज़निंग नियंत्रण के रूप में भेजता है, इसी कारण यह `assistant` के बजाय एडाप्टर पर रहता है:

| एडाप्टर | स्तर क्या बन जाता है |
| --- | --- |
| `gateway()` | AI SDK का [`reasoning`](https://ai-sdk.dev/docs/ai-sdk-core/reasoning) कॉल विकल्प, जिसे गेटवे मॉडल की अपनी सेटिंग से मैप करता है — उदाहरण के लिए, OpenAI का `reasoning_effort`। |
| `openrouter()` | OpenRouter का `reasoning.effort`, जो मॉडल पर सेट होता है। इसका प्रदाता AI SDK के कॉल विकल्प को अनदेखा करता है, इसलिए स्तर को वहाँ रखा जाता है जहाँ OpenRouter उसे पढ़ता है। |
| `llmgateway()` | अनुरोध में `reasoning_effort`, AI SDK के कॉल विकल्प के माध्यम से। |
| `openaiCompatible()` | अनुरोध में `reasoning_effort`, इसलिए एंडपॉइंट को उस पैरामीटर को स्वीकार करना होगा। |
| `inkeep()` | उपलब्ध नहीं। Inkeep अपनी स्वयं की QA पाइपलाइन चलाता है जिसमें कोई रीज़निंग नियंत्रण नहीं है, इसलिए इस एडाप्टर में कोई `reasoning` विकल्प नहीं है और इसे सेट करना एक कॉन्फ़िग त्रुटि है। |

मॉडल को उस स्तर का समर्थन करना होगा जिसे आप चुनते हैं: OpenAI ऐसे स्तर को अस्वीकार कर देता है जो कोई मॉडल प्रदान नहीं करता (`"none"` और `"xhigh"` केवल कुछ पर ही मौजूद हैं), इसलिए कोई स्तर सेट करने से पहले मॉडल का दस्तावेज़ीकरण देखें। मॉडल का डिफ़ॉल्ट बनाए रखने के लिए इसे अनसेट छोड़ दें। [रिट्रीवल आकार](#retrieval-size) की तरह, यह संपूर्णता के बदले टाइम-टू-फ़र्स्ट-टोकन का सौदा करता है, और उत्तर दोनों ही स्थितियों में आधारित रहते हैं।

## एनालिटिक्स [#analytics]

किसी [एनालिटिक्स प्रदाता](/docs/configuration/analytics) के कॉन्फ़िगर होने पर, सहायक अपना उपयोग उसी `track()` के माध्यम से रिपोर्ट करता है जिसका उपयोग पृष्ठ फ़ीडबैक विजेट करता है, ताकि प्रश्न आपके पेजव्यू के साथ ही दर्ज हों:

| इवेंट | कब | गुण |
| --- | --- | --- |
| `ask` | कोई प्रश्न भेजा जाता है | `path`, `questionChars` |
| `ask_answer` | उत्तर की स्ट्रीमिंग पूरी होती है | `path`, `questionChars`, `ms`, `chars` |
| `ask_error` | अनुरोध विफल होता है, बीच में टूटता है, या खाली वापस आता है | `path`, `questionChars`, `ms`, `status` |

`path` वह पृष्ठ है जहाँ से पाठक ने पूछा (सर्व किया गया pathname, ताकि यह किसी `base` के अंतर्गत फ़ीडबैक विजेट और आपके पेजव्यू से मेल खाए), `questionChars` प्रश्न की लंबाई, `ms` प्रश्न भेजने से लेकर अंतिम चंक तक का समय, और `chars` उत्तर की लंबाई। `status` HTTP स्टेटस है: `0` जब कोई प्रतिक्रिया आई ही नहीं (ऑफ़लाइन, DNS, CORS), और `200` जब प्रतिक्रिया ठीक थी लेकिन उसकी स्ट्रीम उत्तर के बीच में टूट गई — प्रदाता या क्रेडेंशियल त्रुटि इसी रूप में सामने आती है, क्योंकि बैकएंड अपने हेडर पहले ही भेज चुका होता है — या उसने कुछ भी नहीं दिया। उत्तर के बीच में बातचीत साफ़ करने पर इनमें से कोई भी परिणाम रिपोर्ट नहीं होता।

प्रश्न का टेक्स्ट कभी किसी प्रदाता तक नहीं पहुँचता: यह मुक्त-रूप पाठक इनपुट है (चिपकाई गई कुंजियाँ, त्रुटि लॉग, नाम) जो अधिकांश प्रदाताओं की शर्तों और प्रति-मान आकार सीमाओं का उल्लंघन करेगा। यह केवल `blume:track` DOM इवेंट पर, `detail.props` में `question` के रूप में यात्रा करता है, ताकि आपका लिखा हुआ कोई लिसनर इसे वहाँ अग्रेषित कर सके जहाँ आप उचित समझें। `blume/hooks` के `useAssistant` पर बना कोई कस्टम चैट UI भी वही इवेंट रिपोर्ट करता है। बिना किसी प्रदाता के कॉन्फ़िगर किए अंतर्निहित प्रदाता कॉल no-op होते हैं, लेकिन `blume:track` इवेंट फिर भी फ़ायर होता है, इसलिए उसे सुनने वाला कोई कस्टम इंटीग्रेशन उन्हें प्राप्त करता है।

## दर सीमन [#rate-limiting]

`POST /api/ask` एंडपॉइंट **अप्रमाणित** है — इसे ऐसा होना ही पड़ता है, ताकि इन-पेज सहायक इसे कॉल कर सके। Blume प्रत्येक अनुरोध को मान्य करता है — विकृत बॉडी को अस्वीकार करता है, इसे 1–40 संदेशों तक सीमित करता है, और केवल `user`/`assistant` भूमिकाएँ स्वीकार करता है ताकि कोई कॉलर अपना स्वयं का सिस्टम प्रॉम्प्ट इंजेक्ट करके रूट को एक सामान्य LLM प्रॉक्सी में न बदल सके — जिससे यह सीमित रहे कि एक कॉल आपके मॉडल पर कितना खर्च कर सकती है, लेकिन यह किसी को एंडपॉइंट को बार-बार कॉल करने से नहीं रोक सकता। यदि लागत का दुरुपयोग एक चिंता है, तो रूट को एक रेट लिमिटर के पीछे रखें — आपके होस्ट की (उदा. Vercel की) एज रेट लिमिटिंग, एक मिडलवेयर, या आपके मॉडल प्रदाता की प्रति-कुंजी खर्च सीमाएँ।

यह एंडपॉइंट [एजेंट रीडेबिलिटी मैनिफ़ेस्ट](/docs/discoverability/agent-discovery#agent-readability) में साइट की बाकी मशीन-पठनीय सतह के साथ प्रचारित किया जाता है।
