OpenAI недавно представила интересное дополнение к OpenAI Completions API — вызов функций. Эта функция позволяет разработчикам определять функции в формате JSON, к которым модель может обращаться, когда для выполнения запроса необходимы дополнительные внешние операции.

Эта возможность открывает множество функций, в том числе:

  • Доступ к информации в режиме реального времени, такой как прогнозы погоды, финансовые данные и новости
  • Хранение и выполнение кода
  • Доступ к данным через SQL-запросы или службы REST
  • Управление IoT-устройствами

Рабочий процесс высокого уровня функции вызова функции в Completions API выглядит следующим образом:

  1. Пользователь делает запрос.
  2. Процессор сообщений (код приложения) преобразует этот запрос в подсказку сообщения. Он также добавляет к приглашению список поддерживаемых функций (таких как «веб-поиск» или «выполнение команды ОС»).
  3. Это приглашение сообщения затем отправляется в Completions API. Если модель ИИ определяет, что для выполнения запроса ей нужна дополнительная информация, она проверяет список предоставляемых поддерживаемых функций. Если он находит соответствующую функцию, он возвращает запрос на выполнение этой функции вместе с необходимыми параметрами.
  4. Получив этот запрос функции, процессор сообщений использует соответствующие обработчики для выполнения функции.
  5. Затем результаты выполнения функции и исходный запрос отправляются обратно в Completions API.
  6. Затем Completions API использует эту информацию для формулирования ответа на исходный запрос пользователя.
  7. Наконец, этот ответ отправляется обратно пользователю».

Хотя некоторые из этих функций доступны через ChatGPT и плагины, настоящим переломным моментом является возможность создания автономных приложений, использующих эти мощные возможности.

Определение функций

funcDef = {
    "name": "file_save",
    "description": "save code or text into a file",
    "parameters": {
        "type": "object",
        "properties": {
            "directory_path": {
                "type": "string",
                "description": "the location of the file to be saved",
            },
            "file_name": {
                "type": "string",
                "description": "the name of the file to be saved",
            },
            "file_content": {
                "type": "string",
                "description": "the content of the file to be saved",
            },
        },
        "required": ["directory_path", "file_name", "file_content"],
    },
}

Давайте рассмотрим пример определения функции для сохранения текста в файл:

Определение описывает функцию, модель использует его при сопоставлении функций с некоторой потребностью в имеющейся у нее информации.

В определении перечислены и описаны параметры, необходимые для выполнения функции.

Затем набор определений функций может быть передан в API при выполнении запроса, что позволяет модели сохранять текст и код в локальной файловой системе.

Вызов API завершения

Помимо выбора версий модели, которые поддерживают вызов функций, основное отличие заключается в том, что набор определений функций отправляется в API через параметр functions, как показано ниже:

def get_completionWithFunctions(messages ,functions:str, temperature:int=0, model:str="gpt-3.5-turbo-0613", max_retries:int=3, retry_wait:int=1):
    logging.info(f'get_completionWithFunctions start: model {model} functions {functions} messages {messages}')

    retries = 0
    while retries <= max_retries:
        try:
            response = openai.ChatCompletion.create(
                model=model,
                messages=messages,
                functions=functions,
                function_call = "auto", 
                temperature=temperature, 
            )
            logging.info(f'get_completion end: {model}')
            response_message = response["choices"][0]["message"]
            return response_message
            
        except RateLimitError as e:
            if retries == max_retries:
                raise e
            retries += 1
            print(f"RateLimitError encountered, retrying... (attempt {retries})")
            time.sleep(retry_wait)

Обработка запроса пользователя

Когда модель обрабатывает запрос пользователя, требующий дополнительной информации, она использует предоставленный список функций.

Если запрос пользователя «напишите код Python для вычисления первых N простых чисел и сохраните код в файле primes.py», модель может сгенерировать код и, зная о функции «file_save», ответить запросом на сохранение файл.

Код, который вызывает метод get_completionWithFunctions(), затем проверяет ответ на запрос вызова функции:

function_calling_definition = self.handler.get_function_calling_definition()

        max_iterations = 5
        itr = 0
        for i in range(max_iterations):

            #completion_messages = [{"role": "user", "content": message}]
            #default is gpt-3.5-turbo-0613  you can alos use gpt-4-0613
            response_message = get_completionWithFunctions(completion_messages, function_calling_definition, 0, model)

            #check if a function call is requested
            if response_message.get("function_call"):
                action = []
                function_name = response_message["function_call"]["name"]
                function_args_text = response_message["function_call"]["arguments"]
                function_args = json.loads(function_args_text)

                #extract the paramters and nane of the function reqested
                action_dict = dict()
                action_dict["action_name"] = function_name
                for key, value in function_args.items():
                    action_dict[key] = value

                #execute the function if available
                response = self.handler.process_action_dict(action_dict, account_name)
                response_message_text = QuokkaLoki.handler_repsonse_formated_text(response)

                completion_messages.append(response_message)
                completion_messages.append(
                    {
                        "role": "function",
                        "name": function_name,
                        "content": response_message_text,
                    }
                )
            else:
                break

