
Shadow-debugger – Background LLM error diagnosis for Python and FastAPI
Background error diagnosis for Python apps and web APIs.
以下正文同步自 Hacker News 最新,版权归原站所有,已转换为易读排版。
Background error diagnosis for Python apps and web APIs.
When an exception or HTTP 500 happens, shadow-debugger captures the stack frame from your code, strips secrets from local variables and request data, and sends the context to an LLM in a background worker thread. Your app returns its normal response right away; a few seconds later you get a Markdown postmortem in ./shadow_reports/.
It works offline with Ollama (zero external dependencies) or with Gemini, OpenAI (including OpenAI-compatible endpoints like Groq, vLLM, LM Studio), and Anthropic.
@app.get("/checkout/{order_id}") async def checkout(order_id: int, discount_items: int = 0): unit_discount = 50 / discount_items return {"order_id": order_id, "discount": unit_discount}
shadow-debugger writes shadow_reports/incident_20261018_103012_ZeroDivisionError_9f2a1c4b.md:
Shadow Debugger Incident Report
Timestamp: 2026-10-18T10:30:12.418290+00:00
Exception: ZeroDivisionError: division by zero
Location: app/routes.py:42 in checkout
Fingerprint: 9f2a1c4b8e1032d1 (occurrences so far: 1)
1. Root Cause Summary
checkout() divides 50 by discount_items without checking for 0. When the query parameter is omitted or set to 0, Python raises ZeroDivisionError.
2. Trigger Condition
GET /checkout/1042?discount_items=0 with local state {"order_id": 1042, "discount_items": 0}.
3. Proposed Fix
unit_discount = 50 / discount_items if discount_items > 0 else 0.0
- unit_discount = 50 / discount_items
+ unit_discount = 50 / discount_items if discount_items > 0 else 0.0
4. Prevention Advice
Validate numeric query parameters with Query(gt=0) in FastAPI or guard denominators before dividing.
Installation
Core package (stdlib only — works with local Ollama out of the box)
pip install shadow-debugger
Or install with the provider / framework you use:
pip install "shadow-debugger[gemini]" pip install "shadow-debugger[openai]" pip install "shadow-debugger[anthropic]" pip install "shadow-debugger[fastapi]" pip install "shadow-debugger[flask]" pip install "shadow-debugger[django]"
Quick start
Local with Ollama (no API key)
import shadow_debugger
shadow_debugger.init( provider="ollama", model="llama3.2", print_to_console=True, )
Cloud providers
import shadow_debugger
Uses GEMINI_API_KEY
shadow_debugger.init(provider="gemini", model="gemini-3.8-flash")
Uses OPENAI_API_KEY (or pass base_url=... for Groq / vLLM / LM Studio)
shadow_debugger.init(provider="openai", model="gpt-5.4-nano")
Uses ANTHROPIC_API_KEY
shadow_debugger.init(provider="anthropic", model="claude-haiku-5-5")
Web frameworks
FastAPI / Starlette
from fastapi import FastAPI import shadow_debugger
shadow_debugger.init(provider="ollama", model="llama3.2")
app = FastAPI() app.add_middleware(shadow_debugger.FastAPIWatcherMiddleware)
Flask
from flask import Flask import shadow_debugger
app = Flask(name) shadow_debugger.init(provider="ollama", model="llama3.2") shadow_debugger.init_flask(app)
init_flask hooks into got_request_exception, so normal 404/4xx responses are left untouched.
MIDDLEWARE = [ "shadow_debugger.integrations.DjangoWatcherMiddleware",
...
]
Decorator & manual capture
@watch works on both regular and async def functions:
import shadow_debugger
@shadow_debugger.watch(reraise=False) async def process_order(payload: dict): return payload["items"]["price"] / payload["items"]["quantity"]
Or inside an existing try/except block:
try: sync_inventory() except Exception as exc: shadow_debugger.capture_exception(exc, extra_metadata={"job": "inventory"})
Privacy & what gets sent
If you use a cloud provider, the prompt includes the traceback, the 5 lines of source around the error, and the local variables of the failing function. To keep sensitive data out of prompts:
All options can be passed to shadow_debugger.init(...):
import shadow_debugger from shadow_debugger import Provider, register_provider
@register_provider("my-gateway") class MyGatewayProvider(Provider): default_model = "my-model" env_key = "MY_GATEWAY_KEY"
def complete(self, system: str, prompt: str) -> str: self.check_configuration()
Call your LLM endpoint and return Markdown
return "..."
shadow_debugger.init(provider="my-gateway")
Roadmap & contributing
I'm actively looking for feedback and contributors. A few areas where PRs are very welcome:
See CONTRIBUTING.md for local setup instructions.
正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。