सामग्री पर जाएँ
Blume
Esc
↑↓नेविगेट↵खोलें⌘Jप्रीव्यू
इस पेज पर

सहायक

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

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

ai: {
  assistant: {
    enabled: true,
  },
}

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

सुझाए गए प्रश्न

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

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 को अनसेट (या खाली) छोड़ दें और पैनल एक सादे इनपुट के साथ खुलेगा।

कोड के बारे में पूछना

सहायक चालू होने पर, हर कोड ब्लॉक को उसके कॉपी बटन के बगल में एक Ask बटन मिलता है। यह ब्लॉक को संलग्न करके सहायक खोलता है, जो इनपुट के ऊपर एक चिप के रूप में दिखाया जाता है, ताकि पाठक पूछ सके कि यह क्या करता है, यह विफल क्यों होता है, या इसे कैसे अनुकूलित करें। बिना किसी प्रश्न के भेजे जाने पर, यह सहायक से कोड समझाने को कहता है। कोड प्रश्न के बाद एक फ़ेंस्ड ब्लॉक के रूप में, अधिकतम 6,000 वर्णों तक, मॉडल को भेजा जाता है।

useAssistant पर बना कोई कस्टम चैट UI भी ऐसा ही कर सकता है: window पर blume:open-assistant को सुनें, जिसके detail.code में ब्लॉक का language, source, और title होता है।

सहायता से संपर्क करें

जब डॉक्स उत्तर न दे सकें, तो पाठक को किसी व्यक्ति के पास भेजें। support सेट करें, और बातचीत शुरू होते ही पैनल उसके नीचे एक Contact support लिंक दिखाता है:

ai: {
  assistant: {
    enabled: true,
    support: "mailto:help@example.com", // or "https://example.com/support", or "/support"
  },
},

एक mailto: पता बातचीत को बॉडी के रूप में लेकर एक ईमेल शुरू करता है, ताकि पाठक को दोबारा समझाना न पड़े (लंबी बातचीत में उसके नवीनतम टर्न रखे जाते हैं)। किसी URL या आपकी साइट के किसी पृष्ठ को बातचीत की id एक thread क्वेरी पैरामीटर के रूप में मिलती है। सहायक के ask, ask_answer, और ask_error एनालिटिक्स इवेंट में वही thread होता है, ताकि आपकी सहायता टीम आपके एनालिटिक्स में बातचीत ढूँढ सके।

कस्टम निर्देश

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

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.",
  },
}

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

ग्राउंडिंग

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

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

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

पृष्ठ खोजना और पढ़ना

पुनःप्राप्त पृष्ठ केवल एक शुरुआत हैं। सहायक स्वयं भी चीज़ें खोज सकता है: उसके पास एक search_docs टूल है जो आपके डॉक्स में खोज करता है, और एक read_page टूल जो पूरा पृष्ठ पढ़ता है, उस स्थिति के लिए जब कोई अंश उत्तर तक पहुँचने से पहले ही समाप्त हो जाए। यह एक ही प्रश्न के भीतर खोज सकता है, एक-दो पृष्ठ पढ़ सकता है, फिर से खोज सकता है, और फिर उत्तर दे सकता है। टूल कॉल आपके सर्वर पर ग्राउंडिंग वाले उसी स्नैपशॉट पर चलती हैं, पाठक की भाषा और डॉक्स संस्करण तक सीमित रहती हैं, और कभी पाठक तक नहीं पहुँचतीं; पाठक को केवल उत्तर दिखता है।

टूल हर उस एडाप्टर के लिए डिफ़ॉल्ट रूप से चालू हैं जिसके मॉडल टूल कॉलिंग का समर्थन करते हैं। OpenAI-संगत एंडपॉइंट के लिए ये बंद हैं, क्योंकि हो सकता है कोई सेल्फ-होस्टेड मॉडल इसका समर्थन न करे। किसी भी डिफ़ॉल्ट को बदलने के लिए tools सेट करें:

ai: {
  assistant: {
    enabled: true,
    provider: openai({ baseUrl, model, apiKeyEnv }),
    tools: true, // this model supports tool calling
  },
}

प्रत्येक प्रश्न अधिकतम पाँच मॉडल चरण लेता है: टूल कॉल के अधिकतम चार दौर, फिर उत्तर। tools: false के साथ, सहायक केवल पुनःप्राप्त पृष्ठों से उत्तर देता है, जैसा वह टूल के आने से पहले करता था।

रिट्रीवल आकार

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

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 से अधिकतम एक पृष्ठ अधिक उद्धृत कर सकता है।

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

