<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Learning AI, One Concept at a Time]]></title><description><![CDATA[Figuring out how AI works, why it matters, and what we can build with it.]]></description><link>https://tokenofmyattention.hashnode.dev</link><image><url>https://cdn.hashnode.com/uploads/logos/6aabca10651797b386d56517/6d0aa896-ffcc-4ff5-b859-1baf6e192904.jpg</url><title>Learning AI, One Concept at a Time</title><link>https://tokenofmyattention.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Fri, 16 Oct 2026 12:21:08 GMT</lastBuildDate><atom:link href="https://tokenofmyattention.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Google Course - Agentic Engineering from Scratch - Part 1]]></title><description><![CDATA[https://www.youtube.com/watch?v=vE31B0D3n08

Goals

To learn what AI agents are, not just in theory, but in practice.

Look at the ideas behind modern agents.

Build your very first AI agent step by s]]></description><link>https://tokenofmyattention.hashnode.dev/google-course-agentic-engineering-from-scratch-part-1</link><guid isPermaLink="true">https://tokenofmyattention.hashnode.dev/google-course-agentic-engineering-from-scratch-part-1</guid><dc:creator><![CDATA[Alyssa Ng]]></dc:creator><pubDate>Wed, 07 Oct 2026 05:36:21 GMT</pubDate><content:encoded><![CDATA[<p><a class="embed-card" href="https://www.youtube.com/watch?v=vE31B0D3n08">https://www.youtube.com/watch?v=vE31B0D3n08</a></p>

<h2>Goals</h2>
<ul>
<li><p>To learn what AI agents are, not just in theory, but in practice.</p>
</li>
<li><p>Look at the ideas behind modern agents.</p>
</li>
<li><p>Build your very first AI agent step by step using Google's ADK.</p>
</li>
<li><p>Understand how AI agents reason, act, and adapt, and you'll have code that you can actually run yourself.</p>
</li>
</ul>
<h2>So What are AI Agents?</h2>
<p>At the simplest level, an agent is software that doesn't just answer; it can decide and take action. Instead of generating a single response like a traditional chatbot, it looks at your request, figures out what steps need to be taken, maybe calls an API, runs code, looks at the results, and then decides what to do next.</p>
<p>One of the clearest explanations comes from the research paper <a href="https://arxiv.org/abs/2210.03629"><mark class="bg-yellow-200 dark:bg-yellow-500/30">ReAct: Synergizing Reasoning and Acting in Language Models</mark></a><mark class="bg-yellow-200 dark:bg-yellow-500/30">.</mark></p>
<p><mark class="bg-yellow-200 dark:bg-yellow-500/30">// To read the research paper: </mark> <a href="https://arxiv.org/pdf/2210.03629"><mark class="bg-yellow-200 dark:bg-yellow-500/30">https://arxiv.org/pdf/2210.03629</mark></a></p>
<p>The idea in that paper was simple but powerful. Language models shouldn't just generate text in one go. They can actually reason step by step, take an action like calling a tool or API, observe the results, and then decide what to do next.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6aabca10651797b386d56517/6829aabc-38a4-4b4c-8b97-3203a14eef83.png" alt="" style="display:block;margin:0 auto" />

<p>That cycle of reasoning, acting, observing, and adjusting is the foundation of how modern AI agents work, and it lines up with how it's defined: Systems with reasoning, planning, and memory, with enough autonomy to adapt and make decisions on behalf of the user.</p>
<p>Now, not all agents behave in the same way. A useful way to think about them is in three broad patterns:</p>
<ol>
<li><p>First, we have <strong>Sequential Agents</strong>. These run step-by-step like an assembly line. Predictable and rigid. <strong>&gt;&gt; Good for simple, predictable flows.</strong></p>
</li>
<li><p>Second, we have <strong>Reactive Agents</strong>. These decide in the moment; they look at the current state and ask, "What should I do next?" They're flexible, but they don't plan ahead. <strong>&gt;&gt; Good for dynamic problems.</strong></p>
</li>
<li><p>Lastly, we have <strong>Deliberate or Planning Agents</strong>. These pause to sketch a plan, then execute. Think about booking travel. You don't just buy a flight randomly. You pick dates, hotels, and then that's the order of steps that you follow through. <strong>&gt;&gt; Good for multi-step goals with dependencies.</strong></p>
</li>
</ol>
<p>Each of them should be applied to different problems.</p>
<h3><mark class="bg-yellow-200 dark:bg-yellow-500/30">SDK vs ADK</mark></h3>
<ul>
<li><p><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">SDK (Software Development Kit):</mark></strong> <mark class="bg-yellow-200 dark:bg-yellow-500/30">Comprehensive suite of tools used to build traditional platform applications.</mark></p>
</li>
<li><p><strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">ADK (Agent Development Kit)</mark></strong><mark class="bg-yellow-200 dark:bg-yellow-500/30">: Specialised framework designed to build autonomous AI agents capable of reasoning, planning, and tool execution.</mark></p>
</li>
</ul>
<h2>Building a Blog-Writing Agent with Google ADK</h2>
<p>You give it a topic, it will generate a structured outline, turn that outline into a full blog post, and then suggest alternative titles and hooks.</p>
<p>This is where ADK's categories come in.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6aabca10651797b386d56517/1faf98e2-acff-4776-82f9-e69ba70e6958.png" alt="" style="display:block;margin:0 auto" />

<p>As we walk through the code, notice how the planner and writer agents are LLM agents, which are powered by a model. They're wrapped in loop agents, which are workflow agents in ADK. These handle retries automatically if validation fails. And if we ever wanted something beyond that, ADK would also let us extend a custom agent by subclassing the base agent.</p>
<p>So let's set up the environment and then go line by line through the code.</p>
<p>First off, you need to install UV.</p>
<h3>Environment Setup (Terminal)</h3>
<pre><code class="language-python">// Environment Setup
pip install uv
pip install google-adk
</code></pre>
<h3>Step 1: Imports and Config</h3>
<pre><code class="language-python"># agent.py
import os
import sys
from pathlib import Path
import datetime

from dotenv import load_dotenv
from google.adk.agents import Agent, LoopAgent
from google.adk.tools import agent_tool

# --- env/config -----------------------
load_dotenv()

MODEL = os.getenv("MODEL", "gemini-flash-latest")
</code></pre>
<h3>Meet the Planner Agent</h3>
<ul>
<li><p>We give it the name ("BlogPlanner") so it's easy to identify.</p>
</li>
<li><p>And we tell it which model to use (model=MODEL), which comes from our environment file.</p>
</li>
<li><p>The (description) is just a human-readable note.</p>
</li>
<li><p>The important part of the introduction is in the (instructions). Here we tell it what ot produce.</p>
</li>
<li><p>Finally, we look at the (output_key), we set it to blog outline. This means whatever this agent writes will be stored in shared state under that name so that the next agent to pick it up can do so automatically.</p>
</li>
</ul>
<pre><code class="language-python"># --- Sub-Agent: Planner ----------------
blog_planner = Agent(
    name="BlogPlanner",
    model=MODEL,
    description="Creates a practical, skimmable outline in Markdown.",
    instruction="""
        You are a technical content strategist. Produce a clear Markdown outline with:
        - Title
        - Short intro
        - 4-6 main sections (each with 2-3 bullets)
        - Conclusion

        If `codebase_context` exists in state, weave in specific sections/snippets.
        Return only the outline in Markdown.
    """,
    output_key="blog_outline"
)
</code></pre>
<h3>The Outline Validation Checker</h3>
<p>Next, we add a second agent. The Outline Validation Checker. This one doesn't write anything new. It just checks the outline. It's instruction is strict. That way we can automatically decide whether to accept the outline or try again.</p>
<p>A critical gate validating the planner's output with 2 simple results: Okay / Retry.</p>
<pre><code class="language-python"># Outline Validation Checker Class
class OutlineValidationChecker(Agent):
    def __init__(self):
        super().__init__(
            name="OutlineValidationChecker",
            model=MODEL,
            description="Validates that the outline is usable.",
            instruction="""
                Check the outline in state `blog_outline`. If it has a title, intro, 4-6 sections, and a conclusion, respond exactly "ok".
                Otherwise respond exactly "retry" and list missing pieces.
            """,
            output_key="validation result",
        )
</code></pre>
<h3>Robust Blog Planner</h3>
<p>To connect the planner and the checker, we've wrapped them inside a loop agent called Robust Blog Planner.</p>
<p>The loop first runs the planner, then the checker. If the checker says "ok", we're done. If the checker says "retry", the loop runs the planner again with the same instructions. It can do this up to three times. This gives us a safety net. So if the model forgets something, it has another chance to get it right.</p>
<p>The (blog_planner) agent is passed as a sub-agent.</p>
<p>The (OutlineValidationChecker) is another sub-agent responsible for validation.</p>
<pre><code class="language-python"># The robust_blog_planner
robust_blog_planner = LoopAgent(
    name="RobustBlogPlanner",
    description="Retries planning if validation fails.",
    sub_agents=[
        blog_planner,
        OutlineValidationChecker()],
    max_iterations=3,
)
</code></pre>
<h3>The Blogwriter Agent</h3>
<p>Transforming outlines into full-length technical blog posts.</p>
<p>Now we create another agent called blogwriter, this one takes the outline we just saved in blog outline and turns it into a full markdown blogpost.</p>
<p>The instruction tells it how to write.</p>
<p>The finish draft is saved under (blog_post) in shared state, ready for the next step.</p>
<pre><code class="language-python"># --- Sub-Agent: Writer ----------------
blog_writer = Agent(
    name="BlogWriter",
    model=MODEL,
    description="Writes a technical blog post from the outline.",
    instruction="""
        Write a complete Markdown article from the outline in `blog_outline`.
        
        Guidelines: 
        - Audience: Software engineers; skip basics and focus on practical insight. 
        - Explain both the 'how' and 'why'/
        - Include concise code snippets when helpful.
        - Follow the outline's structure (H2/H3).
        - Output only the final article in Markdown (no fence around the whole post).
    """,
    output_key="blog_post",
)
</code></pre>
<h3>The Blog Post Validation Checker</h3>
<pre><code class="language-python">class BlogPostValidationChecker(Agent):
    def __init__(self):
        super().__init__(
            name="BlogPostValidationChecker",
            model=MODEL,
            description="Validates the final post.",
            instruction="""
                Check `blog_post` for: intro, clear sections matching the outline, conclusion, and technical clarity.
                If passes, respond "ok". Else respond "retry" with the specific fixes.
            """,
            output_key="validation_result",
        )
</code></pre>
<h3>Robust Blog Writer</h3>
<p>Just like with planning, we combine the writer and its checker into a loop agent, called Robust Blog Writer. This makes the system automatically retry the writing step until the validation passes, up to three times.</p>
<pre><code class="language-python"># --- The Robust Blog Writer Loop ----------
robust_blog_writer = LoopAgent(
    name="RobustBlogWriter",
    description="Retries writing if validation fails.",
    sub_agents=[
        blog_writer,
        BlogPostValidationChecker()],
    max_iterations=3,
)
</code></pre>
<h3>Using agent_tool.AgentTool</h3>
<p>Now we wrap each loop, the (robust_blog_planner) and the (robust_blog_writer) as tools. This is what lets the root agent call them directly, without worrying about what's happening inside.</p>
<pre><code class="language-python"># --- Wrap Each Loop as Tools --------------
# Expose planner/writer as tools so the root agent can call them explicitly
planner_tool = agent_tool.AgentTool(agent=robust_blog_planner)
writer_tool  = agent_tool.AgentTool(agent=robust_blog_writer)
</code></pre>
<h3>Root Agent: Blogger</h3>
<p>Finally, we put it all together with the root agent called Blogger.</p>
<p>The instructions Blogger are simple. When a user gives it a topic, first it calles the planner tool to make an outline. Then it calls the writer tool to draft the full post. And finally it adds three alternative titles and two sweet tweet length hooks.</p>
<p>The root agent only has access to the two tools we exposed, the planner, and the writer. So it's workflow is clear and controlled.</p>
<pre><code class="language-python"># --- Root Agent: Trends → Plan → Write ----
root_agent = Agent(
    name="Blogger",
    model=MODEL,
    description="Minimal multi-agent blogger that plans and writes.",
    instruction=f"""
        If the user gives a topic:
        1) Call the planner tool to generate the outline.
        2) Call the writer tool to produce the full draft.
        3) End with 3 alternate titles and 2 tweet-length hook.
        
        If the trends tool fails or times out, continue with a sensible outline and draft anyway.

        Date: {datetime.datetime.now().strftime("%Y-%m-%d")}
    """,
    tools=[
        planner_tool,
        writer_tool,
    ],
)
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/6aabca10651797b386d56517/d0fd847b-eafc-4596-a1e8-5bcea34ceccf.png" alt="" style="display:block;margin:0 auto" />

