Files
TheRock/rocm-systems/experimental/python/perfxpert/docs/guides/agentic-mode.md
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

9.5 KiB

Agentic Mode Guide

PerfXpert's analysis can run in two modes:

  • Air-gap mode — no LLM call, deterministic only. All analysis goes through the same agentic routing + tools, but every agent returns its "airgap" path: rule-based classification + knowledge lookups, without model inference.
  • LLM-enabled mode — identical routing, but agents call out to an LLM for free-form narrative + rich recommendations.

This guide explains how to select between them, what changes in the output, and how provider selection works.

The same agent/session machinery powers perfxpert analyze, perfxpert.api.*, the 8 agent MCP tools exposed by perfxpert-mcp, and every perfxpert-code backend. The entry surface changes the shell/UI and config plumbing, not the analysis brain.

Cross-links:

Air-gap mode

Enable via any of:

# SKIP-SAMPLE — env-var setup
export PERFXPERT_AIRGAP=1
# SKIP-SAMPLE — per-session override (verified elsewhere under the harness)
from perfxpert.agents.runtime import build_session
session = build_session(airgap=True)

Behavior:

  • No outbound network calls from the agent layer. Provider resolution is skipped entirely.
  • RootOutput.recommendations is currently empty in the root air-gap path. Deterministic mode still classifies the bottleneck and returns the terse template narrative, but it does not yet populate structured recommendation dicts until an LLM-backed path is used.
  • primary_bottleneck is still set (classifier runs deterministically against the knowledge YAMLs).
  • narrative is either empty or a terse deterministic summary.
  • Gate cascade behavior is unchanged — it's middleware; no LLM involvement in gates.

Use air-gap mode for:

  • Secure / regulated environments where no LLM provider is allowed
  • CI pipelines where reproducibility is critical
  • Ad-hoc triage when you just want the deterministic hot-kernel + bottleneck classification

LLM-enabled mode

progress spinner

Live agent-phase progress UI captured under PERFXPERT_AIRGAP=1 for deterministic rendering of the analysis flow.

Pick a provider explicitly:

# SKIP-SAMPLE — requires a configured provider; shown as the canonical call
from perfxpert.agents.runtime import build_session
from perfxpert.agents.schemas import RootInput

session = build_session(provider="anthropic")  # or openai / ollama / private / opencode
output = session.run_root(RootInput(
    user_query="Propose the first optimization for my hot kernel.",
    database_path="/tmp/trace.db",
))

# recommendations is a List[Dict[str, Any]] — use dict access, not attribute
for rec in output.recommendations:
    print(rec["name"], rec["title"])

When airgap=False (the default), build_session:

  1. Resolves the provider from the provider arg, falling back to DEFAULT_PROVIDER (currently "anthropic").
  2. Validates it against PROVIDER_REGISTRY; raises ValueError on unknown providers.
  3. Calls runtime.recursion_guard.ensure_not_recursive(prov) — this blocks provider="opencode" from being chosen from inside an already-running opencode session (would recurse forever).
  4. Returns an AnalysisSession bound to that provider.

Behavior differences vs air-gap:

  • recommendations[]["name"] carries the technique identifier (e.g. "async_stream_overlap", "vgpr_reduction") — same key as air-gap mode, but title / description / rationale are LLM-rewritten for the specific kernel instead of being templated verbatim from the knowledge YAMLs.
  • narrative is a full natural-language summary.
  • Each agent's fence slice shapes the LLM's voice + constraints — never concatenated with the others.
  • Gate cascade still runs deterministically on every edit the LLM proposes; a rewarded-hack still gets rejected at gate 2 (SOL).

Provider ladder

all providers

The five primary providers come directly from the CLI's --llm registry: anthropic, openai, ollama, private, opencode. The CLI also accepts claude-code as a compatibility alias for the patched opencode backend used by perfxpert-code.

PROVIDER_REGISTRY is defined in perfxpert/agents/runtime.py (with a hard-coded fallback there; build_session imports the richer copy from perfxpert.providers when the optional provider package is available). It lists the supported providers in preference order. Current entries:

