Ai_python_visualizer
Watch Python execute, one step at a time — with an AI agent explaining what's actually happening to the stack and heap, not just narrating the code back to you.
Inspiration
I struggled learning Python the way most beginners do: I could read a
tutorial, copy the code, run it, and watch the output appear — but the
gap between "I typed this" and "this happened" stayed a black box. A
for loop would finish and I'd have no real mental model of what
happened on each pass. A list would get mutated somewhere deep in a
function and I'd have no idea why the original variable outside the
function also changed.
Programiz was the site that got me through the early stretch — the step-by-step framing, the plain-language explanations, the sense that someone was walking next to you instead of just handing you a reference page. What I kept wishing for on top of that was: what if the explanation wasn't written once for every learner, but generated live, for my code, at my level, grounded in what the interpreter actually did on that exact run? That's the gap Ai_python_visualizer tries to close — Programiz's clarity, pointed at your own code, explained by something that actually watched it execute instead of guessing.
What it does
You paste a Python function, hit run, and step through its execution
one event at a time — call, line, return, exception — with:
- A live graph of the stack and heap (React Flow), so you can see a frame get pushed when a function is entered and popped when it returns, instead of imagining it.
- An AI-narrated explanation for every step, generated by a LangGraph agent running on Groq — but grounded in real interpreter state (heap identity, AST shape), not the model's guess about what a line of code "probably" does.
- Captured program output, so
print()statements show up exactly where they belong instead of vanishing into a server log. - A Learn Python link to the official docs, for anything a single trace can't cover on its own.
The core promise: mutation and rebinding are never confused. If
cart.append(item) mutates a list in place, the tool says so — checked
against the object's actual heap identity, not phrasing.
How we built it
- Tracer: Python's own
sys.settrace, sandboxed with a restricted builtins list, blocked imports, blocked dunder sandbox-escape patterns, a step limit, and a wall-clock timeout. Deterministic, no LLM involved — this is the part that has to be exactly right. - Explanation agent: LangGraph, backed by Groq's
openai/gpt-oss-20b(a Mixture-of-Experts model with only ~3.6B active parameters per token — picked specifically for low-latency tool-calling). The agent has real tools, not just a prompt:state_diff(checks heap identity to tell mutation from rebind),ast_scope_lookup(parses the surrounding code shape), and a retrieval tool for extra grounding. - Concept RAG: a small, curated knowledge base — CPython internals, common exceptions, a couple of third-party libraries — chunked with header-based Markdown splitting, embedded via the Jina AI Embeddings API, and searched through Qdrant. Retrieval is triggered deterministically from the step's own execution shape (event type, AST node, runtime type) rather than left to however the model happens to phrase a search.
- Frontend: React + Vite, Monaco for the editor, Tailwind for styling, Zustand for state — a landing page and the actual visualizer built as two separate static entry points from one build.
- Backend: FastAPI on Vercel serverless, layered so routers only import "downward" into agent/tracer/rag/core — adding an endpoint never means touching the file everything else imports from.
Challenges we ran into
- Silent failures are the enemy of debugging an AI pipeline.
search_concepts()was deliberately built to fail soft — return[]rather than break an explanation just because RAG hiccuped. That same design choice made a real bug (a stale, removed Qdrant client method) look identical to "nothing matched," for a while. We ended up building a dedicateddiagnose.pyscript whose entire job is to bypass that safety net and surface the real error. - A wrong collection name hid in plain sight. Pointing at the wrong Qdrant collection (an unrelated one from a different project on the same cluster) returned real results with real scores — it just wasn't our data. A clean-looking response isn't the same as a correct one.
- Latency added up in ways that weren't obvious from the outside. What looked like "one AI call" was actually retrieval, a routing decision, and a second forced-format call stacked sequentially. Fixing it took three separate, independent changes — a smaller/faster model, skipping retrieval on the genuinely low-value query, and collapsing the agent's decision and its final answer into one call instead of two.
- "Works on my machine" turned out to mean "works on Windows."
A component import that resolved fine locally (
LearnPythonvs.learnpython.jsx) broke the Vercel build outright, because Windows' filesystem doesn't care about case and Linux does.
Accomplishments that we're proud of
- A tracer that's actually deterministic where it needs to be — the facts (mutation vs. rebind, call stack shape) never come from the LLM's imagination, only from real interpreter state.
- A retrieval system with an actual golden-dataset evaluation harness behind it, not just vibes — real hit-rate@k numbers, and a documented, honestly-labeled gap (one case the automatic retrieval still can't reach) instead of pretending it's perfect.
- Meaningfully cutting explanation latency through real architectural changes, not just "try a different model and hope."
- A project structure that stayed maintainable through a lot of iteration — routers, core config, tracer, agent, and RAG all stayed cleanly separated the whole way through.
What we learned
- Deterministic tools beat prose for anything that has a factually correct answer — the agent's job is narration, not fact-finding, once you give it the right tools to check its own claims.
- A safety net that hides failures gracefully in production is exactly the thing that makes failures hard to find in development — the two goals are in real tension, and you need both a soft-fail path and a hard-fail diagnostic path, on purpose, as separate tools.
- The "obvious" fix is often the wrong scope. A slow endpoint wasn't one slow thing — it was three ordinary things happening in sequence instead of being questioned individually.
What's next for Ai_python_visualizer
- A properly hardened execution sandbox (microVM-level isolation) for the day this needs to safely handle fully untrusted, public code — the current sandbox is intentionally scoped for a trusted, educational audience, not the open internet.
- A bigger, more structured concept corpus — more third-party libraries, deeper CPython internals, so RAG grounding covers more of what people actually run into.
- Closing the one documented retrieval gap: teaching automatic retrieval to recognize a plain rebind (not just container mutations and exceptions) so it doesn't depend on the agent thinking to search for it itself.
- Saved traces and shareable links, so a tricky step can be sent to someone else instead of re-explained from scratch.

Log in or sign up for Devpost to join the conversation.