<p>You've successfully written your first agent script. The next step is to run it.</p>
<h2>Running with ADK Web</h2>
<img src="https://cdn.hashnode.com/uploads/covers/6aabca10651797b386d56517/c5aaad9a-0b5a-4799-8ce2-d7550f5c5e8a.png" alt="" style="display:block;margin:0 auto" />

<h3>ADK Web (Terminal)</h3>
<pre><code class="language-shell">adk web
</code></pre>
<p>Head into your terminal and launch it using this command with ADK web. So you can view everything inside a simple UI.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6aabca10651797b386d56517/567a3264-4f7a-425a-96df-d90762f19a9f.png" alt="" style="display:block;margin:0 auto" />

<h3>Local ADK Web Link (Browser)</h3>
<img src="https://cdn.hashnode.com/uploads/covers/6aabca10651797b386d56517/30e50fba-0746-4d27-980f-1bcabc56a159.png" alt="" style="display:block;margin:0 auto" />

<p>Once that is running, open the local ADK web link in your browser and start interacting with the agent directly.</p>
<p>To kick things off, I'm going to ask it to generate a blog on the top 10 use cases for AI agents. Let's see how it plans, writes, and delivers the results. Your subagents will then work together to create a blog post.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6aabca10651797b386d56517/83376db3-2e48-4615-988f-9ce8b2522faf.png" alt="" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/6aabca10651797b386d56517/cb2a8281-a7c5-46e9-a853-7e708397ec0b.png" alt="" style="display:block;margin:0 auto" />

<div>
<div>💡</div>
<div>Note: The Python file containing all this code must be named "agent.py" so that the agent can be identified. Otherwise, it may return an error message such as "Failed to load agents. To get started, run adk web in the folder that contains the agents. Warning: No agents found in current folder."</div>
</div>

<div>
<div>💡</div>
<div>Note: The folder containing the <a target="_self" rel="noopener noreferrer nofollow" class="text-primary underline underline-offset-2 hover:text-primary/80 cursor-pointer" href="http://agent.py" style="pointer-events:none">agent.py</a> and other project files name MUST not contain any spaces. Eg. I changed it from "Google Course - Agentic AI" to "GoogleCourse_AgenticAI".</div>
</div>

<details>
<summary>Debugging using "adk web" vs "adk run ."</summary>
<p><strong>Why this happens on Windows</strong></p><p>When you simply type <code>adk web</code>, the server defaults to scanning parent paths or structural workspaces. Explicitly appending the <code>.</code> forces the local FastAPI server to map the configuration, state graphs, and streaming API responses directly to the <a target="_self" rel="noopener noreferrer nofollow" class="text-primary underline underline-offset-2 hover:text-primary/80 cursor-pointer" href="http://agent.py" style="pointer-events:none"><code>agent.py</code></a> in your active working directory.</p><p>Once you run <code>adk run .</code>, let me know:</p><ul><li><p>Did it successfully start an <strong>interactive chat session</strong> in your terminal?</p></li><li><p>If it failed, what <strong>error traceback or missing environment variable notice</strong> did it print?</p></li></ul>
</details><div>
<div>💡</div>
<div>Ensure to check the current Python version as well, ideally newer than 3.9</div>
</div>

<h3>Gemini API Key</h3>
<img src="https://cdn.hashnode.com/uploads/covers/6aabca10651797b386d56517/58ee799b-e517-4c06-9fc0-aacaa516f409.png" alt="" style="display:block;margin:0 auto" />

<p><a href="https://ai.google.dev/gemini-api/docs/api-key">https://ai.google.dev/gemini-api/docs/api-key</a></p>
<p>Create a new key.</p>
<p>You can pass your valid api key via 2 methods.</p>
<p><strong>(1) Use an .env file (I did this)</strong></p>
<p>ADK automatically reads environment variables from a file named <code>.env</code> in your project folder.</p>
<p>Create a file named .env (make sure it has no .txt extension) directly inside your project directory.</p>
<p>Add your Gemini API key to the file.</p>
<pre><code class="language-plaintext">GOOGLE_API_KEY="YourActualAPIKeyGoesHere"
</code></pre>
<p><strong>(2) Set it directly in PowerShell (I did not do this)</strong></p>
<p>Save the file and restart your agent with (adk run .) or (adk web .)</p>
<h3>Gemini Overloaded with Requests</h3>
<img src="https://cdn.hashnode.com/uploads/covers/6aabca10651797b386d56517/56d7895d-755f-4cd9-8bed-d1efefdaca5f.png" alt="" style="display:block;margin:0 auto" />

<p>Try again, or switch to a faster, lower-demand model.</p>
<p>Switched from latest model to the latest LITE model.</p>
<pre><code class="language-python"># --- env/config ---------------------------
load_dotenv()

# MODEL = os.getenv("MODEL", "gemini-flash-latest")
# gemini model currently experiencing high demand, cannot run the latest model...
MODEL = os.getenv("MODEL", "gemini-flash-lite-latest")
</code></pre>
<p>Boom it works perfectly now.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6aabca10651797b386d56517/5dc3f545-3aba-4fb4-a998-7ac91ee6e996.png" alt="" style="display:block;margin:0 auto" />

<p>And that's it. You've built and run your first AI agent with Google's ADK. We started from the idea of what agents are, then walked through the code step by step, and finally saw it come to life in the terminal.</p>
]]></content:encoded></item><item><title><![CDATA[PewDiePie vs OpenAI]]></title><description><![CDATA[Super surprising to see PewDiePie's name pop up on my socials again after so long! I remember crowding around my friend's iPhone 5 to watch his YouTube gameplay over a decade ago...
I remember when he]]></description><link>https://tokenofmyattention.hashnode.dev/pewdiepie-vs-openai</link><guid isPermaLink="true">https://tokenofmyattention.hashnode.dev/pewdiepie-vs-openai</guid><dc:creator><![CDATA[Alyssa Ng]]></dc:creator><pubDate>Sat, 03 Oct 2026 02:35:24 GMT</pubDate><content:encoded><![CDATA[<p>Super surprising to see PewDiePie's name pop up on my socials again after so long! I remember crowding around my friend's iPhone 5 to watch his YouTube gameplay over a decade ago...</p>
<p>I remember when he came to Singapore for an award ceremony at MBS, and I got the chance to bro-fist him in 2013, which feels like a lifetime ago...</p>
<p>I'm definitely interested to see how this plays out.<br />Here I'll jot down some quick notes on what I know so far!</p>
<h2>Situation Summary:</h2>
<ul>
<li><p>PewDiePie has released his custom local AI model - Ajax, designed for users to run privately on their home PC for everyday web searching, email, and calendar management.</p>
</li>
<li><p>While developing Ajax, he was banned from OpenAI twice for “distillation”: using OpenAI to generate training data for his own AI model development.</p>
</li>
</ul>
<h2>YouTube Video:</h2>
<p><a class="embed-card" href="https://www.youtube.com/watch?v=ODDJXGY_1kQ">https://www.youtube.com/watch?v=ODDJXGY_1kQ</a></p>