Provider Source Typical use
anthropic Claude API Production default; requires ANTHROPIC_API_KEY
openai OpenAI API Alternative hosted; requires OPENAI_API_KEY
ollama Local Ollama Fully local; requires a running ollama serve
private Any OpenAI-compatible endpoint Internal deployments; requires PERFXPERT_LLM_PRIVATE_URL + PERFXPERT_LLM_PRIVATE_MODEL; CLI preflight also needs PERFXPERT_LLM_PRIVATE_API_KEY or --llm-api-key
opencode Bundled opencode CLI Used by perfxpert-code; not callable from inside opencode itself (recursion-guarded)

perfxpert doctor reports which providers are reachable from the current shell. See contributing/providers.md for how to register a new one.

Private OpenAI-compatible endpoints use JSON for extra headers:

# SKIP-SAMPLE — requires a reachable private endpoint
export PERFXPERT_LLM_PRIVATE_URL="https://llm-api.iexample.com/OpenAI"
export PERFXPERT_LLM_PRIVATE_MODEL="gpt-5.3-codex"
export PERFXPERT_LLM_PRIVATE_API_KEY="..."
export PERFXPERT_LLM_PRIVATE_HEADERS='{
  "Ocp-Apim-Subscription-Key": ".......",
  "user": ".....",
  "api-version": "preview"
}'
perfxpert analyze -i trace.db --llm private

Fallback chain (PERFXPERT_LLM_FALLBACK_CHAIN)

The multi-provider fallback chain lets a rate-limited or unavailable primary provider hand off to another, so users don't have to rerun. Set the env var to a comma-separated list of provider names in preference order:

# SKIP-SAMPLE — requires a real trace.db and live LLM credentials
# Try Anthropic first; fall back to OpenAI, then a private endpoint.
export PERFXPERT_LLM_FALLBACK_CHAIN="anthropic,openai,private"
perfxpert analyze -i trace.db --llm anthropic

When set, build_session(provider="anthropic", ...) keeps the configured provider selection but still surfaces typed provider errors from perfxpert/providers/_exceptions.py. The concrete exception surface in this tree is:

Exception Meaning
RateLimitError HTTP 429 / short-term throttle; eligible for fallback cascade
QuotaExceededError Hard quota / billing exhaustion; surfaces immediately
TransientError Retryable provider/network/API blip; eligible for fallback cascade
FatalError Non-retryable provider failure or malformed provider response
TimeoutError Per-call timeout budget exceeded
AuthError Bad API key / missing credential
ProviderChainExhausted Every provider in the configured fallback chain failed
ProviderError Generic provider failure when no narrower typed subclass applies

The recursion_guard still applies to each candidate — opencode cannot be chosen from inside an already-running opencode session.

Unset or empty: no fallback. A typed error surfaces to the caller unchanged.

Related knob:

  • PERFXPERT_DISABLE_RATE_LIMIT_RETRY=1 disables client-side retry before falling through; useful when you want the fallback chain to take over immediately on 429.

CLI entry points

Two CLI surfaces drive the same agent runtime:

  • perfxpert analyze ... — batch / one-shot. Reads a .db file or a source directory, emits a single report (JSON / markdown / webview). Use --llm <provider> to pick the provider; omit --llm to run air-gap.
  • perfxpert-code ... — interactive launcher. Plain perfxpert-code uses the patched opencode path; perfxpert-code claude|gemini|codex stages the same prompt/MCP surface into the user's native backend. perfxpert-code run -m <message> is the non-interactive equivalent when the patched opencode path is in use.

Roughly:

Task Command
Analyze a trace deterministically perfxpert analyze -i trace.db
Analyze with Claude perfxpert analyze -i trace.db --llm anthropic
Drive an optimization session conversationally perfxpert-code
Drive an optimization session non-interactively perfxpert-code run -m "optimize hot kernel"

Under the hood, the batch CLI, Python API, MCP wrappers, and perfxpert-code backends all funnel into build_session() and the same run_* methods. The differences are output rendering and whether an external TUI talks to those runners through MCP.

When to use which

  • CI / regression gates → perfxpert analyze in air-gap mode. Reproducible, no network, deterministic output.
  • Interactive optimization → perfxpert-code. Natural-language back-and-forth, session persistence, gate cascade active on every edit.
  • External MCP clients (Claude Desktop, Cursor) → always air-gap safe because the MCP server only exposes READ_ONLY tools; see mcp-server.md.
  • Scripted LLM runs → perfxpert-code run -m "..." or build_session(provider="anthropic") in Python.