{
  "@context": "https://schema.org",
  "@id": "https://aggr.aymericbeaumet.com/items/huggingface-co/2025-09-10-jupyter-agents-training-llms-to-reason-with-notebooks/#webpage",
  "@type": [
    "WebPage",
    "ArchiveComponent"
  ],
  "articleBody": "The past year has been all about giving LLMs more tools and autonomy to solve more complex and open ended tasks. The goal of the **Jupyter Agent** is to give the model the ultimate tool: code execution.\n\nA natural way to display multi-step code execution together with reasoning is within a Jupyter Notebook, which consists of code and markdown cells. So we built Jupyter Agent to act as an agent that can execute code directly inside a Jupyter notebook and use this environment to solve data analysis and data science tasks. Think of it like *Cursor*, but living natively inside your data science workflow.\\\nWe built a [demo](https://huggingface.co/spaces/lvwerra/jupyter-agent-2) of this vision with **Qwen-3 Coder**, currently one of the strongest coding models. This is a follow-up to our earlier work on [jupyter-agent (v1)](https://huggingface.co/spaces/lvwerra/jupyter-agent).\n\nWhile large models are starting to show useful behavior, the key question is how we can continue improving them. To this end, we focus on strengthening smaller models to perform well on agentic data science tasks as they currently struggle to compete with the large models.\n\nThe goal of this project is to build a pipeline to first generate high-quality training data, then fine-tune an existing small model, and finally evaluate whether the model's performance improves on relevant benchmarks.\n\nLet’s begin with the last step: selecting a strong benchmark for evaluating models on data science tasks.\n\n## 🏁 Primer: the DABStep Benchmark\n\nIn order to understand if we are making progress towards better data science agents we need a benchmark to measure such capabilities. Last year, in partnership with [Adyen](https://huggingface.co/adyen), we introduced the **[DABStep benchmark](https://huggingface.co/blog/dabstep)**: a way to evaluate data science agents on realistic tasks. The setup is simple: provide the LLM with datasets and ask it to answer non-trivial data questions.\n\nExample tasks:\n\n| Question                                                                                                                                                                                               | Answer      |\n| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------- |\n| Which card scheme had the highest average fraud rate in 2023?                                                                                                                                          | SwiftCharge |\n| For the year 2023, focusing on the merchant *Crossfit Hanna*, if we incentivize users to switch to a different Authorization Characteristics Indicator, which option would be the most cost-effective? | E:346.49    |\n\nThis benchmark remains challenging for today’s LLMs — e.g. the best out-of-the-box model is Claude 4 Sonnet which reaches not even 20% accuracy on the hard tasks.\\\nYou can explore the live leaderboard [here](https://huggingface.co/spaces/adyen/DABstep).\n\n## 🎯 First Baseline\n\nNow that we identified a good benchmark we can try to climb it! We set out to build a dataset for fine-tuning such that even **a small data agent model** could perform well on DABStep.\n\nOur first choice was [**Qwen3-4B-Thinking-2507**](https://huggingface.co/Qwen/Qwen3-4B-Thinking-2507): extremely small (fast to iterate with, easy to run), yet strong enough to act in agentic scenarios.\n\nBaseline results:\n\n- *Easy tasks:* **44.4%**\n- *Hard tasks:* **2.1%**\n\nNot great — but a promising starting point, since it left a lot of room for improvement. Let's see how we can improve it!\n\n## 🔧 Primer on Scaffolding\n\nA core aspect of agents that sets it apart from a pure chat model is the scaffolding built around the model to steer its behaviour. The evaluation script in DABStep for example uses [smolagents](https://github.com/huggingface/smolagents) to execute code. Smolagents comes with predefined behaviors, prompting structures, and expected formats.\n\nWe also studied the [**Qwen-Agent**](https://github.com/QwenLM/Qwen-Agent) codebase, where the authors tailoring scaffolding to the model. This makes sense: Claude Code, for example, works shockingly well with Claude Sonnet because their scaffolding is aligned.\n\nSo, we restructured our scaffolding:\n\n- Stripped it down to ~200 lines of code.\n- No external dependencies.\n- Inspired by the spirit of [**tiny-agents**](https://huggingface.co/blog/tiny-agents).\n\n👉 Check it out here: [utils.py](https://huggingface.co/spaces/lvwerra/jupyter-agent-2/blob/main/utils.py).\n\n**Results:** accuracy jumped from **44.4% → 59.7% (easy split)**. 🚀\n\n**Our loop:**\n\n- While loop with two tools: *code execution* to run the code and *final\\_answer* to return the final answer.\n- We differ from Qwen-Agent by explicitly adding a **final\\_answer** tool — which in our testing has improved performance.\n- Compared to smolagents, we simplified the scaffolding by removing a lot of prompts and tools. Smolagents also hardcodes a lot of assumptions into the model by using the ReACT framework.\n\n## 🏃♂️ Training Pipeline\n\nWith simplified scaffolding in place, we focused on fine-tuning Qwen3-4B for **data science agentic tasks**.\n\n## ⚙️ Dataset Pipeline\n\nThe recipe to improve a model on a certain task or behaviour is to train it on data that reflects the tasks as closely as possible. A natural starting point is to look at real Jupyter Notebooks and find notebooks that align closely with the task that we plan to tackle, namely data analysis.\n\nKaggle notebooks offer a wealth of high quality data analysis notebooks and are made available by Kaggle:\n\n**Datasets:**\n\n- **Kaggle Notebooks dataset**: ~2TB of notebooks.\n- **Kaggle Datasets**: 5TB of kaggle datasets that we manually downloaded and linked to the notebooks.\n- Rich metadata for each notebook (authors, datasets used, etc.).\n\nNow that we have good results with a base model it's time to build a dataset that will help us improve it even further. We designed a multi-stage pipeline using [Datatrove](https://github.com/huggingface/datatrove) to clean and prepare Kaggle notebooks at scale.\n\n![Jupyter Agent Dataset Pipeline](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/jupyter-agent-2/jupyter-agent-dataset-pipeline.png)\n\nHere’s how each step worked:\n\n### 1. Large-scale deduplication\n\nWe started with ~2TB of Kaggle notebooks and reduced it to ~250GB reusing our work from the BigCode project. As part of the StarCoder2 training data processing the notebooks (without output cells) were already deduplicated. Most Kaggle notebooks are small variations or near-identical copies, so this step was essential.\\\n*Key insight:* ~90% of raw notebooks are duplicates, which would have skewed training if left unfiltered.\n\n### 2. Downloading linked datasets\n\nMost Kaggle notebooks reference external datasets via Kaggle metadata. To make sure the code inside notebooks could actually run, we built a pipeline that automatically fetched these linked datasets. This step was crucial, since many notebooks would otherwise be incomplete or non-executable.\n\nUsing the **kagglehub** package, we downloaded thousands of datasets — about **5TB** in total. To keep things manageable and relevant:\n\n- We filtered out datasets containing model checkpoints, large multimodal corpora, or LLM-related files.\n- We also excluded very large datasets (10GB+) that couldn’t fit into the virtual [E2B sandboxes](https://e2b.dev/) we used for execution.\n\nBy the end, we had a rich collection of executable notebooks paired with their datasets, providing the foundation for training agents in realistic, runnable environments.\n\n### 3. Edu scoring\n\nWe scored notebooks based on educational quality using [Qwen3-32B](https://huggingface.co/Qwen/Qwen3-32B). We saw that using the whole notebook was not optimal, as many contained trivial or broken code. Our educational scoring approach is detailed in edu\\_scoring.py.\n\n**TL;DR:** We assigned each notebook a score from 1–5 based on clarity, completeness, and educational value, and kept only those above a chosen threshold. This filtering removed about 70% of the notebooks.\n\nThis is similar to the insight from the BeyondWeb paper, which showed that using high-quality data is better for synthetic data generation — a step we relied on for QA (Question-Answer) generation. This helped the model learn from “high quality” notebooks instead of noisy ones.\n\n### 4. Filtering irrelevant notebooks\n\nWe excluded notebooks about training LLMs or unrelated to data analysis. We also removed notebooks that didn’t actually use datasets through an automated LLM-based filtering process using Qwen3-32B. The implementation of filtering can be found in [`extract_packages_and_files.py`](https://github.com/huggingface/jupyter-agent/blob/main/data/pipelines/extract_packages_and_files.py).\n\n**TL;DR:** We prompted Qwen3-32B to identify and remove notebooks that either (1) had nothing to do with data analysis, or (2) didn’t actually use datasets. This step removed about 20% of the notebooks.\n\nThis ensured we trained only on relevant data science tasks.\n\n### 5. QA generation\n\nUsing the cleaned notebooks, we generated question–answer pairs using [Qwen3-32B](https://huggingface.co/Qwen/Qwen3-32B). The questions and answer are grounded in the real notebook traces so the QA pairs are based on real code execution results. **Prompt design:** we asked the LLM to produce natural questions that could realistically be asked of the dataset, then validated whether the notebook provided a correct answer.\n\n*Challenge:* We had to try many prompts to get higher-difficulty questions because LLMs tended to generate trivial ones like \"what is the size of the dataset\".\\\n*Insight:* We broke this into two steps because LLMs tended to hallucinate answers:\n\n1. Generate the question and answer.\n2. Ask another LLM (with access to the notebook) to check whether the answer was correct.\n\nThe complete prompting strategy and implementation is available in [`generate_qa.py`](https://github.com/huggingface/jupyter-agent/blob/main/data/pipelines/generate_qa.py).\n\n### 6. Trace generation\n\nFinally we want to generate clean code execution traces since even the original notebooks after processing are often open ended and verbose with lots of irrelevant parts. However, we want our Jupyter Agent to get to the result efficiently. To generate cleaner notebook traces for training we generated traces synthetically based on the original notebooks.\\\nWe have prompted [Qwen-3-Coder-480B](https://huggingface.co/Qwen/Qwen3-Coder-480B-A35B-Instruct) model to generate a jupyter notebook code to answer the question from the previously generated synthetic QA pair. Traces captured step-by-step code execution, including intermediate outputs, which are crucial for agent training.\n\nWe used [E2B](https://e2b.dev/) for our agent to solve the synthetic QA pairs, which required fetching Kaggle datasets so the code could actually run via E2B.\n\n*Challenge 1:* Many datasets were unavailable.\\\n*Trick:* Since LLMs are strong at code and have a decent world model, we prompted them to **act as a code interpreter** when the dataset was missing.\n\nBeginning of the prompt:\n\n```\nYou are a stateful Python code interpreter that executes code in a persistent environment. Your role is to execute Python code while maintaining state across multiple code cells, similar to a Jupyter notebook environment.\n[REST OF THE PROMPT]\n```\n\n*Challenge 2:* [Qwen3-Coder-480B-A35B](https://huggingface.co/Qwen/Qwen3-Coder-480B-A35B-Instruct) model does not support thinking mode - how can we extract code commentary? By default it often outputs just a brief comment followed by several steps of code execution. However, we'd like some reasoning or comments between every cell. *Trick:* When switching from [Qwen3-32B](https://huggingface.co/Qwen/Qwen3-32B) to [Qwen3-Coder-480B-A35B](https://huggingface.co/Qwen/Qwen3-Coder-480B-A35B-Instruct) we noticed that often output message content was empty. This turns out to be a previously known quirk of Qwen3-Coder models in which when using tool calling the model would not return an empty assistant response. We enforce some text commentary through tooling by passing 'comment' as a required field in the code execution tool call. This way when non-reasoning model is used for code cell generation it will by default output some description of its actions from 1st POV, emulating the thinking traces structure.\n\n**Note:** the generated final answer in the notebook may vary from the answer specified in the QA pair. This is caused by the fact that the agent model could use data preprocessing methods and steps different from the original Kaggle notebook and the synthetic question would not usually specify them. This discrepancy is normal and lays the foundation for a new exciting research direction of how language models tend to treat data analysis and whether they do it differently from humans. For full transparency we keep both LLM-generated final answer and original answer from the real Kaggle notebook as a signal of model's performance. We encourage the community to try different dataset mixes to see how they can push performance even further.\n\n### 7. Final curation\n\nWe truncated overly long outputs and filtered out trivial traces to prevent content length issues and keep only high-quality traces.\\\nWe kept non-trivial, multi-turn traces aligned with DABStep-style tasks.\\\nThe resulting [Jupyter Agent Dataset](https://huggingface.co/datasets/jupyter-agent/jupyter-agent-dataset) became the foundation for SFT on Qwen3-4B models with 51k synthetic notebooks and almost 0.2B tokens.\n\nWith this dataset in hand, the natural next step is to see whether it actually helps our model become a stronger data science agent. Let’s move on to the training pipeline and evaluate the impact!\n\n## 🏃♂️ Training Pipeline\n\nWith the curated dataset ready, we turned to the key question: **does this data actually help the model get better at solving data analysis tasks?** To find out, we set up a simple fine-tuning pipeline and ran experiments to measure the impact of training on our synthetic notebooks.\n\nSome training steps turned out to be particularly interesting and gave us useful insights:\n\n- For trace generation, we used LLMs to generate QA pairs, which gave us a **verifiable environment**.\n- Finally, we fine-tuned **Qwen3-4B** with [TRL](https://huggingface.co/docs/trl).\n  - Used `assistant_loss_only=True` → small performance boost.\n  - Added neftune noise for full-parameter multi-epoch training → avoids overfitting.\n\n**Challenges:**\n\n- Prompting models for tool calling is tricky: not all prompts deliver the same performance ([Qwen docs](https://qwen.readthedocs.io/en/latest/framework/function_call.html#vllm)).\n- We had to manually test each one to find what worked best.\n- There’s no standardization in response formats for tool calling, making it difficult to switch between models.\n- Native Qwen's generation prompt is not adapted to `assistant_loss_only=True` training mode in TRL which requires to have generation tokens by default. Thus, we adapt the original chat templates by wrapping the assistant response part in the generation tags.\n- Training thinking models on short reasoning texts may disrupt model capabilities → full-parameter training works better comparing to PEFT in this case.\n\nOur complete training implementation, including hyperparameter configurations and template adaptations, is available in our [finetuning directory](https://github.com/huggingface/jupyter-agent/tree/main/finetuning) in our repo.\n\n## 📊 Results\n\nFirst, we generated our final dataset using [Qwen3-Coder-480B-A35B](https://huggingface.co/Qwen/Qwen3-Coder-480B-A35B-Instruct) which contains high quality code and short reasoning-like traces. Afterwards, we started our training and we have experimented with various configurations like PEFT/adapters vs. full-parameter tuning, learning rate, number of epochs, adding noise and others. We found out, that full-parameter fine-tuning allows the model to learn and replicate the [Qwen3-Coder-480B-A35B](https://huggingface.co/Qwen/Qwen3-Coder-480B-A35B-Instruct) behavior response quality better with shorter supporting commentary fitting more to the data analysis task without unnecessary long reasoning.\n\nWe have done a small ablation study on the impact of no. training epochs:\n\n| Model                                     | No. of epochs | DABstep (Easy) |\n| ----------------------------------------- | ------------- | -------------- |\n| Qwen-3-4B-Instruct-2507 (Base)            | 0             | 38.67%         |\n| Qwen-3-4B-Instruct-2507 (Our Scaffolding) | 0             | 52.78%         |\n| Qwen-3-4B-Instruct-2507                   | 2             | 63.89%         |\n| Qwen-3-4B-Instruct-2507                   | 3             | 73.61%         |\n| Qwen-3-4B-Instruct-2507                   | 5             | **75%**        |\n| Qwen-3-4B-Instruct-2507                   | 7             | 70.83%         |\n\nWe observe that it is beneficial to have a bit more epochs than usual for SFT with lower learning rate and higher neftune noise (7). Finally, we compare our trained models with implemented scaffolding to define the pure impact of our training dataset. In summary, we can see up to 36%/22% boost on DABStep easy score compared with base/scaffolded model:\n\n![DABstep Easy Score](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/jupyter-agent-2/training_dabstep_easy.png)\n\nWe can also see, that the hard score can increase too even though our dataset is focused on easier questions:\n\n![DABstep Hard Score](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/jupyter-agent-2/training_dabstep_hard.png)\n\nFrom figures above one can notice a noticeable impact of both new scaffolding and tuning on our synthetic notebooks. This makes Qwen-4B (with our pipeline + scaffolding) a state-of-the-art small-model agent on DABStep.\n\nIn practice, the model can now solve a wide range of realistic Kaggle-style data analysis tasks with consistent execution.\\\nIt’s not yet strong enough for the hardest queries, but we’ve shown that even small models can become powerful agents when paired with the right data and scaffolding.\n\n## Try Jupyter Agent Yourself\n\nThese results demonstrate that even small models can become powerful data science agents with the right training approach. Ready to try it yourself? We've made everything openly available so you can experiment with our fine-tuned models and dataset.\n\nWe openly release best-performing checkpoints of tuned Qwen3-4B-Instruct-2507 and Qwen3-4B-Thinking-2507 together with the training dataset, which you can try out and experiment with:\n\n- [Jupyter Agent Dataset](https://huggingface.co/datasets/jupyter-agent/jupyter-agent-dataset)\n- [Jupyter-Agent-Qwen3-4B-Instruct](https://huggingface.co/jupyter-agent/jupyter-agent-qwen3-4b-instruct)\n- [Jupyter-Agent-Qwen3-4B-Thinking](https://huggingface.co/jupyter-agent/jupyter-agent-qwen3-4b-thinking)\n\nYou can load Jupyter Agent Dataset in just a couple of lines using the following code:\n\n```python\nfrom datasets import load_dataset\n# To load the train split of a specific subset, such as non-thinking, you can do\nds = load_dataset(\"jupyter-agent/jupyter-agent-dataset\", split=\"non-thinking\")\n# apply chat template\ntokenizer.apply_chat_template(ds[0][\"text\"])\n```\n\nYou can also use sourced Kaggle datasets directly with E2B code execution using the following code:\n\n```python\nimport kagglehub\nimport e2b_code_interpreter as e2b\nfrom datasets import load_dataset\n\n# load the Jupyter Agent Dataset\nds = load_dataset(\"jupyter-agent/jupyter-agent-dataset\", split=\"thinking\")\n# get the kaggle dataset name\ndataset_name = ds[0][\"kaggle_dataset_name\"]\n# load the dataset locally from Kaggle Hub\npath = kagglehub.dataset_download(dataset_name)\nprint(path) # this is the folder path where the dataset is downloaded\n# initialize sandbox\nsandbox_init = e2b.Sandbox(timeout=240)\n# write used file to E2B sandbox\nfile_name = ds[0][\"files_used\"][0]\nfile_name = file_name.split('/')[-1] if '/' in file_name else file_name\nwith open(f\"{path}/{file_name}\", \"rb\") as file:\n    sandbox_init.files.write(f\"/home/user/input/{file_name}\", file)\n# execute code with E2B\nexecution = sandbox_init.run_code(\"<some code>\")\n```\n\nYou use tuned Jupyter Agent Qwen-based models following the Qwen documentation code:\n\n```python\nfrom transformers import AutoModelForCausalLM, AutoTokenizer\n\nmodel_name = \"jupyter-agent/jupyter-agent-qwen3-4b-instruct\"\n\n# load the tokenizer and the model\ntokenizer = AutoTokenizer.from_pretrained(model_name)\nmodel = AutoModelForCausalLM.from_pretrained(\n    model_name,\n    torch_dtype=\"auto\",\n    device_map=\"auto\"\n)\n\n# prepare the model input\nprompt = \"Give me a short introduction to large language model.\"\nmessages = [\n    {\"role\": \"user\", \"content\": prompt}\n]\ntext = tokenizer.apply_chat_template(\n    messages,\n    tokenize=False,\n    add_generation_prompt=True,\n)\nmodel_inputs = tokenizer([text], return_tensors=\"pt\").to(model.device)\n\n# conduct text completion\ngenerated_ids = model.generate(\n    **model_inputs,\n    max_new_tokens=16384\n)\noutput_ids = generated_ids[0][len(model_inputs.input_ids[0]):].tolist() \n\ncontent = tokenizer.decode(output_ids, skip_special_tokens=True)\n\nprint(\"content:\", content)\n```\n\nFor Thinking model you can decode both thinking response and content using the next code:\n\n```python\nfrom transformers import AutoModelForCausalLM, AutoTokenizer\n\nmodel_name = \"jupyter-agent/jupyter-agent-qwen3-4b-thinking\"\n\n# ...use same processing code from above...\ntry:\n    # index finding 151668 (</think>)\n    index = len(output_ids) - output_ids[::-1].index(151668)\nexcept ValueError:\n    index = 0\n\nthinking_content = tokenizer.decode(output_ids[:index], skip_special_tokens=True).strip(\"\\n\")\ncontent = tokenizer.decode(output_ids[index:], skip_special_tokens=True).strip(\"\\n\")\n```\n\n## 🔮 Next Steps\n\n- *Harder tasks:* Generate more challenging, multi-step questions that better reflect real-world analysis.\n- *Scaling up:* Train on larger volumes of curated traces to push beyond the current 3.4% performance on the hard split.\n- *Distillation:* Investigate knowledge distillation, which has shown strong results for improving small models.\n- *Reinforcement Learning (RL):* Build an RL environment, which has been shown to achieve state-of-the-art performance on agentic tasks. Since our QA setup already provides a verifiable environment, we could leverage it directly for RL training.\n\nMaybe this will lead to… **Jupyter-Agent 3.** 😉\n\nWe hope that our findings will inspire others to continue progress in developing more powerful notebook coding agents and we're excited to see what the community builds next. Dive into our [jupyter-agent dataset](https://huggingface.co/datasets/jupyter-agent/jupyter-agent-dataset) on the 🤗 Hub and explore the codebase at [https://github.com/huggingface/jupyter-agent](https://github.com/huggingface/jupyter-agent) to start your own experiments on agents for jupyter notebooks.\n",
  "authors": [],
  "captured_at": "2026-10-04T12:50:30.804479567+00:00",
  "category": "ai",
  "content_html": "<p>The past year has been all about giving LLMs more tools and autonomy to solve more complex and open ended tasks. The goal of the <strong>Jupyter Agent</strong> is to give the model the ultimate tool: code execution.</p>\n<p>A natural way to display multi-step code execution together with reasoning is within a Jupyter Notebook, which consists of code and markdown cells. So we built Jupyter Agent to act as an agent that can execute code directly inside a Jupyter notebook and use this environment to solve data analysis and data science tasks. Think of it like <em>Cursor</em>, but living natively inside your data science workflow.<br />\nWe built a <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/spaces/lvwerra/jupyter-agent-2\">demo</a> of this vision with <strong>Qwen-3 Coder</strong>, currently one of the strongest coding models. This is a follow-up to our earlier work on <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/spaces/lvwerra/jupyter-agent\">jupyter-agent (v1)</a>.</p>\n<p>While large models are starting to show useful behavior, the key question is how we can continue improving them. To this end, we focus on strengthening smaller models to perform well on agentic data science tasks as they currently struggle to compete with the large models.</p>\n<p>The goal of this project is to build a pipeline to first generate high-quality training data, then fine-tune an existing small model, and finally evaluate whether the model's performance improves on relevant benchmarks.</p>\n<p>Let’s begin with the last step: selecting a strong benchmark for evaluating models on data science tasks.</p>\n<h2>🏁 Primer: the DABStep Benchmark</h2>\n<p>In order to understand if we are making progress towards better data science agents we need a benchmark to measure such capabilities. Last year, in partnership with <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/adyen\">Adyen</a>, we introduced the <strong><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/blog/dabstep\">DABStep benchmark</a></strong>: a way to evaluate data science agents on realistic tasks. The setup is simple: provide the LLM with datasets and ask it to answer non-trivial data questions.</p>\n<p>Example tasks:</p>\n<table>\n<thead>\n<tr>\n<th>Question</th>\n<th>Answer</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Which card scheme had the highest average fraud rate in 2023?</td>\n<td>SwiftCharge</td>\n</tr>\n<tr>\n<td>For the year 2023, focusing on the merchant <em>Crossfit Hanna</em>, if we incentivize users to switch to a different Authorization Characteristics Indicator, which option would be the most cost-effective?</td>\n<td>E:346.49</td>\n</tr>\n</tbody>\n</table>\n<p>This benchmark remains challenging for today’s LLMs — e.g. the best out-of-the-box model is Claude 4 Sonnet which reaches not even 20% accuracy on the hard tasks.<br />\nYou can explore the live leaderboard <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/spaces/adyen/DABstep\">here</a>.</p>\n<h2>🎯 First Baseline</h2>\n<p>Now that we identified a good benchmark we can try to climb it! We set out to build a dataset for fine-tuning such that even <strong>a small data agent model</strong> could perform well on DABStep.</p>\n<p>Our first choice was <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/Qwen/Qwen3-4B-Thinking-2507\"><strong>Qwen3-4B-Thinking-2507</strong></a>: extremely small (fast to iterate with, easy to run), yet strong enough to act in agentic scenarios.</p>\n<p>Baseline results:</p>\n<ul>\n<li><em>Easy tasks:</em> <strong>44.4%</strong></li>\n<li><em>Hard tasks:</em> <strong>2.1%</strong></li>\n</ul>\n<p>Not great — but a promising starting point, since it left a lot of room for improvement. Let's see how we can improve it!</p>\n<h2>🔧 Primer on Scaffolding</h2>\n<p>A core aspect of agents that sets it apart from a pure chat model is the scaffolding built around the model to steer its behaviour. The evaluation script in DABStep for example uses <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/huggingface/smolagents\">smolagents</a> to execute code. Smolagents comes with predefined behaviors, prompting structures, and expected formats.</p>\n<p>We also studied the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/QwenLM/Qwen-Agent\"><strong>Qwen-Agent</strong></a> codebase, where the authors tailoring scaffolding to the model. This makes sense: Claude Code, for example, works shockingly well with Claude Sonnet because their scaffolding is aligned.</p>\n<p>So, we restructured our scaffolding:</p>\n<ul>\n<li>Stripped it down to ~200 lines of code.</li>\n<li>No external dependencies.</li>\n<li>Inspired by the spirit of <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/blog/tiny-agents\"><strong>tiny-agents</strong></a>.</li>\n</ul>\n<p>👉 Check it out here: <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/spaces/lvwerra/jupyter-agent-2/blob/main/utils.py\">utils.py</a>.</p>\n<p><strong>Results:</strong> accuracy jumped from <strong>44.4% → 59.7% (easy split)</strong>. 🚀</p>\n<p><strong>Our loop:</strong></p>\n<ul>\n<li>While loop with two tools: <em>code execution</em> to run the code and <em>final_answer</em> to return the final answer.</li>\n<li>We differ from Qwen-Agent by explicitly adding a <strong>final_answer</strong> tool — which in our testing has improved performance.</li>\n<li>Compared to smolagents, we simplified the scaffolding by removing a lot of prompts and tools. Smolagents also hardcodes a lot of assumptions into the model by using the ReACT framework.</li>\n</ul>\n<h2>🏃♂️ Training Pipeline</h2>\n<p>With simplified scaffolding in place, we focused on fine-tuning Qwen3-4B for <strong>data science agentic tasks</strong>.</p>\n<h2>⚙️ Dataset Pipeline</h2>\n<p>The recipe to improve a model on a certain task or behaviour is to train it on data that reflects the tasks as closely as possible. A natural starting point is to look at real Jupyter Notebooks and find notebooks that align closely with the task that we plan to tackle, namely data analysis.</p>\n<p>Kaggle notebooks offer a wealth of high quality data analysis notebooks and are made available by Kaggle:</p>\n<p><strong>Datasets:</strong></p>\n<ul>\n<li><strong>Kaggle Notebooks dataset</strong>: ~2TB of notebooks.</li>\n<li><strong>Kaggle Datasets</strong>: 5TB of kaggle datasets that we manually downloaded and linked to the notebooks.</li>\n<li>Rich metadata for each notebook (authors, datasets used, etc.).</li>\n</ul>\n<p>Now that we have good results with a base model it's time to build a dataset that will help us improve it even further. We designed a multi-stage pipeline using <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/huggingface/datatrove\">Datatrove</a> to clean and prepare Kaggle notebooks at scale.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/jupyter-agent-2/jupyter-agent-dataset-pipeline.png\" alt=\"Jupyter Agent Dataset Pipeline\" loading=\"eager\" decoding=\"async\" fetchpriority=\"high\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>Here’s how each step worked:</p>\n<h3>1. Large-scale deduplication</h3>\n<p>We started with ~2TB of Kaggle notebooks and reduced it to ~250GB reusing our work from the BigCode project. As part of the StarCoder2 training data processing the notebooks (without output cells) were already deduplicated. Most Kaggle notebooks are small variations or near-identical copies, so this step was essential.<br />\n<em>Key insight:</em> ~90% of raw notebooks are duplicates, which would have skewed training if left unfiltered.</p>\n<h3>2. Downloading linked datasets</h3>\n<p>Most Kaggle notebooks reference external datasets via Kaggle metadata. To make sure the code inside notebooks could actually run, we built a pipeline that automatically fetched these linked datasets. This step was crucial, since many notebooks would otherwise be incomplete or non-executable.</p>\n<p>Using the <strong>kagglehub</strong> package, we downloaded thousands of datasets — about <strong>5TB</strong> in total. To keep things manageable and relevant:</p>\n<ul>\n<li>We filtered out datasets containing model checkpoints, large multimodal corpora, or LLM-related files.</li>\n<li>We also excluded very large datasets (10GB+) that couldn’t fit into the virtual <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://e2b.dev/\">E2B sandboxes</a> we used for execution.</li>\n</ul>\n<p>By the end, we had a rich collection of executable notebooks paired with their datasets, providing the foundation for training agents in realistic, runnable environments.</p>\n<h3>3. Edu scoring</h3>\n<p>We scored notebooks based on educational quality using <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/Qwen/Qwen3-32B\">Qwen3-32B</a>. We saw that using the whole notebook was not optimal, as many contained trivial or broken code. Our educational scoring approach is detailed in edu_scoring.py.</p>\n<p><strong>TL;DR:</strong> We assigned each notebook a score from 1–5 based on clarity, completeness, and educational value, and kept only those above a chosen threshold. This filtering removed about 70% of the notebooks.</p>\n<p>This is similar to the insight from the BeyondWeb paper, which showed that using high-quality data is better for synthetic data generation — a step we relied on for QA (Question-Answer) generation. This helped the model learn from “high quality” notebooks instead of noisy ones.</p>\n<h3>4. Filtering irrelevant notebooks</h3>\n<p>We excluded notebooks about training LLMs or unrelated to data analysis. We also removed notebooks that didn’t actually use datasets through an automated LLM-based filtering process using Qwen3-32B. The implementation of filtering can be found in <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/huggingface/jupyter-agent/blob/main/data/pipelines/extract_packages_and_files.py\"><code>extract_packages_and_files.py</code></a>.</p>\n<p><strong>TL;DR:</strong> We prompted Qwen3-32B to identify and remove notebooks that either (1) had nothing to do with data analysis, or (2) didn’t actually use datasets. This step removed about 20% of the notebooks.</p>\n<p>This ensured we trained only on relevant data science tasks.</p>\n<h3>5. QA generation</h3>\n<p>Using the cleaned notebooks, we generated question–answer pairs using <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/Qwen/Qwen3-32B\">Qwen3-32B</a>. The questions and answer are grounded in the real notebook traces so the QA pairs are based on real code execution results. <strong>Prompt design:</strong> we asked the LLM to produce natural questions that could realistically be asked of the dataset, then validated whether the notebook provided a correct answer.</p>\n<p><em>Challenge:</em> We had to try many prompts to get higher-difficulty questions because LLMs tended to generate trivial ones like &quot;what is the size of the dataset&quot;.<br />\n<em>Insight:</em> We broke this into two steps because LLMs tended to hallucinate answers:</p>\n<ol>\n<li>Generate the question and answer.</li>\n<li>Ask another LLM (with access to the notebook) to check whether the answer was correct.</li>\n</ol>\n<p>The complete prompting strategy and implementation is available in <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/huggingface/jupyter-agent/blob/main/data/pipelines/generate_qa.py\"><code>generate_qa.py</code></a>.</p>\n<h3>6. Trace generation</h3>\n<p>Finally we want to generate clean code execution traces since even the original notebooks after processing are often open ended and verbose with lots of irrelevant parts. However, we want our Jupyter Agent to get to the result efficiently. To generate cleaner notebook traces for training we generated traces synthetically based on the original notebooks.<br />\nWe have prompted <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/Qwen/Qwen3-Coder-480B-A35B-Instruct\">Qwen-3-Coder-480B</a> model to generate a jupyter notebook code to answer the question from the previously generated synthetic QA pair. Traces captured step-by-step code execution, including intermediate outputs, which are crucial for agent training.</p>\n<p>We used <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://e2b.dev/\">E2B</a> for our agent to solve the synthetic QA pairs, which required fetching Kaggle datasets so the code could actually run via E2B.</p>\n<p><em>Challenge 1:</em> Many datasets were unavailable.<br />\n<em>Trick:</em> Since LLMs are strong at code and have a decent world model, we prompted them to <strong>act as a code interpreter</strong> when the dataset was missing.</p>\n<p>Beginning of the prompt:</p>\n<pre><code><span class=\"code-snippet\">You are a stateful Python code interpreter that executes code in a persistent environment. Your role is to execute Python code while maintaining state across multiple code cells, similar to a Jupyter notebook environment.\n[REST OF THE PROMPT]\n</span></code></pre>\n<p><em>Challenge 2:</em> <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/Qwen/Qwen3-Coder-480B-A35B-Instruct\">Qwen3-Coder-480B-A35B</a> model does not support thinking mode - how can we extract code commentary? By default it often outputs just a brief comment followed by several steps of code execution. However, we'd like some reasoning or comments between every cell. <em>Trick:</em> When switching from <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/Qwen/Qwen3-32B\">Qwen3-32B</a> to <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/Qwen/Qwen3-Coder-480B-A35B-Instruct\">Qwen3-Coder-480B-A35B</a> we noticed that often output message content was empty. This turns out to be a previously known quirk of Qwen3-Coder models in which when using tool calling the model would not return an empty assistant response. We enforce some text commentary through tooling by passing 'comment' as a required field in the code execution tool call. This way when non-reasoning model is used for code cell generation it will by default output some description of its actions from 1st POV, emulating the thinking traces structure.</p>\n<p><strong>Note:</strong> the generated final answer in the notebook may vary from the answer specified in the QA pair. This is caused by the fact that the agent model could use data preprocessing methods and steps different from the original Kaggle notebook and the synthetic question would not usually specify them. This discrepancy is normal and lays the foundation for a new exciting research direction of how language models tend to treat data analysis and whether they do it differently from humans. For full transparency we keep both LLM-generated final answer and original answer from the real Kaggle notebook as a signal of model's performance. We encourage the community to try different dataset mixes to see how they can push performance even further.</p>\n<h3>7. Final curation</h3>\n<p>We truncated overly long outputs and filtered out trivial traces to prevent content length issues and keep only high-quality traces.<br />\nWe kept non-trivial, multi-turn traces aligned with DABStep-style tasks.<br />\nThe resulting <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/datasets/jupyter-agent/jupyter-agent-dataset\">Jupyter Agent Dataset</a> became the foundation for SFT on Qwen3-4B models with 51k synthetic notebooks and almost 0.2B tokens.</p>\n<p>With this dataset in hand, the natural next step is to see whether it actually helps our model become a stronger data science agent. Let’s move on to the training pipeline and evaluate the impact!</p>\n<h2>🏃♂️ Training Pipeline</h2>\n<p>With the curated dataset ready, we turned to the key question: <strong>does this data actually help the model get better at solving data analysis tasks?</strong> To find out, we set up a simple fine-tuning pipeline and ran experiments to measure the impact of training on our synthetic notebooks.</p>\n<p>Some training steps turned out to be particularly interesting and gave us useful insights:</p>\n<ul>\n<li>For trace generation, we used LLMs to generate QA pairs, which gave us a <strong>verifiable environment</strong>.</li>\n<li>Finally, we fine-tuned <strong>Qwen3-4B</strong> with <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/docs/trl\">TRL</a>.\n<ul>\n<li>Used <code>assistant_loss_only=True</code> → small performance boost.</li>\n<li>Added neftune noise for full-parameter multi-epoch training → avoids overfitting.</li>\n</ul>\n</li>\n</ul>\n<p><strong>Challenges:</strong></p>\n<ul>\n<li>Prompting models for tool calling is tricky: not all prompts deliver the same performance (<a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://qwen.readthedocs.io/en/latest/framework/function_call.html#vllm\">Qwen docs</a>).</li>\n<li>We had to manually test each one to find what worked best.</li>\n<li>There’s no standardization in response formats for tool calling, making it difficult to switch between models.</li>\n<li>Native Qwen's generation prompt is not adapted to <code>assistant_loss_only=True</code> training mode in TRL which requires to have generation tokens by default. Thus, we adapt the original chat templates by wrapping the assistant response part in the generation tags.</li>\n<li>Training thinking models on short reasoning texts may disrupt model capabilities → full-parameter training works better comparing to PEFT in this case.</li>\n</ul>\n<p>Our complete training implementation, including hyperparameter configurations and template adaptations, is available in our <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/huggingface/jupyter-agent/tree/main/finetuning\">finetuning directory</a> in our repo.</p>\n<h2>📊 Results</h2>\n<p>First, we generated our final dataset using <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/Qwen/Qwen3-Coder-480B-A35B-Instruct\">Qwen3-Coder-480B-A35B</a> which contains high quality code and short reasoning-like traces. Afterwards, we started our training and we have experimented with various configurations like PEFT/adapters vs. full-parameter tuning, learning rate, number of epochs, adding noise and others. We found out, that full-parameter fine-tuning allows the model to learn and replicate the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/Qwen/Qwen3-Coder-480B-A35B-Instruct\">Qwen3-Coder-480B-A35B</a> behavior response quality better with shorter supporting commentary fitting more to the data analysis task without unnecessary long reasoning.</p>\n<p>We have done a small ablation study on the impact of no. training epochs:</p>\n<table>\n<thead>\n<tr>\n<th>Model</th>\n<th>No. of epochs</th>\n<th>DABstep (Easy)</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Qwen-3-4B-Instruct-2507 (Base)</td>\n<td>0</td>\n<td>38.67%</td>\n</tr>\n<tr>\n<td>Qwen-3-4B-Instruct-2507 (Our Scaffolding)</td>\n<td>0</td>\n<td>52.78%</td>\n</tr>\n<tr>\n<td>Qwen-3-4B-Instruct-2507</td>\n<td>2</td>\n<td>63.89%</td>\n</tr>\n<tr>\n<td>Qwen-3-4B-Instruct-2507</td>\n<td>3</td>\n<td>73.61%</td>\n</tr>\n<tr>\n<td>Qwen-3-4B-Instruct-2507</td>\n<td>5</td>\n<td><strong>75%</strong></td>\n</tr>\n<tr>\n<td>Qwen-3-4B-Instruct-2507</td>\n<td>7</td>\n<td>70.83%</td>\n</tr>\n</tbody>\n</table>\n<p>We observe that it is beneficial to have a bit more epochs than usual for SFT with lower learning rate and higher neftune noise (7). Finally, we compare our trained models with implemented scaffolding to define the pure impact of our training dataset. In summary, we can see up to 36%/22% boost on DABStep easy score compared with base/scaffolded model:</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/jupyter-agent-2/training_dabstep_easy.png\" alt=\"DABstep Easy Score\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>We can also see, that the hard score can increase too even though our dataset is focused on easier questions:</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/jupyter-agent-2/training_dabstep_hard.png\" alt=\"DABstep Hard Score\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>From figures above one can notice a noticeable impact of both new scaffolding and tuning on our synthetic notebooks. This makes Qwen-4B (with our pipeline + scaffolding) a state-of-the-art small-model agent on DABStep.</p>\n<p>In practice, the model can now solve a wide range of realistic Kaggle-style data analysis tasks with consistent execution.<br />\nIt’s not yet strong enough for the hardest queries, but we’ve shown that even small models can become powerful agents when paired with the right data and scaffolding.</p>\n<h2>Try Jupyter Agent Yourself</h2>\n<p>These results demonstrate that even small models can become powerful data science agents with the right training approach. Ready to try it yourself? We've made everything openly available so you can experiment with our fine-tuned models and dataset.</p>\n<p>We openly release best-performing checkpoints of tuned Qwen3-4B-Instruct-2507 and Qwen3-4B-Thinking-2507 together with the training dataset, which you can try out and experiment with:</p>\n<ul>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/datasets/jupyter-agent/jupyter-agent-dataset\">Jupyter Agent Dataset</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/jupyter-agent/jupyter-agent-qwen3-4b-instruct\">Jupyter-Agent-Qwen3-4B-Instruct</a></li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/jupyter-agent/jupyter-agent-qwen3-4b-thinking\">Jupyter-Agent-Qwen3-4B-Thinking</a></li>\n</ul>\n<p>You can load Jupyter Agent Dataset in just a couple of lines using the following code:</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-from syntax-python\">from</span></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-meta syntax-import-source syntax-python\"> <span class=\"syntax-meta syntax-import-path syntax-python\"><span class=\"syntax-meta syntax-import-name syntax-python\">datasets</span></span> <span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span></span></span></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"> <span class=\"syntax-meta syntax-generic-name syntax-python\">load_dataset</span></span>\n<span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> To load the train split of a specific subset, such as non-thinking, you can do\n</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">ds</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">load_dataset</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">jupyter-agent/jupyter-agent-dataset<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-variable syntax-parameter syntax-python\">split</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">non-thinking<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> apply chat template\n</span><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">tokenizer</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">apply_chat_template</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">ds</span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-python\">[</span></span><span class=\"syntax-meta syntax-item-access syntax-arguments syntax-python\"><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">0</span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-python\">]</span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-python\">[</span></span><span class=\"syntax-meta syntax-item-access syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">text<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-python\">]</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n</span></span></code></pre>\n<p>You can also use sourced Kaggle datasets directly with E2B code execution using the following code:</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">kagglehub</span></span></span>\n<span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">e2b_code_interpreter</span></span> <span class=\"syntax-keyword syntax-control syntax-import syntax-as syntax-python\">as</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">e2b</span></span></span>\n<span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-from syntax-python\">from</span></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-meta syntax-import-source syntax-python\"> <span class=\"syntax-meta syntax-import-path syntax-python\"><span class=\"syntax-meta syntax-import-name syntax-python\">datasets</span></span> <span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span></span></span></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"> <span class=\"syntax-meta syntax-generic-name syntax-python\">load_dataset</span></span>\n\n<span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> load the Jupyter Agent Dataset\n</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">ds</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">load_dataset</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">jupyter-agent/jupyter-agent-dataset<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-variable syntax-parameter syntax-python\">split</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">thinking<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> get the kaggle dataset name\n</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">dataset_name</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">ds</span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-python\">[</span></span><span class=\"syntax-meta syntax-item-access syntax-arguments syntax-python\"><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">0</span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-python\">]</span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-python\">[</span></span><span class=\"syntax-meta syntax-item-access syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">kaggle_dataset_name<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-python\">]</span></span>\n<span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> load the dataset locally from Kaggle Hub\n</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">path</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">kagglehub</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">dataset_download</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">dataset_name</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-function syntax-builtin syntax-python\">print</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">path</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span> <span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> this is the folder path where the dataset is downloaded\n</span><span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> initialize sandbox\n</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">sandbox_init</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">e2b</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">Sandbox</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-variable syntax-parameter syntax-python\">timeout</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">240</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> write used file to E2B sandbox\n</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">file_name</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">ds</span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-python\">[</span></span><span class=\"syntax-meta syntax-item-access syntax-arguments syntax-python\"><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">0</span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-python\">]</span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-python\">[</span></span><span class=\"syntax-meta syntax-item-access syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">files_used<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-python\">]</span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-python\">[</span></span><span class=\"syntax-meta syntax-item-access syntax-arguments syntax-python\"><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">0</span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-python\">]</span></span>\n<span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">file_name</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">file_name</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">split</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&#39;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\">/<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&#39;</span></span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-python\">[</span></span><span class=\"syntax-meta syntax-item-access syntax-arguments syntax-python\"><span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">-</span><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">1</span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-python\">]</span></span> <span class=\"syntax-meta syntax-statement syntax-if syntax-python\"><span class=\"syntax-keyword syntax-control syntax-flow syntax-conditional syntax-python\">if</span> <span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&#39;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-single syntax-python\">/<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&#39;</span></span></span> <span class=\"syntax-keyword syntax-operator syntax-logical syntax-python\">in</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">file_name</span></span> <span class=\"syntax-keyword syntax-control syntax-flow syntax-else syntax-inline syntax-python\">else</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">file_name</span></span></span>\n<span class=\"syntax-meta syntax-statement syntax-with syntax-python\"><span class=\"syntax-keyword syntax-control syntax-flow syntax-with syntax-python\">with</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-function syntax-builtin syntax-python\">open</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-storage syntax-type syntax-string syntax-python\">f</span><span class=\"syntax-meta syntax-string syntax-interpolated syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-interpolated syntax-python\"><span class=\"syntax-meta syntax-interpolation syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-interpolation syntax-begin syntax-python\">{</span><span class=\"syntax-source syntax-python syntax-embedded\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">path</span></span></span></span><span class=\"syntax-meta syntax-interpolation syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-interpolation syntax-end syntax-python\">}</span></span><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">/</span><span class=\"syntax-meta syntax-interpolation syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-interpolation syntax-begin syntax-python\">{</span><span class=\"syntax-source syntax-python syntax-embedded\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">file_name</span></span></span></span><span class=\"syntax-meta syntax-interpolation syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-interpolation syntax-end syntax-python\">}</span></span><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">rb<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span> <span class=\"syntax-meta syntax-statement syntax-with syntax-python\"><span class=\"syntax-keyword syntax-control syntax-flow syntax-with syntax-as syntax-python\">as</span></span></span><span class=\"syntax-meta syntax-statement syntax-with syntax-python\"> <span class=\"syntax-meta syntax-generic-name syntax-python\">file</span><span class=\"syntax-punctuation syntax-section syntax-block syntax-with syntax-python\">:</span></span>\n    <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">sandbox_init</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">files</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">write</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-storage syntax-type syntax-string syntax-python\">f</span><span class=\"syntax-meta syntax-string syntax-interpolated syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-interpolated syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">/home/user/input/</span><span class=\"syntax-meta syntax-interpolation syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-interpolation syntax-begin syntax-python\">{</span><span class=\"syntax-source syntax-python syntax-embedded\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">file_name</span></span></span></span><span class=\"syntax-meta syntax-interpolation syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-interpolation syntax-end syntax-python\">}</span></span><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">file</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> execute code with E2B\n</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">execution</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">sandbox_init</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">run_code</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">&lt;some code&gt;<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n</span></span></code></pre>\n<p>You use tuned Jupyter Agent Qwen-based models following the Qwen documentation code:</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-from syntax-python\">from</span></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-meta syntax-import-source syntax-python\"> <span class=\"syntax-meta syntax-import-path syntax-python\"><span class=\"syntax-meta syntax-import-name syntax-python\">transformers</span></span> <span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span></span></span></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"> <span class=\"syntax-meta syntax-generic-name syntax-python\">AutoModelForCausalLM</span><span class=\"syntax-punctuation syntax-separator syntax-import-list syntax-python\">,</span> <span class=\"syntax-meta syntax-generic-name syntax-python\">AutoTokenizer</span></span>\n\n<span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">model_name</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">jupyter-agent/jupyter-agent-qwen3-4b-instruct<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span>\n\n<span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> load the tokenizer and the model\n</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">tokenizer</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">AutoTokenizer</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">from_pretrained</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">model_name</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">model</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">AutoModelForCausalLM</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">from_pretrained</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\">\n    <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">model_name</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>\n    <span class=\"syntax-variable syntax-parameter syntax-python\">torch_dtype</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">auto<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>\n    <span class=\"syntax-variable syntax-parameter syntax-python\">device_map</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">auto<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span>\n</span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n\n<span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> prepare the model input\n</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">prompt</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">Give me a short introduction to large language model.<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span>\n<span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">messages</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-structure syntax-list syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-list syntax-begin syntax-python\">[</span>\n    <span class=\"syntax-meta syntax-structure syntax-dictionary-or-set syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-dictionary-or-set syntax-begin syntax-python\">{</span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">role<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-python\">:</span> <span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">user<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-dictionary-or-set syntax-python\">,</span> <span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">content<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-python\">:</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">prompt</span></span><span class=\"syntax-punctuation syntax-section syntax-dictionary-or-set syntax-end syntax-python\">}</span></span>\n<span class=\"syntax-punctuation syntax-section syntax-list syntax-end syntax-python\">]</span></span>\n<span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">text</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">tokenizer</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">apply_chat_template</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\">\n    <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">messages</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>\n    <span class=\"syntax-variable syntax-parameter syntax-python\">tokenize</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-constant syntax-language syntax-python\">False</span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>\n    <span class=\"syntax-variable syntax-parameter syntax-python\">add_generation_prompt</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-constant syntax-language syntax-python\">True</span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>\n</span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">model_inputs</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">tokenizer</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-structure syntax-list syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-list syntax-begin syntax-python\">[</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">text</span></span><span class=\"syntax-punctuation syntax-section syntax-list syntax-end syntax-python\">]</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-variable syntax-parameter syntax-python\">return_tensors</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">pt<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">to</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">model</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">device</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n\n<span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> conduct text completion\n</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">generated_ids</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">model</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">generate</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\">\n    <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">*</span><span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">*</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">model_inputs</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span>\n    <span class=\"syntax-variable syntax-parameter syntax-python\">max_new_tokens</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">16384</span>\n</span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">output_ids</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">generated_ids</span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-python\">[</span></span><span class=\"syntax-meta syntax-item-access syntax-arguments syntax-python\"><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">0</span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-python\">]</span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-python\">[</span></span><span class=\"syntax-meta syntax-item-access syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-function syntax-builtin syntax-python\">len</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">model_inputs</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span><span class=\"syntax-meta syntax-generic-name syntax-python\">input_ids</span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-python\">[</span></span><span class=\"syntax-meta syntax-item-access syntax-arguments syntax-python\"><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">0</span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-python\">]</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span><span class=\"syntax-punctuation syntax-separator syntax-slice syntax-python\">:</span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-python\">]</span></span><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">tolist</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span> \n\n<span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">content</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">tokenizer</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">decode</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">output_ids</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-variable syntax-parameter syntax-python\">skip_special_tokens</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-constant syntax-language syntax-python\">True</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n\n<span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-function syntax-builtin syntax-python\">print</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">content:<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">content</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n</span></span></code></pre>\n<p>For Thinking model you can decode both thinking response and content using the next code:</p>\n<pre><code class=\"language-python\"><span class=\"code-snippet\" data-language=\"Python\"><span class=\"syntax-source syntax-python\"><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-from syntax-python\">from</span></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-meta syntax-import-source syntax-python\"> <span class=\"syntax-meta syntax-import-path syntax-python\"><span class=\"syntax-meta syntax-import-name syntax-python\">transformers</span></span> <span class=\"syntax-meta syntax-statement syntax-import syntax-python\"><span class=\"syntax-keyword syntax-control syntax-import syntax-python\">import</span></span></span></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"></span><span class=\"syntax-meta syntax-statement syntax-import syntax-python\"> <span class=\"syntax-meta syntax-generic-name syntax-python\">AutoModelForCausalLM</span><span class=\"syntax-punctuation syntax-separator syntax-import-list syntax-python\">,</span> <span class=\"syntax-meta syntax-generic-name syntax-python\">AutoTokenizer</span></span>\n\n<span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">model_name</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\">jupyter-agent/jupyter-agent-qwen3-4b-thinking<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span>\n\n<span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> ...use same processing code from above...\n</span><span class=\"syntax-meta syntax-statement syntax-try syntax-python\"><span class=\"syntax-keyword syntax-control syntax-flow syntax-try syntax-python\">try</span><span class=\"syntax-punctuation syntax-section syntax-block syntax-try syntax-python\">:</span></span>\n    <span class=\"syntax-comment syntax-line syntax-number-sign syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-python\">#</span> index finding 151668 (&lt;/think&gt;)\n</span>    <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">index</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-support syntax-function syntax-builtin syntax-python\">len</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">output_ids</span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span> <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">-</span> <span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">output_ids</span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-python\">[</span></span><span class=\"syntax-meta syntax-item-access syntax-arguments syntax-python\"><span class=\"syntax-punctuation syntax-separator syntax-slice syntax-python\">:</span><span class=\"syntax-punctuation syntax-separator syntax-slice syntax-python\">:</span><span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-python\">-</span><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">1</span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-python\">]</span></span><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">index</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">151668</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-meta syntax-statement syntax-except syntax-python\"><span class=\"syntax-keyword syntax-control syntax-flow syntax-except syntax-python\">except</span> <span class=\"syntax-support syntax-type syntax-exception syntax-python\">ValueError</span><span class=\"syntax-punctuation syntax-section syntax-block syntax-except syntax-python\">:</span></span>\n    <span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">index</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-python\">0</span>\n\n<span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">thinking_content</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">tokenizer</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">decode</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">output_ids</span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-python\">[</span></span><span class=\"syntax-meta syntax-item-access syntax-arguments syntax-python\"><span class=\"syntax-punctuation syntax-separator syntax-slice syntax-python\">:</span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">index</span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-python\">]</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-variable syntax-parameter syntax-python\">skip_special_tokens</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-constant syntax-language syntax-python\">True</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">strip</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-constant syntax-character syntax-escape syntax-python\">\\n</span><span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n<span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">content</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span> <span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">tokenizer</span><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">decode</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">output_ids</span></span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-python\">[</span></span><span class=\"syntax-meta syntax-item-access syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-meta syntax-generic-name syntax-python\">index</span></span><span class=\"syntax-punctuation syntax-separator syntax-slice syntax-python\">:</span></span><span class=\"syntax-meta syntax-item-access syntax-python\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-python\">]</span></span><span class=\"syntax-punctuation syntax-separator syntax-arguments syntax-python\">,</span> <span class=\"syntax-variable syntax-parameter syntax-python\">skip_special_tokens</span><span class=\"syntax-keyword syntax-operator syntax-assignment syntax-python\">=</span><span class=\"syntax-constant syntax-language syntax-python\">True</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span><span class=\"syntax-meta syntax-function-call syntax-python\"><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-punctuation syntax-accessor syntax-dot syntax-python\">.</span></span><span class=\"syntax-meta syntax-qualified-name syntax-python\"><span class=\"syntax-variable syntax-function syntax-python\">strip</span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-begin syntax-python\">(</span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-python\"><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-python\">&quot;</span></span></span><span class=\"syntax-meta syntax-string syntax-python\"><span class=\"syntax-string syntax-quoted syntax-double syntax-python\"><span class=\"syntax-constant syntax-character syntax-escape syntax-python\">\\n</span><span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-python\">&quot;</span></span></span></span><span class=\"syntax-punctuation syntax-section syntax-arguments syntax-end syntax-python\">)</span></span>\n</span></span></code></pre>\n<h2>🔮 Next Steps</h2>\n<ul>\n<li><em>Harder tasks:</em> Generate more challenging, multi-step questions that better reflect real-world analysis.</li>\n<li><em>Scaling up:</em> Train on larger volumes of curated traces to push beyond the current 3.4% performance on the hard split.</li>\n<li><em>Distillation:</em> Investigate knowledge distillation, which has shown strong results for improving small models.</li>\n<li><em>Reinforcement Learning (RL):</em> Build an RL environment, which has been shown to achieve state-of-the-art performance on agentic tasks. Since our QA setup already provides a verifiable environment, we could leverage it directly for RL training.</li>\n</ul>\n<p>Maybe this will lead to… <strong>Jupyter-Agent 3.</strong> 😉</p>\n<p>We hope that our findings will inspire others to continue progress in developing more powerful notebook coding agents and we're excited to see what the community builds next. Dive into our <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://huggingface.co/datasets/jupyter-agent/jupyter-agent-dataset\">jupyter-agent dataset</a> on the 🤗 Hub and explore the codebase at <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/huggingface/jupyter-agent\">https://github.com/huggingface/jupyter-agent</a> to start your own experiments on agents for jupyter notebooks.</p>\n",
  "content_markdown": "The past year has been all about giving LLMs more tools and autonomy to solve more complex and open ended tasks. The goal of the **Jupyter Agent** is to give the model the ultimate tool: code execution.\n\nA natural way to display multi-step code execution together with reasoning is within a Jupyter Notebook, which consists of code and markdown cells. So we built Jupyter Agent to act as an agent that can execute code directly inside a Jupyter notebook and use this environment to solve data analysis and data science tasks. Think of it like *Cursor*, but living natively inside your data science workflow.\\\nWe built a [demo](https://huggingface.co/spaces/lvwerra/jupyter-agent-2) of this vision with **Qwen-3 Coder**, currently one of the strongest coding models. This is a follow-up to our earlier work on [jupyter-agent (v1)](https://huggingface.co/spaces/lvwerra/jupyter-agent).\n\nWhile large models are starting to show useful behavior, the key question is how we can continue improving them. To this end, we focus on strengthening smaller models to perform well on agentic data science tasks as they currently struggle to compete with the large models.\n\nThe goal of this project is to build a pipeline to first generate high-quality training data, then fine-tune an existing small model, and finally evaluate whether the model's performance improves on relevant benchmarks.\n\nLet’s begin with the last step: selecting a strong benchmark for evaluating models on data science tasks.\n\n## 🏁 Primer: the DABStep Benchmark\n\nIn order to understand if we are making progress towards better data science agents we need a benchmark to measure such capabilities. Last year, in partnership with [Adyen](https://huggingface.co/adyen), we introduced the **[DABStep benchmark](https://huggingface.co/blog/dabstep)**: a way to evaluate data science agents on realistic tasks. The setup is simple: provide the LLM with datasets and ask it to answer non-trivial data questions.\n\nExample tasks:\n\n| Question                                                                                                                                                                                               | Answer      |\n| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------- |\n| Which card scheme had the highest average fraud rate in 2023?                                                                                                                                          | SwiftCharge |\n| For the year 2023, focusing on the merchant *Crossfit Hanna*, if we incentivize users to switch to a different Authorization Characteristics Indicator, which option would be the most cost-effective? | E:346.49    |\n\nThis benchmark remains challenging for today’s LLMs — e.g. the best out-of-the-box model is Claude 4 Sonnet which reaches not even 20% accuracy on the hard tasks.\\\nYou can explore the live leaderboard [here](https://huggingface.co/spaces/adyen/DABstep).\n\n## 🎯 First Baseline\n\nNow that we identified a good benchmark we can try to climb it! We set out to build a dataset for fine-tuning such that even **a small data agent model** could perform well on DABStep.\n\nOur first choice was [**Qwen3-4B-Thinking-2507**](https://huggingface.co/Qwen/Qwen3-4B-Thinking-2507): extremely small (fast to iterate with, easy to run), yet strong enough to act in agentic scenarios.\n\nBaseline results:\n\n- *Easy tasks:* **44.4%**\n- *Hard tasks:* **2.1%**\n\nNot great — but a promising starting point, since it left a lot of room for improvement. Let's see how we can improve it!\n\n## 🔧 Primer on Scaffolding\n\nA core aspect of agents that sets it apart from a pure chat model is the scaffolding built around the model to steer its behaviour. The evaluation script in DABStep for example uses [smolagents](https://github.com/huggingface/smolagents) to execute code. Smolagents comes with predefined behaviors, prompting structures, and expected formats.\n\nWe also studied the [**Qwen-Agent**](https://github.com/QwenLM/Qwen-Agent) codebase, where the authors tailoring scaffolding to the model. This makes sense: Claude Code, for example, works shockingly well with Claude Sonnet because their scaffolding is aligned.\n\nSo, we restructured our scaffolding:\n\n- Stripped it down to ~200 lines of code.\n- No external dependencies.\n- Inspired by the spirit of [**tiny-agents**](https://huggingface.co/blog/tiny-agents).\n\n👉 Check it out here: [utils.py](https://huggingface.co/spaces/lvwerra/jupyter-agent-2/blob/main/utils.py).\n\n**Results:** accuracy jumped from **44.4% → 59.7% (easy split)**. 🚀\n\n**Our loop:**\n\n- While loop with two tools: *code execution* to run the code and *final\\_answer* to return the final answer.\n- We differ from Qwen-Agent by explicitly adding a **final\\_answer** tool — which in our testing has improved performance.\n- Compared to smolagents, we simplified the scaffolding by removing a lot of prompts and tools. Smolagents also hardcodes a lot of assumptions into the model by using the ReACT framework.\n\n## 🏃♂️ Training Pipeline\n\nWith simplified scaffolding in place, we focused on fine-tuning Qwen3-4B for **data science agentic tasks**.\n\n## ⚙️ Dataset Pipeline\n\nThe recipe to improve a model on a certain task or behaviour is to train it on data that reflects the tasks as closely as possible. A natural starting point is to look at real Jupyter Notebooks and find notebooks that align closely with the task that we plan to tackle, namely data analysis.\n\nKaggle notebooks offer a wealth of high quality data analysis notebooks and are made available by Kaggle:\n\n**Datasets:**\n\n- **Kaggle Notebooks dataset**: ~2TB of notebooks.\n- **Kaggle Datasets**: 5TB of kaggle datasets that we manually downloaded and linked to the notebooks.\n- Rich metadata for each notebook (authors, datasets used, etc.).\n\nNow that we have good results with a base model it's time to build a dataset that will help us improve it even further. We designed a multi-stage pipeline using [Datatrove](https://github.com/huggingface/datatrove) to clean and prepare Kaggle notebooks at scale.\n\n![Jupyter Agent Dataset Pipeline](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/jupyter-agent-2/jupyter-agent-dataset-pipeline.png)\n\nHere’s how each step worked:\n\n### 1. Large-scale deduplication\n\nWe started with ~2TB of Kaggle notebooks and reduced it to ~250GB reusing our work from the BigCode project. As part of the StarCoder2 training data processing the notebooks (without output cells) were already deduplicated. Most Kaggle notebooks are small variations or near-identical copies, so this step was essential.\\\n*Key insight:* ~90% of raw notebooks are duplicates, which would have skewed training if left unfiltered.\n\n### 2. Downloading linked datasets\n\nMost Kaggle notebooks reference external datasets via Kaggle metadata. To make sure the code inside notebooks could actually run, we built a pipeline that automatically fetched these linked datasets. This step was crucial, since many notebooks would otherwise be incomplete or non-executable.\n\nUsing the **kagglehub** package, we downloaded thousands of datasets — about **5TB** in total. To keep things manageable and relevant:\n\n- We filtered out datasets containing model checkpoints, large multimodal corpora, or LLM-related files.\n- We also excluded very large datasets (10GB+) that couldn’t fit into the virtual [E2B sandboxes](https://e2b.dev/) we used for execution.\n\nBy the end, we had a rich collection of executable notebooks paired with their datasets, providing the foundation for training agents in realistic, runnable environments.\n\n### 3. Edu scoring\n\nWe scored notebooks based on educational quality using [Qwen3-32B](https://huggingface.co/Qwen/Qwen3-32B). We saw that using the whole notebook was not optimal, as many contained trivial or broken code. Our educational scoring approach is detailed in edu\\_scoring.py.\n\n**TL;DR:** We assigned each notebook a score from 1–5 based on clarity, completeness, and educational value, and kept only those above a chosen threshold. This filtering removed about 70% of the notebooks.\n\nThis is similar to the insight from the BeyondWeb paper, which showed that using high-quality data is better for synthetic data generation — a step we relied on for QA (Question-Answer) generation. This helped the model learn from “high quality” notebooks instead of noisy ones.\n\n### 4. Filtering irrelevant notebooks\n\nWe excluded notebooks about training LLMs or unrelated to data analysis. We also removed notebooks that didn’t actually use datasets through an automated LLM-based filtering process using Qwen3-32B. The implementation of filtering can be found in [`extract_packages_and_files.py`](https://github.com/huggingface/jupyter-agent/blob/main/data/pipelines/extract_packages_and_files.py).\n\n**TL;DR:** We prompted Qwen3-32B to identify and remove notebooks that either (1) had nothing to do with data analysis, or (2) didn’t actually use datasets. This step removed about 20% of the notebooks.\n\nThis ensured we trained only on relevant data science tasks.\n\n### 5. QA generation\n\nUsing the cleaned notebooks, we generated question–answer pairs using [Qwen3-32B](https://huggingface.co/Qwen/Qwen3-32B). The questions and answer are grounded in the real notebook traces so the QA pairs are based on real code execution results. **Prompt design:** we asked the LLM to produce natural questions that could realistically be asked of the dataset, then validated whether the notebook provided a correct answer.\n\n*Challenge:* We had to try many prompts to get higher-difficulty questions because LLMs tended to generate trivial ones like \"what is the size of the dataset\".\\\n*Insight:* We broke this into two steps because LLMs tended to hallucinate answers:\n\n1. Generate the question and answer.\n2. Ask another LLM (with access to the notebook) to check whether the answer was correct.\n\nThe complete prompting strategy and implementation is available in [`generate_qa.py`](https://github.com/huggingface/jupyter-agent/blob/main/data/pipelines/generate_qa.py).\n\n### 6. Trace generation\n\nFinally we want to generate clean code execution traces since even the original notebooks after processing are often open ended and verbose with lots of irrelevant parts. However, we want our Jupyter Agent to get to the result efficiently. To generate cleaner notebook traces for training we generated traces synthetically based on the original notebooks.\\\nWe have prompted [Qwen-3-Coder-480B](https://huggingface.co/Qwen/Qwen3-Coder-480B-A35B-Instruct) model to generate a jupyter notebook code to answer the question from the previously generated synthetic QA pair. Traces captured step-by-step code execution, including intermediate outputs, which are crucial for agent training.\n\nWe used [E2B](https://e2b.dev/) for our agent to solve the synthetic QA pairs, which required fetching Kaggle datasets so the code could actually run via E2B.\n\n*Challenge 1:* Many datasets were unavailable.\\\n*Trick:* Since LLMs are strong at code and have a decent world model, we prompted them to **act as a code interpreter** when the dataset was missing.\n\nBeginning of the prompt:\n\n```\nYou are a stateful Python code interpreter that executes code in a persistent environment. Your role is to execute Python code while maintaining state across multiple code cells, similar to a Jupyter notebook environment.\n[REST OF THE PROMPT]\n```\n\n*Challenge 2:* [Qwen3-Coder-480B-A35B](https://huggingface.co/Qwen/Qwen3-Coder-480B-A35B-Instruct) model does not support thinking mode - how can we extract code commentary? By default it often outputs just a brief comment followed by several steps of code execution. However, we'd like some reasoning or comments between every cell. *Trick:* When switching from [Qwen3-32B](https://huggingface.co/Qwen/Qwen3-32B) to [Qwen3-Coder-480B-A35B](https://huggingface.co/Qwen/Qwen3-Coder-480B-A35B-Instruct) we noticed that often output message content was empty. This turns out to be a previously known quirk of Qwen3-Coder models in which when using tool calling the model would not return an empty assistant response. We enforce some text commentary through tooling by passing 'comment' as a required field in the code execution tool call. This way when non-reasoning model is used for code cell generation it will by default output some description of its actions from 1st POV, emulating the thinking traces structure.\n\n**Note:** the generated final answer in the notebook may vary from the answer specified in the QA pair. This is caused by the fact that the agent model could use data preprocessing methods and steps different from the original Kaggle notebook and the synthetic question would not usually specify them. This discrepancy is normal and lays the foundation for a new exciting research direction of how language models tend to treat data analysis and whether they do it differently from humans. For full transparency we keep both LLM-generated final answer and original answer from the real Kaggle notebook as a signal of model's performance. We encourage the community to try different dataset mixes to see how they can push performance even further.\n\n### 7. Final curation\n\nWe truncated overly long outputs and filtered out trivial traces to prevent content length issues and keep only high-quality traces.\\\nWe kept non-trivial, multi-turn traces aligned with DABStep-style tasks.\\\nThe resulting [Jupyter Agent Dataset](https://huggingface.co/datasets/jupyter-agent/jupyter-agent-dataset) became the foundation for SFT on Qwen3-4B models with 51k synthetic notebooks and almost 0.2B tokens.\n\nWith this dataset in hand, the natural next step is to see whether it actually helps our model become a stronger data science agent. Let’s move on to the training pipeline and evaluate the impact!\n\n## 🏃♂️ Training Pipeline\n\nWith the curated dataset ready, we turned to the key question: **does this data actually help the model get better at solving data analysis tasks?** To find out, we set up a simple fine-tuning pipeline and ran experiments to measure the impact of training on our synthetic notebooks.\n\nSome training steps turned out to be particularly interesting and gave us useful insights:\n\n- For trace generation, we used LLMs to generate QA pairs, which gave us a **verifiable environment**.\n- Finally, we fine-tuned **Qwen3-4B** with [TRL](https://huggingface.co/docs/trl).\n  - Used `assistant_loss_only=True` → small performance boost.\n  - Added neftune noise for full-parameter multi-epoch training → avoids overfitting.\n\n**Challenges:**\n\n- Prompting models for tool calling is tricky: not all prompts deliver the same performance ([Qwen docs](https://qwen.readthedocs.io/en/latest/framework/function_call.html#vllm)).\n- We had to manually test each one to find what worked best.\n- There’s no standardization in response formats for tool calling, making it difficult to switch between models.\n- Native Qwen's generation prompt is not adapted to `assistant_loss_only=True` training mode in TRL which requires to have generation tokens by default. Thus, we adapt the original chat templates by wrapping the assistant response part in the generation tags.\n- Training thinking models on short reasoning texts may disrupt model capabilities → full-parameter training works better comparing to PEFT in this case.\n\nOur complete training implementation, including hyperparameter configurations and template adaptations, is available in our [finetuning directory](https://github.com/huggingface/jupyter-agent/tree/main/finetuning) in our repo.\n\n## 📊 Results\n\nFirst, we generated our final dataset using [Qwen3-Coder-480B-A35B](https://huggingface.co/Qwen/Qwen3-Coder-480B-A35B-Instruct) which contains high quality code and short reasoning-like traces. Afterwards, we started our training and we have experimented with various configurations like PEFT/adapters vs. full-parameter tuning, learning rate, number of epochs, adding noise and others. We found out, that full-parameter fine-tuning allows the model to learn and replicate the [Qwen3-Coder-480B-A35B](https://huggingface.co/Qwen/Qwen3-Coder-480B-A35B-Instruct) behavior response quality better with shorter supporting commentary fitting more to the data analysis task without unnecessary long reasoning.\n\nWe have done a small ablation study on the impact of no. training epochs:\n\n| Model                                     | No. of epochs | DABstep (Easy) |\n| ----------------------------------------- | ------------- | -------------- |\n| Qwen-3-4B-Instruct-2507 (Base)            | 0             | 38.67%         |\n| Qwen-3-4B-Instruct-2507 (Our Scaffolding) | 0             | 52.78%         |\n| Qwen-3-4B-Instruct-2507                   | 2             | 63.89%         |\n| Qwen-3-4B-Instruct-2507                   | 3             | 73.61%         |\n| Qwen-3-4B-Instruct-2507                   | 5             | **75%**        |\n| Qwen-3-4B-Instruct-2507                   | 7             | 70.83%         |\n\nWe observe that it is beneficial to have a bit more epochs than usual for SFT with lower learning rate and higher neftune noise (7). Finally, we compare our trained models with implemented scaffolding to define the pure impact of our training dataset. In summary, we can see up to 36%/22% boost on DABStep easy score compared with base/scaffolded model:\n\n![DABstep Easy Score](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/jupyter-agent-2/training_dabstep_easy.png)\n\nWe can also see, that the hard score can increase too even though our dataset is focused on easier questions:\n\n![DABstep Hard Score](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/jupyter-agent-2/training_dabstep_hard.png)\n\nFrom figures above one can notice a noticeable impact of both new scaffolding and tuning on our synthetic notebooks. This makes Qwen-4B (with our pipeline + scaffolding) a state-of-the-art small-model agent on DABStep.\n\nIn practice, the model can now solve a wide range of realistic Kaggle-style data analysis tasks with consistent execution.\\\nIt’s not yet strong enough for the hardest queries, but we’ve shown that even small models can become powerful agents when paired with the right data and scaffolding.\n\n## Try Jupyter Agent Yourself\n\nThese results demonstrate that even small models can become powerful data science agents with the right training approach. Ready to try it yourself? We've made everything openly available so you can experiment with our fine-tuned models and dataset.\n\nWe openly release best-performing checkpoints of tuned Qwen3-4B-Instruct-2507 and Qwen3-4B-Thinking-2507 together with the training dataset, which you can try out and experiment with:\n\n- [Jupyter Agent Dataset](https://huggingface.co/datasets/jupyter-agent/jupyter-agent-dataset)\n- [Jupyter-Agent-Qwen3-4B-Instruct](https://huggingface.co/jupyter-agent/jupyter-agent-qwen3-4b-instruct)\n- [Jupyter-Agent-Qwen3-4B-Thinking](https://huggingface.co/jupyter-agent/jupyter-agent-qwen3-4b-thinking)\n\nYou can load Jupyter Agent Dataset in just a couple of lines using the following code:\n\n```python\nfrom datasets import load_dataset\n# To load the train split of a specific subset, such as non-thinking, you can do\nds = load_dataset(\"jupyter-agent/jupyter-agent-dataset\", split=\"non-thinking\")\n# apply chat template\ntokenizer.apply_chat_template(ds[0][\"text\"])\n```\n\nYou can also use sourced Kaggle datasets directly with E2B code execution using the following code:\n\n```python\nimport kagglehub\nimport e2b_code_interpreter as e2b\nfrom datasets import load_dataset\n\n# load the Jupyter Agent Dataset\nds = load_dataset(\"jupyter-agent/jupyter-agent-dataset\", split=\"thinking\")\n# get the kaggle dataset name\ndataset_name = ds[0][\"kaggle_dataset_name\"]\n# load the dataset locally from Kaggle Hub\npath = kagglehub.dataset_download(dataset_name)\nprint(path) # this is the folder path where the dataset is downloaded\n# initialize sandbox\nsandbox_init = e2b.Sandbox(timeout=240)\n# write used file to E2B sandbox\nfile_name = ds[0][\"files_used\"][0]\nfile_name = file_name.split('/')[-1] if '/' in file_name else file_name\nwith open(f\"{path}/{file_name}\", \"rb\") as file:\n    sandbox_init.files.write(f\"/home/user/input/{file_name}\", file)\n# execute code with E2B\nexecution = sandbox_init.run_code(\"<some code>\")\n```\n\nYou use tuned Jupyter Agent Qwen-based models following the Qwen documentation code:\n\n```python\nfrom transformers import AutoModelForCausalLM, AutoTokenizer\n\nmodel_name = \"jupyter-agent/jupyter-agent-qwen3-4b-instruct\"\n\n# load the tokenizer and the model\ntokenizer = AutoTokenizer.from_pretrained(model_name)\nmodel = AutoModelForCausalLM.from_pretrained(\n    model_name,\n    torch_dtype=\"auto\",\n    device_map=\"auto\"\n)\n\n# prepare the model input\nprompt = \"Give me a short introduction to large language model.\"\nmessages = [\n    {\"role\": \"user\", \"content\": prompt}\n]\ntext = tokenizer.apply_chat_template(\n    messages,\n    tokenize=False,\n    add_generation_prompt=True,\n)\nmodel_inputs = tokenizer([text], return_tensors=\"pt\").to(model.device)\n\n# conduct text completion\ngenerated_ids = model.generate(\n    **model_inputs,\n    max_new_tokens=16384\n)\noutput_ids = generated_ids[0][len(model_inputs.input_ids[0]):].tolist() \n\ncontent = tokenizer.decode(output_ids, skip_special_tokens=True)\n\nprint(\"content:\", content)\n```\n\nFor Thinking model you can decode both thinking response and content using the next code:\n\n```python\nfrom transformers import AutoModelForCausalLM, AutoTokenizer\n\nmodel_name = \"jupyter-agent/jupyter-agent-qwen3-4b-thinking\"\n\n# ...use same processing code from above...\ntry:\n    # index finding 151668 (</think>)\n    index = len(output_ids) - output_ids[::-1].index(151668)\nexcept ValueError:\n    index = 0\n\nthinking_content = tokenizer.decode(output_ids[:index], skip_special_tokens=True).strip(\"\\n\")\ncontent = tokenizer.decode(output_ids[index:], skip_special_tokens=True).strip(\"\\n\")\n```\n\n## 🔮 Next Steps\n\n- *Harder tasks:* Generate more challenging, multi-step questions that better reflect real-world analysis.\n- *Scaling up:* Train on larger volumes of curated traces to push beyond the current 3.4% performance on the hard split.\n- *Distillation:* Investigate knowledge distillation, which has shown strong results for improving small models.\n- *Reinforcement Learning (RL):* Build an RL environment, which has been shown to achieve state-of-the-art performance on agentic tasks. Since our QA setup already provides a verifiable environment, we could leverage it directly for RL training.\n\nMaybe this will lead to… **Jupyter-Agent 3.** 😉\n\nWe hope that our findings will inspire others to continue progress in developing more powerful notebook coding agents and we're excited to see what the community builds next. Dive into our [jupyter-agent dataset](https://huggingface.co/datasets/jupyter-agent/jupyter-agent-dataset) on the 🤗 Hub and explore the codebase at [https://github.com/huggingface/jupyter-agent](https://github.com/huggingface/jupyter-agent) to start your own experiments on agents for jupyter notebooks.\n",
  "dateCreated": "2026-10-04T12:50:30.804479567+00:00",
  "date_created": "2025-09-10T00:00:00+00:00",
  "date_modified": "2025-09-10T00:00:00+00:00",
  "date_published": "2025-09-10T00:00:00+00:00",
  "description": "The past year has been all about giving LLMs more tools and autonomy to solve more complex and open ended tasks. The goal of the Jupyter Agent is to give the model the ultimate tool: code execution. A natural way to display multi-step code…",
  "external_url": "https://huggingface.co/blog/jupyter-agent-2",
  "git": {
    "commit": "ebb0941c5c06a2ab2377342d607535262a3e969e",
    "path": "items/huggingface-co/2025/09/2025-09-10-jupyter-agents-training-llms-to-reason-with-notebooks.md",
    "permalink": "https://github.com/aymericbeaumet/aggr-instance/blob/ebb0941c5c06a2ab2377342d607535262a3e969e/items/huggingface-co/2025/09/2025-09-10-jupyter-agents-training-llms-to-reason-with-notebooks.md"
  },
  "id": "urn:aggr:item:521c7d772fa94915e34cbfdcc3cb7e21657c93c2",
  "isBasedOn": {
    "@id": "https://huggingface.co/blog/jupyter-agent-2"
  },
  "mainEntity": {
    "@id": "https://huggingface.co/blog/jupyter-agent-2",
    "@type": "CreativeWork",
    "archivedAt": {
      "@id": "https://aggr.aymericbeaumet.com/items/huggingface-co/2025-09-10-jupyter-agents-training-llms-to-reason-with-notebooks/#webpage"
    },
    "dateModified": "2025-09-10T00:00:00+00:00",
    "datePublished": "2025-09-10T00:00:00+00:00",
    "headline": "Jupyter Agents: training LLMs to reason with notebooks",
    "timeRequired": "PT14M",
    "url": "https://huggingface.co/blog/jupyter-agent-2",
    "wordCount": 3049
  },
  "name": "Archived snapshot: Jupyter Agents: training LLMs to reason with notebooks",
  "preview": null,
  "reading_minutes": 14,
  "replicated_at": null,
  "source": "huggingface-co",
  "source_name": "Hugging Face - Blog",
  "summary": null,
  "tags": [],
  "temporalCoverage": "2026-10-04T12:50:30.804479567+00:00",
  "title": "Jupyter Agents: training LLMs to reason with notebooks",
  "url": "https://aggr.aymericbeaumet.com/items/huggingface-co/2025-09-10-jupyter-agents-training-llms-to-reason-with-notebooks/",
  "word_count": 3049
}