<h2>My Notes on the Video</h2>
<p>(Mostly content from Pewdie’s video, personal comments are indicated by //)</p>
<h3>Ajax Introduction</h3>
<ul>
<li><p>Ajax is a fine-tuned AI model that can browse the web, do private searches, write your emails, manage your calendar, etc.</p>
</li>
<li><p>Ajax is tuned for the Odysseus harness.</p>
</li>
<li><p>Ajax is a private “first base” foundation, it does not collect any data whatsoever from its users.</p>
</li>
<li><p>Most other open source projects also collect user data, but not this one.</p>
</li>
<li><p>Instead of stealing data, Pewdiepie hoped to ask his follower base to donate their data.</p>
</li>
<li><p>Creating <a href="http://data.pewdiepie.com">data.pewdiepie.com</a> for people to submit their data.</p>
</li>
<li><p>He tried to reduce friction and made tutorials, but still no one submitted their data…</p>
</li>
<li><p><mark class="bg-yellow-200 dark:bg-yellow-500/30">// Wtf is the difference between Ajax and Odysseus systems? What exactly are they?</mark></p>
</li>
<li><p><mark class="bg-yellow-200 dark:bg-yellow-500/30">// Also, it's nice that they're named after the rival Greek heroes, with convenient timing after most people are now familiar with some of the mythology post-release of the Odysseus movie.</mark></p>
</li>
<li><p><mark class="bg-yellow-200 dark:bg-yellow-500/30">// Hmm but Ajax did go temporarily insane and killed because of his hallucinations though, so maybe not the best name for an AI model when everyone is still fighting to reduce AI hallucinations…</mark></p>
</li>
</ul>
<h3>OpenAI and Decryption</h3>
<ul>
<li><p>He went to OpenAI to distil a bit - to increase the performance of his smaller AI model, he can distil the knowledge from a larger model to train on</p>
</li>
<li><p><mark class="bg-yellow-200 dark:bg-yellow-500/30">// To Study: Knowledge Distillation Wiki Page</mark></p>
</li>
<li><p><mark class="bg-yellow-200 dark:bg-yellow-500/30">// </mark> <a href="https://en.wikipedia.org/wiki/Knowledge_distillation"><mark class="bg-yellow-200 dark:bg-yellow-500/30">https://en.wikipedia.org/wiki/Knowledge_distillation</mark></a> </p>
</li>
<li><p><mark class="bg-yellow-200 dark:bg-yellow-500/30">// Also TIL that "distil" is UK English. "distill" is American English.</mark></p>
</li>
<li><p>He wanted to distil OpenAI's GPT -5.6 Sol model because he liked it. </p>
</li>
<li><p>The problem was that OpenAI encrypts their reasoning tokens, all the information that gives it chain-of-thought thinking on how it solves the problem.</p>
</li>
<li><p>Pewdiepie found a study that decrypts the data using their own API, and it worked.</p>
</li>
<li><p><mark class="bg-yellow-200 dark:bg-yellow-500/30">// To Study: Reasoning tokens, chain-of-thought thinking in AI</mark></p>
</li>
<li><p><mark class="bg-yellow-200 dark:bg-yellow-500/30">// To Study: Data Encryption</mark></p>
</li>
<li><p><mark class="bg-yellow-200 dark:bg-yellow-500/30">// To Study: arXiv - stealing reasoning traces from proprietary LLM APIs</mark></p>
</li>
<li><p><mark class="bg-yellow-200 dark:bg-yellow-500/30">// </mark> <a href="https://arxiv.org/abs/2608.09867"><mark class="bg-yellow-200 dark:bg-yellow-500/30">https://arxiv.org/abs/2608.09867</mark></a></p>
</li>
<li><p>Pewdiepie then went on to talk about how these giant tech companies “worked hard” to steal everyone’s data to make their AI machines. How dare we, as consumers, take part of their hard work stolen from us?</p>
</li>
<li><p>RIP he got banned from OpenAI, appealed and got accepted.</p>
</li>
<li><p>Then he ran OpenAI GPT Sol again to create his model’s training seed data, and OpenAI banned him a second time.</p>
</li>
<li><p><mark class="bg-yellow-200 dark:bg-yellow-500/30">// This ofc brings up the very interesting ethical and legal debate surrounding AI developers collecting and scraping internet data, there is plenty of ongoing discussion on privacy, data ownership concerns, lack of opt-out options, consent, uncompensated use of personal content, etc.</mark></p>
</li>
<li><p><mark class="bg-yellow-200 dark:bg-yellow-500/30">// I don’t have answers to questions about the fairness of data collection and use, but it is fascinating to hear different perspectives and to weigh the trade-off between the convenience of powerful AI tools and digital ethics.</mark></p>
</li>
<li><p><mark class="bg-yellow-200 dark:bg-yellow-500/30">// Before watching the video, I also did not expect Pewdiepie to be so vocal about his takes on AI and data collection, but it makes sense given that his internet presence would also be subject to lots of scrutiny, surveillance, and data harvesting.</mark></p>
</li>
</ul>
<h3>Decensoring AI</h3>
<ul>
<li><p>Decensoring AI is like removing its ability to say No.</p>
</li>
<li><p>Pewdiepie compared it to brain surgery: </p>
<ul>
<li><p>Imagine I’m asking you for your deepest, darkest secret.</p>
</li>
<li><p>You are thinking it in your head.</p>
</li>
<li><p>You don’t even have to answer it out loud.</p>
</li>
<li><p>I am actually running an MRI scan on your brain right now, and I can spot exactly what part of your brain was active when you refused to answer it.</p>
</li>
<li><p>I “zippity zap” it (remove it)</p>
</li>
</ul>
</li>
<li><p>By repeatedly feeding the AI model all these different dialogues that it does not want to reply to, it is possible to identify the parts responsible for the AI model’s censorship (data set of cursed questions).</p>
</li>
<li><p>These parts can then be ablated, removed.</p>
</li>
<li><p>This does cause “brain damage”, and the more extensive the removal, the more damaged the AI model becomes.  </p>
</li>
<li><p><mark class="bg-yellow-200 dark:bg-yellow-500/30">// I really like the brain surgery comparison, it makes it much easier to understand the general concept of de-censoring AI.</mark></p>
</li>
<li><p><mark class="bg-yellow-200 dark:bg-yellow-500/30">// To Study: Decensoring AI, how are the parts identified, how are the parts ablated/removed.</mark></p>
</li>
<li><p><mark class="bg-yellow-200 dark:bg-yellow-500/30">// To Study: Program called Heretic, open-source project that makes the process super simple.</mark></p>
</li>
<li><p>This gives Pewdiepie the flexibility to decide and control the extent and areas of censorship that he wants to retain in his model. To think about where to draw the line, and what kind of AI use is responsible use.</p>
</li>
<li><p>There’s a bazillion other models out there uncensored, so it does not matter too much.</p>
</li>
<li><p>But Pewdiepie drew the line at causing harm to other people, or causing harm to yourself, as that goes against his personal philosophy.</p>
</li>
<li><p><mark class="bg-yellow-200 dark:bg-yellow-500/30">// I like that Pewdiepie has a strong stance on his personal philosophy and avoiding doing harm. </mark> </p>
</li>
<li><p><mark class="bg-yellow-200 dark:bg-yellow-500/30">// Creating a small, independent model does give this kind of freedom to exercise one’s personal ethics instead of playing it as safe as possible, unlike the large firms.</mark></p>
</li>
<li><p><mark class="bg-yellow-200 dark:bg-yellow-500/30">// But he isn’t being irresponsible about it.</mark></p>
</li>
</ul>
<h3>Teaching the AI Model</h3>
<ul>
<li><p>Pewdiepie ran GRPO to train his model Ajax, and he found it really fun because it's a more interactive way of teaching the model.</p>
</li>
<li><p>The model will run the same task a set number of times (16). If it solves the task even one time out of the 16 times, that becomes valuable training data. </p>
</li>
<li><p>You reinforce the ability to generate the solution and hope for it to improve the model.</p>
</li>
<li><p><mark class="bg-yellow-200 dark:bg-yellow-500/30">// To Study: GRPO</mark></p>
</li>
<li><p><mark class="bg-yellow-200 dark:bg-yellow-500/30">// Group Relative Policy Optimization (GRPO) is a memory-efficient reinforcement learning algorithm that eliminates the need for a separate critic model by evaluating multiple outputs within a group to calculate relative advantages</mark></p>
</li>
<li><p>After 4 days of training, he ran out of tasks to fit the criteria, so he had to quickly synthesise more.</p>
</li>
<li><p>There was a back-and-forth process where it first improved, then flatlined, and then it started improving again.</p>
</li>
<li><p>He had to run reinforcement training, then run the decensoring ablation again, and then have to quantise,The capabilities of open models and harnesses point the way forward for users to use uncensored, less restricted intelligence on their own hardware, an important goal in keeping the technology free. and benchmark it to ensure nothing was lost.</p>
</li>
<li><p>Spent 8 weeks going through the dos and don'ts, by doing the don'ts over and over and over.</p>
</li>
</ul>
<h3>Small Model Advantages</h3>
<ul>
<li><p>Pewdiepie originally planned to train a way bigger model, but then he realised no one would be able to use it. </p>
</li>
<li><p>The main idea behind Ajax was to give everyone access to run a local AI, and for that it had to be a small model.</p>
</li>
<li><p><mark class="bg-yellow-200 dark:bg-yellow-500/30">// I like that he is coming from a place of accessibility and thinking of the average use of AI for most people.</mark></p>
</li>
<li><p>Pewdiepie’s napkin maths: OpenAI/Anthropic models are rumoured to be one trillion parameter models, which would take roughly 27 copies of his computer to run one instance of a model, about 150 houses in terms of electricity use.</p>
</li>
<li><p>It makes no sense to poke “that giant beast” to ask it for basic tasks like checking emails.</p>
</li>
<li><p>He really believes strongly in creating small models trained for a specific harness.</p>
</li>
<li><p>Most people use AI for searching, researching, browsing; just saving time going through lots of pieces of information. Getting information quickly to you.</p>
</li>
<li><p>That is where his small model works best.</p>
</li>
<li><p>Important for AI to not replace creativity, to not replace thinking.</p>
</li>
<li><p>A lot of AI problems can be solved by running it on your own.</p>
</li>
<li><p>That is a future that he thinks is exciting, and that’s what he wants to build with Odysseus and Ajax.</p>
</li>
<li><p>He strongly believes that AI should not replace learning new things or thinking for yourself.</p>
</li>
<li><p>Everyone still needs the basic knowledge of different subject matters, and when they get to the point of understanding, that is when they can utilise AI to start accelerating their work and process.</p>
</li>
<li><p><mark class="bg-yellow-200 dark:bg-yellow-500/30">// I agree with all that he said! I think it's well put too!</mark></p>
</li>
</ul>
<h2>Other Notes</h2>
<p><strong>T</strong><a href="https://www.tomshardware.com/tech-industry/artificial-intelligence/pewdiepie-unveils-uncensored-ajax-ai-model-built-to-run-on-home-pcs-creator-says-openai-banned-him-twice-while-making-it"><strong>om's Hardware - PewDiePie unveils ‘uncensored’ Ajax AI model built to run on home PCs — creator says OpenAI banned him twice over model distillation used to build his product</strong></a></p>
<ul>
<li><p>Ajax is built for Odysseus, his self-hosted AI workspace, as an autonomous, always-on agent and assistant.</p>
</li>
<li><p>The setup is similar to <a href="https://www.tomshardware.com/tech-industry/artificial-intelligence/setting-up-openclaw-isnt-as-straightforward-as-the-internet-wants-you-to-think-running-local-ai-on-humble-hardware">OpenClaw</a> and Nous Research’s Hermes Agent.</p>
</li>
<li><p>Ajax, a fine-tuned Qwen3.5-9B model...</p>
</li>
<li><p><mark class="bg-yellow-200 dark:bg-yellow-500/30">// I wonder why he used Qwen as the basis for Ajax, maybe they're less strict idk how Alibaba compares as a Chinese company vs the western based AI companies that I'm more familiar with?</mark></p>
</li>
<li><p>The video announced the first version, using Alibaba’s model, as a follow-up to his workspace launch in May.</p>
</li>
<li><p>Frontier AI model companies such as OpenAI and Anthropic make sure to hide their reasoning in numerous ways, including encryption and attempted distillation; such a campaign OpenAI recently attributed to <a href="https://www.tomshardware.com/tech-industry/artificial-intelligence/openai-says-actors-linked-to-moonshot-ai-spearheaded-a-campaign-to-extract-its-models-hidden-reasoning-logged-attempts-peaked-at-16-000-users-over-two-days">actors linked to Moonshot AI</a> is seen as a threat.</p>
</li>
<li><p>To "uncensor" his model, he relied on automatic abliteration through the open-source Heretic, where you discover prompts the model refuses to trace and remove the refusal, preferably without doing “brain damage” by removing too much.</p>
</li>
<li><p><mark class="bg-yellow-200 dark:bg-yellow-500/30">// I just liked the use of the word abliteration here haha</mark></p>
</li>
<li><p><mark class="bg-yellow-200 dark:bg-yellow-500/30">// The term combines "ablation" (surgically removing a part) and "obliteration" (destroying it).</mark></p>
</li>
<li><p>The capabilities of open models and harnesses point the way forward for users to use uncensored, less restricted intelligence on their own hardware, an important goal in keeping the technology free.</p>
</li>
</ul>
<h2>Tweets that I Saw</h2>
<p>It was all over my X/Twitter feed, which was what initially drew me to watch PewDiePie's video to understand what was going on!</p>
<p>I am disappointed that for everyone's eagerness to comment on his video, there hasn't been much interesting input, praise, or critique on his work.</p>
<p>Too early to tell I suppose.</p>
<p>Everyone's just acting shocked that he's as knowledgeable about AI as he is.</p>
<p>Which isn't very meaningful, even for a tweet, but I'm glad to have been brought awareness about his interesting project!</p>
<img src="https://cdn.hashnode.com/uploads/covers/6aabca10651797b386d56517/012aea03-d501-4018-abde-4cdc21ca6045.png" alt="" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/6aabca10651797b386d56517/747d1245-8483-40fb-8b29-9aa4e464cf18.png" alt="" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/6aabca10651797b386d56517/e956e50e-9266-42ab-a7da-62ad71b663a2.png" alt="" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/6aabca10651797b386d56517/d748fd13-1e37-47d5-bce2-8c5db6a519d5.png" alt="" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/6aabca10651797b386d56517/860c2b2b-4994-4c35-ae18-4d6e4e789641.png" alt="" style="display:block;margin:0 auto" />]]></content:encoded></item><item><title><![CDATA[Prompt Engineering Is Easy. Knowing What “Good” Looks Like Isn’t.]]></title><description><![CDATA[💡
Prompt Engineering: The Hard Part Isn’t the Prompt


TO BE ENTIRELY HONEST, my first impression of prompt engineering was that it would be reserved for the extremely technologically challenged...
I]]></description><link>https://tokenofmyattention.hashnode.dev/prompt-engineering-is-easy-knowing-what-good-looks-like-isn-t</link><guid isPermaLink="true">https://tokenofmyattention.hashnode.dev/prompt-engineering-is-easy-knowing-what-good-looks-like-isn-t</guid><dc:creator><![CDATA[Alyssa Ng]]></dc:creator><pubDate>Sat, 26 Sep 2026 08:12:07 GMT</pubDate><content:encoded><![CDATA[<div>
<div>💡</div>
<div>Prompt Engineering: The Hard Part Isn’t the Prompt</div>
</div>

