Skip to main content
Kneepoint

Kneepoint

Find where your AI agent breaks. Load testing, cost per resolved task, and chaos engineering for AI agents — one command, one self-contained report.

PyPI CI Python License: Apache 2.0

Your agent passes its evals at concurrency 1. Production is not concurrency 1. Kneepoint ramps concurrent multi-turn sessions against any OpenAI-compatible endpoint, judges whether each task was actually resolved, prices every token, injects the faults production will inject for you, and answers three questions:

  1. The knee point — the concurrency where latency stops being flat and starts to climb. Reported as a range with a confidence label, never as a bare number the data cannot support.
  2. $ / resolved task — spend divided by tasks actually solved, retries and failures included. Not tokens, not requests.
  3. Resilience score — how much of your resolution rate survives rate limits, server errors, tool timeouts and malformed tool JSON.

Everything runs on your machine. Results are plain JSONL under an open, versioned output format you can build on without asking anyone.

Install

pip install kneepoint

Python 3.11 or newer. Nothing on this page needs an API key.

First run: the demo

kneepoint demo

This starts a bundled, deliberately naive support agent, injects chaos into its LLM calls (429s, 503s) and its tool calls (timeouts, garbage JSON), ramps concurrency against it, and opens the report in your browser. Nothing leaves your machine and nothing is billed — the cost figures use play-money prices.

Useful flags: --hold-seconds 10 (longer holds mean more samples per level and smoother curves), --seed N (reproducible prompt sampling and chaos), --no-open, --out DIR.

Against your own agent

kneepoint init                            # starter kneepoint.yaml + prompt corpus
kneepoint validate kneepoint.yaml         # schema-check the file without running anything
kneepoint run --scenario kneepoint.yaml   # ramp, judge, price, report

Any OpenAI-compatible chat endpoint is a target. A scenario is one YAML file, validated strictly — unknown keys are rejected — and every value in it can be overridden by a flag (--ramp 1..20 --chaos off …): flag beats scenario beats default.

target:
  url: http://127.0.0.1:8000/v1
  model: my-agent
  # auth_env: AGENT_API_KEY                       # env var holding a bearer token

