<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Ju Lin's AI Weblog</title><link>https://julin.ai/</link><description>Recent content on Ju Lin's AI Weblog</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Thu, 27 Aug 2026 00:00:00 +1200</lastBuildDate><atom:link href="https://julin.ai/index.xml" rel="self" type="application/rss+xml"/><item><title>Where MCP Is Headed Next</title><link>https://julin.ai/2026/08/27/mcp-roadmap/</link><pubDate>Thu, 27 Aug 2026 00:00:00 +1200</pubDate><guid>https://julin.ai/2026/08/27/mcp-roadmap/</guid><description>&lt;p&gt;&lt;a href="https://blog.modelcontextprotocol.io/posts/mcp-roadmap/"&gt;The MCP maintainers published an updated roadmap&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Since March, MCP went stateless (no more session handshakes), turned Tasks into an official extension for long-running work, and shipped enterprise auth pieces like issuer validation and Client ID Metadata Documents.&lt;/p&gt;
&lt;p&gt;Next up: one HTTP-native transport instead of separate stdio and HTTP paths, real agent identity (workload federation, token exchange), and progressive tool discovery for large catalogs. No firm dates yet.&lt;/p&gt;
&lt;p&gt;MCP is leaving its single-session, request/response origins behind for something built for long-running, multi-agent systems.&lt;/p&gt;</description></item><item><title>Agents Should Be Durable, Not Long-Lived</title><link>https://julin.ai/2026/08/26/durable-agents/</link><pubDate>Wed, 26 Aug 2026 00:00:00 +1200</pubDate><guid>https://julin.ai/2026/08/26/durable-agents/</guid><description>&lt;p&gt;A common way to build an AI agent is to treat it as a long-running process. A worker receives a request, enters an agent loop, calls models and tools, waits for results, and eventually returns an answer.&lt;/p&gt;
&lt;p&gt;This works well until agents start doing real work.&lt;/p&gt;
&lt;p&gt;An agent may spend twenty minutes researching a problem, wait ten minutes for a build, ask a user for approval, or come back hours later when an external job finishes. Keeping a worker alive for the whole run wastes resources and makes failures expensive. A deployment, crash, or machine restart can also destroy work that has already happened.&lt;/p&gt;</description></item><item><title>What Is an Agent Harness?</title><link>https://julin.ai/2026/08/26/agent-harness/</link><pubDate>Wed, 26 Aug 2026 00:00:00 +1200</pubDate><guid>https://julin.ai/2026/08/26/agent-harness/</guid><description>&lt;p&gt;An oversimplified equation: &lt;strong&gt;agent harness = ai agent − model.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="overview"&gt;Overview&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://julin.ai/2026/08/26/agent-harness/diagram-equation.svg" alt="AI Agent minus Model equals Harness."&gt;&lt;/p&gt;
&lt;p&gt;An agent harness is everything in an AI agent besides the model — everything outside the LLM inference call. It&amp;rsquo;s a piece of software that provides an environment for the LLM to observe and take actions.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The agent harness has a &lt;strong&gt;system prompt&lt;/strong&gt; that defines the LLM&amp;rsquo;s basic behavior and controls how it puts out tokens.&lt;/li&gt;
&lt;li&gt;The agent harness includes a set of &lt;strong&gt;tools&lt;/strong&gt; that the LLM can call.&lt;/li&gt;
&lt;li&gt;The agent harness interacts with the LLM to get tokens back.&lt;/li&gt;
&lt;li&gt;The agent harness interleaves LLM outputs and tool calls, typically called the &lt;strong&gt;agent loop&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="the-system-prompt"&gt;The system prompt&lt;/h3&gt;
&lt;p&gt;&lt;img src="https://julin.ai/2026/08/26/agent-harness/diagram-sequence.svg" alt="Sequence diagram: the harness sends the system prompt, then the user message, and the LLM sends tokens back."&gt;&lt;/p&gt;</description></item><item><title>Four Ways to Teach an AI to Draw a Cat</title><link>https://julin.ai/2026/08/24/four-ways-to-teach-ai-eli5/</link><pubDate>Mon, 24 Aug 2026 00:00:00 +1200</pubDate><guid>https://julin.ai/2026/08/24/four-ways-to-teach-ai-eli5/</guid><description>&lt;style&gt;
 .teach-cat{
 container-type:inline-size;
 }

 .teach-cat *{box-sizing:border-box}

 .teach-cat .inner{max-width:720px;margin:0 auto}

 /* ---------- header ---------- */
 .teach-cat header{padding:clamp(4px,2cqw,10px) 0 clamp(20px,4cqw,32px)}

 .teach-cat .deck{
 margin:0;
 max-width:52ch;
 font-size:1.05rem;
 line-height:1.55;
 color:var(--text-muted);
 }

 /* ---------- one by one ---------- */
 .teach-cat .grid{
 display:flex;
 flex-direction:column;
 border-top:1px solid var(--border);
 }

 .teach-cat .card{
 padding:clamp(22px,3cqw,34px) 0;
 border-bottom:1px solid var(--border);
 }
 .teach-cat .card:last-child{border-bottom:0}

 .teach-cat .art{width:100%;height:auto;display:block;margin:0 0 clamp(12px,2cqw,18px)}

 .teach-cat .name{
 margin:0 0 clamp(12px,2cqw,18px);
 font-weight:700;
 font-size:clamp(1.4rem,3cqw,1.8rem);
 line-height:1.1;
 color:var(--text);
 }

 .teach-cat .say{
 margin:10px 0 0;
 max-width:38ch;
 font-size:1.02rem;
 line-height:1.5;
 color:var(--text);
 }

 .teach-cat .def{
 margin:10px 0 0;
 max-width:52ch;
 font-size:1rem;
 line-height:1.55;
 color:var(--text-muted);
 }

 .teach-cat .example-label{
 margin:18px 0 0;
 font-size:.85rem;
 color:var(--text-muted);
 }

 .teach-cat .card pre{margin:8px 0 0}
 .teach-cat .card pre code{font-size:.82rem;line-height:1.5}

 /* ---------- footer ---------- */
 .teach-cat .punch{
 padding:clamp(28px,5cqw,44px) 0 clamp(6px,3cqw,16px);
 display:flex;
 align-items:flex-start;
 gap:clamp(12px,2cqw,18px);
 }
 .teach-cat .punch svg{flex:0 0 auto;margin-top:6px}
 .teach-cat .punch-line{
 margin:0;
 font-weight:600;
 font-size:clamp(1.1rem,2.6cqw,1.4rem);
 line-height:1.3;
 max-width:32ch;
 color:var(--text);
 }
 .teach-cat .punch em{font-style:normal;color:var(--accent-dark)}
 .teach-cat .foot-note{
 margin:14px 0 0;
 max-width:64ch;
 font-size:1rem;
 font-weight:400;
 line-height:1.6;
 color:var(--text-muted);
 }
 .teach-cat .foot-note strong{font-weight:800;color:var(--text)}

 /* ---------- chalk rendering ---------- */
 .teach-cat .stroke{
 fill:none;
 stroke:var(--text);
 stroke-width:2.1;
 stroke-linecap:round;
 stroke-linejoin:round;
 opacity:.85;
 }
 .teach-cat .thin{stroke-width:1.5;opacity:.55}
 .teach-cat .dot{fill:var(--text);opacity:.85;stroke:none}
 .teach-cat .c-accent{stroke:var(--accent)}
 .teach-cat .traced{stroke-dasharray:3.5 5.5;opacity:.75}

 .teach-cat .lbl{
 font-size:11px;
 font-weight:800;
 letter-spacing:.16em;
 text-transform:uppercase;
 fill:var(--text-muted);
 stroke:none;
 }
 .teach-cat .lbl.on-accent{fill:var(--accent-dark)}
 .teach-cat .num{
 font-size:58px;
 font-weight:700;
 fill:var(--accent-dark);
 stroke:none;
 }

 /* ---------- reveal ---------- */
 .teach-cat .chalk-draw{transition:stroke-dashoffset 780ms cubic-bezier(.4,.05,.2,1)}
 .teach-cat .chalk-fade{opacity:0;transition:opacity 500ms ease}
 .teach-cat .drawn .chalk-fade{opacity:1}
 .teach-cat .chalk-fade.traced{opacity:0}
 .teach-cat .drawn .chalk-fade.traced{opacity:.75}
 .teach-cat .chalk-fade.dot{opacity:0}
 .teach-cat .drawn .chalk-fade.dot{opacity:.85}

 .teach-cat .rise{opacity:0;transform:translateY(10px);transition:opacity 620ms ease,transform 620ms cubic-bezier(.2,.7,.3,1)}
 .teach-cat .drawn .rise,.teach-cat .rise.drawn{opacity:1;transform:none}

 @media (prefers-reduced-motion:reduce){
 .teach-cat .chalk-draw,.teach-cat .chalk-fade,.teach-cat .rise{transition:none}
 }

 .teach-cat :focus-visible{outline:2px solid var(--accent);outline-offset:3px}