<p>TO BE ENTIRELY HONEST, my first impression of prompt engineering was that it would be reserved for the extremely technologically challenged...</p>
<p>It seems entirely intuitive to me that large language models (LLMs) as a prediction engine would produce more desirable outcomes when a user is able to provide more details on the task, context, and expectations.</p>
<p>However, I have learnt that prompt engineering is more than the obvious show of writing and optimising prompts. Many people get overly fixated on that part of the process. It is harder to set up a framework for evaluating the quality/accuracy of the LLM responses and output. It can be hard to define quality and measure how desirable a result is.</p>
<h2>What is Prompt Engineering</h2>
<p>See my previous post dedicated to this!</p>
<p>(<a href="https://tokenofmyattention.hashnode.dev/prompt-engineering-how-to-communicate-effectively-with-llms">https://tokenofmyattention.hashnode.dev/prompt-engineering-how-to-communicate-effectively-with-llms</a>)</p>
<p>The simplest way to summarise this is "better prompt → better response".</p>
<p>There are multiple techniques and frameworks for people to consider when writing and improving their LLM prompts.</p>
<p>LLMs do respond to the information and instructions provided in their context. A prompt that clearly communicates the task, relevant context, constraints, and expected output can generally give the model a better basis for generating a useful response.</p>
<p>However, what defines usefulness or desirability in an LLM response may not always be obvious.</p>
<p>Prompt Engineering is not a literary competition. There is no basis for the cleverest prompt.</p>
<p>The more I learn about the topic, the more I think prompt engineering is better understood as a design and evaluation problem.</p>
<h2>Prompt Engineering Starts with Defining the Task</h2>
<p>Before optimising something, you need to know what you are optimising <em>for</em>. If the objective is vague, optimisation becomes difficult.</p>
<p>Imagine trying to improve a search engine without defining what makes a search result relevant. Or improving a recommendation system without deciding what "good recommendation" means. Or testing a software application without defining what constitutes correct behaviour.</p>
<p>Note: Personal preference is not the same thing as quality.</p>
<p>I might prefer an answer because it sounds polished, while someone else might prefer a more concise version. And both of us might be wrong because the answer contains technical inaccuracies that neither of us caught.</p>
<p>Furthermore, it is infeasible to manually read and rate every response from an LLM-powered application.</p>
<h2>Optimisation Loop</h2>
<p>Informally, a simple take on prompt engineering probably looks similar to:<br />Write prompt → Send to LLM → Get response → Looks good? → Repeat</p>
<p>The issue is that "Looks good" is not a rigorous evaluation methodology.</p>
<p>A more engineering-oriented workflow looks something like:</p>
<p>Define task →<br />Define quality criteria →<br />Build evaluation dataset →<br />Run prompt / model →<br />Evaluate outputs →<br />Analyse failures →<br />Modify prompt →<br />Re-run evaluation →<br />Compare against previous version →<br />etc.</p>
<p>The prompt is therefore only one part of the process, the evaluation loop is what allows us to determine whether our changes actually helped.</p>
<h2>1. Start by Defining the Task</h2>
<p>Before evaluating an LLM, we need to know what it is supposed to do. This sounds obvious, but LLM applications can involve surprisingly ambiguous objectives.</p>
<p>Consider a customer-support application.</p>
<p>We might ask an LLM to:</p>
<pre><code class="language-plaintext">Classify incoming customer messages into categories.
</code></pre>
<p>That sounds sufficiently specific. But what does success mean?</p>
<p>Suppose the available categories are:</p>
<pre><code class="language-plaintext">Billing 
Technical Issue 
Account Access 
Product Information 
Other
</code></pre>
<p>And there is an incoming customer message that reads:</p>
<pre><code class="language-plaintext">"I was charged twice and I can't log into my account."
</code></pre>
<p>Should this message be categorised under Billing? Account Access? Both?</p>
<p>Suddenly, the evaluation problem exposes an ambiguity in the task definition itself. Before optimising the prompt, we may need to define the expected behaviour.</p>
<p>In this case, we may add the requirement:</p>
<pre><code class="language-plaintext">Assign exactly one category based on the customer's primary issue. If multiple issues are present, select the issue most directly related to the customer's requested resolution.
</code></pre>
<p>The process of testing an LLM can reveal that the original task was not sufficiently specified.</p>
<h2>2. Build an Evaluation Dataset</h2>
<p>Once the task is defined, we need examples against which to evaluate the system. This can be thought of as an <strong>evaluation dataset</strong> or <strong>test set</strong>.</p>
<p>For our customer-support classifier, it might look like:</p>
<table>
<thead>
<tr>
<th>Input</th>
<th>Expected Output</th>
</tr>
</thead>
<tbody><tr>
<td>"I was charged twice."</td>
<td>Billing</td>
</tr>
<tr>
<td>"I forgot my password."</td>
<td>Account Access</td>
</tr>
<tr>
<td>"The application crashes when I open it."</td>
<td>Technical Issue</td>
</tr>
<tr>
<td>"What plans do you offer?"</td>
<td>Product Information</td>
</tr>
<tr>
<td>"I was charged twice and can't log in."</td>
<td>Billing</td>
</tr>
</tbody></table>
<p>The expected outputs become our reference answers, sometimes called ground truth or golden answers, depending on the evaluation setup.</p>
<p>Now the criteria for a model's response has become "Does the model's output match the expected behaviour?"</p>
<h2>3. Your Test Dataset Should Contain More Than Easy Examples</h2>
<p>A common mistake would be to create a dataset consisting only of obvious examples.</p>
<p>For example:</p>
<pre><code class="language-plaintext">"I forgot my password." → Account Access 
"My application crashes." → Technical Issue 
"I want to know your pricing." → Product Information
</code></pre>
<p>These examples are obvious, and most models will likely perform well on them. The more interesting test cases are the difficult ones.</p>
<p><strong>Ambiguous Inputs</strong></p>
<pre><code class="language-plaintext">"I can't access my account after being charged."
</code></pre>
<p><strong>Incomplete Inputs</strong></p>
<pre><code class="language-plaintext">"It doesn't work."
</code></pre>
<p><strong>Unusual Phrasing</strong></p>
<pre><code class="language-plaintext">"Money got taken twice from me."
</code></pre>
<p><strong>Typos</strong></p>
<pre><code class="language-plaintext">"I was chared twise."
</code></pre>
<p><strong>Multiple Issues</strong></p>
<pre><code class="language-plaintext">"I can't log in and I was charged twice."
</code></pre>
<p><strong>Out-of-distribution inputs</strong></p>
<pre><code class="language-plaintext">"Can I become a reseller?"
</code></pre>
<p>These cases tell us much more about how robust our prompt is.</p>
<p>This is also where evaluation datasets become valuable beyond simply measuring performance.</p>
<p>They can act as a catalogue of known failure modes.</p>
<h2>4. Define Evaluation Criteria</h2>
<p>Once we have our test cases, we need to determine how outputs will be judged.</p>
<p>For a classification task, this can be relatively straightforward. Comparing the LLM answer against our expected answer gives upfront matches or incorrect mismatches.</p>
<p>But LLMs have many applications outside of classification tasks. E.g. Consider a task to summarise a text or document. There may not be any singular correct answer. Two summaries could use completely different wording while both being excellent. This means traditional exact-match evaluation is insufficient to judge these tasks.</p>
<p>We may instead evaluate other dimensions of the answer, such as:</p>
<ul>
<li><p>Correctness: Does the output contain factual errors?</p>
</li>
<li><p>Relevance: Does it address the intended task?</p>
</li>
<li><p>Completeness: Does it include the important information?</p>
</li>
<li><p>Groundedness: Is the answer supported by the supplied source material?</p>
</li>
<li><p>Instruction Following: Did the model follow the specified requirement?</p>
</li>
<li><p>Style: Does the output match the desired tone and format?</p>
</li>
<li><p>Safety: Does the response satisfy the application's safety requirements?</p>
</li>
</ul>
<p>The exact criteria will depend heavily on the application. Every LLM with a different task will have a different metric to evaluate the quality of its output.</p>
<h2>5. Not Every Evaluation Needs The Same Metric</h2>
<p>For LLM evaluation where multiple outputs may be considered acceptable or good, we have to diverge from traditional software testing. For conventional software testing, we can often determine deterministic assertions or outputs, as the expected result is exact and always the same.</p>
<pre><code class="language-plaintext">E.g. assert calculate_tax(100, 0.1) == 10
</code></pre>
<p>For LLMs a few popular evaluation methods will be listed below:</p>
<h3>Exact-match Evaluation</h3>
<p>Same as traditional software testing. Actual output should match expected output.</p>
<p>This works well for structured tasks such as:</p>
<ul>
<li><p>classification</p>
</li>
<li><p>yes/no decisions</p>
</li>
<li><p>fixed labels</p>
</li>
<li><p>structured identifiers</p>
</li>
<li><p>exact values</p>
</li>
</ul>
<h3>Rule-based Evaluation</h3>
<p>We can also evaluate specific properties of an output.</p>
<p>For example:</p>
<pre><code class="language-plaintext">Does the response contain a valid email address? 
Does it contain exactly five bullet points? 
Is it below 200 words? 
Does it contain prohibited information? 
Is valid JSON returned?
</code></pre>
<p>These checks are deterministic and relatively easy to automate. So for structured LLM applications, output validation can be particularly valuable.</p>
<h3>Semantic Evaluation</h3>
<p>Sometimes two answers can be different strings but have essentially the same meaning.</p>
<p>For example:</p>
<pre><code class="language-plaintext">Version 1: "The meeting was postponed until Monday."
</code></pre>
<pre><code class="language-plaintext">Version 2: "The meeting has been moved to Monday."
</code></pre>
<p>An exact string comparison would mark these as different. So instead we can apply a semantic evaluation to assess whether the responses convey equivalent information. This is where techniques involving embeddings or model-based evaluation can become useful.</p>
<h2>6. LLM-as-a-Judge</h2>
<p>As always, you can count on AI to help automate repetitive tasks.</p>
<p>There is an interesting approach to use a secondary LLM to evaluate the output of your target LLM.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6aabca10651797b386d56517/1bef966c-a7f3-40e3-8223-41fc613e9e3f.png" alt="" style="display:block;margin:0 auto" />

<p>The evaluating Model B might receive instructions such as:</p>
<pre><code class="language-plaintext">Evaluate the response for factual accuracy, relevance, completeness and instruction following. 

Give each dimension a score from 1–5 and explain any identified issues.
</code></pre>
<p>This is often referred to as LLM-as-a-judge.</p>
<p>This is appealing as LLMs can process information and text to evaluate qualities that are impossible to capture with traditional coding deterministic rules. No "if/else" assertion is able to encode the question of "Does this response provide a clear explanation appropriate for a beginner?"</p>
<p>However, we still have the problem of evaluating Model B.</p>
<p>Who judges the judge? Who evaluates the evaluator?</p>
<p>The judging model itself can be prone to mistakes. Being biased to certain writing styles, failing to notice factual errors, producing inconsistent evaluations, etc.</p>
<p>An LLM judge cannot be treated as an unquestionable source of truth. So it is likely that introducing an LLM judge will come with its own round of evaluation criteria, reliability, and other qualities testing in the first place.</p>
<p>It is a lot of work, and I can only imagine justifying it when there is a need to test a lot of LLM models.</p>
<h2>7. Human Evaluation Still Matters</h2>
<p>For subjective tasks, human evaluation can remain extremely valuable.</p>
<p>However, it can be difficult to process the variance in human responses and preferences in AI responses. Just simply asking "Do you like this response?" will result in plenty of vague and inconsistent judgement.</p>
<p>Suppose we are building an AI assistant that drafts customer-support responses.</p>
<p>We could ask reviewers to rate responses on a defined rubric:</p>
<table>
<thead>
<tr>
<th>Criterion</th>
<th>1/5</th>
<th>3/5</th>
<th>5/5</th>
</tr>
</thead>
<tbody><tr>
<td>Accuracy</td>
<td>Major errors</td>
<td>Minor errors</td>
<td>Fully accurate</td>
</tr>
<tr>
<td>Relevance</td>
<td>Off-topic</td>
<td>Partially relevant</td>
<td>Directly addresses issue</td>
</tr>
<tr>
<td>Tone</td>
<td>Inappropriate</td>
<td>Acceptable</td>
<td>Appropriate</td>
</tr>
<tr>
<td>Completeness</td>
<td>Missing key information</td>
<td>Mostly complete</td>
<td>Fully addresses issue</td>
</tr>
</tbody></table>
<p>This gives human evaluation more structure and makes the judgement more consistent and reproducible.</p>
<h2>8. Evaluation Should Happen Across a Test Set</h2>
<p>Imagine a scenario where we have 100 test cases for an LLM, and we calculate the accuracy of 2 prompts.</p>
<p>Accuracy = Correct Predictions / Total Predictions</p>
<table>
<thead>
<tr>
<th>Prompt A</th>
<th>Prompt B</th>
</tr>
</thead>
<tbody><tr>
<td>92 correct</td>
<td></td>
</tr>
<tr>
<td>8 incorrect</td>
<td></td>
</tr>
<tr>
<td>92% accuracy</td>
<td>95 correct</td>
</tr>
<tr>
<td>5 incorrect</td>
<td></td>
</tr>
<tr>
<td>95% accuracy</td>
<td></td>
</tr>
</tbody></table>
<p>Here we have clear evidence that Prompt B had higher success and accuracy than Prompt A, and will likely perform better across future use cases.</p>
<h2>9. Look at the Failures, not just the Score</h2>
<p>Suppose we achieve a prompt with a high 95% accuracy rate, that may seem like a successful test set result. However, it is important to investigate further into the failures.</p>
<p>Imagine that the 5 failures are all of the same category. Eg. "Ambiguous billing issue".</p>
<p>This tells us more about the prompt and the LLM mode. It may not have a general classfication problem, it may have a specific weakness around ambiguous billing requests in particular. This allows us to improve the prompt or system based on an identified failure mode.</p>
<p>Perhaps we need an explicit instruction in the prompt for ambiguous billing cases? Or we need additional examples. Or the category definitions themselves could be further refined. Or the model itself could be further refined with more data.</p>
<p>This is much more informative than the simple statistic of a 95% accuracy rate</p>
<h2>10. Few-Shot Examples become Testable Interventions</h2>
<p>This also changes how I think about techniques such as few-shot prompting. Instead of adding examples because they "seem helpful," we can test whether they actually improve performance.</p>
<pre><code class="language-plaintext">Version A: Classify the customer request into one of the following categories...
</code></pre>
<pre><code class="language-plaintext">Classify the customer request into one of the following categories. 

Example 1: 
Input: "I forgot my password." 
Output: Account Access 

Example 2: 
Input: "I was charged twice." 
Output: Billing 

Now classify: {input}
</code></pre>
<p>We can run both prompts across the same evaluation dataset. Perhaps Version B improves accuracy, perhaps it does not. Perhaps it improves ambiguous cases while making another category worse.</p>
<p>The point is that prompting techniques become hypotheses to test, rather than techniques that we assume must work.</p>
<h2>11. Prompt Versions should be treated like Software Versions</h2>
<p>This was unexpected to me. This is another area where LLM development starts to resemble traditional software engineering.</p>
<p>You can version out your prompts with incremental improvements along the way.</p>
<p>For example:</p>
<table style="min-width:50px"><colgroup><col style="min-width:25px"></col><col style="min-width:25px"></col></colgroup><tbody><tr><td><p>prompt_v1</p></td><td><p>v1: Basic instruction</p></td></tr><tr><td><p>prompt_v2</p></td><td><p>v2: Added output format</p></td></tr><tr><td><p>prompt_v3</p></td><td><p>v3: Added examples for ambiguous cases</p></td></tr></tbody></table>

<p>Each version represents a change, and if the same evaluatin dataset is maintained, it is possible to compare the performance of each version against each other. This creates a basic form of regression testing, where the goal is for each systematic change to improve the LLM behaviour without breaking or deteriorating any existing behaviour that was already working.</p>
<p>Having a clear version list with changes made makes it easier to keep track of progress and any mistakes or regression made.</p>
<h2>12. Evaluation Datasets Should Evolve</h2>
<p>A test dataset is not something we necessarily create once and forget. As we discover new failure modes, we can add them in. Over time, the dataset becomes a collection of cases that represent the behaviour we care about.</p>
<p>This creates an interesting feedback loop:</p>
<p>Real-world failures → evaluation cases → prompt improvements → better system</p>
<p>Thus, the evaluation dataset effectively becomes part of the engineering infrastructure.</p>
<h2>13. LLM Evaluation is Inherently Application-Specific</h2>
<p>Once again, this boils down to: There is no universal definition of a "good LLM response."</p>
<p>Consider two systems.</p>
<p><strong>System A: Creative Writing Assistant</strong></p>
<p>We might care about:</p>
<ul>
<li><p>creativity</p>
</li>
<li><p>style</p>
</li>
<li><p>coherence</p>
</li>
<li><p>originality</p>
</li>
<li><p>engagement</p>
</li>
</ul>
<p><strong>System B: Enterprise knowledge assistant</strong></p>
<p>We might care much more about:</p>
<ul>
<li><p>roundedness</p>
</li>
<li><p>citation correctness</p>
</li>
<li><p>completeness</p>
</li>
<li><p>instruction following</p>
</li>
<li><p>refusal of unsupported claims</p>
</li>
</ul>
<p>The same output could potentially be desirable in one application and unacceptable in another.</p>
<p>This means that evaluation cannot be separated from the purpose of the system.</p>
<h2>14. The Evaluation Pipeline</h2>
<p>Putting everything together, an LLM evaluation workflow might look something like:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6aabca10651797b386d56517/c9833f2a-a4d7-429f-a846-c6be1b5114c8.png" alt="" style="display:block;margin:0 auto" />

<p>The actual implementation can be considerably more sophisticated, but the fundamental loop remains similar.</p>
<h2>My Takeaways</h2>
<p>Rather than thinking about prompt engineering as: "How do I phrase my instruction?"</p>
<p>I now find it more useful to think of: "I have an LLM-based system with a desired behaviour. How can I define, measure and improve that behaviour?"</p>
<p>The prompt is merely one of the levers I can change and manipulate to get my target result. The evaluation framework tells me whether pulling that lever actually helped. And the test dataset gives me the evidence to make that decision.</p>
<p>This makes prompt engineering feel much closer to an empirical engineering discipline than a collection of clever prompting tricks.</p>
<h2>Resources</h2>
<ul>
<li><p>OpenAI - Evaluation Best Practices</p>
</li>
<li><p>OpenAI - Getting Started with Datasets / Evals</p>
</li>
<li><p>OpenAI - Model Optimization</p>
<ul>
<li><p>Optimizing LLM Accuracy</p>
</li>
<li><p>Generative AI Evaluation</p>
</li>
</ul>
</li>
<li><p>A Survey on LLM-as-a-Judge - arXiv</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Prompt Engineering: How to Communicate Effectively with LLMs]]></title><description><![CDATA[Compare these two prompts:
Prompt 1: Write a cover letter for me.

Prompt 2: Write a professional but personable cover letter for a Software Engineer position at a technology company.

My background: ]]></description><link>https://tokenofmyattention.hashnode.dev/prompt-engineering-how-to-communicate-effectively-with-llms</link><guid isPermaLink="true">https://tokenofmyattention.hashnode.dev/prompt-engineering-how-to-communicate-effectively-with-llms</guid><dc:creator><![CDATA[Alyssa Ng]]></dc:creator><pubDate>Thu, 24 Sep 2026 05:03:05 GMT</pubDate><content:encoded><![CDATA[<p>Compare these two prompts:</p>
<pre><code class="language-plaintext">Prompt 1: Write a cover letter for me.
</code></pre>
<pre><code class="language-plaintext">Prompt 2: Write a professional but personable cover letter for a Software Engineer position at a technology company.