अपने स्वयं के हार्डवेयर पर, मॉडल की कॉन्टेक्स्ट विंडो का आकार भी केवल अंशों के लिए नहीं, बल्कि पूरे प्रॉम्प्ट के लिए तय करें: अब तक की बातचीत अधिकतम 24,000 वर्ण जोड़ती है, और tools चालू होने पर, एक read_page परिणाम अधिकतम 20,000 वर्ण — जो अकेले ही लगभग 5,000 टोकन हैं। उदाहरण के लिए, Ollama छोटे GPU पर डिफ़ॉल्ट रूप से 4k-टोकन की विंडो का उपयोग करता है, और जो प्रॉम्प्ट उससे बड़ा हो जाता है वह विफल नहीं होता: Ollama प्रॉम्प्ट की शुरुआत को हटा देता है, जहाँ निर्देश और अंश होते हैं, और मॉडल आपके डॉक्स के बिना उत्तर देता है।

बाहरी एंडपॉइंट

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

ai: {
  assistant: {
    enabled: true,
    endpoint: "https://api.example.com/v1/docs/ask",
  },
}

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

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

messages अब तक की बातचीत है, जो नए प्रश्न के साथ समाप्त होती है। अंतर्निहित रूट अधिकतम 40 संदेश और JSON के रूप में उनके अधिकतम 24,000 वर्ण स्वीकार करता है, इसलिए जब कोई बातचीत इनमें से किसी भी सीमा से बड़ी हो जाती है, तो पैनल उसके वे नवीनतम टर्न भेजता है जो सीमा में समा सकें और सबसे पुराने टर्न हटा देता है।

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

क्रॉस-ओरिजिन कॉलर

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

ai: {
  assistant: {
    enabled: true,
    cors: ["https://www.example.com"],
  },
}

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

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

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 उस बैकएंड का काम है, और दोनों को सेट करना एक कॉन्फ़िग त्रुटि है। एंडपॉइंट दोनों ही स्थितियों में अप्रमाणित रहता है, इसलिए दर सीमन संबंधी सलाह क्रॉस-ओरिजिन ट्रैफ़िक पर भी लागू होती है।

सर्वर आउटपुट आवश्यक

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

import { vercel } from "blume/deploy";

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

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

एडाप्टर

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

import { defineConfig } from "blume";
import { anthropic } from "blume/ai";

export default defineConfig({
  ai: {
    assistant: {
      enabled: true,
      provider: anthropic({ model: "claude-sonnet-5" }),
    },
  },
});
एडाप्टर किससे उत्तर देता है API कुंजी env वेरिएबल इंस्टॉल करने के लिए SDK
openai() एक OpenAI मॉडल, या कोई भी OpenAI-संगत एंडपॉइंट OPENAI_API_KEY @ai-sdk/openai (baseUrl के साथ @ai-sdk/openai-compatible)
anthropic() एक Claude मॉडल ANTHROPIC_API_KEY @ai-sdk/anthropic
gemini() एक Gemini मॉडल GEMINI_API_KEY @ai-sdk/google
grok() एक xAI Grok मॉडल XAI_API_KEY @ai-sdk/xai
gateway() (डिफ़ॉल्ट) Vercel AI Gateway के माध्यम से एक provider/model स्ट्रिंग AI_GATEWAY_API_KEY कोई नहीं — Blume के साथ आता है
openrouter() कोई भी OpenRouter मॉडल OPENROUTER_API_KEY @openrouter/ai-sdk-provider
llmgateway() कोई भी LLMGateway मॉडल LLMGATEWAY_API_KEY @ai-sdk/openai-compatible
inkeep() एक Inkeep QA मॉडल INKEEP_API_KEY @ai-sdk/openai-compatible

openai(), anthropic(), gemini(), और grok() आपकी कुंजी के साथ प्रदाता के अपने API को कॉल करते हैं — बीच में कुछ नहीं होता। ये SDK वैकल्पिक पीयर निर्भरताएँ हैं, इसलिए अपने प्रोजेक्ट में वही जोड़ें जिसकी आपके एडाप्टर को आवश्यकता है (उदा. npm install @ai-sdk/anthropic)। यदि वह अनुपस्थित है, तो blume build Vite चलने से पहले ही रुक जाता है और पैकेज तथा उसे इंस्टॉल करने वाले कमांड का नाम बताता है, और blume doctor भी इसकी रिपोर्ट करता है।

