Advanced Programming for Data Scientists
Coding with AI, and building AI that acts.
Nir Naim · Tel Aviv University · 3-hour session
Roadmap
Before we start · the basics
What this “AI” actually is — and what “vibe coding” even means.
The tool under the hood
Think “autocomplete that read the whole library,” not “a mind that knows facts.”
Why it works for us
Read this twice
Your job: stay the engineer who decides what's actually correct.
The name for it
You describe what you want in plain language → the AI writes the code → you run, review & steer. You focus on the intent and the outcome, not on typing every character.
Term coined by Andrej Karpathy, early 2025 — now how a lot of real software gets built.
What changes for you
You're still the engineer — now the pilot, not the typist.
Before class
GitHub Student Pack (with your @mail.tau.ac.il email) → Copilot Pro → VS Code → the Copilot extension. If not — do it now, it's on the course site.
Ask → visualize → test → fix → iterate.
Warm-up ispow2(n)
# no bin / len / logs / strings — bit ops only. 0 is NOT a power of two. def ispow2(n): return n > 0 and (n & (n - 1)) == 0
Tell it the forbidden built-ins up front — or it reaches for bin().
The mental model
You stay the engineer. The AI is a very fast, very literal pair-programmer.
Demo longest_run(n)
longest_run(n) → length of the longest run of consecutive 1 bits.
bin() 👀)▶ Live now longest_run
Full walkthrough, live — ask, visualize, test, fix, iterate.
The takeaway
The AI happily breaks the rules unless you state them. bin() worked — but was forbidden.
Once you have tests, you can let the AI rewrite the code and know instantly if it broke.
Before your turn
Your turn
Reverse the low num_bits bits of x. Same loop: ask (with constraints) → visualize → test → fix → improve.
Timer + visualizer are on the course site → In Class.
with PydanticAI
The core idea
What makes it an agent
Remove the loop and the tools → you're back to one chat message.
What is a tool?
@agent.tool_plain def word_count(text: str) -> int: """Return the number of words in the given text.""" return len(text.split())
The docstring is the tool's instruction manual for the model.
Why bother
An LLM alone is a brilliant intern with no phone, no internet, no notebook. Tools give it the phone and the notebook.
On "doing" tasks, tool-using agents complete far more than single prompts.
Your stack = 3 choices
PydanticAI, LangGraph, LlamaIndex…
We use PydanticAI.
Gemini, Claude, GPT, Llama…
Swappable in one line. Gateway = API / OpenRouter / Ollama.
Tools · observability · tests · guardrails.
Where the real work is.
Model & framework are easy swaps. The harness is what makes an agent good.
The point
Same model, same framework — a strong harness is the difference between a demo and something you'd ship.
Architectures · first cut
Same brick underneath: the augmented LLM (model + tools + memory).
Architectures · the ladder simple → complex
Scaling up · & the one rule
Supervisors of workers. High control, big tasks.
Peers, no boss. Exploration at scale.
3–8 peers, tight loops on one artifact.
Rule: every layer adds cost, latency & failure points. Use the fewest pieces that solve it.
Tools at scale
One open standard. Plug your agent into ready-made servers — GitHub, Slack, databases, filesystem, browser — and it gains all their tools at once.
No credit card needed
aistudio.google.com, generous requests/day:freeUsageLimitExceededBecause agents loop, always cap the number of requests.
▶ Live first_agent.py
class Answer(BaseModel): result: int agent = Agent("google-gla:gemini-2.0-flash", output_type=Answer) @agent.tool_plain def add(a: int, b: int) -> int: """Add two integers.""" return a + b out = agent.run_sync("What is 21 + 21? Use the add tool.", usage_limits=UsageLimits(request_limit=5)) print(out.output.result) # -> 42
Assume it misbehaves
At home · workshop
Fan out with asyncio.gather, fan in with a synthesizer — then trace it and eval it. Full guide on the site.
Recap
The same loop — from a bit trick to a parallel agent pipeline.
Nir Naim · Course site has everything: prep · demo · challenge · workshop
Bonus · optional
A quick, high-level peek at the architecture behind every modern LLM.
The architecture
Remember the opener: a next-word predictor. This is the engine that does the predicting.
Step 1 text → numbers
vibe coding → ["vibe", " cod", "ing"]Step 2 · the key idea
Each token looks at every other token and decides which ones matter for what comes next.
bank pays attention to river → water's edge.
bank pays attention to savings → money.
Same word — context resolves the meaning. That's the breakthrough.
Step 3 stack it up · predict
Trained on trillions of words. At runtime it predicts one token, adds it, and predicts again — “autoregressive.”
Why it mattered
You don't need the math to use it well — but now you've seen what's inside the box.