My background: I have a Computer Science degree and three years of experience working in software development and technical project coordination.

Emphasise my experience working across engineering teams, debugging software issues, and coordinating multiple projects. Keep it under 400 words and avoid generic phrases such as "I am excited to apply."
</code></pre>
<p>The second prompt gives the model considerably more information about the task, context, constraints, and desired output.</p>
<p>This is the basic idea behind prompt engineering.</p>
<p>Rather than treating an LLM like a search box, prompt engineering is about learning how to communicate with a model in a way that makes the desired outcome clearer and more reproducible.</p>
<h2>What is Prompt Engineering?</h2>
<p>Prompt engineering is the process of designing and refining instructions given to a language model so that it produces an output that better meets a particular objective.</p>
<p>A prompt can be as simple as:</p>
<pre><code class="language-plaintext">"Explain quantum computing."
</code></pre>
<p>Or it can contain multiple components:</p>
<ul>
<li><p>A task</p>
</li>
<li><p>Background context</p>
</li>
<li><p>Constraints</p>
</li>
<li><p>Examples</p>
</li>
<li><p>Desired output format</p>
</li>
<li><p>Tone or style</p>
</li>
<li><p>Information the model should use</p>
</li>
<li><p>Instructions about what to avoid</p>
</li>
</ul>
<p>For example:</p>
<pre><code class="language-plaintext">Task: 
Explain Retrieval-Augmented Generation (RAG). 

Audience: 
A beginner who understands basic LLM concepts. 

Requirements: 
- Explain the problem RAG solves 
- Describe the retrieval and generation stages 
- Give a simple real-world analogy 
- Include one practical example 

Output: Use headings and keep the explanation under 600 words.
</code></pre>
<p>The goal isn't simply to make a prompt longer.</p>
<p>The goal is to make the model's job clearer.</p>
<h2>Why Does Prompt Engineering Matter?</h2>
<p>LLMs don't inherently know what we mean when we give them an ambiguous instruction.</p>
<p>Consider:</p>
<pre><code class="language-plaintext">"Tell me about Python."
</code></pre>
<p>Depending on the context, we could be asking about:</p>
<p>The Python programming language Python's history Python syntax Python libraries Python as a career Python the animal</p>
<p>A more precise prompt reduces this ambiguity:</p>
<pre><code class="language-plaintext">"I'm a beginner learning programming. Explain what Python is, why it is commonly used for AI and data science, and show me three simple examples of Python syntax."
</code></pre>
<p>The model now has considerably more information about what constitutes a useful answer.</p>
<p>This is why effective prompting is less about discovering a magical combination of words and more about communicating requirements clearly.</p>
<p>OpenAI, Google, Microsoft and Anthropic all emphasise variations of the same fundamental principle: provide clear instructions, relevant context, and appropriate constraints, then iterate based on the results.</p>
<h2>A Useful Mental Model: Task + Context + Constraints + Output</h2>
<p>One way I find useful to think about prompts is to break them into four components. Task Context Constraints Output.</p>
<h3>Task</h3>
<p>What do you want the model to do?</p>
<p>Examples:</p>
<pre><code class="language-plaintext">Summarise this article. Explain this Python function. Compare these two approaches. Generate five ideas for a blog post.
</code></pre>
<p>The task should be explicit.</p>
<p>Instead of:</p>
<pre><code class="language-plaintext">"What do you think about this?"
</code></pre>
<p>Try:</p>
<pre><code class="language-plaintext">"Identify the three strongest arguments in this proposal and explain one potential weakness for each."
</code></pre>
<h3>Context</h3>
<p>What information does the model need to complete the task?</p>
<p>For example:</p>
<pre><code class="language-plaintext">I am a beginner learning about machine learning.
</code></pre>
<p>or:</p>
<pre><code class="language-plaintext">This presentation is intended for non-technical business executives.
</code></pre>
<p>or:</p>
<pre><code class="language-plaintext">The following text is an internal project update. Do not introduce information that isn't contained in the text.
</code></pre>
<p>Context gives the model information that might otherwise be missing.</p>
<p>This is especially important for domain-specific tasks.</p>
<h3>Constraints</h3>
<p>What boundaries should the model follow?</p>
<p>For example:</p>
<pre><code class="language-plaintext">Keep the answer under 500 words. Use only the information provided below. Do not use technical jargon without explaining it. Return exactly five recommendations.
</code></pre>
<p>Constraints help define what a successful response should look like.</p>
<h3>Output</h3>
<p>What should the final response look like?</p>
<p>You can specify:</p>
<pre><code class="language-plaintext">- Markdown
- Bullet points
- Tables
- JSON
- An email
- A step-by-step explanation
- A specific tone
- A specific length
</code></pre>
<p>For example:</p>
<p>Return the results as a Markdown table with these columns:</p>
<pre><code class="language-plaintext">| Concept | Definition | Example | Common Mistake |
</code></pre>
<p>This is particularly useful when the output will subsequently be processed by another system or used as structured data.</p>
<h2>Some Common Prompt Engineering Techniques</h2>
<p>Once the basics are understood, there are several techniques worth experimenting with.</p>
<h3>Zero-Shot Prompting</h3>
<p>The simplest approach is to give the model a task without providing examples.</p>
<pre><code class="language-plaintext">Classify the following review as positive, negative, or neutral: "The battery life is excellent, but the screen is disappointing."
</code></pre>
<p>The model has to infer the task from the instruction alone.</p>
<p>This is often sufficient for straightforward tasks.</p>
<h3>Few-Shot Prompting</h3>
<p>Instead of explaining the task abstractly, provide examples of the desired behaviour.</p>
<p>For example:</p>
<pre><code class="language-plaintext">Classify each sentence as positive or negative.

