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
toolsisupported_parameters. Kontrollera medGET /models, se Modeller. För det sista steget, leta efterstructured_outputsellerresponse_format. - Routning: lägg till
provider: { "require_parameters": true }(i Python viaextra_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-minihanterar 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) ochmax_tokensper 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_reachedtill 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.