Vi använder cookies. Cookies och webbläsarlagring håller dig inloggad och kommer ihåg dina preferenser. Med ditt tillstånd mäter vi också hur webbplatsen används. Du kan när som helst. Läs vår cookiepolicy.

Guide: agenter med verktygsanrop

Kom igång

Guide: agenter med verktygsanrop

Bygg en agentloop med parallella verktygsanrop, stegbegränsning, strukturerad slututdata och kostnadskontroll, med kod för Python och Node.

En agent är en loop: modellen läser konversationen, bestämmer sig för att anropa ett eller flera av dina verktyg, du kör dem och skickar tillbaka resultaten, och modellen fortsätter tills den kan svara. api14 stöder detta med OpenAI:s tools-format på alla modeller med verktygsstöd, så samma kod fungerar med OpenAI, Anthropic, Google och andra leverantörer genom att byta modell-id.

Den här guiden bygger en liten agent med stegbegränsning, parallell körning av verktyg, ett strukturerat slutsvar och kostnadskontroll. Koden använder det officiella paketet openai med base URL https://api14.com/api/v1.

Definiera verktyg

Varje verktyg består av ett namn, en beskrivning som modellen läser och ett JSON Schema för dess argument. Håll beskrivningarna specifika, de är modellens enda dokumentation.

import json, os
from openai import OpenAI

client = OpenAI(base_url="https://api14.com/api/v1", api_key=os.environ["API14_API_KEY"])

def search_orders(customer_email: str) -> list:
    return [{"id": "A-1001", "status": "shipped"}]  # din databasfråga

def get_shipment(order_id: str) -> dict:
    return {"order_id": order_id, "carrier": "UPS", "eta": "2026-10-09"}  # ditt API-anrop

TOOLS = {"search_orders": search_orders, "get_shipment": get_shipment}

tools = [
    {"type": "function", "function": {
        "name": "search_orders",
        "description": "List a customer's orders with their status.",
        "parameters": {"type": "object", "properties": {"customer_email": {"type": "string"}},
                       "required": ["customer_email"]},
    }},
    {"type": "function", "function": {
        "name": "get_shipment",
        "description": "Carrier and estimated delivery date for one order.",
        "parameters": {"type": "object", "properties": {"order_id": {"type": "string"}},
                       "required": ["order_id"]},
    }},
]

Loopen med stegbegränsning

Varje varv är ett separat debiterat anrop, så begränsa alltid antalet steg. Returnera verktygsfel till modellen som innehåll i stället för att krascha. Modeller brukar reda ut det genom att rätta argumenten.

MAX_STEPS = 8

def run_tool(call):
    try:
        args = json.loads(call.function.arguments)
        result = TOOLS[call.function.name](**args)
    except Exception as e:  # ogiltig JSON, okänt verktyg eller så misslyckades din funktion
        result = {"error": str(e)}
    return {"role": "tool", "tool_call_id": call.id, "content": json.dumps(result)}

def agent(task, model="openai/gpt-5-mini"):
    messages = [
        {"role": "system", "content": "You are a support agent. Use tools to look things up. Be brief."},
        {"role": "user", "content": task},
    ]
    spent = 0.0
    for step in range(MAX_STEPS):
        r = client.chat.completions.create(model=model, messages=messages, tools=tools, max_tokens=1000)
        spent += r.usage.cost
        msg = r.choices[0].message
        if not msg.tool_calls:
            return msg.content, spent
        messages.append(msg)
        messages.extend(run_tool(call) for call in msg.tool_calls)
    raise RuntimeError(f"No answer after {MAX_STEPS} steps (spent ${spent:.4f})")

print(agent("Where is my order? My email is ada@example.com"))

Skicka tools med varje anrop i loopen. Många leverantörer avvisar ett tool-meddelande när anropet saknar verktygsdefinitioner.

Parallella verktygsanrop

Med parallel_tool_calls (på som standard där det stöds) kan en modell begära flera anrop i en tur, till exempel get_shipment för tre beställningar. Kör dem samtidigt och lägg till ett tool-meddelande per anrop, i valfri ordning. tool_call_id kopplar varje resultat till sitt anrop. I Node:

import OpenAI from "openai";

const client = new OpenAI({ baseURL: "https://api14.com/api/v1", apiKey: process.env.API14_API_KEY });
const MAX_STEPS = 8;

