Function Calling og Tool Use med LLM'er i Python — fra teori til produktion

Lær hvordan function calling og tool use fungerer med LLM'er i Python. Komplet guide med arbejdende kodeeksempler for OpenAI og Claude, parallelle tool calls, Pydantic-validering og Model Context Protocol (MCP).

Hvis du har fulgt med i vores serie om AI-udvikling i Python — fra AI-agenter med LangGraph til RAG-pipelines med ChromaDB — har du allerede set, at de mest kraftfulde AI-systemer ikke bare genererer tekst. De handler. De slår op i databaser, kalder API'er, udfører beregninger og orkestrerer komplekse arbejdsgange.

Men hvordan fungerer det egentlig under motorhjelmen?

Svaret er function calling (også kaldet tool use) — den mekanisme, der forvandler en sprogmodel fra en sofistikeret tekstgenerator til en agent, der kan interagere med den virkelige verden. Og ærligt talt, når man først forstår konceptet, ændrer det fundamentalt måden man tænker AI-arkitektur på.

I denne guide tager vi hele turen: fra de grundlæggende koncepter over arbejdende Python-kode med både OpenAI og Claude, til parallelle tool calls, fejlhåndtering i produktion og det nye Model Context Protocol (MCP), der er ved at standardisere hele feltet i 2026.

Hvad er function calling, og hvorfor er det vigtigt?

Lad os starte med det mest afgørende at forstå: LLM'en udfører aldrig selv funktionen. Det er en misforståelse, som selv erfarne udviklere har — jeg har selv set det i code reviews mere end én gang. Når en model som GPT-4o eller Claude "kalder en funktion", sker der i virkeligheden dette:

  1. Du beskriver dine tilgængelige funktioner (tools) i et JSON Schema-format
  2. Modellen analyserer brugerens besked og beslutter, om en funktion er relevant
  3. Modellen returnerer et struktureret JSON-objekt med funktionens navn og argumenter
  4. Din kode eksekverer funktionen med de angivne argumenter
  5. Resultatet sendes tilbage til modellen
  6. Modellen bruger resultatet til at formulere et endeligt svar

