- BrainTools - https://www.braintools.ru -
Недавно мы рассказывали, как собрали AI-менеджера маркетплейсов на правилах [1] : фраза проходит через регулярки, превращается в операцию из закрытого списка, операция идёт в API площадки. Модель там только помогала угадать операцию. Всё, что меняет кабинет, — только кнопкой владельца.
Первые владельцы с ним поговорили. Ниже — что мы увидели в этих разговорах, почему переделали менеджера почти с нуля и почему новая версия получилась свободнее, но при этом вся в ограничителях.
Люди пишут не по списку. Мы ждали «покажи остатки на ВБ», а получили «почему просели продажи», «что делать с худи» и «сравни с прошлым месяцем, только без возвратов». Правила такие фразы не узнавали, и менеджер отвечал общим ответом. Таких фраз было [32] из [120].
Цифры есть, понимания нет. Это оказалось важнее всего. Заказы, остатки, воронку и расходы на рекламу селлер и так видит в кабинете площадки. Ему нужно другое: почему мало продаж. Может, карточка не находится в поиске. Может, реклама тратит деньги на запросы, по которым никто не покупает. Может, цена выше, чем у соседей по выдаче. Менеджер 1.0 честно показывал таблицу, а вывод из неё оставлял человеку.
Каждая новая просьба — новая ветка кода. Регулярка, обработчик, строка в списке операций, проверка в смоук-тесте. Владельцы просили быстрее, чем мы успевали дописывать.
И пара честных багов. Их нашли читатели прошлой статьи, и мы их признаём:
если владелец называл площадку, которая не подключена, менеджер молча отвечал по первой подключённой;
кнопка с новой ценой собиралась из снимка кабинета, а перед записью текущая цена не перечитывалась.
Оба бага — следствие самого устройства: решения принимает код, а код знает только те случаи, которые мы предусмотрели.
Мы перевернули схему. Раньше код разбирал фразу и звал обработчик. Теперь модель видит разговор и список инструментов, сама решает, что вызвать и в каком порядке, смотрит результат и продолжает, пока не будет готова ответить. Примерно так работают агенты для программистов, и мы взяли ту же идею.
Инструментами стали все операции из первой версии. Заказы, остатки, цены, акции, воронка, отзывы — каждая операция из закрытого списка превратилась в инструмент сама, переписывать их не пришлось. Сверху добавили новые:
сравнение продаж по товарам: последние 7 дней против предыдущих 7;
карточка товара целиком;
журнал: что и когда меняли в кабинете;
план: задачу из нескольких шагов агент сначала расписывает, потом делает;
память [2]: «запомни, что худи мы больше не возим»;
наблюдение и «проверь позже»: менеджер сам возвращается к задаче через время.
Теперь на «почему просели продажи» агент может сам посмотреть продажи по товарам, найти, что упало, открыть эту карточку, проверить остатки и рекламу и только потом ответить.
Дать модели доступ к кабинету, где лежат цены и рекламные бюджеты, — решение, после которого плохо спится. Поэтому вторую версию мы обложили ограничениями со всех сторон.
Ход ограничен по шагам и по времени. Не больше восьми шагов с инструментами, не больше 150 секунд на ответ, не больше шести вызовов за шаг. Время кончилось — агент отвечает тем, что успел узнать.
MAX_STEPS = 8
BUDGET = 150 # секунд на весь ход
LAST_CALL = 25 # осталось меньше — последний шаг без инструментов
CALLS_PER_STEP = 6 # параллельных вызовов в одном шаге
def run(ctx, system, history, tools):
msgs = history + [{"role": "user", "content": ctx.q}]
start = time.monotonic()
for step in range(MAX_STEPS + 1):
left = BUDGET - (time.monotonic() - start)
last = step == MAX_STEPS or left < LAST_CALL
if last:
msgs.append({"role": "user", "content":
"Время на задачу кончилось. Ответьте тем, что уже узнали, "
"и скажите, что осталось сделать."})
r = providers.call(system, msgs, [] if last else tools, left)
if not r.calls:
return r.text # ответил текстом — ход окончен
for c in r.calls[:CALLS_PER_STEP]:
msgs.append(tool_result(c, run_tool(ctx, c)))
Упавший инструмент ход не роняет: модель получает ошибку [3] словами и решает, что делать дальше.
Инструменты — узкие и с инструкцией. Каждый инструмент мы снабдили описанием, как им пользоваться: «до 15 результатов», «лимит общий, пачкой не зовите», «один-два вызова широкими словами, потом один-два финалиста». Данные перед передачей модели подрезали: таблица — до 200 строк, название — до 60 знаков, ячейка — до 120.
Запись — только то, что владелец уже видел. Кнопок под ответами больше нет: агент спрашивает словами «Делаю?», владелец отвечает «да». Но «да» — это не разрешение на что угодно. Выполнить можно только конкретное предложение из прошлого ответа, и проверяет это код, а не модель:
def _confirm(ctx, a):
"""Выполнить предложение из ПРОШЛОГО ответа: владелец его видел и согласился."""
if ctx.who == "поручение": # ход по расписанию: соглашаться некому
return Out("Это ход по расписанию — подготовьте и спросите владельца.")
if _NO.search(ctx.q.lower()):
return Out("Владелец не согласился — не выполняю.")
msg, act = find_offer(ctx.earlier, a.get("act"))
if act is None:
return Out("Такого предложения в прошлых ответах нет. Подготовьте и спросите.")
if now() - msg.created_at > FRESH: # час
return Out("Предложение старше часа — цифры могли измениться. Подготовьте заново.")
ok, say = staff_work.do(ctx.db, ctx.tenant, msg, act["id"])
return Out(("Выполнено: " if ok else "Не вышло: ") + say)
Модель не может придумать правку и тут же её выполнить. Не может выполнить её ночью по таймеру. Не может применить цену, которую владелец видел вчера: через час предложение протухает, и агент обязан собрать его заново на свежих цифрах.
Свобода выбора инструментов не делает модель селлером. Она знает, что такое маркетплейс, но не знает, как опытный менеджер ищет нишу или почему карточка проваливается в выдаче. Поэтому мы дали агенту скиллы — библиотеку знаний должности.
На полку менеджера легли:
метод «от ниши до готовой карточки» по шагам;
статьи практиков о SEO карточек и разборе конкурентов;
руководство по аналитике MPStats и два десятка страниц его базы знаний.
Оглавление полки лежит в промпте, нужные статьи агент открывает сам под задачу. Чтобы конспекты не съедали контекст, их заранее сжимает более умная модель.
Инструментов при этом стало много, и каждый шаг агента тяжелел. Мы разложили их по группам и прятали редкие: агент находит их поиском, а не получает все сразу. Шаг соседнего сотрудника, маркетолога, похудел с 35 до 14,5 КБ.
И ещё одна мелочь, которая потом оказалась очень полезной. Если владелец просит то, для чего инструмента нет, агент не выкручивается. Он зовёт отдельный инструмент «нет инструмента», пишет, чего не хватило, и честно отвечает «пока не умею». Все такие просьбы по всем проектам собираются в одном списке в админке. По нему мы решаем, что добавлять первым.
Как и в первый раз, менеджер работает в двух местах: на демо-магазине без сети и у владельцев с живыми кабинетами.
Добавился эталон: восемь типовых задач селлера и модель-судья, которая ставит ответу оценку от 1 до 5. Он видит данные, которые получил агент, и может проверить не только тон, но и цифры.
Смотрим на три вещи:
насколько глубоко агент копает, прежде чем ответить;
сколько раз он упирается в «пока не умею» и в чём именно;
где наши ограничители спасают, а где мешают.
Мы дали агенту свободу и тут же обложили её правилами. С виду всё под контролем: шаги посчитаны, данные отмерены, каждая запись — с согласия владельца. Менеджер стал отвечать увереннее и подробнее. Вопрос в том, на чём держится эта уверенность. Когда закончим разбирать тесты, поделимся результатами.
Автор: Haimi
Источник [4]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/37621
URLs in this post:
[1] как собрали AI-менеджера маркетплейсов на правилах: https://habr.com/ru/articles/1099778/
[2] память: http://www.braintools.ru/article/4140
[3] ошибку: http://www.braintools.ru/article/4192
[4] Источник: https://habr.com/ru/articles/1100298/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1100298
Нажмите здесь для печати.