workload:
  ramp: {from: 1, to: 50, step: 5, hold_seconds: 20}
  conversation:
    turns: {min: 1, max: 3}                       # multi-turn: context grows every turn
    corpus: ./prompts/*.txt                       # your real prompt distribution

resolution:
  check: {kind: contains, value: "[RESOLVED"}     # or a regex, or an LLM judge

cost:
  input_per_mtok: 3.00
  output_per_mtok: 15.00
  max_spend: 0.50                                 # observed stop threshold; active calls may overshoot

chaos:
  profile: standard                               # 429s, 503s, tool faults

slo:
  min_resolution_rate: 0.90                       # fail/unknown -> exit 1

Set cost.max_spend before pointing at a paid model. Supply both prices explicitly (zero is allowed). The controller stops new work when observed spend reaches the threshold or usage is unknown, drains active calls, and reports partial results with exit code 3. Active calls may overshoot: this is not a billing guarantee. Capped runs skip calibration and reject configured LLM judging; --force never bypasses runtime control. See cost control.

LLM faults need no infrastructure: they are injected inside Kneepoint's own HTTP client. Tool faults have to sit between your agent and its tools, so kneepoint proxy --upstream <your tool service> --fault-log faults.jsonl runs a small reverse proxy, and kneepoint run --fault-log faults.jsonl carries what it served into the resilience grid. Details, and the standard fault profile, in Chaos testing.

Three copy-anywhere example scenarios ship in the repo — support bot, RAG agent, agent with MCP tools — and Local models covers measuring a local model behind an agent, which is not the same as ramping the model server on its own.

Reading the report

The report is one HTML file with everything embedded, meant to be read by someone who has never used Kneepoint. Top to bottom:

  • Verdict — the knee as a range with a confidence label, and what each of the two detection methods concluded. The low end of the range is a cautious latency threshold estimate; inspect throughput and SLOs before choosing an operating load, because saturation can occur earlier. When the crossing lands on the last level of the ramp, the verdict says N or beyond and tells you to widen the ramp rather than reporting a knee it cannot see. A near miss within 15% of doubling is inconclusive and names its levels; a clear non-crossing does not invent a knee.
  • The knee curve — p50/p95/p99 latency against concurrency, knee marked.
  • TTFT vs. TPOT and inter-token latency — whether the target is slow to start (queueing) or slow to continue (decode contention), when it streams.
  • Quality under load and the quality curve — resolution rate against concurrency. Quality often cliffs before latency does.
  • Errors — failures per level with the status-code mix and the most common error strings; a 429 and a timeout have different fixes.
  • Retry amplification — how much load the generator itself added on top of the workload, because a ramp with retries can partly manufacture the knee it measures.
  • Cost — total spend, retry waste, and $ / resolved task.
  • Resilience — per-fault pass / degraded / fail, relative to the sessions that took no fault.
  • Run metadata — target, model, ramp, hold, seed, chaos profile, prices, thresholds, versions, read back from the run's own sidecar. Two reports are comparable only when these match.

Every chart plays by the same rules: the sample count sits under each level on the x-axis, a level below --min-samples stays on the axis marked not plotted rather than disappearing, y starts at zero, nothing is smoothed, and levels contaminated by an abandoned request are shaded on the chart itself. Every section ends with a short How to read this line, worded from the chapter of the Kneepoint Book that owns the metric.

What a run writes

Four files into --out (default reports/), all named from one run id, all four paths printed when the run finishes:

File What it is
run-<id>.jsonl one line per request attempt
run-<id>-sessions.jsonl one line per simulated user session
run-<id>-meta.json what the run was: target, ramp, seed, chaos, prices, versions
run-<id>-report.html the report, derived from the other three

Lost the HTML, or want it regenerated?

kneepoint report reports/run-<id>.jsonl

rebuilds it from the stored files — byte-identical to the run's own report when the sidecar is present. Every JSONL line carries schema_version and kneepoint_version, and Output format is the contract: every field, when it is null and why null never means zero, and what may change within a schema version (nothing is removed, renamed or redefined).

CI gate

Kneepoint is a test: it exits non-zero when your agent regresses.

- run: pip install kneepoint
- run: kneepoint run --scenario kneepoint.yaml --out reports
- uses: actions/upload-artifact@v4
  if: always()
  with: {name: kneepoint-report, path: reports/}

Each configured SLO is pass, fail (a measured SLO breach), or unknown (insufficient evidence), with its threshold, measurement and reason in the CLI and report. No configured SLO means no fabricated pass. The latency check uses levels with at least --min-samples successful requests. An eligible-level breach makes the whole-run latency check fail, even when another level is thin or invalid. Otherwise, any thin or invalid level makes it unknown; with all levels eligible and valid, it can pass. The policy constant in kneepoint/analyze/slo.py can also allow a measured thin-level breach to fail. A thin level can never establish a pass. Exit codes: 0 completed with no failed or unknown configured checks · 1 any failed or unknown SLO · 2 usage error · 3 budget control stop (takes precedence over SLO results). Checks describe observed records; they do not certify completion of the configured ramp. Pin seed so a red build reruns the same prompts and chaos. kneepoint report recomputes checks, including price overrides; its exit code reports rendering success, not an SLO gate. Full CI docs →

Measurement integrity

A capacity number is only worth as much as the measurement behind it, so Kneepoint says what it cannot know. Percentiles are not computed below --min-samples; a knee is a range when the deciding ratio is a near miss; and when a request is abandoned at the client wall, every later level is flagged as contaminated — the server may still be generating, so those levels can be measuring the previous level's leftovers. Measurement integrity documents what is guaranteed and what is not.

If you have results from 0.1.0, re-run them. Three defects in that release affected the numbers it printed — the headline knee came from the wrong method, tool faults were never attributed outside the demo, and abandoned requests were not detected as such. The changelog states each one plainly.

Where it fits

Evals tell you the agent can do the task. Observability tells you what happened in production. Kneepoint tells you where it breaks before production does — under concurrency, with growing context, with the tools misbehaving. Use all three.

Documentation

Quickstart · Scenario reference · The three metrics · Chaos testing · Output format · CI gate · Roadmap

The Kneepoint Book — foundations, latency, throughput & capacity, quality under load, stability & resilience, cost & tokens, reading charts, diagnostic recipes, glossary — the metric definitions the CLI implements and the report teaches from.

Issues and contributions

Bug reports, wrong-looking numbers and agents that Kneepoint mis-measures are all welcome as issues. Pull requests are not being accepted for now.

To reproduce a number or run the suite yourself:

git clone https://github.com/kneepoint-dev/kneepoint && cd kneepoint
pip install -e ".[dev]"
ruff check . && pytest -q        # runs against the bundled mock agent: no keys, $0

Apache 2.0 licensed — see LICENSE and NOTICE. Built in public at kneepoint.dev.

Metadata

Release files for kneepoint 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for kneepoint 0.3.0
File Size Uploaded Provenance
kneepoint-0.3.0.tar.gz 505.3 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for kneepoint 0.3.0
File Interpreter ABI Platform
kneepoint-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 609.7 kB

Release files / kneepoint-0.3.0.tar.gz

Download URL kneepoint-0.3.0.tar.gz
Size 505.3 kB
Tags Source
SHA-256 checksum
How to use checksums
e446292f19bf405aa32a1b7cad10391a3b689d2ecdcbb1c570e281d79696be9f
BLAKE2b-256 checksum
How to use checksums
1d6ca96430b46cf78aaabdc6bc84390d1f7954d0db225ec6a48c20b1619441a4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.6

Release files / kneepoint-0.3.0-py3-none-any.whl

Download URL kneepoint-0.3.0-py3-none-any.whl
Size 104.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c1c80dd9ec4c42a26e09b8127213608bd0d5d87699a00026d45df8bbf81d9c92
BLAKE2b-256 checksum
How to use checksums
1058b19ecd83790cfb2cc585e3de333dce1a50ccb87ca8e06dc278fa82bcc59d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.6

Security for kneepoint 0.3.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page