Tænk på det som en samtale mellem en rådgiver og en assistent. Rådgiveren (LLM'en) ved, hvilke opgaver der skal udføres, og kan specificere præcis, hvad der skal gøres — men det er assistenten (din kode), der rent faktisk udfører arbejdet.

Det er denne adskillelse, der gør arkitekturen sikker. Modellen har aldrig direkte adgang til dine systemer. Den kan kun anmode om, at du udfører noget på dens vegne. Det er et vigtigt designvalg.

Forudsætninger og opsætning

For at følge med i denne guide skal du bruge:

  • Python 3.11 eller nyere
  • En API-nøgle fra OpenAI og/eller Anthropic (Claude)
  • Grundlæggende kendskab til Python og JSON

Installér de nødvendige pakker

python -m venv tool-use-env
source tool-use-env/bin/activate  # macOS/Linux

pip install openai anthropic pydantic

Konfigurér miljøvariabler

export OPENAI_API_KEY="din-openai-noegle"
export ANTHROPIC_API_KEY="din-anthropic-noegle"

Function calling med OpenAI i Python

Lad os starte med OpenAI, da de var de første til at introducere function calling helt tilbage i juni 2023. Formatet har udviklet sig en del siden da, og i 2026 bruger vi tools-parameteren med strict mode.

Trin 1: Definér dine tools

Hver tool beskrives som et JSON Schema-objekt med et navn, en beskrivelse og parametre. Beskrivelsen er afgørende — det er den, modellen bruger til at beslutte, hvornår et tool er relevant. Så brug tid på at skrive gode beskrivelser, det betaler sig virkelig.

tools = [
    {
        "type": "function",
        "function": {
            "name": "hent_vejr",
            "description": "Hent aktuelle vejrdata for en given by",
            "strict": True,
            "parameters": {
                "type": "object",
                "properties": {
                    "by": {
                        "type": "string",
                        "description": "Byens navn, f.eks. København"
                    },
                    "enhed": {
                        "type": "string",
                        "enum": ["celsius", "fahrenheit"],
                        "description": "Temperaturenhed"
                    }
                },
                "required": ["by", "enhed"],
                "additionalProperties": False
            }
        }
    }
]

Læg mærke til "strict": True — det anbefales altid i 2026. Strict mode sikrer, at modellens tool calls altid overholder dit schema præcist ved at bruge constrained decoding under motorhjelmen. Det eliminerer typefejl og manglende felter, og det er ærligt talt en game changer sammenlignet med de tidlige dage, hvor man konstant måtte håndtere malformede JSON-svar.

Trin 2: Send beskeden og håndtér tool calls

from openai import OpenAI
import json

client = OpenAI()

def hent_vejr(by: str, enhed: str) -> dict:
    """Simuleret vejr-API."""
    data = {
        "København": {"temperatur": 14, "tilstand": "Overskyet"},
        "Aarhus": {"temperatur": 12, "tilstand": "Let regn"},
    }
    info = data.get(by, {"temperatur": 0, "tilstand": "Ukendt"})
    return {"by": by, "temperatur": info["temperatur"], "enhed": enhed,
            "tilstand": info["tilstand"]}

TILGAENGELIGE_FUNKTIONER = {
    "hent_vejr": hent_vejr,
}

def kald_med_tools(bruger_besked: str) -> str:
    messages = [{"role": "user", "content": bruger_besked}]

    # Første kald: modellen beslutter om den vil bruge et tool
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=messages,
        tools=tools,
    )

    assistent_besked = response.choices[0].message

    # Tjek om modellen vil kalde et tool
    if assistent_besked.tool_calls:
        messages.append(assistent_besked)

        # Eksekvér hvert tool call
        for tool_call in assistent_besked.tool_calls:
            func_name = tool_call.function.name
            func_args = json.loads(tool_call.function.arguments)

            # Kald den rigtige funktion
            resultat = TILGAENGELIGE_FUNKTIONER[func_name](**func_args)

            # Send resultatet tilbage til modellen
            messages.append({
                "role": "tool",
                "tool_call_id": tool_call.id,
                "content": json.dumps(resultat, ensure_ascii=False)
            })

        # Andet kald: modellen genererer endeligt svar
        final_response = client.chat.completions.create(
            model="gpt-4o",
            messages=messages,
            tools=tools,
        )
        return final_response.choices[0].message.content

    return assistent_besked.content

# Test det
print(kald_med_tools("Hvordan er vejret i København?"))

Det her er kerneflowet for al function calling. Uanset om du bruger OpenAI, Claude eller et helt tredje framework, er mønsteret det samme: beskriv → kald → eksekvér → returner → svar. Når du har forstået dette loop, kan du implementere tool use med stort set enhver LLM-udbyder.

Tool use med Claude og Anthropic SDK

Claudes implementation af tool use følger det samme koncept, men med en lidt anderledes syntaks. Anthropics seneste Python SDK (2026) introducerer desuden en elegant beta_tool-dekorator og tool_runner, der automatiserer hele loopet — og det er faktisk ret elegant.

Metode 1: Manuel tool use

from anthropic import Anthropic
import json

client = Anthropic()

# Definér tools i Anthropic-format
tools = [
    {
        "name": "hent_aktiekurs",
        "description": "Hent den aktuelle aktiekurs for et givet selskab",
        "input_schema": {
            "type": "object",
            "properties": {
                "symbol": {
                    "type": "string",
                    "description": "Aktiesymbolet, f.eks. NOVO-B for Novo Nordisk"
                }
            },
            "required": ["symbol"]
        }
    }
]

