When you are hunting a performance issue or a bug, your model can only reason with your code and some logs or tracecalls you feed into the chat. It would be even more helpful, if your agent could access and even interact with the current state of your application. This is, in a nutshell, what ipyllm brings.
What is ipyllm? Link to heading
ipyllm is a open source IPython extension that seamlessly integrates Large Language Models (LLMs) into your live IPython environment. I have described it in previous posts. tldr: it is an agent with full access to your IPython environment, so it can reason about your actual state of the application and IPython history. Caution: it runs code in your environment too.n More on this later.
You can, for example, prompt queries on your DB.
%llm Which models relate to Invoice, and what are the reverse accessors?
ORM queries that are verified, not guessed Link to heading
The usual failure of a chat assistant is a plausible queryset with a wrong field name. Here the model can check:
%llm Top 5 customers by total order value in the last 90 days, with their
most recent order. Run it and show me the SQL.
Because it can introspect _meta and execute the result, it can correct itself when Order.total turns out to be Order.amount_cents. You get a queryset that ran against your schema, plus str(qs.query) to sanity-check what Django generated.
N+1 hunting on your own data Link to heading
This is where live state pays off most:
%llm `orders` is slow to render. Count the queries it issues, find the
N+1, and test a fix with select_related / prefetch_related.
The model can measure with CaptureQueriesContext, apply the fix, and measure again. “47 queries down to 3” is far more convincing than a suggestion you have to take on faith, and it’s against your real data volume, not a toy example.
Debugging inside a view Link to heading
ipyllm ships ipyllm.embed(), which works like IPython’s embed() but with the assistant already loaded. Drop it where something looks wrong:
import ipyllm
def checkout(request):
order = build_order(request)
if not order.is_valid():
ipyllm.embed() # sees `request`, `request.user`, `order`
...
%llm Why is this order invalid? Check the form errors and the session.
The model sees the function’s actual locals: the real request, the real session, the real object. One practical note: an embedded shell needs a working stdin, so runserver’s autoreloader gets in the way. Use runserver --noreload, run tests with output capture off (pytest -s), or use embed() in management commands, where it just works.
Making sense of failing commands Link to heading
Migration conflicts and cryptic test failures are tedious to explain to anyone. %%llm --run runs the command, captures stdout, stderr, and the exit status, and hands them to the model with your question:
%%llm --run Explain the failure and suggest a fix.
python manage.py migrate
Because the model also has your live shell, it can look at the relevant models while it reads the error. Output sent to the model is capped at 12,000 characters (beginning and end), and commands time out after 120 seconds by default.
Prototype a data fix, then keep the code Link to heading
Need a one-off cleanup? Prototype it against a sample, and record what happened:
%llm --save fix_duplicates.py
%llm Find customers with duplicate emails differing only by case and
draft a merge routine. Run it on three examples first.
ipyllm writes your requests as comments and the model-executed Python as code. It’s a starting point you review and tidy into a management command or RunPython step, not something to ship as is.
Caveat Link to heading
In a pandas session, a bad model-written line costs you a variable. In a Django shell, it can touch a database. Model-requested code runs in your process with your permissions, and it is not sandboxed. This is a complex topic I will deal with in greater depth in a different post.
In any case, a few habits make this safe enough for daily use:
- Development data only. Never point this at production. Not once.
- Turn approval on.
%llm --approval onmakes you review code before it runs, and you can make it the default withc.IpyllmMagics.require_approval = True. The docs are blunt that approval is a review step, not a security boundary, so read what you approve. - Mind your secrets.
settingsholdsSECRET_KEYand credentials, andconnection.settings_dictincludes the database password. If the model inspects them, they go to your provider. Don’t ask it to, and prefer environment-variable-based settings you haven’t loaded into the shell. - Mind your data. Querysets contain real rows, possibly personal data. Use a scrubbed dev database, and check your provider’s data handling.
- Make writes reversible. Ask the model to wrap experiments in a transaction and roll back:
%llm Run this inside transaction.atomic() and roll back at the end,
so I can see the effect without committing anything.
That last one is a convention you ask for, not a guarantee, so it pairs with approval rather than replacing it.
Ipyllm’s use case Link to heading
ipyllm isn’t a replacement for your editor’s assistant. It’s for the moments when the answer depends on state: what’s actually in this queryset, what this request actually contains, what this query actually does. Those are exactly the moments where pasting into a chat window loses the most.
If you try it in a Django project, I’d like to hear what works and what doesn’t, especially around shell_plus and embed() in your test setup. A read-only mode and automatic redaction of settings are on my wish list, and Django developers are the people best placed to tell me what’s most useful.
Docs: juampatronics.com/ipyllm · Code: github.com/juampatronics/ipyllm