Skip to content

Quick Start#

The following example uses FakeEmbedder, which requires no network access or model downloads and runs directly.

Prerequisites

pip install python-nlql, Python ≥ 3.11.

Build the engine and ingest#

import nlql

engine = nlql.Engine(nlql.embed.FakeEmbedder())

engine.add_text("AI agents plan tasks, keep memory, and call external tools.",
                id="doc-0", metadata={"status": "published", "topic": "agents"})
engine.add_text("Retrieval-augmented generation grounds LLM answers in your documents.",
                id="doc-1", metadata={"status": "published", "topic": "rag"})
engine.add_text("Banana bread needs flour, sugar, and about forty minutes to bake.",
                id="doc-2", metadata={"status": "draft", "topic": "cooking"})

print(f"ingested {len(engine)} sentences")
# → ingested 3 sentences

Engine takes a single embedder. Here FakeEmbedder is used for demonstration; swap in a real implementation such as OpenAIEmbedder and the rest of the code stays the same.

Option 1: NLQL statement#

query = """
    SELECT SENTENCE
    LET relevance = SIMILARITY(content, "autonomous agents and tools")
    WHERE meta.status == "published"
    ORDER BY relevance DESC
    LIMIT 3
"""
for unit in engine.search(query):
    print(f"  [{unit.scores['relevance']:+.3f}] {unit.content}")

Option 2: Python chaining#

Suited for scenarios that assemble queries programmatically:

from nlql.sdk.builder import select, similarity, Meta

built = (
    select("sentence")
    .let("relevance", similarity("content", "autonomous agents and tools"))
    .where(Meta("status") == "published")
    .order_by("relevance", desc=True)
    .limit(3)
    .build()
)
for unit in engine.search(built):
    print(f"  [{unit.scores['relevance']:+.3f}] {unit.content}")

Both forms return identical results

The NLQL statement and the chained builder compile to the same IR, so the returned results (order and scores) are exactly the same.

Inspect the execution plan#

import json
print(json.dumps(engine.explain(query), indent=2, ensure_ascii=False))

engine.explain() outputs the query's execution plan: return granularity, relevance computation, filtering, and ordering. Use it to investigate query behavior.

Option 3: LLM tool calling#

Construct the JSON form of the query (the IR) directly — exactly what an LLM tool call returns:

schema = engine.function_tool()   # tool description, hand to the LLM

results = engine.search_ir({
    "select": {"granularity": "sentence"},
    "let": [{"name": "relevance",
             "call": ["SIMILARITY", ["content", "autonomous agents and tools"]]}],
    "where": ["==", ["path", "meta", "status"], "published"],
    "order_by": [{"key": "relevance", "desc": True}],
    "limit": 3,
})

All three forms compile to the same IR and return identical results.

Next steps#


Full source: examples/quickstart.py