Example: "I love this laptop." → Positive

Example: "The keyboard feels terrible." → Negative

Now classify: "The display is beautiful." →
</code></pre>
<p>The examples give the model a pattern to follow.</p>
<p>Few-shot prompting can be particularly useful when the desired output has a specific structure or classification scheme.</p>
<h3>Role Prompting</h3>
<p>Another commonly used technique is to specify a role or perspective.</p>
<p>For example:</p>
<pre><code class="language-plaintext">You are a senior software engineer reviewing code written by a junior developer.

Review the following code for:
1. Bugs
2. Security issues
3. Readability
4. Performance

Explain your recommendations clearly and provide corrected code where appropriate.
</code></pre>
<p>This establishes a perspective and gives the model a clearer set of responsibilities.</p>
<p>However, I don't think of role prompting as simply saying:</p>
<pre><code class="language-plaintext">"You are an expert."
</code></pre>
<p>and expecting better answers dramatically.</p>
<p>The more useful part is defining what the model should actually do in that role.</p>
<p>Anthropic's prompting guidance similarly treats roles as one technique among several, alongside clarity, examples, context and structured prompts.</p>
<h3>Structured Prompts</h3>
<p>For more complicated tasks, structuring the prompt can make both the prompt and the resulting output easier to understand.</p>
<p>For example:</p>
<pre><code class="language-plaintext">## Role
You are a technical writer.

## Task
Explain Retrieval-Augmented Generation.

## Audience
Computer Science students who understand basic LLM concepts.

## Include
- What RAG is
- Why it is useful
- How retrieval works
- How generation works
- A simple example

## Constraints
- Avoid unnecessary jargon
- Use one analogy
- Keep the article below 1,000 words

## Output
Use Markdown headings and bullet points.
</code></pre>
<p>Markdown headings, lists and other delimiters can make logical boundaries clearer to the model. XML-style tags can also be useful, particularly when separating instructions from large blocks of reference material.</p>
<h2>Prompt Engineering Is Iterative</h2>
<p>One of the biggest takeaways from learning about prompt engineering is that writing a prompt isn't necessarily a one-shot process.</p>
<p>You might start with:</p>
<pre><code class="language-plaintext">Explain RAG.
</code></pre>
<p>The answer might be technically correct but too advanced.</p>
<p>So you refine it:</p>
<pre><code class="language-plaintext">Explain RAG to someone who understands what an LLM is but has never encountered RAG. 

Use a simple analogy and explain: 
1. Why RAG is needed 
2. How retrieval works 
3. How the retrieved information is used to generate an answer
</code></pre>
<p>Then perhaps you realise the explanation is still too long:</p>
<pre><code class="language-plaintext">Keep the explanation below 500 words.
</code></pre>
<p>Then you might want to test whether the model understood the concept:</p>
<pre><code class="language-plaintext">After explaining RAG, give me three questions to test my understanding. Do not provide the answers until I respond.
</code></pre>
<p>This creates a cycle:</p>
<p>Prompt → Output → Evaluate → Refine → Output</p>
<p>OpenAI explicitly recommends iterative refinement, while Anthropic recommends establishing success criteria and ways to evaluate the result before attempting to optimise a prompt.</p>
<h2>Prompt Engineering Has Limits</h2>
<p>It is also important not to treat prompt engineering as a solution to every LLM problem.</p>
<p>If a model doesn't have the information required to answer a question, simply making the prompt longer doesn't magically give it that information.</p>
<p>Similarly, a prompt cannot guarantee that an LLM will always produce a correct answer.</p>
<p>Depending on the problem, other approaches may be more appropriate, such as:</p>
<ul>
<li><p>Retrieval-Augmented Generation (RAG)</p>
</li>
<li><p>Tool use</p>
</li>
<li><p>Function calling</p>
</li>
<li><p>Fine-tuning</p>
</li>
<li><p>Model selection</p>
</li>
<li><p>Evaluation systems</p>
</li>
<li><p>Better source data</p>
</li>
<li><p>Application-level validation</p>
</li>
</ul>
<p>Anthropic's prompt engineering documentation makes a similar point: some problems that appear to be prompting problems may instead be better addressed through model selection, evaluation, or other system-level changes.</p>
<p>This is an important shift in perspective.</p>
<p>Prompt engineering is one component of building useful AI systems, not the entire solution.</p>
<h2>(WIP) Add On: I should discuss LLMs doing their own prompt engineering.</h2>
<p>I was going to dedicate another article to this, but I fear that the section is short enough to add here when I have the time.</p>
<p>Summary: You can prompt an LLM to help draft/improve/modify/write better. Especially useful for prompts that will be reused often.</p>
<h2>Resources</h2>
<ul>
<li><p><a href="https://help.openai.com/en/articles/10032626-prompt-engineering-best-practices-for-chatgpt">OpenAI - Prompt engineering best practices for ChatGPT</a></p>
<ul>
<li><p>Can read up on other similar companies' documentation</p>
</li>
<li><p>OpenAI</p>
</li>
<li><p>Google Cloud</p>
</li>
<li><p>Anthropic</p>
</li>
<li><p>Microsoft</p>
</li>
</ul>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[RAG Explained: How AI Learns to Answer Questions About Your Data]]></title><description><![CDATA[💡
What is an AI's favorite cleaning tool? A RAG-enabled mop for sweeping up hallucinations. 😛


Large Language Models (LLMs) are AI models that are remarkably good at generating answers written in h]]></description><link>https://tokenofmyattention.hashnode.dev/rag-explained-how-ai-learns-to-answer-questions-about-your-data</link><guid isPermaLink="true">https://tokenofmyattention.hashnode.dev/rag-explained-how-ai-learns-to-answer-questions-about-your-data</guid><dc:creator><![CDATA[Alyssa Ng]]></dc:creator><pubDate>Mon, 21 Sep 2026 09:38:10 GMT</pubDate><content:encoded><![CDATA[<div>
<div>💡</div>
<div>What is an AI's favorite cleaning tool? A <strong>RAG</strong>-enabled mop for sweeping up hallucinations. 😛</div>
</div>

<p>Large Language Models (LLMs) are AI models that are remarkably good at generating answers written in human-like text.</p>
<p>Retrieval-Augmented Generation (RAG) is a technique / AI architecture design that enables LLMs to retrieve and incorporate new information from external data sources, at the time when a question is asked.</p>
<p>Not all AI models can access information beyond the data they were trained on. Therefore, AI architects and developers must consider whether it is practical and effective to incorporate the required data directly into the model's training process, or whether the data should instead remain external and be retrieved by the model only when needed.</p>
<p>For example, imagine asking an LLM about a company's internal policies, a private knowledge base, or a document that was just freshly published. The LLM may simply not have that information, as such data was not included in its training process.</p>
<p>You could fine-tune the model on the company's employee handbook and private databases, but that makes the model inflexible to updates and policy changes, as updating and re-running the AI model training process can be a computationally exhausting task.</p>
<p>RAG takes a different approach: Instead of modifying the AI model itself, we can keep the company's documents and policies outside the model, and retrieve the relevant information as needed. So data and policy changes can be quickly modified and updated directly to the external database, without needing to retrain the model.</p>
<p>The model does not need to contain the entire knowledge base. It just needs be able to use the RAG system to obtain the right information in its context when it generates its LLM answer.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6aabca10651797b386d56517/d5a91413-648f-46f6-9d4e-aeb97dce7e7c.png" alt="" style="display:block;margin:0 auto" />

<p>As shown in the flow chart above, the process of generating an answer to a user's question can be summarised as:</p>
<p><strong>Retrieve relevant information → give it to LLM → generate an answer</strong></p>
<p>This simple idea has become one of the fundamental patterns for building AI applications, especially when dealing with private, domain-specific, and frequently changing data.</p>
<h2>3 Stages of RAG (Retrieval-Augmented Generation)</h2>
<p>The name describes the 3 core stages</p>
<ol>
<li><p><strong>Retrieval:</strong> Finding information relevant to the user's question.</p>
</li>
<li><p><strong>Augmentation</strong>: Add that retrieved information to the prompt sent to the LLM.</p>
</li>
<li><p><strong>Generation</strong>: Ask the LLM to generate an answer using the additional context.</p>
</li>
</ol>
<img src="https://cdn.hashnode.com/uploads/covers/6aabca10651797b386d56517/6e59da32-e0a1-4427-89b5-e9586a8781f7.png" alt="" style="display:block;margin:0 auto" />

<p>Microsoft describes this basic pattern as retrieving <strong>grounding data</strong>, providing it to the model, and generating a response grounded in that information.</p>
<p>(The concept of grounding to avoid hallucinations to be elaborated on further below... )</p>
<h3>Why can't we just put the entire document into the prompt?</h3>
<p>Sometimes we can!</p>
<p>But imagine a company has:</p>
<ul>
<li><p>10,000 PDF documents</p>
</li>
<li><p>thousands of web pages</p>
</li>
<li><p>internal wiki pages</p>
</li>
<li><p>product specifications</p>
</li>
<li><p>technical documentation</p>
</li>
<li><p>customer records</p>
</li>
</ul>
<p>Often times we know the data we want is from a specific PILE of documents, but we have trouble identifying which one precisely. Sending everything to the LLM for every question would be extremely inefficient.</p>
<p>Instead, RAG creates a searchable representation of the knowledge base.</p>
<p>The system can then retrieve only the pieces that are likely to be relevant.</p>
<p><strong>Overview of the Process</strong></p>
<img src="https://cdn.hashnode.com/uploads/covers/6aabca10651797b386d56517/f99a732a-4588-4579-8140-1158b747e017.png" alt="" style="display:block;margin:0 auto" />

<h3>Step 0a: Split the Document into Chunks</h3>
<p>Before we can retrieve information, documents usually need to be broken into smaller pieces called <strong>chunks</strong>.</p>
<p>For example:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6aabca10651797b386d56517/2613c4a9-a027-40ed-91e5-0838268cb1b2.png" alt="" style="display:block;margin:0 auto" />

<p>Retrieval works better when the system can identify the specific section that answers the question.</p>
<p>There are different chunking strategies / methods that work to divide a document into smaller pieces.</p>
<p>It is often more complicated than simply choosing an arbitrary number of characters to divide the text by.</p>
<p>A chunk that is too small may lose important context. While a chunk that is too large may group lots of irrelevant information together.</p>
<p>This makes chunking strategy one of the important designs in a RAG System.</p>
<h3>Step 0b: Turn Chunks into Embeddings</h3>
<p>This is where the concept of embeddings becomes especially useful.</p>
<p>An embedding model converts text into a numerical representation (aka a vector coordinates in a high n-dimensional vector space).</p>
<p>E.g. "How many days of annual leave do employees receive?" → Embedding Model → [0.12, -0.43, 0.19, ..., 0.31]</p>
<p>Each chunk will receive its own embedding from the embedding model. The goal is not to encode the exact words, but the vector should represent aspects of the text's meaning. This will allow us to compare a user's question against document chunks based on semantic similarity.</p>
<p>E.g.</p>
<ul>
<li><p>User Question: "How much vacation can I take?"</p>
</li>
<li><p>Document Chunk: "Employees are entitled to 15 days of annual leave..."</p>
</li>
</ul>
<p>There is semantic similarity between the User Question and the Document Chunk. The words are different, but the concepts are closely related.</p>
<p>Ideally the embedding model will be able to convey the relationship between the 2 similar concepts, and make it easier to retrieve the information.</p>
<h3>Step 0c: Store the Embeddings</h3>
<p>The embeddings can be stored in a system designed for efficient retrieval. This might be a vector database or a search engine supporting vector search.</p>
<p>E.g.</p>
<p>Document Chunk → Embedding Model → Vector → Vector Index</p>
<p>The database may not only store the numerical vector, but also additional metadata. The metadata can later help with filtering, citations, and access control.</p>
<p>E.g.</p>
<pre><code class="language-plaintext">{ 
    "document": "employee_handbook.pdf", 
    "section": "annual_leave", 
    "page": 42, 
    "text": "Employees are entitled to..." 
}
</code></pre>
<h3>Step 1: Retrieve Relevant Chunks</h3>
<p>When a user asks the LLM a question, the text of the question will also get converted into an embedding.</p>
<p>The Question Vector is then used to find similar Document Chunk Vectors.</p>
<p>Those vectors then become reference points to pull out the relevant document information.</p>
<p>The relevant information is then passed into the LLM to be processed.</p>
<p>E.g.</p>
<ul>
<li><p>User Question: "How much vacation can I take?"</p>
</li>
<li><p>User Questions → Embedding Model → Query Vector → Search Database Vector Index to find similar Document Chunk Vectors → Return Most Relevant Chunks</p>
</li>
<li><p>The retrieval system might return:</p>
<ul>
<li><p>1. Annual Leave Policy</p>
</li>
<li><p>2. Leave Entitlement</p>
</li>
<li><p>3. Leave Carry-Forward Rules</p>
</li>
</ul>
</li>
<li><p>These retrieved chunks then become the context that we give to the LLM.</p>
</li>
</ul>
<h3>Step 2: Augment the Prompt</h3>
<p>Augment the prompt to be passed to the LLM.</p>
<p>Instead of simply sending: "How much vacation can I take?"</p>
<p>We can provide the LLM with the retrieved information:</p>
<ul>
<li><p>Data Context: 1. Annual Leave Policy | 2. Leave Entitlement | 3. Leave Carry-Forward Rules</p>
</li>
<li><p>User Question: "How much vacation can I take?"</p>
</li>
</ul>
<p>The LLM can now generate an answer using information retrieved from the company's knowledge base.</p>
<h3>Step 3: Generate the Answer</h3>
<p>Finally, the LLM receives: (User Question + Retrieved Context).</p>
<p>Then it processes this modified/augmented input.</p>
<p>And generates the final answer.</p>
<p>For example: "Employees are entitled to 15 days of annual leave per calendar year."</p>
<p>The important part is that the answer is grounded in retrieved information rather than relying entirely on the model's pre-trained knowledge.</p>
<h2>The Complete RAG Pipeline</h2>
<p>Putting everything together...</p>
<img src="https://cdn.hashnode.com/uploads/covers/6aabca10651797b386d56517/31a4a561-2f22-43e5-a4f4-e99a2c94f18a.png" alt="" style="display:block;margin:0 auto" />

