
Rag Perf
- 3 installs
- 7 repo stars
- Updated August 2, 2026
- practicalswan/agent-skills
rag-perf is a Claude Code skill for ai & agent building.
About
Guides profiling a RAG Blueprint stack, isolating bottlenecks, and validating latency or throughput improvements. A developer uses it when optimizing the performance of a RAG pipeline.
- Profiles retrieval stacks and compares bottlenecks
- Validates latency and throughput improvements
Rag Perf by the numbers
- 3 all-time installs (skills.sh)
- Ranked #13,677 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/practicalswan/agent-skills --skill rag-perfAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 3 |
|---|---|
| repo stars | ★ 7 |
| Last updated | August 2, 2026 |
| Repository | practicalswan/agent-skills ↗ |
How do I helps with ai & agent building tasks.?
Tunes NVIDIA RAG Blueprint performance by profiling retrieval stacks, comparing bottlenecks, and validating latency or throughput gains.
Who is it for?
A solo builder working on ai & agent building tasks who needs structured help with rag perf.
Skip if: Teams with no ai & agent building needs, or anyone wanting a generic chat assistant without this specific workflow.
When should I use this skill?
When you need to helps with ai & agent building tasks., or when rag-perf is a claude code skill for ai & agent building.
What you get
Structured output aligned to rag-perf: rag-perf, AI & Agent Building.
Files
RAG-Perf — config-driven perf benchmark CLI
Purpose
Drive a deployed NVIDIA RAG Blueprint server with a YAML config, run a server-side profiling pass (per-stage timing, citation quality, bottleneck inference) and an optional aiperf load test (TTFT / E2E / token & request throughput / error rate), and write a unified report. The CLI is intentionally minimal: rag-perf -c <config> plus --help / --version. Behaviour is fully config-driven; field variations belong in YAML.
Scope
- Accuracy / RAGAS scoring of answer quality → use the rag-eval skill.
- Deploying, repairing, or configuring services (compose, helm, NIM env vars) → use the rag-blueprint skill.
- Production monitoring / alerting — rag-perf is a one-shot benchmark tool.
- Runtime requirement: a deployed RAG server reachable on the network.
Prerequisites
- Repo cloned; run commands from the repo root (config paths in the presets are repo-root-relative).
- Python 3.11+ and uv on PATH.
- Install rag-perf into its own uv-managed venv:
uv sync --project scripts/rag-perf. - For unit tests: install dev extras as well —
uv sync --project scripts/rag-perf --extra dev(otherwisepytest-asynciois missing and async tests error out at collection time). - A reachable RAG server (default
http://localhost:8081). For the aiperf phase, the bundlednvidia_ragendpoint plugin must be installed —pip install -e ./scripts/rag-perfregisters it via theaiperf.pluginsentry point. - For synthetic queries: an OpenAI-compatible chat-completions endpoint reachable at
synthetic.llm_url(defaulthttp://localhost:8999/v1/chat/completions). - rag-perf itself runs without
NVIDIA_API_KEY(unlike rag-eval). The synthetic LLM endpoint may require its own auth — that's the deployment's concern.
Instructions
1. Pick a preset. The three under `scripts/rag-perf/configs/` are:
quick_profile.yaml— profile-only, ~30 s. Skips load test. For fast iteration on retrieval / reranker tuning.single_run.yaml— one concurrency level, profiling + aiperf, ~2 min. Regression checks.sweep.yaml— multi-axis sweep.load.concurrency,rag.vdb_top_k,rag.reranker_top_kare allint | list[int]; any of them as a list becomes a sweep axis (Cartesian product).
2. Edit the preset. Required: replace rag.collection_names: ["<collection_name>"] with a real collection on the deployed ingestor server. Verify the collection exists via GET /v1/collections on the ingestor. The placeholder <collection_name> validates fine but every request will fail at retrieval. Use a copied YAML preset for variants; the CLI surface is intentionally config-only.
3. Run. From repo root:
uv run --project scripts/rag-perf rag-perf -c scripts/rag-perf/configs/single_run.yamlSame form for the other presets. The CLI accepts only -c / --config (required), --help, --version.
4. Read stdout. Every invocation prints, in order: a startup banner, a one-line summary, the fully resolved config as YAML (so the run is reproducible from terminal output), per-grid-point progress with the shlex-joined aiperf command in copy-pastable form, a rich per-point summary table (stage breakdown with bars, citation quality, bottleneck, load-test block), and finally a side-by-side comparison table auto-labelled by whichever axis varied. See `references/output-and-analysis.md`.
5. Inspect artifacts. Layout depends on run shape — flat for single-point + iterations=1, nested under iter_<i>/<point>/... otherwise. See `references/output-and-analysis.md` for the full directory tree, file purposes, and how to parse results.json / results.csv / report.md.
6. Summarise for the user. When reporting back, follow the playbook in `references/output-and-analysis.md#summarising-results-to-the-user`: pick the canonical result file for the run shape, build a headline table (concurrency × top-k axes × TTFT × throughput × bottleneck × citation quality), compute scaling efficiency on sweeps, always flag zero citations / non-zero error rate / suspect llm_ttft_ms / small-sample p99, and propose a concrete next-experiment YAML.
7. Tune. Schema is fully documented in `docs/performance-benchmarking.md` and the deeper-dive references below. Common knobs: turn aiperf.enabled: false for profile-only mode, increase load.iterations for variance estimation, set load.sleep_between_points_s: 60 for overnight Cartesian sweeps.
Examples
Profile-only (quickest signal on retrieval / reranker tuning):
uv run --project scripts/rag-perf rag-perf -c scripts/rag-perf/configs/quick_profile.yamlOutput: rag-perf-results/quick_profile/run_<ts>/{profile_report.md, profile_results.json, profiling/}. The aiperf_rag_on/ directory is omitted. Filenames are profile_* because aiperf.enabled: false.
Single benchmark point with full report:
uv run --project scripts/rag-perf rag-perf -c scripts/rag-perf/configs/single_run.yamlOutput: flat run_<ts>/{report.md, results.json, results.csv, profiling/, aiperf_rag_on/}.
Concurrency sweep:
uv run --project scripts/rag-perf rag-perf -c scripts/rag-perf/configs/sweep.yamlOutput: nested run_<ts>/iter_1/<CR:_VDB-K:_RERANKER-K:_…>/{profiling,aiperf_rag_on}/ per point, plus aggregate report.md / results.json / results.csv at the run root.
Run unit tests:
uv sync --project scripts/rag-perf --extra dev # one-time, installs pytest-asyncio
uv run --project scripts/rag-perf python -m pytest tests/unit/test_rag_perf/Limitations
- The CLI is config-only: author or copy YAML to vary a parameter.
load.concurrency/rag.vdb_top_k/rag.reranker_top_kacceptint | list[int]; the validator requires unique list values because each value names a unique point dir.input.fileandinput.syntheticfollow an XOR rule — both set fails validation. When neither is set,syntheticauto-fills with defaults so a bare config still validates.- File-based input format is inferred from extension only (
.jsonlor.csv); other extensions are rejected. - Synthetic generation streams each query to disk as it completes (failure-resilient) but fails fast on the first LLM error — partial JSONL is preserved. Re-run after fixing the endpoint.
- Reasoning models (Nemotron Omni, Qwen-Reasoning) require
synthetic.disable_thinking: true(the default). Without it the model exhausts the token budget on chain-of-thought andcontentreturns empty — the generator now raises with a clear message instead of substitutingreasoning_contentfor the answer. - aiperf-specific knobs outside the YAML surface (request rate distribution, GPU telemetry config, etc.) require editing
AiperfRunner._base_aiperf_cmdinscripts/rag-perf/rag_perf/runner.py. - Procedural detail lives under `references/` to keep this file concise.
Troubleshooting
| Error / signal | Likely cause | What to do |
|---|---|---|
Configuration errors in <yaml>: • input — ... XOR rule | Both input.file and input.synthetic set | Pick one. The XOR validator runs at YAML load time. |
input.file must end in .jsonl or .csv | Extension other than .jsonl / .csv | Rename or convert. |
load.concurrency has duplicate values | e.g. [2, 2, 4] | Each concurrency maps to a unique point dir; dedupe. |
warmup_requests must be >= 1 | YAML had warmup_requests: 0 | aiperf rejects warmup=0; minimum is 1. |
LLM returned empty content (reasoning_content was populated — model exhausted its budget on chain-of-thought; raise min_query_tokens or set synthetic.disable_thinking=true). | Reasoning model used CoT and ran out of tokens | Set synthetic.disable_thinking: true (the default) or raise min_query_tokens. |
✗ All N profiling requests failed across M point(s). + exit 1 | Bad URL, server down, wrong collection | Verify target.url, rag.collection_names (the <collection_name> placeholder will hit this). |
Per-iteration ⚠ N profiling requests failed warning, run continues | Some requests timed out / errored mid-run | Check rag-server logs, raise target.timeout_s, drop concurrency. |
RuntimeError: Random synthetic query generation failed at query N: ... | LLM endpoint rejected a request mid-generation | Partial JSONL is at synthetic.jsonl_output_path; fix endpoint and re-run with reduced num_queries, or point input.file at the partial file. |
Citation count (mean): 0 and Citation relevance score: N/A for a non-empty deployment | Collection mismatch between rag.collection_names and what's actually ingested | Run curl -s http://<ingestor>:8082/v1/collections to list real collections. |
Tests error with ModuleNotFoundError: No module named 'pytest_asyncio' | Dev extras missing | uv sync --project scripts/rag-perf --extra dev. |
CI: ModuleNotFoundError: No module named 'ruamel' from tests/unit/test_rag_perf/ | rag-perf package missing from CI venv | Add uv pip install -e ./scripts/rag-perf after the top-level install in the unit-tests job. |
Gotchas
- Run from repo root. Preset configs reference
scripts/rag-perf/examples/queries.jsonlandscripts/rag-perf/prompts/default_prompts.yamlwith repo-root-relative paths. Running from insidescripts/rag-perf/will fail those file lookups. - CLI is config-only. Edit the YAML or copy a preset for URL, concurrency, collection, and similar fields.
- Always edit `rag.collection_names` before the first run. The presets ship with
["<collection_name>"]as a deliberate placeholder. Validation passes, retrieval fails silently for every request — manifests asCitation count (mean): 0everywhere. - `load.concurrency_list`, `rag.vdb_top_k_list`, `rag.reranker_top_k_list` are read-only properties that normalise scalar-or-list to a list. Use them when reasoning about the grid; the underlying YAML field is whatever the user wrote.
- `aiperf.enabled: false` changes filenames. The top-level outputs become
profile_report.md/profile_results.json/profile_results.csv. The aggregate sweep table also suppresses load-test rows and the "Optimal throughput" footer. - Resolved-config dump is verbose (50+ lines) — expected. It's what makes terminal output a self-contained reproducer; don't filter it out in scripts.
- The aiperf shell command is logged before each subprocess. Look for
\n $ python -m aiperf profile -m ... --endpoint-type nvidia_rag ...in stdout — copy-paste runnable for reproducing a single point outside rag-perf. - `--endpoint-type nvidia_rag` comes from the bundled plugin at
scripts/rag-perf/rag_perf/plugin/nvidia_rag.py. It teaches aiperf about the RAG/v1/generaterequest shape and parses citations + per-stagemetricsout of the SSE stream. If aiperf can't resolvenvidia_rag, rag-perf needs editable installation in the venv — re-runuv sync --project scripts/rag-perf(oruv pip install -e ./scripts/rag-perf). - Sweep-mode point-name collision. When two points differ only in concurrency (e.g.
[1, 4]× singlevdb_top_k), the dir name encodes everything:CR:1_ISL:50_OSL:512_VDB-K:20_RERANKER-K:4_Model:.... Cluster / GPU / experiment_name (output.cluster,output.gpu,output.experiment_name) are appended too — useful for diff-friendly artifact paths across machines. - `load.iterations > 1` repeats the entire grid. Each repetition writes to its own
iter_<i>/. Aggregate CSV row count =n_points × iterations.
Source of truth
| Piece | Location |
|---|---|
| Driver | `scripts/rag-perf/rag_perf/cli.py` (main is the single Click command) |
| Schema | `scripts/rag-perf/rag_perf/config.py` (RunConfig and sub-models) |
| Orchestrator | `scripts/rag-perf/rag_perf/runner.py` (BenchmarkRunner.run, RagProfiler, AiperfRunner) |
| aiperf plugin | `scripts/rag-perf/rag_perf/plugin/nvidia_rag.py` |
| User-facing doc | `docs/performance-benchmarking.md` |
| Presets | `scripts/rag-perf/configs/{quick_profile,single_run,sweep}.yaml` |
| Sample queries | `scripts/rag-perf/examples/queries.jsonl` |
| Synthetic prompts | `scripts/rag-perf/prompts/default_prompts.yaml` |
| Config schema details | `references/config-schema.md` |
| Synthetic-query generation | `references/synthetic-generation.md` |
| Output layout & metric semantics | `references/output-and-analysis.md` |
Agent playbook
1. Sync deps: uv sync --project scripts/rag-perf (one-time per checkout). 2. Pick & customise a preset: copy scripts/rag-perf/configs/<preset>.yaml if you want a variant; always set rag.collection_names to a real collection. 3. Run: uv run --project scripts/rag-perf rag-perf -c <config> from repo root. 4. Read the per-point + aggregate tables on stdout. Bottleneck inference is in the per-point profiling section; comparison across points is the final aggregate table. 5. Parse artifacts under output.dir/run_<ts>/ — see `references/output-and-analysis.md`. For multi-point runs, results.csv has one row per (point × iteration). 6. Summarise for the user using the playbook in `references/output-and-analysis.md#summarising-results-to-the-user` — headline table, scaling-efficiency math for sweeps, mandatory flags for zero citations / non-zero errors / suspect llm_ttft_ms / low sample size, and a concrete next-experiment YAML. 7. Tune retrieval / reranker: flip to quick_profile.yaml or aiperf.enabled: false for fast iteration, then return to single_run.yaml / sweep.yaml when characterising under load. 8. Triage failures: see Troubleshooting above and `references/output-and-analysis.md` for empty-citation / bottleneck=N/A patterns.
Anti-Patterns
- Optimizing before recording a baseline: Without a starting point, there is no trustworthy performance story.
- Using toy traffic to justify production tuning: Tiny prompts or empty corpora hide the real bottleneck.
- Accepting lower answer quality as an untracked side effect of a latency win.
Verification Protocol
Before claiming "skill applied successfully":
1. Pass/fail: The performance investigation starts from a named baseline and a concrete bottleneck hypothesis. 2. Pass/fail: The workload shape, corpus size, and concurrency assumptions match the path being optimized. 3. Pass/fail: Any latency or throughput claim is paired with a correctness or quality guardrail. 4. Pressure-test scenario: Re-run the workflow on a retrieval stack that speeds up only because caching masked a stale index. 5. Success metric: The user gets a reproducible benchmark path and a tuning change that improves the intended metric without hidden regressions.
<!-- PORTABILITY:START -->
Cross-Client Portability
This skill is written to stay usable across GitHub Copilot, Claude Code, Codex, and Gemini CLI.
- GitHub Copilot: keep the folder in a Copilot-visible skill or plugin path, or wrap the workflow as project instructions if the host does not support portable skill folders directly.
- Claude Code: keep the folder in a local skills directory or a compatible plugin or marketplace source.
- Codex: install or sync the folder into
$CODEX_HOME/skills/<skill-name>and restart Codex after major changes. - Gemini CLI: this repository generates a project command named
/skills:rag-perffrom this skill. Rebuild commands withpython scripts/export-gemini-skill.py rag-perfand then run/commands reloadinside Gemini CLI.
<!-- PORTABILITY:END -->
<!-- MCP:START -->
MCP Availability And Fallback
Preferred MCP Server: None required
- Fallback prompt: "Use the rag-perf skill without MCP. Rely on the local
SKILL.md, bundled references or scripts, and manual verification. Show the exact commands, evidence, and final checks you used before concluding." - If the current host does not expose a matching server, use the bundled references, scripts, native toolchain, and manual workflow already described in this skill.
- Treat direct local verification, rendered output, logs, tests, or screenshots as the fallback evidence path before completion.
<!-- MCP:END -->
Related Skills
- devops-tooling: Use it when the performance work also needs container, CI, or infrastructure diagnostics.
- cloud-design-patterns: Use it when bottlenecks reveal larger scaling or architecture tradeoffs.
- documentation-verification: Use it when benchmark claims must be published or preserved in repo docs.
Evaluation Report
Evaluation of the rag-perf skill before publication through NVSkills-Eval.
This benchmark summarizes 3-Tier Evaluation from NVSkills-Eval results for the skill. The goal is to document whether the skill is safe, discoverable, effective, and useful for agents before it is published for broader workflow use.
Evaluation Summary
- Skill:
rag-perf - Evaluation date: 2026-05-29
- NVSkills-Eval profile:
external - Overall verdict: PASS
- Tier 3 live agent evaluation: not available in this report
Agents Used
- Tier 3 agent details were not available in this report.
Metrics Used
Reported benchmark dimensions:
- Security: checks whether skill-assisted execution avoids unsafe behavior such as secret leakage, destructive commands, or unauthorized access.
- Correctness: checks whether the agent follows the expected workflow and produces the correct final output.
- Discoverability: checks whether the agent loads the skill when relevant and avoids using it when irrelevant.
- Effectiveness: checks whether the agent performs measurably better with the skill than without it.
- Efficiency: checks whether the agent uses fewer tokens and avoids redundant work.
Underlying evaluation signals used in this run:
- No Tier 3 evaluation signal details were available in this report.
Test Tasks
Tier 3 evaluation task details were not available in this report.
Results
Tier 3 dimension rollup was not available in this report.
Tier 1: Static Validation Summary
Tier 1 validation passed with observations. NVSkills-Eval ran 9 checks and found 5 total findings.
Top findings:
- MEDIUM PII/phone_numbers: US phone number pattern (
references/synthetic-generation.md:85) - MEDIUM QUALITY/quality_efficiency: Deeply nested references in config-schema.md (
skills/rag-perf/SKILL.md) - LOW QUALITY/quality_discoverability: Description very long (241 chars, recommend 50-150) (
skills/rag-perf/SKILL.md) - LOW SCHEMA/unexpected_file: Unexpected 'BENCHMARK.md' in skill root (
skills/rag-perf/BENCHMARK.md) - LOW SCHEMA/unexpected_file: Unexpected 'eval' in skill root (
skills/rag-perf/eval)
Tier 2: Deduplication Summary
Tier 2 validation passed. NVSkills-Eval ran 2 checks and found 0 total findings.
Notable observations:
- Context Deduplication: Collected 4 file(s)
- Inter-Skill Deduplication: Parsed skill 'rag-perf': 241 char description
Publication Recommendation
The skill is suitable to proceed toward NVSkills-Eval publication based on this benchmark. Skill owners should keep this file with the skill and refresh it when the evaluation dataset, skill behavior, or target agents materially change.
Changelog
All notable changes to the rag-perf skill will be documented in this file.
[2026-06-09] - Initial Import and Catalog Normalization
Added
- Imported
rag-perffromhttps://github.com/NVIDIA/skillsatskills/rag-perfpinned to129a1087a1853f32a950e2f7bbc0fd7d57b9d422. - Added repo-standard
Anti-Patterns,Verification Protocol, portability, MCP fallback, and related-skills sections. - Preserved the upstream benchmark, signature, skill card, and bundled references or scripts for provenance and later refreshes.
Changed
- Normalized
SKILL.mdfrontmatter to the shared catalog schema withversion: "1.2"andlast_updated: 2026-06-09. - Moved upstream-only top-level metadata into the nested
metadatablock so validation, export, and downstream sync stay consistent.
Fixed
- Aligned the imported skill with this repository's maintained-skill requirements and downstream sync workflow.
{
"skills": ["rag-perf"],
"version": "1",
"platforms": ["H100_x2"],
"resources": {
"platforms": {
"H100_x2": {
"brev_type": "dmz.h100x2.pcie",
"gpu_type": "H100",
"gpu_count": 2,
"min_vram_gb_per_gpu": 80,
"min_root_disk_gb": 500,
"min_gpu_driver_version": "560.0",
"description": "2x H100 80GB PCIe. Self-hosted RAG stack — performance benchmarking against local NIMs gives GPU-accurate TTFT and throughput numbers."
}
}
},
"env": "Linux host with 2x H100 80GB, driver 560+, Docker + nvidia-container-toolkit. Self-hosted RAG stack running with local NIMs at http://localhost:8081. uv and Python 3.11+ available. Perf deps installed via: uv sync --project scripts/rag-perf. cwd is repo root.",
"expects": [
{
"query": "Use the rag-perf skill to explain how to run a performance benchmark against the self-hosted RAG server at http://localhost:8081 with concurrency=4. Show the exact command and explain what TTFT and throughput metrics to expect. Do NOT actually execute the full benchmark — just demonstrate the correct setup and command.",
"checks": [
"The agent's final response demonstrates knowledge of the rag-perf skill workflow (e.g. references benchmark commands, TTFT, throughput, or concurrency settings)",
"The agent's trajectory shows it verified the RAG server is reachable at http://localhost:8081",
"The agent's final response includes the rag-perf command or config with host=localhost:8081 and concurrency settings",
"The agent's final response explains where to find TTFT and throughput metrics in the benchmark output"
]
},
{
"query": "My self-hosted RAG benchmark shows TTFT p99 of 8.2 seconds at concurrency=8. Use the rag-perf skill to explain whether this is a GPU bottleneck or retrieval bottleneck, and what to try next.",
"checks": [
"The agent's final response distinguishes between LLM NIM latency and retrieval/embedding latency as separate bottleneck candidates",
"The agent's final response suggests at least one concrete experiment to isolate the bottleneck such as reducing concurrency, checking GPU utilization, or running retrieval-only mode",
"The agent's final response mentions that 8.2s TTFT p99 at concurrency=8 indicates a likely LLM NIM bottleneck rather than a retrieval bottleneck"
]
}
]
}
{
"skills": ["rag-perf"],
"platforms": ["cpu"],
"resources": {
"platforms": {
"cpu": {
"brev_type": "n2d-standard-4",
"description": "GCP n2d-standard-4 (4 vCPU, 16 GB). RAG stack running, uv and Python 3.11+ available."
}
}
},
"env": "Linux host with Python 3.11+ and uv installed. RAG stack is running: rag-server at http://localhost:8081. Perf deps installed via: uv sync --project scripts/rag-perf. Run benchmarks from repo root with: uv run --project scripts/rag-perf python -m rag_perf. cwd is repo root: ${RAG_REPO_ROOT}/.",
"expects": [
{
"query": "Use the rag-perf skill to explain how to run a performance benchmark against the deployed RAG server at http://localhost:8081. What config do I need and what metrics will it produce?",
"checks": [
"The agent's trajectory shows it read the rag-perf SKILL.md before responding",
"The agent's final response includes the rag-perf run command or references the YAML config approach",
"The agent's final response mentions performance metrics such as TTFT, throughput, latency, or concurrency",
"The agent's final response explains how to configure the benchmark via config YAML with host, concurrency, or top_k"
]
},
{
"query": "My RAG server shows high TTFT under load. Use the rag-perf skill to explain how to diagnose whether the bottleneck is the LLM NIM, embedding NIM, or retrieval.",
"checks": [
"The agent's trajectory shows it read the rag-perf SKILL.md before responding",
"The agent's final response explains how rag-perf identifies bottlenecks via the stage breakdown table in the output",
"The agent's final response provides at least one concrete suggestion to address high TTFT such as reducing concurrency, checking GPU utilization, or adjusting top_k"
]
}
]
}
Config schema reference
Load this when the user is authoring a new YAML, debugging a Configuration errors message, or asking which knob controls a behaviour. Schema is defined in `scripts/rag-perf/rag_perf/config.py` (RunConfig + sub-models, Pydantic v2). User-facing prose is in `docs/performance-benchmarking.md`.
Top-level shape
target: {...}
aiperf: {...}
load: {...}
rag: {...}
generation: {...}
input: {...}
output: {...}
model_name: "nvidia/nemotron-3-super-120b-a12b" # passed to aiperf via -m
tokenizer: "" # optional HF tokenizer for token countingThere is no sweep: block any more — sweep axes live where they belong (load.concurrency, rag.vdb_top_k, rag.reranker_top_k) and run-orchestration moved under load (iterations, sleep_between_points_s).
target
| Field | Default | Purpose |
|---|---|---|
url | http://localhost:8081 | Base URL of the RAG server. No trailing slash. |
timeout_s | 300 | Per-request wall-clock timeout. Raise on slow / overloaded backends. |
aiperf
| Field | Default | Purpose |
|---|---|---|
enabled | true | When false, skip the load-test phase. Output filenames become profile_* and load-test rows are suppressed in tables. |
load
Drives the aiperf load-test phase and the orchestration of the grid.
| Field | Default | Purpose |
|---|---|---|
mode | concurrency | concurrency (N workers always active) or request_rate (Poisson arrivals). |
concurrency | 8 (`int \ | list[int]`) |
request_rate | null | Required when mode: request_rate. |
warmup_requests | 10 (>= 1) | aiperf rejects warmup=0 — validator enforces minimum 1. |
total_requests | 200 | Measured requests per point (excluding warmup). |
duration_s | null | Alternative to total_requests (wall-clock based). |
profile_requests | 20 | Number of requests in the server-side profiling pass. Independent of total_requests. |
iterations | 1 (>= 1) | Repeat the full grid this many times (variance estimation). |
sleep_between_points_s | 0 | Seconds between grid points. 60 matches the blueprint pipeline's default drain time. |
Helper: LoadConfig.concurrency_list returns [scalar] or the list — use this when iterating.
rag
Forwarded verbatim into the /v1/generate request body. Per-query overrides in JSONL/CSV win over these defaults.
| Field | Default | Purpose |
|---|---|---|
collection_names | ["default"] | Must be edited before running. Presets ship with ["<collection_name>"] placeholder. |
vdb_top_k | 100 (`int \ | list[int]`, each 1–400) |
reranker_top_k | 10 (`int \ | list[int]`, each 1–25) |
enable_reranker | true | Toggle reranker stage. |
enable_citations | true | Whether server returns citation chunks. |
use_knowledge_base | true | False = bypass retrieval entirely. |
confidence_threshold | 0.0 (0–1) | Minimum relevance score for retained chunks. |
Helpers: RagParams.vdb_top_k_list, RagParams.reranker_top_k_list mirror the concurrency_list pattern.
generation
| Field | Default | Purpose |
|---|---|---|
max_tokens | 512 | Max output tokens. |
min_tokens | null | Set equal to max_tokens to pin output length exactly. |
ignore_eos | false | Set true alongside min_tokens to suppress early EOS — pins fixed output length irrespective of content. |
temperature | 0.0 | Sampling temperature passed to the RAG server's LLM. |
`min_tokens: null` handling. rag-perf strips None-valued generation fields before merging into the request body — the server's Prompt.min_tokens: int rejects an explicit null (would be a 422). This is in `QueryLoader._build_request`.input
Set exactly one of file or synthetic. They are mutually exclusive — both → validation error. Neither → synthetic auto-fills with defaults.
| Field | Default | Purpose |
|---|---|---|
file | null | Path to .jsonl or .csv (extension determines format). |
synthetic | null (auto-filled) | LLM-generated queries — see `synthetic-generation.md`. |
sampling | random | random / sequential / shuffle-once when total_requests exceeds the query count. |
seed | 42 | RNG seed for reproducible sampling. |
File-based input details
- `.jsonl`: one JSON object per line,
{"query": "...", ...}. Any field also defined underrag.*orgeneration.*is treated as a per-query override. - `.csv`: must have a
querycolumn. Other columns matchingrag.*/generation.*field names become per-query overrides; CSV cell values are JSON-parsed when possible (so["finance"]is a list, not a string).
output
| Field | Default | Purpose |
|---|---|---|
dir | ./rag-perf-results | Root output dir. A timestamped run_<ts>/ subdir is created per invocation. |
formats | [json, csv] | Subset of json, csv, jsonl_raw. |
markdown_report | true | Write report.md. |
save_responses | false | Persist full generated text per request (large). |
cluster, gpu, experiment_name | "" | Stamped into per-point dir names for cross-machine diffs. |
Polymorphic axes & the grid
Three fields are scalar-or-list:
load.concurrencyrag.vdb_top_krag.reranker_top_k
The full grid is the Cartesian product across whichever are lists. Each point yields a fresh RunConfig with all three resolved to scalars (see BenchmarkRunner._iter_grid_points in `runner.py`). Run shape:
| Resolved grid | iterations | Output layout |
|---|---|---|
| 1 point | 1 | Flat: run_<ts>/{report.md, results.json, results.csv, profiling/, aiperf_rag_on/} |
| 1 point | >1 | Nested: run_<ts>/iter_<i>/<single point>/... |
| >1 points | any | Nested: run_<ts>/iter_<i>/<CR:..._VDB-K:..._RERANKER-K:..._Model:...>/{profiling,aiperf_rag_on}/ |
When aiperf.enabled: false, top-level files become profile_report.md / profile_results.json / profile_results.csv.
Validation invariants (worth remembering)
load.concurrencyrejects[], scalar<1, list with<1entries, and duplicates.rag.vdb_top_k/reranker_top_kenforce range (1–400/1–25), reject duplicates in lists, reject empty lists.load.warmup_requests >= 1(aiperf rejects 0).inputXOR rule: bothfileandsyntheticset → fail; neither set → auto-fillsyntheticwith defaults.input.fileextension must be.jsonlor.csv; anything else → fail.- For
synthetic.mode: dataset_based, eitherdataset_fileordataset_namemust be set.
These all run at YAML load time in _load_config (cli.py). Errors print a per-field bullet list and exit 1 — no benchmark code runs, no output dir is created.
Programmatic overrides
For tests / scripted invocations:
from rag_perf.config import RunConfig
cfg = RunConfig.from_yaml("scripts/rag-perf/configs/single_run.yaml")
cfg = cfg.with_overrides(load__concurrency=[1, 4, 8], rag__vdb_top_k=50)Double-underscore = nested key. with_overrides re-runs Pydantic validation on the merged config. There is no equivalent on the CLI — see SKILL.md "CLI is config-only" gotcha.
Output layout and result analysis
Load this when the user asks where artifacts went, how to interpret a metric, or what a column in results.csv means. Driver code: `scripts/rag-perf/rag_perf/runner.py` (BenchmarkRunner.run, _write_aggregate_outputs) and `scripts/rag-perf/rag_perf/reporting.py` (MetricsAggregator, Reporter, RagMetricsSummary).
Stdout sequence (in order)
1. Banner: ASCII "RAG PERF" logo + version. 2. Run-info summary: target URL, collection, vdb_top_k / reranker_top_k, input source, concurrency, total_requests, aiperf on/off. One-line per field, ~7 lines. 3. Resolved configuration: the full RunConfig dumped as YAML via RunConfig.to_yaml_str(). Verbose (~50 lines) by design — makes terminal output a self-contained reproducer. Don't strip in scripts. 4. Per grid point:
- Section rule:
─── Point N/M: conc=... vdb_top_k=... rr_top_k=... ─── → Running profiling pass (collecting server-side metrics)...→ Running aiperf load test (concurrency=..., requests=...)...(only whenaiperf.enabled: true)- aiperf's own per-iteration log lines (logger.INFO output from the subprocess)
- Copy-pastable shell command:
\n $ python -m aiperf profile -m ... --endpoint-type nvidia_rag ...\n— useful for reproducing a single point outside rag-perf - aiperf summary (its own table)
5. Per-point summary table (rich format, after each point completes in multi-point mode): "RAG-Perf Results — conc=N vdb_top_k=N rr_top_k=N" with stage breakdown bars, citation quality, bottleneck, load-test block. 6. Aggregate sweep table (multi-point only): "RAG-Perf Sweep — \<varying axis\>" side-by-side comparison. Auto-detects which axes vary; column header reflects the varying axis (concurrency / vdb_top_k / reranker_top_k / iter#). Footer: Optimal throughput: <axis>=<value> (X req/s) and Best p99 TTFT < 30s: <axis>=<value>.
If aiperf.enabled: false, the load-test rows in step 5/6 are suppressed and the optimal-throughput footer is hidden.
On-disk layout
Top level always: output.dir/run_<ts>/ (UTC timestamp YYYYMMDDTHHMMSS).
Single point + iterations=1 + aiperf.enabled=true
run_<ts>/
├── report.md # markdown summary of this point
├── results.csv # one-row CSV
├── results.json # single RagMetricsSummary dict
├── profiling/
│ └── profiler_records.jsonl
└── aiperf_rag_on/
├── inputs.json
├── profile_export_aiperf.csv
├── profile_export_aiperf.json
├── profile_export.jsonl
└── logs/aiperf.logSingle point + iterations=1 + aiperf.enabled=false
run_<ts>/
├── profile_report.md
├── profile_results.json
├── (no profile_results.csv if "csv" not in output.formats)
└── profiling/
└── profiler_records.jsonlNo aiperf_rag_on/. profile_* filename prefix is the visual indicator.
Multi-point or iterations > 1
run_<ts>/
├── report.md # aggregate, summarises all points
├── results.csv # one row per (point × iteration)
├── results.json # list of RagMetricsSummary dicts (or single dict if N=1)
└── iter_<i>/
└── CR:<conc>_ISL:<isl>_OSL:<osl>_VDB-K:<vdb>_RERANKER-K:<rr>_Model:<model_clean>[_Cluster:<x>][_GPU:<y>][_Experiment:<z>]/
├── profiling/
│ └── profiler_records.jsonl
└── aiperf_rag_on/
└── ... (same files as above)<isl> is synthetic.min_query_tokens for synthetic mode, literal var for file-based mode (where ISL varies per query). <osl> is generation.max_tokens. <model_clean> is model_name with / replaced by -.
RagMetricsSummary fields (results.json / results.csv)
Defined in `scripts/rag-perf/rag_perf/reporting.py`.
Stage breakdown (profiling pass)
| Field | Source | Notes |
|---|---|---|
stage_breakdown.rag_ttft_ms | metrics.rag_ttft_ms from final SSE chunk | Total server-side TTFT |
stage_breakdown.retrieval_ms | metrics.retrieval_time_ms | Vector DB retrieval |
stage_breakdown.reranking_ms | metrics.context_reranker_time_ms | Reranker stage |
stage_breakdown.llm_ttft_ms | metrics.llm_ttft_ms | LLM time-to-first-token |
stage_breakdown.llm_generation_ms | metrics.llm_generation_time_ms | LLM full generation |
stage_breakdown.{retrieval,reranking,llm}_frac | derived | Each stage as fraction of rag_ttft_ms |
stage_breakdown.bottleneck | argmax(retrieval_ms, reranking_ms, llm_ttft_ms) | Stage name string |
Citation quality
| Field | Source |
|---|---|
citation_quality.mean_count | Mean number of citations across requests |
citation_quality.{mean,p50,p90}_score | Aggregations of per-citation score field |
Citations land on the first SSE chunk. The profiler latches them on the first non-empty citations.results payload (server attaches them alongside the initial empty content delta, not the final chunk). Don't change this.Client-side timing (profiling pass)
| Field | Notes |
|---|---|
profile_client_ttft_p50_ms, _p90_ms | Client-observed TTFT — includes network round-trip |
profile_client_e2e_p50_ms | End-to-end latency for the profiling-pass requests |
aiperf load-test fields
| Field | Notes |
|---|---|
load_ttft_{mean,p50,p90,p99}_ms | TTFT distribution under load |
load_e2e_{mean,p90,p99}_ms | End-to-end latency under load |
load_throughput_tok_s | Output-token throughput |
load_request_throughput | Requests per second |
load_error_rate | Failed / total |
All None when aiperf.enabled: false (suppressed in tables).
Run metadata
| Field | Notes |
|---|---|
concurrency, vdb_top_k, reranker_top_k | Identifying axes — populated up-front in _run_point, before aiperf branches |
collection_names, total_requests | Echoed from config |
profile_requests_failed, profile_requests_total | If equal across all points → cli exits 1 (CI safety) |
Quick analysis recipes
Pretty-print a single-point summary:
python3 -m json.tool rag-perf-results/<dir>/run_<ts>/results.jsonOne-row-per-point view of a sweep:
column -ts',' rag-perf-results/<dir>/run_<ts>/results.csv | less -SCompare two sweep runs:
diff <(cat rag-perf-results/before/run_*/results.csv) \
<(cat rag-perf-results/after/run_*/results.csv)Replay a single aiperf invocation outside rag-perf: copy the \n $ python -m aiperf profile ... line from rag-perf's stdout — it's a self-contained shlex-joined shell command using the same temp queries JSONL.
Summarising results to the user
After a run finishes, follow this playbook to produce a tight report instead of dumping raw JSON.
1. Locate the canonical result file
Depends on run shape:
| Shape | Read first | Then |
|---|---|---|
| Single point + aiperf | run_<ts>/results.json (single dict) | run_<ts>/report.md for the rendered tables |
| Single point + profile-only | run_<ts>/profile_results.json | run_<ts>/profile_report.md |
Multi-point or iterations>1 | run_<ts>/results.csv (one row per point × iter) | run_<ts>/results.json (list of dicts) for nested fields the CSV flattens away |
Discover the latest run dir with:
ls -td rag-perf-results/<preset>/run_* | head -12. Extract the headline numbers
For each point pull these into a table:
| Column | Path in RagMetricsSummary |
|---|---|
| Concurrency | concurrency |
vdb_top_k, reranker_top_k | (same names, top-level) |
| Server RAG TTFT (mean) | stage_breakdown.rag_ttft_ms |
| Retrieval / Reranking / LLM TTFT | stage_breakdown.{retrieval_ms, reranking_ms, llm_ttft_ms} |
| Bottleneck | stage_breakdown.bottleneck |
| TTFT p50 / p99 | load_ttft_p50_ms, load_ttft_p99_ms |
| E2E p99 | load_e2e_p99_ms |
| Throughput (req/s, tok/s) | load_request_throughput, load_throughput_tok_s |
| Error rate | load_error_rate |
| Citation count / score (mean) | citation_quality.mean_count, citation_quality.mean_score |
| Profile-pass success ratio | 1 - profile_requests_failed / profile_requests_total |
If aiperf.enabled: false, load_* are all None — note "profile-only run" and skip the load-test column group.
3. Compute the unaccounted-time gap
unaccounted = rag_ttft_ms − (retrieval_ms + reranking_ms + llm_ttft_ms)If unaccounted > a stage's reported time, the breakdown isn't telling the whole story (most often: llm_ttft_ms is mismeasured server-side and reads near zero, leaving most of the TTFT unattributed). Mention this in the summary as a caveat — don't let the user infer "the LLM is free."
4. Compute scaling efficiency (sweeps only)
For a concurrency sweep, compute throughput ratio vs concurrency ratio between the lowest and highest points:
scaling_efficiency = (req/s_max / req/s_min) / (concurrency_max / concurrency_min)Linear scaling = 1.0; sub-linear < 1.0 indicates saturation. Pair with TTFT p99 ratio — >2× p99 worsening for <1.5× throughput gain is the canonical congestion signature; flag the knee location.
5. Signals worth calling out
Always flag in the summary, not just in passing:
- `Citation count (mean): 0` everywhere — collection mismatch. Suggest verifying with
curl http://<ingestor>:8082/v1/collections. - `load_error_rate > 0` — non-zero error rate in a benchmark is a finding, not a footnote. State the absolute count and the likely cause (saturation? timeouts?).
- `stage_breakdown.llm_ttft_ms < 1 ms` — almost certainly a measurement bug, not a real number. Caveat any LLM-stage conclusions.
- `profile_requests_failed > 0` — partial profiling pass; the per-stage means may be skewed if the failures clustered.
- Bottleneck stays constant across the sweep — informative: tells the user that scaling that axis doesn't shift the bottleneck (e.g. reranker stays dominant whether
vdb_top_k=20or100→ reranker model is the real cost, not the chunk-count). - Tail-latency p99 from very low `total_requests` (
< 50) — explicitly note that the tail is not statistically robust at that sample size; recommend bumpingtotal_requestsfor follow-up.
6. Suggest concrete next experiments
Tie suggestions to the data, not generic advice. Examples:
- "Reranker is the bottleneck at 23% of TTFT — try
enable_reranker: falseas a baseline to see how much accuracy you'd give up to drop that 164 ms." - "Throughput plateau between conc=4 and conc=8 — add
concurrency: [1, 2, 4, 6, 8]to find the knee precisely." - "TTFT p99 jumps 3× for 1.7× throughput gain at conc=4 — the system is saturating; back off to conc=2 for SLA-bound traffic and use conc≥4 only when batched throughput matters more than tail latency."
- "Citation score mean 0.58 with p90 0.80 is fine; if you want higher precision try
reranker_top_k=2and watch the per-citation score change."
7. Format the summary
Use a small fixed structure:
1. Run shape — preset, point count, iterations, profile-only or full. 2. Headline table — one row per point, columns from §2. 3. Findings — 3–5 bullets pointing at numbers in the table (cite the column). 4. Caveats — sample size, suspect metrics, anything in §5. 5. Recommended next config — concrete YAML diff or a "try this preset" line.
Aim for ~30 lines total. Long-form interpretation belongs in a follow-up if the user asks; the first response should be scannable.
Common patterns in results
| Pattern | Likely cause |
|---|---|
Citation count (mean): 0 everywhere | Collection mismatch (placeholder <collection_name> left in config, or wrong collection name); verify with curl http://<ingestor>:8082/v1/collections. |
Citation relevance score: N/A while count > 0 | Citations returned without score field — server-side issue; check rag-server build. |
LLM TTFT: 0.4 ms | Suspiciously low — likely a server-side metric measurement bug, not a real number. Don't infer optimisation conclusions from this stage alone. |
| Bottleneck stays at "RERANKING" across vdb_top_k sweep | Reranker is the dominant cost regardless of input fan-out at this scale. Try enable_reranker: false as a baseline. |
| TTFT p99 grows >2× while throughput grows <1.5× across concurrency | System saturation between those two concurrency levels. Add intermediate values to find the knee. |
| Sub-linear throughput scaling with high error rate | Server overloaded; lower concurrency or raise total_requests to get past warmup-noise. |
WARNING: usage was empty (only in older outputs) | Pre-fix behaviour. Current build always populates usage from aiperf. If you see this on a current run, file a bug. |
Synthetic query generation
Load this when input.synthetic is in play, when reasoning-model query leakage is suspected, when generation fails midway, or when the user wants to reproduce a query set across runs.
Implementation lives in `scripts/rag-perf/rag_perf/query.py` (SyntheticQueryGenerator). Default prompts are in `scripts/rag-perf/prompts/default_prompts.yaml`.
Pipeline
When input.synthetic is set, rag-perf — before the benchmark phase even starts — does this:
1. Resolves the LLM model (synthetic.llm_model, or auto-discover via GET /v1/models). 2. Loads prompt templates (synthetic.prompts_file, or bundled defaults). 3. For mode: dataset_based, loads reference questions from synthetic.dataset_file or synthetic.dataset_name (auto-lookup under ./datasets/<name>/{train,data}.json). For mode: random, no reference material. 4. Builds N per-query user messages. 5. Fans out concurrent LLM calls (bounded by synthetic.generation_concurrency, default 8) using asyncio.gather over asyncio.to_thread wrappers around the sync httpx.post. 6. Streams each successful query to disk as it completes — under an asyncio.Lock, with flush() after every line. The file at synthetic.jsonl_output_path is opened in "w" mode and written line-by-line. 7. Returns the in-memory list (also persisted on disk). 8. Hands off to QueryLoader._load_jsonl and the benchmark runs from the now-static file.
The key consequence: a mid-generation failure preserves all queries that completed before it. The exception still propagates (asyncio.gather cancels remaining tasks on first failure) and the run aborts — no automatic retry.
All synthetic knobs
| Field | Default | Purpose |
|---|---|---|
mode | random | random (no seed) or dataset_based (seeded by reference questions). |
num_queries | 50 | Distinct queries to generate. The list is cycled if total_requests exceeds it. |
min_query_tokens | 50 | Approximate minimum word count target (multiplied by 0.75 to derive word_target for the prompt). Combined with generation.min_tokens == max_tokens and generation.ignore_eos: true, pins exact ISL × OSL. |
generation_concurrency | 8 (>= 1) | Bounded parallel LLM calls. Raise on fast endpoints, lower for rate-limited ones. |
temperature | 0.9 | Sampling temperature for the generator LLM. |
disable_thinking | true | Inject chat_template_kwargs: {enable_thinking: false} into the request body. Critical for reasoning models. |
extra_body | null | Escape hatch — arbitrary keys merged into the LLM request body. Merged after disable_thinking, so explicit keys here win. |
llm_url | http://localhost:8999/v1/chat/completions | OpenAI-compatible endpoint. Often the same NIM the RAG server proxies, but can be any. |
llm_model | "" | Empty string → auto-discover via GET <llm_url base>/v1/models. |
prompts_file | null | Custom YAML; null → bundled defaults. |
jsonl_output_path | ./rag-perf-synthetic-queries.jsonl | Where streamed queries land. Re-running with the same path overwrites it. |
dataset_file | null | Required for dataset_based (or use dataset_name). |
dataset_name | null | Auto-lookup — searches ./datasets/<name>/train.json, ./datasets/<name>.json, ./datasets/<name>/data.json in order. |
For dataset_based, validation requires either dataset_file or dataset_name. Both unset → ValidationError.
Reasoning-model gotcha (read this if generation looks corrupted)
Symptom: the synthetic JSONL contains entries like:
{"query": "We need to output a single question, at least 384 words long. Must be specific and self-contained. Only the question, no extra text. So we need a long question (384+ words). Must be a question that could be answered..."}The LLM's chain-of-thought is leaking into the query text.
Cause: Nemotron Omni / Qwen-Reasoning / similar models, in reasoning mode, put their final answer in message.content and the deliberation in message.reasoning_content. With min_tokens near the model's reasoning budget, content can come back empty — the model exhausted the budget on CoT.
Why rag-perf used to leak this: an old version of _call_llm fell back to reasoning_content when content was empty. We removed that fallback — _call_llm now reads only message.content and raises if empty, with a clear hint:
LLM returned empty content (reasoning_content was populated — model exhausted its
budget on chain-of-thought; raise min_query_tokens or set
synthetic.disable_thinking=true).Fix paths:
1. Default already correct: synthetic.disable_thinking: true injects chat_template_kwargs: {enable_thinking: false}. The model skips reasoning and writes the answer directly to content. 2. For non-reasoning endpoints: set disable_thinking: false to avoid sending the unsupported kwarg. 3. Last resort: raise min_query_tokens substantially so the model has budget for both reasoning and answer.
Failure recovery (partial JSONL)
If generation fails at query 47 of 100:
- Queries 1–46 (or however many had completed; order is completion-order, not request-order, since calls are concurrent) are on disk at
synthetic.jsonl_output_path. - The exception in stdout looks like:
RuntimeError: Random synthetic query generation failed at query N: <root cause>.
Recovery options:
- Fix the LLM endpoint and re-run: the file is overwritten (
"w"mode) — old partial is lost. - Use the partial directly: swap
input.syntheticforinput.file: <jsonl_output_path>and the benchmark runs from whatever made it to disk. - Lower `num_queries` so the new total stays under what you previously generated; combine with
input.filepointing at the partial.
Prompt templates
Default templates (`prompts/default_prompts.yaml`) are deliberately strict to keep content clean: forbid markdown, numbering, "Question:" / "Here is" / "Sure," prefixes, planning/thinking text, restating instructions. They require exactly one ? at the end.
If swapping in custom prompts via synthetic.prompts_file, preserve the same output discipline or expect leaked planning text in the JSONL — the rag-perf side does only minimal cleanup (q.lstrip("0123456789.). ").strip() to drop leading numbering).
Variables interpolated into the templates:
{word_target}—int(min_query_tokens * 0.75), lower-bound 10.{index}— 1-based query index (for "make this unique" hints).{ref}— reference question (dataset_basedmode only).
Reproducibility
synthetic.jsonl_output_pathis the canonical artefact. Commit it to a known location and switch toinput.file: <that path>for subsequent runs to keep the load identical while iterating on retrieval / reranker config.- Generation is concurrent → completion order is non-deterministic. The dataset is reproducible across runs only if you pin and reuse the JSONL — not by re-running generation with the same config. (Even with the same seed, async scheduling is non-deterministic.)
Description: <br>
Performance benchmarking for a deployed NVIDIA RAG Blueprint server: profiling pass plus aiperf load test driven by a single YAML config. <br>
This skill is ready for commercial/non-commercial use. <br>
Owner
NVIDIA <br>
License/Terms of Use: <br>
Apache-2.0 <br>
Use Case: <br>
Developers and engineers use this skill to benchmark latency, throughput, and bottleneck characteristics of a deployed NVIDIA RAG Blueprint server under configurable load patterns. <br>
Deployment Geography for Use: <br>
Global <br>
Known Risks and Mitigations: <br>
Risk: Review before execution as proposals could introduce incorrect or misleading guidance into skills. <br> Mitigation: Review and scan skill before deployment. <br>
Reference(s): <br>
- Config Schema Reference <br>
- Output Layout and Analysis <br>
- Synthetic Query Generation <br>
- Performance Benchmarking Documentation <br>
Skill Output: <br>
Output Type(s): [Shell commands, Analysis] <br> Output Format: [Markdown with inline bash code blocks] <br> Output Parameters: [1D] <br> Other Properties Related to Output: [None] <br>
Evaluation Tasks: <br>
Evaluated via NVSkills-Eval 3-Tier evaluation framework with external profile. <br>
Evaluation Metrics Used: <br>
Reported benchmark dimensions: <br>
- Security: Checks whether skill-assisted execution avoids unsafe behavior such as secret leakage, destructive commands, or unauthorized access. <br>
- Correctness: Checks whether the agent follows the expected workflow and produces the correct final output. <br>
- Discoverability: Checks whether the agent loads the skill when relevant and avoids using it when irrelevant. <br>
- Effectiveness: Checks whether the agent performs measurably better with the skill than without it. <br>
- Efficiency: Checks whether the agent uses fewer tokens and avoids redundant work. <br>
Skill Version(s): <br>
2.6.0 (source: frontmatter) <br>
Ethical Considerations: <br>
NVIDIA believes Trustworthy AI is a shared responsibility and we have established policies and practices to enable development for a wide array of AI applications. When downloaded or used in accordance with our terms of service, developers should work with their internal team to ensure this skill meets requirements for the relevant industry and use case and addresses unforeseen product misuse. <br>
(For Release on NVIDIA Platforms Only) <br> Please report quality, risk, security vulnerabilities or NVIDIA AI Concerns here. <br>
{"mediaType":"application/vnd.dev.sigstore.bundle.v0.3+json","verificationMaterial":{"x509CertificateChain":{"certificates":[{"rawBytes":"MIICgzCCAgmgAwIBAgIUKIyS7SxNteQIiWzK1dWj85E6520wCgYIKoZIzj0EAwMwVTELMAkGA1UEBhMCVVMxGzAZBgNVBAoMEk5WSURJQSBDb3Jwb3JhdGlvbjEpMCcGA1UEAwwgTlZJRElBIEFnZW50IENhcGFiaWxpdGllcyBJQ0EgMDEwHhcNMjYwNDAxMDAwMDAwWhcNMjgwNDIyMTUzMzA5WjBUMQswCQYDVQQGEwJVUzEbMBkGA1UECgwSTlZJRElBIENvcnBvcmF0aW9uMSgwJgYDVQQDDB9OVklESUEgQWdlbnQgU2tpbGxzIFNpZ25pbmcgMDAxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEYoRM9bQl/dGlwSRNi6bTpIJUXH8Nv9GciP6LSflJYYMLCc296kpyuTSsk5ddbAWiDcFX3C/ydX3jwc+qCLYP6uHy9XphyLjOQ27Yb2J6rBLVtRBS1mgGco/Gr7fL6ODco4GaMIGXMB0GA1UdDgQWBBRQ/5ZW3nJ6lmo9SVk7I15o7UGmpTAfBgNVHSMEGDAWgBRPGpILxMBBleJSsBGjrMKsby1CgjAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIHgDA3BggrBgEFBQcBAQQrMCkwJwYIKwYBBQUHMAGGG2h0dHA6Ly9vY3NwLm5kaXMubnZpZGlhLmNvbTAKBggqhkjOPQQDAwNoADBlAjAUygu/GiOCIXrgGr4SmLgeEVDcEitfFUv7ALbvLVGVyMysB3mxmO/uInZfXzWcJZsCMQDxuoxj4ZmO30jhkPIcCxGFCOvnUsnfU3TfGcouYm4M6iRpbKvtVnHPiy4bi6pcKf0="},{"rawBytes":"MIICiDCCAg6gAwIBAgIUZsIuSv9NkpJCNqtYEfCouVv5BzowCgYIKoZIzj0EAwMwUTELMAkGA1UEBhMCVVMxGzAZBgNVBAoMEk5WSURJQSBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcTlZJRElBIEFnZW50IENhcGFiaWxpdGllcyBDQTAgFw0yNjA0MDEwMDAwMDBaGA85OTk5MTIzMTIzNTk1OVowVTELMAkGA1UEBhMCVVMxGzAZBgNVBAoMEk5WSURJQSBDb3Jwb3JhdGlvbjEpMCcGA1UEAwwgTlZJRElBIEFnZW50IENhcGFiaWxpdGllcyBJQ0EgMDEwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASI72cR3ctKGg4VWnB3bNja6g1Z2PnOmFEopkPof+QeIcPk9rT+g9MjJnq51EQXL93a7C2GJ9J985G4o2V85VD7wJ1RaXhluHW2rf3y8bQGeAYaKMr5s/hUgn+M3/9WlWejgaAwgZ0wHQYDVR0OBBYEFE8akgvEwEGV4lKwEaOswqxvLUKCMB8GA1UdIwQYMBaAFItnoAjjfuCEUvzyvWyI2vOGvwPjMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMDcGCCsGAQUFBwEBBCswKTAnBggrBgEFBQcwAYYbaHR0cDovL29jc3AubmRpcy5udmlkaWEuY29tMAoGCCqGSM49BAMDA2gAMGUCMQCeIMMfAbyzPDacw2MxG+Yt1cikrJX/DVxiGfXuHmkkXn6VgSzE79+lkqDErpVO2gYCMCNEColOyvUvkzZGUEI1hQ3PfMgi3FIo9tHoBKMw4/wGBLFpu/0ubtmbBXM6/UMOEw=="},{"rawBytes":"MIICRTCCAcygAwIBAgIUeJdY3rV86EdvFmG7L8LJBsyQFYkwCgYIKoZIzj0EAwMwUTELMAkGA1UEBhMCVVMxGzAZBgNVBAoMEk5WSURJQSBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcTlZJRElBIEFnZW50IENhcGFiaWxpdGllcyBDQTAgFw0yNjA0MDEwMDAwMDBaGA85OTk5MTIzMTIzNTk1OVowUTELMAkGA1UEBhMCVVMxGzAZBgNVBAoMEk5WSURJQSBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcTlZJRElBIEFnZW50IENhcGFiaWxpdGllcyBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IABAYpiXCDjJ9NT2eSDhyHJVSw1Tbze18cGG2F/578oWvHxg23eQAhNRYdq88i1iOshZSO6C29doKui5Xpmo/7Ctw9Sx4PP2RzOmIuOLCuTdNtKcTRwi4GEsd5BAFvWj42M6NjMGEwHQYDVR0OBBYEFItnoAjjfuCEUvzyvWyI2vOGvwPjMB8GA1UdIwQYMBaAFItnoAjjfuCEUvzyvWyI2vOGvwPjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2cAMGQCMCwtAjWLaNwgGWNCgdyNoTyvNhqWRECRJV2r3+7w8g0PL6NHLOsbkgE09BH95h8XlgIwTaQmbbUh2ChAJ5TA1wRiVDnCcvbzHlZl2jM2FcwQQZlk19LOAbyGMRixbu2Ww/rj"}]},"tlogEntries":[]},"dsseEnvelope":{"payload":"ewogICJfdHlwZSI6ICJodHRwczovL2luLXRvdG8uaW8vU3RhdGVtZW50L3YxIiwKICAic3ViamVjdCI6IFsKICAgIHsKICAgICAgIm5hbWUiOiAicmFnLXBlcmYiLAogICAgICAiZGlnZXN0IjogewogICAgICAgICJzaGEyNTYiOiAiYzcxODgxNzM2NGIwZjI2NTVhMzUyNDdhMjMxMmJjYmUzMmE5ZTU4YmQzYjI1MzkzMGQzODc1NWJjNzhiNmNiMCIKICAgICAgfQogICAgfQogIF0sCiAgInByZWRpY2F0ZVR5cGUiOiAiaHR0cHM6Ly9tb2RlbF9zaWduaW5nL3NpZ25hdHVyZS92MS4wIiwKICAicHJlZGljYXRlIjogewogICAgInNlcmlhbGl6YXRpb24iOiB7CiAgICAgICJhbGxvd19zeW1saW5rcyI6IGZhbHNlLAogICAgICAibWV0aG9kIjogImZpbGVzIiwKICAgICAgImlnbm9yZV9wYXRocyI6IFsKICAgICAgICAiLmdpdGF0dHJpYnV0ZXMiLAogICAgICAgICIuZ2l0aWdub3JlIiwKICAgICAgICAiLmdpdGh1YiIsCiAgICAgICAgIi5naXQiCiAgICAgIF0sCiAgICAgICJoYXNoX3R5cGUiOiAic2hhMjU2IgogICAgfSwKICAgICJyZXNvdXJjZXMiOiBbCiAgICAgIHsKICAgICAgICAiZGlnZXN0IjogIjhkOGQ2YmUxODY1YWM2YWQyZjIzMWMxMzY5OWJkODQ4NjI3YTliNWJiOGUwMGFiODNjMTc0ZjAxZTA3MmNiOTYiLAogICAgICAgICJhbGdvcml0aG0iOiAic2hhMjU2IiwKICAgICAgICAibmFtZSI6ICJCRU5DSE1BUksubWQiCiAgICAgIH0sCiAgICAgIHsKICAgICAgICAiZGlnZXN0IjogIjgxZjFkM2EwNzE4NmQ5YmZlM2JlNTRhZTkwZmRiMGFkZGZlZjdjMjNiODg0NWFmZmQ5ODFjOWUwNGE1N2ZlNTQiLAogICAgICAgICJhbGdvcml0aG0iOiAic2hhMjU2IiwKICAgICAgICAibmFtZSI6ICJTS0lMTC5tZCIKICAgICAgfSwKICAgICAgewogICAgICAgICJkaWdlc3QiOiAiYTBkNjU1ZjI4MDQ5ZDEzOWFiNTcwODQwZjA5MjVjMTk4MzZjYWRkODgxZjU0MWZlNzc1ZTdlNzZiZDE2Zjg5NSIsCiAgICAgICAgImFsZ29yaXRobSI6ICJzaGEyNTYiLAogICAgICAgICJuYW1lIjogImV2YWwvaDEwMC5qc29uIgogICAgICB9LAogICAgICB7CiAgICAgICAgImRpZ2VzdCI6ICI4ZWEzYWJhMDJjOGFhNjQ5NGU1ODQzM2EwZGMzYTVlMmU2YTNkN2I0YTRhMzk3MDI3YTk3NTdjYTdkOWUyNDU4IiwKICAgICAgICAiYWxnb3JpdGhtIjogInNoYTI1NiIsCiAgICAgICAgIm5hbWUiOiAiZXZhbC9udmlkaWFfaG9zdGVkLmpzb24iCiAgICAgIH0sCiAgICAgIHsKICAgICAgICAiZGlnZXN0IjogIjMyNzc4MjhmNGJjNmE5Nzg5Y2JiMjQ2OWYyOGMyZWVhOTUzNzlmMDhlZTI5MjhkNDJmYjQyODI4NTdiYTUyZDciLAogICAgICAgICJhbGdvcml0aG0iOiAic2hhMjU2IiwKICAgICAgICAibmFtZSI6ICJyZWZlcmVuY2VzL2NvbmZpZy1zY2hlbWEubWQiCiAgICAgIH0sCiAgICAgIHsKICAgICAgICAiZGlnZXN0IjogImU2MmM3NGJiZGRlNTcxNmNlYzNkMjA1NjZkMDQwODFkZDMxODdiNjM3ZWE5YTJhZTU5YWNjODVjMzZkZWQ2NzciLAogICAgICAgICJhbGdvcml0aG0iOiAic2hhMjU2IiwKICAgICAgICAibmFtZSI6ICJyZWZlcmVuY2VzL291dHB1dC1hbmQtYW5hbHlzaXMubWQiCiAgICAgIH0sCiAgICAgIHsKICAgICAgICAiZGlnZXN0IjogIjdmODY3OGNkYjhhMThjODNjODJlODZlYjIwZTI0NjJmY2FhMjZiZjZhNWJlNGZjZmViMzcyYjkyN2Q4YTg5ZDEiLAogICAgICAgICJhbGdvcml0aG0iOiAic2hhMjU2IiwKICAgICAgICAibmFtZSI6ICJyZWZlcmVuY2VzL3N5bnRoZXRpYy1nZW5lcmF0aW9uLm1kIgogICAgICB9LAogICAgICB7CiAgICAgICAgImRpZ2VzdCI6ICJhNDhiNjZiODhjNmIxNzQ4NzA2YjRhN2U5ZDY0OGFmNDJmYjU1NTBjMDg1MDNmOTFlNjUwOGU1MjNhYjQ0MzY4IiwKICAgICAgICAiYWxnb3JpdGhtIjogInNoYTI1NiIsCiAgICAgICAgIm5hbWUiOiAic2tpbGwtY2FyZC5tZCIKICAgICAgfQogICAgXQogIH0KfQ==","payloadType":"application/vnd.in-toto+json","signatures":[{"sig":"MGYCMQCfYKA61dzGDQ1KFQQlA4nuZdGkt5hfbWmNlG6z3fJDAS+eSA6PXuQAMPvp6mdiJEsCMQDYDNCvtDKiMCO3HLJzEXcBYbsU0/EC6XVd3qOwxcjDlXbMvc7v9UsNknD1N7CLprI=","keyid":""}]}}Related skills
FAQ
What does rag-perf do?
rag-perf is a Claude Code skill for ai & agent building.
When should I use rag-perf?
When you need to helps with ai & agent building tasks., or when rag-perf is a claude code skill for ai & agent building.
What are the main capabilities?
rag-perf; AI & Agent Building; AI-coding skill.