Development Guide
Requirements
| Name | Installation | Purpose |
|---|---|---|
| Python 3.11+ | Download | The library is Python-based. |
| uv | Instructions | uv is used for package management and virtualenv management in Python codebases |
Installing dependencies
Generating synthetic queries
Follow these steps to generate synthetic queries using AutoQ:
-
Set up your project directory:
-
Create an
Place your input files inside theinputfolder and add your input data:./inputdirectory. To get started, you can use the AP News dataset provided in the datasets folder. To download this example dataset directly into yourinputfolder, run: You can also download directly to Azure Blob Storage. See the Datasets documentation for storage options. -
Initialize the configuration:
This is the local-filesystem variant.Alternative blob variant (choose this instead of the local command above; do not run both):
This command creates two files in theuv run benchmark-qed config init autoq . \ --storage-type blob \ --container-name my-container \ --account-url https://<account>.blob.core.windows.net \ --base-dir autoq_test./autoq_testdirectory:.env: Stores environment variables for the AutoQ pipeline. Open this file and replace<API_KEY>with your OpenAI or Azure API key.settings.yaml: Contains pipeline settings. Edit this file as needed for your use case.
The generated
settings.yamlincludes commented-out sections for configuring Azure Blob Storage as input and output backends. Uncomment and fill in thestoragesection underinputto read data from blob storage, or theoutput_storagesection to write results to blob storage instead of the local filesystem. -
Generate synthetic queries:
This is the local-filesystem variant.Alternative blob-stored config variant (choose this instead of the local command above; do not run both):
This will process your input data and save the generated queries in theuv run benchmark-qed autoq blob://my-container/autoq_test/settings.yaml output \ --account-url https://<account>.blob.core.windows.netoutputdirectory.By default, AutoQ also generates assertions for data-driven queries. Assertions are testable factual statements that can be used to evaluate answer accuracy. You can configure assertion generation in
settings.yaml:
Comparing RAG answer pairs
Follow these steps to compare RAG answer pairs using the pairwise scoring pipeline:
-
Set up your project directory:
-
Create an
Copy your RAG answer files into theinputfolder and add your question-answer data:./inputdirectory. To get started, you can use the example RAG answers available in the example data folder. To download this example dataset directly into yourinputfolder, run: You can also download directly to Azure Blob Storage. See the Datasets documentation for storage options. -
Create a configuration file for pairwise comparison:
This is the local-filesystem variant.Alternative blob variant (choose this instead of the local command above; do not run both):
This command creates two files in theuv run benchmark-qed config init autoe_pairwise . \ --storage-type blob \ --container-name my-container \ --account-url https://<account>.blob.core.windows.net \ --base-dir pairwise_test./pairwise_testdirectory:.env: Contains environment variables for the pairwise comparison tests. Open this file and replace<API_KEY>with your OpenAI or Azure API key.settings.yaml: Contains pipeline settings, including a persistent stage-aware SQLite cache under.benchmark_qed_cache/differential_pairwise.
The generated
settings.yamlincludes commented-outinput_storageandoutput_storagesections for configuring Azure Blob Storage backends. -
Run the pairwise comparison:
This is the local-filesystem variant.Alternative blob-stored config variant (choose this instead of the local command above; do not run both):
The results will be saved in theuv run benchmark-qed autoe pairwise-scores blob://my-container/pairwise_test/settings.yaml output \ --account-url https://<account>.blob.core.windows.netoutputdirectory.
Comparing RAG answer pairs (differential, extract-and-judge)
The standard pairwise-scores command shows the judge the full text of both answers side by side. LLM judges are known to have biases in this setting — they tend to favor longer answers, richer formatting, or whichever answer appears first, even when the underlying content is not actually better. Counterbalancing the answer order (as the standard pipeline does) cancels position bias, but not length and formatting bias.
The differential-pairwise-scores command reduces those biases with a two-step extract-and-judge method (Censheng's method):
- Extract — For each question, the LLM first separates the two answers into three buckets: content that is common to both, content that is unique to answer A, and content that is unique to answer B.
- Judge — The judge then compares only the unique content (with the common content supplied as context) on the configured criteria (the standard defaults or any user-defined criteria).
Because the shared material and padding are stripped out before judging, the verdict is driven by each answer's substantive, distinct contribution rather than by its length or presentation. If two answers convey the same information in different amounts of text, they correctly come out as a tie.
Key points:
- This is additive — it is a separate command and does not change the existing
pairwise-scoresbehavior. - The criteria are configurable via a
criteriafield (the standard defaults are used when omitted), and they are judged together in a single call. - The output uses the same schema and significance pipeline as
pairwise-scores(win_rates.csv,winrates_sig_tests.csv), so results are directly comparable to the standard method. - Cost trade-off: each comparison makes roughly twice the LLM calls (one extraction step plus one judging step) in exchange for a more bias-resistant verdict.
Follow these steps to run the differential pairwise scoring pipeline:
-
Set up your project directory:
-
Create an
Copy your RAG answer files into theinputfolder and add your question-answer data:./inputdirectory. To get started, you can use the example RAG answers available in the example data folder. To download this example dataset directly into yourinputfolder, run: You can also download directly to Azure Blob Storage. See the Datasets documentation for storage options. -
Create a configuration file for differential pairwise comparison:
This is the local-filesystem variant.Alternative blob variant (choose this instead of the local command above; do not run both):
This command creates two files in theuv run benchmark-qed config init autoe_differential_pairwise . \ --storage-type blob \ --container-name my-container \ --account-url https://<account>.blob.core.windows.net \ --base-dir differential_pairwise_test./differential_pairwise_testdirectory:.env: Contains environment variables for the pairwise comparison tests. Open this file and replace<API_KEY>with your OpenAI or Azure API key.settings.yaml: Contains pipeline settings, which you can modify as needed.
The differential command reuses the pairwise configuration structure (
base,others,question_sets,trials,llm_config,criteria); whencriteriais omitted the standard defaults are used. The generatedsettings.yamlwires up the extract-and-judge prompts underprompt_config(extract_system_prompt,extract_user_prompt,judge_system_prompt,judge_user_prompt); edit those prompt files underprompts/or remove theprompt_configsection to use the built-in defaults.The generated
cache_configcaches extraction and verdict stages independently. A failed judge call can therefore resume from its completed extraction, and changing criteria invalidates verdicts without repeating extraction. Settype: nonewithstorage: nullto force both stages to run again.The generated
settings.yamlincludes commented-outinput_storageandoutput_storagesections for configuring Azure Blob Storage backends. -
Run the differential pairwise comparison:
This is the local-filesystem variant.Alternative blob-stored config variant (choose this instead of the local command above; do not run both):
The results will be saved in theuv run benchmark-qed autoe differential-pairwise-scores blob://my-container/differential_pairwise_test/settings.yaml output \ --account-url https://<account>.blob.core.windows.netoutputdirectory. In addition to the per-criterion win scores, each cached comparison CSV also records the extractedcommon,unique_1, andunique_2content for inspection.Inspect the default stage cache with:
uv run benchmark-qed cache inspect \ .benchmark_qed_cache/differential_pairwise/differential_pairwise.sqlite3Existing comparison CSVs are checked before the stage cache. To fully recompute a comparison, use a new output directory (or remove its CSV) and also disable, relocate, or clear the stage cache. See Evaluation Caches for backend and clearing guidance.
Scoring RAG answers against reference answers
Follow these steps to score RAG answers against reference answers using example data from the AP news dataset:
-
Set up your project directory:
-
Create an
Copy your RAG answers and reference answers into theinputfolder and add your data:inputdirectory. To get started, you can use the example RAG answers available in the example data folder. To download this example dataset directly into yourinputfolder, run: You can also download directly to Azure Blob Storage. See the Datasets documentation for storage options. -
Create a configuration file for reference scoring:
This is the local-filesystem variant.Alternative blob variant (choose this instead of the local command above; do not run both):
This creates two files in theuv run benchmark-qed config init autoe_reference . \ --storage-type blob \ --container-name my-container \ --account-url https://<account>.blob.core.windows.net \ --base-dir reference_test./reference_testdirectory:.env: Contains environment variables for the reference scoring pipeline. Open this file and replace<API_KEY>with your OpenAI or Azure API key.settings.yaml: Contains pipeline settings, including a persistent SQLite judgment cache under.benchmark_qed_cache/reference.
The generated
settings.yamlincludes commented-outinput_storageandoutput_storagesections for configuring Azure Blob Storage backends. The SQLite cache remains local when blob input/output storage is enabled. -
Run the reference scoring:
This is the local-filesystem variant.Alternative blob-stored config variant (choose this instead of the local command above; do not run both):
The results will be saved in theuv run benchmark-qed autoe reference-scores blob://my-container/reference_test/settings.yaml output \ --account-url https://<account>.blob.core.windows.netoutputdirectory.Successful question/criterion/trial judgments are cached immediately. If a request fails, rerun the same command to reuse completed judgments and evaluate only misses. Inspect the cache with:
Set
cache_config.type: nonewithstorage: nullwhen fresh judgments are required.
Scoring RAG answers against assertions
Follow these steps to evaluate RAG answers against per-question assertions using answer-level (LLM-as-a-judge) evaluation:
-
Set up your project directory:
-
Create an
Copy your RAG answers and assertion files into theinputfolder and add your data:inputdirectory. To get started, you can use the example RAG answers and generated assertions from the AP news dataset:This downloads example answers and assertion files. You can also use your own assertions JSON files or download directly from Azure Blob Storage. See the Datasets documentation for storage options.uv run benchmark-qed data download example_answers input uv run benchmark-qed data download AP_news input -
Create a configuration file for assertion evaluation:
This is the local-filesystem variant.Alternative blob variant (choose this instead of the local command above; do not run both):
This command creates two files in theuv run benchmark-qed config init autoe_assertion . \ --storage-type blob \ --container-name my-container \ --account-url https://<account>.blob.core.windows.net \ --base-dir assertion_test./assertion_testdirectory:.env: Contains environment variables for the assertion evaluation pipeline. Open this file and replace<API_KEY>with your OpenAI or Azure API key.settings.yaml: Contains pipeline settings, which you can modify as needed.
The generated
settings.yamlincludes commented-outinput_storageandoutput_storagesections for configuring Azure Blob Storage backends. -
Run the assertion evaluation:
This is the local-filesystem variant.Alternative blob-stored config variant (choose this instead of the local command above; do not run both):
The results will be saved in theuv run benchmark-qed autoe assertion-scores blob://my-container/assertion_test/settings.yaml output \ --account-url https://<account>.blob.core.windows.netoutputdirectory, including per-assertion scores and per-question summaries.The generated single-RAG configuration enables a persistent SQLite cache at
.benchmark_qed_cache/assertion/assertion.sqlite3. Each question/assertion/trial judgment is persisted independently, so rerunning after an interruption evaluates only missing work. Inspect it with:Set
cache_config.type: nonewithstorage: nullwhen fresh judgments are required. This answer-level cache does not apply to multi-RAG or hierarchical assertion scoring; chunk-level assertion evaluation uses its own assertion/chunk cache.
Evaluating retrieved chunks against assertions
Chunk-level evaluation scores how well retrieved passages (chunks) support assertions, without waiting for answer synthesis. This is useful for:
- Fast retrieval evaluation: Assess retrieval quality before generating complete answers
- Efficient iteration: Fix retriever settings without re-running expensive answer generation
- Persistent caching: Avoid re-evaluating same (assertion, chunk) pairs across multiple runs
Prerequisites: Where do chunks come from?
Chunks are the retrieved passages from your RAG system. You obtain them by running your retriever (e.g., vector search, BM25, hybrid) on each question. Chunks should include:
- The passage text
- The chunk index (chunk_id)
- The retrieval rank when available
Step-by-step guide
-
Set up your project directory:
-
Initialize the chunk-assertion project:
For a local-filesystem project, run:
Alternative blob variant (choose this instead of the local command above; do not run both):
uv run benchmark-qed config init autoe_chunk_assertion . \ --storage-type blob \ --container-name my-container \ --account-url https://<account>.blob.core.windows.net \ --base-dir chunk_assertion_testThe command creates the project structure before any settings need to be edited:
settings.yaml: Pipeline configuration with input placeholders.env: Environment-variable placeholders for credentialsinput/: Local input directoryprompts/: Default chunk-assertion judge prompts
Set the required credentials in
.envbefore running the evaluation. -
Prepare the retrieval and assertion inputs:
You need two JSON files with matching
question_idvalues:- A retrieval-results file produced by your retriever. BenchmarkQED evaluates the retrieved chunks, not the synthesized answer.
- An assertions file containing the per-question assertions to check.
To try the workflow with bundled example data, download both kinds of files into the generated
input/directory:The examples include matching files for
data_local,data_global, anddata_linked, with bothvector_rag_short_contextandvector_rag_long_contextretrieval results.If you use your own retriever, its retrieval-results file must be a JSON array in this form:
[ { "question_id": "q1", "text": "What is photosynthesis?", "context": [ { "chunk_id": "0", "text": "Photosynthesis converts sunlight into chemical energy.", "rank": 0 }, { "chunk_id": "5", "text": "Chlorophyll captures light energy.", "rank": 1 } ] } ]Each context item requires
chunk_idandtext;rankis optional. When every item has a rank, chunks are evaluated in rank order. Otherwise, their existing list order is used. See the chunk-level assertion example in the AutoE notebook for programmatic usage. -
Review the generated
settings.yaml:The generated configuration already points to the bundled
data_localshort-context example:generated: name: my_retriever retrieval_path: input/vector_rag_short_context/data_local_retrieval_results.json assertions: assertions_path: input/data_local_assertions.jsonIf you downloaded the bundled data in the previous step, these defaults can be used unchanged. To evaluate another example set, change
data_localin both paths todata_globalordata_linked. To use the long-context retriever, also changevector_rag_short_contexttovector_rag_long_context. The question set must match in both files.Other important generated settings are:
k_list: Retrieval depths for which coverage metrics are reportedmax_chunks_per_question: Optional cap on evaluated chunkscache_config: Cache backend for assertion/chunk judgmentsllm_config: Judge model, provider, credentials, and request settingsprompt_config: Judge prompt files
The default cache is persistent SQLite:
cache_config: type: sqlite storage: type: file base_dir: .benchmark_qed_cache/chunk_assertions database_name: chunk_assertions.sqlite3Supported cache types are
sqlite,json,memory, andnone. Existing localchunk_assertions.jsonlcaches are imported automatically. Persistent local caches coordinate concurrent processes so only one process judges each uncached assertion/chunk pair.Cache storage is independent of
input_storageandoutput_storage. A JSON cache withstorage.type: fileremains local even when inputs and outputs use Azure Blob Storage, and its relativebase_diris resolved from the directory where the command is run. To place JSON entries in blob storage, setcache_config.storage.type: bloband provide its container and credentials explicitly. See Evaluation Caches for local and blob JSON examples. -
Run the chunk-level assertion evaluation:
Alternative blob-stored config variant (choose this instead of the local command above; do not run both):
-
Review the outputs and cache:
The
output/directory contains:chunk_assertion_results.json: Coverage metrics at each kper_query_metrics_*.json: Per-question metrics for paired significance testingdebug/: Detailed per-question evaluation records
Inspect the default SQLite cache, including namespace counts and active work leases, with:
The inspection command applies only to SQLite cache files. To force fresh LLM judgments, set
cache_config.type: noneandstorage: null.
Chunk-level evaluation benefits
- Efficient caching: Results cached at
(assertion, chunk)granularity using SHA256 content-addressing - Multi-k reporting: Coverage, Strict Coverage, and Coverage Strength metrics at each k value
- Reusable cache: Re-run with different k values or retriever configs with zero LLM cost on overlapping chunks
-
Coverage metrics:
-
Coverage: % of assertions with full or partial support in top-k chunks
- Strict Coverage: % of assertions with full support only
- Coverage Strength: Average score across all assertions
For detailed instructions on configuring and running AutoE subcommands, please refer to the AutoE CLI Documentation.
To learn how to use AutoE programmatically, please see the AutoE Notebook Example.
Diving Deeper
To explore the query synthesis workflow in detail, please see the AutoQ CLI Documentation for command-line usage and the AutoQ Notebook Example for a step-by-step programmatic guide.
For a deeper understanding of AutoE evaluation pipelines, please refer to the AutoE CLI Documentation for available commands and the AutoE Notebook Example for hands-on examples.