def hent_aktiekurs(symbol: str) -> dict:
    """Simuleret aktie-API."""
    kurser = {"NOVO-B": 892.50, "MAERSK-B": 10250.00, "DSV": 1340.75}
    kurs = kurser.get(symbol, 0.0)
    return {"symbol": symbol, "kurs": kurs, "valuta": "DKK"}

# Send besked med tools
response = client.messages.create(
    model="claude-sonnet-4-5-20250514",
    max_tokens=1024,
    tools=tools,
    messages=[{"role": "user",
               "content": "Hvad er Novo Nordisks aktuelle aktiekurs?"}]
)

# Håndtér tool use
if response.stop_reason == "tool_use":
    # Find tool use-blokken
    tool_block = next(b for b in response.content if b.type == "tool_use")

    # Eksekvér funktionen
    resultat = hent_aktiekurs(**tool_block.input)

    # Send resultatet tilbage
    final_response = client.messages.create(
        model="claude-sonnet-4-5-20250514",
        max_tokens=1024,
        tools=tools,
        messages=[
            {"role": "user",
             "content": "Hvad er Novo Nordisks aktuelle aktiekurs?"},
            {"role": "assistant", "content": response.content},
            {"role": "user", "content": [
                {"type": "tool_result",
                 "tool_use_id": tool_block.id,
                 "content": json.dumps(resultat, ensure_ascii=False)}
            ]}
        ]
    )
    print(final_response.content[0].text)

Metode 2: Automatisk tool runner (anbefalet i 2026)

Anthropics nyeste SDK gør det hele væsentligt enklere med beta_tool-dekoratoren. I stedet for at håndtere hele loopet manuelt, lader du SDK'et klare det:

from anthropic import Anthropic, beta_tool
import json

client = Anthropic()

@beta_tool
def hent_valutakurs(fra_valuta: str, til_valuta: str) -> str:
    """Hent vekselkursen mellem to valutaer.
    Args:
        fra_valuta: Kildevalutaen, f.eks. DKK
        til_valuta: Målvalutaen, f.eks. EUR
    Returns:
        En JSON-streng med vekselkursoplysninger.
    """
    kurser = {("DKK", "EUR"): 0.134, ("DKK", "USD"): 0.146,
              ("EUR", "DKK"): 7.46, ("USD", "DKK"): 6.85}
    kurs = kurser.get((fra_valuta, til_valuta), 0.0)
    return json.dumps({"fra": fra_valuta, "til": til_valuta,
                       "kurs": kurs})

# tool_runner håndterer hele loopet automatisk
runner = client.beta.messages.tool_runner(
    model="claude-sonnet-4-5-20250514",
    max_tokens=1024,
    tools=[hent_valutakurs],
    messages=[{"role": "user",
               "content": "Hvad er vekselkursen fra DKK til EUR?"}],
)

for message in runner:
    if hasattr(message, "content"):
        for block in message.content:
            if hasattr(block, "text"):
                print(block.text)

Med tool_runner behøver du ikke manuelt håndtere loopet. SDK'et opdager tool calls, kalder dine funktioner og sender resultaterne tilbage til Claude automatisk. Det reducerer markant mængden af boilerplate-kode — og gør koden meget mere læsbar i processen.

Parallelle tool calls

Okay, nu bliver det interessant. I mange realistiske scenarier har modellen brug for at kalde flere tools i samme tur. Forestil dig en bruger, der spørger: "Hvad er vejret i København og Aarhus, og hvad er Novo Nordisks aktiekurs?" — det er tre uafhængige opslag, der kan (og bør) udføres samtidigt.

OpenAI: parallelle tool calls er standard

OpenAI aktiverer parallelle tool calls som standard. Modellen kan returnere flere tool calls i et enkelt svar, og du kan eksekvere dem parallelt med Pythons ThreadPoolExecutor:

from concurrent.futures import ThreadPoolExecutor

