- Hvad er funktionskald?
- Hvordan funktionskald fungerer
- Anvendelsesscenarier
- Opsætning af funktionskald med Phi-4-mini og Ollama
- Arbejdet med Qwen3 funktionskald
- Foundry Local-integration
- Bedste praksis og fejlfinding
- Avancerede eksempler
Funktionskald er en kraftfuld funktionalitet, der gør det muligt for Small Language Models (SLMs) at interagere med eksterne værktøjer, API'er og tjenester. I stedet for kun at være begrænset til deres træningsdata, kan SLM'er nu:
- Forbinde til eksterne API'er (vejrtjenester, databaser, søgemaskiner)
- Udføre specifikke funktioner baseret på brugerforespørgsler
- Hente realtidsinformation fra forskellige kilder
- Udføre beregningsopgaver via specialiserede værktøjer
- Kæde flere operationer sammen for komplekse arbejdsgange
Denne funktionalitet forvandler SLM'er fra statiske tekstgeneratorer til dynamiske AI-agenter, der kan udføre opgaver i den virkelige verden.
Processen med funktionskald følger en systematisk arbejdsgang:
- Eksterne værktøjer: SLM'er kan forbinde til vejrtjenester, databaser, webtjenester og andre eksterne systemer
- Funktionsdefinitioner: Hvert værktøj defineres med specifikke parametre, input/output-formater og beskrivelser
- API-kompatibilitet: Værktøjer integreres via standardiserede grænseflader (REST API'er, SDK'er osv.)
Funktioner defineres med tre nøglekomponenter:
{
"name": "function_name",
"description": "Clear description of what the function does",
"parameters": {
"parameter_name": {
"description": "What this parameter represents",
"type": "data_type",
"default": "default_value"
}
}
}- Naturlig sprogbehandling: SLM'en analyserer brugerinput for at forstå intentionen
- Funktionsmatching: Bestemmer, hvilke funktion(er) der er nødvendige for at opfylde forespørgslen
- Parameterudtræk: Identificerer og udtrækker nødvendige parametre fra brugerens besked
SLM'en genererer struktureret JSON, der indeholder:
- Funktionsnavn, der skal kaldes
- Nødvendige parametre med passende værdier
- Eksekveringskontekst og metadata
- Parametervalidering: Sikrer, at alle nødvendige parametre er til stede og korrekt formateret
- Funktionsudførelse: Applikationen udfører den specificerede funktion med de angivne parametre
- Fejlhåndtering: Håndterer fejl, tidsoverskridelser og ugyldige svar
- Resultatbehandling: Funktionsoutput returneres til SLM'en
- Kontekstintegration: SLM'en inkorporerer resultaterne i sit svar
- Brugerkommunikation: Præsenterer informationen i et naturligt, samtalebaseret format
Konverter naturlige sprogforespørgsler til strukturerede API-kald:
- "Vis mine seneste ordrer" → Databaseforespørgsel med bruger-ID og datofiltre
- "Hvordan er vejret i Tokyo?" → Vejr-API-kald med lokalitetsparameter
- "Find e-mails fra John i sidste uge" → E-mailtjenesteforespørgsel med afsender- og datofiltre
Transformér brugerforespørgsler til specifikke funktionskald:
- "Planlæg et møde i morgen kl. 14" → Kalender-API-integration
- "Send en besked til teamet" → Kommunikationsplatform-API
- "Lav en sikkerhedskopi af mine filer" → Filhåndteringsoperation
Håndter komplekse matematiske eller logiske operationer:
- "Beregn renters rente på $10.000 ved 5% i 10 år" → Finansiel beregningsfunktion
- "Analyser dette datasæt for tendenser" → Statistiske analyseværktøjer
- "Optimer denne rute til levering" → Ruteoptimeringsalgoritmer
Kæd flere funktionskald sammen for komplekse operationer:
- Hent data fra flere kilder
- Parse og valider informationen
- Transformer data til det ønskede format
- Gem resultater i passende systemer
- Generér rapporter eller visualiseringer
Muliggør dynamiske interfaceopdateringer:
- "Vis salgsdata på dashboardet" → Diagramgenerering og visning
- "Opdater kortet med nye lokationer" → Geospatiale data
- "Opdater lageroversigten" → Realtidsdatasynkronisering
Microsofts Phi-4-mini understøtter både enkelt- og parallelle funktionskald via Ollama. Sådan opsættes det:
- Ollama version 0.5.13 eller højere
- Phi-4-mini model (anbefalet:
phi4-mini:3.8b-fp16)
# Download the model (if not already present)
ollama run phi4-mini:3.8b-fp16
# Verify the model is available
ollama listPå grund af nuværende begrænsninger i Ollamas standard-skabeloner skal du oprette en brugerdefineret ModelFile med følgende skabelon:
TEMPLATE """
{{- if .Messages }}
{{- if or .System .Tools }}<|system|>
{{ if .System }}{{ .System }}
{{- end }}
In addition to plain text responses, you can chose to call one or more of the provided functions.
Use the following rule to decide when to call a function:
* if the response can be generated from your internal knowledge (e.g., as in the case of queries like "What is the capital of Poland?"), do so
* if you need external information that can be obtained by calling one or more of the provided functions, generate a function calls
If you decide to call functions:
* prefix function calls with functools marker (no closing marker required)
* all function calls should be generated in a single JSON list formatted as functools[{"name": [function name], "arguments": [function arguments as JSON]}, ...]
* follow the provided JSON schema. Do not hallucinate arguments or values. Do to blindly copy values from the provided samples
* respect the argument type formatting. E.g., if the type if number and format is float, write value 7 as 7.0
* make sure you pick the right functions that match the user intent
Available functions as JSON spec:
{{- if .Tools }}
{{ .Tools }}
{{- end }}<|end|>
{{- end }}
{{- range .Messages }}
{{- if ne .Role "system" }}<|{{ .Role }}|>
{{- if and .Content (eq .Role "tools") }}
{"result": {{ .Content }}}
{{- else if .Content }}
{{ .Content }}
{{- else if .ToolCalls }}
functools[
{{- range .ToolCalls }}{{ "{" }}"name": "{{ .Function.Name }}", "arguments": {{ .Function.Arguments }}{{ "}" }}
{{- end }}]
{{- end }}<|end|>
{{- end }}
{{- end }}<|assistant|>
{{ else }}
{{- if .System }}<|system|>
{{ .System }}<|end|>{{ end }}{{ if .Prompt }}<|user|>
{{ .Prompt }}<|end|>{{ end }}<|assistant|>
{{ end }}{{ .Response }}{{ if .Response }}<|user|>{{ end }}
"""
# Save the template above as 'Modelfile' and run:
ollama create phi4-mini-fc:3.8b-fp16 -f ./Modelfileimport json
import requests
# Define the tool/function
tools = [
{
"name": "get_weather",
"description": "Get current weather information for a location",
"parameters": {
"location": {
"description": "The city or location name",
"type": "str",
"default": "New York"
},
"units": {
"description": "Temperature units (celsius or fahrenheit)",
"type": "str",
"default": "celsius"
}
}
}
]
# Create the message with system prompt including tools
messages = [
{
"role": "system",
"content": "You are a helpful weather assistant",
"tools": json.dumps(tools)
},
{
"role": "user",
"content": "What's the weather like in London today?"
}
]
# Make request to Ollama API
response = requests.post(
"http://localhost:11434/api/chat",
json={
"model": "phi4-mini-fc:3.8b-fp16",
"messages": messages,
"stream": False
}
)
print(response.json())import json
import requests
# Define multiple tools for parallel execution
AGENT_TOOLS = {
"booking_flight": {
"name": "booking_flight",
"description": "Book a flight ticket",
"parameters": {
"departure": {
"description": "Departure airport code",
"type": "str"
},
"destination": {
"description": "Destination airport code",
"type": "str"
},
"outbound_date": {
"description": "Departure date (YYYY-MM-DD)",
"type": "str"
},
"return_date": {
"description": "Return date (YYYY-MM-DD)",
"type": "str"
}
}
},
"booking_hotel": {
"name": "booking_hotel",
"description": "Book a hotel room",
"parameters": {
"city": {
"description": "City name for hotel booking",
"type": "str"
},
"check_in_date": {
"description": "Check-in date (YYYY-MM-DD)",
"type": "str"
},
"check_out_date": {
"description": "Check-out date (YYYY-MM-DD)",
"type": "str"
}
}
}
}
SYSTEM_PROMPT = """
You are my travel agent with some tools available.
"""
messages = [
{
"role": "system",
"content": SYSTEM_PROMPT,
"tools": json.dumps(AGENT_TOOLS)
},
{
"role": "user",
"content": "I need to travel from London to New York from March 21 2025 to March 27 2025. Please book both flight and hotel."
}
]
# The model will generate parallel function calls
response = requests.post(
"http://localhost:11434/api/chat",
json={
"model": "phi4-mini-fc:3.8b-fp16",
"messages": messages,
"stream": False
}
)
print(response.json())Qwen3 tilbyder avancerede funktionskald med fremragende ydeevne og fleksibilitet. Sådan implementeres det:
Qwen-Agent giver en høj-niveau ramme, der forenkler implementeringen af funktionskald:
pip install -U "qwen-agent[gui,rag,code_interpreter,mcp]"import os
from qwen_agent.agents import Assistant
# Configure the LLM
llm_cfg = {
'model': 'Qwen3-8B',
# Option 1: Use Alibaba Model Studio
'model_type': 'qwen_dashscope',
'api_key': os.getenv('DASHSCOPE_API_KEY'),
# Option 2: Use local deployment
# 'model_server': 'http://localhost:8000/v1',
# 'api_key': 'EMPTY',
# Optional configuration for thinking mode
'generate_cfg': {
'thought_in_content': True, # Include reasoning in response
}
}
# Define tools using MCP (Model Context Protocol)
tools = [
{
'mcpServers': {
'time': {
'command': 'uvx',
'args': ['mcp-server-time', '--local-timezone=Asia/Shanghai']
},
'fetch': {
'command': 'uvx',
'args': ['mcp-server-fetch']
}
}
},
'code_interpreter', # Built-in code execution tool
]
# Create the assistant
bot = Assistant(llm=llm_cfg, function_list=tools)
# Example usage
messages = [
{
'role': 'user',
'content': 'What time is it now? Also, fetch the latest news from https://example.com/news'
}
]
# Generate response with function calling
for response in bot.run(messages=messages):
print(response)Du kan også definere brugerdefinerede funktioner til Qwen3:
import json
from qwen_agent.tools.base import BaseTool
class WeatherTool(BaseTool):
description = 'Get weather information for a specific location'
parameters = [
{
'name': 'location',
'type': 'string',
'description': 'City or location name',
'required': True
},
{
'name': 'units',
'type': 'string',
'description': 'Temperature units (celsius or fahrenheit)',
'required': False,
'default': 'celsius'
}
]
def call(self, params: str, **kwargs) -> str:
"""Execute the weather lookup"""
params_dict = json.loads(params)
location = params_dict.get('location')
units = params_dict.get('units', 'celsius')
# Simulate weather API call
weather_data = {
'location': location,
'temperature': '22°C' if units == 'celsius' else '72°F',
'condition': 'Partly cloudy',
'humidity': '65%'
}
return json.dumps(weather_data)
# Use the custom tool
tools = [WeatherTool()]
bot = Assistant(llm=llm_cfg, function_list=tools)
messages = [{'role': 'user', 'content': 'What\'s the weather in Tokyo?'}]
response = bot.run(messages=messages)
print(list(response)[-1])Qwen3 understøtter dynamisk skift mellem tænke- og ikke-tænkemodus:
# Enable thinking mode for complex reasoning
messages = [
{
'role': 'user',
'content': '/think Solve this complex math problem: If a train travels 120 km in 1.5 hours, and another train travels 200 km in 2.5 hours, which train is faster and by how much?'
}
]
# Disable thinking mode for simple queries
messages = [
{
'role': 'user',
'content': '/no_think What is the capital of France?'
}
]Qwen3 er fremragende til at kæde flere funktionskald sammen:
# Complex workflow example
messages = [
{
'role': 'user',
'content': '''
I need to prepare for a business meeting:
1. Check my calendar for conflicts tomorrow
2. Get weather forecast for the meeting location (San Francisco)
3. Find recent news about the client company (TechCorp)
4. Calculate travel time from my office to their headquarters
'''
}
]
# Qwen3 will automatically determine the sequence of function calls neededMicrosofts Foundry Local tilbyder en OpenAI-kompatibel API til at køre modeller lokalt med forbedret privatliv og ydeevne.
Download installationsprogrammet fra Foundry Local releases side og følg installationsvejledningen.
brew tap microsoft/foundrylocal
brew install foundrylocalimport openai
from foundry_local import FoundryLocalManager
# Initialize with model alias
alias = "phi-3.5-mini" # Or any supported model
manager = FoundryLocalManager(alias)
# Create OpenAI client pointing to local endpoint
client = openai.OpenAI(
base_url=manager.endpoint,
api_key=manager.api_key
)
# Define functions for the model
functions = [
{
"name": "calculate_tax",
"description": "Calculate tax amount based on income and rate",
"parameters": {
"type": "object",
"properties": {
"income": {
"type": "number",
"description": "Annual income amount"
},
"tax_rate": {
"type": "number",
"description": "Tax rate as decimal (e.g., 0.25 for 25%)"
}
},
"required": ["income", "tax_rate"]
}
}
]
# Make function calling request
response = client.chat.completions.create(
model=manager.model_info.id,
messages=[
{
"role": "user",
"content": "Calculate the tax for someone earning $75,000 with a 22% tax rate"
}
],
functions=functions,
function_call="auto"
)
print(response.choices[0].message.content)# List available models
foundry model list
# Download specific model
foundry model download phi-3.5-mini
# Run model interactively
foundry model run phi-3.5-mini
# Remove model from cache
foundry model remove phi-3.5-mini
# Delete all cached models
foundry model remove "*"Foundry Local vælger automatisk den bedste modelvariant til din hardware:
- CUDA GPU: Downloader GPU-optimerede modeller
- Qualcomm NPU: Bruger NPU-accelererede varianter
- Kun CPU: Vælger CPU-optimerede modeller
# Good
{
"name": "get_stock_price",
"description": "Retrieve current stock price for a given symbol"
}
# Avoid
{
"name": "get_data",
"description": "Gets data"
}{
"name": "send_email",
"description": "Send an email message to specified recipients",
"parameters": {
"to": {
"type": "array",
"items": {"type": "string"},
"description": "List of recipient email addresses",
"required": True
},
"subject": {
"type": "string",
"description": "Email subject line",
"required": True
},
"body": {
"type": "string",
"description": "Email message content",
"required": True
},
"priority": {
"type": "string",
"enum": ["low", "normal", "high"],
"description": "Email priority level",
"default": "normal",
"required": False
}
}
}def execute_function(function_name, parameters):
try:
# Validate required parameters
if function_name == "send_email":
if not parameters.get("to") or not parameters.get("subject"):
return {"error": "Missing required parameters: to, subject"}
# Validate email format
email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
for email in parameters["to"]:
if not re.match(email_pattern, email):
return {"error": f"Invalid email format: {email}"}
# Execute function logic
result = perform_actual_function(function_name, parameters)
return {"success": True, "data": result}
except Exception as e:
return {"error": str(e)}Symptomer: Modellen svarer med tekst i stedet for at kalde funktionen
Løsninger:
- Tjek funktionsbeskrivelsen: Sørg for, at den klart matcher brugerens intention
- Bekræft parameterdefinitioner: Sørg for, at alle nødvendige parametre er korrekt defineret
- Gennemgå systemprompten: Inkluder klare instruktioner om, hvornår funktioner skal bruges
- Test med eksplicitte forespørgsler: Prøv "Brug venligst vejrfunktionen til at hente data for London"
Symptomer: Funktion kaldt med forkerte eller manglende parametre
Løsninger:
- Tilføj parameter-eksempler: Inkluder prøveværdier i parameterbeskrivelser
- Brug enum-begrænsninger: Begræns parameterværdier til specifikke muligheder, hvor det er muligt
- Implementer fallback-værdier: Giv fornuftige standardværdier for valgfrie parametre
{
"name": "book_restaurant",
"parameters": {
"cuisine": {
"type": "string",
"enum": ["italian", "chinese", "mexican", "american", "french"],
"description": "Type of cuisine (example: 'italian' for Italian food)"
},
"party_size": {
"type": "integer",
"minimum": 1,
"maximum": 20,
"description": "Number of people (example: 4 for a family of four)"
}
}
}Symptomer: Kun én funktion udføres, når flere burde køre
Løsninger:
- Tjek modelsupport: Sørg for, at din model understøtter parallelle funktionskald
- Opdater systemprompten: Inkluder "nogle værktøjer" eller "flere værktøjer" i systembeskeden
- Brug passende modelversioner: Phi-4-mini:3.8b-fp16 anbefales til Ollama
Symptomer: Funktionskald fungerer ikke med Ollamas standardopsætning
Løsninger:
- Brug brugerdefineret ModelFile: Anvend den korrigerede skabelon, der er angivet i denne vejledning
- Opdater Ollama: Sørg for, at du bruger version 0.5.13 eller højere
- Tjek modelkvantisering: Højere kvantiseringsniveauer (Q8_0, fp16) fungerer bedre end stærkt kvantiserede versioner
- Hold funktioner fokuserede: Hver funktion bør have et enkelt, klart formål
- Minimer eksterne afhængigheder: Reducer API-kald og netværksanmodninger, hvor det er muligt
- Cache resultater: Gem ofte forespurgte data for at forbedre svartider
import asyncio
import aiohttp
async def batch_function_calls(function_calls):
"""Execute multiple function calls concurrently"""
async with aiohttp.ClientSession() as session:
tasks = []
for call in function_calls:
if call["name"] == "fetch_url":
task = fetch_url_async(session, call["parameters"]["url"])
tasks.append(task)
results = await asyncio.gather(*tasks)
return results
async def fetch_url_async(session, url):
async with session.get(url) as response:
return await response.text()- Forbindelsespuljer: Genbrug database- og API-forbindelser
- Hastighedsbegrænsning: Implementer korrekt hastighedsbegrænsning for eksterne API'er
- Timeout-håndtering: Indstil rimelige tidsgrænser for alle eksterne kald
import json
from typing import List, Dict
from qwen_agent.agents import Assistant
class MultiAgentSystem:
def __init__(self):
# Research Agent
self.research_agent = Assistant(
llm={'model': 'Qwen3-8B', 'model_server': 'http://localhost:8000/v1'},
function_list=[
{'mcpServers': {'search': {'command': 'uvx', 'args': ['mcp-server-search']}}},
{'mcpServers': {'fetch': {'command': 'uvx', 'args': ['mcp-server-fetch']}}}
]
)
# Analysis Agent
self.analysis_agent = Assistant(
llm={'model': 'Qwen3-8B', 'model_server': 'http://localhost:8000/v1'},
function_list=['code_interpreter']
)
# Communication Agent
self.comm_agent = Assistant(
llm={'model': 'Qwen3-8B', 'model_server': 'http://localhost:8000/v1'},
function_list=[self.create_email_tool(), self.create_slack_tool()]
)
def create_email_tool(self):
"""Custom email sending tool"""
class EmailTool:
name = "send_email"
description = "Send email to specified recipients"
parameters = {
"to": {"type": "string", "description": "Recipient email"},
"subject": {"type": "string", "description": "Email subject"},
"body": {"type": "string", "description": "Email content"}
}
def call(self, params):
# Implement actual email sending logic
return f"Email sent successfully to {params['to']}"
return EmailTool()
def create_slack_tool(self):
"""Custom Slack messaging tool"""
class SlackTool:
name = "send_slack"
description = "Send message to Slack channel"
parameters = {
"channel": {"type": "string", "description": "Slack channel"},
"message": {"type": "string", "description": "Message content"}
}
def call(self, params):
# Implement actual Slack API call
return f"Message sent to {params['channel']}"
return SlackTool()
async def process_complex_request(self, user_request: str):
"""Process complex multi-step requests using multiple agents"""
# Step 1: Research phase
research_prompt = f"Research the following topic and gather relevant information: {user_request}"
research_results = []
for response in self.research_agent.run([{'role': 'user', 'content': research_prompt}]):
research_results.append(response)
# Step 2: Analysis phase
analysis_prompt = f"Analyze the following research data and provide insights: {research_results[-1]}"
analysis_results = []
for response in self.analysis_agent.run([{'role': 'user', 'content': analysis_prompt}]):
analysis_results.append(response)
# Step 3: Communication phase
comm_prompt = f"Create a summary report and send it via email: {analysis_results[-1]}"
comm_results = []
for response in self.comm_agent.run([{'role': 'user', 'content': comm_prompt}]):
comm_results.append(response)
return {
'research': research_results[-1],
'analysis': analysis_results[-1],
'communication': comm_results[-1]
}
# Usage example
async def main():
system = MultiAgentSystem()
request = """
Analyze the impact of remote work on productivity in tech companies.
Research recent studies, analyze the data, and send a summary to our team.
"""
results = await system.process_complex_request(request)
print("Multi-agent processing complete:", results)
# Run the example
# asyncio.run(main())class DynamicToolSelector:
def __init__(self):
self.available_tools = {
'weather': {
'description': 'Get weather information',
'domains': ['weather', 'temperature', 'forecast', 'climate'],
'function': self.get_weather
},
'calculator': {
'description': 'Perform mathematical calculations',
'domains': ['math', 'calculate', 'compute', 'arithmetic'],
'function': self.calculate
},
'web_search': {
'description': 'Search the internet for information',
'domains': ['search', 'find', 'lookup', 'research'],
'function': self.web_search
},
'file_manager': {
'description': 'Manage files and directories',
'domains': ['file', 'directory', 'save', 'load', 'delete'],
'function': self.manage_files
}
}
def analyze_intent(self, user_input: str) -> List[str]:
"""Analyze user input to determine which tools might be needed"""
user_words = user_input.lower().split()
relevant_tools = []
for tool_name, tool_info in self.available_tools.items():
for domain in tool_info['domains']:
if domain in user_words:
relevant_tools.append(tool_name)
break
return relevant_tools
def get_tool_definitions(self, tool_names: List[str]) -> List[Dict]:
"""Generate function definitions for selected tools"""
definitions = []
for tool_name in tool_names:
if tool_name == 'weather':
definitions.append({
'name': 'get_weather',
'description': 'Get current weather information',
'parameters': {
'location': {'type': 'string', 'description': 'City or location name'},
'units': {'type': 'string', 'enum': ['celsius', 'fahrenheit'], 'default': 'celsius'}
}
})
elif tool_name == 'calculator':
definitions.append({
'name': 'calculate',
'description': 'Perform mathematical calculations',
'parameters': {
'expression': {'type': 'string', 'description': 'Mathematical expression to evaluate'},
'precision': {'type': 'integer', 'default': 2, 'description': 'Decimal places for result'}
}
})
# Add more tool definitions as needed
return definitions
def get_weather(self, location: str, units: str = 'celsius') -> Dict:
"""Mock weather function"""
return {
'location': location,
'temperature': '22°C' if units == 'celsius' else '72°F',
'condition': 'Sunny',
'humidity': '60%'
}
def calculate(self, expression: str, precision: int = 2) -> Dict:
"""Safe mathematical calculation"""
try:
# Simple evaluation for demo - in production, use a proper math parser
import math
allowed_names = {
k: v for k, v in math.__dict__.items() if not k.startswith("__")
}
allowed_names.update({"abs": abs, "round": round})
result = eval(expression, {"__builtins__": {}}, allowed_names)
return {
'expression': expression,
'result': round(float(result), precision),
'success': True
}
except Exception as e:
return {
'expression': expression,
'error': str(e),
'success': False
}
def web_search(self, query: str, max_results: int = 5) -> Dict:
"""Mock web search function"""
return {
'query': query,
'results': [
{'title': f'Result {i+1} for {query}', 'url': f'https://example{i+1}.com'}
for i in range(max_results)
]
}
def manage_files(self, action: str, file_path: str, content: str = None) -> Dict:
"""Mock file management function"""
return {
'action': action,
'file_path': file_path,
'success': True,
'message': f'Successfully {action}ed file: {file_path}'
}
# Usage example
def smart_assistant_with_dynamic_tools():
selector = DynamicToolSelector()
user_requests = [
"What's the weather like in New York and calculate 15% tip on $50?",
"Search for recent AI developments and save the results to a file",
"Calculate the area of a circle with radius 10 and check weather in Tokyo"
]
for request in user_requests:
print(f"\nUser Request: {request}")
# Analyze which tools might be needed
relevant_tools = selector.analyze_intent(request)
print(f"Relevant Tools: {relevant_tools}")
# Get function definitions for the LLM
tool_definitions = selector.get_tool_definitions(relevant_tools)
print(f"Tool Definitions: {len(tool_definitions)} functions available")
# In a real implementation, you would pass these to your LLM
# The LLM would then decide which functions to call and with what parameters
### Enterprise Integration Example
```python
import asyncio
import json
from typing import Dict, List, Any
from dataclasses import dataclass
from datetime import datetime
@dataclass
class FunctionResult:
"""Standardresultatformat for alle funktionskald"""
success: bool
data: Any = None
error: str = None
execution_time: float = 0.0
timestamp: datetime = None
class EnterpriseAIAgent:
"""Produktionsklar AI-agent med omfattende funktionskaldsfunktioner"""
def __init__(self, config: Dict):
self.config = config
self.functions = {}
self.audit_log = []
self.rate_limiters = {}
# Initialiser kerneforretningsfunktioner
self._register_core_functions()
def _register_core_functions(self):
"""Registrer alle tilgængelige forretningsfunktioner"""
# CRM-funktioner
self.register_function(
name="get_customer_info",
description="Hent kundeinformation fra CRM",
parameters={
"customer_id": {"type": "string", "required": True},
"include_history": {"type": "boolean", "default": False}
},
handler=self._get_customer_info,
rate_limit=100 # kald pr. minut
)
# Salgsfunktioner
self.register_function(
name="create_sales_opportunity",
description="Opret en ny salgsmulighed",
parameters={
"customer_id": {"type": "string", "required": True},
"product_id": {"type": "string", "required": True},
"estimated_value": {"type": "number", "required": True},
"expected_close_date": {"type": "string", "required": True}
},
handler=self._create_sales_opportunity,
rate_limit=50
)
# Analysefunktioner
self.register_function(
name="generate_sales_report",
description="Generer salgspræstationsrapport",
parameters={
"period": {"type": "string", "enum": ["daily", "weekly", "monthly", "quarterly"]},
"region": {"type": "string", "required": False},
"product_category": {"type": "string", "required": False}
},
handler=self._generate_sales_report,
rate_limit=10
)
# Notifikationsfunktioner
self.register_function(
name="send_notification",
description="Send notifikation til teammedlemmer",
parameters={
"recipients": {"type": "array", "items": {"type": "string"}},
"message": {"type": "string", "required": True},
"priority": {"type": "string", "enum": ["low", "medium", "high"], "default": "medium"},
"channel": {"type": "string", "enum": ["email", "slack", "teams"], "default": "email"}
},
handler=self._send_notification,
rate_limit=200
)
def register_function(self, name: str, description: str, parameters: Dict,
handler: callable, rate_limit: int = 60):
"""Registrer en ny funktion med agenten"""
self.functions[name] = {
'description': description,
'parameters': parameters,
'handler': handler,
'rate_limit': rate_limit,
'call_count': 0,
'last_reset': datetime.now()
}
async def execute_function(self, function_name: str, parameters: Dict) -
Could you please provide the markdown file content that needs to be translated?
"""Udfør en funktion med omfattende fejlhåndtering og logning"""
start_time = datetime.now()
try:
# Valider, at funktionen eksisterer
if function_name not in self.functions:
return FunctionResult(
success=False,
error=f"Funktionen '{function_name}' blev ikke fundet",
timestamp=start_time
)
# Tjek hastighedsbegrænsninger
if not self._check_rate_limit(function_name):
return FunctionResult(
success=False,
error=f"Hastighedsbegrænsning overskredet for funktionen '{function_name}'",
timestamp=start_time
)
# Valider parametre
validation_result = self._validate_parameters(function_name, parameters)
if not validation_result.success:
return validation_result
# Udfør funktionen
func_info = self.functions[function_name]
handler = func_info['handler']
if asyncio.iscoroutinefunction(handler):
result_data = await handler(**parameters)
else:
result_data = handler(**parameters)
execution_time = (datetime.now() - start_time).total_seconds()
result = FunctionResult(
success=True,
data=result_data,
execution_time=execution_time,
timestamp=start_time
)
# Log vellykket udførelse
self._log_function_call(function_name, parameters, result)
return result
except Exception as e:
execution_time = (datetime.now() - start_time).total_seconds()
result = FunctionResult(
success=False,
error=str(e),
execution_time=execution_time,
timestamp=start_time
)
# Log mislykket udførelse
self._log_function_call(function_name, parameters, result)
return result
def _check_rate_limit(self, function_name: str) -> bool:
"""Tjek om funktionens kald er inden for hastighedsbegrænsninger"""
func_info = self.functions[function_name]
now = datetime.now()
# Nulstil tæller, hvis et minut er gået
if (now - func_info['last_reset']).seconds >= 60:
func_info['call_count'] = 0
func_info['last_reset'] = now
# Tjek om grænsen er overskredet
if func_info['call_count'] >= func_info['rate_limit']:
return False
func_info['call_count'] += 1
return True
def _validate_parameters(self, function_name: str, parameters: Dict) -> FunctionResult:
"""Valider funktionens parametre"""
func_params = self.functions[function_name]['parameters']
# Tjek påkrævede parametre
for param_name, param_info in func_params.items():
if param_info.get('required', False) and param_name not in parameters:
return FunctionResult(
success=False,
error=f"Mangler påkrævet parameter: {param_name}"
)
# Valider parameter typer og begrænsninger
for param_name, value in parameters.items():
if param_name in func_params:
param_info = func_params[param_name]
# Typevalidering
expected_type = param_info.get('type')
if expected_type == 'string' and not isinstance(value, str):
return FunctionResult(
success=False,
error=f"Parameter '{param_name}' skal være en streng"
)
elif expected_type == 'number' and not isinstance(value, (int, float)):
return FunctionResult(
success=False,
error=f"Parameter '{param_name}' skal være et tal"
)
elif expected_type == 'boolean' and not isinstance(value, bool):
return FunctionResult(
success=False,
error=f"Parameter '{param_name}' skal være en boolsk værdi"
)
# Enum-validering
if 'enum' in param_info and value not in param_info['enum']:
return FunctionResult(
success=False,
error=f"Parameter '{param_name}' skal være en af følgende: {param_info['enum']}"
)
return FunctionResult(success=True)
def _log_function_call(self, function_name: str, parameters: Dict, result: FunctionResult):
"""Log funktionens kald til revisionsformål"""
log_entry = {
'timestamp': result.timestamp.isoformat(),
'function_name': function_name,
'parameters': parameters,
'success': result.success,
'execution_time': result.execution_time,
'error': result.error if not result.success else None
}
self.audit_log.append(log_entry)
# Valgfrit: skriv til eksternt logningssystem
if self.config.get('enable_external_logging', False):
self._write_to_external_log(log_entry)
def _write_to_external_log(self, log_entry: Dict):
"""Skriv logindgang til eksternt logningssystem"""
# Implementeringen afhænger af dit logningsinfrastruktur
# f.eks. send til ELK stack, CloudWatch osv.
pass
# Implementeringer af forretningsfunktioner
async def _get_customer_info(self, customer_id: str, include_history: bool = False) -> Dict:
"""Hent kundeinformation fra CRM-systemet"""
# Simuler database-/API-kald
await asyncio.sleep(0.1) # Simuler netværksforsinkelse
customer_data = {
'customer_id': customer_id,
'name': 'John Doe',
'email': 'john.doe@example.com',
'phone': '+1-555-0123',
'status': 'active',
'tier': 'premium'
}
if include_history:
customer_data['purchase_history'] = [
{'date': '2024-01-15', 'product': 'Produkt A', 'amount': 1500},
{'date': '2024-03-22', 'product': 'Produkt B', 'amount': 2300}
]
return customer_data
async def _create_sales_opportunity(self, customer_id: str, product_id: str,
estimated_value: float, expected_close_date: str) -> Dict:
"""Opret en ny salgschance"""
# Simuler CRM API-kald
await asyncio.sleep(0.2)
opportunity_id = f"OPP-{datetime.now().strftime('%Y%m%d%H%M%S')}"
return {
'opportunity_id': opportunity_id,
'customer_id': customer_id,
'product_id': product_id,
'estimated_value': estimated_value,
'expected_close_date': expected_close_date,
'status': 'open',
'created_date': datetime.now().isoformat()
}
async def _generate_sales_report(self, period: str, region: str = None,
product_category: str = None) -> Dict:
"""Generer omfattende salgsrapport"""
# Simuler dataaggregering
await asyncio.sleep(0.5)
return {
'report_id': f"RPT-{datetime.now().strftime('%Y%m%d%H%M%S')}",
'period': period,
'region': region,
'product_category': product_category,
'total_sales': 125000.00,
'total_opportunities': 45,
'conversion_rate': 0.67,
'top_products': [
{'product_id': 'PROD-001', 'sales': 45000},
{'product_id': 'PROD-002', 'sales': 32000}
],
'generated_at': datetime.now().isoformat()
}
async def _send_notification(self, recipients: List[str], message: str,
priority: str = 'medium', channel: str = 'email') -> Dict:
"""Send notifikation via angivet kanal"""
# Simuler notifikationstjeneste-kald
await asyncio.sleep(0.1)
notification_id = f"NOTIF-{datetime.now().strftime('%Y%m%d%H%M%S')}"
return {
'notification_id': notification_id,
'recipients': recipients,
'channel': channel,
'priority': priority,
'status': 'sent',
'sent_at': datetime.now().isoformat()
}
def get_function_definitions(self) -> List[Dict]:
"""Hent OpenAI-kompatible funktionsdefinitioner for alle registrerede funktioner"""
definitions = []
for func_name, func_info in self.functions.items():
definition = {
'name': func_name,
'description': func_info['description'],
'parameters': {
'type': 'object',
'properties': {},
'required': []
}
}
for param_name, param_info in func_info['parameters'].items():
definition['parameters']['properties'][param_name] = {
'type': param_info['type'],
'description': param_info.get('description', '')
}
if 'enum' in param_info:
definition['parameters']['properties'][param_name]['enum'] = param_info['enum']
if 'default' in param_info:
definition['parameters']['properties'][param_name]['default'] = param_info['default']
if param_info.get('required', False):
definition['parameters']['required'].append(param_name)
definitions.append(definition)
return definitions
# Eksempel på brug til virksomhedsintegration
async def enterprise_demo():
"""Demonstrer virksomhedens AI-agent kapaciteter"""
config = {
'enable_external_logging': True,
'max_concurrent_functions': 10,
'default_timeout': 30
}
agent = EnterpriseAIAgent(config)
# Eksempel 1: Behandling af kundeforespørgsler
print("=== Behandling af kundeforespørgsler ===")
# Hent kundeinformation
result = await agent.execute_function(
'get_customer_info',
{'customer_id': 'CUST-12345', 'include_history': True}
)
if result.success:
print(f"Kundeinformation hentet: {result.data['name']}")
print(f"Udførelsestid: {result.execution_time:.3f}s")
# Eksempel 2: Oprettelse af salgschance
print("\n=== Oprettelse af salgschance ===")
result = await agent.execute_function(
'create_sales_opportunity',
{
'customer_id': 'CUST-12345',
'product_id': 'PROD-001',
'estimated_value': 15000.0,
'expected_close_date': '2025-09-30'
}
)
if result.success:
print(f"Salgschance oprettet: {result.data['opportunity_id']}")
# Eksempel 3: Batch-operationer
print("\n=== Batch-operationer ===")
tasks = [
agent.execute_function('generate_sales_report', {'period': 'monthly'}),
agent.execute_function('send_notification', {
'recipients': ['manager@company.com'],
'message': 'Ny salgschance oprettet',
'priority': 'high',
'channel': 'email'
})
]
results = await asyncio.gather(*tasks)
for i, result in enumerate(results):
if result.success:
print(f"Task {i+1} fuldført med succes")
else:
print(f"Task {i+1} mislykkedes: {result.error}")
# Vis revisionslog
print(f"\n=== Revisionslog ({len(agent.audit_log)} poster) ===")
for entry in agent.audit_log[-3:]: # Vis de sidste 3 poster
print(f"{entry['timestamp']}: {entry['function_name']} - {'SUCCESS' if entry['success'] else 'FAILED'}")
# Kør virksomhedens demo
# asyncio.run(enterprise_demo())
## Konklusion
Funktionskald i Small Language Models repræsenterer et paradigmeskift fra statiske AI-assistenter til dynamiske, kapable agenter, der kan interagere med den virkelige verden. Denne vejledning har dækket:
### Vigtige pointer
1. **Grundlæggende forståelse**: Funktionskald gør det muligt for SLM'er at gå ud over deres træningsdata ved at forbinde til eksterne værktøjer og tjenester.
2. **Fleksibilitet i implementering**: Der findes flere tilgange, fra lav-niveau implementeringer med brugerdefinerede skabeloner til høj-niveau frameworks som Qwen-Agent og Foundry Local.
3. **Overvejelser for produktion**: Virksomhedsudrulninger kræver opmærksomhed på fejlhåndtering, hastighedsbegrænsning, sikkerhed og revisionslogning.
4. **Optimering af ydeevne**: Korrekt funktionsdesign, effektiv udførelse og smart caching kan markant forbedre svartider.
### Fremtidige retninger
Efterhånden som SLM-teknologien fortsætter med at udvikle sig, kan vi forvente:
- **Forbedret nøjagtighed i funktionskald**: Bedre identifikation af intentioner og parameterudtrækning
- **Avanceret parallel behandling**: Mere sofistikeret orkestrering af flere funktioner
- **Bedre integrationsstandarder**: Standardiserede protokoller for værktøjsintegration
- **Avancerede sikkerhedsfunktioner**: Forbedret autentificering og autorisationsmekanismer
- **Udvidet økosystem**: Voksende bibliotek af forudbyggede funktioner og integrationer
### Kom godt i gang
For at begynde implementeringen af funktionskald i dine projekter:
1. **Start simpelt**: Begynd med grundlæggende scenarier med enkeltfunktioner
2. **Vælg dit framework**: Vælg mellem direkte implementering (Ollama/Phi-4) eller framework-assisteret (Qwen-Agent)
3. **Design funktioner omhyggeligt**: Fokusér på klare, veldokumenterede funktionsdefinitioner
4. **Implementér fejlhåndtering**: Byg robust fejlhåndtering fra starten
5. **Skalér gradvist**: Gå fra simple til komplekse scenarier, efterhånden som du får erfaring
Funktionskald transformerer SLM'er fra imponerende tekstgeneratorer til praktiske AI-agenter, der kan løse virkelige problemer. Ved at følge mønstrene og praksisserne i denne vejledning kan du bygge kraftfulde, pålidelige AI-systemer, der går langt ud over traditionelle chatgrænseflader.
### Ressourcer og referencer
- **Phi-4 Modeller**: [Hugging Face Collection](https://huggingface.co/collections/microsoft/phi-4-677e9380e514feb5577a40e4)
- **Qwen3 Dokumentation**: [Officiel Qwen Dokumentation](https://qwen.readthedocs.io/)
- **Ollama**: [Officiel Hjemmeside](https://ollama.com/)
- **Foundry Local**: [GitHub Repository](https://github.com/microsoft/Foundry-Local)
- **Bedste Fremgangsmåder for Funktionskald**: [Hugging Face Guide](https://huggingface.co/docs/hugs/en/guides/function-calling)
Husk, at funktionskald er et område i konstant udvikling, og det at holde sig opdateret med de nyeste fremskridt inden for dine valgte frameworks og modeller vil hjælpe dig med at bygge mere effektive AI-agenter.
## ➡️ Hvad er næste skridt
- [03: Model Context Protocol (MCP) Integration](./03.IntroduceMCP.md)
---
**Ansvarsfraskrivelse**:
Dette dokument er blevet oversat ved hjælp af AI-oversættelsestjenesten [Co-op Translator](https://github.com/Azure/co-op-translator). Selvom vi bestræber os på nøjagtighed, skal du være opmærksom på, at automatiserede oversættelser kan indeholde fejl eller unøjagtigheder. Det originale dokument på dets oprindelige sprog bør betragtes som den autoritative kilde. For kritisk information anbefales professionel menneskelig oversættelse. Vi er ikke ansvarlige for eventuelle misforståelser eller fejltolkninger, der måtte opstå som følge af brugen af denne oversættelse.