Welcome to Chapter 3! If you’ve ever wanted to build your own intelligent agent and share it with others, you’re in the right place. In this chapter, we’re taking the crucial step from setting up our environment to creating our very first AI agent using AIPack.
This chapter is your hands-on introduction to the core components of AIPack: the .aip file format and the structure of basic multi-stage markdown agents. We’ll start with the simplest possible agent and gradually add more functionality, ensuring you understand each piece before moving on. By the end, you’ll not only have a working agent but also a solid mental model for how AIPack organizes and executes AI workflows.
Before we dive in, ensure you’ve successfully completed the installation and basic configuration steps from Chapter 2. Specifically, make sure aipack is installed and you have at least one AI model configured (like Ollama’s Llama 3 or an OpenAI API key).
What are AI Packs and .aip Files?
At the heart of AIPack lies the .aip file. Think of an .aip file as a blueprint or a recipe for your AI agents and skills. It’s a single, self-contained file that defines everything needed to run a specific AI workflow.
The Purpose of .aip Files
Why do we need a special file format? Imagine you’ve built an amazing AI agent that can summarize GitHub issues. How do you share it with a teammate? How do you ensure it runs consistently across different machines? The .aip file solves this by:
- Packaging: Bundling all agent definitions, model configurations, and logic into one portable unit.
- Sharing: Allowing easy distribution of agents – you can email an
.aipfile, upload it to a repository, or even publish it. - Versioning: Providing a clear, declarative definition that can be version-controlled, just like code.
- Reproducibility: Ensuring that an agent behaves the same way when run by anyone, anywhere, given the same inputs and models.
Inside an .aip File: A YAML Manifest
An .aip file is essentially a YAML-formatted document. YAML (YAML Ain’t Markup Language) is human-readable and commonly used for configuration files. It defines the metadata of your pack, the agents it contains, and any reusable skills.
For this chapter, we’ll focus on the agents section, which holds the definitions of our AI agents.
Anatomy of a Basic Markdown Agent
AIPack agents are powerful because they combine the flexibility of large language models (LLMs) with structured control flow. The most common type of agent you’ll build is a multi-stage markdown agent.
What Makes it “Multi-Stage”?
Instead of having the LLM try to solve a complex problem in one go, AIPack breaks down tasks into distinct, sequential stages. This approach offers several benefits:
- Clarity: Each stage has a clear objective (e.g., “plan,” “execute,” “review”).
- Control: You can inject specific instructions, tools, or human feedback at each stage.
- Debugging: It’s easier to pinpoint where an agent went wrong if you can see its output at each step.
- Efficiency: By guiding the LLM through a process, you can often achieve better results with fewer tokens.
The Role of Markdown and Lua
Within each stage, you define the agent’s behavior using a combination of:
- Markdown: This is where you provide instructions, context, and prompts directly to the LLM. It’s like writing a detailed instruction manual for your AI.
- Lua Logic: For more advanced control, conditional execution, tool calls, or data manipulation, AIPack allows you to embed Lua scripts. Lua is a lightweight, fast, and embeddable scripting language, perfect for orchestrating agent workflows.
Let’s visualize this basic flow:
In this simple diagram, the agent progresses through predefined stages, each potentially interacting with the LLM and processing information before moving to the next.
Step-by-Step Implementation: Building a Simple “Hello, AIPack!” Agent
Let’s get our hands dirty and build a minimal AI Pack. Our first agent will simply greet us and acknowledge the input we give it.
1. Project Setup
First, create a new directory for our first AI Pack. Open your terminal or command prompt and run:
mkdir my-first-aipack
cd my-first-aipack
2. Creating Your .aip File
Inside my-first-aipack, create a new file named hello_world.aip. You can use VS Code or any text editor.
Now, let’s add the basic structure for our AI Pack. We’ll start with the pack’s metadata and then define our first agent.
# hello_world.aip
name: "HelloWorldPack"
version: "0.1.0"
description: "A simple AIPack to say hello."
agents:
hello_agent:
description: "A friendly agent that greets you."
model: "ollama/llama3" # Or "openai/gpt-4o", "anthropic/claude-3-opus", etc.
stages:
- name: "greet"
prompt: |
Hello! You are a friendly AI assistant.
Your task is to greet the user and incorporate their input into your greeting.
User input: {{ .Prompt }}
Your greeting:
Explanation of the Code:
name,version,description(Pack Level): These fields define the overall AI Pack.nameis a unique identifier,versionhelps with tracking changes, anddescriptionprovides a summary.agents: This is the top-level key that holds all agent definitions within this.aipfile.hello_agent(Agent Level): This is the unique identifier for our agent. You can define multiple agents under theagentskey.description(Agent Level): A brief explanation of whathello_agentdoes.model: This specifies which AI model the agent should use. I’ve used"ollama/llama3"as an example. CRITICAL: Replace this with the identifier of a model you have configured locally (e.g., if you set up Ollama withllama3, useollama/llama3) or a cloud model you have access to (e.g.,openai/gpt-4o). If you’re unsure, refer back to Chapter 2’s model configuration.stages: This is a list of sequential steps the agent will take. Ourhello_agentcurrently has only one stage.- name: "greet"(Stage Level): Defines a single stage named “greet”.prompt: |: This is where the magic happens! The content following|(a YAML multiline string indicator) is the actual instruction set and context given to the LLM for this stage.Hello! You are a friendly AI assistant.sets the role and tone.Your task is to greet the user and incorporate their input into your greeting.clearly defines the objective.User input: {{ .Prompt }}: This is an important piece!{{ .Prompt }}is a Go template variable that AIPack automatically populates with the user’s input when you run the agent. This allows our agent to be dynamic.Your greeting:provides a clear instruction for the LLM’s output format.
3. Running Your Agent
Now that our hello_world.aip file is ready, let’s run our agent! Open your terminal in the my-first-aipack directory and execute:
aipack run hello_world.aip hello_agent --prompt "AIPack journey!"
Explanation of the Command:
aipack run: The command to execute an agent defined in an.aipfile.hello_world.aip: The path to our AI Pack file.hello_agent: The specific agent withinhello_world.aipthat we want to run. Remember, an.aipfile can contain multiple agents.--prompt "AIPack journey!": This is the user input that will be passed to the agent. It will replace{{ .Prompt }}in our agent’s prompt.
You should see output similar to this (the exact wording might vary slightly depending on your chosen LLM):
Hello! I'm a friendly AI assistant. It's wonderful to embark on this AIPack journey with you!
Congratulations! You’ve just built and run your first AI agent. Take a moment to appreciate this milestone.
4. Adding Basic Lua Logic
While markdown prompts are great for instructions, sometimes you need more dynamic control. This is where Lua comes in. Let’s add a small Lua block to our agent to demonstrate its power. We’ll make the agent respond differently if the prompt contains the word “secret”.
Modify your hello_world.aip file:
# hello_world.aip
name: "HelloWorldPack"
version: "0.1.0"
description: "A simple AIPack to say hello."
agents:
hello_agent:
description: "A friendly agent that greets you."
model: "ollama/llama3" # Or your chosen model
stages:
- name: "greet"
lua: |
local prompt_text = context.vars.Prompt
if string.find(prompt_text, "secret", 1, true) then
context.vars.CustomGreeting = "Shhh, you've found the secret! Hello, mysterious user!"
else
context.vars.CustomGreeting = "Hello, valued user!"
end
prompt: |
You are a friendly AI assistant.
Your task is to greet the user using the provided custom greeting and incorporate their original input.
Custom Greeting: {{ .CustomGreeting }}
User input: {{ .Prompt }}
Your response:
Explanation of the Changes:
lua: |: This block introduces Lua code that will be executed before thepromptis sent to the LLM.local prompt_text = context.vars.Prompt: In AIPack,context.varsis a table (like a dictionary in Python) that holds variables accessible throughout the agent’s execution. We’re retrieving the user’s original prompt and storing it in a local Lua variable.if string.find(prompt_text, "secret", 1, true) then ... end: This is a standard Lua conditional statement.string.findsearches for the substring “secret” withinprompt_text. The1, truearguments ensure a case-sensitive search from the beginning of the string.context.vars.CustomGreeting = "...": We’re creating a new variable,CustomGreeting, within thecontext.varstable. Its value depends on whether “secret” was found. This variable will now be available to our markdownprompt.Custom Greeting: {{ .CustomGreeting }}in prompt: We’ve updated the markdown prompt to include{{ .CustomGreeting }}, which will be replaced by the value we set in Lua.
Now, run the agent with two different prompts:
Without “secret”:
aipack run hello_world.aip hello_agent --prompt "Good morning!"Expected output might be:
Hello, valued user! Good morning! It's great to connect with you.With “secret”:
aipack run hello_world.aip hello_agent --prompt "What's the secret to a great AIPack?"Expected output might be:
Shhh, you've found the secret! Hello, mysterious user! The secret to a great AIPack lies in clear instructions and well-defined stages.
You’ve successfully added conditional logic using Lua! This tiny step opens up a world of possibilities for dynamic agent behavior.
Mini-Challenge: Enhance Your Greeting
Now it’s your turn to extend our hello_agent.
Challenge: Modify the hello_agent in hello_world.aip so that it also includes the current year in its greeting, regardless of the user’s prompt. For instance, if the year is 2026, the agent should say something like “Greetings in 2026!”
Hint: You can either try to instruct the LLM directly in the markdown prompt to include the current year (which might work, but is less reliable for precise dates), or you can leverage Lua’s os.date function to get the current year and inject it into context.vars, similar to how we used CustomGreeting. Using Lua will give you more reliable control.
What to observe/learn: How to incorporate dynamic, real-world information (like the current date/time) into your agent’s prompts, either by relying on the LLM’s general knowledge or by explicitly injecting it via Lua.
💡 **Solution Hint (for Lua approach)**
Lua's `os.date` function can format dates. `os.date("%Y")` will give you the current year as a string. You can then assign this to a `context.vars` variable.Common Pitfalls & Troubleshooting
Even with simple agents, you might encounter some bumps. Here are a few common issues and how to resolve them:
- YAML Indentation Errors: YAML is very strict about indentation. If you see errors like
mapping values are not allowed hereorbad indentation of a mapping entry, double-check that your spaces are consistent (usually 2 spaces per level, never tabs). - Incorrect Agent Name: When running
aipack run hello_world.aip hello_agent, ensurehello_agentexactly matches the name defined in your.aipfile under theagentskey. Typo here is a common mistake. - Model Not Found/Configured: If you get an error saying
model 'ollama/llama3' not foundor similar, it means AIPack can’t connect to or find the specified model.- For Ollama: Ensure Ollama is running and that you have pulled the model (e.g.,
ollama pull llama3). - For Cloud Models (OpenAI, Anthropic): Verify your API key is correctly set in your environment variables or
aipack.yamlconfiguration, and that the model name is correct (e.g.,openai/gpt-4o). Refer to Chapter 2 for setup details.
- For Ollama: Ensure Ollama is running and that you have pulled the model (e.g.,
- Lua Syntax Errors: Lua is generally forgiving, but syntax mistakes will halt the agent. Look for error messages that pinpoint the line number in your
luablock. Common mistakes include missingendforifstatements or typos in function names (string.findvs.string.Find).
Summary
You’ve just completed a significant step in your AIPack journey! Here are the key takeaways from this chapter:
.aipFiles: These YAML-based files are the standard for defining, packaging, and sharing AI agents and skills in AIPack.- Multi-Stage Agents: AIPack encourages breaking down complex tasks into manageable stages, making agents more robust and easier to debug.
- Markdown Prompts: You can directly instruct LLMs within agent stages using markdown, incorporating dynamic inputs like
{{ .Prompt }}. - Lua Logic: For advanced control flow, conditional logic, and data manipulation, you can embed Lua scripts within your agent stages, using
context.varsto pass data between Lua and the markdown prompt. - Running Agents: The
aipack run <pack_file> <agent_name> --prompt "..."command is your gateway to executing your AI agents.
This foundational understanding of .aip files, markdown agents, and basic Lua is crucial for everything we’ll build moving forward. In the next chapter, we’ll explore more advanced agent configurations, including how to manage context and introduce tools to your agents, allowing them to interact with the outside world!
References
- AIPack GitHub Repository: https://github.com/aipack-ai/aipack
- Ollama Official Website: https://ollama.com/
- Lua 5.4 Reference Manual: https://www.lua.org/manual/5.4/
This page is AI-assisted and reviewed. It references official documentation and recognized resources where relevant.