# Section02 : Извикване на функции в малки езикови модели (SLMs) ## Съдържание 1. [Какво е извикване на функции?](../../../Module06) 2. [Как работи извикването на функции](../../../Module06) 3. [Приложения](../../../Module06) 4. [Настройка на извикване на функции с Phi-4-mini и Ollama](../../../Module06) 5. [Работа с извикване на функции в Qwen3](../../../Module06) 6. [Локална интеграция с Foundry](../../../Module06) 7. [Най-добри практики и отстраняване на проблеми](../../../Module06) 8. [Разширени примери](../../../Module06) ## Какво е извикване на функции? Извикването на функции е мощна възможност, която позволява на малките езикови модели (SLMs) да взаимодействат с външни инструменти, API и услуги. Вместо да бъдат ограничени до своите тренировъчни данни, SLMs вече могат: - **Да се свързват с външни API** (услуги за времето, бази данни, търсачки) - **Да изпълняват специфични функции** според заявките на потребителя - **Да извличат информация в реално време** от различни източници - **Да извършват изчислителни задачи** чрез специализирани инструменти - **Да свързват множество операции** за сложни работни потоци Тази възможност трансформира SLMs от статични генератори на текст в динамични AI агенти, способни да изпълняват задачи в реалния свят. ## Как работи извикването на функции Процесът на извикване на функции следва систематичен работен поток: ### 1. Интеграция на инструменти - **Външни инструменти**: SLMs могат да се свързват с API за времето, бази данни, уеб услуги и други външни системи - **Дефиниции на функции**: Всеки инструмент се дефинира със специфични параметри, формати за вход/изход и описания - **Съвместимост с API**: Инструментите се интегрират чрез стандартизирани интерфейси (REST API, SDK и др.) ### 2. Дефиниция на функции Функциите се дефинират с три ключови компонента: ```json { "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" } } } ``` ### 3. Откриване на намерение - **Обработка на естествен език**: SLM анализира входа на потребителя, за да разбере намерението - **Съответствие на функции**: Определя кои функции са необходими за изпълнение на заявката - **Извличане на параметри**: Идентифицира и извлича необходимите параметри от съобщението на потребителя ### 4. Генериране на JSON изход SLM генерира структуриран JSON, съдържащ: - Името на функцията, която да бъде извикана - Необходимите параметри с подходящи стойности - Контекст на изпълнение и метаданни ### 5. Външно изпълнение - **Валидиране на параметри**: Уверява се, че всички необходими параметри са налични и правилно форматирани - **Изпълнение на функцията**: Приложението изпълнява посочената функция с предоставените параметри - **Управление на грешки**: Обработва неуспехи, изтичане на времето и невалидни отговори ### 6. Интеграция на отговори - **Обработка на резултати**: Изходът от функцията се връща към SLM - **Интеграция на контекст**: SLM включва резултатите в своя отговор - **Комуникация с потребителя**: Представя информацията в естествен, разговорен формат ## Приложения ### Извличане на данни Превръщане на заявки на естествен език в структурирани API повиквания: - **"Покажи моите последни поръчки"** → Заявка към база данни с потребителски ID и филтри за дата - **"Какво е времето в Токио?"** → API за времето с параметър за местоположение - **"Намери имейли от Джон миналата седмица"** → Заявка към имейл услуга с филтри за подател и дата ### Изпълнение на операции Превръщане на заявки на потребителя в специфични извиквания на функции: - **"Насрочи среща за утре в 14:00"** → Интеграция с API за календар - **"Изпрати съобщение до екипа"** → API за комуникационна платформа - **"Създай резервно копие на моите файлове"** → Операция с файловата система ### Изчислителни задачи Обработка на сложни математически или логически операции: - **"Изчисли сложна лихва върху $10,000 при 5% за 10 години"** → Функция за финансови изчисления - **"Анализирай този набор от данни за тенденции"** → Инструменти за статистически анализ - **"Оптимизирай този маршрут за доставка"** → Алгоритми за оптимизация на маршрути ### Работни потоци за обработка на данни Свързване на множество извиквания на функции за сложни операции: 1. **Извличане на данни** от множество източници 2. **Парсиране и валидиране** на информацията 3. **Трансформиране** на данни в необходимия формат 4. **Съхраняване на резултати** в подходящи системи 5. **Генериране на отчети** или визуализации ### Интеграция с потребителски интерфейс Позволяване на динамични актуализации на интерфейса: - **"Покажи данни за продажбите на таблото"** → Генериране и показване на графики - **"Актуализирай картата с нови местоположения"** → Интеграция на геопространствени данни - **"Обнови дисплея на инвентара"** → Синхронизация на данни в реално време ## Настройка на извикване на функции с Phi-4-mini и Ollama Phi-4-mini на Microsoft поддържа както единично, така и паралелно извикване на функции чрез Ollama. Ето как да го настроите: ### Предварителни условия - Ollama версия 0.5.13 или по-нова - Модел Phi-4-mini (препоръчва се: `phi4-mini:3.8b-fp16`) ### Стъпки за инсталация #### 1. Инсталиране и стартиране на Phi-4-mini ```bash # Download the model (if not already present) ollama run phi4-mini:3.8b-fp16 # Verify the model is available ollama list ``` #### 2. Създаване на персонализиран шаблон за ModelFile Поради текущи ограничения в шаблоните по подразбиране на Ollama, трябва да създадете персонализиран ModelFile със следния шаблон: ```modelfile 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 }} """ ``` #### 3. Създаване на персонализиран модел ```bash # Save the template above as 'Modelfile' and run: ollama create phi4-mini-fc:3.8b-fp16 -f ./Modelfile ``` ### Пример за единично извикване на функция ```python import 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()) ``` ### Пример за паралелно извикване на функции ```python 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 Qwen3 предлага разширени възможности за извикване на функции с отлична производителност и гъвкавост. Ето как да го приложите: ### Използване на рамката Qwen-Agent Qwen-Agent предоставя високонадеждна рамка, която опростява внедряването на извикване на функции: #### Инсталация ```bash pip install -U "qwen-agent[gui,rag,code_interpreter,mcp]" ``` #### Основна настройка ```python 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) ``` ### Персонализирано внедряване на функции Можете също така да дефинирате персонализирани функции за Qwen3: ```python 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 #### Контрол на режим на мислене Qwen3 поддържа динамично превключване между мисловен и немисловен режим: ```python # 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 е отличен при свързване на множество извиквания на функции: ```python # 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 needed ``` ## Локална интеграция с Foundry Foundry Local на Microsoft предоставя API, съвместим с OpenAI, за локално изпълнение на модели с подобрена поверителност и производителност. ### Настройка и инсталация #### Windows Изтеглете инсталатора от [страницата с издания на Foundry Local](https://github.com/microsoft/Foundry-Local/releases) и следвайте инструкциите за инсталация. #### macOS ```bash brew tap microsoft/foundrylocal brew install foundrylocal ``` #### Основна употреба ```python import 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) ``` ### Разширени функции на Foundry Local #### Управление на модели ```bash # 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 автоматично избира най-добрия вариант на модела за вашия хардуер: - **CUDA GPU**: Изтегля модели, оптимизирани за GPU - **Qualcomm NPU**: Използва варианти с ускорение от NPU - **Само CPU**: Избира модели, оптимизирани за CPU ## Най-добри практики и отстраняване на проблеми ### Най-добри практики за дефиниране на функции #### 1. Ясно и описателно именуване ```python # Good { "name": "get_stock_price", "description": "Retrieve current stock price for a given symbol" } # Avoid { "name": "get_data", "description": "Gets data" } ``` #### 2. Изчерпателни дефиниции на параметри ```python { "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 } } } ``` #### 3. Валидиране на входа и управление на грешки ```python 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)} ``` ### Чести проблеми и решения #### Проблем 1: Функцията не се извиква **Симптоми**: Моделът отговаря с текст вместо да извика функцията **Решения**: 1. **Проверете описанието на функцията**: Уверете се, че ясно съответства на намерението на потребителя 2. **Проверете дефинициите на параметрите**: Уверете се, че всички необходими параметри са правилно дефинирани 3. **Прегледайте системния промпт**: Включете ясни инструкции кога да се използват функции 4. **Тествайте с явни заявки**: Опитайте "Моля, използвайте функцията за времето, за да получите данни за Лондон" #### Проблем 2: Неправилни параметри **Симптоми**: Функцията се извиква с грешни или липсващи параметри **Решения**: 1. **Добавете примери за параметри**: Включете примерни стойности в описанията на параметрите 2. **Използвайте ограничения за enum**: Ограничете стойностите на параметрите до специфични опции, когато е възможно 3. **Внедрете резервни стойности**: Осигурете разумни стойности по подразбиране за опционални параметри ```python { "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)" } } } ``` #### Проблем 3: Неуспехи при паралелно извикване на функции **Симптоми**: Само една функция се изпълнява, когато трябва да се изпълнят няколко **Решения**: 1. **Проверете поддръжката на модела**: Уверете се, че вашият модел поддържа паралелно извикване на функции 2. **Актуализирайте системния промпт**: Включете "някои инструменти" или "множество инструменти" в системното съобщение 3. **Използвайте подходящи версии на модела**: Препоръчва се Phi-4-mini:3.8b-fp16 за Ollama #### Проблем 4: Проблеми с шаблони в Ollama **Симптоми**: Извикването на функции не работи с настройката по подразбиране на Ollama **Решения**: 1. **Използвайте персонализиран ModelFile**: Приложете коригирания шаблон, предоставен в този урок 2. **Актуализирайте Ollama**: Уверете се, че използвате версия 0.5.13 или по-нова 3. **Проверете квантизацията на модела**: По-високите нива на квантизация (Q8_0, fp16) работят по-добре от силно квантизирани версии ### Оптимизация на производителността #### 1. Ефективен дизайн на функции - **Поддържайте функциите фокусирани**: Всяка функция трябва да има една ясна цел - **Минимизирайте външните зависимости**: Намалете API повикванията и мрежовите заявки, където е възможно - **Кеширайте резултати**: Съхранявайте често заявявани данни за подобряване на времето за отговор #### 2. Групиране и асинхронни операции ```python 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() ``` #### 3. Управление на ресурси - **Пулове за връзки**: Повторно използвайте връзки към бази данни и API - **Ограничаване на скоростта**: Внедрете правилно ограничаване на скоростта за външни API - **Управление на изтичане на времето**: Задайте разумни времеви ограничения за всички външни повиквания ## Разширени примери ### Система за сътрудничество между множество агенти ```python 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()) ``` ### Система за динамичен избор на инструменти ```python 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: """Стандартен формат за резултати от всички извиквания на функции""" success: bool data: Any = None error: str = None execution_time: float = 0.0 timestamp: datetime = None class EnterpriseAIAgent: """Готов за производство AI агент с обширни възможности за извикване на функции""" def __init__(self, config: Dict): self.config = config self.functions = {} self.audit_log = [] self.rate_limiters = {} # Инициализиране на основни бизнес функции self._register_core_functions() def _register_core_functions(self): """Регистриране на всички налични бизнес функции""" # CRM функции self.register_function( name="get_customer_info", description="Извличане на информация за клиент от CRM", parameters={ "customer_id": {"type": "string", "required": True}, "include_history": {"type": "boolean", "default": False} }, handler=self._get_customer_info, rate_limit=100 # повиквания на минута ) # Функции за продажби self.register_function( name="create_sales_opportunity", description="Създаване на нова възможност за продажба", 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 ) # Аналитични функции self.register_function( name="generate_sales_report", description="Генериране на отчет за представянето на продажбите", 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 ) # Функции за уведомления self.register_function( name="send_notification", description="Изпращане на уведомление до членове на екипа", parameters={ "recipients": {"type": "array", "items": {"type": "string"}}, "message": {"type": "string", "required": True}, "priority": {"type": "string", "enum": ["low", "medium", "high"], "default": "medium"}, "channel": {" Моля, предоставете съдържанието на markdown файла, който искате да бъде преведен. """Изпълнение на функция с цялостно управление на грешки и логване""" start_time = datetime.now() try: # Проверка дали функцията съществува if function_name not in self.functions: return FunctionResult( success=False, error=f"Функцията '{function_name}' не е намерена", timestamp=start_time ) # Проверка на ограниченията за честота if not self._check_rate_limit(function_name): return FunctionResult( success=False, error=f"Превишен лимит за честота на функцията '{function_name}'", timestamp=start_time ) # Проверка на параметрите validation_result = self._validate_parameters(function_name, parameters) if not validation_result.success: return validation_result # Изпълнение на функцията 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 ) # Логване на успешно изпълнение 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 ) # Логване на неуспешно изпълнение self._log_function_call(function_name, parameters, result) return result def _check_rate_limit(self, function_name: str) -> bool: """Проверка дали извикването на функцията е в рамките на ограниченията за честота""" func_info = self.functions[function_name] now = datetime.now() # Нулиране на брояча, ако е минала една минута if (now - func_info['last_reset']).seconds >= 60: func_info['call_count'] = 0 func_info['last_reset'] = now # Проверка дали е под лимита 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: """Проверка на параметрите на функцията""" func_params = self.functions[function_name]['parameters'] # Проверка на задължителните параметри 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"Липсва задължителен параметър: {param_name}" ) # Проверка на типовете и ограниченията на параметрите for param_name, value in parameters.items(): if param_name in func_params: param_info = func_params[param_name] # Проверка на типа expected_type = param_info.get('type') if expected_type == 'string' and not isinstance(value, str): return FunctionResult( success=False, error=f"Параметърът '{param_name}' трябва да бъде низ" ) elif expected_type == 'number' and not isinstance(value, (int, float)): return FunctionResult( success=False, error=f"Параметърът '{param_name}' трябва да бъде число" ) elif expected_type == 'boolean' and not isinstance(value, bool): return FunctionResult( success=False, error=f"Параметърът '{param_name}' трябва да бъде булев" ) # Проверка на стойностите в enum if 'enum' in param_info and value not in param_info['enum']: return FunctionResult( success=False, error=f"Параметърът '{param_name}' трябва да бъде един от: {param_info['enum']}" ) return FunctionResult(success=True) def _log_function_call(self, function_name: str, parameters: Dict, result: FunctionResult): """Логване на извикване на функция за одитни цели""" 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) # Опционално записване във външна система за логване if self.config.get('enable_external_logging', False): self._write_to_external_log(log_entry) def _write_to_external_log(self, log_entry: Dict): """Записване на лог във външна система за логване""" # Имплементацията зависи от вашата инфраструктура за логване # напр. изпращане към ELK stack, CloudWatch и др. pass # Имплементации на бизнес функции async def _get_customer_info(self, customer_id: str, include_history: bool = False) -> Dict: """Извличане на информация за клиент от CRM система""" # Симулиране на заявка към база данни/API await asyncio.sleep(0.1) # Симулиране на мрежово забавяне 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': 'Product A', 'amount': 1500}, {'date': '2024-03-22', 'product': 'Product 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: """Създаване на нова продажбена възможност""" # Симулиране на заявка към CRM API 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: """Генериране на подробен отчет за продажбите""" # Симулиране на агрегиране на данни 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: """Изпращане на известие чрез избрания канал""" # Симулиране на заявка към услуга за известия 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]: """Получаване на дефиниции на функции, съвместими с OpenAI, за всички регистрирани функции""" 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 # Пример за използване за корпоративна интеграция async def enterprise_demo(): """Демонстрация на възможностите на корпоративен AI агент""" config = { 'enable_external_logging': True, 'max_concurrent_functions': 10, 'default_timeout': 30 } agent = EnterpriseAIAgent(config) # Пример 1: Обработка на клиентски запитвания print("=== Обработка на клиентски запитвания ===") # Получаване на информация за клиент result = await agent.execute_function( 'get_customer_info', {'customer_id': 'CUST-12345', 'include_history': True} ) if result.success: print(f"Информация за клиента е получена: {result.data['name']}") print(f"Време за изпълнение: {result.execution_time:.3f}s") # Пример 2: Създаване на продажбена възможност print("\n=== Създаване на продажбена възможност ===") 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"Възможността е създадена: {result.data['opportunity_id']}") # Пример 3: Партидни операции print("\n=== Партидни операции ===") tasks = [ agent.execute_function('generate_sales_report', {'period': 'monthly'}), agent.execute_function('send_notification', { 'recipients': ['manager@company.com'], 'message': 'Създадена е нова възможност', 'priority': 'high', 'channel': 'email' }) ] results = await asyncio.gather(*tasks) for i, result in enumerate(results): if result.success: print(f"Задача {i+1} е изпълнена успешно") else: print(f"Задача {i+1} неуспешна: {result.error}") # Показване на одитния лог print(f"\n=== Одитен лог ({len(agent.audit_log)} записа) ===") for entry in agent.audit_log[-3:]: # Показване на последните 3 записа print(f"{entry['timestamp']}: {entry['function_name']} - {'УСПЕХ' if entry['success'] else 'НЕУСПЕХ'}") # Изпълнение на корпоративната демонстрация # asyncio.run(enterprise_demo()) - **Phi-4 Модели**: [Hugging Face Колекция](https://huggingface.co/collections/microsoft/phi-4-677e9380e514feb5577a40e4) - **Qwen3 Документация**: [Официална Qwen Документация](https://qwen.readthedocs.io/) - **Ollama**: [Официален Уебсайт](https://ollama.com/) - **Foundry Local**: [GitHub Репозитори](https://github.com/microsoft/Foundry-Local) - **Най-добри практики за извикване на функции**: [Hugging Face Ръководство](https://huggingface.co/docs/hugs/en/guides/function-calling) Запомнете, че извикването на функции е развиваща се област, и следенето на последните новости във вашите избрани рамки и модели ще ви помогне да изграждате по-ефективни AI агенти. ## ➡️ Какво следва - [03: Интеграция на Протокол за Контекст на Модела (MCP)](./03.IntroduceMCP.md) --- **Отказ от отговорност**: Този документ е преведен с помощта на AI услуга за превод [Co-op Translator](https://github.com/Azure/co-op-translator). Въпреки че се стремим към точност, моля, имайте предвид, че автоматизираните преводи може да съдържат грешки или неточности. Оригиналният документ на неговия роден език трябва да се счита за авторитетен източник. За критична информация се препоръчва професионален човешки превод. Ние не носим отговорност за недоразумения или погрешни интерпретации, произтичащи от използването на този превод.