Complete reference for Almanac's query API.
POST http://localhost:3000/api/query
{
"query": "What did we discuss about the API refactor?",
"mode": "mix"
}{
"query": "What did we discuss about the API refactor?",
"mode": "mix",
"top_k": 60,
"chunk_top_k": 20,
"score_threshold": 0.5,
"disable_rerank": false,
"source": "slack",
"record_types": ["message", "thread"],
"date_range": {
"start": "2024-01-01",
"end": "2024-01-31"
},
"entity_limit": 10,
"metadata": {
"user_id": "user_123",
"session_id": "session_456"
}
}The search query or question.
{
"query": "How does authentication work?"
}Examples:
"API refactor"- Simple keyword search"What is Alice working on?"- Entity-focused question"How does X connect to Y?"- Relationship question
Query mode determining retrieval strategy.
Options: naive, local, global, hybrid, mix
Default: mix
{
"query": "...",
"mode": "mix"
}Mode Details:
naive: Fast vector search onlylocal: Entity-focused retrievalglobal: Relationship-focused retrievalhybrid: Combines local + globalmix: Hybrid + reranking (most accurate)
See LightRAG Guide for detailed comparison.
Number of candidates to retrieve before reranking.
Range: 1-200
Default: 60
{
"query": "...",
"top_k": 100
}Guidelines:
- 20-40: Fast queries, simple questions
- 60-80: Standard (recommended)
- 100-200: Complex queries, need more context
Number of final results to return after reranking.
Range: 1-100
Default: 20
{
"query": "...",
"chunk_top_k": 10
}Use Cases:
- 5-10: Chatbot responses, focused answers
- 20: Standard display
- 50+: Research, comprehensive results
Minimum relevance score (0.0-1.0) for results.
Range: 0.0-1.0
Default: 0.5
{
"query": "...",
"score_threshold": 0.7
}Guidelines:
- 0.5: Balanced (default)
- 0.7: High precision, fewer results
- 0.3: High recall, more results
Disable LLM-based reranking (only for mix mode).
Default: false
{
"query": "...",
"mode": "mix",
"disable_rerank": false
}Performance Impact:
- Disabled (false): Slower (~300-600ms) but more accurate
- Enabled (true): Faster (~200-400ms) but less accurate
Filter results to specific data source.
{
"query": "...",
"source": "slack"
}Examples: slack, github, notion, custom-api
Filter results to specific record types.
{
"query": "...",
"record_types": ["message", "thread"]
}Examples:
- Slack:
message,thread,channel - GitHub:
issue,pull_request,commit - Notion:
page,database,block
Filter results by date range.
{
"query": "...",
"date_range": {
"start": "2024-01-01",
"end": "2024-01-31"
}
}Formats: ISO 8601 date strings
Max entities to traverse in local mode.
Range: 1-50
Default: Auto-calculated based on query
{
"query": "...",
"mode": "local",
"entity_limit": 15
}Custom metadata for tracking/analytics.
{
"query": "...",
"metadata": {
"user_id": "user_123",
"source": "chatbot",
"session_id": "abc"
}
}{
"results": [
{
"id": "507f1f77bcf86cd799439011",
"score": 0.92,
"title": "Alice in #engineering",
"content": "We should start the API refactor...",
"source": "slack",
"recordType": "message",
"sourceId": "1234.5678",
"primaryDate": "2024-01-10T14:30:00Z",
"entities": ["Alice", "API refactor", "engineering"],
"relationships": ["Alice → works_on → API refactor"],
"metadata": {
"channel": "#engineering",
"user": "Alice"
}
}
],
"metadata": {
"mode": "mix",
"total": 1,
"processingTime": 456,
"reranked": true
}
}Unique document identifier.
Relevance score (0.0-1.0).
Interpretation:
- 0.9-1.0: Highly relevant
- 0.7-0.9: Relevant
- 0.5-0.7: Somewhat relevant
- <0.5: Low relevance
Document title or primary identifier.
Document text content.
Data source name (slack, github, etc.).
Type of record (message, issue, page, etc.).
Original ID in source system.
Main timestamp (ISO 8601).
Extracted entities relevant to query.
"entities": ["Alice", "API refactor", "backend"]Extracted relationships relevant to query.
"relationships": [
"Alice → works_on → API refactor",
"API refactor → depends_on → database migration"
]Source-specific metadata.
"metadata": {
"channel": "#engineering",
"user": "Alice",
"thread_ts": "1234.5678"
}Query mode used.
Number of results returned.
Query execution time in milliseconds.
Whether results were reranked.
{
"error": "Invalid query parameter",
"message": "Query must be a non-empty string",
"code": "INVALID_QUERY"
}Common Causes:
- Missing
queryfield - Invalid
modevalue - Invalid parameter types
{
"error": "Rate limit exceeded",
"message": "Maximum 100 requests per minute",
"code": "RATE_LIMIT_EXCEEDED",
"retryAfter": 30
}{
"error": "Query execution failed",
"message": "Database connection timeout",
"code": "QUERY_FAILED"
}curl -X POST http://localhost:3000/api/query \
-H "Content-Type: application/json" \
-d '{
"query": "What did we discuss about the API refactor?",
"mode": "mix",
"top_k": 60,
"chunk_top_k": 20
}'const query = async (question: string) => {
const response = await fetch('http://localhost:3000/api/query', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
query: question,
mode: 'mix',
top_k: 60,
chunk_top_k: 20,
}),
});
if (!response.ok) {
throw new Error(`Query failed: ${response.statusText}`);
}
return await response.json();
};import requests
def query(question: str, mode: str = "mix") -> dict:
response = requests.post(
"http://localhost:3000/api/query",
json={
"query": question,
"mode": mode,
"top_k": 60,
"chunk_top_k": 20
},
timeout=30
)
response.raise_for_status()
return response.json()package main
import (
"bytes"
"encoding/json"
"net/http"
)
type QueryRequest struct {
Query string `json:"query"`
Mode string `json:"mode"`
TopK int `json:"top_k"`
ChunkTopK int `json:"chunk_top_k"`
}
func query(question string) (map[string]interface{}, error) {
req := QueryRequest{
Query: question,
Mode: "mix",
TopK: 60,
ChunkTopK: 20,
}
body, _ := json.Marshal(req)
resp, err := http.Post(
"http://localhost:3000/api/query",
"application/json",
bytes.NewBuffer(body),
)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
return result, nil
}Query multiple sources in parallel:
const multiSourceQuery = async (question: string) => {
const sources = ['slack', 'github', 'notion'];
const results = await Promise.all(
sources.map((source) =>
fetch('http://localhost:3000/api/query', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
query: question,
source,
mode: 'hybrid',
}),
}).then((r) => r.json()),
),
);
// Combine and sort
const allResults = results.flatMap((r) => r.results);
return allResults.sort((a, b) => b.score - a.score).slice(0, 20);
};Start with fast mode, upgrade if needed:
const smartQuery = async (question: string) => {
// Try naive first
const naiveResults = await query({ query: question, mode: 'naive' });
// Check quality
const avgScore = naiveResults.reduce((sum, r) => sum + r.score, 0) / naiveResults.length;
// Upgrade to mix if scores are low
if (avgScore < 0.7) {
return await query({ query: question, mode: 'mix' });
}
return naiveResults;
};For large result sets:
const paginatedQuery = async (question: string, page: number, pageSize: number) => {
const offset = page * pageSize;
return await fetch('http://localhost:3000/api/query', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
query: question,
mode: 'mix',
top_k: 200, // Retrieve many candidates
chunk_top_k: pageSize,
offset, // Skip previous pages
}),
}).then((r) => r.json());
};Default limits:
- 100 requests/minute per IP
- 1000 requests/hour per IP
For higher limits, contact support or self-host.
// Fast queries
mode: 'naive'; // 50-100ms
// Balanced
mode: 'hybrid'; // 200-400ms
// Accurate
mode: 'mix'; // 300-600ms// Faster, fewer candidates
top_k: 30;
// Slower, more comprehensive
top_k: 100;// For speed-sensitive applications
{
mode: "hybrid",
disable_rerank: true
}const cache = new Map();
const cachedQuery = async (question: string) => {
if (cache.has(question)) {
return cache.get(question);
}
const results = await query(question);
cache.set(question, results);
return results;
};- Query Modes Guide - Understand each mode
- Best Practices - Optimization tips
- Examples - Real-world usage