Quickstart
Install Antfly, load data, and run your first queries
- curl and jq (for sample data)
This guide walks you through installing Antfly, loading data, and running your first queries — from full-text search to semantic search to AI-powered RAG.
Allow 45–90 minutes on a laptop, excluding a source build. The basic full-text check takes seconds; model downloads and background indexing take most of the time. Slower hardware may need longer timeouts.
Install Antfly
brew install antflydb/taps/antfly
# Verify
antfly --version
Start Antfly
Start Antfly in standalone mode:
antfly standalone --inference-host-budget-mb 8192 2>&1 | tee "antfly.log"
If you installed with Homebrew, you can run Antfly as a service instead:
brew services start antfly
Standalone mode starts metadata, data nodes, and Antfly inference in a single process — ideal for local development. You can also access the web dashboard at http://127.0.0.1:8080 to manage tables, run queries, and monitor your cluster. The numeric loopback address matches standalone's secure default bind on systems where localhost resolves to IPv6 first.
The 8 GiB inference host budget lets the later all-local RAG example use the embedding, reranking, and Gemma models in one request. If you use a hosted generator instead, you can omit that option.
Verify the basic data path
Before starting the longer semantic workflow, verify that storage and full-text search work with one document:
curl -fsS -X POST http://127.0.0.1:8080/db/v1/tables/hello \
-H "Content-Type: application/json" \
-d '{}'
curl -fsS -X POST http://127.0.0.1:8080/db/v1/tables/hello/batch \
-H "Content-Type: application/json" \
-d '{"inserts":{"first":{"title":"Hello","body":"Antfly is ready."}},"sync_level":"full_text"}'
antfly query --table hello \
--full-text-search 'body:Antfly' \
--fields 'title,body'
The last command should return the document with key first. If it does not,
stop here and use Troubleshooting.
Install the text embedding model
Now pull the text embedding model used for semantic search. Antfly inference runs models locally without an external API:
antfly inference pull hf:Qwen/Qwen3-Embedding-0.6B-GGUF:q8-0-bundle-v1
antfly inference list
Qwen3-Embedding uses an instruction for search queries but embeds indexed documents without it. Antfly applies that distinction automatically: index and artifact writes use the document role, while semantic searches use the query role. The Q8_0 bundle runs on native CPU on Linux and macOS, and uses Metal automatically when it is available.
If the running standalone process does not detect the newly installed model, restart it once before creating the embeddings index.
Once the embeddings index reaches queryable, Antfly durably preserves that
published snapshot across later restarts while the remaining embeddings resume
in the background. complete still means all source outcomes and the final
vector publication have settled.
Download Sample Data
In a new terminal, download 10,000 Wikipedia articles enriched with thumbnail images:
curl -L -o wiki-articles.jsonl https://cdn.antfly.io/datasets/wiki-articles-10k-v001.json
head -n 1 wiki-articles.jsonl | jq '.'
The fixture is newline-delimited JSON (JSONL): one article per line. Every
article has title, body, and url; 2,446 of the 10,000 articles also have
an optional thumbnail_url used later for image search.
Create a Table
Create a table with a text embedding index for semantic search:
antfly table create --table wikipedia \
--index '{
"name": "title_body",
"type": "embeddings",
"template": "{{title}} {{body}}",
"embedder": {
"provider": "antfly",
"model": "Qwen/Qwen3-Embedding-0.6B-GGUF:q8-0-bundle-v1"
},
"chunker": {
"provider": "antfly",
"text": {
"target_tokens": 200,
"overlap_tokens": 25
}
}
}'
Verify the table and index were created:
antfly table list
antfly index list --table wikipedia
Antfly also provisions full_text_index_v0 automatically. That default index
is what makes the full-text query later in this guide work; title_body is the
managed embeddings index created above.
Load Data
# Load all 10,000 articles using the title as the document ID
antfly load --table wikipedia \
--file wiki-articles.jsonl \
--id-field title \
--sync-level full_text
This shared load step ensures that every query tab below runs against the same
dataset. full_text fences the inexpensive text index for each load batch but
does not wait for embeddings, which continue asynchronously. The CLI reads
JSONL and batches documents automatically. Applications
that need to own ingestion should use the SDK Batch Operations
workflow with bounded batches and retries.
Embedding generation runs in the background. Wait until 10% of documents have searchable embeddings; skipped documents are excluded:
antfly index wait --table wikipedia \
--index title_body \
--until source-covered=10% \
--timeout 45m
Continue when this succeeds. Results improve as the remaining documents are
indexed. To wait for the full corpus instead, use --until complete.
Use antfly index list --table wikipedia to check progress. Timing depends on
hardware; if the wait times out, see Troubleshooting before
continuing.
Articles can produce multiple chunks, so SEARCHABLE may exceed the document
count. avg_embeddings measures chunk embeddings per second, not documents.
Search
You can run these queries using the CLI (shown below) or the web dashboard at http://127.0.0.1:8080.
Full-Text Search
Search for articles containing specific terms:
antfly query --table wikipedia \
--full-text-search 'body:"Korea"' \
--fields "title,url" \
--limit 5
Semantic Search
Find articles semantically similar to a natural language query:
antfly query --table wikipedia \
--semantic-search "anatomy and physiology" \
--indexes "title_body" \
--fields "title,url" \
--limit 5
You've loaded 10,000 documents and run your first full-text and semantic searches. From here, the guide builds on what you have — adding reranking, image search, and RAG.
Hybrid Search & Reranking
Hybrid search combines full-text and semantic search using Reciprocal Rank Fusion (RRF). The Qwen3 text reranker jointly scores each query-document pair to improve the ordering of those candidates.
Pull the reranker model:
antfly inference pull hf:ggml-org/Qwen3-Reranker-0.6B-Q8_0-GGUF:gguf:Q8_0 --tasks rerank
If Antfly doesn't detect the new model, restart antfly standalone.
The Q8 model is about 610 MiB and runs on native CPU or Metal. The first query loads it; reranking full articles can take tens of seconds, especially while indexing continues.
antfly query --table wikipedia \
--full-text-search 'body:Einstein' \
--semantic-search "theory of relativity and physics" \
--indexes "title_body" \
--fields "title,url" \
--limit 10 \
--reranker '{
"provider": "antfly",
"model": "ggml-org/Qwen3-Reranker-0.6B-Q8_0-GGUF:gguf:Q8_0",
"field": "body"
}' \
--pruner '{"min_score_ratio": 0.01}'
Reranking vs Pruning:
- Reranking re-scores each query-document pair for relevance. It improves ordering but keeps the same number of results.
- Pruning filters out low-relevance results based on score quality. Use
min_score_ratioto keep only results scoring at least N% of the top result, ormax_score_gap_percentto detect "elbows" in score distribution.
Image Search
Search by visual content using ClipClap, a multimodal embedding model that understands text, images, and audio.
Confirm the ClipClap model is available
antfly inference pull antflydb/clipclap:gguf:Q4_K
If Antfly doesn't detect the new model, restart antfly standalone.
Add an image index to your table
Add a ClipClap-based index to embed each article's Wikipedia thumbnail:
antfly index create --table wikipedia \
--index thumbnail \
--type embeddings \
--coverage-policy partial \
--template "{{#if thumbnail_url}}{{remoteMedia url=thumbnail_url}}{{/if}}" \
--embedder '{"provider": "antfly", "model": "antflydb/clipclap"}'
Antfly probes the selected embedding model during creation and stores its
dimension in the normalized index definition. Specify dimension only when
you also want creation to verify an explicit expected size.
Adding an index starts background image indexing. Articles without thumbnails are skipped; wait for 250 searchable images before continuing.
antfly index wait --table wikipedia \
--index thumbnail \
--until searchable-artifacts=250 \
--timeout 45m
Use antfly index list --table wikipedia to monitor detailed progress.
Search by visual content
ClipClap understands visual concepts, so you can describe what you're looking for in natural language:
antfly query --table wikipedia \
--semantic-search "map of a country" \
--indexes "thumbnail" \
--fields "title,url,thumbnail_url" \
--limit 5
Multimodal image search responds best to concrete visual descriptions ("red sports car", "mountain landscape") rather than abstract concepts. For a deeper dive, see the Image Search with CLIP example.
RAG (Retrieval-Augmented Generation)
Combine search with local LLM answer generation using the retrieval agent.
Pull a generation model
antfly inference pull hf:ggml-org/gemma-4-E4B-it-GGUF:gguf:Q4_0 \
--tasks generate \
--projector auto
--projector auto includes image and audio support. Try a local file with
antfly inference generate <model-dir> "Describe this input" --image ./photo.jpg
or --audio ./clip.wav. Use --projector none for a smaller, text-only download.
The RAG example below uses text and limits output to 512 tokens per model turn.
For other providers, see the next step.
Build a query and generate an answer
Give Gemma an intent and a table. The retrieval agent delegates query planning to the query builder, searches, and answers from the results.
antfly agents retrieval --table wikipedia \
--intent "What are the major events in Korean history?" \
--fields "title,body" \
--limit 5 \
--generator '{
"provider": "antfly",
"model": "ggml-org/gemma-4-E4B-it-GGUF",
"max_tokens": 512
}' \
--max-internal-iterations 8 \
--streaming
The CLI and cURL commands stream Server-Sent Events as each step completes. A
terminal event: done marks success; an error or incomplete stream makes the
CLI exit nonzero. The SDK examples request structured JSON instead. Each
example uses bounded, read-only tool calls and requests only a grounded answer.
Use --no-streaming for JSON from the CLI.
Inspect a query plan (optional)
To build a query without retrieving documents:
antfly agents query-builder --table wikipedia \
--intent "Find articles about anatomy" \
--generator '{"provider":"antfly","model":"ggml-org/gemma-4-E4B-it-GGUF","max_tokens":512,"temperature":0}' \
--max-internal-iterations 8
Add --execute to run the same composed retrieval workflow shown above.
RAG with alternative providers
The previous step uses Antfly inference for local inference. You can also use cloud APIs or Ollama:
Requires a Google AI API key. Set the GEMINI_API_KEY environment variable — Antfly picks it up automatically:
export GEMINI_API_KEY="your-api-key-here"
antfly agents retrieval --table wikipedia \
--semantic-search "What are the major events in Korean history?" \
--indexes "title_body" \
--fields "title,body" \
--limit 5 \
--generator '{"provider": "gemini", "model": "gemini-2.5-flash"}' \
--max-context-tokens 2048 \
--generate
Choosing a generator model:
ggml-org/gemma-4-E4B-it-GGUF— local GGUF inference via Antfly inference, no API key needed- Ollama
gemma3:4b-it-qat— local inference via Ollama, quantized for fast CPU/GPU performance - Gemini
gemini-2.5-flash— cloud API, fast and high quality, requires API key - OpenAI
gpt-4.1-mini— cloud API, fast and high quality, requires API key
Structured output
Add --no-streaming to get structured JSON output with source references instead of streaming text:
antfly agents retrieval --table wikipedia \
--semantic-search "Explain the theory of relativity" \
--indexes "title_body" \
--fields "title,body,url" \
--limit 5 \
--generator '{"provider": "gemini", "model": "gemini-2.5-flash"}' \
--no-streaming --generate
Evaluation
Add --eval to score the quality of retrieval and generation:
antfly agents retrieval --table wikipedia \
--semantic-search "What are the major events in Korean history?" \
--indexes "title_body" \
--fields "title,body" \
--limit 5 \
--generator '{"provider": "gemini", "model": "gemini-2.5-flash"}' \
--generate \
--eval '{
"evaluators": ["faithfulness", "relevance"],
"judge": {"provider": "gemini", "model": "gemini-2.5-flash"}
}'
Available evaluators:
- Retrieval metrics (require
ground_truth.relevant_ids):recall,precision,ndcg,mrr,map - LLM-as-judge metrics (require
judgeconfig):relevance,faithfulness,completeness,coherence,safety,helpfulness,correctness,citation_quality
Troubleshooting
antfly is not found after the Linux install
The user installer places the binary in ~/.local/bin. Make it available in
the current terminal, then retry:
export PATH="$HOME/.local/bin:$PATH"
antfly --version
Antfly reports a legacy data directory
Antfly refuses to overwrite a legacy Go-runtime directory. Keep that directory intact, back it up with the old runtime, and start this quickstart with a new database directory:
antfly standalone --data-dir "$HOME/.antfly-zig" 2>&1 | tee antfly.log
Models remain in the documented ~/.antfly/inference/models store unless you
explicitly pass --models-dir or set ANTFLY_INFERENCE_MODELS_DIR.
MODEL_NOT_FOUND
Confirm that the requested model is installed and inspect the resolved model directory printed in the standalone startup log:
antfly inference list
grep -F 'standalone inference paths' antfly.log
Pull the missing model again, or pass the intended directory explicitly with
antfly standalone --models-dir <path>.
An index remains pending or index wait times out
Do not continue to semantic, image, or RAG steps until the relevant index has
reached the guide's readiness threshold. queryable_partial is safe to
use while coverage grows, but an empty published generation cannot produce
results. If index wait times out, capture the full
status and recent watchdog messages:
antfly index list --table wikipedia --output json | jq '.'
grep -E 'watchdog|derived worker|NotFound|EnrichmentWaitTimeout' antfly.log | tail -n 100
Remember that physical chunk/vector counts can exceed source-document counts.
Continual growth for unchanged source data, no generation-coverage progress, or
an unexplained ready to pending transition should be reported with the JSON
status, log excerpt, Antfly version, and startup command.
Startup reports a port conflict or memory error
Stop the process already using ports 8080 or 4200, or select different public
and health ports with --port and --health-port. For memory errors, stop
other large local models and retry with a smaller model or a larger process
memory envelope appropriate for the machine.
Stop the quickstart
Press Ctrl+C in the standalone terminal. If you used Homebrew services, run:
brew services stop antfly
Next Steps
- Explore the Dashboard — Manage tables, run queries, and monitor your cluster at
http://127.0.0.1:8080 - Image Search with CLIP — Build a full image search application
- Browse Models — Discover available embedding, reranking, and generation models with
antfly inference list --remote - SDKs — Build applications with Go, TypeScript, Python, or Rust
- Backup and Restore — Protect your data
- Production Deployment — Deploy on Kubernetes with the Antfly Operator
Additional Resources
- Antfly CLI & REST API Documentation
- Hybrid Search Guide
- Inference Guide — Configure ML inference, embedding providers, and more
- Configuration Reference