— Если я продаю велосипеды, будет ли релевантным для моей рекламной кампании в Google Ads слово «маунтин байк»? Ответь только «Да» или «Нет»

— Да

При создании ключевых слов в Google Ads я предпочитаю подход, когда за базовое ядро берутся ключевые слов полученные в рамках исследования, а не генерации. Поэтому до использования ChatGPT в качестве генератора ключевых слов я пока я пока не добрался. А вот автоматический анализ меня заинтересовал сильнее.

Представьте себе — вам надо поддерживать мониторинг «здоровья» 10-20 рекламных аккаунтов, ведущихся на разных языках, по несколько рекламных кампаний в каждом. Вариант с ручным добавлением релевантных ключевых слов отпадает практически сразу.

За годы работы я разработал несколько методик по автоматическому добавлению ключевых слов в работающие поисковые кампании:

  • Создание ключевых слов из поисковых запросов
  • Расширение ядра за счет автоматического парсинга поисковых подсказок
  • Автоматическая загрузка ключевых слов конкурентов выявленных в рамках исследования Auction Insights
  • Майнинг новых фраз в обычные кампании из DSA кампаний
  • И т.д. и т.п.

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

То есть добавление было автоматическим, а старт и использования — нет. Что в свою очередь может негативно сказываться на оценке релевантности уже активных ключевых слов со стороны Google Ads и вести к уменьшению показов, если по какой-либо причине такие фразы долго не запускаются или не удаляются человеком.

В попытке исправить эту ситуацию и хотя бы частично переложить обязанности модерации на скрипты я решил использовать для этих целей ChatGPT.

Логика в общем-то была довольно несложная. Нам надо запросить у ИИ какую-то оценку релевантности (и т.п.) ключевого слова к тематике бизнеса, рекламной кампании, или группы объявлений. И ответы ИИ должны быть максимально бинарные — хорошо\плохо.

Я сделал два ярлыка:

  1. GPT_YES — для ключевых фраз которые ChatGPT оценит как релевантные, и
  2. GPT_NO — для ключевых фраз которые ChatGPT оценит как не-релевантные

Далее мы ставим скрипт на регулярное исполнение и оценку ВСЕХ ключевых фраз, даже тех которые уже активны.

Выглядит это вот так:

function account() {

    Logger.log(`${get_account_name()} - Start`);

    ensureAccountLabels();

    let labels_arr = [];
    let labelSelector = AdsApp.labels()
        .withCondition("label.name LIKE 'GPT_%'");
        let labelIterator = labelSelector.get();
    while (labelIterator.hasNext()) {
        let label = labelIterator.next();
        labels_arr.push(`'${label.getResourceName()}'`);
    }
    let labels_str = labels_arr.join(',');
    Logger.log(labels_str);
    var campaignSelector = AdsApp
        .campaigns()
        .withCondition("campaign.name LIKE '%Generic%'");
        let campaignIterator = campaignSelector.get();
    while (campaignIterator.hasNext()) {
        let campaign = campaignIterator.next();
        let keywordSelector = campaign
            .keywords()
            .withCondition(`ad_group_criterion.labels CONTAINS NONE (${labels_str})`)
            .withCondition("ad_group_criterion.status != REMOVED")
            .withLimit(50)
            .orderBy("metrics.cost_micros DESC");
            let keywordIterator = keywordSelector.get();
        while (keywordIterator.hasNext()) {
            let keyword = keywordIterator.next();
            let text = keyword.getText();
            let prompt = create_prompt(text);
            let response = gpt4(prompt);
            if (response.indexOf('Yes') > -1) {
                keyword.applyLabel('GPT_YES')
            }
            if (response.indexOf('No') > -1) {
                keyword.applyLabel('GPT_NO')
            }
            Logger.log(`${text} => ${response}`);
        }
    }

    Logger.log(`${get_account_name()} - Finish`);
}

Получив фразы еще не помеченные ярлыками мы генерируем для них промт, и задаем вопрос ChatGPT.

Промт генерируется вот так:

function create_prompt(key) {
    let str = `My company is a %%%online store%%%.
    We advertise in Google Ads to attract people interested in %%%buy shirts%%%.
    Do you think the "${key}" is a good target keyword for us?
    Answer only “Yes” or “No”.`;
    return str;
}

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

Ну и обращаемся с этим вопросом к OpenAI:

function gpt4(prompt) {

    let messages = [{
        "role": "user",
        "content": prompt
    }];

    // Call the OpenAI GPT-3 API with the messages array to get a response.
    let response = callAPI(messages);

    // Return the GPT-3 response.
    return response;
}

function callAPI(messages) {
    Utilities.sleep(2000);
    // Create data object to send to API
    let data = {
        'model': 'gpt-4',
        'messages': messages,
    };

    // Set options for UrlFetchApp
    let options = {
        'method': 'post',
        'contentType': 'application/json',
        'payload': JSON.stringify(data),
        'headers': {
            Authorization: 'Bearer ' + config().openai_apikey,
        },
        muteHttpExceptions: true
    };

    // Fetch response from API using UrlFetchApp
    let response = UrlFetchApp.fetch(
        'https://api.openai.com/v1/chat/completions',
        options,
    );

    // Log the response content
    // Logger.log(response.getContentText());

    // Check if there is an error in the response
    if (JSON.parse(response.getContentText()).error?.message != undefined) {
        // Return the error message
        return JSON.parse(response.getContentText())['error']['message'];
    } else {
        // Return the response from the API
        return JSON.parse(response.getContentText())['choices'][0]['message']['content'].replace(/^\n\n/, '');
    }
}

Далее ждем какое=то время пока скрипт переметит ярлыками ключевые фразы.

Теперь мы можем проверить — насколько адекватна оценка ChatGPT. Нам остается только построить отчет по ярлыкам, добавив него интересующие нас показатели — ctr, cpc, cpa, conversion rate и т.д.

LabelImpressionsClicksCtrCost Per ClickConversion RateCost Per Conversion
GPT_YES— 1— 1— %— $— %— $
GPT_NO— 1— 1— %— $— %— $
Должна получится примерно такая табличка

По этому отчету вы сможете понять работает ли для вашей ситуации этот метод. У меня тесты показали значительное отличие и дали возможность делать автоматические выводы на основе этих ярлыков.

Полный скрипт на гитхабе — https://github.com/pamnard/Google-Ads-Scripts/tree/master в папке [Worker] GPT Labeler.