<p>This separation between <strong>indexing</strong> and <strong>querying</strong> is an important part of understanding how real RAG systems work.</p>
<h2>Does RAG Eliminate Hallucinations?</h2>
<p>No. :(</p>
<p>This is one of the most critical and important misconceptions about RAG.</p>
<p>In fact I was also confused to learn otherwise as I have previously read articles that said RAG was one of the main techniques to counter AI hallucinations.</p>
<p>My improved understanding of the RAG method and the step-by-step process has cleared up my confusion and helped me to think more clearly about the relationship between LLM and the RAG method!</p>
<p>RAG can help ground an LLM's response in external information, but it doesn't guarantee that the final answer is correct.</p>
<p>There are several possible failure points.</p>
<h3>Failure 1: Bad Retrieval</h3>
<p>The correct information exists, but the system retrieves the wrong chunks.</p>
<p>User Question → Poor Retrieval → Wrong Context → LLM → Wrong Answer</p>
<h3>Failure 2: Missing Information</h3>
<p>The answer is simply not in the knowledge base.</p>
<h3>Failure 3: Poor Chunking</h3>
<p>The relevant information may have been split in a way that removes necessary context.</p>
<h3>Failure 4: Poor Generation</h3>
<p>The correct information was retrieved, but the LLM itself misunderstood, or incorrectly synthesized it, or still continued to hallucinate.</p>
<p>This means improving a RAG system isn't simply about choosing a better LLM.</p>
<p>You also need to improve the <strong>retrieval pipeline</strong>.</p>
<h2>Beyond Basic RAG</h2>
<p>A basic RAG implementation might look like:</p>
<p>Question → Vector Search → Top-K Chunks → LLM</p>
<p>But the real-world systems can become much more sophisticated by integrating other methods and technology.</p>
<p>They may include:</p>
<ul>
<li><p>keyword search</p>
</li>
<li><p>semantic search</p>
</li>
<li><p>hybrid search</p>
</li>
<li><p>metadata filtering</p>
</li>
<li><p>query rewriting</p>
</li>
<li><p>query decomposition</p>
</li>
<li><p>reranking</p>
</li>
<li><p>multiple retrieval steps</p>
</li>
<li><p>citations</p>
</li>
<li><p>retrieval evaluation</p>
</li>
<li><p>response evaluation</p>
</li>
</ul>
<p>For example, hybrid search can combine traditional lexical matching with semantic/vector retrieval.</p>
<p>Microsoft's current RAG guidance discusses vector, full-text, hybrid and multiple-search approaches as part of designing retrieval systems. (To do further research in the future)</p>
<h2>RAG vs Fine-Tuning an LLM</h2>
<p>This is another area of confusion for many, but RAG and fine-tuning solve different problems.</p>
<p>RAG changes what information the model can access.</p>
<p>Fine-tuning changes how the model behaves.</p>
<h3>RAG</h3>
<p>Useful when you want the model to access:</p>
<ul>
<li><p>private information</p>
</li>
<li><p>frequently changing information</p>
</li>
<li><p>company documentation</p>
</li>
<li><p>product documentation</p>
</li>
<li><p>knowledge bases</p>
</li>
<li><p>external sources</p>
</li>
</ul>
<h3>Fine-tuning</h3>
<p>Useful when you want to change aspects of how a model behaves, such as:</p>
<ul>
<li><p>output style</p>
</li>
<li><p>formatting</p>
</li>
<li><p>specialised task behaviour</p>
</li>
<li><p>domain-specific patterns</p>
</li>
</ul>
<h2>My Thoughts on RAG</h2>
<p>I think RAG is an interesting example of how useful AI applications are often more complex than most of the public would assume, and how huge improvements in AI can come from updates in smaller components and tools that work together behind the scenes to produce better results as a whole.</p>
<p>An LLM by itself is essentially a powerful language model.</p>
<p>But a useful AI application often looks more like:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6aabca10651797b386d56517/b05e3760-5c71-4954-ac9e-82601a0890dc.png" alt="" style="display:block;margin:0 auto" />

<p>The intelligence of the application isn't necessarily contained entirely inside the model.</p>
<p>It's also in the surrounding system:</p>
<p>Data + Retrieval + Orchestration + Model + Evaluation</p>
<p>That's what makes RAG such an important pattern for modern AI applications.</p>
<h2>Moving Forward</h2>
<p>Understanding basic RAG is only the beginning.</p>
<p>The next questions become much more interesting:</p>
<ul>
<li><p>How should documents be chunked?</p>
</li>
<li><p>How do we choose an embedding model?</p>
</li>
<li><p>How many chunks should we retrieve?</p>
</li>
<li><p>When should we use hybrid search?</p>
</li>
<li><p>How do we rerank results?</p>
</li>
<li><p>How do we evaluate retrieval quality?</p>
</li>
<li><p>How do we handle conflicting documents?</p>
</li>
<li><p>How do we cite sources?</p>
</li>
<li><p>How does RAG work with tables and images?</p>
</li>
<li><p>What is GraphRAG?</p>
</li>
<li><p>What is agentic RAG?</p>
</li>
</ul>
<p>These are the problems that turn a simple "chat with your PDF" demo into an actual AI engineering system.</p>
<p>And that's probably the most important thing I've learned about RAG so far: <strong>A RAG application isn't just an LLM with a vector database attached.</strong></p>
<p>It's a retrieval system, a data pipeline, and a generation system working together.</p>
<h2>Resources:</h2>
<ul>
<li><p><a href="https://learn.microsoft.com/en-us/training/modules/rag-fundamentals/">Microsoft - Introduction to retrieval-augmented generation concepts</a></p>
</li>
<li><p><a href="https://learn.microsoft.com/en-us/azure/foundry/concepts/retrieval-augmented-generation">Microsoft - Retrieval augmented generation (RAG) and indexes</a></p>
</li>
<li><p><a href="http://learn.microsoft.com/en-us/shows/generative-ai-for-beginners/retrieval-augmented-generation-rag-and-vector-databases-generative-ai-for-beginners">Microsoft - Generative AI for Beginners</a></p>
</li>
<li><p><a href="https://www.pinecone.io/learn/retrieval-augmented-generation/">pinecone - Retrieval-Augmented Generation (RAG)</a></p>
</li>
<li><p><a href="https://en.wikipedia.org/wiki/Retrieval-augmented_generation">Wikipedia - Retrieval-augmented generation</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[LLMs Explained: Tokens, Context Windows, Parameters & Embeddings]]></title><description><![CDATA[Large Language Models (LLM) refers to a type of AI model (typically a neural network). It has quickly become one of the most important technologies, utilised in tools such as ChatGPT, Gemini, Claude, ]]></description><link>https://tokenofmyattention.hashnode.dev/llms-explained-tokens-context-windows-parameters-embeddings</link><guid isPermaLink="true">https://tokenofmyattention.hashnode.dev/llms-explained-tokens-context-windows-parameters-embeddings</guid><dc:creator><![CDATA[Alyssa Ng]]></dc:creator><pubDate>Fri, 18 Sep 2026 05:37:30 GMT</pubDate><content:encoded><![CDATA[<p>Large Language Models (LLM) refers to a type of AI model (typically a neural network). It has quickly become one of the most important technologies, utilised in tools such as ChatGPT, Gemini, Claude, etc. It is a key component for AI to process and generate human-readable language.</p>
<p>Despite how frequently LLMs are discussed, some of the fundamental concepts behind them can be surprisingly difficult to distinguish. What exactly is a token? How does a context window differ from a model's parameters? And where do embeddings fit into the picture?</p>
<p>Below are some of the key concepts behind LLMs, that will provide a useful foundation for learning how LLMs function:</p>
<ul>
<li><p><strong>Tokens</strong>: how text is represented as discrete units</p>
</li>
<li><p><strong>Context windows</strong>: how much information a model can process at once</p>
</li>
<li><p><strong>Parameters</strong>: the learned values that determine how a model behaves</p>
</li>
<li><p><strong>Embeddings</strong>: numerical representations that capture semantic relationships</p>
</li>
</ul>
<h2>Tokens: How LLMs Read Text</h2>
<p>While humans can naturally understand words, phrases, and sentences to parse meaning and information, machines can only process numbers. Hence, the text must be converted to numbers.</p>
<p>One way of doing this is using tokenisation. Where text is broken down into small tokens, discrete units that can then be associated to a numerical integer index.</p>
<h3>The Tokenisation Algorithm</h3>
<p>A common misconception is that one word corresponds to one token.</p>
<p>This may be true in some cases, but it is not necessary.</p>
<p>A single token may represent:</p>
<ul>
<li><p>an entire word</p>
</li>
<li><p>part of a word</p>
</li>
<li><p>punctuation</p>
</li>
<li><p>whitespace</p>
</li>
<li><p>numbers</p>
</li>
<li><p>special characters</p>
</li>
</ul>
<p>The exact tokenisation depends on the model and tokeniser being used.</p>
<p>A relatively uncommon or long word may be split into multiple small subword tokens for processing.</p>
<p>This approach allows models to represent a very large vocabulary without requiring a separate token for every possible word.</p>
<h3>Practical Tips for Tokenisation</h3>
<p>If an application has a context limit of a certain number of tokens, the limit applies to the tokenised representation of the input, not simply to the number of words.</p>
<p>This is particularly important when working with:</p>
<ul>
<li><p>long documents</p>
</li>
<li><p>source code</p>
</li>
<li><p>chat histories</p>
</li>
<li><p>retrieved documents</p>
</li>
<li><p>structured data</p>
</li>
<li><p>multilingual text</p>
</li>
</ul>
<p>A prompt that appears relatively short to a human can still consume a substantial number of tokens depending on its content.</p>
<h2>Context Windows: The Model's Working Context</h2>
<p>A model's <strong>context window</strong> refers to the amount of tokenised information it can consider within a single processing context. It is the max amount od information the AI model can process at one time.</p>
<p>This can include both the user's input and other information provided to the model, such as:</p>
<ul>
<li><p>previous conversation messages</p>
</li>
<li><p>system instructions</p>
</li>
<li><p>retrieved documents</p>
</li>
<li><p>tool outputs</p>
</li>
<li><p>other contextual information</p>
</li>
</ul>
<p>The larger the context window, the more information will be considered in processing a suitable response. But more memory and computation are required.</p>
<p>It is similar to RAM in concept, where only so much data can fit at a time, and anything outside is not immediately computed.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6aabca10651797b386d56517/04bb83f7-6873-4037-8ad1-d423dcbf9d76.png" alt="" style="display:block;margin:0 auto" />

