Querying#
Turn a retrieved set of documents and a question into a generated, grounded
answer. fastrag.query composes a Retriever, a PromptTemplate, and a
ChatModel into one QueryEngine with an ask and a stream surface.
examples/12_querying.py and examples/13_streaming.py run the same three
pieces without the QueryEngine wrapper — retrieve, render, then
llm.invoke/llm.stream directly — so there is no standalone runnable
example of QueryEngine.ask itself to point literalinclude at; the
snippet below is illustrative:
import asyncio
from fastrag.query import PromptTemplate, QueryEngine
from fastrag.query.llm import OpenAIChatModel
async def main():
engine = QueryEngine(
retriever=retriever, # any fastrag.retrieval Retriever
llm=OpenAIChatModel(
model="llama3.2:3b",
api_key="ollama",
base_url="http://localhost:11434/v1",
),
prompt=PromptTemplate(
system="You are an expert on data spaces. Cite sources as [n].",
template="Documents:\n{context}\n\nQuestion: {question}\n\nAnswer:",
),
)
answer = await engine.ask("What is AgrospAI?")
print(answer.text)
for source in answer.sources:
print(source.metadata.get("source_uri"))
asyncio.run(main())
ask vs stream#
ask(question)— returns anAnswerwithtextandsources(the retrieved documents cited, in order).stream(question)— yields aSourcesChunkfirst, thenTokenChunks as the model generates, then oneDoneChunk. This is the surface the serving layer uses for SSE.
The prompt#
PromptTemplate.template must contain both {context} and {question}; it
is validated at construction (a missing placeholder raises
ConfigurationError rather than silently answering from the model’s own
knowledge). render(context=..., question=...) numbers the documents by
source and builds the messages: each page gets one [n], followed by its
retrieved chunks in page order, so an answer cites a page once rather than
once per chunk. Each page of a PDF is its own source, linked by the
#page=N URL its parser records as source_url. group_sources(context)
returns those groups, [n] being groups[n - 1]. DEFAULT_RAG_PROMPT is the shipped default. It asks for
citations as [n], once per paragraph, and for one language version when
several documents say the same thing.
Chat models#
ChatModel is the message-to-answer contract; OpenAIChatModel speaks any
OpenAI-protocol endpoint (OpenAI, Ollama, vLLM, llama.cpp), selected by
base_url. ChatModel.invoke(messages) returns str; stream(messages)
yields tokens.
See also#
Retrieval for the Retriever you pass in; Serving for
what QueryEngine.stream feeds; examples/12_querying.py and
examples/13_streaming.py for the retrieve/render/invoke steps
QueryEngine.ask/stream wrap, run end to end.