Skip to content

Building an Agent in 50 Lines of Code

A ground-up look at what an agent really is under the hood: an inference client, a set of tools, and a while loop, using Hugging Face's Tiny Agents as a concrete reference.

  • 3 min read
  • Theory and practice
  • Day 2 of 7

Theory

The best way to understand agents is to build one from scratch. Julien Chaumond from Hugging Face did exactly that and distilled it into a key insight:

Once you have an MCP client, an agent is literally just a while loop on top of it.

Strip away the frameworks and you're left with three pieces:

  1. An LLM inference client: something that can send a list of messages and receive a response
  2. A set of tools: functions with a name, description, and JSON schema for their parameters
  3. A while loop: the agentic loop that keeps calling the LLM, executing tool calls, and feeding results back until the task is done

The anatomy of a tool

A tool is just a function described in a way the LLM can understand:

{
  "type": "function",
  "function": {
    "name": "get_weather",
    "description": "Get current temperature for a given location.",
    "parameters": {
      "type": "object",
      "properties": {
        "location": {
          "type": "string",
          "description": "City and country e.g. Bogotá, Colombia"
        }
      }
    }
  }
}

You pass a list of these to the LLM alongside your messages. The LLM decides when to call one and with what arguments. You execute it, capture the result, append it to the message history as a tool role message, and loop.

The while loop

The core of any agent is this pattern:

while true:
  response = llm.chat(messages, tools=available_tools)
  if response has no tool calls:
    break  // task is done or the agent is stuck
  for each tool_call in response:
    result = execute(tool_call)
    messages.append(tool_result(result))

That's it. Everything else (memory management, MCP integration, multi-agent coordination) is built on top of this loop.

Why this matters for engineers

Knowing the raw loop helps you:

  • Debug agent failures: when an agent loops forever or stops too early, you can trace exactly which message caused it
  • Evaluate frameworks: any framework (LangChain, CrewAI, BMAD, etc.) is an abstraction over this loop: you can ask what it adds and whether the complexity is worth it
  • Understand tool design: because the LLM picks tools based on their description, a well-named, well-described tool will be called correctly; a vague one won't
  • Reason about cost and latency: every iteration of the loop is an LLM call; knowing this helps you design agents that exit cleanly rather than running indefinitely

Practice

Run this in a repository you already know, not a toy project. The point is to feel where the practice helps and where it gets in the way on code that has history.

Reimplement the agentic loop from scratch in your language or framework of choice. You don't need MCP support. The goal is to feel how the loop works, not to build a production tool.

What to build:

  1. Define 2–3 simple tools (e.g., get_current_time, add_numbers, reverse_string). Each tool is just a real function plus a JSON schema description.
  2. Write a function that calls an LLM (OpenAI-compatible API, Anthropic, Ollama, etc.) with a list of messages and a list of tool schemas.
  3. Parse the response: if it contains tool calls, execute them and append the results to the message list. If it contains a plain text response, print it and stop.
  4. Wrap steps 2–3 in a while loop that runs until the LLM stops calling tools.
  5. Test it with a prompt that requires using at least one of your tools (e.g., "What is 17 + 38?").

What to observe:

  • How many loop iterations did it take?
  • What did the raw messages array look like at each step?
  • What happened when you gave it a goal that needed no tools?
  • What happened when you gave it a goal it couldn't achieve with your tools?

This exercise is deliberately low-level. The point is not to ship something; it's to internalize the loop so you can reason about any framework built on top of it.

The rest of day 2

  1. 01How Large Language Models Work
  2. 02Prompt Engineering for Engineers
  3. 03From Autocomplete to Agents
  4. 04Building an Agent in 50 Lines of CodeYou are here
  5. 05Memory and State in Agent Workflows
  6. 06AI Failure Modes Every Engineer Must Know
  7. 07Human in the Loop
Where this comes from

This path is the shortest route to the ideas. AI-Native Software Engineering (O'Reilly Media) is where each one is worked out in full, with the patterns, the trade-offs and the failure modes. The pillars cover the foundations one long essay at a time.