def haandter_parallel_tool_calls(assistent_besked, messages):
    """Eksekvér flere tool calls parallelt."""
    if not assistent_besked.tool_calls:
        return assistent_besked.content

    messages.append(assistent_besked)

    def eksekver_tool(tool_call):
        func_name = tool_call.function.name
        func_args = json.loads(tool_call.function.arguments)
        func = TILGAENGELIGE_FUNKTIONER.get(func_name)
        if func:
            return tool_call.id, json.dumps(func(**func_args),
                                            ensure_ascii=False)
        return tool_call.id, json.dumps({"fejl": "Ukendt funktion"})

    # Eksekvér alle tool calls parallelt
    with ThreadPoolExecutor() as executor:
        futures = [executor.submit(eksekver_tool, tc)
                   for tc in assistent_besked.tool_calls]
        resultater = [f.result() for f in futures]

    # Tilføj alle resultater til messages
    for tool_call_id, resultat in resultater:
        messages.append({
            "role": "tool",
            "tool_call_id": tool_call_id,
            "content": resultat
        })

    return messages

Det her er en af de ting, der virkelig gør en forskel i produktionsmiljøer. Hvis hvert API-kald tager 200ms, og du har fire parallelle tool calls, sparer du fra 800ms (sekventielt) ned til cirka 200ms (parallelt). I brugervendte applikationer er den forskel enorm — dine brugere vil kunne mærke det.

Claude: håndtering af flere tool calls

Claude kan også returnere flere tool_use-blokke i ét svar. Du håndterer dem på nøjagtig samme måde — saml alle resultater og send dem samlet tilbage. Bruger du tool_runner, klarer den også dette automatisk.

Strukturerede outputs med Pydantic

I produktionsapplikationer vil du typisk have typevaliderede, strukturerede svar — ikke bare rå JSON-strenge, du selv skal parse og validere. Her kommer Pydantic ind i billedet, og det er (efter min mening) en af de vigtigste brikker i et solidt tool-use setup.

Claude med Pydantic og output_format

Anthropics SDK understøtter nu Pydantic-modeller direkte via messages.parse():

from pydantic import BaseModel
from anthropic import Anthropic

class ProduktAnmeldelse(BaseModel):
    produkt_navn: str
    vurdering: int
    fordele: list[str]
    ulemper: list[str]
    anbefaling: bool

client = Anthropic()

response = client.messages.parse(
    model="claude-sonnet-4-5-20250514",
    max_tokens=1024,
    messages=[{
        "role": "user",
        "content": "Analysér denne anmeldelse: 'iPhone 16 Pro er fantastisk. "
                   "Kameraet er sindssygt godt, batteriet holder hele dagen, "
                   "og Face ID virker fejlfrit. Prisen er dog ret høj, "
                   "og den er tung.'"
    }],
    output_format=ProduktAnmeldelse,
)

anmeldelse = response.parsed_output
print(f"Produkt: {anmeldelse.produkt_navn}")
print(f"Vurdering: {anmeldelse.vurdering}/10")
print(f"Anbefalet: {'Ja' if anmeldelse.anbefaling else 'Nej'}")

Under motorhjelmen kompilerer Claude dit Pydantic-schema til en grammatik og begrænser token-generering, så outputtet altid matcher dit schema. Det er ikke bare "best effort" — det er garanteret skemaoverholdelse via constrained decoding. Ingen flere frustrerende parsingfejl kl. 2 om natten.

Byg et komplet tool-call loop til produktion

Så lad os samle alt det, vi har gennemgået, til en robust, produktionsklar implementation. Denne version håndterer flere tools, fejl og et fuldt agentic loop:

from openai import OpenAI
import json
from datetime import datetime

client = OpenAI()

# --- Definér dine tools ---

