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

Поэтому в качестве обходного пути люди создали несколько плагинов или используют сторонние библиотеки, такие как langchain, для подключения LLM к пользовательским источникам данных.

Что ж, OpenAI, наконец, решил эту проблему, предоставив разработчикам возможность вызывать пользовательские функции непосредственно в библиотеке OpenAI. Новые модели gpt-3.5-turbo-0613 и gpt-4–0613 были точно настроены, чтобы определять не только то, какую пользовательскую функцию вызывать, но и то, с какими параметрами она должна вызывать эту функцию.

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

Давайте начнем!

Установите необходимые зависимости Python

pip install openai
pip install yfinance

Создание нашей пользовательской функции

Вот что будет делать функция:

  • Используйте Yahoo Finance API для извлечения информации об акциях
  • Найдите целевую цену акции
  • Возвращает низкие, средние и высокие ценовые цели

Примечание. Целевая цена акции — это расчетная будущая цена акции, рассчитанная аналитиками

import yfinance as yf
import openai
import json
openai.api_key = "YOUR-OPENAI-API-KEY"

def get_stock_price_target(ticker: str):
    ticker_info = yf.Ticker(ticker).info
    current_price = ticker_info.get('currentPrice')
    target_low = ticker_info.get('targetLowPrice')
    target_mid = ticker_info.get('targetMedianPrice')
    target_high = ticker_info.get('targetHighPrice')
    return {"current_price": current_price, "target_low": target_low, "target_mid": target_mid, "target_high": target_high}

Эта функция принимает биржевой символ в качестве аргумента и возвращает выходные данные JSON, содержащие различные целевые цены. Например, если вы хотите получить целевую цену акций Apple, вы должны вызвать функцию следующим образом: get_stock_price_target('AAPL')

Подготовка нашей пользовательской функции

Несмотря на название вызов функции, ChatGPT на самом деле не вызывает нашу функцию. Вместо этого он создает объект JSON с аргументами для этой функции. Код нашего приложения будет отвечать за выполнение функции на основе сгенерированного объекта JSON.

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

functions = [
    {
        "name": "get_stock_price_target",
        "description": "Use this function to get the price target for a stock. The output will be in JSON format.",
        "parameters": {
            "type": "object",
            "properties": {
                "ticker": {
                    "type": "string",
                    "description": "The ticker symbol for the stock, e.g. GOOG",
                }
            },
            "required": ["ticker"],
        },
    }
]

Интеграция нашей пользовательской функции с ChatGPT

def ask_question(question: str):
    # First API call
    messages = [{"role": "user", "content": question}]
    response = openai.ChatCompletion.create(
        model="gpt-3.5-turbo-0613",
        messages=messages,
        functions=functions,
        function_call="auto",
    )
    response_message = response["choices"][0]["message"]
    # Figure out which function to call
    if response_message.get("function_call"):
        available_functions = {
            "get_stock_price_target": get_stock_price_target
        }
        function_name = response_message["function_call"]["name"]
        function_to_call = available_functions[function_name]
        function_args = json.loads(response_message["function_call"]["arguments"])
        # Call the user defined function
        function_response = function_to_call(
            ticker=function_args.get('ticker')
        )
        function_response = str(function_response)
        messages.append(response_message)
        # Add the data from the function so chatGPT has that in its history
        messages.append(
            {
                "role": "function",
                "name": function_name,
                "content": function_response,
            }
        )
        # Second API call to answer the users question based on the data retrieved from the custom function
        second_response = openai.ChatCompletion.create(
            model="gpt-3.5-turbo-0613",
            messages=messages,
        )
        answer = second_response['choices'][0]['message']['content']
        return answer

Вызов функции работает путем двойного вызова API ChatGPT:

  • Во-первых, мы передаем functions внутри метода ChatCompletion.create
  • При первом вызове API ChatGPT определяет, какую функцию с какими параметрами вызывать. Он вернет объект JSON, подобный следующему:
{
  "content": null,
  "function_call": {
    "arguments": "{\n\"ticker\": \"AAPL\"\n}",
    "name": "get_stock_price_target"
  },
  "role": "assistant"
}
  • Далее наш код должен вручную вызвать функцию, которую мы получаем из объекта JSON. Мы берем ответ от нашей функции и добавляем его в messages, который представляет собой список для отслеживания истории нашего чата.
  • Теперь, когда у нас есть информация о целевой цене внутри нашего messages, мы можем сделать второй вызов API. На этот раз у ChatGPT есть данные, необходимые для ответа на наш вопрос.

Давайте протестируем наш код:

response = ask_question("What is the price target for MSFT?")
print(response)

Выход:

The price target for MSFT (Microsoft Corporation) is as follows:

- Target Low: $232.00
- Target Mid: $340.00
- Target High: $400.00

Успех! ChatGPT смог вызвать нужную функцию с правильными параметрами и вернуть ответ!

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

Создание другой функции

Для этой функции мы будем хранить информацию о целевой цене в базе данных SQLite и вычислять потенциальную доходность для данной акции.

Шаг 1. Заполните базу данных

import sqlite3