<h3>Context window ≠ model knowledge</h3>
<p>It is a common misunderstanding that the context window limits the model's full scope of information.</p>
<p>An LLM may have been trained on a large amount of information, but that does not mean all of that information is simultaneously present in its context.</p>
<p>A useful distinction is:</p>
<p><strong>Training data → learned into parameters</strong></p>
<p><strong>Prompt/context → information currently available to the model</strong></p>
<p>The context window determines how much tokenised information can be supplied to the model during a particular interaction.</p>
<h3>Why Context Windows Matter</h3>
<p>Larger context windows can be useful for tasks involving large amounts of information, such as:</p>
<ul>
<li><p>analysing lengthy documents</p>
</li>
<li><p>reviewing large codebases</p>
</li>
<li><p>maintaining long conversations</p>
</li>
<li><p>comparing multiple sources</p>
</li>
<li><p>processing large datasets</p>
</li>
</ul>
<p>However, simply increasing the context window does not automatically guarantee better reasoning or better answers. The quality, relevance, and organisation of the information provided to the model still matter.</p>
<h2>Parameters: What the Model Learns</h2>
<p>If tokens describe the information being presented to a model, <strong>parameters</strong> are part of what the model has learned during training.</p>
<p>Parameters are numerical values that are adjusted during the training process.</p>
<p>A simplified view of training looks like this:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6aabca10651797b386d56517/266f49ee-7fa6-4637-af55-60481435dfe9.png" alt="" style="display:block;margin:0 auto" />

<p>Through repeated training, the model adjusts its parameters so that it becomes better at predicting the next token.</p>
<p>Modern neural networks can contain billions or even hundreds of billions of parameters.</p>
<h3>What Are Parameters?</h3>
<p>It is tempting to think of parameters as a database containing facts.</p>
<p>That is not quite accurate.</p>
<p>The parameters are numerical values distributed throughout the neural network. Collectively, they encode patterns and relationships learned during training.</p>
<p>These patterns can include relationships involving:</p>
<ul>
<li><p>language</p>
</li>
<li><p>syntax</p>
</li>
<li><p>semantics</p>
</li>
<li><p>concepts</p>
</li>
<li><p>code</p>
</li>
<li><p>factual associations</p>
</li>
<li><p>patterns of reasoning</p>
</li>
</ul>
<p>The model does not generally retrieve a sentence from a database every time it generates an answer. Instead, its learned parameters influence the probability distribution over possible next tokens.</p>
<h3>More parameters ≠ automatically better</h3>
<p>Model size is often discussed using parameter count, but parameter count alone does not determine capability.</p>
<p>Performance also depends on factors such as:</p>
<ul>
<li><p>architecture</p>
</li>
<li><p>training data</p>
</li>
<li><p>training methodology</p>
</li>
<li><p>optimisation</p>
</li>
<li><p>inference techniques</p>
</li>
<li><p>model specialisation</p>
</li>
<li><p>context handling</p>
</li>
</ul>
<p>Consequently, a smaller model can outperform a larger model on particular tasks.</p>
<h2>Embeddings: Representing Meaning Numerically</h2>
<p>Embeddings provide another important piece of the LLM ecosystem.</p>
<p>An embedding is a numerical representation of some piece of information—such as a token, word, sentence, document, or other object—in a high-dimensional vector space (embedding space).</p>
<p><a href="https://developers.google.com/machine-learning/glossary#encoder">Encoding</a> refers to the process of choosing an initial numerical representation of data to train the model on.</p>
<p>An embedding represents each item in <em>n</em>-dimensional space with <em>n</em> floating-point numbers (typically in the range –1 to 1 or 0 to 1).</p>
<p>For example, a simplified embedding might look like:</p>
<p>"cat" → [0.21, -0.43, 0.17, 0.82, ...]</p>
<p>The embedding is in the form of a numerical array called a vector, which maps the coordinates of the data point in a high-dimensional vector space.</p>
<p>The following example is from <a href="https://developers.google.com/machine-learning/crash-course/embeddings/embedding-space">Google Machine Learning Crash Course</a>, because I lack the creativity to invent a more suitable case:</p>
<p>A one-dimensional representation of food, using "sandwich-y" to determine the positioning of a food data point.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6aabca10651797b386d56517/377c7b24-fcad-41e1-a3cd-e23696e88a7f.png" alt="" style="display:block;margin:0 auto" />

<p>A two-dimensional representation of food, plotted by both "sandwichness" and "dessertness".</p>
<img src="https://cdn.hashnode.com/uploads/covers/6aabca10651797b386d56517/edc811d0-836b-4d5f-b656-fc36a33f41c1.png" alt="" style="display:block;margin:0 auto" />

<p>An AI model typically uses a much higher-dimensional space to plot out its data.</p>
<p>The important idea is not each numerical vector itself. The important part is the relationship between each of these vectors.</p>
<h3>Semantic Similarity</h3>
<p>Items with related meanings can be represented by vectors that are closer together in the embedding space.</p>
<p>Eg. A shawarma is more similar to a hot dog, and may be grouped together. Or a borscht and a salad can be grouped together due to similar characteristics, as determined by their similar vector positions.</p>
<p>This allows systems to perform operations based on semantic similarity rather than simply matching exact words.</p>
<p>For example, a search system could retrieve a document about "automobiles" when a user searches for "cars," even though the exact words may differ.</p>
<h2>How These Concepts Fit Together</h2>
<p>These four concepts describe different parts of the LLM pipeline.</p>
<table>
<thead>
<tr>
<th>Concept</th>
<th>What it represents</th>
<th>Why it matters</th>
</tr>
</thead>
<tbody><tr>
<td>Tokens</td>
<td>Discrete units of text data</td>
<td>Determine how text is processed</td>
</tr>
<tr>
<td>Context window</td>
<td>Amount of tokenised information available at once</td>
<td>Determines how much information can be considered</td>
</tr>
<tr>
<td>Parameters</td>
<td>Learned numerical values inside the model</td>
<td>Encode patterns learned during training</td>
</tr>
<tr>
<td>Embeddings</td>
<td>Numerical vector representations</td>
<td>Enable semantic comparison and retrieval</td>
</tr>
</tbody></table>
<p>It is important to consider each component when designing or debugging LLM applications.</p>
<p>For example:</p>
<ul>
<li><p>If a document is too large to process, <strong>context limitations</strong> may be relevant.</p>
</li>
<li><p>If an application exceeds its token budget, <strong>tokenisation</strong> matters.</p>
</li>
<li><p>If a model lacks useful learned patterns, <strong>training and parameters</strong> become relevant.</p>
</li>
<li><p>If a system needs to find semantically relevant documents, <strong>embeddings and vector search</strong> become important.</p>
</li>
</ul>
<p>Building a document-question-answering system may require decisions about:</p>
<ul>
<li><p>how documents should be chunked</p>
</li>
<li><p>how many tokens can fit into the context</p>
</li>
<li><p>which embedding model should be used</p>
</li>
<li><p>how vectors should be stored and searched</p>
</li>
<li><p>how retrieved information should be passed to the LLM</p>
</li>
<li><p>how much context should be included in each request</p>
</li>
</ul>
<h3>A Simple Mental Model</h3>
<p>One way to remember the differences is to think of an LLM as a system processing information through several stages.</p>
<p><strong>Tokens</strong> are the units the model processes.</p>
<p><strong>The context window</strong> determines how much tokenised information can be considered at once.</p>
<p><strong>Parameters</strong> contain the learned numerical patterns that shape the model's behaviour.</p>
<p><strong>Embeddings</strong> represent information as vectors that can be compared based on learned relationships.</p>
<h2>Resources</h2>
<ul>
<li><p><a href="https://developers.google.com/machine-learning/crash-course/llm">Google Machine Learning Crash Course: LLM</a></p>
</li>
<li><p><a href="https://developers.google.com/machine-learning/crash-course/embeddings">Google ML Crash Course: Embedding</a></p>
</li>
<li><p><a href="https://help.openai.com/en/articles/4936856-understanding-and-counting-tokens">OpenAI: Understanding and Counting Tokens</a></p>
</li>
<li><p><a href="https://help.openai.com/en/collections/6864438-embeddings">OpenAI: Embeddings Documentation</a></p>
</li>
<li><p><a href="https://arxiv.org/abs/1706.03762">Attention Is All You</a> (The Original Transformer Paper)</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Learning AI in Public: From CS Fundamentals to LLMs]]></title><description><![CDATA[I'm a Computer Science graduate who spent the first few years of my career working in software development and technical project execution. Along the way, I've realised that I want to go deeper into A]]></description><link>https://tokenofmyattention.hashnode.dev/learning-ai-in-public-from-cs-fundamentals-to-llms</link><guid isPermaLink="true">https://tokenofmyattention.hashnode.dev/learning-ai-in-public-from-cs-fundamentals-to-llms</guid><dc:creator><![CDATA[Alyssa Ng]]></dc:creator><pubDate>Thu, 17 Sep 2026 11:51:03 GMT</pubDate><content:encoded><![CDATA[<p>I'm a Computer Science graduate who spent the first few years of my career working in software development and technical project execution. Along the way, I've realised that I want to go deeper into AI — not just learn how to use AI tools, but actually understand what's happening underneath them.</p>
<p>So I'm starting from the ground up, I want to understand questions like:</p>
<ul>
<li><p>How does a neural network actually learn?</p>
</li>
<li><p>What exactly is an embedding?</p>
</li>
<li><p>Why did Transformers change AI?</p>
</li>
<li><p>How does attention work?</p>
</li>
<li><p>What actually happens when I send a prompt to an LLM?</p>
</li>
<li><p>How are LLMs trained?</p>
</li>
<li><p>What's the difference between prompting, RAG and fine-tuning?</p>
</li>
<li><p>Why do LLMs hallucinate?</p>
</li>
<li><p>How do you evaluate whether an AI system is actually good?</p>
</li>
</ul>
<p>And I plan to use this blog to document my learning experience.</p>
<h3><strong>Why write about it?</strong></h3>
<p>I've always believed that the best test of understanding should follow the Feynman Technique: to explain a concept simply in your own words, as if teaching it to a beginner or a child.  </p>
<p>I want this writing process to force me to go beyond "I think I kind of get it" and to avoid muddling my way through half-understandings; I want to progress towards being able to articulate and explain the details of how AI has enabled computers and machines to mimic human thinking, to learn from data, and to perform complex tasks like problem-solving and decision-making.</p>
<p>I want this blog to be a public notebook of things I'm learning, building and trying to understand.</p>
<p>Some posts will probably be beginner-friendly explanations. Others will get more technical as I go deeper into the underlying concepts.</p>
<p>I'm also hoping that writing publicly will make me more disciplined about actually building things rather than endlessly consuming courses and tutorials.</p>
<h3>What I'll be learning</h3>
<p>I'm currently interested in the intersection of:</p>
<p><strong>Artificial Intelligence · Machine Learning · LLMs · Software Engineering · AI Products</strong></p>
<p>Currently, I want to start working my way through topics such as neural networks, embeddings, Transformers, LLM architectures, training, fine-tuning, RAG, evaluation and AI application engineering.</p>
<p>I will not be able to write from the perspective of an expert, but I hope that I can achieve meaningful learning here, and to encourage others who also wish to start their learning journey.</p>
<h3>What to expect</h3>
<p>I'll be turning my notes and experiments into short technical articles — partly as a way to reinforce my own understanding, and partly in the hope that they might help someone else who is learning the same things.</p>
<p>If I get something wrong, I'll fix it.</p>
<p>If I learn something interesting, I'll write about it.</p>
<p>And hopefully, over time, this blog becomes a record of how my understanding of AI develops from the fundamentals to actually building things with it.</p>
<p><strong>Let's see where this goes.</strong></p>
]]></content:encoded></item></channel></rss>