<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Francesco Gabellini</title><description>A minimal hugo theme focus on content</description><link>http://gabelfra1.github.io/gabelfra.github.io/</link><language>en</language><copyright>Copyright 2026, Calvin Tran</copyright><lastBuildDate>Mon, 21 Sep 2026 00:00:00 +0000</lastBuildDate><generator>Hugo - gohugo.io</generator><docs>http://cyber.harvard.edu/rss/rss.html</docs><atom:link href="http://gabelfra1.github.io/gabelfra.github.io//atom.xml" rel="self" type="application/atom+xml"/><item><title>Is Jev calibrated?</title><link>http://gabelfra1.github.io/gabelfra.github.io/posts/jev/</link><description>&lt;p>The same experiment as &lt;code>confidence.ipynb&lt;/code> (OpenAI &lt;code>gpt-4o-mini&lt;/code> + logprobs), redone with TypeSafe&amp;rsquo;s &lt;strong>Jev&lt;/strong>:
20 Newsgroups posts, classified as &lt;code>mac&lt;/code> / &lt;code>motor&lt;/code> / &lt;code>baseball&lt;/code>, then checked with reliability curves and ECE.&lt;/p>
&lt;p>What is the same: the data (test split, &lt;code>random_state=42&lt;/code>, first 500 posts, truncated to 500 characters), the F1 score, the per-class reliability curves, and ECE.&lt;/p>
&lt;p>What is different:&lt;/p>
&lt;ul>
&lt;li>Jev&amp;rsquo;s &lt;strong>Choice&lt;/strong> answer returns a probability for every option, so there is no logprob-token heuristic to map tokens back to classes.&lt;/li>
&lt;li>The API key is read from &lt;code>TYPESAFE_API_KEY&lt;/code> (or prompted for), never hardcoded.&lt;/li>
&lt;li>The ECE function is fixed: the original silently dropped every prediction with probability exactly &lt;code>1.0&lt;/code> (the most overconfident ones).&lt;/li>
&lt;li>Recalibration uses &lt;strong>Platt scaling&lt;/strong>, scored out-of-fold, and the last section compares Jev (raw and recalibrated) with the OpenAI run.&lt;/li>
&lt;/ul>
&lt;p>All analysis uses Jev&amp;rsquo;s &lt;code>probabilities&lt;/code>. Its &lt;code>confidence&lt;/code> field is a rescaled peak of that distribution, not a probability of being correct, so it is saved but not used for calibration.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">os&lt;/span>&lt;span style="color:#f92672">,&lt;/span> &lt;span style="color:#111">sys&lt;/span>&lt;span style="color:#f92672">,&lt;/span> &lt;span style="color:#111">subprocess&lt;/span>&lt;span style="color:#f92672">,&lt;/span> &lt;span style="color:#111">getpass&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">try&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">typesafe_sdk&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">except&lt;/span> &lt;span style="color:#75af00">ModuleNotFoundError&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">subprocess&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">check_call&lt;/span>&lt;span style="color:#111">([&lt;/span>&lt;span style="color:#111">sys&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">executable&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;-m&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;pip&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;install&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;-q&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;typesafe-sdk&amp;#34;&lt;/span>&lt;span style="color:#111">])&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># pip may upgrade packages this kernel already imported (e.g. typing_extensions), so a restart is required&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">raise&lt;/span> &lt;span style="color:#75af00">RuntimeError&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;typesafe-sdk was just installed. Restart the kernel (Kernel &amp;gt; Restart) and run all cells again.&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">if&lt;/span> &lt;span style="color:#f92672">not&lt;/span> &lt;span style="color:#111">os&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">environ&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">get&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;TYPESAFE_API_KEY&amp;#34;&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">os&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">environ&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;TYPESAFE_API_KEY&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">getpass&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">getpass&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;TypeSafe API key (create one at https://console.typesafe.ai/): &amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">numpy&lt;/span> &lt;span style="color:#00a8c8">as&lt;/span> &lt;span style="color:#111">np&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">pandas&lt;/span> &lt;span style="color:#00a8c8">as&lt;/span> &lt;span style="color:#111">pd&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">matplotlib.pyplot&lt;/span> &lt;span style="color:#00a8c8">as&lt;/span> &lt;span style="color:#111">plt&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> &lt;span style="color:#111">concurrent.futures&lt;/span> &lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">ThreadPoolExecutor&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">as_completed&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> &lt;span style="color:#111">sklearn&lt;/span> &lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">metrics&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> &lt;span style="color:#111">sklearn.calibration&lt;/span> &lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">calibration_curve&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> &lt;span style="color:#111">sklearn.datasets&lt;/span> &lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">fetch_20newsgroups&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> &lt;span style="color:#111">sklearn.linear_model&lt;/span> &lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">LogisticRegression&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> &lt;span style="color:#111">sklearn.model_selection&lt;/span> &lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">StratifiedKFold&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> &lt;span style="color:#111">typesafe_sdk&lt;/span> &lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">Choice&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">TypeSafeClient&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">TypeSafeError&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="1-data">1. Data&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">MODEL&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#d88200">&amp;#34;jev-latest&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">SAMPLE_SIZE&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">500&lt;/span> &lt;span style="color:#75715e"># same as the OpenAI notebook&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">MAX_CHARS&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">500&lt;/span> &lt;span style="color:#75715e"># same truncation as the OpenAI notebook&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">MAX_WORKERS&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">8&lt;/span> &lt;span style="color:#75715e"># parallel requests; the SDK retries 429s with backoff&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">RESULTS_CSV&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#d88200">&amp;#34;jev_classification_results.csv&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">FORCE_RECOMPUTE&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#00a8c8">False&lt;/span> &lt;span style="color:#75715e"># True = ignore the cached CSV and call the API again&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">categories_to_fetch&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#39;comp.sys.mac.hardware&amp;#39;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#39;rec.motorcycles&amp;#39;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#39;rec.sport.baseball&amp;#39;&lt;/span>&lt;span style="color:#111">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">simplified_names&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#39;mac&amp;#39;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#39;motor&amp;#39;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#39;baseball&amp;#39;&lt;/span>&lt;span style="color:#111">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">prob_cols&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;prob_&lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">n&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span> &lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">n&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">simplified_names&lt;/span>&lt;span style="color:#111">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">fetch_kwargs&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">dict&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">remove&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#39;headers&amp;#39;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#39;footers&amp;#39;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#39;quotes&amp;#39;&lt;/span>&lt;span style="color:#111">),&lt;/span> &lt;span style="color:#111">categories&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">categories_to_fetch&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">shuffle&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#00a8c8">True&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">random_state&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">42&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">newsgroups_train&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">fetch_20newsgroups&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">subset&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#39;train&amp;#39;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#f92672">**&lt;/span>&lt;span style="color:#111">fetch_kwargs&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">newsgroups_test&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">fetch_20newsgroups&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">subset&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#39;test&amp;#39;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#f92672">**&lt;/span>&lt;span style="color:#111">fetch_kwargs&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">assert&lt;/span> &lt;span style="color:#111">list&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">newsgroups_test&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">target_names&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#111">categories_to_fetch&lt;/span> &lt;span style="color:#75715e"># so target id i &amp;lt;-&amp;gt; simplified_names[i]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">sample_data&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">newsgroups_test&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">data&lt;/span>&lt;span style="color:#111">[:&lt;/span>&lt;span style="color:#111">SAMPLE_SIZE&lt;/span>&lt;span style="color:#111">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">y_true_sample&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">newsgroups_test&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">target&lt;/span>&lt;span style="color:#111">[:&lt;/span>&lt;span style="color:#111">SAMPLE_SIZE&lt;/span>&lt;span style="color:#111">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">print&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">len&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">sample_data&lt;/span>&lt;span style="color:#111">)&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200"> test articles; class counts: &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">np&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">bincount&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">y_true_sample&lt;/span>&lt;span style="color:#111">)&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">tolist&lt;/span>&lt;span style="color:#111">()&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>500 test articles; class counts: [163, 176, 161]
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="2-one-jev-call">2. One Jev call&lt;/h3>
&lt;p>One &lt;code>Choice&lt;/code> question. The option names are what the answer is keyed by, and their descriptions are sent to the model, so each one says what the newsgroup covers.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">QUESTIONS&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;category&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">Choice&lt;/span>&lt;span style="color:#111">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">instructions&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#34;Which newsgroup was this post written in?&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">criteria&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;mac&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;Apple Macintosh computer hardware&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;motor&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;Motorcycles&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;baseball&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;Baseball&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">classify&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">client&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">article&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;&amp;#34;&amp;#34;One Jev call -&amp;gt; (probability vector in simplified_names order, Jev confidence, model version).&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">response&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">client&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">system_one&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">article&lt;/span>&lt;span style="color:#111">[:&lt;/span>&lt;span style="color:#111">MAX_CHARS&lt;/span>&lt;span style="color:#111">],&lt;/span> &lt;span style="color:#111">QUESTIONS&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">model&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">MODEL&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">answer&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">response&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">choices&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;category&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">probs&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">np&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">array&lt;/span>&lt;span style="color:#111">([&lt;/span>&lt;span style="color:#111">answer&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">probabilities&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">get&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">n&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#ae81ff">0.0&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">n&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">simplified_names&lt;/span>&lt;span style="color:#111">])&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">probs&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">answer&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">confidence&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">response&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">model&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">sample_article&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">newsgroups_train&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">data&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">20&lt;/span>&lt;span style="color:#111">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">true_category&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">simplified_names&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#111">newsgroups_train&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">target&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">20&lt;/span>&lt;span style="color:#111">]]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">with&lt;/span> &lt;span style="color:#111">TypeSafeClient&lt;/span>&lt;span style="color:#111">()&lt;/span> &lt;span style="color:#00a8c8">as&lt;/span> &lt;span style="color:#111">client&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">response&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">client&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">system_one&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">sample_article&lt;/span>&lt;span style="color:#111">[:&lt;/span>&lt;span style="color:#111">MAX_CHARS&lt;/span>&lt;span style="color:#111">],&lt;/span> &lt;span style="color:#111">QUESTIONS&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">model&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">MODEL&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">answer&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">response&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">choices&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;category&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">print&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;True category: &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">true_category&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">print&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;Jev choice: &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">answer&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">choice&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200"> (confidence &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">answer&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">confidence&lt;/span>&lt;span style="color:#d88200">:&lt;/span>&lt;span style="color:#d88200">.3f&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">, model &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">response&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">model&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">)&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">display&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">pd&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">Series&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">answer&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">probabilities&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">name&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#34;probability&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">sort_values&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">ascending&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#00a8c8">False&lt;/span>&lt;span style="color:#111">)&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">to_frame&lt;/span>&lt;span style="color:#111">())&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="3-classify-the-sample">3. Classify the sample&lt;/h3>
&lt;p>Results are written to &lt;code>jev_classification_results.csv&lt;/code> as soon as the calls finish, and reused on later runs (set &lt;code>FORCE_RECOMPUTE = True&lt;/code> to redo them). Failed calls are counted and excluded, like the invalid predictions in the OpenAI notebook.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">run_one&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">client&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">article&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">try&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">probs&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">confidence&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">model&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">classify&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">client&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">article&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">probs&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">confidence&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">model&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#00a8c8">None&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">except&lt;/span> &lt;span style="color:#111">TypeSafeError&lt;/span> &lt;span style="color:#00a8c8">as&lt;/span> &lt;span style="color:#111">e&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#00a8c8">None&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#00a8c8">None&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#00a8c8">None&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">repr&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">e&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">if&lt;/span> &lt;span style="color:#111">os&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">path&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">exists&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">RESULTS_CSV&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">and&lt;/span> &lt;span style="color:#f92672">not&lt;/span> &lt;span style="color:#111">FORCE_RECOMPUTE&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">print&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;Using cached results from &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">RESULTS_CSV&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">else&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">rows&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">errors&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">[],&lt;/span> &lt;span style="color:#111">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">print&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;Starting Jev calls for &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">len&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">sample_data&lt;/span>&lt;span style="color:#111">)&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200"> articles...&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">with&lt;/span> &lt;span style="color:#111">TypeSafeClient&lt;/span>&lt;span style="color:#111">()&lt;/span> &lt;span style="color:#00a8c8">as&lt;/span> &lt;span style="color:#111">client&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">ThreadPoolExecutor&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">MAX_WORKERS&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#00a8c8">as&lt;/span> &lt;span style="color:#111">pool&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">futures&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">[&lt;/span>&lt;span style="color:#111">pool&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">submit&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">run_one&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">client&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">a&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">a&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">enumerate&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">sample_data&lt;/span>&lt;span style="color:#111">)]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">done&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">future&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">enumerate&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">as_completed&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">futures&lt;/span>&lt;span style="color:#111">),&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">probs&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">confidence&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">model&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">error&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">future&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">result&lt;/span>&lt;span style="color:#111">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">if&lt;/span> &lt;span style="color:#111">error&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">errors&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">]&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">error&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">else&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">rows&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">append&lt;/span>&lt;span style="color:#111">({&lt;/span>&lt;span style="color:#d88200">&amp;#34;article_idx&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;y_true_final&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">int&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">y_true_sample&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">]),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">**&lt;/span>&lt;span style="color:#111">dict&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">zip&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">prob_cols&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">probs&lt;/span>&lt;span style="color:#111">)),&lt;/span> &lt;span style="color:#d88200">&amp;#34;confidence&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">confidence&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;model&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">model&lt;/span>&lt;span style="color:#111">})&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">if&lt;/span> &lt;span style="color:#111">done&lt;/span> &lt;span style="color:#f92672">%&lt;/span> &lt;span style="color:#ae81ff">50&lt;/span> &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">print&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;Processed &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">done&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">/&lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">len&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">sample_data&lt;/span>&lt;span style="color:#111">)&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200"> articles.&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">if&lt;/span> &lt;span style="color:#f92672">not&lt;/span> &lt;span style="color:#111">rows&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">raise&lt;/span> &lt;span style="color:#75af00">RuntimeError&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;Every Jev call failed. First error: &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">next&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">iter&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">errors&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">values&lt;/span>&lt;span style="color:#111">()))&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">pd&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">DataFrame&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">rows&lt;/span>&lt;span style="color:#111">)&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">sort_values&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;article_idx&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">to_csv&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">RESULTS_CSV&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">index&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#00a8c8">False&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">print&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;Saved &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">len&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">rows&lt;/span>&lt;span style="color:#111">)&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200"> results to &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">RESULTS_CSV&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">; &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">len&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">errors&lt;/span>&lt;span style="color:#111">)&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200"> calls failed.&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">if&lt;/span> &lt;span style="color:#111">errors&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">print&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;First errors:&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">list&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">errors&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">values&lt;/span>&lt;span style="color:#111">())[:&lt;/span>&lt;span style="color:#ae81ff">3&lt;/span>&lt;span style="color:#111">])&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">results_df&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">pd&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">read_csv&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">RESULTS_CSV&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">print&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;Model version(s): &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">results_df&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#39;model&amp;#39;&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">unique&lt;/span>&lt;span style="color:#111">()&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">tolist&lt;/span>&lt;span style="color:#111">()&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>Using cached results from jev_classification_results.csv
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Model version(s): [&amp;#39;jev-1.13.0&amp;#39;]
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="4-macro-f1">4. Macro F1&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">y_true&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">results_df&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;y_true_final&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">to_numpy&lt;/span>&lt;span style="color:#111">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">P&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">results_df&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#111">prob_cols&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">to_numpy&lt;/span>&lt;span style="color:#111">()&lt;/span> &lt;span style="color:#75715e"># (n_samples, 3) probabilities straight from Jev&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">y_pred&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">P&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">argmax&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">axis&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">f1_jev&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">metrics&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">f1_score&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">y_true&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">y_pred&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">average&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#34;macro&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">print&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;==================================================&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">print&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;Macro F1 (Jev): &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">f1_jev&lt;/span>&lt;span style="color:#d88200">:&lt;/span>&lt;span style="color:#d88200">.4f&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200"> accuracy: &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">y_pred&lt;/span> &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#111">y_true&lt;/span>&lt;span style="color:#111">)&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">mean&lt;/span>&lt;span style="color:#111">()&lt;/span>&lt;span style="color:#d88200">:&lt;/span>&lt;span style="color:#d88200">.4f&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">print&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;(Calculated on &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">len&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">y_true&lt;/span>&lt;span style="color:#111">)&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200"> valid predictions out of &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">SAMPLE_SIZE&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">)&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">print&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;==================================================&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>==================================================
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Macro F1 (Jev): 0.9186 accuracy: 0.9180
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>(Calculated on 500 valid predictions out of 500)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>==================================================
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="5-calibration-plot-per-class-one-vs-rest">5. Calibration plot (per class, one-vs-rest)&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">fig&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">ax&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">plt&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">subplots&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">figsize&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#ae81ff">10&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#ae81ff">8&lt;/span>&lt;span style="color:#111">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">ax&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">plot&lt;/span>&lt;span style="color:#111">([&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">],&lt;/span> &lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">],&lt;/span> &lt;span style="color:#d88200">&amp;#34;k:&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">label&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#34;Perfectly calibrated&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">name&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">enumerate&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">simplified_names&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">fraction_of_positives&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">mean_predicted_value&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">calibration_curve&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">y_true&lt;/span> &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">P&lt;/span>&lt;span style="color:#111">[:,&lt;/span> &lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">],&lt;/span> &lt;span style="color:#111">n_bins&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">10&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">ax&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">plot&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">mean_predicted_value&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">fraction_of_positives&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;o-&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">label&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">name&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">ax&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">set_xlabel&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;Mean Predicted Probability (Jev)&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">ax&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">set_ylabel&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;Fraction of Positives (True Probability)&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">ax&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">set_title&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;Calibration Plot (Reliability Curve) for Jev Predictions (N=&lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">len&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">y_true&lt;/span>&lt;span style="color:#111">)&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">)&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">ax&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">legend&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">loc&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#34;lower right&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">ax&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">grid&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#00a8c8">True&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">linestyle&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#34;--&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">alpha&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">0.7&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">plt&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">savefig&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;jev_calibration_plot.png&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">plt&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">show&lt;/span>&lt;span style="color:#111">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;figure>
&lt;img src="../../images/jev_calibration_plot.png" alt="jev_calibration_plot">
&lt;/figure>
&lt;h3 id="6-expected-calibration-error">6. Expected Calibration Error&lt;/h3>
&lt;p>Same definition as the original notebook, with one fix: &lt;code>np.digitize&lt;/code> puts a probability of exactly &lt;code>1.0&lt;/code> in bin index 10, which the loop never visits, so those predictions were dropped from the average. Jev (like the OpenAI mapping) returns many exact &lt;code>0.0&lt;/code>/&lt;code>1.0&lt;/code> values, and the &lt;code>1.0&lt;/code> ones are where overconfidence shows up, so they have to be counted.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">expected_calibration_error&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">y_true&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">prob_pred&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">n_bins&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">10&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">y_true&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">prob_pred&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">np&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">asarray&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">y_true&lt;/span>&lt;span style="color:#111">),&lt;/span> &lt;span style="color:#111">np&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">asarray&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">prob_pred&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">bins&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">np&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">linspace&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">n_bins&lt;/span> &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">binids&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">np&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">clip&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">np&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">digitize&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">prob_pred&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">bins&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">-&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">n_bins&lt;/span> &lt;span style="color:#f92672">-&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#75715e"># p == 1.0 goes in the last bin&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">ece&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0.0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">b&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">range&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">n_bins&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">mask&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">binids&lt;/span> &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#111">b&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">if&lt;/span> &lt;span style="color:#111">mask&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">any&lt;/span>&lt;span style="color:#111">():&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">ece&lt;/span> &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#111">abs&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">y_true&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#111">mask&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">mean&lt;/span>&lt;span style="color:#111">()&lt;/span> &lt;span style="color:#f92672">-&lt;/span> &lt;span style="color:#111">prob_pred&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#111">mask&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">mean&lt;/span>&lt;span style="color:#111">())&lt;/span> &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#111">mask&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">sum&lt;/span>&lt;span style="color:#111">()&lt;/span> &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#111">len&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">y_true&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">ece&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">name&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">enumerate&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">simplified_names&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">ece&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">expected_calibration_error&lt;/span>&lt;span style="color:#111">((&lt;/span>&lt;span style="color:#111">y_true&lt;/span> &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">)&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">astype&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">int&lt;/span>&lt;span style="color:#111">),&lt;/span> &lt;span style="color:#111">P&lt;/span>&lt;span style="color:#111">[:,&lt;/span> &lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">])&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">print&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;ECE for &amp;#39;&lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">name&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">&amp;#39;: &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">ece&lt;/span> &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#ae81ff">100&lt;/span>&lt;span style="color:#d88200">:&lt;/span>&lt;span style="color:#d88200">.2f&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">%&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>ECE for &amp;#39;mac&amp;#39;: 5.34%
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ECE for &amp;#39;motor&amp;#39;: 4.50%
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ECE for &amp;#39;baseball&amp;#39;: 1.96%
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Helper used by the tables below. &lt;strong>Top-label ECE&lt;/strong> asks whether the probability given to the predicted class matches how often that prediction is right (with a bootstrap 95% interval). Per-class ECE alone looks good when most probabilities are near 0, and ECE is biased upward at a few hundred samples, so read the interval before calling a difference real. &lt;code>acc p&amp;gt;=0.99&lt;/code> is the direct test of &amp;ldquo;a probability of 1.0 should be right every time&amp;rdquo;.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">N_CLASSES&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">len&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">simplified_names&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">summarize&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">name&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">y&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">P&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">n_boot&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">1000&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">seed&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">y_pred&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">top_prob&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">P&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">argmax&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">axis&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">),&lt;/span> &lt;span style="color:#111">P&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">max&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">axis&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">correct&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">y_pred&lt;/span> &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#111">y&lt;/span>&lt;span style="color:#111">)&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">astype&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">int&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">rng&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">np&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">random&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">default_rng&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">seed&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">boots&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">[&lt;/span>&lt;span style="color:#111">expected_calibration_error&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">correct&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#111">idx&lt;/span>&lt;span style="color:#111">],&lt;/span> &lt;span style="color:#111">top_prob&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#111">idx&lt;/span>&lt;span style="color:#111">])&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">idx&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">rng&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">integers&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">len&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">y&lt;/span>&lt;span style="color:#111">),&lt;/span> &lt;span style="color:#111">len&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">y&lt;/span>&lt;span style="color:#111">))&lt;/span> &lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">_&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">range&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">n_boot&lt;/span>&lt;span style="color:#111">))]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">lo&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">hi&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">np&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">percentile&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">boots&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">2.5&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#ae81ff">97.5&lt;/span>&lt;span style="color:#111">])&lt;/span> &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#ae81ff">100&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">sure&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">top_prob&lt;/span> &lt;span style="color:#f92672">&amp;gt;=&lt;/span> &lt;span style="color:#ae81ff">0.99&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">row&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;model&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">name&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;n&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">len&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">y&lt;/span>&lt;span style="color:#111">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;accuracy&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">correct&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">mean&lt;/span>&lt;span style="color:#111">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;macro F1&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">metrics&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">f1_score&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">y&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">y_pred&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">average&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#34;macro&amp;#34;&lt;/span>&lt;span style="color:#111">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;mean top prob&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">top_prob&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">mean&lt;/span>&lt;span style="color:#111">(),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;top-label ECE %&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">expected_calibration_error&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">correct&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">top_prob&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#ae81ff">100&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;95% CI&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;[&lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">lo&lt;/span>&lt;span style="color:#d88200">:&lt;/span>&lt;span style="color:#d88200">.1f&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">, &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">hi&lt;/span>&lt;span style="color:#d88200">:&lt;/span>&lt;span style="color:#d88200">.1f&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">]&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;Brier&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">np&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">mean&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">np&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">sum&lt;/span>&lt;span style="color:#111">((&lt;/span>&lt;span style="color:#111">P&lt;/span> &lt;span style="color:#f92672">-&lt;/span> &lt;span style="color:#111">np&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">eye&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">P&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">shape&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">])[&lt;/span>&lt;span style="color:#111">y&lt;/span>&lt;span style="color:#111">])&lt;/span> &lt;span style="color:#f92672">**&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">axis&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">)),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;n p&amp;gt;=0.99&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">int&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">sure&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">sum&lt;/span>&lt;span style="color:#111">()),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;acc p&amp;gt;=0.99&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">correct&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#111">sure&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">mean&lt;/span>&lt;span style="color:#111">()&lt;/span> &lt;span style="color:#00a8c8">if&lt;/span> &lt;span style="color:#111">sure&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">any&lt;/span>&lt;span style="color:#111">()&lt;/span> &lt;span style="color:#00a8c8">else&lt;/span> &lt;span style="color:#111">np&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">nan&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">c&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">enumerate&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">simplified_names&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">row&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;ECE &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">c&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200"> %&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">expected_calibration_error&lt;/span>&lt;span style="color:#111">((&lt;/span>&lt;span style="color:#111">y&lt;/span> &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">)&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">astype&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">int&lt;/span>&lt;span style="color:#111">),&lt;/span> &lt;span style="color:#111">P&lt;/span>&lt;span style="color:#111">[:,&lt;/span> &lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">])&lt;/span> &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#ae81ff">100&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">row&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="7-platt-recalibration">7. Platt recalibration&lt;/h3>
&lt;p>Platt scaling fits one sigmoid per class on the logit of Jev&amp;rsquo;s probability (2 parameters per class), then renormalises the rows to sum to 1.&lt;/p>
&lt;p>It is scored &lt;strong>out-of-fold&lt;/strong>: with 5-fold cross-validation each article is recalibrated by a model that never saw it, so all ~500 articles count and nothing is scored on the data it was fitted on. Probabilities of exactly 0 or 1 are clipped to &lt;code>1e-6&lt;/code> first, because the logit of 0 or 1 is infinite.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">EPS&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">1e-6&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">_logit&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">p&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">p&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">np&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">clip&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">p&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">EPS&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span> &lt;span style="color:#f92672">-&lt;/span> &lt;span style="color:#111">EPS&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">np&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">log&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">p&lt;/span> &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#111">(&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span> &lt;span style="color:#f92672">-&lt;/span> &lt;span style="color:#111">p&lt;/span>&lt;span style="color:#111">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">fit_platt&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">P_fit&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">y_fit&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">[&lt;/span>&lt;span style="color:#111">LogisticRegression&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">C&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">1e3&lt;/span>&lt;span style="color:#111">)&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">fit&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">_logit&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">P_fit&lt;/span>&lt;span style="color:#111">[:,&lt;/span> &lt;span style="color:#111">[&lt;/span>&lt;span style="color:#111">k&lt;/span>&lt;span style="color:#111">]]),&lt;/span> &lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">y_fit&lt;/span> &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#111">k&lt;/span>&lt;span style="color:#111">)&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">astype&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">int&lt;/span>&lt;span style="color:#111">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">k&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">range&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">P_fit&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">shape&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">])]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">apply_platt&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">models&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">P_new&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">cal&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">np&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">column_stack&lt;/span>&lt;span style="color:#111">([&lt;/span>&lt;span style="color:#111">m&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">predict_proba&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">_logit&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">P_new&lt;/span>&lt;span style="color:#111">[:,&lt;/span> &lt;span style="color:#111">[&lt;/span>&lt;span style="color:#111">k&lt;/span>&lt;span style="color:#111">]]))[:,&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">]&lt;/span> &lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">k&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">m&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">enumerate&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">models&lt;/span>&lt;span style="color:#111">)])&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">totals&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">cal&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">sum&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">axis&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">keepdims&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#00a8c8">True&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">np&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">where&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">totals&lt;/span> &lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">cal&lt;/span> &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#111">np&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">where&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">totals&lt;/span> &lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">totals&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">),&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span> &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#111">cal&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">shape&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">])&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">out_of_fold_platt&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">P&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">y&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">n_splits&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">5&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">seed&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">42&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">out&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">np&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">zeros_like&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">P&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">fit_idx&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">test_idx&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">StratifiedKFold&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">n_splits&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">shuffle&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#00a8c8">True&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">random_state&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">seed&lt;/span>&lt;span style="color:#111">)&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">split&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">P&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">y&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">out&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#111">test_idx&lt;/span>&lt;span style="color:#111">]&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">apply_platt&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">fit_platt&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">P&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#111">fit_idx&lt;/span>&lt;span style="color:#111">],&lt;/span> &lt;span style="color:#111">y&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#111">fit_idx&lt;/span>&lt;span style="color:#111">]),&lt;/span> &lt;span style="color:#111">P&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#111">test_idx&lt;/span>&lt;span style="color:#111">])&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">out&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">P_platt&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">out_of_fold_platt&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">P&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">y_true&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">fig&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">axes&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">plt&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">subplots&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">N_CLASSES&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">figsize&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#ae81ff">18&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#ae81ff">5&lt;/span>&lt;span style="color:#111">),&lt;/span> &lt;span style="color:#111">sharey&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#00a8c8">True&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">name&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">ax&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">enumerate&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">zip&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">simplified_names&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">axes&lt;/span>&lt;span style="color:#111">)):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">ax&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">plot&lt;/span>&lt;span style="color:#111">([&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">],&lt;/span> &lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">],&lt;/span> &lt;span style="color:#d88200">&amp;#34;k:&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">label&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#34;Perfectly calibrated&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">probs&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">style&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">label&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">[(&lt;/span>&lt;span style="color:#111">P&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;o--&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;Jev (raw)&amp;#34;&lt;/span>&lt;span style="color:#111">),&lt;/span> &lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">P_platt&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;s-&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;Jev + Platt (out-of-fold)&amp;#34;&lt;/span>&lt;span style="color:#111">)]:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">frac&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">mean_p&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">calibration_curve&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">y_true&lt;/span> &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">probs&lt;/span>&lt;span style="color:#111">[:,&lt;/span> &lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">],&lt;/span> &lt;span style="color:#111">n_bins&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">10&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">ax&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">plot&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">mean_p&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">frac&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">style&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">label&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">label&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">alpha&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">0.8&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">ax&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">set_title&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;&amp;#39;&lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">name&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">&amp;#39; (N=&lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">len&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">y_true&lt;/span>&lt;span style="color:#111">)&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">)&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">ax&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">set_xlabel&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;Mean Predicted Probability&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">ax&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">grid&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#00a8c8">True&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">linestyle&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#34;--&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">alpha&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">0.7&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">axes&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">set_ylabel&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;Fraction of Positives&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">axes&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">legend&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">loc&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#34;upper left&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">plt&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">tight_layout&lt;/span>&lt;span style="color:#111">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">plt&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">savefig&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;jev_platt_calibration_plot.png&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">plt&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">show&lt;/span>&lt;span style="color:#111">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">print&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;Accuracy: raw &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">P&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">argmax&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#111">y_true&lt;/span>&lt;span style="color:#111">)&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">mean&lt;/span>&lt;span style="color:#111">()&lt;/span>&lt;span style="color:#d88200">:&lt;/span>&lt;span style="color:#d88200">.4f&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200"> | Platt &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">P_platt&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">argmax&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#111">y_true&lt;/span>&lt;span style="color:#111">)&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">mean&lt;/span>&lt;span style="color:#111">()&lt;/span>&lt;span style="color:#d88200">:&lt;/span>&lt;span style="color:#d88200">.4f&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">name&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">enumerate&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">simplified_names&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">before&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">expected_calibration_error&lt;/span>&lt;span style="color:#111">((&lt;/span>&lt;span style="color:#111">y_true&lt;/span> &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">)&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">astype&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">int&lt;/span>&lt;span style="color:#111">),&lt;/span> &lt;span style="color:#111">P&lt;/span>&lt;span style="color:#111">[:,&lt;/span> &lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">])&lt;/span> &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#ae81ff">100&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">after&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">expected_calibration_error&lt;/span>&lt;span style="color:#111">((&lt;/span>&lt;span style="color:#111">y_true&lt;/span> &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">)&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">astype&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">int&lt;/span>&lt;span style="color:#111">),&lt;/span> &lt;span style="color:#111">P_platt&lt;/span>&lt;span style="color:#111">[:,&lt;/span> &lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">])&lt;/span> &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#ae81ff">100&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">print&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;ECE &amp;#39;&lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">name&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">&amp;#39;: &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">before&lt;/span>&lt;span style="color:#d88200">:&lt;/span>&lt;span style="color:#d88200">.2f&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">% -&amp;gt; &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">after&lt;/span>&lt;span style="color:#d88200">:&lt;/span>&lt;span style="color:#d88200">.2f&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">% after Platt&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>Accuracy: raw 0.9180 | Platt 0.9260
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ECE &amp;#39;mac&amp;#39;: 5.34% -&amp;gt; 2.23% after Platt
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ECE &amp;#39;motor&amp;#39;: 4.50% -&amp;gt; 2.10% after Platt
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>ECE &amp;#39;baseball&amp;#39;: 1.96% -&amp;gt; 1.87% after Platt
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;figure>
&lt;img src="../../images/jev_platt_calibration_plot.png" alt="jev_platt_calibration_plot">
&lt;/figure>
&lt;h3 id="8-comparison-with-the-openai-run">8. Comparison with the OpenAI run&lt;/h3>
&lt;p>&lt;code>openai_classification_results.csv&lt;/code> does not keep the article index (and has 496 valid rows), so the OpenAI run is a different sample of the same distribution: compare it as a reference rather than row by row. Its probabilities come from the first-token logprob heuristic in &lt;code>confidence.ipynb&lt;/code>, renormalised over the matched tokens; Jev&amp;rsquo;s are its native &lt;code>probabilities&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">runs&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;Jev&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">y_true&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">P&lt;/span>&lt;span style="color:#111">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;Jev + Platt (out-of-fold)&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">y_true&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">P_platt&lt;/span>&lt;span style="color:#111">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">if&lt;/span> &lt;span style="color:#111">os&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">path&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">exists&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;openai_classification_results.csv&amp;#34;&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">openai_df&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">pd&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">read_csv&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;openai_classification_results.csv&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">runs&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;OpenAI gpt-4o-mini&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">openai_df&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;y_true_final&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">to_numpy&lt;/span>&lt;span style="color:#111">(),&lt;/span> &lt;span style="color:#111">openai_df&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#111">prob_cols&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">to_numpy&lt;/span>&lt;span style="color:#111">())&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">else&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">print&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;openai_classification_results.csv not found; showing Jev only.&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">summary&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">pd&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">DataFrame&lt;/span>&lt;span style="color:#111">([&lt;/span>&lt;span style="color:#111">summarize&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">name&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">y&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">probs&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">name&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">y&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">probs&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">runs&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">items&lt;/span>&lt;span style="color:#111">()])&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">set_index&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;model&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">display&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">summary&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">round&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#ae81ff">3&lt;/span>&lt;span style="color:#111">))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;table>
&lt;thead>
&lt;tr>
&lt;th>metric&lt;/th>
&lt;th>Jev&lt;/th>
&lt;th>Jev + Platt (out-of-fold)&lt;/th>
&lt;th>OpenAI gpt-4o-mini&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>n&lt;/td>
&lt;td>500&lt;/td>
&lt;td>500&lt;/td>
&lt;td>496&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>accuracy&lt;/td>
&lt;td>0.918&lt;/td>
&lt;td>0.926&lt;/td>
&lt;td>0.911&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>macro F1&lt;/td>
&lt;td>0.919&lt;/td>
&lt;td>0.926&lt;/td>
&lt;td>0.913&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>mean top prob&lt;/td>
&lt;td>0.942&lt;/td>
&lt;td>0.920&lt;/td>
&lt;td>0.986&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>top-label ECE %&lt;/td>
&lt;td>3.524&lt;/td>
&lt;td>1.248&lt;/td>
&lt;td>7.454&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>95% CI&lt;/td>
&lt;td>[2.5, 5.8]&lt;/td>
&lt;td>[1.1, 3.4]&lt;/td>
&lt;td>[5.4, 9.8]&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Brier&lt;/td>
&lt;td>0.115&lt;/td>
&lt;td>0.099&lt;/td>
&lt;td>0.154&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>n p&amp;gt;=0.99&lt;/td>
&lt;td>356&lt;/td>
&lt;td>328&lt;/td>
&lt;td>451&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>acc p&amp;gt;=0.99&lt;/td>
&lt;td>0.997&lt;/td>
&lt;td>0.997&lt;/td>
&lt;td>0.967&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>ECE mac %&lt;/td>
&lt;td>5.338&lt;/td>
&lt;td>2.232&lt;/td>
&lt;td>6.813&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>ECE motor %&lt;/td>
&lt;td>4.498&lt;/td>
&lt;td>2.102&lt;/td>
&lt;td>5.224&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>ECE baseball %&lt;/td>
&lt;td>1.962&lt;/td>
&lt;td>1.868&lt;/td>
&lt;td>3.437&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">colors&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">{&lt;/span>&lt;span style="color:#d88200">&amp;#34;Jev&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;tab:blue&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;Jev + Platt (out-of-fold)&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;tab:green&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;OpenAI gpt-4o-mini&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;tab:orange&amp;#34;&lt;/span>&lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">fig&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">axes&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">plt&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">subplots&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">N_CLASSES&lt;/span> &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">figsize&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#ae81ff">22&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#ae81ff">5&lt;/span>&lt;span style="color:#111">),&lt;/span> &lt;span style="color:#111">sharey&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#00a8c8">True&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">ax&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">title&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">zip&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">axes&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">[&lt;/span>&lt;span style="color:#f92672">*&lt;/span>&lt;span style="color:#111">simplified_names&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;top label (all classes)&amp;#34;&lt;/span>&lt;span style="color:#111">]):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">ax&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">plot&lt;/span>&lt;span style="color:#111">([&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">],&lt;/span> &lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">],&lt;/span> &lt;span style="color:#d88200">&amp;#34;k:&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">label&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#34;Perfectly calibrated&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">ax&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">set_title&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">title&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">ax&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">set_xlabel&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;Mean Predicted Probability&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">ax&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">grid&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#00a8c8">True&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">linestyle&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#34;--&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">alpha&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">0.7&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">name&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">y&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">probs&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">runs&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">items&lt;/span>&lt;span style="color:#111">():&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">i&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">range&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">N_CLASSES&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">frac&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">mean_p&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">calibration_curve&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">y&lt;/span> &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">probs&lt;/span>&lt;span style="color:#111">[:,&lt;/span> &lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">],&lt;/span> &lt;span style="color:#111">n_bins&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">10&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">axes&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#111">i&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">plot&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">mean_p&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">frac&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;o-&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">color&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">colors&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#111">name&lt;/span>&lt;span style="color:#111">],&lt;/span> &lt;span style="color:#111">label&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">name&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">frac&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">mean_p&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">calibration_curve&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">probs&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">argmax&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#111">y&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">probs&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">max&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">),&lt;/span> &lt;span style="color:#111">n_bins&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">10&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">axes&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">plot&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">mean_p&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">frac&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;o-&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">color&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">colors&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#111">name&lt;/span>&lt;span style="color:#111">],&lt;/span> &lt;span style="color:#111">label&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">name&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">axes&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">set_ylabel&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;Fraction of Positives&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">axes&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">legend&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">loc&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#34;upper left&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">plt&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">tight_layout&lt;/span>&lt;span style="color:#111">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">plt&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">savefig&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;jev_vs_openai_calibration.png&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">plt&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">show&lt;/span>&lt;span style="color:#111">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;figure>
&lt;img src="../../images/jev_vs_openai_calibration.png" alt="jev_vs_openai_calibration">
&lt;/figure></description><author>Calvin Tran</author><guid>http://gabelfra1.github.io/gabelfra.github.io/posts/jev/</guid><pubDate>Mon, 21 Sep 2026 00:00:00 +0000</pubDate></item><item><title>Classification is back</title><link>http://gabelfra1.github.io/gabelfra.github.io/posts/classification/</link><description>&lt;h3 id="the-decision-was-always-the-product">The decision was always the product&lt;/h3>
&lt;p>A while ago I wrote about &lt;a href="http://gabelfra1.github.io/gabelfra.github.io/blog/llm-are-way-too-confident">how badly calibrated LLMs are&lt;/a>. Any GPT-model beat a traditional ML model (TF-IDF &amp;amp; Naive Bayes) at classifcation but it&amp;rsquo;s probability scores are just too uncalibrated to be useful.&lt;/p>
&lt;p>Then I wrote a &lt;a href="http://gabelfra1.github.io/gabelfra.github.io/blog/building-effective-agents">code along on agentic patterns&lt;/a>, and every one of those patterns has the same problem underneath. Routing is a classifier, the evaluator is a classifier, the tool selector is a classifier and so on..&lt;/p>
&lt;p>Put the two articles together and you have the real problem with modern automation. What we build is workflows. What a workflow needs at every node is a decision with an honest probability attached. What the model is optimised to produce is text not calibrated decisions.&lt;/p>
&lt;h4 id="what-automation-actually-asks-for">What automation actually asks for&lt;/h4>
&lt;p>Strip the marketing off any enterprise use case and the loop is the same. Ingest some context, most of it unstructured. Make a decision. Act on it with a tool. Repeat.&lt;/p>
&lt;p>None of those steps needs the capability to produce text. Nobody in production reads the model&amp;rsquo;s reasoning trace of why it routed the ticket to the credit card team. The explanation exists because text is the only interface on offer, so we generate it and throw it away after parsing the output to generate a structured response.&lt;/p>
&lt;p>The parsing is the tell. If your first action on receiving a model output is to run a validator over it, the model is not speaking your language.&lt;/p>
&lt;h4 id="the-hoops">The hoops&lt;/h4>
&lt;p>Everyone building these systems carries the same scaffolding. A Pydantic schema plus some additional tricks , because the model can emit a category that does not exist. Temperature zero, which does not make the system deterministic, it just makes it feel deterministic.
Retry loops, so you make five calls instead of one.&lt;/p>
&lt;p>This is not a prompting problem. &lt;a href="https://arxiv.org/abs/1706.04599">Guo et al. (2017)&lt;/a> showed that modern networks drift towards overconfidence as a property of how we train them, and RLHF pushes the same way by optimising for what a human rater prefers to read. A model rewarded for sounding helpful will sound certain.&lt;/p>
&lt;h4 id="system-one-models">System One models&lt;/h4>
&lt;p>TypeSafe released &lt;a href="https://typesafe.ai/blog/introducing-system-one-models-and-jev">Jev&lt;/a> on 15 September, the first of what they call &lt;strong>System One models&lt;/strong>. The name comes from Kahneman&amp;rsquo;s split between fast intuitive judgement and slow deliberate reasoning.&lt;/p>
&lt;p>The design decision is the interesting part. Jev gives up text generation entirely. It samples all of its outputs in parallel in a single query rather than one token at a time, and it is trained with a method they call Reinforcement Learning for Calibrated Decisions instead of RLHF. You send a state and a set of typed questions, and you get back typed values and probability distributions.&lt;/p>
&lt;p>Everything in the previous section becomes unnecessary if that holds. There is no parsing because there is no string. There are no type errors, not because they are rare but because the possible outputs are defined in advance and schema matching is guaranteed. And the probability is not fugazi, it is what the model was trained to produce.&lt;/p>
&lt;h4 id="calibration-is-king">Calibration is king&lt;/h4>
&lt;p>&lt;strong>Calibration means that among all the predictions the model assigns 70% to, roughly 70% turn out correct.&lt;/strong> Without that property you cannot set a threshold, and without a threshold every decision needs a human in the loop.&lt;/p>
&lt;p>Jav returns the full distribution and also collapses its shape into a single confidence number, so you can threshold without computing it yourself. A flat distribution means low confidence: no option is a clear winner, or the state does not contain enough to go on. What follows is the pattern every risk function already understands.
A floor below which you route to a human, and above it a bar for acting without confirmation that scales with what the action costs if it is wrong.&lt;/p>
&lt;h4 id="the-part-i-am-not-sold-on-yet">The part I am not sold on yet&lt;/h4>
&lt;p>The workflow evals are the weak point, agreement with a panel of frontier LLMs is not the same as being right (try LLM as a judge), and it is a strange yardstick for a model whose pitch is that frontier LLMs are badly calibrated. The one claim genuinely free of this problem is type safety, which is guaranteed by construction and falsifiable with a single API call.&lt;/p>
&lt;p>And the obvious one. This does not replace LLMs. It replaces the part of your agent that was pretending to be a classifier. When you need generated language,images or video you still need a generative model. What changes is that the decision layer stops being made of the same material as the generation layer.&lt;/p>
&lt;p>What I want to see, and intend to run myself (if I get my hand on the early access), is a straight calibration benchmark. Same 20 Newsgroups setup as the first article, reliability diagram, ECE, Brier score, no vendor in the loop.&lt;/p>
&lt;h3 id="conclusion">Conclusion&lt;/h3>
&lt;p>I ended the calibration article by saying that where a decision depends on a trustworthy measure of confidence, modern LLMs are a bad choice, and you should accept the cost of labels and training something simpler. I still think that was right for the world as it was.&lt;/p>
&lt;p>But if the generality (of inputs) and the calibration (of outputs) hold up across common domains, RLCD could turn out to be the missing piece in every automation workflow.&lt;/p>
&lt;p>And I would be very happy to delete the scaffolding we built around LLMs to force them into being type safe and marginally less overconfident, and to pay less for the privilege.&lt;/p></description><author>Calvin Tran</author><guid>http://gabelfra1.github.io/gabelfra.github.io/posts/classification/</guid><pubDate>Thu, 17 Sep 2026 00:00:00 +0000</pubDate></item><item><title>Who Watches the Watchmen?</title><link>http://gabelfra1.github.io/gabelfra.github.io/posts/evaluation/</link><description>&lt;p>&lt;em>This article is about single-turn LLM generation: producing text, answering questions, summarising, and so on. I am not going to cover multi-turn conversation or agentic systems. The question is a practical one. You have shipped, or are about to ship, a system that relies on an LLM for real users in a real business. How do you know if it is any good?&lt;/em>&lt;/p>
&lt;h3 id="the-old-world-nlp-measures">The old world: NLP measures&lt;/h3>
&lt;p>Before large language models entered the picture, NLP evaluation had a clean, mathematical answer: measure how similar the output is to a known good reference. The dominant metric was BLEU (&lt;a href="https://aclanthology.org/P02-1040/">Papineni et al., 2002&lt;/a>), the Bilingual Evaluation Understudy, imported from the machine translation research that would later give us the Transformer (&lt;a href="https://arxiv.org/abs/1706.03762">Vaswani et al., 2017&lt;/a>). BLEU counts overlapping n-grams between a generated string and a reference string and produces a score between 0 and 1. ROUGE (&lt;a href="https://aclanthology.org/W04-1013/">Lin, 2004&lt;/a>) did the same for summarisation. Cosine similarity over TF-IDF or word embeddings offered a softer version of the same idea.&lt;/p>
&lt;p>These metrics had real virtues. They were fast, cheap, deterministic, and needed no human in the loop once you had a reference corpus.&lt;/p>
&lt;p>The problem is that language is not a bag of words, and meaning is not proximity in token space. &amp;ldquo;The patient is not responding to treatment&amp;rdquo; and &amp;ldquo;The patient is responding well to treatment&amp;rdquo; share most of their surface and would score highly against one another. &amp;ldquo;The medication was administered&amp;rdquo; and &amp;ldquo;The medication was not administered&amp;rdquo; sit a single negation apart. Similarity-based metrics are structurally blind to these distinctions, and in a real world scenario that blindness becomes fatal.&lt;/p>
&lt;h3 id="closing-the-gap-natural-language-inference">Closing the gap: Natural Language Inference&lt;/h3>
&lt;p>The field&amp;rsquo;s next attempt to do better came through Natural Language Inference (NLI): the task of deciding whether a hypothesis is entailed by, contradicted by, or neutral with respect to a premise. Models fine-tuned on datasets like SNLI (&lt;a href="https://arxiv.org/abs/1508.05326">Bowman et al., 2015&lt;/a>) and MNLI (&lt;a href="https://arxiv.org/abs/1704.05426">Williams et al., 2018&lt;/a>) learned something closer to semantic reasoning than to surface matching.&lt;/p>
&lt;p>The training data looks like this:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Premise&lt;/th>
&lt;th>Hypothesis&lt;/th>
&lt;th>Label&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>A football game with kids playing.&lt;/td>
&lt;td>Some kids are playing.&lt;/td>
&lt;td>Entailment&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>A man is in a kitchen cooking&lt;/td>
&lt;td>The man is sleeping.&lt;/td>
&lt;td>Contradiction&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>The idea, applied to evaluation, was to check not whether the output looked like the reference, but whether it was logically coherent with, it was a genuine improvement. NLI-based scoring caught contradictions that BLEU missed; it was sensitive to negation, to entailment direction, to whether a claim was supported or merely adjacent to the reference.&lt;/p>
&lt;p>But NLI brought its own problem, and you can already see it in the table above. Those premises and hypotheses are short, tidy, single-clause sentences derived from image captions. Real documents do not read like the Elements of Euclid. Real world documents are messy, contextual, sentences long, full of hedges and asides and clauses that depend on one another. An entailment model trained on caption pairs has very little to say about whether a four-paragraph answer faithfully reflects a retrieved policy document. It was a well-designed experiment that, for the most part, stayed in the lab.&lt;/p>
&lt;h3 id="the-new-world--llm-as-judge">The new world : LLM-as-Judge&lt;/h3>
&lt;p>Once capable LLMs existed, the obvious move was to use them to evaluate each other. Feed the system prompt, the user query and the model&amp;rsquo;s response to a capable judge model and get back a score. This approach, LLM-as-Judge, was studied systematically by &lt;a href="https://arxiv.org/abs/2306.05685">Zheng et al. (2023)&lt;/a> and has since become the de facto standard. A capable judge can assess fluency, faithfulness, relevance and tone in a single pass, and it can explain its reasoning on edge cases that would confuse any fixed metric.&lt;/p>
&lt;p>A growing ecosystem of packages wraps this pattern into something you can drop into a pipeline. RAGAS (&lt;a href="https://arxiv.org/abs/2309.15217">Es et al., 2024&lt;/a>) is one example among many: built for retrieval-augmented generation, it scores dimensions like faithfulness (does the answer stick to the retrieved context?), answer relevancy and context recall, each judged independently so you get a full picture rather than one opaque number. DeepEval, TruLens and others occupy the same space with different trade-offs. &lt;strong>The framework matters less than understanding what it is doing underneath, which is asking an LLM to grade another LLM.&lt;/strong>&lt;/p>
&lt;p>That is where the real problem lives, and it is one of epistemology: you are using a model with its own biases to evaluate a model with its own biases. Three failure modes are well documented. &lt;strong>Self-preference bias&lt;/strong>: judges favour outputs that resemble their own, and &lt;a href="https://arxiv.org/abs/2404.13076">Panickssery et al. (2024)&lt;/a> link this directly to a model&amp;rsquo;s ability to recognise its own generations, so using GPT-4 to judge GPT-4 is not a neutral act. &lt;strong>Verbosity bias&lt;/strong>: longer, more hedged answers score higher than concise, correct ones.&lt;strong>Position bias&lt;/strong>: in a pairwise comparison the answer shown first wins more often.&lt;/p>
&lt;p>Mitigations exist: prompt the judge to reason before scoring, run each comparison in both orders and average, use a different model family as judge than the one under test. None of them fully closes the gap. LLM-as-Judge is powerful tool but has it&amp;rsquo;s cracks.&lt;/p>
&lt;h3 id="back-to-basics-the-golden-dataset">Back to basics: the golden dataset&lt;/h3>
&lt;p>The canonical machine learning answer is the test dataset: a golden dataset of inputs paired with verified outputs, against which any version of the system can be scored and compared. The appeal is obvious. It is deterministic, reproducible and immune to judge bias.&lt;/p>
&lt;p>The problem is circular in an uncomfortable way. To score an LLM&amp;rsquo;s free-form generation against a golden answer, you need a method to compare the produced response to the expected one, and you are right back where you started. A similarity metric misses semantic divergence; an NLI model carries the problems described above; a human reviewing every pair does not scale. You can use an LLM judge for the comparison, but then your golden evaluation is only as good as that judge, and you have not escaped the watchmen problem, you have just moved it up one layer.&lt;/p>
&lt;p>Golden datasets still earn their place when you narrow what they test. For constrained tasks (extracting a specific field, classifying into a fixed set of categories, requiring a response to contain certain factual claims) binary or near-binary correctness checks are both tractable and meaningful. The failure mode is stretching this to open-ended generation, where the space of acceptable answers is large and your reference is only one valid output among many.&lt;/p>
&lt;p>When you do need to measure closeness to an expected answer, the most reliable options today are embedding-based similarity using a strong general-purpose embedding model, or structured decomposition: break the expected answer into individual factual claims and verify each one separately rather than comparing the whole.&lt;/p>
&lt;h3 id="the-user-as-ground-truth">The user as ground truth&lt;/h3>
&lt;p>There is one more signal, and it sits in production: the user. Thumbs up and thumbs down, copy-to-clipboard events, a follow-up question that reveals the first answer was wrong, session usage. These are all expressions of satisfaction or dissatisfaction that need no instrumentation beyond basic analytics.&lt;/p>
&lt;p>The seductive thing about implicit feedback is that it is free, continuous and available at scale. The dangerous thing is that it is confounded by almost everything: UI, task difficulty, user expertise, stylistic preferences that have nothing to do with quality. A thumbs down might mean &amp;ldquo;the answer was wrong&amp;rdquo;, or &amp;ldquo;the answer was right but too boring&amp;rdquo;, or &amp;ldquo;I clicked it by accident&amp;rdquo;, or &amp;ldquo;I was already frustrated before I opened the tool&amp;rdquo;. Explicit Likert ratings remove some of that ambiguity but add survey fatigue and selection bias, since the users who rate are rarely representative of the users who do not.&lt;/p>
&lt;p>Treat user feedback as a monitoring signal, not a validation metric. It is good for catching regressions, surfacing categories of failure and deciding what to investigate next. It is not reliable enough to be the primary basis for an iteration decision.&lt;/p>
&lt;h3 id="a-practical-framework">A practical framework&lt;/h3>
&lt;p>Putting it all together, here is a reasonable approach for a team shipping a production LLM system, at least in my opinion&lt;/p>
&lt;p>&lt;strong>Define what correctness means before you build anything.&lt;/strong> The evaluation strategy should fall out of the task definition, not get bolted on afterwards. If you cannot write down in concrete terms what a good response looks like, you are not ready.&lt;/p>
&lt;p>&lt;strong>Use automated metrics as filters, not as truth.&lt;/strong> LLM-as-Judge metrics catch obvious failures reliably and subtle ones unreliably. Use them to shrink the volume of output that needs human eyes, not to replace those eyes.&lt;/p>
&lt;p>&lt;strong>Build a golden dataset for regression testing&lt;/strong> A modest, carefully curated set of inputs with verified references beats a large noisy one.That set is your foundation for changing the system without breaking it in production.&lt;/p>
&lt;p>&lt;strong>Show the retrieved context or the reasoning trace to the user.&lt;/strong> If the job is to convey accurate information, expose the sources behind each answer so the user can confirm or reject them. This turns your users into a distributed check on your failure modes.&lt;/p>
&lt;p>&lt;strong>Treat user feedback as continuous monitoring.&lt;/strong> Log it, track it over time, investigate anomalies, and keep iterating.&lt;/p>
&lt;p>&lt;strong>Evaluate offline first, then ship with monitoring.&lt;/strong> The ship of certainty sailed long ago. The goal is not to be perfect before deployment, which is unattainable, but to have enough signal to catch a mistake quickly and roll back.&lt;/p>
&lt;p>&lt;strong>Stay sceptical of every metric&lt;/strong> All of this is probabilistic. No single number tells you the system is good; you are watching whether the whole picture is trending in the right direction. Any metric can be gamed, can drift, or can look healthy while something underneath rots. Trust the convergence of several weak signals over any one strong-looking score.&lt;/p>
&lt;h3 id="conclusion">Conclusion&lt;/h3>
&lt;p>There is no clean solution to this. Every evaluation method has a crack, and every crack is filled by some other method you are trusting implicitly. What you can do is be honest about where each layer breaks down, stack layers that fail in different ways, and keep humans in contact with real output often enough to catch what the metrics miss. That is not a perfect answer. It is the only one on offer.&lt;/p>
&lt;h4 id="references">References&lt;/h4>
&lt;ul>
&lt;li>Papineni, K., Roukos, S., Ward, T., Zhu, W. (2002). &lt;a href="https://aclanthology.org/P02-1040/">BLEU: a Method for Automatic Evaluation of Machine Translation&lt;/a>. ACL.&lt;/li>
&lt;li>Lin, C. (2004). &lt;a href="https://aclanthology.org/W04-1013/">ROUGE: A Package for Automatic Evaluation of Summaries&lt;/a>. Text Summarization Branches Out, ACL Workshop.&lt;/li>
&lt;li>Vaswani, A., et al. (2017). &lt;a href="https://arxiv.org/abs/1706.03762">Attention Is All You Need&lt;/a>. NeurIPS.&lt;/li>
&lt;li>Bowman, S., Angeli, G., Potts, C., Manning, C. (2015). &lt;a href="https://arxiv.org/abs/1508.05326">A Large Annotated Corpus for Learning Natural Language Inference&lt;/a>. EMNLP.&lt;/li>
&lt;li>Williams, A., Nangia, N., Bowman, S. (2018). &lt;a href="https://arxiv.org/abs/1704.05426">A Broad-Coverage Challenge Corpus for Sentence Understanding through Inference&lt;/a>. NAACL.&lt;/li>
&lt;li>Zhang, T., Kishore, V., Wu, F., Weinberger, K., Artzi, Y. (2020). &lt;a href="https://arxiv.org/abs/1904.09675">BERTScore: Evaluating Text Generation with BERT&lt;/a>. ICLR.&lt;/li>
&lt;li>Zheng, L., et al. (2023). &lt;a href="https://arxiv.org/abs/2306.05685">Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena&lt;/a>. NeurIPS.&lt;/li>
&lt;li>Es, S., James, J., Espinosa-Anke, L., Schockaert, S. (2024). &lt;a href="https://arxiv.org/abs/2309.15217">RAGAS: Automated Evaluation of Retrieval Augmented Generation&lt;/a>. EACL.&lt;/li>
&lt;li>Panickssery, A., Bowman, S., Feng, S. (2024). &lt;a href="https://arxiv.org/abs/2404.13076">LLM Evaluators Recognize and Favor Their Own Generations&lt;/a>. NeurIPS.&lt;/li>
&lt;/ul></description><author>Calvin Tran</author><guid>http://gabelfra1.github.io/gabelfra.github.io/posts/evaluation/</guid><pubDate>Sun, 21 Jun 2026 00:00:00 +0000</pubDate></item><item><title>PageIndex: When Your RAG Reads Like a Human</title><link>http://gabelfra1.github.io/gabelfra.github.io/posts/pageindex/</link><description>&lt;h3 id="the-explainability-problem-nobody-talks-about">The Explainability Problem Nobody Talks About&lt;/h3>
&lt;p>Standard RAG has a transparency problem, and it&amp;rsquo;s not one that shows up in benchmark numbers.&lt;/p>
&lt;p>When a user asks &lt;em>&amp;ldquo;why did the system return this paragraph and not that one?&amp;rdquo;&lt;/em>, the honest answer is: &lt;em>&amp;ldquo;because the cosine similarity was 0.83 instead of 0.79.&amp;rdquo;&lt;/em> That answer is technically correct and completely useless. Nobody outside of an ML team reasons about document retrieval in terms of vector distances. They reason about sections, chapters, topics, and arguments.&lt;/p>
&lt;p>This gap between how retrieval systems work and how humans think about information lookup creates a problem: the users either accept the result blindly or reject the whole system because they can&amp;rsquo;t audit it. Neither is good.&lt;/p>
&lt;p>&lt;a href="https://github.com/VectifyAI/PageIndex">PageIndex&lt;/a> is an approach that sidesteps this problem entirely by discarding vector similarity and replacing it with something more explainable : &lt;strong>structure-aware, reasoning-based retrieval&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h3 id="how-humans-actually-look-things-up">How Humans Actually Look Things Up&lt;/h3>
&lt;p>If you remember searching for something in a physical library before Google, I do, you remember the process intuitively. You didn&amp;rsquo;t scan every page of every book. You:&lt;/p>
&lt;ol>
&lt;li>Found the right book by subject&lt;/li>
&lt;li>Opened the table of contents&lt;/li>
&lt;li>Found the relevant chapter&lt;/li>
&lt;li>Skimmed the section headings&lt;/li>
&lt;li>Read the specific paragraph&lt;/li>
&lt;/ol>
&lt;p>That multi-level navigation was precise and fully explainable. You could tell anyone exactly why you landed on page 247 of &lt;em>Option futures and other derivatives&lt;/em>.&lt;/p>
&lt;p>PageIndex replicates this exact behavior. Instead of embedding chunks and retrieving by similarity, it first builds a hierarchical index of the documents. Baiscally a machine-readable table of contents with summaries at each node and then asks an LLM to &lt;em>reason&lt;/em> about which branch of that tree is likely to contain the answer. The LLM walks the index the same way I used to serarch the uni library.&lt;/p>
&lt;hr>
&lt;h3 id="two-phases-index-then-retrieve">Two Phases: Index Then Retrieve&lt;/h3>
&lt;p>The workflow has two clean phases.&lt;/p>
&lt;p>&lt;strong>Phase 1 — Build the index.&lt;/strong> Submit a document to PageIndex.
It parses the document structure (headings, sections, subsections), generates a summary for each node, and returns a JSON tree. This happens once per document.&lt;/p>
&lt;p>&lt;strong>Phase 2 — Reason and retrieve.&lt;/strong> At query time, pass the tree (without full text) to an LLM and ask it to identify which nodes are relevant. Then pull the actual text only from those nodes and generate the final answer.&lt;/p>
&lt;p>The tree for a typical long document looks like this:&lt;/p>
&lt;pre tabindex="0">&lt;code>Document Root
├── Abstract [pages 1-1]
│ └── &amp;#34;Overview of the proposed method and key results...&amp;#34;
├── Introduction [pages 2-3]
│ └── &amp;#34;Motivation, problem statement, and prior work...&amp;#34;
├── Methodology [pages 4-8]
│ ├── Data Collection [pages 4-5]
│ ├── Model Architecture [pages 5-7]
│ └── Training Procedure [pages 7-8]
├── Results [pages 9-12]
│ ├── Quantitative Evaluation [pages 9-11]
└── Conclusion [pages 11-12]
└── &amp;#34;Summary of findings and future directions...&amp;#34;
&lt;/code>&lt;/pre>&lt;p>The LLM sees this structure with the summaries and can reason: &lt;em>&amp;ldquo;the question is about conclusions, so I should look at the Conclusion node.&amp;rdquo;&lt;/em> That reasoning is visible, auditable, and directly explainable to any user.&lt;/p>
&lt;hr>
&lt;h3 id="the-code">The Code&lt;/h3>
&lt;p>Setup is minimal : Clone, install dependencies, and set your LLM key.
Then generate the tree locally from a PDF :&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>python3 run_pageindex.py --pdf_path document.pdf &lt;span style="color:#8045ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8045ff">&lt;/span> --if-add-node-summary yes &lt;span style="color:#8045ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8045ff">&lt;/span> --if-add-node-text yes
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Load the result and set up your LLM client:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">pageindex.utils&lt;/span> &lt;span style="color:#00a8c8">as&lt;/span> &lt;span style="color:#111">utils&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">openai&lt;/span>&lt;span style="color:#f92672">,&lt;/span> &lt;span style="color:#111">json&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">with&lt;/span> &lt;span style="color:#111">open&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;results/document_structure.json&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#00a8c8">as&lt;/span> &lt;span style="color:#111">f&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">tree&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">json&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">load&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">f&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">utils&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">print_tree&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">tree&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">call_llm&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">prompt&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">model&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#34;gpt-4.1&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">temperature&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">client&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">openai&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">AsyncOpenAI&lt;/span>&lt;span style="color:#111">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">response&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#00a8c8">await&lt;/span> &lt;span style="color:#111">client&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">chat&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">completions&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">create&lt;/span>&lt;span style="color:#111">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">model&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">model&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">messages&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">[{&lt;/span>&lt;span style="color:#d88200">&amp;#34;role&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;user&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;content&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">prompt&lt;/span>&lt;span style="color:#111">}],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">temperature&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">temperature&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">response&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">choices&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">message&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">content&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">strip&lt;/span>&lt;span style="color:#111">()&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>At query time, strip the full text out of the tree, show it to the LLM, and ask for the relevant nodes:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">query&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#d88200">&amp;#34;What are the main conclusions?&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">tree_without_text&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">utils&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">remove_fields&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">tree&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">copy&lt;/span>&lt;span style="color:#111">(),&lt;/span> &lt;span style="color:#111">fields&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#39;text&amp;#39;&lt;/span>&lt;span style="color:#111">])&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">search_prompt&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d88200">You are given a question and a tree structure of a document.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d88200">Each node contains a node id, title, and summary.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d88200">Find all nodes likely to contain the answer.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d88200">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d88200">Question: &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">query&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d88200">Document tree: &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">json&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">dumps&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">tree_without_text&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">indent&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">2&lt;/span>&lt;span style="color:#111">)&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d88200">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d88200">Reply in JSON:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d88200">&lt;/span>&lt;span style="color:#8045ff">{{&lt;/span>&lt;span style="color:#d88200">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d88200"> &amp;#34;thinking&amp;#34;: &amp;#34;&amp;lt;your reasoning&amp;gt;&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d88200"> &amp;#34;node_list&amp;#34;: [&amp;#34;node_id_1&amp;#34;, &amp;#34;node_id_2&amp;#34;]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d88200">&lt;/span>&lt;span style="color:#8045ff">}}&lt;/span>&lt;span style="color:#d88200">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d88200">&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">tree_search_result&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">call_llm&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">search_prompt&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Then extract text only from the selected nodes and generate the answer:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">node_map&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">utils&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">create_node_mapping&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">tree&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">result&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">json&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">loads&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">tree_search_result&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">node_list&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">result&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;node_list&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">relevant_content&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#d88200">&amp;#34;&lt;/span>&lt;span style="color:#8045ff">\n\n&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">join&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">node_map&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#111">nid&lt;/span>&lt;span style="color:#111">][&lt;/span>&lt;span style="color:#d88200">&amp;#34;text&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span> &lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">nid&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">node_list&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">answer&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#00a8c8">await&lt;/span> &lt;span style="color:#111">call_llm&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;Answer based on context:&lt;/span>&lt;span style="color:#8045ff">\n\n&lt;/span>&lt;span style="color:#d88200">Question: &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">query&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#8045ff">\n&lt;/span>&lt;span style="color:#d88200">Context: &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">relevant_content&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;hr>
&lt;h3 id="stateless-by-design-storable-if-needed">Stateless by Design, Storable if Needed&lt;/h3>
&lt;p>Because the index is just JSON, the whole system is flexible about state. You can run it entirely in memory for small queries, or persist the tree to disk, a database, or an object store, you do you.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">json&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># persist&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">with&lt;/span> &lt;span style="color:#111">open&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;doc_tree.json&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;w&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#00a8c8">as&lt;/span> &lt;span style="color:#111">f&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">json&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">dump&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">tree&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">f&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># restore&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">with&lt;/span> &lt;span style="color:#111">open&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;doc_tree.json&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#00a8c8">as&lt;/span> &lt;span style="color:#111">f&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">tree&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">json&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">load&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">f&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This is meaningful in practice. Vector databases introduce a whole infrastructure layer: embedding models, database extensions, fancy fusion algorithm. PageIndex&amp;rsquo;s index is a JSON file. It integrates with whatever you already have,an S3 bucket, a Redis cache,just some memory. No additional infrastructure required.&lt;/p>
&lt;hr>
&lt;h3 id="structure-aware-chunking-vs-fixed-size-chunking">Structure-Aware Chunking vs Fixed-Size Chunking&lt;/h3>
&lt;p>This is perhaps the most underappreciated difference.&lt;/p>
&lt;p>Traditional RAG cuts documents into fixed-size chunks, typically 512 or 1024 tokens, with some overlap to avoid losing context. The problem is that documents are not uniformly structured. A single section might be 200 tokens; another might be 3000. A fixed-size chunk will routinely split a coherent argument mid-sentence or merge the end of one section with the start of an unrelated one.&lt;/p>
&lt;pre tabindex="0">&lt;code>Traditional RAG chunking (fixed-size):
│◄── 512 tokens ──►│◄── 512 tokens ──►│◄── 512 tokens ──►│
[intro...][ch1 end][ch2 start...mid ][...ch2 end][ch3...]
PageIndex chunking (structure-aware):
│◄── Introduction ──►│◄─────── Chapter 2 ─────────►│◄── Chapter 3 ──►│
[coherent unit ] [coherent unit ] [coherent unit ]
&lt;/code>&lt;/pre>&lt;p>Structure-aware chunks are semantically complete. When shown to the user as a source reference, they read like a passage — not like a sentence that got cut off because a token counter hit a limit.&lt;/p>
&lt;hr>
&lt;h3 id="scaling-limitations">Scaling Limitations&lt;/h3>
&lt;p>PageIndex is not a silver bullet. It is fundamentally an in-context approach: the entire tree (without text) is passed to the LLM at query time. For very long documents with deep, granular structure, this tree can itself become large. The LLM must process it in a single context window.&lt;/p>
&lt;p>It is worth being honest about this. But it is equally worth being honest about the fact that &lt;strong>standard RAG also does not excel at scale&lt;/strong>. Top-k retrieval over large corpora produces noisy results; relevance degrades as the corpus grows and context bloating is real.&lt;/p>
&lt;p>For the use cases where it fits: long structured documents, regulatory filings, technical manuals, research papers, contracts PageIndex is genuinely strong. &lt;a href="https://github.com/VectifyAI/PageIndex">FinanceBench results&lt;/a> report ~98.7% accuracy on financial document QA.&lt;/p>
&lt;hr>
&lt;h3 id="conclusion">Conclusion&lt;/h3>
&lt;p>PageIndex is a good example of a retrieval approach that optimises for the right thing. Not just accuracy, but &lt;strong>explainability&lt;/strong>. The retrieval path is a reasoning trace. The chunks are coherent sections. The index is a plain JSON file.&lt;/p>
&lt;p>None of this is magic. It is essentially the same thing a well-organised student does when they open a textbook. The insight is just recognising that human information retrieval is already an excellent algorithm, and that replicating it is could be better than replacing it with cosine similarity.&lt;/p>
&lt;p>The official repo and cookbook are at &lt;a href="https://github.com/VectifyAI/PageIndex">github.com/VectifyAI/PageIndex&lt;/a> if you want to run the full notebook.&lt;/p>
&lt;p>As a recovering statistician, I am profoundly happy when I can make an AI system a bit more explainable, and profoundly unhappy when I can&amp;rsquo;t.&lt;/p></description><author>Calvin Tran</author><guid>http://gabelfra1.github.io/gabelfra.github.io/posts/pageindex/</guid><pubDate>Tue, 12 May 2026 00:00:00 +0000</pubDate></item><item><title>Do Foundational Models Actually Work for Forecasting?</title><link>http://gabelfra1.github.io/gabelfra.github.io/posts/timesfm/</link><description>&lt;h3 id="traditional-forecasting">Traditional forecasting&lt;/h3>
&lt;p>Every forecasting practitioner from a math/stats background knows the ritual.
You get a new series, run the ADF test, differentiate, and hope that the series is stationary. You plot the ACF and PACF, count the significant lags, make a guess at &lt;code>p&lt;/code> and &lt;code>q&lt;/code>, run a grid search over AIC, wait, then, once you have figured out the period, you do it all over again with a seasonal component.&lt;/p>
&lt;p>For the uninitiated, you can find a more in-depth explanation in the bible of forecasting:
&lt;a href="https://otexts.com/fpp3/">Forecasting: Principles and Practice&lt;/a>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Step 1: determine d via ADF + KPSS&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">find_d&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">series&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">max_d&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">2&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">ser&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">series&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">copy&lt;/span>&lt;span style="color:#111">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">d&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">range&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">max_d&lt;/span> &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">adf_p&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">adfuller&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">ser&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">dropna&lt;/span>&lt;span style="color:#111">(),&lt;/span> &lt;span style="color:#111">autolag&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#34;AIC&amp;#34;&lt;/span>&lt;span style="color:#111">)[&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">kpss_p&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">kpss&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">ser&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">dropna&lt;/span>&lt;span style="color:#111">(),&lt;/span> &lt;span style="color:#111">regression&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#34;c&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">nlags&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#34;auto&amp;#34;&lt;/span>&lt;span style="color:#111">)[&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">if&lt;/span> &lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">adf_p&lt;/span> &lt;span style="color:#f92672">&amp;lt;&lt;/span> &lt;span style="color:#ae81ff">0.05&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">and&lt;/span> &lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">kpss_p&lt;/span> &lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#ae81ff">0.05&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">d&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">ser&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">ser&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">diff&lt;/span>&lt;span style="color:#111">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">max_d&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Step 2: detect seasonal period from the periodogram&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">s&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">detect_season&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">m4_series&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Step 3: AIC grid search over (p,q) x (P,Q)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">p&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">q&lt;/span>&lt;span style="color:#111">),&lt;/span> &lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">P&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">Q&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">itertools&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">product&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">search_pq&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">search_PQ&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">aic&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">SARIMAX&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">data&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">order&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">p&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">d&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">q&lt;/span>&lt;span style="color:#111">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">seasonal_order&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">P&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">D&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">Q&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">s&lt;/span>&lt;span style="color:#111">))&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">fit&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">disp&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#00a8c8">False&lt;/span>&lt;span style="color:#111">)&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">aic&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">...&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>If you wanted to modernize your forecasting approach and follow what practitioners on Kaggle are doing, you could switch to a machine learning model like LightGBM. However, with LightGBM, you first need to engineer lag features, decide how many lags to include, add rolling statistics, and tune hyperparameters such as &lt;code>num_leaves&lt;/code>, &lt;code>learning_rate&lt;/code>, and &lt;code>subsample&lt;/code> using tools like Optuna before you can even think of generating a single forecast.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">study&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">optuna&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">create_study&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">direction&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#34;minimize&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">sampler&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">optuna&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">samplers&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">TPESampler&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">seed&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">42&lt;/span>&lt;span style="color:#111">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">study&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">optimize&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">objective&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">n_trials&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">40&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">show_progress_bar&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#00a8c8">True&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">best_lgb_params&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">study&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">best_params&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The problem is worse than just tedium: &lt;strong>none of this work transfers between projects&lt;/strong>. You accumulate better instincts and reusable code snippets, but every new series forces you to restart the entire process from scratch.&lt;/p>
&lt;h3 id="deep-learning-did-not-solve-the-problem">Deep learning did not solve the problem&lt;/h3>
&lt;p>The obvious hope was that deep learning would do what it did for images and text: learn a universal representation and make the hand-crafted pipeline obsolete. It did not work out that way.&lt;/p>
&lt;p>The M4 competition (2018), covering 100,000 real-world series, was the first large-scale empirical test. The winner was a hybrid ES-RNN, not a pure deep learning model, but a classical Exponential Smoothing model with an RNN on top. Pure neural methods consistently underperformed compared to statistical baselines that had been around for decades.&lt;/p>
&lt;p>The M5 and M6 competitions confirmed the pattern. The use of LightGBM with careful feature engineering repeatedly beat deep learning architectures.
The community largely concluded that deep learning was simply too cumbersome to train on short series, too prone to overfitting, and too sensitive to architecture choices to be worth the cost of training.&lt;/p>
&lt;p>The fundamental problem was that every deep learning model still needed to be trained from scratch on each dataset. It was essentially a more expensive version of the same ritual.&lt;/p>
&lt;h3 id="what-timesfm-changes">What TimesFM changes&lt;/h3>
&lt;p>Google Research published &lt;a href="https://arxiv.org/abs/2310.10688">A decoder-only foundation model for time-series forecasting&lt;/a> in 2023.
I&amp;rsquo;ve noticed the advances in transformer models when they started to creep into the industry I work in, aka banking, but only recently, while reading the paper &lt;a href="https://arxiv.org/html/2604.08649v1">PRAGMA: Revolut Foundation Model&lt;/a>, did it click.
The core idea is simple: pre-train a large transformer on an enormous and diverse corpus of time series data, then use it zero-shot on any new series — no hyperparameter search, no statistical tests.&lt;/p>
&lt;p>&lt;strong>TimesFM is to forecasting what GPT was to NLP: a single pre-trained model that generalises across tasks it has never seen.&lt;/strong>&lt;/p>
&lt;p>This is the part that matters for practitioners. After all the machinery described above — stationarity tests, seasonal detection, AIC search, Optuna — the TimesFM inference path is:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">timesfm&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">tfm&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">timesfm&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">TimesFm&lt;/span>&lt;span style="color:#111">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">hparams&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">timesfm&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">TimesFmHparams&lt;/span>&lt;span style="color:#111">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">backend&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#34;torch&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">horizon_len&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">14&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">context_len&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">512&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">checkpoint&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">timesfm&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">TimesFmCheckpoint&lt;/span>&lt;span style="color:#111">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">huggingface_repo_id&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#34;google/timesfm-1.0-200m-pytorch&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">point_forecast&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">_&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">tfm&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">forecast&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">inputs&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#111">train_data&lt;/span>&lt;span style="color:#111">],&lt;/span> &lt;span style="color:#111">freq&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">])&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>There is no &lt;code>fit()&lt;/code>. The model has never seen your series. You hand it the historical values, and it returns a forecast. The entire statistical/ML ritual is replaced by a forward pass through a pre-trained network.&lt;/p>
&lt;h3 id="running-the-same-backtesting-as-sarima-and-lightgbm">Running the same backtesting as SARIMA and LightGBM&lt;/h3>
&lt;p>To make this a fair comparison, all three models were evaluated on M4 Daily series D2047 — 8,533 daily observations — using identical &lt;code>TimeSeriesSplit&lt;/code> cross-validation with five folds and a 14-step forecast horizon.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> &lt;span style="color:#111">sklearn.model_selection&lt;/span> &lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">TimeSeriesSplit&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">n_splits&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">5&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">test_size&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">14&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">tscv&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">TimeSeriesSplit&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">n_splits&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">n_splits&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">test_size&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">test_size&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># SARIMA: fit a new model per fold with the tuned (p,d,q)(P,D,Q,s)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">fold&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">train_idx&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">test_idx&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">enumerate&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">tscv&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">split&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">m4_series&lt;/span>&lt;span style="color:#111">)):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">fit&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">SARIMAX&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">train_data&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">order&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">best_order&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">seasonal_order&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">best_sorder&lt;/span>&lt;span style="color:#111">)&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">fit&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">disp&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#00a8c8">False&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">preds&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">fit&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">forecast&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">steps&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">test_size&lt;/span>&lt;span style="color:#111">)&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">values&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># LightGBM: train a new model per fold with Optuna-tuned params&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">fold&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">train_idx&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">test_idx&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">enumerate&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">tscv&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">split&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">m4_series&lt;/span>&lt;span style="color:#111">)):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">model&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">lgb&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">LGBMRegressor&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#f92672">**&lt;/span>&lt;span style="color:#111">best_lgb_params&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">model&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">fit&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">X_tr&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">y_tr&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># recursive prediction ...&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># TimesFM: no training, same context each fold&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">fold&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">train_idx&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">test_idx&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">enumerate&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">tscv&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">split&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">m4_series&lt;/span>&lt;span style="color:#111">)):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">point_forecast&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">_&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">tfm&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">forecast&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">inputs&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#111">train_data&lt;/span>&lt;span style="color:#111">],&lt;/span> &lt;span style="color:#111">freq&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">])&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">preds&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">point_forecast&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>SARIMA requires running the full stationarity and order-selection pipeline before the loop. LightGBM requires several Optuna trials on an inner cross-validation. TimesFM requires none of that — the same three-line setup serves every fold unchanged.&lt;/p>
&lt;p>The result: &lt;strong>TimesFM achieves competitive MAE without a single line of training code&lt;/strong>, while SARIMA and LightGBM each needed a bespoke calibration pipeline just to participate.&lt;/p>
&lt;figure>
&lt;img src="../../images/timesfm_cv_mae.png" alt="time_series_cv">
&lt;/figure>
&lt;h3 id="why-this-could-democratise-forecasting">Why this could democratise forecasting&lt;/h3>
&lt;p>TimesFM collapses the forecasting stack. A developer with no background in time-series statistics can load the model, pass in a dataframe, and get a probabilistic forecast within seconds.&lt;/p>
&lt;p>This mirrors exactly what happened to NLP. Before the transformer era, building a production sentiment classifier for customer service calls meant curating internal transcriptions, collecting customer feedback labels, engineering linguistic features, selecting and tuning a model, and repeating this process for every new business domain or language. After GPT, it is possible to load a pre-trained model, pass in your call transcripts, and get sentiment predictions without annotation pipelines. The barrier to entry collapsed by an order of magnitude, and the volume of NLP applications in production exploded.&lt;/p>
&lt;h3 id="the-limits-are-real">The limits are real&lt;/h3>
&lt;p>I didn&amp;rsquo;t spend five years studying statistical theory and another five as a data scientist just to watch it all get dismissed. Time series is &lt;em>weird&lt;/em> in ways that GPT&amp;rsquo;s text never had to deal with. Financial returns don&amp;rsquo;t behave like energy demand. Sensor data from a factory floor look nothing like web traffic. The distribution shift between Google&amp;rsquo;s pre-training corpus and your specific problem can be absolutely massive.&lt;/p>
&lt;p>Fine-tuning on domain-specific data can help close much of that gap, and Google&amp;rsquo;s own benchmarks show that even a few hundred in-domain examples significantly improve TimesFM&amp;rsquo;s accuracy. But that is still a fundamentally different burden than training SARIMA from scratch — it is adaptation, not construction.&lt;/p>
&lt;h3 id="conclusion">Conclusion&lt;/h3>
&lt;p>Over the past decade, the pattern in machine learning has been consistent: provided that a large enough pre-training corpus is available, foundation models eventually outperform or at the very least match task-specific models trained from scratch for a fraction of the deployment cost. Text, images, audio, code — the story is always the same.&lt;/p>
&lt;p>Time series proved more resistant simply because the data is messier, the frequency and domain vary wildly, and the benchmarks were designed around the assumption that every model would be trained from scratch. TimesFM, and the family of models following it, challenge this core assumption.&lt;/p>
&lt;p>Whether TimesFM specifically becomes the standard, or is surpassed by the next generation of temporal foundation models, the direction is now clear. The era of bespoke per-series models is ending.&lt;/p></description><author>Calvin Tran</author><guid>http://gabelfra1.github.io/gabelfra.github.io/posts/timesfm/</guid><pubDate>Sat, 18 Apr 2026 00:00:00 +0000</pubDate></item><item><title>Building effective agents</title><link>http://gabelfra1.github.io/gabelfra.github.io/posts/agentic/</link><description>&lt;h3 id="agentic-pattern">Agentic pattern&lt;/h3>
&lt;p>We&amp;rsquo;re doing something different today.
Instead of a typical article, this is a code along tutorial based on Anthropic&amp;rsquo;s foundational blogpost on agentic patterns : &lt;a href="https://www.anthropic.com/engineering/building-effective-agents">Building effective agents&lt;/a>.&lt;/p>
&lt;p>The objective of this article is to demystify the complexity of agentic workflows by presenting a simple and clear Python implementation of the core concepts defined in the Anthropic article.&lt;/p>
&lt;h3 id="0-set-up">0) Set-up&lt;/h3>
&lt;p>Replicating this exercise is possible with any LLM provider that is compatible with the &lt;a href="http://platform.openai.com/docs/libraries">Openai Client library&lt;/a> and the set-up is minimal.
We just need the LLM client, pydantic for &lt;a href="https://ai.pydantic.dev/output/">structured output&lt;/a> and json to parse the response.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># --- Libraries ---&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">openai&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> &lt;span style="color:#111">pydantic&lt;/span> &lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">BaseModel&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> &lt;span style="color:#111">pydantic&lt;/span> &lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">BaseModel&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">Field&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">json&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> &lt;span style="color:#111">typing&lt;/span> &lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">Literal&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">TypedDict&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="1-prompt-chaining">1) Prompt chaining&lt;/h3>
&lt;p>&lt;strong>Prompt chaining decomposes a task into a sequence of steps, where each LLM call processes the output of the previous one&lt;/strong>.&lt;/p>
&lt;p>In this simple example we are going to create a chain (sequence) of prompts (generate_joke,improve_joke,polish_joke) in order to generate an output (a joke).&lt;/p>
&lt;p>The chain represents the simplest workflow pattern, marking the first step in complexity beyond standard one-shot prompting for generating answers.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># --- State ---&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">state&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;topic&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;joke&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;improved_joke&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;final_joke&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># --- Functions ---&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">generate_joke&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">topic&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">str&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">-&amp;gt;&lt;/span> &lt;span style="color:#111">str&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">response&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">client&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">chat&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">completions&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">create&lt;/span>&lt;span style="color:#111">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">messages&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">[{&lt;/span>&lt;span style="color:#d88200">&amp;#34;role&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;user&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;content&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;Write a joke about &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">topic&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200"> with just single a sentence&amp;#34;&lt;/span>&lt;span style="color:#111">}],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">response&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">choices&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">message&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">content&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">improve_joke&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">joke&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">str&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">-&amp;gt;&lt;/span> &lt;span style="color:#111">str&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">response&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">client&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">chat&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">completions&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">create&lt;/span>&lt;span style="color:#111">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">messages&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">[{&lt;/span>&lt;span style="color:#d88200">&amp;#34;role&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;user&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;content&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;Make this joke funnier by adding wordplay or puns: &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">joke&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>&lt;span style="color:#111">}],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">response&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">choices&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">message&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">content&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">polish_joke&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">joke&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">str&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">-&amp;gt;&lt;/span> &lt;span style="color:#111">str&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">response&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">client&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">chat&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">completions&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">create&lt;/span>&lt;span style="color:#111">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">messages&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">[{&lt;/span>&lt;span style="color:#d88200">&amp;#34;role&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;user&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;content&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d88200"> Write a short, funny joke in the following format:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d88200"> Why did [subject] [action]?
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d88200"> To [funny reason related to the subject]!
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d88200"> The joke should be based on the following : &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">joke&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d88200"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#111">}],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">response&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">choices&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">message&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">content&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">check_punchline&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">joke&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">str&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">-&amp;gt;&lt;/span> &lt;span style="color:#111">bool&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">joke&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">count&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;?&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">&amp;gt;=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># --- Workflow Execution ---&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">run_workflow&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">topic&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">str&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;topic&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">topic&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;joke&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">generate_joke&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">topic&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;improved_joke&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">improve_joke&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;joke&amp;#34;&lt;/span>&lt;span style="color:#111">])&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;final_joke&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">polish_joke&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;improved_joke&amp;#34;&lt;/span>&lt;span style="color:#111">])&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">if&lt;/span> &lt;span style="color:#111">check_punchline&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;final_joke&amp;#34;&lt;/span>&lt;span style="color:#111">]):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">print&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;final_joke&amp;#34;&lt;/span>&lt;span style="color:#111">])&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">else&lt;/span> &lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">print&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;joke did not passed quality gate&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">state&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># --- Run ---&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">result&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">run_workflow&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;cats at work&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="2-routing">2) Routing&lt;/h3>
&lt;p>&lt;strong>Routing classifies an input and directs it to a specialized followup task&lt;/strong>.&lt;/p>
&lt;p>In this example, we use an initial LLM call to determine the next step whether to generate a poem, a story, or a joke, and then execute only the selected route.&lt;/p>
&lt;p>The routing pattern is particularly interesting because it leverages specialization in prompts and data sources. Instead of having one generalist &amp;lsquo;agent&amp;rsquo; that knows everything, it is more efficient to employ multiple specialized agents that the router can direct tasks to as needed.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># --- Schema for routing ---&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">class&lt;/span> &lt;span style="color:#75af00">Route&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">BaseModel&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">step&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">Literal&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;poem&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;story&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;joke&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">Field&lt;/span>&lt;span style="color:#111">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">None&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">description&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#34;The next step in the routing process&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># --- State ---&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">class&lt;/span> &lt;span style="color:#75af00">State&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">TypedDict&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">input&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">str&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">decision&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">str&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">output&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">str&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># --- Router using structured output ---&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">llm_call_router&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">State&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">-&amp;gt;&lt;/span> &lt;span style="color:#111">dict&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">response&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">client&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">chat&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">completions&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">create&lt;/span>&lt;span style="color:#111">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">messages&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">[&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">{&lt;/span>&lt;span style="color:#d88200">&amp;#34;role&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;system&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;content&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;Route the input to story, joke, or poem based on the user&amp;#39;s request.&amp;#34;&lt;/span>&lt;span style="color:#111">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">{&lt;/span>&lt;span style="color:#d88200">&amp;#34;role&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;user&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;content&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;input&amp;#34;&lt;/span>&lt;span style="color:#111">]},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">response_format&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;type&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;json_schema&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;json_schema&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;name&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;route&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;schema&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;type&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;object&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;properties&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;step&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;type&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;string&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;enum&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;poem&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;story&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;joke&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;required&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;step&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">decision&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">json&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">loads&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">response&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">choices&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">message&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">content&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">{&lt;/span>&lt;span style="color:#d88200">&amp;#34;decision&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">decision&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;step&amp;#34;&lt;/span>&lt;span style="color:#111">]}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># --- Nodes ---&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">llm_call_story&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">State&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">-&amp;gt;&lt;/span> &lt;span style="color:#111">dict&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">response&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">client&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">chat&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">completions&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">create&lt;/span>&lt;span style="color:#111">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">messages&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">[{&lt;/span>&lt;span style="color:#d88200">&amp;#34;role&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;user&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;content&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;Write a story about: &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#39;input&amp;#39;&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>&lt;span style="color:#111">}],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">{&lt;/span>&lt;span style="color:#d88200">&amp;#34;output&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">response&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">choices&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">message&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">content&lt;/span>&lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">llm_call_joke&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">State&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">-&amp;gt;&lt;/span> &lt;span style="color:#111">dict&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">response&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">client&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">chat&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">completions&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">create&lt;/span>&lt;span style="color:#111">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">messages&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">[{&lt;/span>&lt;span style="color:#d88200">&amp;#34;role&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;user&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;content&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;Write a joke about: &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#39;input&amp;#39;&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>&lt;span style="color:#111">}],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">{&lt;/span>&lt;span style="color:#d88200">&amp;#34;output&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">response&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">choices&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">message&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">content&lt;/span>&lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">llm_call_poem&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">State&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">-&amp;gt;&lt;/span> &lt;span style="color:#111">dict&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">response&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">client&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">chat&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">completions&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">create&lt;/span>&lt;span style="color:#111">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">messages&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">[{&lt;/span>&lt;span style="color:#d88200">&amp;#34;role&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;user&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;content&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;Write a poem about: &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#39;input&amp;#39;&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>&lt;span style="color:#111">}],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">{&lt;/span>&lt;span style="color:#d88200">&amp;#34;output&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">response&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">choices&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">message&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">content&lt;/span>&lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># --- Routing Logic ---&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">route_decision&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">State&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">-&amp;gt;&lt;/span> &lt;span style="color:#111">str&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">if&lt;/span> &lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;decision&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span> &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#d88200">&amp;#34;story&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#d88200">&amp;#34;story&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">elif&lt;/span> &lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;decision&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span> &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#d88200">&amp;#34;joke&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#d88200">&amp;#34;joke&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">elif&lt;/span> &lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;decision&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span> &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#d88200">&amp;#34;poem&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#d88200">&amp;#34;poem&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># --- Workflow Execution ---&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">run_workflow&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">user_input&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">str&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">State&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">{&lt;/span>&lt;span style="color:#d88200">&amp;#34;input&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">user_input&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;decision&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;output&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># Step 1: Route&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">route_result&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">llm_call_router&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;decision&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">route_result&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;decision&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># Step 2: Execute based on decision&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">if&lt;/span> &lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;decision&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span> &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#d88200">&amp;#34;story&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">state&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">update&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">llm_call_story&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">elif&lt;/span> &lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;decision&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span> &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#d88200">&amp;#34;joke&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">state&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">update&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">llm_call_joke&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">elif&lt;/span> &lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;decision&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span> &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#d88200">&amp;#34;poem&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">state&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">update&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">llm_call_poem&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">state&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># --- Run ---&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">result&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">run_workflow&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;Write me a short story about cats at work&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="3-parallelization">3) Parallelization&lt;/h3>
&lt;p>&lt;strong>Breaking a task into independent subtasks run in parallel&lt;/strong>.&lt;/p>
&lt;p>Unlike the previous example, which decided between a poem, a story, or a joke, this case involves generating all three in parallel and then aggregating the results.&lt;/p>
&lt;p>This is a typical pattern across computer science: when a problem is too complex or slow for a single computation, it is broken down into simpler ones to achieve greater efficiency and reduced processing time.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># --- State ---&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">class&lt;/span> &lt;span style="color:#75af00">State&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">TypedDict&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">topic&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">str&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">joke&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">str&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">story&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">str&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">poem&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">str&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">combined_output&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">str&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># --- LLM Call Functions ---&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">call_llm&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">prompt&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">str&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">-&amp;gt;&lt;/span> &lt;span style="color:#111">str&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">response&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">client&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">chat&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">completions&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">create&lt;/span>&lt;span style="color:#111">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">messages&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">[{&lt;/span>&lt;span style="color:#d88200">&amp;#34;role&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;user&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;content&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">prompt&lt;/span>&lt;span style="color:#111">}],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">response&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">choices&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">message&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">content&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">call_llm_1&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">State&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">-&amp;gt;&lt;/span> &lt;span style="color:#111">dict&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">{&lt;/span>&lt;span style="color:#d88200">&amp;#34;joke&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">call_llm&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;Write a joke about &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#39;topic&amp;#39;&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>&lt;span style="color:#111">)}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">call_llm_2&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">State&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">-&amp;gt;&lt;/span> &lt;span style="color:#111">dict&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">{&lt;/span>&lt;span style="color:#d88200">&amp;#34;story&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">call_llm&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;Write a story about &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#39;topic&amp;#39;&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>&lt;span style="color:#111">)}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">call_llm_3&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">State&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">-&amp;gt;&lt;/span> &lt;span style="color:#111">dict&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">{&lt;/span>&lt;span style="color:#d88200">&amp;#34;poem&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">call_llm&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;Write a poem about &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#39;topic&amp;#39;&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>&lt;span style="color:#111">)}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">aggregator&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">State&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">-&amp;gt;&lt;/span> &lt;span style="color:#111">dict&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">combined&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;Here&amp;#39;s a story, joke, and poem about &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#39;topic&amp;#39;&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">!&lt;/span>&lt;span style="color:#8045ff">\n\n&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">combined&lt;/span> &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;STORY:&lt;/span>&lt;span style="color:#8045ff">\n&lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#39;story&amp;#39;&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#8045ff">\n\n&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">combined&lt;/span> &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;JOKE:&lt;/span>&lt;span style="color:#8045ff">\n&lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#39;joke&amp;#39;&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#8045ff">\n\n&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">combined&lt;/span> &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;POEM:&lt;/span>&lt;span style="color:#8045ff">\n&lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#39;poem&amp;#39;&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">{&lt;/span>&lt;span style="color:#d88200">&amp;#34;combined_output&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">combined&lt;/span>&lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># --- Workflow Execution ---&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">run_workflow&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">topic&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">str&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">-&amp;gt;&lt;/span> &lt;span style="color:#111">State&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">State&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">{&lt;/span>&lt;span style="color:#d88200">&amp;#34;topic&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">topic&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;joke&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;story&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;poem&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;combined_output&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># Run tasks in parallel (or sequentially for simplicity)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">state&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">update&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">call_llm_1&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">state&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">update&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">call_llm_2&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">state&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">update&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">call_llm_3&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># Aggregate results&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">state&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">update&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">aggregator&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">state&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># --- Run ---&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">result&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">run_workflow&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;cats&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="4-evaluator-optimizer">4) Evaluator-optimizer&lt;/h3>
&lt;p>&lt;strong>In the evaluator-optimizer workflow, one LLM call generates a response while another provides evaluation and feedback in a loop&lt;/strong>.&lt;/p>
&lt;p>In this example, we implement a feedback loop: the evaluator grades the generated joke and returns feedback to the generator until the resulting joke is deemed satisfactory.&lt;/p>
&lt;p>This is a highly interesting pattern as it represents a significant step toward true autonomy. In this case, two &amp;lsquo;agents&amp;rsquo; collaboratively &amp;rsquo;think&amp;rsquo; about a problem until they reach consensus that it is solved, operating without any human intervention or feedback.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">class&lt;/span> &lt;span style="color:#75af00">State&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">TypedDict&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">joke&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">str&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">topic&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">str&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">feedback&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">str&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">funny_or_not&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">str&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># --- Schema for evaluation ---&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">llm_call_evaluator&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">State&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">-&amp;gt;&lt;/span> &lt;span style="color:#111">dict&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">response&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">client&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">chat&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">completions&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">create&lt;/span>&lt;span style="color:#111">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">messages&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">[&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">{&lt;/span>&lt;span style="color:#d88200">&amp;#34;role&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;system&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;content&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;Grade the joke as funny or not funny and provide feedback if needed.&amp;#34;&lt;/span>&lt;span style="color:#111">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">{&lt;/span>&lt;span style="color:#d88200">&amp;#34;role&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;user&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;content&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;Joke: &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#39;joke&amp;#39;&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>&lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">response_format&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;type&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;json_schema&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;json_schema&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;name&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;feedback&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;schema&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;type&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;object&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;properties&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;grade&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">{&lt;/span>&lt;span style="color:#d88200">&amp;#34;type&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;string&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;enum&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;funny&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;not funny&amp;#34;&lt;/span>&lt;span style="color:#111">]},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;feedback&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">{&lt;/span>&lt;span style="color:#d88200">&amp;#34;type&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;string&amp;#34;&lt;/span>&lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;required&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;grade&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;feedback&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">result&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">json&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">loads&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">response&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">choices&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">message&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">content&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">{&lt;/span>&lt;span style="color:#d88200">&amp;#34;funny_or_not&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">result&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;grade&amp;#34;&lt;/span>&lt;span style="color:#111">],&lt;/span> &lt;span style="color:#d88200">&amp;#34;feedback&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">result&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;feedback&amp;#34;&lt;/span>&lt;span style="color:#111">]}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># --- Joke Generator ---&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">llm_call_generator&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">State&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">-&amp;gt;&lt;/span> &lt;span style="color:#111">dict&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">if&lt;/span> &lt;span style="color:#111">state&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">get&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;feedback&amp;#34;&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">prompt&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;Write a joke about &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#39;topic&amp;#39;&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200"> but improve it based on this feedback: &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#39;feedback&amp;#39;&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">else&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">prompt&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;Write a joke about &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#39;topic&amp;#39;&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">response&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">client&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">chat&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">completions&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">create&lt;/span>&lt;span style="color:#111">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">messages&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">[{&lt;/span>&lt;span style="color:#d88200">&amp;#34;role&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;user&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;content&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">prompt&lt;/span>&lt;span style="color:#111">}],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">{&lt;/span>&lt;span style="color:#d88200">&amp;#34;joke&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">response&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">choices&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">message&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">content&lt;/span>&lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># --- Workflow ---&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">run_workflow&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">topic&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">str&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">max_loops&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">int&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">5&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">State&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">{&lt;/span>&lt;span style="color:#d88200">&amp;#34;topic&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">topic&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;joke&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;feedback&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;funny_or_not&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">i&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">range&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">max_loops&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># Generate joke&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">state&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">update&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">llm_call_generator&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># Evaluate joke&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">eval_result&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">llm_call_evaluator&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">state&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">update&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">eval_result&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">if&lt;/span> &lt;span style="color:#111">state&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;funny_or_not&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span> &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#d88200">&amp;#34;funny&amp;#34;&lt;/span> &lt;span style="color:#f92672">and&lt;/span> &lt;span style="color:#111">i&lt;/span>&lt;span style="color:#f92672">&amp;gt;&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span> &lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">print&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34; -- Joke accepted! --&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">break&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">else&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">print&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;Joke rejected, improving...&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">state&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># --- Run ---&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">result&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">run_workflow&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;cats at work&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="5-agents">5) Agents&lt;/h3>
&lt;p>&lt;strong>Agents are emerging in key capabilities—understanding complex inputs, engaging in reasoning and planning, using tools reliably, and recovering from errors&lt;/strong>.&lt;/p>
&lt;p>Finally, we demonstrate an example of a truly autonomous agent. Though limited to arithmetic tools in this case, the agent can receive a task, reason, plan which tools to use, execute those tools, and autonomously stop the reasoning process when it is ready to generate the final answer to the user.&lt;/p>
&lt;figure>
&lt;img src="../../images/anthropic.png"
alt="agentic_pattern">
&lt;/figure>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># --- Define Python functions ---&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">multiply&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">a&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">int&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">b&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">int&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">-&amp;gt;&lt;/span> &lt;span style="color:#111">int&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">a&lt;/span> &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#111">b&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">add&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">a&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">int&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">b&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">int&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">-&amp;gt;&lt;/span> &lt;span style="color:#111">int&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">a&lt;/span> &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#111">b&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">divide&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">a&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">int&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">b&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">int&lt;/span>&lt;span style="color:#111">)&lt;/span> &lt;span style="color:#f92672">-&amp;gt;&lt;/span> &lt;span style="color:#111">float&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">a&lt;/span> &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#111">b&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># --- Define tool schemas ---&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">tools&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">[&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;name&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;multiply&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;description&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;Multiply two integers&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;parameters&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;type&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;object&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;properties&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;a&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">{&lt;/span>&lt;span style="color:#d88200">&amp;#34;type&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;integer&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;description&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;First integer&amp;#34;&lt;/span>&lt;span style="color:#111">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;b&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">{&lt;/span>&lt;span style="color:#d88200">&amp;#34;type&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;integer&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;description&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;Second integer&amp;#34;&lt;/span>&lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;required&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;a&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;b&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;name&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;add&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;description&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;Add two integers&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;parameters&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;type&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;object&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;properties&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;a&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">{&lt;/span>&lt;span style="color:#d88200">&amp;#34;type&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;integer&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;description&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;First integer&amp;#34;&lt;/span>&lt;span style="color:#111">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;b&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">{&lt;/span>&lt;span style="color:#d88200">&amp;#34;type&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;integer&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;description&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;Second integer&amp;#34;&lt;/span>&lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;required&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;a&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;b&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;name&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;divide&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;description&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;Divide two integers&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;parameters&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;type&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;object&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;properties&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;a&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">{&lt;/span>&lt;span style="color:#d88200">&amp;#34;type&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;integer&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;description&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;First integer&amp;#34;&lt;/span>&lt;span style="color:#111">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;b&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">{&lt;/span>&lt;span style="color:#d88200">&amp;#34;type&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;integer&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;description&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;Second integer&amp;#34;&lt;/span>&lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;required&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;a&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;b&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># --- Map tool names to Python functions ---&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">tools_by_name&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;multiply&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">multiply&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;add&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">add&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;divide&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">divide&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">json&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># --- Workflow ---&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">run_agent&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">user_input&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">str&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">max_iterations&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">int&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">5&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">messages&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">[&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">{&lt;/span>&lt;span style="color:#d88200">&amp;#34;role&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;system&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;content&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;You are a helpful assistant tasked with performing arithmetic on a set of inputs.&amp;#34;&lt;/span>&lt;span style="color:#111">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">{&lt;/span>&lt;span style="color:#d88200">&amp;#34;role&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;user&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;content&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">user_input&lt;/span>&lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">i&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">range&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">max_iterations&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">response&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">client&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">chat&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">completions&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">create&lt;/span>&lt;span style="color:#111">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">model&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">model&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">messages&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">messages&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">tools&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">tools&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">tool_choice&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#34;auto&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">last_message&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">response&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">choices&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">message&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">tool_calls&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">last_message&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">tool_calls&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># Keep the last LLM message in history&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">messages&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">append&lt;/span>&lt;span style="color:#111">({&lt;/span>&lt;span style="color:#d88200">&amp;#34;role&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;assistant&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;content&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">last_message&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">content&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;tool_calls&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">tool_calls&lt;/span>&lt;span style="color:#111">})&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">if&lt;/span> &lt;span style="color:#111">tool_calls&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">print&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>&lt;span style="color:#8045ff">\n&lt;/span>&lt;span style="color:#d88200"> Iteration &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">i&lt;/span>&lt;span style="color:#f92672">+&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">: Tool calls detected&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># Execute tool calls&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">call&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">tool_calls&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">func_name&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">call&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">function&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">name&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">args&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">json&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">loads&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">call&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">function&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">arguments&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># Print tool name and arguments&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">print&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34; Calling tool: &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">func_name&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200"> with arguments: &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">args&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">result&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">tools_by_name&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#111">func_name&lt;/span>&lt;span style="color:#111">](&lt;/span>&lt;span style="color:#f92672">**&lt;/span>&lt;span style="color:#111">args&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># Append tool response&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">messages&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">append&lt;/span>&lt;span style="color:#111">({&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;role&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;tool&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;tool_call_id&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">call&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">id&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;content&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">str&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">result&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">})&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">else&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e"># No tool calls → final answer&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">print&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>&lt;span style="color:#8045ff">\n&lt;/span>&lt;span style="color:#d88200">Final answer after &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">i&lt;/span>&lt;span style="color:#f92672">+&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200"> iterations: &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">last_message&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">content&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">last_message&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">content&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#d88200">&amp;#34;Max iterations reached without a final answer.&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># --- Run ---&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">answer&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">run_agent&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;Please multiply 3 and 4 and divide the result by 2&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="conclusion">Conclusion&lt;/h3>
&lt;p>I hope these examples have helped the reader realise the simplicity behind the patterns for implementing agentic workflows. While using higher-level packages like &lt;a href="https://docs.langchain.com/oss/python/langgraph/workflows-agents">LangChain&lt;/a> offers &amp;lsquo;shorter&amp;rsquo; implementation methods, this often obscures the underlying details. To truly understand these core concepts, I believe a simpler approach using just the API and basic Python is most effective.&lt;/p></description><author>Calvin Tran</author><guid>http://gabelfra1.github.io/gabelfra.github.io/posts/agentic/</guid><pubDate>Wed, 10 Dec 2025 00:00:00 +0000</pubDate></item><item><title>LLM are way too confident</title><link>http://gabelfra1.github.io/gabelfra.github.io/posts/calibration/</link><description>&lt;h3 id="the-paradox-of-high-accuracy-and-low-reliability">The Paradox of High Accuracy and Low Reliability&lt;/h3>
&lt;p>In this article, we&amp;rsquo;ll explore LLM&amp;rsquo;s impressive ability to achieve &lt;a href="https://cdn.openai.com/better-language-models/language_models_are_unsupervised_multitask_learners.pdf">high zero-shot performance on a classification tasks&lt;/a> and at the same time being way too &lt;a href="https://arxiv.org/abs/2505.02151">overconfident&lt;/a> on all of their responses.&lt;/p>
&lt;p>&lt;strong>Calibration&lt;/strong> it ensures that the model &amp;ldquo;knows what it doesn&amp;rsquo;t know.&amp;rdquo;
For instance, if a model assigns a probability of 70% to a collection of predictions, we expect that 70% of those specific predictions will be correct in reality. When a model is perfectly calibrated, you can directly trust its confidence scores as an honest statement of its likelihood of being right.&lt;/p>
&lt;p>GPT can easily classify a sample without any prior fine-tuning but its confidence scores often don&amp;rsquo;t accurately reflect the likelihood of its predictions being correct. This disparity between performance and reliability is a significant challenge for deploying these models in real-world applications.&lt;/p>
&lt;h4 id="the-data">The data&lt;/h4>
&lt;p>The dataset for this article is sourced from scikit-learn (sklearn) open datasets. This is a classic NLP classification problem where the raw data consists of various news articles, and the target variable maps to 20 distinct article topics.&lt;/p>
&lt;p>For the sake of simplifying this demonstration, we filtered the original corpus. Our reduced dataset now exclusively comprises articles belonging to three specific categories: &amp;lsquo;mac&amp;rsquo;, &amp;lsquo;motorcycles&amp;rsquo;, and &amp;lsquo;baseball&amp;rsquo;.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> &lt;span style="color:#111">sklearn.datasets&lt;/span> &lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">fetch_20newsgroups&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">categories_to_fetch&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#39;comp.sys.mac.hardware&amp;#39;&lt;/span>&lt;span style="color:#111">,&lt;/span>&lt;span style="color:#d88200">&amp;#39;rec.motorcycles&amp;#39;&lt;/span>&lt;span style="color:#111">,&lt;/span>&lt;span style="color:#d88200">&amp;#39;rec.sport.baseball&amp;#39;&lt;/span>&lt;span style="color:#111">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">simplified_names&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#39;mac&amp;#39;&lt;/span>&lt;span style="color:#111">,&lt;/span>&lt;span style="color:#d88200">&amp;#39;motor&amp;#39;&lt;/span>&lt;span style="color:#111">,&lt;/span>&lt;span style="color:#d88200">&amp;#39;baseball&amp;#39;&lt;/span>&lt;span style="color:#111">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Fetch the data, removing headers/footers/quotes for cleaner text&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">newsgroups_train&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">fetch_20newsgroups&lt;/span>&lt;span style="color:#111">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">subset&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#39;train&amp;#39;&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">remove&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#39;headers&amp;#39;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#39;footers&amp;#39;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#39;quotes&amp;#39;&lt;/span>&lt;span style="color:#111">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">categories&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">categories_to_fetch&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">shuffle&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#00a8c8">True&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">random_state&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">42&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">newsgroups_test&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">fetch_20newsgroups&lt;/span>&lt;span style="color:#111">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">subset&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#39;test&amp;#39;&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">remove&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#39;headers&amp;#39;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#39;footers&amp;#39;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#39;quotes&amp;#39;&lt;/span>&lt;span style="color:#111">),&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">categories&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">categories_to_fetch&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">shuffle&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#00a8c8">True&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">random_state&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">42&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="the-baseline-model">The baseline model&lt;/h4>
&lt;p>Before the AI model, we first need to establish a baseline classifier. This was accomplished using a classical machine learning approach: we vectorized the text data using the well-established TF-IDF (Term Frequency-Inverse Document Frequency) method, and then trained a simple Naive Bayes classifier on the resulting features.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> &lt;span style="color:#111">sklearn.feature_extraction.text&lt;/span> &lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">TfidfVectorizer&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> &lt;span style="color:#111">sklearn.naive_bayes&lt;/span> &lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">MultinomialNB&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">vectorizer&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">TfidfVectorizer&lt;/span>&lt;span style="color:#111">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">vectors&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">vectorizer&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">fit_transform&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">newsgroups_train&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">data&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">clf&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">MultinomialNB&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">alpha&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">.01&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">clf&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">fit&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">vectors&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">newsgroups_train&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">target&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">vectors_test&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">vectorizer&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">transform&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">newsgroups_test&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">data&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">pred&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">clf&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">predict&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">vectors_test&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Our Naive Bayes baseline model achieved a respectable &lt;strong>85% F1 score&lt;/strong>.
Crucially, it also demonstrated a decently calibrated output:&lt;/p>
&lt;figure>
&lt;img src="../../images/baseline_calibration.png" alt="baseline_calibration">
&lt;/figure>
&lt;h4 id="the-ai-model">The AI model&lt;/h4>
&lt;p>Now we move to a modern approach for this NLP task: &lt;strong>zero-shot classification&lt;/strong>.
By leveraging the &lt;a href="https://openai.com/index/gpt-4-research/">OpenAI API&lt;/a> we completely bypass the need for any training. Instead, we tap directly into the vast pre-training knowledge of GPT and use a prompt to instruct the model to classify the news articles. This method allows us to achieve high performance without a single training loop.&lt;/p>
&lt;p>This Python snippet defines a function, get_api_metrics_data, which performs zero-shot classification on a given news article using the OpenAI GPT-4o-mini model. It uses a system prompt to enforce classification into one of three specified categories (simplified_names) and is configured to return log probabilities for the top tokens (logprobs=True, top_logprobs=3) &lt;a href="https://cookbook.openai.com/examples/using_logprobs">OpenAI LogProb cookbook&lt;/a>.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> &lt;span style="color:#111">openai&lt;/span> &lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">OpenAI&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Prompt &lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">SYSTEM_PROMPT&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;&amp;#34;&amp;#34;You are an expert classifier.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d88200">Classify the article into exactly one of the following categories: &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#d88200">&amp;#39;, &amp;#39;&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">join&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">simplified_names&lt;/span>&lt;span style="color:#111">)&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d88200">Return ONLY the category name, exactly as it appears in the list, and nothing else.&amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Inference function&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">def&lt;/span> &lt;span style="color:#75af00">get_api_metrics_data&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">article&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;&amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d88200"> Calls the API once and returns both the probability vector (for calibration)
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d88200"> and the predicted integer ID.
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#d88200"> &amp;#34;&amp;#34;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">prob_vector&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">np&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">zeros&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#ae81ff">3&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">pred_id&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">try&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">completion&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">client&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">chat&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">completions&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">create&lt;/span>&lt;span style="color:#111">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">model&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#34;gpt-4o-mini&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">messages&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">[{&lt;/span>&lt;span style="color:#d88200">&amp;#34;role&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;system&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;content&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">SYSTEM_PROMPT&lt;/span>&lt;span style="color:#111">},&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">{&lt;/span>&lt;span style="color:#d88200">&amp;#34;role&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">&amp;#34;user&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#d88200">&amp;#34;content&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;Article: &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">article&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">...&lt;/span>&lt;span style="color:#8045ff">\n&lt;/span>&lt;span style="color:#d88200">Category:&amp;#34;&lt;/span>&lt;span style="color:#111">}],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">logprobs&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#00a8c8">True&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">top_logprobs&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">3&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">temperature&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">predicted_name&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">completion&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">choices&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">message&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">content&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">strip&lt;/span>&lt;span style="color:#111">()&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">lower&lt;/span>&lt;span style="color:#111">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">pred_id&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">category_to_id&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">get&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">predicted_name&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">logprobs_content&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">completion&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">choices&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">logprobs&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">content&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">if&lt;/span> &lt;span style="color:#111">logprobs_content&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">first_token_logprobs&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">logprobs_content&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">]&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">top_logprobs&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">class_probs&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">np&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">zeros&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#ae81ff">3&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">lp_item&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">first_token_logprobs&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">token&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">lp_item&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">token&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">strip&lt;/span>&lt;span style="color:#111">()&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">lower&lt;/span>&lt;span style="color:#111">()&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">linear_prob&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">np&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">exp&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">lp_item&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">logprob&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">if&lt;/span> &lt;span style="color:#d88200">&amp;#39;mac&amp;#39;&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">token&lt;/span> &lt;span style="color:#f92672">or&lt;/span> &lt;span style="color:#111">token&lt;/span> &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#d88200">&amp;#39;mac&amp;#39;&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">class_probs&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">]&lt;/span> &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#111">linear_prob&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">elif&lt;/span> &lt;span style="color:#d88200">&amp;#39;motor&amp;#39;&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">token&lt;/span> &lt;span style="color:#f92672">or&lt;/span> &lt;span style="color:#111">token&lt;/span> &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#d88200">&amp;#39;motor&amp;#39;&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">class_probs&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">]&lt;/span> &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#111">linear_prob&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">elif&lt;/span> &lt;span style="color:#d88200">&amp;#39;baseball&amp;#39;&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">token&lt;/span> &lt;span style="color:#f92672">or&lt;/span> &lt;span style="color:#111">token&lt;/span> &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#d88200">&amp;#39;baseball&amp;#39;&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">class_probs&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#ae81ff">2&lt;/span>&lt;span style="color:#111">]&lt;/span> &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#111">linear_prob&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">total_relevant_prob&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">np&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">sum&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">class_probs&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">if&lt;/span> &lt;span style="color:#111">total_relevant_prob&lt;/span> &lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">prob_vector&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">class_probs&lt;/span> &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#111">total_relevant_prob&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">else&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">if&lt;/span> &lt;span style="color:#111">pred_id&lt;/span> &lt;span style="color:#f92672">!=&lt;/span> &lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">prob_vector&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#111">pred_id&lt;/span>&lt;span style="color:#111">]&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">1.0&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">prob_vector&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">pred_id&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">except&lt;/span> &lt;span style="color:#75af00">Exception&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">return&lt;/span> &lt;span style="color:#111">np&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">zeros&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#ae81ff">3&lt;/span>&lt;span style="color:#111">),&lt;/span> &lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Our AI model demonstrated an impressive &lt;strong>F1 score of 95%&lt;/strong>, significantly outperforming the Naive Bayes baseline by a solid 10% margin.
However the model exhibits &lt;strong>severe miscalibration&lt;/strong>, oscillating between being overconfident when its predictions are likely wrong, and being overly pessimistic (underconfident) when its predictions are correct :&lt;/p>
&lt;figure>
&lt;img src="../../images/ai_calibration.png" alt="baseline_calibration">
&lt;/figure>
&lt;h4 id="can-we-fix-it-">Can we fix it ?&lt;/h4>
&lt;p>To address the observed miscalibration, we applied a traditional post-processing technique: fitting a second regression model to map the estimated scores to true probabilities. Specifically, we leveraged the &lt;a href="https://scikit-learn.org/stable/modules/calibration.html">Isotonic regression&lt;/a> from the scikit-learn package, a common method for recalibrating uncalibrated estimators.&lt;/p>
&lt;p>However, isolating the results for a specific class, such as the &amp;lsquo;hardware&amp;rsquo; (mac) category, clearly shows the limitations of this approach:&lt;/p>
&lt;figure>
&lt;img src="../../images/openai_calibration_plot_isotonic_mac.png" alt="baseline_calibration">
&lt;/figure>
&lt;p>As the initial confidence scores from the GPT model exhibited virtually no correlation with the real class probabilities, it proved impossible to fix the miscalibration effectively using Isotonic Regression or any other simple linear or non-linear transformation. The underlying issue is the fundamental instability of the model&amp;rsquo;s confidence scores.&lt;/p>
&lt;h4 id="why-is-this-a-problem-">Why is this a problem ?&lt;/h4>
&lt;p>In most practical applications, simply providing a prediction label is insufficient; a clear measure of the confidence level in that prediction is absolutely essential. Consider a fraud detection system: it is designed to automatically approve transactions with high-confidence predictions of safety, while low-confidence predictions are deliberately flagged for mandatory human review. If the model&amp;rsquo;s underlying confidence scores are inaccurate or &amp;ldquo;miscalibrated,&amp;rdquo; this entire risk-managed workflow completely breaks down, leading to either high-risk transactions being overlooked or excessive manual review of safe transactions.&lt;/p>
&lt;h3 id="conclusion">Conclusion&lt;/h3>
&lt;p>While Large Language Models (LLMs) like GPT offer incredible zero-shot performance on NLP tasks, completely eliminating the need for training data, they suffer from a fundamental practical limitation: &lt;strong>they currently lack an effective and reliable mechanism for measuring output uncertainty and calibration&lt;/strong>.&lt;/p>
&lt;p>This absence means that in any use case where decision-making critically depends on a trustworthy measure of confidence or risk, modern LLMs become a terrible choice. Instead, practitioners should rely on simpler, well-calibrated Machine Learning models, even though these require the initial investment of collecting and training on labeled data. The superior performance of the LLM isn&amp;rsquo;t always worth the cost of unreliable risk assessment.&lt;/p></description><author>Calvin Tran</author><guid>http://gabelfra1.github.io/gabelfra.github.io/posts/calibration/</guid><pubDate>Sat, 11 Oct 2025 00:00:00 +0000</pubDate></item><item><title>Diarization &amp; Transcription with Whisper and PyAnnote</title><link>http://gabelfra1.github.io/gabelfra.github.io/posts/asr/</link><description>&lt;p>Speaker Diarization answers the question &amp;ldquo;who spoke when?&amp;rdquo; by segmenting an audio stream based on speaker identity, while transcription tells us &amp;ldquo;what was said&amp;rdquo;.&lt;/p>
&lt;h3 id="introducing-the-key-components">Introducing the Key Components&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>Whisper&lt;/strong>: Automatic Speech Recognition model that converts speech to text.&lt;/li>
&lt;li>&lt;strong>Pyannote.audio&lt;/strong>: Deep neural network for speaker diarization.&lt;/li>
&lt;li>&lt;strong>WhisperX&lt;/strong>: Optimized Whisper variant that integrates multiple components.&lt;/li>
&lt;/ul>
&lt;h3 id="a-step-by-step-implementation-guide">A Step-by-Step Implementation Guide&lt;/h3>
&lt;p>This section provides a practical guide to implementing speaker diarization using WhisperX, Pyannote, and Whisper, while highlighting WhisperX&amp;rsquo;s advantages. For our audio sample, we can grab a segment from pretty much any free podcast out there – let&amp;rsquo;s go for a clip from &lt;a href="https://lexfridman.com/podcast/">Lex Friedman&lt;/a>, one of my personal favorites.&lt;/p>
&lt;h4 id="setup">Setup&lt;/h4>
&lt;p>Before diving into the code, it is essential to prepare your development environment.
Make sure you have a Python virtual environment set up, it would also be beneficial to have access to a GPU compatible with CUDA for acceleration.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>python -m venv venv
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">source&lt;/span> venv/bin/activate
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>To utilize Pyannote.audio models for diarization through WhisperX, you will need a Hugging Face access token with &amp;lsquo;read&amp;rsquo; permissions, for which you must accept the user agreements for the pyannote/segmentation-3.0 and pyannote/speaker-diarization-3.1 models on the Hugging Face website: &lt;a href="https://github.com/pyannote/pyannote-audio">HuggingFace&lt;/a>&lt;/p>
&lt;p>Finally we can pip install our dependencies:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>python -m pip install torch numpy pyannote.audio whisper whisperx
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>First, we&amp;rsquo;ll import the necessary libraries, and configure our Hugging Face token and file path.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">torch&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">whisper&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> &lt;span style="color:#111">pyannote.audio&lt;/span> &lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">Pipeline&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> &lt;span style="color:#111">whisperx.diarize&lt;/span> &lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">DiarizationPipeline&lt;/span>&lt;span style="color:#111">,&lt;/span>&lt;span style="color:#111">assign_word_speakers&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">from&lt;/span> &lt;span style="color:#111">whisperx&lt;/span> &lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">load_align_model&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">align&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">hugging_face_token&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#34;hf_token&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">audio_path&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#d88200">&amp;#34;audio_file_path&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Check if cuda is available&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#111">torch&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">DEVICE&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">torch&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">device&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;cuda&amp;#34;&lt;/span> &lt;span style="color:#00a8c8">if&lt;/span> &lt;span style="color:#111">torch&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">cuda&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">is_available&lt;/span>&lt;span style="color:#111">()&lt;/span> &lt;span style="color:#00a8c8">else&lt;/span> &lt;span style="color:#d88200">&amp;#34;cpu&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">DEVICE&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="diarization">Diarization&lt;/h4>
&lt;p>In the first code snippet, a pre-trained pyannote model is utilized to determine when different speakers are active in an audio recording. The output of this speaker segmentation can be viewed via the print statement:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">#Initialize pipeline&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">pipeline&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">Pipeline&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">from_pretrained&lt;/span>&lt;span style="color:#111">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;pyannote/speaker-diarization-3.1&amp;#34;&lt;/span>&lt;span style="color:#111">,&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">use_auth_token&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">hugging_face_token&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># send pipeline to GPU (when available)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">pipeline&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">to&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">torch&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">device&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">&amp;#34;cuda&amp;#34;&lt;/span>&lt;span style="color:#111">))&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># apply pretrained pipeline&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">diarization&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">pipeline&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">audio_path&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># print the result&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">turn&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">_&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">speaker&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">diarization&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">itertracks&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">yield_label&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#00a8c8">True&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">print&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;start=&lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">turn&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">start&lt;/span>&lt;span style="color:#d88200">:&lt;/span>&lt;span style="color:#d88200">.1f&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">s stop=&lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">turn&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">end&lt;/span>&lt;span style="color:#d88200">:&lt;/span>&lt;span style="color:#d88200">.1f&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">s speaker_&lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">speaker&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This plot illustrates the various segments identified by the model throughout the podcast&amp;rsquo;s duration.&lt;/p>
&lt;figure>
&lt;img src="../../images/diarization_output.png" alt="Diarization">
&lt;/figure>
&lt;h4 id="transcription">Transcription&lt;/h4>
&lt;p>Now let&amp;rsquo;s run the Whisper model to generate the transcription:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">model_name&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#d88200">&amp;#34;turbo&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">model&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">whisper&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">load_model&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">model_name&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">DEVICE&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">script&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">model&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">transcribe&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">audio_path&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="naive-alignment">Naive alignment&lt;/h4>
&lt;p>The following script attempts a basic diarization-to-transcription alignment. It directly links diarization segments (which identify who spoke when) with Whisper&amp;rsquo;s transcription segments (which capture what was said) by simply checking if their timestamps overlap. However, this straightforward timestamp-based matching is often insufficient and can lead to significant inaccuracies, such as misaligned text, missing words, or incorrect speaker attribution, because it doesn&amp;rsquo;t account for precise word timings or subtle overlaps in speech.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Create a text associating diarization segments with Whisper transcription&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">output_text&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">turn&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">_&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">speaker&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">diarization&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">itertracks&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">yield_label&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#00a8c8">True&lt;/span>&lt;span style="color:#111">):&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">segment_text&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">segment&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">script&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;segments&amp;#34;&lt;/span>&lt;span style="color:#111">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00a8c8">if&lt;/span> &lt;span style="color:#111">segment&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;start&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span> &lt;span style="color:#f92672">&amp;gt;=&lt;/span> &lt;span style="color:#111">turn&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">start&lt;/span> &lt;span style="color:#f92672">and&lt;/span> &lt;span style="color:#111">segment&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;end&amp;#34;&lt;/span>&lt;span style="color:#111">]&lt;/span> &lt;span style="color:#f92672">&amp;lt;=&lt;/span> &lt;span style="color:#111">turn&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">end&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">segment_text&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">append&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">segment&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;text&amp;#34;&lt;/span>&lt;span style="color:#111">])&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">combined_text&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#d88200">&amp;#34; &amp;#34;&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">join&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">segment_text&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">output_text&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">append&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#d88200">f&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">speaker&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200"> [&lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">turn&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">start&lt;/span>&lt;span style="color:#d88200">:&lt;/span>&lt;span style="color:#d88200">.2f&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">s - &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">turn&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">end&lt;/span>&lt;span style="color:#d88200">:&lt;/span>&lt;span style="color:#d88200">.2f&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">s]: &lt;/span>&lt;span style="color:#d88200">{&lt;/span>&lt;span style="color:#111">combined_text&lt;/span>&lt;span style="color:#d88200">}&lt;/span>&lt;span style="color:#d88200">&amp;#34;&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Print the result&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">line&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">output_text&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">print&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">line&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="advanced-alignment---whisperx">Advanced alignment - WhisperX&lt;/h4>
&lt;p>While a simple timestamp overlap can lead to significant inaccuracies in aligning diarization and transcription segments, WhisperX addresses these challenges through forced alignment. Unlike basic timestamp matching, WhisperX refines the alignment by first leveraging the more precise word-level timestamps generated by its underlying Whisper model. It then performs a forced alignment process, which essentially &amp;ldquo;snaps&amp;rdquo; the diarization segments to the exact start and end times of the individual words within the transcription. This method accounts for subtle overlaps and ensures that each word is attributed to the correct speaker, even when speech segments are close together or overlap slightly.&lt;/p>
&lt;figure>
&lt;img src="../../images/whisperx.png" alt="whisperx">
&lt;/figure>
&lt;p>This script first uses the pyannote library to identify speakers and time of enunciation in an audio file (that&amp;rsquo;s the &amp;ldquo;diarization&amp;rdquo; part). Then, it takes a pre-generated text transcript (script[&amp;ldquo;segments&amp;rdquo;]) and uses WhisperX&amp;rsquo;s alignment models to precisely match each word in the transcript to its exact timing in the audio. Finally, it combines the speaker information from pyannote with the word-level timings from WhisperX to produce a highly accurate, time-stamped transcript where each spoken word is correctly attributed to the right speaker.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#272822;background-color:#fafafa;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-python" data-lang="python">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Initialize a diarization pipeline&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">diarization_pipeline&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">DiarizationPipeline&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">use_auth_token&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">hugging_face_token&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">diarized&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">diarization_pipeline&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">audio_path&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Align Script&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">model_a&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">metadata&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">load_align_model&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">language_code&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">script&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;language&amp;#34;&lt;/span>&lt;span style="color:#111">],&lt;/span> &lt;span style="color:#111">device&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#111">DEVICE&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">script_aligned&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">align&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">script&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;segments&amp;#34;&lt;/span>&lt;span style="color:#111">],&lt;/span> &lt;span style="color:#111">model_a&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">metadata&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">audio_path&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">DEVICE&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># Align Speakers&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">result_segments&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">word_seg&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">list&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">assign_word_speakers&lt;/span>&lt;span style="color:#111">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">diarized&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">script_aligned&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">)&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">values&lt;/span>&lt;span style="color:#111">())&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#111">transcribed&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#111">[]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">result_segment&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">result_segments&lt;/span>&lt;span style="color:#111">:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">transcribed&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">append&lt;/span>&lt;span style="color:#111">(&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">{&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;start&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">result_segment&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;start&amp;#34;&lt;/span>&lt;span style="color:#111">],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;end&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">result_segment&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;end&amp;#34;&lt;/span>&lt;span style="color:#111">],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;text&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">result_segment&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;text&amp;#34;&lt;/span>&lt;span style="color:#111">],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#d88200">&amp;#34;speaker&amp;#34;&lt;/span>&lt;span style="color:#111">:&lt;/span> &lt;span style="color:#111">result_segment&lt;/span>&lt;span style="color:#111">[&lt;/span>&lt;span style="color:#d88200">&amp;#34;speaker&amp;#34;&lt;/span>&lt;span style="color:#111">],&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">}&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">start&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">end&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">text&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">speaker&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">[&lt;/span>&lt;span style="color:#111">i&lt;/span>&lt;span style="color:#f92672">.&lt;/span>&lt;span style="color:#111">values&lt;/span>&lt;span style="color:#111">()&lt;/span> &lt;span style="color:#00a8c8">for&lt;/span> &lt;span style="color:#111">i&lt;/span> &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#111">transcribed&lt;/span>&lt;span style="color:#111">]:&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#111">print&lt;/span>&lt;span style="color:#111">(&lt;/span>&lt;span style="color:#111">start&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">end&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">speaker&lt;/span>&lt;span style="color:#111">,&lt;/span> &lt;span style="color:#111">text&lt;/span>&lt;span style="color:#111">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>By combining Pyannote&amp;rsquo;s precise speaker diarization with WhisperX&amp;rsquo;s advanced forced alignment, this guide demonstrates how to generate highly accurate, speaker-attributed transcripts. This approach significantly surpasses basic timestamp matching, ensuring precise information about &amp;ldquo;who spoke when and what was said&amp;rdquo;.&lt;/p>
&lt;h4 id="references-">References :&lt;/h4>
&lt;ul>
&lt;li>&lt;a href="https://github.com/pyannote/pyannote-audio">PyAnnote&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/openai/whisper">Whisper&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://github.com/m-bain/whisperX">WhisperX&lt;/a>&lt;/li>
&lt;/ul></description><author>Calvin Tran</author><guid>http://gabelfra1.github.io/gabelfra.github.io/posts/asr/</guid><pubDate>Fri, 06 Jun 2025 00:00:00 +0000</pubDate></item></channel></rss>