&lt;/style&gt;

&lt;div class="teach-cat" id="teach-cat"&gt;

&lt;!-- shared chalk texture filter --&gt;
&lt;svg width="0" height="0" style="position:absolute" aria-hidden="true"&gt;
 &lt;defs&gt;
 &lt;filter id="teach-cat-chalk" x="-15%" y="-15%" width="130%" height="130%"&gt;
 &lt;feTurbulence type="fractalNoise" baseFrequency="0.055" numOctaves="3" seed="9" result="t"/&gt;
 &lt;feDisplacementMap in="SourceGraphic" in2="t" scale="2.6" xChannelSelector="R" yChannelSelector="G"/&gt;
 &lt;/filter&gt;
 &lt;/defs&gt;
&lt;/svg&gt;

&lt;div class="board"&gt;
 &lt;div class="inner"&gt;

 &lt;header&gt;
 &lt;p class="deck rise"&gt;Same student, same cat, four very different lessons — and every way of training a language model is one of them.&lt;/p&gt;</description></item><item><title>Marin 535B-A23B Starts Training, in the Open</title><link>https://julin.ai/2026/08/24/marin-open-training/</link><pubDate>Mon, 24 Aug 2026 00:00:00 +1200</pubDate><guid>https://julin.ai/2026/08/24/marin-open-training/</guid><description>&lt;blockquote&gt;
