Skip to content

Agents Quickstart

This guide walks you through creating an agent that classifies an incoming request and answers using a serverless function you deploy yourself. By the end you’ll have a real agent answering live requests with streamed events.

You’ll need: a Butterbase app (see the main quickstart if you don’t have one), and either the CLI installed (npm i -g @butterbase/cli) or the MCP server connected to your AI assistant.

  1. Deploy a function and expose it as an agent tool

    Save the following as lookup_account.ts:

    export default async function handler(req: Request, ctx: { db: any }) {
    const { email } = await req.json();
    const { rows } = await ctx.db.query(
    'SELECT id, plan, status FROM accounts WHERE email = $1 LIMIT 1',
    [email],
    );
    return Response.json(rows[0] ?? { error: 'not_found' });
    }

    Deploy it with agent_tool enabled:

    Terminal window
    butterbase functions deploy ./lookup_account.ts \
    --agent-tool \
    --agent-tool-description "Look up a customer account by email. Returns id, plan, status." \
    --agent-tool-mode read_only \
    --agent-tool-exposed-to developer_only
  2. Create an agent

    The agent’s graph spec defines two LLM nodes: a triage step that classifies the message, and an answer step that calls the function you just deployed.

    agent-spec.json
    {
    "spec_version": "1",
    "entry": "triage",
    "nodes": {
    "triage": {
    "type": "llm",
    "model": "anthropic/claude-3.5-haiku",
    "system_prompt": "Classify the user's message as 'billing' or 'other'. Respond with just the category.",
    "input_template": "{{ input.message }}",
    "output_key": "category",
    "tools": []
    },
    "answer": {
    "type": "llm",
    "model": "anthropic/claude-3.5-sonnet",
    "system_prompt": "You are a {{ state.category }} agent. Use lookup_account to find the user before answering.",
    "input_template": "{{ input.message }}",
    "output_key": "reply",
    "tools": [
    { "source": "function", "name": "lookup_account" }
    ]
    },
    "done": { "type": "end", "output_template": "{{ state.reply }}" }
    },
    "edges": [
    { "from": "triage", "to": "answer" },
    { "from": "answer", "to": "done" }
    ],
    "tools": {
    "builtin": [],
    "mcp_servers": [],
    "functions": ["lookup_account"]
    },
    "limits": {
    "max_steps": 10,
    "max_tool_calls": 5,
    "max_parallel_tools": 2,
    "timeout_seconds": 120,
    "human_timeout_seconds": 86400
    }
    }
    Terminal window
    butterbase agents create \
    --name billing-triage \
    --display-name "Billing triage" \
    --default-model anthropic/claude-3.5-haiku \
    --spec ./agent-spec.json
  3. Run it

    Terminal window
    butterbase agents run billing-triage \
    --input '{"message": "Why was I charged twice?"}' \
    --stream

    You’ll see events stream by:

    event: run_start
    event: node_start {"node_id": "triage", "step": 1}
    event: llm_token_usage {"input_tokens": 412, "output_tokens": 4}
    event: node_end {"node_id": "triage", "step": 1}
    event: node_start {"node_id": "answer", "step": 2}
    event: tool_call_start {"tool_name": "lookup_account", "args": {...}}
    event: tool_call_end {"tool_name": "lookup_account", "result": {...}}
    event: llm_token_usage {"input_tokens": 891, "output_tokens": 142}
    event: node_end {"node_id": "answer", "step": 2}
    event: run_end {"output": "Hi! I found your account..."}
  4. Inspect runs in the dashboard

    Open Agents → billing-triage → Runs in the dashboard to see the full event timeline, tool inputs/outputs, and cumulative token + cost.