best-practices-scillm
Error recovery and anti-patterns for scillm LLM proxy. Load this when scillm calls fail, timeout, or return unexpected results. Covers batch sizing, header requirements, model selection, and debugging workflow.
- License 许可
- MIT
- 最近更新
- 2026-06-13
- Stars
- ★ 0
- Forks
- 2
01 前言 Front Matter
- name
- best-practices-scillm
- license
- MIT
- composes
- [ "scillm" ]
- metadata
- { "category": "debugging", "proxy_port": 4001, "debug_endpoint": "/v1/scillm/debug" }
- provides
- [ "best-practices-scillm" ]
- triggers
- [ "scillm error", "scillm timeout", "scillm best practices", "llm call failed", "429 rate limit", "queue timeout", "batch processing scillm" ]
- description
- Error recovery and anti-patterns for scillm LLM proxy. Load this when scillm calls fail, timeout, or return unexpected results. Covers batch sizing, header requirements, model selection, and debugging workflow.
03 SKILL.md 正文
scillm Best Practices — Error Recovery & Anti-Patterns
Load this skill when scillm calls fail. It covers common mistakes and how to fix them.
Quick Debugging
Self-diagnose your failures:
# Get LLM-powered analysis of your recent calls
curl "http://localhost:4001/v1/scillm/debug?caller=YOUR_SKILL_NAME&limit=3" \
-H "Authorization: Bearer sk-dev-proxy-123"
# Or analyze a specific call by ID
curl "http://localhost:4001/v1/scillm/debug/CALL_ID" \
-H "Authorization: Bearer sk-dev-proxy-123"
The debug endpoint returns:
- Diagnosis: What happened
- Root Cause: Why it happened
- Fix: Specific code change
- Best Practice: Which rule applies
Anti-Patterns (Don't Do This)
1. Firing 50+ Requests at Once
WRONG:
# DON'T - fires 400 requests, most will timeout in queue
tasks = [call_proxy(p) for p in all_400_prompts]
results = await asyncio.gather(*tasks)
RIGHT:
# Process in chunks of 4 (matches provider concurrency)
CHUNK_SIZE = 4
for i in range(0, len(prompts), CHUNK_SIZE):
chunk = prompts[i:i + CHUNK_SIZE]
results = await asyncio.gather(*[call_proxy(p) for p in chunk])
Why: The proxy has a 600s queue timeout. Firing 100+ requests through 4 slots takes ~750s minimum (100 ÷ 4 × 30s). Later requests timeout waiting.
2. Missing X-Caller-Skill Header
WRONG:
resp = httpx.post(url, json={"model": "text", ...})
RIGHT:
resp = httpx.post(
url,
headers={
"Authorization": "Bearer sk-dev-proxy-123",
"X-Caller-Skill": "your-skill-name", # REQUIRED
},
json={"model": "text", ...},
)
Why: Without this header, errors can't be traced back to your skill. The dashboard shows "no header" in amber.
3. Short Timeouts
WRONG:
resp = httpx.post(url, timeout=5.0) # Too short for LLM calls
RIGHT:
resp = httpx.post(url, timeout=60.0) # Generous timeout
# Or for batch: timeout=120.0
Why: LLM calls can take 10-30s. The proxy handles retries internally — let it work.
4. Using max_tokens
WRONG:
json={"model": "text", "max_tokens": 100, ...}
RIGHT:
json={"model": "text", ...} # Omit max_tokens entirely
Why: max_tokens causes truncation and downstream failures. The proxy manages token limits.
5. Direct Provider Calls
WRONG:
from openai import OpenAI
client = OpenAI(api_key="sk-...") # Direct to OpenAI
RIGHT:
from openai import OpenAI
client = OpenAI(
base_url="http://localhost:4001/v1",
api_key="sk-dev-proxy-123",
)
Why: Direct calls bypass the proxy's retries, fallbacks, logging, and cost tracking.
Error Semantics (Updated 2026-04-15)
scillm uses specific HTTP codes to communicate different failure modes:
| Code | Meaning | What to Do |
|---|---|---|
| 429 | Upstream provider rate limit — Chutes/Gemini/etc rejected the request | Proxy auto-retries via fallback chain; if persistent, provider is saturated. Wait 60s or let queue drain. |
| 503 | Proxy capacity exhausted — Request waited 600s in queue but couldn't get a slot | Your batch is too large for available capacity. Use chunked processing (CHUNK_SIZE=4). |
| 400 | Bad request — Missing header, invalid model name, malformed JSON | Check X-Caller-Skill header (required), model alias, request format |
| 502 | Provider error — Upstream returned non-JSON or connection dropped | Transient; proxy will retry. If persistent, provider may be down. |
Key distinction: 429 = "provider says slow down" (external). 503 = "proxy queue full" (internal).
Why Batch Operations Fail (Root Causes)
scillm was originally designed for single-call use cases. When batch jobs fire 100+ concurrent requests, protective mechanisms can turn hostile:
| Problem | Root Cause | Fix (2026-04-15) |
|---|---|---|
| Cascade failure after errors | Abuse guard blocked callers after 5 transient errors | Disabled — authenticated callers always pass |
| Queue timeout after 60s | Short timeout couldn't handle 100+ requests through 4 slots | Extended to 600s (10 min) |
| Wrong error semantics | Queue exhaustion returned 429 ("too fast") instead of 503 ("overloaded") | Returns 503 now |
| Event loop blocked | threading.Lock in async middleware blocked the event loop |
Changed to asyncio.Lock |
| Zombie slots persisted | Background cleanup could die silently; 300s stale detection too slow | Auto-restart + 90s stale threshold |
The math that kills unbounded batches:
100 requests ÷ 4 slots × 30s/request = 750s minimum
With 60s queue timeout → requests #25+ die before reaching LLM
The only remaining failure mode: 503 after 600s queue wait. This means chunked processing is required.
Error Patterns & Quick Fixes
| Error | Cause | Fix |
|---|---|---|
503 SERVICE_BUSY |
Queue timeout after 600s | Use CHUNK_SIZE=4 for batches |
429 Rate limit |
Upstream provider exhausted | Proxy auto-retries; let fallback chain work |
Connection refused :4001 |
Proxy not running | docker compose -p scillm up -d |
400 Missing X-Caller-Skill |
Required header missing | Add header to all requests |
401 Unauthorized |
Missing/wrong auth | Use Bearer sk-dev-proxy-123 |
Empty response |
Model returned nothing | Check prompt; try different model |
TRUNCATED status |
Low completion tokens | Normal for short prompts; ignore |
FALLBACK status |
Unexpected model routing | Check cascade in /v1/scillm/providers |
Automatic Error Guidance
When scillm calls fail, the proxy returns enriched error JSON with LLM-powered analysis:
{
"error": {
"message": "Queue timeout after 60s",
"type": "timeout_error",
"code": 504,
"advice": "Your batch of 400 requests caused queue timeout. Process in chunks of 4.",
"recommendation": "CHUNK_SIZE = 4\nresults = []\nfor i in range(0, len(prompts), CHUNK_SIZE):\n chunk = prompts[i:i + CHUNK_SIZE]\n chunk_results = await asyncio.gather(*[call_proxy(p) for p in chunk])\n results.extend(chunk_results)",
"skill": "/best-practices-scillm",
"debug_url": "http://localhost:4001/v1/scillm/debug/abc123",
"analysis": "llm"
}
}
| Field | Description |
|---|---|
advice |
One-sentence fix description |
recommendation |
Copy-paste Python code to fix the issue (for batch errors) |
skill |
Load this skill for full best practices |
debug_url |
API endpoint to get detailed call analysis |
analysis |
"llm" if advice was generated by LLM analysis |
Agents should check error.recommendation — if present, it's executable code to fix the batch.
Model Selection
| Use Case | Model | Notes |
|---|---|---|
| General text | text |
Cascades: Chutes → Gemini → DeepSeek |
| Images/PDFs | vlm |
Auto-detected from image_url content |
| Fast/cheap | text-gemini |
1M context, free tier |
| Always-on | local-text |
Ollama, no cost, for testing |
| High quality | claude-sonnet-4-6 |
OAuth via Claude Code subscription |
Check Proxy Health
Before debugging errors, check proxy state:
# Full health check
curl -s -H "Authorization: Bearer sk-dev-proxy-123" \
"http://localhost:4001/v1/scillm/health" | jq '.concurrency.chutes'
# Response shows:
# {
# "in_flight": 2, # Currently processing
# "queued": 5, # Waiting for slots
# "available": 2, # Slots open
# "backoff_active": false,
# "recent_429s": 0 # Provider rate limits hit
# }
| Field | Healthy | Problem |
|---|---|---|
in_flight |
0-4 | If stuck at limit with queued > 0, slots may be zombies |
queued |
0-10 | If > 50, batch is too large |
backoff_active |
false | If true, provider hit rate limit — proxy is backing off |
recent_429s |
0 | If > 0, provider is rate limiting — let fallback chain work |
Reset stuck state:
curl -X POST -H "Authorization: Bearer sk-dev-proxy-123" \
"http://localhost:4001/v1/scillm/concurrency/reset"
Debugging Workflow
- Check the dashboard:
http://localhost:5183→ scillm tab - Expand your job to see individual calls
- Click a failed call to open Call Trace
- Click "Analyze Call" for LLM-powered diagnosis
- Click "Copy for Agent" to get actionable fix
Or programmatically:
# In your error handler
async def debug_my_call(call_id: str) -> str:
resp = await httpx.get(
f"http://localhost:4001/v1/scillm/debug/{call_id}",
headers={"Authorization": "Bearer sk-dev-proxy-123"},
)
return resp.json().get("analysis", "No analysis")
Checklist Before Calling scillm
[ ] Using httpx or openai SDK (NOT requests)
[ ] base_url = "http://localhost:4001/v1"
[ ] Authorization: Bearer sk-dev-proxy-123
[ ] X-Caller-Skill header set
[ ] timeout >= 60s
[ ] NO max_tokens in request
[ ] Batch size <= 4 concurrent (or chunked)
[ ] response_format: {"type": "json_object"} for JSON output
04 同仓库更多 Skills
best-practices-streamdeck
Project-specific best practices for the Stream Deck control suite: icon format constraints, socket vs config boundaries, widget button lifecycle, page creation via build_page, ArangoDB fallback patterns, and NVIS palette compliance.
best-practices-rust
Repo-specific Rust best practices for agentic coding: thiserror + anyhow error handling, tokio async runtime, tracing for observability, clap for CLI, axum for HTTP, serde patterns, cargo workspace conventions, ownership and lifetimes, and idiomatic Rust 2024 edition patterns.
react-native-skills
React Native and Expo best practices for building performant mobile apps. Use when building React Native components, optimizing list performance, implementing animations, or working with native modules. Triggers on tasks involving React Native, Expo, mobile performance, or native platform APIs.
react-best-practices
React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.
composition-patterns
React composition patterns that scale. Use when refactoring components with boolean prop proliferation, building flexible component libraries, or designing reusable APIs. Triggers on tasks involving compound components, render props, context providers, or component architecture. Includes React 19 API changes.
best-practices-react
React, Next.js, React Native, and web design best practices from Vercel Engineering. Use when writing, reviewing, or refactoring React/Next.js/React Native components, optimizing performance, auditing UI accessibility, or designing component APIs. Triggers: "review react", "optimize component", "check accessibility", "react best practices", "component architecture", "react native performance".