Quail BI leverages large language models (LLMs) to transform natural language questions into SQL queries, generate visualizations, and provide intelligent insights. This page explains how AI is integrated throughout the platform.
Quail uses Azure OpenAI Service by default, but can be configured to use other providers supported by the Vercel AI SDK.
Quail is configured to use Azure OpenAI Service through the Vercel AI SDK:
app/app/api/biChat/route.ts
import { createAzure } from '@ai-sdk/azure';const azure = createAzure({ resourceName: process.env.NEXT_PUBLIC_AZURE_RESOURCE_NAME!, apiKey: process.env.NEXT_PUBLIC_AZURE_API_KEY!,});// Model is selected based on speed mode in the request
Azure OpenAI provides enterprise-grade security, compliance, and data residency options.
Configure these environment variables in .env.local:
.env.local
# Azure AI ConfigurationNEXT_PUBLIC_AZURE_RESOURCE_NAME=your-resource-nameNEXT_PUBLIC_AZURE_API_KEY=your-api-key-hereNEXT_PUBLIC_AZURE_FUNCTION_ENDPOINT=https://your-function.azurewebsites.net
Azure OpenAI
OpenAI
Other Providers
Recommended for production
Enterprise security and compliance
Data residency controls
No data used for model training
SLA-backed availability
Setup:
Create Azure OpenAI resource
Deploy GPT-4 or GPT-4o model
Get endpoint URL and API key
Configure environment variables
Alternative for developmentTo use OpenAI directly, modify the provider:
import { openai } from '@ai-sdk/openai';export const model = openai('gpt-4o');
The chat interface converts natural language questions into SQL queries:
app/app/api/biChat/route.ts
import { generateText } from 'ai';import { model } from '@/lib/ai/provider';export async function POST(req: Request) { const { message, schema } = await req.json(); const { text: sql } = await generateText({ model, system: `You are a SQL expert. Generate SQL queries for the given database schema. Schema: ${JSON.stringify(schema, null, 2)} Rules: - Only generate SELECT queries (read-only) - Use proper SQL syntax - Include appropriate JOINs when needed - Use table aliases for clarity - Return only the SQL query, no explanations`, prompt: message, }); return Response.json({ sql });}
The AI receives the full database schema (tables, columns, relationships) but never sees actual data, following the Agentic Hydration pattern.
The SQL editor can explain queries in plain English:
lib/actions/explain-query.ts
import { generateText } from 'ai';import { model } from '@/lib/ai/provider';export async function explainQuery(sql: string): Promise<string> { const { text } = await generateText({ model, system: `You are a SQL expert who explains queries to non-technical users. Explain what the query does in simple, clear language.`, prompt: `Explain this SQL query: ${sql}`, }); return text;}