&lt;p&gt;🚢 Marin 535B-A23B started training this week! As usual, the whole process is open.&lt;/p&gt;
&lt;p&gt;Voyage plan: pretraining (80%) + midtraining (20%) on 18.75T tokens on 11 x GB200 NVL72 for ~3 months (2.7e24 FLOPs). Post-training will follow.&lt;/p&gt;
&lt;p&gt;Before kicking off the run, we trained a 4-rung scaling ladder from 1.6B-A61M (48B tokens) to 27.7B-A1.2B (926B tokens) to debug issues, and to make a forecast of our hero run. This is by far our biggest run, so definitely expecting the unexpected.&lt;/p&gt;</description></item><item><title>Training Qwen to Paint Watercolors with Pure RL</title><link>https://julin.ai/2026/08/24/qwen-watercolor-rl/</link><pubDate>Mon, 24 Aug 2026 00:00:00 +1200</pubDate><guid>https://julin.ai/2026/08/24/qwen-watercolor-rl/</guid><description>&lt;p&gt;&lt;a href="https://surya.website/rling-qwen-to-paint-with-code"&gt;Surya trained Qwen 3.5&lt;/a&gt; to have taste in watercolor painting. &lt;a href="https://x.com/kickingkeys/status/2091570990048276897"&gt;The results are stunning&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s purely RL:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The system is a four-step loop, run thousands of times during training.&lt;/p&gt;
&lt;p&gt;The model receives a prompt, something like draw a peach hibiscus in watercolour, and writes a complete p5.brush JavaScript sketch. The sketch is rendered in a sandboxed Puppeteer environment, which produces a PNG. The PNG is judged against two random reference paintings sampled from a hand-rated pool, with a separate judge model picking the better watercolour. The judgment is converted into a reward signal, GRPO updates the model, and the loop runs again.&lt;/p&gt;</description></item><item><title>Evals, Explained in Plain Language</title><link>https://julin.ai/2026/08/23/evals-eli5/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +1200</pubDate><guid>https://julin.ai/2026/08/23/evals-eli5/</guid><description>&lt;style&gt;
 .ev{ --ev-down:#c62828 }
 .ev svg{max-width:100%;height:auto;display:block;margin:1.25rem 0}
 .ev .wire{stroke:var(--border);stroke-width:1.8;fill:none}

 .ev .lbl{font-size:13px;fill:var(--text-muted);text-transform:uppercase;letter-spacing:.04em}
 .ev .chip{fill:var(--bg);stroke:var(--border);stroke-width:1.6}
 .ev .chip-lit{fill:var(--accent-light);stroke:var(--accent)}
 .ev .chip-text{font-size:14px;fill:var(--text)}
 .ev .chip-text-lit{fill:var(--accent-dark);font-weight:600}

 .ev .track{fill:var(--border);opacity:.35}
 .ev .fillbar{fill:var(--border)}
 .ev .fillbar.win{fill:var(--accent)}
 .ev .bar-old{fill:var(--border)}
 .ev .bar-new{fill:var(--accent)}
 .ev .bar-new.down{fill:var(--ev-down)}

 .ev .check{fill:none;stroke:var(--accent);stroke-width:4;stroke-linecap:round;stroke-linejoin:round}
 .ev .cross{fill:none;stroke:var(--ev-down);stroke-width:4;stroke-linecap:round}

 .ev .pulse{animation:ev-pulse 1.8s ease-in-out infinite}
 @keyframes ev-pulse{0%,100%{opacity:1}50%{opacity:.55}}

 .ev .q{opacity:0}
 .ev .q1{animation:ev-q1 7s ease-in-out infinite}
 .ev .q2{animation:ev-q2 7s ease-in-out infinite}
 .ev .q3{animation:ev-q3 7s ease-in-out infinite}
 .ev .q4{animation:ev-q4 7s ease-in-out infinite}
 .ev .q5{animation:ev-q5 7s ease-in-out infinite}
 .ev .tally{animation:ev-tally 7s ease-in-out infinite}
 @keyframes ev-q1{0%,4%{opacity:0}8%,90%{opacity:1}96%,100%{opacity:0}}
 @keyframes ev-q2{0%,14%{opacity:0}18%,90%{opacity:1}96%,100%{opacity:0}}
 @keyframes ev-q3{0%,24%{opacity:0}28%,90%{opacity:1}96%,100%{opacity:0}}
 @keyframes ev-q4{0%,34%{opacity:0}38%,90%{opacity:1}96%,100%{opacity:0}}
 @keyframes ev-q5{0%,44%{opacity:0}48%,90%{opacity:1}96%,100%{opacity:0}}
 @keyframes ev-tally{0%,54%{opacity:0}58%,90%{opacity:1}96%,100%{opacity:0}}

 .ev .ln{stroke:var(--accent);stroke-width:3;fill:none;stroke-dasharray:350;animation:ev-line 10s ease-in-out infinite}
 @keyframes ev-line{0%{stroke-dashoffset:350;opacity:1}50%,85%{stroke-dashoffset:0;opacity:1}92%{opacity:0}94%,100%{stroke-dashoffset:350;opacity:0}}
 .ev .pt{opacity:0}
 .ev .pt1{animation:ev-pt1 10s ease-in-out infinite}
 .ev .pt2{animation:ev-pt2 10s ease-in-out infinite}
 .ev .pt3{animation:ev-pt3 10s ease-in-out infinite}
 .ev .pt4{animation:ev-pt4 10s ease-in-out infinite}
 .ev .pt5{animation:ev-pt5 10s ease-in-out infinite}
 @keyframes ev-pt1{0%,1%{opacity:0}3%,85%{opacity:1}92%,100%{opacity:0}}
 @keyframes ev-pt2{0%,13%{opacity:0}15%,85%{opacity:1}92%,100%{opacity:0}}
 @keyframes ev-pt3{0%,25%{opacity:0}27%,85%{opacity:1}92%,100%{opacity:0}}
 @keyframes ev-pt4{0%,37%{opacity:0}39%,85%{opacity:1}92%,100%{opacity:0}}
 @keyframes ev-pt5{0%,49%{opacity:0}51%,85%{opacity:1}92%,100%{opacity:0}}

 @media (prefers-reduced-motion:reduce){
 .ev .pulse{animation:none;opacity:1}
 .ev .q{animation:none;opacity:1}
 .ev .ln{animation:none;stroke-dashoffset:0;opacity:1}
 .ev .pt{animation:none;opacity:1}
 }
&lt;/style&gt;
&lt;div class="ev"&gt;

&lt;p&gt;You can't just &lt;em&gt;feel&lt;/em&gt; that an AI system got better. You need a test — and a way to grade it.&lt;/p&gt;</description></item><item><title>Linus Torvalds on Debugging the Kernel with AI</title><link>https://julin.ai/2026/08/23/linus-ai-debug/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +1200</pubDate><guid>https://julin.ai/2026/08/23/linus-ai-debug/</guid><description>&lt;blockquote&gt;
&lt;p&gt;And this was a debug session from hell, enormously helped by an AI doing much of the grunt-work.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d like to call it my tireless helper, but the AI several times stated flat out that this was impossible and unsolvable and that we should just write a report about it.&lt;/p&gt;
&lt;p&gt;I suspect those things have been trained by people who may not be quite as stubborn as I am.&lt;/p&gt;
&lt;p&gt;But while the AI was ready to give up several times, it did keep adding debug code and analyzing it faithfully when I pushed. So credit where credit is due and I let the AI write the commit message above.&lt;/p&gt;</description></item><item><title>Neural Network, Explained in Plain Language</title><link>https://julin.ai/2026/08/23/neural-network-eli5/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +1200</pubDate><guid>https://julin.ai/2026/08/23/neural-network-eli5/</guid><description>&lt;style&gt;
 .nn{ --nn-wrong:#c62828 }
 .nn svg{max-width:100%;height:auto;display:block;margin:1.25rem 0}
 .nn .node{fill:var(--bg);stroke:var(--text);stroke-width:2.2}
 .nn .node-lit{fill:var(--accent);stroke:var(--accent)}
 .nn .wire{stroke:var(--border);stroke-width:1.8;fill:none}
 .nn .flow{stroke:var(--accent);stroke-width:3;fill:none;stroke-dasharray:5 15;animation:nn-flow 1.5s linear infinite}
 .nn .flow.no{stroke:var(--nn-wrong)}
 @keyframes nn-flow{to{stroke-dashoffset:-40}}
 .nn .lbl{font-size:13px;fill:var(--text-muted);text-transform:uppercase;letter-spacing:.04em}
 .nn .big{font-size:26px;font-weight:600;fill:var(--accent)}
 .nn .big.no{fill:var(--nn-wrong)}

 .nn .dial-wire{fill:none;animation:nn-dial-width 6s ease-in-out infinite,nn-dial-color 6s ease-in-out infinite}
 .nn .dial-ring{fill:var(--bg);animation:nn-dial-color 6s ease-in-out infinite}
 .nn .dial-needle{transform-box:view-box;transform-origin:200px 105px;animation:nn-dial-rotate 6s ease-in-out infinite,nn-dial-color 6s ease-in-out infinite}
 .nn .dial-label{opacity:0}
 .nn .dial-label.label-1{animation:nn-dial-label-1 6s ease-in-out infinite}
 .nn .dial-label.label-2{fill:var(--accent);animation:nn-dial-label-2 6s ease-in-out infinite}
 .nn .dial-label.label-3{animation:nn-dial-label-3 6s ease-in-out infinite}
 @keyframes nn-dial-rotate{
 0%{transform:rotate(-38deg)}
 6%{transform:rotate(-50deg)}
 12%,31%{transform:rotate(-45deg)}
 37%{transform:rotate(9deg)}
 43%,64%{transform:rotate(0deg)}
 70%{transform:rotate(51deg)}
 76%,98%{transform:rotate(45deg)}
 100%{transform:rotate(-38deg)}
 }
 @keyframes nn-dial-width{
 0%,31%{stroke-width:1}
 43%,64%{stroke-width:3}
 76%,98%{stroke-width:7}
 100%{stroke-width:1}
 }
 @keyframes nn-dial-color{
 0%,31%{stroke:var(--text-muted)}
 43%,64%{stroke:var(--accent)}
 76%,98%{stroke:var(--text-muted)}
 100%{stroke:var(--text-muted)}
 }
 @keyframes nn-dial-label-1{
 0%,29%{opacity:1}
 35%,96%{opacity:0}
 100%{opacity:1}
 }
 @keyframes nn-dial-label-2{
 0%,39%{opacity:0}
 45%,62%{opacity:1}
 68%,100%{opacity:0}
 }
 @keyframes nn-dial-label-3{
 0%,72%{opacity:0}
 78%,96%{opacity:1}
 100%{opacity:0}
 }

 .nn .s06-fwd{animation:nn-flow 1.5s linear infinite,nn-phase-fwd 6s ease-in-out infinite}
 .nn .s06-back{animation:nn-flow 1.5s linear infinite,nn-phase-back 6s ease-in-out infinite}
 @keyframes nn-phase-fwd{
 0%,42%{opacity:1}
 48%,100%{opacity:0}
 }
 @keyframes nn-phase-back{
 0%,48%{opacity:0}
 54%,92%{opacity:1}
 98%,100%{opacity:0}
 }
 .nn text.s06-fwd{animation:nn-phase-fwd 6s ease-in-out infinite}
 .nn text.s06-back{animation:nn-phase-back 6s ease-in-out infinite}

 .nn .tick{stroke:var(--accent);stroke-width:2;stroke-linecap:round;transform-box:view-box;animation:nn-wobble 2s ease-in-out infinite}
 @keyframes nn-wobble{
 0%,100%{transform:rotate(-13deg)}
 50%{transform:rotate(13deg)}
 }

 .nn .node-outcome{animation:nn-node-outcome 6s ease-in-out infinite}
 @keyframes nn-node-outcome{
 0%,42%{fill:var(--nn-wrong);stroke:var(--nn-wrong)}
 54%,100%{fill:var(--accent);stroke:var(--accent)}
 }

 @media (prefers-reduced-motion:reduce){
 .nn .flow{animation:none;stroke-dasharray:none;opacity:.9}
 .nn .flow.s06-back{opacity:0}
 .nn .dial-wire,.nn .dial-ring,.nn .dial-needle,.nn .dial-label{animation:none}
 .nn .dial-wire,.nn .dial-needle{stroke:var(--accent);stroke-width:3}
 .nn .dial-ring{stroke:var(--accent)}
 .nn .dial-label.label-2{opacity:1}
 .nn .tick{animation:none}
 .nn text.s06-fwd{animation:none;opacity:0}
 .nn text.s06-back{animation:none;opacity:1}
 .nn .node-outcome{animation:none;fill:var(--accent);stroke:var(--accent)}
 }
&lt;/style&gt;
&lt;div class="nn"&gt;

&lt;p&gt;A machine that learns by getting things wrong.&lt;/p&gt;</description></item><item><title>What Is Agentic UI?</title><link>https://julin.ai/2026/08/23/agentic-ui/</link><pubDate>Sun, 23 Aug 2026 00:00:00 +1200</pubDate><guid>https://julin.ai/2026/08/23/agentic-ui/</guid><description>&lt;p&gt;You already know ChatGPT&amp;rsquo;s style, but it moved away from the old chat interface some time ago. A chat interface works like ping-pong: one message bubble, then another. Agentic UI does not work that way, because it often runs a long process behind the scenes. Between your prompt and the agent&amp;rsquo;s reply, many details happen. The interface must show you these details.&lt;/p&gt;
&lt;p&gt;Here is what I believe agentic UI must give you:&lt;/p&gt;</description></item><item><title>AI Engineering SKill Map</title><link>https://julin.ai/2026/08/22/ai-engineering-skill-map/</link><pubDate>Sat, 22 Aug 2026 00:00:00 +1200</pubDate><guid>https://julin.ai/2026/08/22/ai-engineering-skill-map/</guid><description>&lt;p&gt;Andrew Ng&amp;rsquo;s wrote an &lt;a href="https://x.com/AndrewYNg/status/2090840747738374568"&gt;AI Engineering Skills Map&lt;/a&gt;, which lists six things to learn: LLM foundations, grounding models with data, building agentic systems, evaluation-driven development, operating in production, and machine learning foundations.&lt;/p&gt;
&lt;p&gt;As he broke it down, I think the most important skill is learning how to build reliable systems from LLM&amp;rsquo;s uncertain behavior.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You don’t know in advance what an LLM will output&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is the only only truth you need to take away in this post, if you can&amp;rsquo;t remember all.&lt;/p&gt;</description></item><item><title>ELI5</title><link>https://julin.ai/2026/08/22/eli5-neural-networks/</link><pubDate>Sat, 22 Aug 2026 00:00:00 +1200</pubDate><guid>https://julin.ai/2026/08/22/eli5-neural-networks/</guid><description>&lt;p&gt;&lt;a href="https://x.com/trq212/status/2090884854590382515"&gt;Thariq at Anthropic posted&lt;/a&gt; that it&amp;rsquo;s a skill people there have been using a lot recently: &lt;code&gt;/eli5 &amp;lt;what you want to explain&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I tried it on neural networks. &lt;a href="https://claude.ai/public/artifacts/dedbd15e-76ff-4cdf-9ac7-eaf317d947e4"&gt;Here&amp;rsquo;s what it made&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The first pass had bad colors, low contrast, hard to read. One follow-up prompt asking for a color fix and it was done.&lt;/p&gt;
&lt;p&gt;No formulas, no sigmoid, no softmax, none of the math that actually makes a neural network work. It&amp;rsquo;s missing for good. What&amp;rsquo;s left is the dataflow — inputs go in, get combined, come out the other end as a decision — drawn simply enough to follow at a glance.&lt;/p&gt;</description></item><item><title>Next Token Prediction, Explained in Plain Language</title><link>https://julin.ai/2026/08/22/next-token-prediction-eli5/</link><pubDate>Sat, 22 Aug 2026 00:00:00 +1200</pubDate><guid>https://julin.ai/2026/08/22/next-token-prediction-eli5/</guid><description>&lt;style&gt;
 .tok svg{max-width:100%;height:auto;display:block;margin:1.25rem 0}
 .tok .wire{stroke:var(--border);stroke-width:1.8;fill:none}
 .tok .flow{stroke:var(--accent);stroke-width:3;fill:none;stroke-dasharray:5 15;animation:tok-flow 1.5s linear infinite}
 @keyframes tok-flow{to{stroke-dashoffset:-40}}
 .tok .lbl{font-size:13px;fill:var(--text-muted);text-transform:uppercase;letter-spacing:.04em}

 .tok .chip{fill:var(--bg);stroke:var(--border);stroke-width:1.6}
 .tok .chip-lit{fill:var(--accent-light);stroke:var(--accent)}
 .tok .chip-text{font-size:14px;fill:var(--text)}
 .tok .chip-text-lit{fill:var(--accent-dark);font-weight:600}

 .tok .bar{fill:var(--border)}
 .tok .bar-win{fill:var(--accent)}
 .tok .bar-fade{fill:var(--border);opacity:.4}
 .tok .pulse{animation:tok-pulse 1.8s ease-in-out infinite}
 @keyframes tok-pulse{0%,100%{opacity:1}50%{opacity:.55}}

 .tok .cursor{fill:var(--accent);animation:tok-blink 1s step-end infinite}
 @keyframes tok-blink{0%,100%{opacity:1}50%{opacity:0}}

 .tok .cyc{opacity:0}
 .tok .cyc1{animation:tok-cyc1 5s ease-in-out infinite}
 .tok .cyc2{animation:tok-cyc2 5s ease-in-out infinite}
 .tok .cyc3{animation:tok-cyc3 5s ease-in-out infinite}
 .tok .cyc4{animation:tok-cyc4 5s ease-in-out infinite}
 .tok .cyc5{animation:tok-cyc5 5s ease-in-out infinite}
 @keyframes tok-cyc1{0%,2%{opacity:0}4%,18%{opacity:1}20%,100%{opacity:0}}
 @keyframes tok-cyc2{0%,22%{opacity:0}24%,38%{opacity:1}40%,100%{opacity:0}}
 @keyframes tok-cyc3{0%,42%{opacity:0}44%,58%{opacity:1}60%,100%{opacity:0}}
 @keyframes tok-cyc4{0%,62%{opacity:0}64%,78%{opacity:1}80%,100%{opacity:0}}
 @keyframes tok-cyc5{0%,82%{opacity:0}84%,98%{opacity:1}100%{opacity:0}}

 .tok .track{fill:var(--border);opacity:.35}
 .tok .fillbar{fill:var(--border)}
 .tok .fillbar.win{fill:var(--accent)}

 .tok .tbl{opacity:0}
 .tok .tbl1{animation:tok-tbl1 20s ease-in-out infinite}
 .tok .tbl2{animation:tok-tbl2 20s ease-in-out infinite}
 .tok .tbl3{animation:tok-tbl3 20s ease-in-out infinite}
 .tok .tbl4{animation:tok-tbl4 20s ease-in-out infinite}
 @keyframes tok-tbl1{0%,1%{opacity:0}3%,20%{opacity:1}22%,100%{opacity:0}}
 @keyframes tok-tbl2{0%,26%{opacity:0}28%,45%{opacity:1}47%,100%{opacity:0}}
 @keyframes tok-tbl3{0%,51%{opacity:0}53%,70%{opacity:1}72%,100%{opacity:0}}
 @keyframes tok-tbl4{0%,76%{opacity:0}78%,92%{opacity:1}94%,100%{opacity:0}}

 .tok .rw{opacity:0}
 .tok .rw1{animation:tok-rw1 20s ease-in-out infinite}
 .tok .rw2{animation:tok-rw2 20s ease-in-out infinite}
 .tok .rw3{animation:tok-rw3 20s ease-in-out infinite}
 .tok .rw4{animation:tok-rw4 20s ease-in-out infinite}
 @keyframes tok-rw1{0%,18%{opacity:0}20%,100%{opacity:1}}
 @keyframes tok-rw2{0%,43%{opacity:0}45%,100%{opacity:1}}
 @keyframes tok-rw3{0%,68%{opacity:0}70%,100%{opacity:1}}
 @keyframes tok-rw4{0%,90%{opacity:0}92%,100%{opacity:1}}

 @media (prefers-reduced-motion:reduce){
 .tok .flow{animation:none;stroke-dasharray:none;opacity:.9}
 .tok .pulse{animation:none;opacity:1}
 .tok .cursor{animation:none;opacity:1}
 .tok .cyc{animation:none;opacity:0}
 .tok .cyc5{animation:none;opacity:1}
 .tok .tbl{animation:none;opacity:0}
 .tok .rw{animation:none;opacity:1}
 }
&lt;/style&gt;
&lt;div class="tok"&gt;

&lt;p&gt;An AI writes one little piece at a time. It never knows the whole sentence up front — it only ever picks &lt;strong&gt;what comes next&lt;/strong&gt;.&lt;/p&gt;</description></item><item><title>Pretraining a Mini Kimi K3 for $252</title><link>https://julin.ai/2026/08/21/mini-k3/</link><pubDate>Fri, 21 Aug 2026 00:00:00 +1200</pubDate><guid>https://julin.ai/2026/08/21/mini-k3/</guid><description>&lt;p&gt;Vizuara AI Labs trained a miniature Kimi K3 from scratch: 1.02B parameters, 145M active, 5B tokens, one H200, $252.35.&lt;/p&gt;
&lt;p&gt;Not simplifying the architecture like &lt;a href="https://karpathy.github.io/2026/02/12/microgpt/"&gt;Karpathy&amp;rsquo;s microgpt&lt;/a&gt;, they kept &lt;a href="https://books.vizuara.ai/book/pretraining-a-mini-k3"&gt;Kimi K3&amp;rsquo;s MoE and attention design&lt;/a&gt; intact.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s a surprisingly cheap way to learn pretraining (in real-world). They worked through expert collapse, data-mixing bugs, distributed-training bugs, kernels, and GPU utilization on a modern MoE architecture.&lt;/p&gt;
&lt;p&gt;A few things worth noting:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;5B tokens is probably too little for a 1B model. The authors agree the run was budget constrained. So the cheap cost might due to the training stopped early.&lt;/li&gt;
&lt;li&gt;Beating GPT-2 isn&amp;rsquo;t particularly meaningful when Mini K3 has roughly 10× the parameters.&lt;/li&gt;
&lt;li&gt;MoE at this scale is debatable. A smaller dense model trained on more tokens would likely be better if the goal was capability.&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>About</title><link>https://julin.ai/about/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://julin.ai/about/</guid><description>about</description></item><item><title>Archives</title><link>https://julin.ai/archives/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://julin.ai/archives/</guid><description>archives</description></item></channel></rss>