async function agent(messages, tools, impl, model = "openai/gpt-5-mini") {
  for (let step = 0; step < MAX_STEPS; step++) {
    const res = await client.chat.completions.create({ model, messages, tools, max_tokens: 1000 });
    const msg = res.choices[0].message;
    if (!msg.tool_calls?.length) return msg.content;

    messages.push(msg);
    const results = await Promise.all(msg.tool_calls.map(async (call) => {
      let content;
      try {
        content = JSON.stringify(await impl[call.function.name](JSON.parse(call.function.arguments)));
      } catch (err) {
        content = JSON.stringify({ error: String(err) });
      }
      return { role: "tool", tool_call_id: call.id, content };
    }));
    messages.push(...results);
  }
  throw new Error(`No answer after ${MAX_STEPS} steps`);
}

Om dina verktyg har sidoeffekter som måste ske i ordning (skapa, sedan uppdatera), ange parallel_tool_calls: false så att modellen ber om ett anrop per tur.

Strukturerad slututdata

När agentens svar matas in i annan kod, be om JSON som matchar ett schema. Ett enkelt, portabelt mönster är ett extra anrop efter att loopen har samlat in fakta (messages här är konversationen från loopen. Returnera den från agent() tillsammans med svaret):

schema = {
    "type": "object",
    "properties": {
        "order_id": {"type": "string"},
        "status": {"type": "string", "enum": ["processing", "shipped", "delivered", "unknown"]},
        "eta": {"type": ["string", "null"]},
        "reply": {"type": "string"},
    },
    "required": ["order_id", "status", "eta", "reply"],
    "additionalProperties": False,
}

final = client.chat.completions.create(
    model="openai/gpt-5-mini",
    messages=messages + [{"role": "user", "content": "Summarize the result for our ticket system."}],
    tools=tools,
    tool_choice="none",
    response_format={"type": "json_schema", "json_schema": {"name": "ticket", "strict": True, "schema": schema}},
)
ticket = json.loads(final.choices[0].message.content)

tool_choice: "none" behåller tools i anropet (nödvändigt eftersom historiken innehåller verktygsmeddelanden) samtidigt som fler anrop stoppas. Validera alltid den tolkade JSON:en. Se Strukturerade utdata.

Välja modell

  • Förmåga: modellen måste lista tools i supported_parameters. Kontrollera med GET /models, se Modeller. För det sista steget, leta efter structured_outputs eller response_format.
  • Routning: lägg till provider: { "require_parameters": true } (i Python via extra_body) så att anrop bara går till leverantörer som stöder alla parametrar du skickar. Se Leverantörsroutning.
  • Storlek: små modeller som openai/gpt-5-mini hanterar några välbeskrivna verktyg pålitligt och billigt. Gå över till en större modell när agenten har många verktyg, långa flerstegsplaner eller fortsätter välja fel verktyg.
  • Testa med dina verktyg: kör samma 20–50 verkliga uppgifter mot två eller tre kandidatmodeller och jämför andel lyckade, steg per uppgift och total usage.cost.
curl -s "https://api14.com/api/v1/models?category=text" \
  | jq -r '.data[] | select(.supported_parameters | index("tools")) | "\(.id)  \(.pricing.prompt)"'

Kontrollera kostnaden

En agent kan göra många anrop för en enda uppgift, och hela konversationen skickas om i varje steg. Begränsa utgifterna på flera nivåer:

  • Stegbegränsning (MAX_STEPS) och max_tokens per anrop, som ovan.
  • Budget per uppgift: summera usage.cost över stegen och stoppa när summan passerar din tröskel.
  • Korta verktygsresultat: returnera bara de fält som modellen behöver. Stora verktygsutdata betalas som indata-tokens i varje efterföljande steg.
  • Daglig USD-gräns per nyckel: skapa en dedikerad nyckel för agenten under API-nycklar och ange en daglig gräns. När den nås returnerar anropen 429 daily_limit_reached till nästa UTC-dag. Hantera den koden genom att stoppa agenten, inte genom att försöka igen.
  • Tillåtelselista för modeller: begränsa nyckeln till de modeller du har testat. Allt annat returnerar 403 model_not_allowed.
  • Prompt-cachning: håll systemprompten och verktygsdefinitionerna identiska och först i varje anrop så att rabatter för cachade prefix gäller. Se Prompt-cachning.

Se Verktygsanrop, Hastighetsgränser och Fel.