Skip to main content

REFERENCE

Developer Reference

Authentication, APIs, SDKs, Flow Agent processors and parameter resolution, in full.

Querying a knowledge base

A complete example of question and answer against an Asgard RAG knowledge base

Asgard implements RAG (Retrieval-Augmented Generation) with a knowledge base and the Retrieve Knowledge processor, so the AI answers from the documents and data you have uploaded.

  1. How it works​

    The RAG query happens entirely on the workflow server, and the API you call is exactly the one you call to send an ordinary message:

    the user asks a question
    ↓
    the Asgard API (the same endpoint)
    ↓
    Retrieve Knowledge processor (finds the relevant content in the knowledge base)
    ↓
    LLM (generates the answer from what was retrieved)
    ↓
    the SSE stream

    You do not change how you call the API. Add a Retrieve Knowledge processor to the workflow, point it at a knowledge base, and RAG works from there.

  2. Before you start​

    Set these up on the Asgard platform first:

    1. Create a knowledge base — upload PDFs, text files, web pages
    2. Configure an embedding model — pick the vectorising model, for example OpenAI text-embedding-3-small
    3. Add a Retrieve Knowledge processor to the workflow — set the retrieval strategy and which knowledge base to use
    4. Publish the app — which gives you the namespace and bot-provider-name

    For the detailed steps see knowledge base settings.

  3. How to phrase the question​

    How a question is phrased makes a real difference to what the knowledge base retrieves:

    AdviceExample
    Use concrete keywords✅ How many working days does a refund take?
    Avoid a vague question❌ Tell me everything
    One topic at a time✅ How long is the warranty on product A?
    Give the context✅ I am an enterprise customer. What is the contract renewal process?
  4. cURL​

    curl -X POST "https://api.asgard-ai.com/generic/ns/your-namespace/bot-provider/your-bot-provider/message/sse" \
    -H "Content-Type: application/json" \
    -H "X-API-KEY: your-api-key" \
    -d '{
    "customChannelId": "kb-query-channel-001",
    "customMessageId": "kb-msg-001",
    "text": "What documents do I need for a refund, and what is the process?",
    "action": "NONE"
    }'
  5. JavaScript​

    const BASE_URL = 'https://api.asgard-ai.com';
    const NAMESPACE = 'your-namespace';
    const BOT_PROVIDER = 'your-bot-provider';
    const API_KEY = process.env.ASGARD_API_KEY;

    /**
    * Ask the knowledge base a question and get a RAG answer
    * @param {string} question - the question
    * @param {string} channelId - the channel id; the same channel keeps the conversation memory
    */
    async function queryKnowledgeBase(question, channelId = 'kb-channel-001') {
    const url = `${BASE_URL}/generic/ns/${NAMESPACE}/bot-provider/${BOT_PROVIDER}/message/sse`;

    const response = await fetch(url, {
    method: 'POST',
    headers: {
    'Content-Type': 'application/json',
    'X-API-KEY': API_KEY,
    },
    body: JSON.stringify({
    customChannelId: channelId,
    text: question,
    action: 'NONE',
    }),
    });

    if (!response.ok) {
    throw new Error(`HTTP error: ${response.status}`);
    }

    const reader = response.body.getReader();
    const decoder = new TextDecoder();
    let buffer = '';
    let fullAnswer = '';

    while (true) {
    const { done, value } = await reader.read();
    if (done) break;

    buffer += decoder.decode(value, { stream: true });
    const lines = buffer.split('\n');
    buffer = lines.pop() || '';

    for (const line of lines) {
    if (!line.startsWith('data:')) continue;
    const jsonStr = line.slice(5).trim();
    if (!jsonStr) continue;

    try {
    const event = JSON.parse(jsonStr);

    if (event.eventType === 'asgard.message.delta') {
    const delta = event.fact.messageDelta.message.text;
    fullAnswer += delta;
    // print as it arrives, for the typewriter effect
    process.stdout.write(delta);
    }

    if (event.eventType === 'asgard.run.done') {
    console.log('\n\nQuery complete');
    return fullAnswer;
    }
    } catch (_) {}
    }
    }

    return fullAnswer;
    }

    // usage: asking follow-up questions on one channelId, which keeps the memory
    async function main() {
    const channelId = `kb-session-${Date.now()}`;

    console.log('Question 1:');
    await queryKnowledgeBase('What documents do I need for a refund?', channelId);

    console.log('\n\nQuestion 2, a follow-up:');
    await queryKnowledgeBase('Roughly how many working days does it take?', channelId);
    }

    main().catch(console.error);
  6. Python​

    import requests
    import json
    import os
    import time

    BASE_URL = "https://api.asgard-ai.com"
    NAMESPACE = "your-namespace"
    BOT_PROVIDER = "your-bot-provider"
    API_KEY = os.environ.get("ASGARD_API_KEY")


    def query_knowledge_base(question: str, channel_id: str) -> str:
    """
    Ask the Asgard knowledge base a question and get a RAG answer.

    Args:
    question: the question
    channel_id: the channel id; the same channel keeps the conversation memory

    Returns:
    The full answer text
    """
    url = f"{BASE_URL}/generic/ns/{NAMESPACE}/bot-provider/{BOT_PROVIDER}/message/sse"

    headers = {
    "Content-Type": "application/json",
    "X-API-KEY": API_KEY,
    }

    payload = {
    "customChannelId": channel_id,
    "text": question,
    "action": "NONE",
    }

    full_answer = ""

    with requests.post(url, headers=headers, json=payload, stream=True) as response:
    response.raise_for_status()

    for line in response.iter_lines():
    if not line:
    continue

    decoded = line.decode("utf-8")
    if not decoded.startswith("data:"):
    continue

    json_str = decoded[5:].strip()
    if not json_str:
    continue

    try:
    event = json.loads(json_str)
    event_type = event.get("eventType")

    if event_type == "asgard.message.delta":
    delta = event["fact"]["messageDelta"]["message"]["text"]
    full_answer += delta
    print(delta, end="", flush=True)

    elif event_type == "asgard.run.done":
    print("\n")
    break

    except json.JSONDecodeError:
    pass

    return full_answer


    if __name__ == "__main__":
    channel_id = f"kb-session-{int(time.time())}"

    questions = [
    "What documents do I need for a refund?",
    "Roughly how many working days does a refund take?",
    "Can I still apply after the refund window has closed?",
    ]

    for i, question in enumerate(questions, 1):
    print(f"\nQuestion {i}: {question}")
    print("Answer: ", end="")
    answer = query_knowledge_base(question, channel_id)
    print(f"({len(answer)} characters)")
  7. Reading the sources out of the response​

    When the workflow is set to return the knowledge base sources, they arrive in the template field of the asgard.message.complete event:

    if (event.eventType === 'asgard.message.complete') {
    const message = event.fact.messageComplete.message;

    // the full answer text
    const answerText = message.text;

    // the knowledge base sources, if the workflow is set to return them
    const template = message.template;
    if (template && template.sources) {
    console.log('Sources:');
    template.sources.forEach((source, i) => {
    console.log(` ${i + 1}. ${source.title} — ${source.url || source.fileName}`);
    });
    }
    }
    info

    What template contains depends on how you configured the workflow. See Message Template.

  8. Next​

Ready to get started?

Want to see how Asgard fits your team? Talk to us.

Contact us