एडाप्टर जो डिस्क्रिप्टर लौटाता है वह सादा डेटा होता है — उसका प्रकार, उसके विकल्प, वह जिन env वेरिएबल को पढ़ता है, और उसे जिस SDK की आवश्यकता है — इसलिए जनरेट किया गया रूट (और इजेक्ट किया गया रूट भी) इसे लिटरल के रूप में इनलाइन करता है और प्रदाता SDK को नाम से इम्पोर्ट करता है। अनुरोध के समय कुछ भी blume.config.ts को नहीं पढ़ता, और किसी रूट में कभी कोई सीक्रेट नहीं लिखा जाता: एडाप्टर कुंजी रखने वाले env वेरिएबल का नाम लेते हैं, और रूट उसका मान Astro के getSecret() के माध्यम से पढ़ता है, इसलिए प्रत्येक डिप्लॉयमेंट एडाप्टर उसे अपने तरीके से उपलब्ध कराता है: Node, Vercel, और Netlify पर एनवायरनमेंट वेरिएबल, और Cloudflare पर Worker की बाइंडिंग।

OpenAI

कोई भी OpenAI मॉडल, जिसे सीधे OpenAI के अपने AI SDK प्रदाता के माध्यम से कॉल किया जाता है:

import { defineConfig } from "blume";
import { openai } from "blume/ai";

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

OpenAI-संगत एंडपॉइंट

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

import { defineConfig } from "blume";
import { openai } from "blume/ai";

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

baseUrl होने पर, रूट @ai-sdk/openai-compatible के माध्यम से एंडपॉइंट के Chat Completions API को कॉल करता है, इसलिए @ai-sdk/openai के बजाय वह पैकेज इंस्टॉल करें: अधिकांश संगत एंडपॉइंट OpenAI का Responses API प्रदान नहीं करते। डॉक्स टूल डिफ़ॉल्ट रूप से बंद रहते हैं, क्योंकि हो सकता है कोई सेल्फ-होस्टेड मॉडल टूल कॉलिंग का समर्थन न करे।

Anthropic

कोई भी Claude मॉडल, जिसे सीधे Anthropic के AI SDK प्रदाता के माध्यम से कॉल किया जाता है:

import { defineConfig } from "blume";
import { anthropic } from "blume/ai";

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

Gemini

कोई भी Gemini मॉडल, जिसे सीधे Google के AI SDK प्रदाता के माध्यम से कॉल किया जाता है। कुंजी Google AI Studio से प्राप्त एक API कुंजी है:

import { defineConfig } from "blume";
import { gemini } from "blume/ai";

export default defineConfig({
  ai: {
    assistant: {
      enabled: true,
      provider: gemini({ model: "gemini-3.5-flash" }),
    },
  },
});

Grok

कोई भी xAI Grok मॉडल, जिसे सीधे xAI के AI SDK प्रदाता के माध्यम से कॉल किया जाता है:

import { defineConfig } from "blume";
import { grok } from "blume/ai";

export default defineConfig({
  ai: {
    assistant: {
      enabled: true,
      provider: grok({ model: "grok-4.7" }),
    },
  },
});

Vercel AI Gateway

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

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 पर कोई भी मॉडल, उसके समर्पित AI SDK प्रदाता के माध्यम से:

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 पर कोई भी मॉडल, उसके OpenAI-संगत एंडपॉइंट के माध्यम से:

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 डैशबोर्ड में इंडेक्स किया है — यह अपना स्वयं का रिट्रीवल चलाता है — इसलिए Blume इसे बिना ग्राउंडिंग के छोड़ देता है: इस साइट के पृष्ठों का कोई स्नैपशॉट इंजेक्ट नहीं किया जाता, और रिट्रीवल आकार के विकल्प लागू नहीं होते। इसके पास कोई रीज़निंग नियंत्रण भी नहीं है, इसलिए यह एडाप्टर कोई reasoning नहीं लेता:

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) को ओवरराइड करता है।

हर एडाप्टर द्वारा लिए जाने वाले विकल्प

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

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

