Icho ๐ผ
Deterministic testing for AI applications.
Record once. Replay forever.
Stop paying for every AI test run.
Every time your AI application runs during testing, it probably:
- ๐ธ Calls the LLM again
- ๐ข Slows down your CI pipeline
- ๐ฒ Produces slightly different outputs
- ๐ Depends on internet connectivity
Icho records a real AI execution once and replays it locally during future test runs.
The result
- โก Millisecond replay
- ๐ฐ Zero replay API costs
- ๐งช Deterministic testing
- ๐ป Works offline
Before
from langchain_groq import ChatGroq
model = ChatGroq(model_name="llama-3.1-8b-instant")
response = model.invoke(
"Write a 3-word slogan for gravity."
)
# โฑ๏ธ 2.3 seconds
# ๐ Live API Call
After
from langchain_groq import ChatGroq
from icho import cassette
model = ChatGroq(model_name="llama-3.1-8b-instant")
with cassette("tests/cassettes"):
response = model.invoke(
"Write a 3-word slogan for gravity."
)
# First Run
# โฑ๏ธ 2.3 seconds
# ๐ Live API Call
# ๐พ Recorded
# Every Run After
# โฑ๏ธ 12 ms
# โ No API Calls
# ๐ผ Replayed Locally
Why Icho?
| Without Icho | With Icho |
|---|---|
| Calls the LLM on every test | Record once, replay forever |
| Seconds of latency | Millisecond replay |
| API cost every execution | No replay API cost |
| Internet required | Works offline |
| Non-deterministic | Deterministic |
Supported Frameworks
- โ OpenAI
- โ Anthropic
- โ LangChain
- โ LangGraph
Installation
pip install icho
or
uv add icho
Quick Start
from langchain_groq import ChatGroq
from icho import cassette
model = ChatGroq(model_name="llama-3.1-8b-instant")
with cassette("tests/cassettes"):
response = model.invoke("Hello Icho!")
That's it.
The first execution records the response.
Every matching execution after that replays it locally without calling the LLM.
Features
- ๐งช Phase 2 AI Regression Testing Engine: Compare reference cassettes against new executions across 5 analysis dimensions: Prompt Diff, Tool Diff, Semantic Diff, Cost Diff, and Latency Diff.
- ๐ Searchable AI Executions & Instant Replay: Find past executions with TF-IDF cosine similarity (
icho search "refund" --since yesterday) and generate local replay code (icho replay <hash>). - ๐ผ Record once, replay forever
- โก Replay, Record, Auto, Live, and Regression execution modes
- ๐งฐ Tool Calling & Function Calling support
- ๐ Streaming support (sync & async)
- ๐ PII & Sensitive Information Masking
- ๐ก๏ธ NVIDIA NeMo Guardrails Integration
- ๐ง Deterministic request hashing
- ๐ฏ Custom ignored fields
- ๐ง Custom request normalizers
- ๐๏ธ File, Memory & PostgreSQL storage backends
- ๐งน CLI utilities: Record (
icho record python app.py), Replay (icho replay python app.py), Diff (icho diff), Test (icho test), Eval (icho eval),search,log,stats,inspect,clean
Killer CLI Workflow โก
Icho makes testing and evaluating AI applications as simple as 4 core commands:
Developer runs AI application
โ
icho record python app.py
โ
โโโโโโโโโโโโโโโโ
โ Cassette โ
โโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโฌโโโโโโโโโฌโโโโโโโโโฌโโโโโโโโโ
Replay Diff Test Eval
1. icho record
Run your AI application command โ icho intercepts and records all LLM requests/responses to disk without altering a single line of your code:
icho record python app.py
2. icho replay
Run your AI application in 100% offline, zero-token-cost replay mode, or inspect single cassettes:
# Run application offline with 0 API costs
icho replay python app.py
# Inspect cassette replay details & code snippet
icho replay <cassette_hash>
3. icho diff
Compare cassette executions automatically (defaults to the 2 most recent recordings) or perform 5-dimension Phase 2 regression diff analysis:
# Compare 2 latest recordings
icho diff
# Run 5-dimension Phase 2 regression analysis (Prompt, Tool, Semantic, Cost, Latency)
icho diff execution_1 execution_2 --regression
4. icho test
Execute batch snapshot test suites across directory cassettes in parallel:
icho test tests/cassettes --mode replay
5. icho eval
Evaluate recorded cassettes for NeMo guardrail compliance, PII leakages, JSON schema accuracy, and quality metrics:
icho eval cassettes/
Searchable AI Executions & Instant Replay
When a bug is reported ("The AI gave the wrong answer yesterday"), Icho makes it reproducible in seconds:
# 1. Search past executions by TF-IDF cosine similarity & relative time
icho search "refund request failed" --since yesterday -i
# 2. Inspect target execution and get instant Python replay code
icho replay 1cea06570793
# 3. View chronological Git-like execution history
icho log --path cassettes -n 5
Or query programmatically via Python API:
from icho import search_cassettes
# Search recorded executions by natural language & metadata
results = search_cassettes(query="refund request", since="yesterday", provider="openai")
for res in results:
print(f"Match Score: {res.score:.4f} | Hash: {res.hash[:12]}")
print(f" Input: {res.input_snippet}")
print(f" Output: {res.output_snippet}")
CLI Reference
Icho includes a built-in CLI to search, inspect, format, and debug your recorded cassettes:
| Command | Description | Example |
|---|---|---|
icho diff |
Compare two cassette executions (text, markdown, html formats) | icho diff hash1 hash2 -f html -o diff.html |
icho search |
Search executions by vector cosine similarity, time window, or provider/model | icho search "refund" --since yesterday -i |
icho log |
Show Git-like chronological execution log | icho log --path cassettes -n 10 |
icho replay |
Inspect a target cassette and generate copy-paste Python replay code | icho replay 1cea06570793 |
icho stats |
View total cassette count, disk size, and saved API latency | icho stats --path cassettes |
icho inspect |
List all saved cassettes with providers, models, and timestamps | icho inspect --path cassettes |
icho clean |
Redact volatile timestamps and latency before committing to Git | icho clean --remove-latency --remove-timestamps |
Cassette Execution Diffing (icho diff) ๐
Compare any two recorded cassettes by hash, ID, or file path to inspect prompt, model, parameter, or output differences:
# 1. Compare two cassette executions in terminal text mode
icho diff 1cea06570793 4b93d6e3 --path cassettes
# 2. Export diff comparison report to GitHub Markdown
icho diff 1cea06570793 4b93d6e3 -f markdown -o diff.md
# 3. Export standalone styled HTML diff report
icho diff 1cea06570793 4b93d6e3 -f html -o diff.html
# 4. Interactive Diff from Search Results
icho search "refund request" -i
# Enter result numbers to diff (e.g., '1,2' or 'diff 1 2'):
Phase 2: AI Regression Testing Engine ๐งช
Replay testing validates that an app runs deterministically against recorded cassettes. Phase 2 Regression Testing compares an Old Cassette (reference run) against a New Execution (live call or updated model) across 5 distinct analysis dimensions:
$$\text{Old Cassette} \longrightarrow \text{New Execution} \longrightarrow \begin{cases} \text{1. ๐ Prompt Diff} \ \text{2. ๐ ๏ธ Tool Diff} \ \text{3. ๐ง Semantic Diff} \ \text{4. ๐ฐ Cost Diff} \ \text{5. โก Latency Diff} \end{cases}$$
Python API
from icho import compare_executions, cassette
# Programmatic 5-dimension comparison
report = compare_executions("tests/cassettes/ref_run.json", "tests/cassettes/new_run.json")
print(f"Semantic Similarity: {report.semantic_diff.similarity_score * 100:.1f}%")
print(f"Token Delta: {report.cost_diff.token_delta['total']:+d} tokens")
print(f"Latency Delta: {report.latency_diff.delta_ms:+.1f} ms")
# Enforce CI assertion rules
report.assert_no_regression(
similarity_threshold=0.85,
allow_tool_changes=False,
max_cost_increase_pct=15.0,
max_latency_increase_pct=25.0,
)
# Inline cassette execution with mode="regression"
with cassette(path="tests/cassettes/support_flow.json", mode="regression") as cas:
response = model.invoke("How do I request a refund?")
reg_report = cas.regression_report
print(reg_report.render_text())
CLI Command
# Run 5-dimension regression test comparing two cassette recordings
icho regression reference_run.json new_run.json
# Fail CI build if semantic output drifts below 85% threshold
icho regression reference_run.json new_run.json --fail-on-drift --threshold 0.85
# Export GitHub Markdown or HTML regression report
icho regression old_hash new_hash -f markdown -o regression_report.md
icho regression old_hash new_hash -f html -o regression_report.html
AI Test Datasets (icho test) ๐งช
Organize thousands of conversation scenarios into domain directories using .yaml or .json cassettes:
tests/
โโโ customer_support/
โ โโโ greeting.yaml
โ โโโ refund.yaml
โ โโโ complaint.yaml
โโโ travel_agent/
โ โโโ booking.yaml
โ โโโ cancellation.yaml
โโโ finance/
โโโ invoices.yaml
CLI Command
# Run batch test suite across a domain directory
icho test tests/customer_support/
# Run multi-domain dataset with parallel worker pool
icho test tests/ -j 4
# Run regression suite across datasets against reference cassettes
icho test tests/customer_support/ --mode regression --threshold 0.85 --fail-on-drift
Python API
from icho import discover_suite, SuiteRunner
# Discover nested test suite hierarchy
suite = discover_suite("tests/customer_support")
# Execute batch test suite
runner = SuiteRunner(mode="replay")
report = runner.run(suite)
print(report.render_text())
Pytest Integration ๐งช
Icho includes built-in Pytest support via the icho plugin.
Markers & Fixtures
Use @pytest.mark.icho (or alias @pytest.mark.sequa / @pytest.mark.cassette) or inject the icho_cassette fixture:
import pytest
from langchain_groq import ChatGroq
@pytest.mark.icho(mode="auto")
def test_llm_feature():
model = ChatGroq(model_name="llama-3.1-8b-instant")
response = model.invoke("Say hello")
assert "hello" in response.content.lower()
def test_with_fixture(icho_cassette):
model = ChatGroq(model_name="llama-3.1-8b-instant")
response = model.invoke("Hello world")
Pytest CLI Flags
| Flag | Description | Default |
|---|---|---|
--icho-mode=<mode> |
Globally override cassette mode (auto, record, replay, live) |
Marker / auto |
--icho-path=<path> |
Set base cassette directory | tests/cassettes |
--icho-mask-pii |
Enable PII masking across all test cassette recordings | False |
GitHub Actions Integration ๐
Run deterministic LLM snapshot tests in CI/CD with zero API costs using the official Icho GitHub Action.
Quick Workflow Setup
Add .github/workflows/ai-tests.yml to your repository:
name: AI Snapshot Tests
on:
push:
branches: [ main ]
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Icho LLM Tests
uses: thetechnoadvisor/icho@main
with:
mode: replay
cassette-path: tests/cassettes
post-summary: true
Action Options
| Input | Description | Default |
|---|---|---|
mode |
Execution mode (replay, auto, record, live) |
replay |
cassette-path |
Path to saved cassette files directory | tests/cassettes |
python-version |
Python version for setup | 3.12 |
pytest-args |
Additional arguments passed to pytest | "" |
post-summary |
Post cassette stats report to $GITHUB_STEP_SUMMARY |
true |
Common Use Cases
๐ Speed up AI integration tests
Run your test suite in milliseconds instead of waiting for repeated LLM calls.
๐ฐ Reduce API costs
Replay previously recorded executions without paying for another API request.
๐งช Deterministic testing
Replay the exact same execution every time.
๐ป Offline development
Develop and test AI applications without internet connectivity.
๐ Reproduce bugs
Replay the exact LLM interaction that caused the issue.
Storage Backends
Icho supports multiple storage backends:
- ๐ File Storage
- ๐ง In-Memory Storage
- ๐ PostgreSQL Storage
Choose whichever fits your workflow.
Contributing
Contributions are always welcome.
- โญ Star the repository
- ๐ Report bugs
- ๐ก Suggest new features
- ๐ง Open a Pull Request
License
MIT License.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file icho-0.8.1.tar.gz.
File metadata
- Download URL: icho-0.8.1.tar.gz
- Upload date:
- Size: 65.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
02c85085d6431fbead3ebee8ea9600a528a5ffdd8db1f84bd4a59c4a0f7fe352
|
|
| MD5 |
253649e30dc36935127368dd37d9531a
|
|
| BLAKE2b-256 |
ce95dec9e27f118822a4e7ffbdcf16ad72c8371978e1fdb74e7954a0c7bd1e02
|
File details
Details for the file icho-0.8.1-py3-none-any.whl.
File metadata
- Download URL: icho-0.8.1-py3-none-any.whl
- Upload date:
- Size: 77.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4a7a16e4ff98b5f3a1b6709b4a6f45dc870d671cb59e790568ed19f23b5fd8e0
|
|
| MD5 |
b30c30bb010077f4d20733745a5d84c3
|
|
| BLAKE2b-256 |
332c1b8d8d4bb424acd8d18fbfe9b8fd917d91dd906f18d9406f981d3490454a
|