Llama-3 Func Calling – Hamel’s Blog - Hamel Husain
Hamel Husain показывает, как использовать вызов функций (function calling) с моделью Llama-3 70B Instruct через инференс-API Replicate. В заметке приводится вспомогательный код для парсинга ответа с тегами <function-call> и <answer>, а также утилита для превращения Python-функций в JSON-схему (заимствованная из fastai/llm-hackers). Демонстрируются два инструмента: get_exchange_rate и create_contact. На нескольких сценариях показано поведение модели: когда инструмент не нужен (с предоставленными tools и без них), когда инструмент требуется и есть все параметры, и когда модели не хватает данных и она запрашивает их у пользователя. Полный код инференса с промптом доступен в репозитории replicate-examples автора.
Setup
Настройка
import replicate from pydantic import create_model import inspect, json, re from inspect import Parameter from fastcore.foundation import L from functools import partial from pprint import pprint
import replicate from pydantic import create_model import inspect, json, re from inspect import Parameter from fastcore.foundation import L from functools import partial from pprint import pprint
The following collapsible element contains helper functions for the Replicate inference API and parsing the response:
Следующий сворачиваемый блок содержит вспомогательные функции для инференс-API Replicate и парсинга ответа:
def parse(text): """Use regular expressions to find content within the tags.""" function_call_search = re.search(r"<function-call>\s*(.*?)\s*</function-call>", text, re.DOTALL) answer_search = re.search(r"<answer>\s*(.*?)\s*</answer>", text, re.DOTALL) function_call = function_call_search.group(1).strip() if function_call_search else None answer = answer_search.group(1).strip() if answer_search else None if function_call and function_call != "None": return {"type": "function-call", "content": function_call} elif answer: return {"type": "text", "content": answer} else: return {"type": "text", "content": text} def run(prompt:str, tools:str=None): inp = {"prompt": f"{prompt}", "temperature": 0} if tools: inp['tools'] = tools output = replicate.run( "hamelsmu/llama-3-70b-instruct-awq-with-tools:b6042c085a7927a3d87e065a9f51fb7238ef6870c7a2ab7b03caa3c0e9413e19", input=inp ) txt = ''.join(output) return parse(txt)
def parse(text): """Используем регулярные выражения, чтобы найти содержимое внутри тегов.""" function_call_search = re.search(r"
A helper to help turn functions into a schema from fastai/llm-hackers
Вспомогательная функция, превращающая функции в схему — из fastai/llm-hackers
def schema(f): kw = {n:(o.annotation, ... if o.default==Parameter.empty else o.default) for n,o in inspect.signature(f).parameters.items()} s = create_model(f'Input for `{f.__name__}`', **kw).schema() return dict(name=f.__name__, description=f.__doc__, parameters=s)
def schema(f): kw = {n:(o.annotation, ... if o.default==Parameter.empty else o.default) for n,o in inspect.signature(f).parameters.items()} s = create_model(f'Input for `{f.__name__}`', **kw).schema() return dict(name=f.__name__, description=f.__doc__, parameters=s)
Lets define two tools:
Определим два инструмента:
def get_exchange_rate(base_currency:str, target_currency:str): """ Get the exchange rate between two currencies. Parameters: - base_currency (str): The currency to convert from. - target_currency (str): The currency to convert to. Returns: float: The exchange rate from base_currency to target_currency. """ ... def create_contact(name:str, email:str): """ Create a new contact. Parameters: - name (str): The name of the contact. - email (str): The email address of the contact. Returns: dict: Confirmation of the created contact. """ ... tools = json.dumps(list(L([get_exchange_rate, create_contact]).map(schema)))
def get_exchange_rate(base_currency:str, target_currency:str): """ Получить обменный курс между двумя валютами. Параметры: - base_currency (str): Валюта, из которой производится конвертация. - target_currency (str): Валюта, в которую производится конвертация. Возвращает: float: Обменный курс из base_currency в target_currency. """ ... def create_contact(name:str, email:str): """ Создать новый контакт. Параметры: - name (str): Имя контакта. - email (str): Адрес электронной почты контакта. Возвращает: dict: Подтверждение создания контакта. """ ... tools = json.dumps(list(L([get_exchange_rate, create_contact]).map(schema)))
The Demo
Демонстрация
Scenario 1A: No tool required to answer question
Сценарий 1A: Для ответа на вопрос инструмент не нужен
even though tool is provided
даже если инструмент предоставлен
o1a = run(prompt="Write a very short sentence about SEO.", tools=tools) pprint(o1a)
o1a = run(prompt="Write a very short sentence about SEO.", tools=tools) pprint(o1a)
{'content': 'Search Engine Optimization (SEO) is crucial for online ' 'visibility.', 'type': 'text'}
{'content': 'Search Engine Optimization (SEO) is crucial for online ' 'visibility.', 'type': 'text'}
Scenario 1B: No tool required to answer question
Сценарий 1B: Для ответа на вопрос инструмент не нужен
no tools are provided
инструменты не предоставлены
o1b = run(prompt="Write a very short sentence about SEO.", tools=None) pprint(o1b)
o1b = run(prompt="Write a very short sentence about SEO.", tools=None) pprint(o1b)
{'content': 'Here is a very short sentence about SEO:\n' '\n' '"Optimizing website content with relevant keywords improves ' 'search engine rankings."', 'type': 'text'}
{'content': 'Here is a very short sentence about SEO:\n' '\n' '"Optimizing website content with relevant keywords improves ' 'search engine rankings."', 'type': 'text'}
Scenario 2: Tool is reqiured to answer question
Сценарий 2: Для ответа на вопрос требуется инструмент
o2 = run(prompt="How many Japenese Yen are there in 1000 USD?", tools=tools) pprint(o2)
o2 = run(prompt="How many Japenese Yen are there in 1000 USD?", tools=tools) pprint(o2)
{'content': 'get_exchange_rate(base_currency="USD", target_currency="JPY")', 'type': 'function-call'}
{'content': 'get_exchange_rate(base_currency="USD", target_currency="JPY")', 'type': 'function-call'}
Scenario 3A: Tool reqiured but not enough info in the prompt for the params
Сценарий 3A: Инструмент нужен, но в промпте недостаточно информации для параметров
o3a = run(prompt="Can you help me add a Hamel Husain to my address book?", tools=tools) pprint(o3a)
o3a = run(prompt="Can you help me add a Hamel Husain to my address book?", tools=tools) pprint(o3a)
{'content': "I'd be happy to help you add Hamel Husain to your address book! " 'However, I need more information from you. Could you please ' "provide Hamel's email address? Once I have that, I can assist you " 'in adding the contact.', 'type': 'text'}
{'content': "I'd be happy to help you add Hamel Husain to your address book! " 'However, I need more information from you. Could you please ' "provide Hamel's email address? Once I have that, I can assist you " 'in adding the contact.', 'type': 'text'}
Scenario 3B: Tool required, there is enough info in the prompt
Сценарий 3B: Инструмент нужен, и в промпте достаточно информации
o3b = run(prompt="Can you help me add a Hamel Husain to my address book?\ His email address is h@fmail.com", tools=tools) pprint(o3b)
o3b = run(prompt="Can you help me add a Hamel Husain to my address book?\ His email address is h@fmail.com", tools=tools) pprint(o3b)
{'content': 'create_contact(name="Hamel Husain", email="h@fmail.com")', 'type': 'function-call'}
{'content': 'create_contact(name="Hamel Husain", email="h@fmail.com")', 'type': 'function-call'}