provider: openai({
  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 तक पहुँचाता है, SDK के अपने स्वरूप में — पहले प्रदाता के अनुसार, फिर विकल्प के अनुसार कुंजीबद्ध — इसलिए किसी नए मॉडल नियंत्रण को कभी भी अपने अलग Blume फ़ील्ड की आवश्यकता नहीं होती:

provider: gateway({
  model: "openai/gpt-5.5",
  providerOptions: { openai: { textVerbosity: "low" } },
}),

Blume केवल उन्हीं विकल्पों को मैप करता है जिनका वह नाम लेता है (model, reasoning, apiKeyEnv, headers) और providerOptions को ज्यों का त्यों अग्रेषित करता है, इसलिए इसे JSON होना चाहिए — इसे रूट में इनलाइन किया जाता है — और इसमें वही कुंजी होनी चाहिए जिसकी आधारभूत प्रदाता अपेक्षा करता है (openai() या गेटवे के पीछे किसी OpenAI मॉडल के लिए openai, anthropic() के लिए anthropic, gemini() के लिए google, grok() के लिए xai, OpenRouter पर openrouter, और किसी OpenAI-संगत एंडपॉइंट पर एडाप्टर का name)। सहायक को सक्षम करने से इन-पेज आइलैंड के लिए React भी चालू हो जाता है — देखें Customization।

रीज़निंग

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

provider: gateway({ model: "openai/gpt-5.5", reasoning: "none" }),

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

एडाप्टर स्तर क्या बन जाता है
openai() OpenAI का reasoning_effort। baseUrl होने पर, इसे अनुरोध में reasoning_effort के रूप में भेजा जाता है, इसलिए एंडपॉइंट को उस पैरामीटर को स्वीकार करना होगा।
anthropic() Claude की थिंकिंग: एडैप्टिव थिंकिंग वाले मॉडलों पर एक प्रयास स्तर, पुराने मॉडलों पर एक थिंकिंग बजट, और "none" के लिए थिंकिंग बंद।
gemini() Gemini का थिंकिंग स्तर, या उन मॉडलों पर एक थिंकिंग बजट जो इसे लेते हैं।
grok() xAI का रीज़निंग प्रयास, उन मॉडलों पर जो इसे प्रदान करते हैं।
gateway() AI SDK का reasoning कॉल विकल्प, जिसे गेटवे मॉडल की अपनी सेटिंग से मैप करता है — उदाहरण के लिए, OpenAI का reasoning_effort।
openrouter() OpenRouter का reasoning.effort, जो मॉडल पर सेट होता है। इसका प्रदाता AI SDK के कॉल विकल्प को अनदेखा करता है, इसलिए स्तर को वहाँ रखा जाता है जहाँ OpenRouter उसे पढ़ता है।
llmgateway() अनुरोध में reasoning_effort, AI SDK के कॉल विकल्प के माध्यम से।
inkeep() उपलब्ध नहीं। Inkeep अपनी स्वयं की QA पाइपलाइन चलाता है जिसमें कोई रीज़निंग नियंत्रण नहीं है, इसलिए इस एडाप्टर में कोई reasoning विकल्प नहीं है और इसे सेट करना एक कॉन्फ़िग त्रुटि है।

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

एनालिटिक्स

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

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

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

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

दर सीमन

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

बॉट सुरक्षा

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

import { defineConfig } from "blume";
import { turnstile } from "blume/captcha";

export default defineConfig({
  ai: {
    assistant: {
      enabled: true,
      captcha: turnstile({ siteKey: "0x4AAAAAAA…" }),
    },
  },
});
एडाप्टर प्रदाता सीक्रेट कुंजी env वेरिएबल
turnstile() Cloudflare Turnstile TURNSTILE_SECRET_KEY
hcaptcha() hCaptcha, अदृश्य रूप से चलाया जाता है HCAPTCHA_SECRET_KEY

साइट कुंजी ब्राउज़र तक जाती है और इसे कमिट करना सुरक्षित है; सीक्रेट कुंजी सर्वर पर रहती है। Turnstile के लिए, Cloudflare डैशबोर्ड में एक विजेट बनाएँ और Managed या Invisible मोड चुनें। जब तक सीक्रेट सेट नहीं होता, सहायक उत्तर देता है कि वह कॉन्फ़िगर नहीं है, और blume build चेतावनी देता है। प्रदाता की स्क्रिप्ट पृष्ठ के साथ नहीं, बल्कि पाठक के पहले प्रश्न के साथ लोड होती है।

विफल जाँच पाठक को एक अनूदित “हम यह जाँच नहीं कर सके कि आप मनुष्य हैं” सूचना दिखाती है, और रूट 403 के साथ उत्तर देता है। दोनों प्रदाता ऐसी परीक्षण कुंजियाँ प्रकाशित करते हैं जो हमेशा पास होती हैं, ताकि आप जाँच को स्थानीय रूप से आज़मा सकें: Turnstile की 1x00000000000000000000BB सीक्रेट 1x0000000000000000000000000000000AA के साथ, और hCaptcha की 10000000-ffff-ffff-ffff-000000000001 0x0000000000000000000000000000000000000000 के साथ।

बाहरी एंडपॉइंट के साथ भी पैनल टोकन भेजता है, अनुरोध बॉडी में captcha के रूप में, ताकि आपका बैकएंड उसे सत्यापित कर सके।

यह एंडपॉइंट एजेंट रीडेबिलिटी मैनिफ़ेस्ट में साइट की बाकी मशीन-पठनीय सतह के साथ प्रचारित किया जाता है।

अंतिम अपडेट

क्या यह पेज सहायक था?