def create_sample_database():
    con = sqlite3.connect("tutorial.db")
    cur = con.cursor()
    cur.execute("CREATE TABLE stocks(ticker TEXT, current_price REAL, target_low REAL, target_mid REAL, target_high REAL)")
    sample_tickers = ['AAPL', 'GOOG', 'NVDA', 'ABNB', 'TSLA', 'AMZN', 'MSFT']
    for ticker in sample_tickers:
        price_target = get_stock_price_target(ticker)
        current_price = price_target.get('current_price')
        target_low = price_target.get('target_low')
        target_mid = price_target.get('target_mid')
        target_high = price_target.get('target_high')

        query = ''' INSERT INTO stocks(ticker, current_price, target_low, target_mid, target_high)
                      VALUES(?, ?, ?, ?, ?) '''
        values = (ticker, current_price, target_low, target_mid, target_high)
        cur.execute(query, values)
        con.commit()

    print("Database created successfully!")

Что тут происходит:

  • Сначала мы подключаемся к нашей базе данных SQLite.
  • Мы создаем таблицу с именем stocks, которая содержит пять столбцов (тикер, текущая_цена, target_low, target_mid, target_high).
  • Мы просматриваем список популярных биржевых тикеров и получаем информацию о целевой цене для каждого тикера.
  • Мы вставляем информацию, полученную на предыдущем шаге, в нашу базу данных SQLite.

Шаг 2. Рассчитайте ожидаемую прибыль

def get_expected_returns_for_stock(ticker: str):
    con = sqlite3.connect("tutorial.db")
    cur = con.cursor()
    try:
        cur.execute("SELECT * FROM stocks WHERE ticker=?", (ticker,))
        rows = cur.fetchall()
        if len(rows) == 1:
            current_price = rows[0][1]
            target_mid = rows[0][3]
            target_high = rows[0][4]

            average_upside = ((target_mid - current_price) / current_price) * 100
            high_upside = ((target_high - current_price) / current_price) * 100
            average_upside = round(average_upside, 2)
            high_upside = round(high_upside, 2)

            return {"average_upside": f"{average_upside}%", "high_upside": f"{high_upside}%"}

        else:
            return {"average_upside": "N/A", "high_upside": "N/A"}

    except Exception as e:
        print(e)
    finally:
        cur.close()
        con.close()

Что тут происходит:

  • Во-первых, мы находим ценовые цели с учетом тикера.
  • Затем мы рассчитываем потенциальную доходность акции. average_upside — это средний ожидаемый доход, а high_upside — это самый высокий доход, который мы можем получить на основе анализа аналитика.
  • Мы возвращаем две потенциальные доходности в виде процентного значения.

Запустите две функции следующим образом:

# Populate the database
create_sample_database() # Only run this once!

# Get the expected returns
output = get_expected_returns_for_stock('MSFT')
print(output)

Вот результат, который вы должны увидеть:

{'average_upside': '1.62%', 'high_upside': '19.56%'}

Добавляем нашу вторую функцию в ChatGPT

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

Обновите переменную functions до этого объекта JSON, поскольку теперь у нас есть две функции:

functions = [
    {
        "name": "get_expected_returns_for_stock",
        "description": "Use this function to get the expected return for a stock. The output will be in JSON format.",
        "parameters": {
            "type": "object",
            "properties": {
                "ticker": {
                    "type": "string",
                    "description": "The ticker symbol for the stock, e.g. GOOG",
                }
            },
            "required": ["ticker"],
        },
    },
    {
        "name": "get_stock_price_target",
        "description": "Use this function to get the price target for a stock. The output will be in JSON format.",
        "parameters": {
            "type": "object",
            "properties": {
                "ticker": {
                    "type": "string",
                    "description": "The ticker symbol for the stock, e.g. GOOG",
                }
            },
            "required": ["ticker"],
        },
    }
]

В нашей функции ask_question. Обновите переменную available_functions до:

available_functions = {
    "get_stock_price_target": get_stock_price_target,
    "get_expected_returns_for_stock": get_expected_returns_for_stock
}

С этим небольшим изменением мы можем снова протестировать наш код:

response = ask_question("What is expected return for TSLA stock?")
print(response)

Вот что я получил:

The expected return for TSLA (Tesla Inc.) stock is an average upside of -16.07%. 
However, there is also a potential high upside of 33.89%. 
Please note that these figures are based on historical data and future returns may vary.

Потрясающий! ChatGPT может определить, когда звонить get_expected_returns_for_stock, а когда get_stock_price_target, просто основываясь на вопросе, который задает пользователь.

Заключение

Подключив ChatGPT к пользовательским функциям, разработчики могут получить гораздо больше пользы, используя LLM, не полагаясь на сторонние библиотеки.

Однако эта технология не идеальна, поскольку вам приходится выполнять несколько вызовов API, что делает приложение дорогостоящим и медленным. Вызов функции в настоящее время доступен только для некоторых моделей OpenAI и несовместим с другими LLM.

При этом общее направление, в котором мы движемся, кажется правильным. Истинная мощь LLM будет раскрыта только тогда, когда мы сможем беспрепятственно подключить несколько источников данных к этим моделям.

Надеюсь, вам понравилась эта история.

Спасибо за прочтение!

Повышение уровня кодирования

Спасибо, что являетесь частью нашего сообщества! Перед тем, как ты уйдешь:

🔔 Подписывайтесь на нас: Twitter | ЛинкедИн | "Новостная рассылка"

🚀👉 Присоединяйтесь к коллективу талантов Level Up и найдите прекрасную работу