def soeg_database(foresporgsel: str, maks_resultater: int = 5) -> dict:
    """Simuleret databasesøgning."""
    return {"resultater": [
        {"id": 1, "titel": f"Resultat for: {foresporgsel}",
         "relevans": 0.95}
    ], "total": 1}

def send_email(til: str, emne: str, tekst: str) -> dict:
    """Simuleret email-afsendelse."""
    return {"status": "sendt", "til": til,
            "tidspunkt": datetime.now().isoformat()}

def hent_bruger_info(bruger_id: int) -> dict:
    """Simuleret brugeropslag."""
    brugere = {
        1: {"navn": "Anders Hansen", "email": "[email protected]"},
        2: {"navn": "Mette Nielsen", "email": "[email protected]"},
    }
    return brugere.get(bruger_id, {"fejl": "Bruger ikke fundet"})

FUNKTIONER = {
    "soeg_database": soeg_database,
    "send_email": send_email,
    "hent_bruger_info": hent_bruger_info,
}

TOOL_DEFINITIONER = [
    {
        "type": "function",
        "function": {
            "name": "soeg_database",
            "description": "Søg i virksomhedens interne database",
            "strict": True,
            "parameters": {
                "type": "object",
                "properties": {
                    "foresporgsel": {"type": "string",
                                     "description": "Søgeteksten"},
                    "maks_resultater": {"type": "integer",
                                        "description": "Max antal resultater"}
                },
                "required": ["foresporgsel", "maks_resultater"],
                "additionalProperties": False
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "send_email",
            "description": "Send en email til en modtager",
            "strict": True,
            "parameters": {
                "type": "object",
                "properties": {
                    "til": {"type": "string",
                            "description": "Modtagerens emailadresse"},
                    "emne": {"type": "string",
                             "description": "Emailens emne"},
                    "tekst": {"type": "string",
                              "description": "Emailens indhold"}
                },
                "required": ["til", "emne", "tekst"],
                "additionalProperties": False
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "hent_bruger_info",
            "description": "Hent information om en bruger fra databasen",
            "strict": True,
            "parameters": {
                "type": "object",
                "properties": {
                    "bruger_id": {"type": "integer",
                                  "description": "Brugerens unikke ID"}
                },
                "required": ["bruger_id"],
                "additionalProperties": False
            }
        }
    }
]

MAKS_ITERATIONER = 10

def agent_loop(bruger_besked: str) -> str:
    """Kør et komplet agent-loop med tool calling."""
    messages = [
        {"role": "system",
         "content": "Du er en hjælpsom assistent, der kan søge i "
                    "databaser, sende emails og slå brugerinfo op. "
                    "Brug dine tools når det er relevant."},
        {"role": "user", "content": bruger_besked}
    ]

    for iteration in range(MAKS_ITERATIONER):
        response = client.chat.completions.create(
            model="gpt-4o",
            messages=messages,
            tools=TOOL_DEFINITIONER,
        )

        assistent_besked = response.choices[0].message

        # Hvis ingen tool calls, er vi færdige
        if not assistent_besked.tool_calls:
            return assistent_besked.content

        messages.append(assistent_besked)

        # Eksekvér hvert tool call
        for tool_call in assistent_besked.tool_calls:
            func_name = tool_call.function.name
            try:
                func_args = json.loads(tool_call.function.arguments)
                func = FUNKTIONER.get(func_name)
                if func is None:
                    resultat = {"fejl": f"Ukendt funktion: {func_name}"}
                else:
                    resultat = func(**func_args)
            except json.JSONDecodeError:
                resultat = {"fejl": "Ugyldige argumenter"}
            except Exception as e:
                resultat = {"fejl": str(e)}

            messages.append({
                "role": "tool",
                "tool_call_id": tool_call.id,
                "content": json.dumps(resultat, ensure_ascii=False)
            })

    return "Agenten nåede det maksimale antal iterationer."

# Test med en multi-step opgave
svar = agent_loop(
    "Find information om bruger 1, og send dem en email "
    "med emnet 'Velkommen' og en venlig hilsen."
)
print(svar)

Bemærk den vigtige detalje med MAKS_ITERATIONER. Uden en øvre grænse kan et tool-call loop i teorien køre uendeligt — modellen kunne blive ved med at kalde tools frem og tilbage. I produktion er det kritisk at have det sikkerhedsnet. Ti iterationer er en fornuftig standard for de fleste use cases, men juster efter behov.

Model Context Protocol (MCP) — fremtiden for tool-integration

Indtil nu har vi defineret tools direkte i vores API-kald. Det fungerer fint med et par funktioner, men hvad hvis du har 50 tools? Eller 500? Og hvad hvis de skal fungere på tværs af flere LLM-udbydere?

Det er præcis det problem, Model Context Protocol (MCP) løser.

MCP er en åben standard, der blev lanceret af Anthropic i november 2024 og siden er blevet adopteret af OpenAI, Google DeepMind og hundredvis af andre aktører. I december 2025 blev MCP doneret til Agentic AI Foundation under Linux Foundation — et ret tydeligt signal om, at dette er ved at blive branchens fælles standard.

Tænk på MCP som USB-C for AI-applikationer. Ligesom USB-C giver én standardiseret port til at forbinde enheder, giver MCP én standardiseret protokol til at forbinde AI-modeller med eksterne tools og datakilder. Det er en analogi, der holder overraskende godt.

Hvorfor MCP er vigtigt

Før MCP var problemet fragmentering. Tools bygget til OpenAI's function calling virkede ikke med Claude's tool use eller Gemini's function declarations. Udviklere måtte vedligeholde separate integrationer for hver udbyder, og det var (mildt sagt) besværligt. MCP standardiserer dette med én fælles discovery- og eksekveringsprotokol.

I 2026 er der over 500 offentligt tilgængelige MCP-servere, der dækker databaser, fillagring, web scraping, dokumentbehandling og meget mere. Og nye servere tilføjes ugentligt af community'et.

Hvornår skal du bruge hvad?

En god tommelfingerregel:

  • Native function calling — når du har 1-5 tools og arbejder med én LLM-udbyder. Simpelt og effektivt.
  • MCP — når du har mange tools, har brug for portabilitet mellem modeller, eller bygger en platform. Mere opsætning, men det skalerer langt bedre.

Typiske faldgruber og best practices

Efter at have arbejdet med function calling i talrige projekter er her de fejl, jeg ser oftest — og hvordan du undgår dem.

1. Vage tool-beskrivelser

Kvaliteten af dine tool-beskrivelser er den enkeltstående vigtigste faktor for, om modellen vælger det rigtige tool. En beskrivelse som "hent data" er nærmest ubrugelig. Vær specifik:

# Dårligt:
"description": "Hent data"

# Godt:
"description": "Hent den aktuelle aktiekurs i DKK for et dansk børsnoteret selskab baseret på dets ticker-symbol"

2. Manglende input-validering

Selvom strict mode sikrer korrekt JSON-struktur, kan værdierne stadig være forkerte. En bruger-ID på -1 er teknisk set et gyldigt heltal, men det giver næppe mening. Validér altid med Pydantic eller lignende, før du eksekverer:

from pydantic import BaseModel, Field

class EmailInput(BaseModel):
    til: str = Field(pattern=r"^[\w.+-]+@[\w-]+\.[\w.]+$")
    emne: str = Field(min_length=1, max_length=200)
    tekst: str = Field(min_length=1)

3. Ingen øvre grænse på iterationer

Et tool-call loop uden en maks-grænse kan blive en dyr fejl — bogstaveligt talt. Hver iteration koster API-kald og tokens. Sæt altid en fornuftig grænse.

4. Hallucinerede tool calls

Modeller kan nogle gange forsøge at kalde funktioner, der ikke eksisterer, eller sende argumenter, der ikke matcher skemaet. Det sker sjældnere med strict mode, men håndtér altid KeyError og valideringsfejl gracefully. Din kode skal kunne klare det.

5. For mange tools i kontekstvinduet

Tool-definitioner bruger tokens. Hvis du har 30+ tools, kan det æde en betydelig del af din kontekst. Overvej i stedet Anthropics Tool Search (tilgængelig som beta) eller OpenAI's tilsvarende tool_search (kræver GPT-5.4+). Disse lader modellen dynamisk finde relevante tools i stedet for at have dem alle i konteksten.

Sammenligning: OpenAI vs. Claude tool use

Her er et hurtigt overblik over de vigtigste forskelle mellem de to største udbydere i 2026:

FeatureOpenAI (GPT-4o)Claude (Sonnet/Opus)
Tool-formattools med type: "function"tools med input_schema
Strict modestrict: truestrict: true (beta)
Parallelle callsStandard (kan deaktiveres)Understøttet
Auto tool runnerNej (manuelt loop)beta_tool + tool_runner
Programmatic callingNejJa (beta) — op til 85% tokenreduktion
Tool SearchGPT-5.4+Tilgængelig (beta)
MCP-supportJaJa (oprinder)

Begge platforme er stærke valg. OpenAI har et mere modent og veldokumenteret function calling-API, mens Claude tilbyder innovative features som programmatic tool calling (der kan reducere tokenforbruget med op til 85%) og den elegante tool_runner-abstraktion. Hvilket du vælger afhænger i høj grad af dit eksisterende setup og specifikke behov.

Ofte stillede spørgsmål

Hvad er forskellen på function calling og tool use?

"Function calling" refererer typisk til OpenAI's oprindelige implementation, hvor funktionsskemaer sendes direkte i API-kaldet. "Tool use" er det bredere begreb, der dækker funktioner, datahentning, kodefortolkere og mere. I praksis bruges termerne ofte synonymt i 2026, men "tool use" er det foretrukne begreb, da det bedre beskriver det fulde spektrum af muligheder.

Kan en LLM udføre farlige handlinger via function calling?

Nej — LLM'en kan aldrig selv udføre funktioner. Den returnerer kun strukturerede anmodninger, som din kode håndterer. Det er altid dit ansvar at validere inputs, implementere adgangskontrol og sikre, at brugeren godkender potentielt destruktive handlinger, før de eksekveres. MCP-specifikationen anbefaler altid et "human in the loop" for netop denne grund.

Hvor mange tools kan jeg definere i ét API-kald?

Teknisk set er der ingen fast grænse, men tool-definitioner bruger tokens fra kontekstvinduet. I praksis fungerer 5-15 tools fint. Over 30 tools bør du overveje Tool Search (Claude beta / GPT-5.4+) eller MCP, der lader modellen dynamisk opdage relevante tools uden at have dem alle i konteksten.

Hvad er Model Context Protocol (MCP), og skal jeg bruge det?

MCP er en åben standard for at forbinde AI-modeller med eksterne tools og datakilder via en ensartet protokol. Det er opfundet af Anthropic og nu adopteret af OpenAI, Google og andre. Brug MCP, når du har mange tools, har brug for at skifte mellem LLM-udbydere, eller bygger en platform. For simple projekter med 1-5 tools er native function calling stadig det nemmeste valg.

Hvordan håndterer jeg fejl i tool calls i produktion?

Implementér altid: (1) input-validering med Pydantic eller lignende, (2) try/except omkring funktionseksekvering med meningsfulde fejlbeskeder, (3) en maksimal iterationsgrænse for dit agent-loop, og (4) logging af alle tool calls og resultater til debugging. Returnér fejlbeskeder til modellen frem for at kaste exceptions — modellen kan ofte korrigere sig selv og prøve igen med andre argumenter.

Om Forfatteren Editorial Team

Our team of expert writers and editors.