В приведенном выше примере причудливо названный QuokkaLoki() имеет разные обработчики для поддержки различных запросов, таких как загрузка файла, сохранение файла, выполнение команды, просмотр веб-страниц и веб-поиск. Каждый обработчик сам описывает функцию, которую он предоставляет, тем самым расширяя гибкость и полезность ваших приложений на основе ИИ.

В проекте, над которым я работаю, мы используем вызов функции в цикле, потому что один запрос пользователя может привести к нескольким вызовам. Рассмотрим пример «пожалуйста, просмотрите код HelloWorld.vue в src/sandbox/ вне домашнего каталога, а затем сохраните обзор кода в review.txt». В этом случае один запрос приводит к двум запросам функций.

Пример

В приведенном выше примере пользователь сначала запрашивает у помощника пять лучших ETF для выхода на пенсию. Помощник отвечает списком ETF с краткими описаниями для каждого. Это взаимодействие демонстрирует способность ассистента генерировать информацию из уже существующей базы знаний.

Разговор развивается по мере того, как пользователь запрашивает дополнительную информацию о конкретном ETF, Vanguard Dividend Appreciation ETF (VIG). Помощник отвечает, извлекая дополнительную информацию о VIG, а также предоставляет пользователю список веб-источников для дальнейшего изучения. Это представляет собой функцию помощника «веб-поиск», демонстрирующую его способность находить и представлять полезные, релевантные онлайн-ресурсы.

Наконец, пользователь просит помощника получить текст по одной из предоставленных ссылок. Помощник извлекает и представляет текстовую выдержку из указанной ссылки MarketWatch о VIG ETF. Это действие демонстрирует возможности помощника по очистке веб-страниц, демонстрируя его способность извлекать информацию непосредственно с веб-страниц.

В целом, этот пример выделяет две ключевые возможности, которые становятся возможными благодаря вызову функции: веб-поиск в реальном времени и просмотр веб-текста. Эти функции позволяют ИИ не только генерировать ответы на основе своих обучающих данных, но также извлекать и представлять в режиме реального времени актуальную информацию из Интернета, что делает его очень динамичным и мощным инструментом для пользователей.

Помните, что вызов функций позволяет вам расширить возможности ваших приложений на основе ИИ за пределы обучающих данных модели. С помощью вызова функций ваш помощник может взаимодействовать с различными внешними системами и службами, предоставляя пользователям динамические ответы в реальном времени.

Чтобы продемонстрировать эти возможности и предоставить практическое руководство для разработчиков, стремящихся использовать эту мощную функцию, давайте рассмотрим инновационный проект под названием «Люси».

Люси

«Люси» — это инновационный проект, предназначенный для экспериментов и использования возможностей API автодополнения OpenAI. Проект направлен на управление разговорным поведением и автоматизацию процессов с помощью этой технологии.

Функции

  1. Агенты. Они управляют поведением проекта, обеспечивая простые чаты, управляемые беседы, автоматизацию и вызов функций.
  2. Создание подсказок. Эта функция расширяет подсказки на основе запросов пользователей. Он учитывает долгосрочную актуальность, последние тенденции или сочетание того и другого для создания набора сообщений, которые можно использовать с API-интерфейсом завершения.
  3. Завершения. Этот компонент сохраняет и извлекает завершения и сообщения из чатов на основе учетных записей агентов и пользователей. Он также хранит системные роли для агента на основе имени агента.
  4. Обработчики сообщений. Они обрабатывают входящие сообщения и поддерживают создание подсказок, предустановки, управляемые диалоги, вызов функций и автоматизацию.
  5. Обработчики. Они используются автоматизацией и вызовами функций для поддержки запросов, сделанных моделью или агентами. Они обрабатывают загрузку файлов, сохранение файлов, веб-поиск и загрузку веб-страниц.
  6. Чанкеры. Это инструменты для фрагментации текста при загрузке большого текстового файла с веб-страницы. Он обрабатывает файл фрагментами.
  7. Контекст: это хранилище информации, которое может использоваться совместно с различными агентами. Он используется, когда несколько агентов помогают обработать запрос пользователя, например, в управляемом разговоре или автоматизации.

Рабочий процесс

В «Люси» вышеупомянутые функции эффективно взаимодействуют для управления и автоматизации диалогового поведения. Построитель подсказок обогащает пользовательский запрос, который функция завершения сохраняет и вызывает по мере необходимости. Процессоры сообщений обрабатывают входящие сообщения, а обработчики еще больше расширяют эти возможности. Чанкеры обрабатывают большие данные, а контекст служит общим хранилищем информации.

Ссылка на проект

Примеры кода, опубликованные в этом сообщении блога, основаны на проекте «Люси», и вы можете изучить полную кодовую базу по предоставленной ссылке на GitHub. Это даст вам практическое понимание того, как реализовать и использовать функцию вызова функций в API автодополнения OpenAI для создания мощных, интерактивных и динамичных приложений ИИ.

Подробнее о проекте можно узнать по ссылке: https://github.com/junwin/lucy