Головна / Статті / Цикл наступного токену: ментальна модель ШІ, перш ніж ви почнете працювати з агентами

Цикл наступного токену: ментальна модель ШІ, перш ніж ви почнете працювати з агентами

Дізнайтеся, як працюють токени, вікна контексту, вибірка даних та цикл генерації, за допомогою невеликих прикладів на Python без підключення до мережі, які пояснюють, чому існують RAG, ReAct та LangGraph.

1143 слів

Інженери, які працюють з LLM через фреймворки на кшталт LangChain, часто не можуть визначити, коли щось ламається, чи проблема у самому фреймворку, API, яке він обгортає, чи у моделі. Рішенням є чітка ментальна модель: LLM — це функція прогнозування наступного токена, яка викликається багаторазово у циклі. З таким розумінням RAG — це спосіб вибору того, що буде передано у функцію, ReAct — спосіб обробки того, що повертається, а LangGraph — спосіб координації багатьох викликів. Наведені нижче приклади працюють локально з Python та однією невеликою бібліотекою, без необхідності API-ключа.

Генерація — це прогнозування наступного токена у циклі

Для заданої послідовності токенів модель повертає ймовірність кожного можливого наступного токена. Вибирається один токен, додається до послідовності, а потім вона знову подається у функцію. Цей процес повторюється до моменту появи токена зі знаком зупинки або до досягнення межі довжини. Стрімове виведення просто демонструє цей цикл токен за токеном.

Випливають дві наслідки:

  • Плану немає. Кожен токен залежить лише від токенів, що йдуть перед ним.
  • Пам’яті між викликами немає. Кожен запит починається саме з тих токенів, які ви надсилаєте, і саме тому існує генерація з підтримкою пошуку інформації.

Токени — це частини слів, а не самі слова

Модель бачить цілі числа, а не текст. Токенайзер перетворює рядки на ідентифікатори токенів та назад. Часто вживані слова зазвичай стають одним токеном, тоді як рідкісні слова та код розділяються на кілька токенів. Приблизна оцінка: один токен дорівнює приблизно трьом чвертям слова.

Цей фрагмент завантажує o200k_base, кодування сімейства gpt-4o, через tiktoken, кодує речення та виводить кожен ідентифікатор разом із відповідним фрагментом тексту. Зверніть увагу, що „LangGraph“ стає двома токенами, а пробіли на початку належать до наступного токену.

import tiktoken

# tokenizer of the gpt-4o model family
enc = tiktoken.get_encoding("o200k_base")

ids = enc.encode("LangGraph orchestrates agents.")
print(ids)
# [30741, 9922, 109873, 1381, 19297, 13]

for i in ids:
    print(i, repr(enc.decode([i])))
# 'Lang' 'Graph' ' orchestr' 'ates' ' agents' '.'

Навчання та інференс — це окремі етапи

Під час навчання ваги коригуються шляхом прогнозування наступних токенів у великих обсягах тексту. Інференс полягає у використанні вже замороженого моделювання. Ваш запит ніколи не змінює ваг, тому інформація, якої бракує моделі, мусить бути включена до запиту під час інференсу. Саме це робить RAG.

Вікно контексту — це весь світ моделі

Одне запитання може обробити лише певну кількість токенів, і цей ліміт, вікно контексту, охоплює одночасно запит та генерований результат. Усе, що знаходиться поза ним, не існує для цього запитання. Чат здається безперервним лише тому, що додаток щоразу пересилає попередні повідомлення, а RAG існує тому, що збірки документів не вміщуються повністю, тож замість цього завантажуються кілька релевантних фрагментів.

Бюджетування — це проста арифметика. Допоміжний модуль підраховує кількість токенів за допомогою вищезгаданого токенайзера та віднімає їх, разом із резервом на відповідь, від діапазону у 128 000 токенів, який вказаний для gpt-4o-mini. Ліміти відрізняються між моделями та версіями, тому перевірте актуальну документацію вашого постачальника.

def count_tokens(text: str) -> int:
    return len(enc.encode(text))

prompt = "Summarize the attached design doc."
window = 128_000     # e.g. gpt-4o-mini
reserve = 1_000      # room for the answer
used = count_tokens(prompt)
print("left:", window - reserve - used)

Температура впливає на вибір наступного токену

Метод вибірки обирає один токен з розподілу моделі, а температура змінює цей розподіл. При значенні майже нульовому майже завжди обирається найбільш ймовірний токен. При значенні 1,0 та вище менш ймовірні токени отримують реальний шанс. Використовуйте температуру 0 для екстракції, структурованого виведення та агентів для виклику інструментів, а приблизно 0,7–1,0 — для складання тексту та мозкового штурму. Наш посібник про температуру, top-k та top-p охоплює інші параметри вибірки.

Створення циклу в мініатюрі

У наступному прикладі справжній токенайзер поєднується з фальшивою моделлю, створеною за допомогою таблиці пошуку. Вона дуже мала, але дотримується того ж циклу, що й справжній LLM: кодування, прогнозування, додавання та зупинка.

Спочатку невеликий корпус токенізується, і підраховується кількість кожної суміжної пари ідентифікаторів. Для кожного токена таблиця зберігає лише його найчастіший наступник, що робить цей прогнозувальний механізм «жадібним», що еквівалентно температурі нуля.

CORPUS = (
    "the agent calls the model. "
    "the model returns a token. "
    "the agent calls the tool. "
    "the tool returns a result."
)

ids = enc.encode(CORPUS)
counts = {}
for a, b in zip(ids, ids[1:]):
    counts.setdefault(a, {})
    counts[a][b] = counts[a].get(b, 0) + 1

# greedy "model": token -> likeliest successor
table = {
    a: max(s, key=s.get)
    for a, s in counts.items()
}

Цикл кодує запит, знаходить найімовірнішого наступника останнього токена, додає його та виводить розкодований текст. Відсутній наступник повертає None, що є замінником токена зупинки. Основна операція — додавання: вихідний текст стає вхідним.

seq = enc.encode("the agent calls")
for _ in range(3):
    nxt = table.get(seq[-1])
    if nxt is None:    # our toy "stop token"
        break
    seq.append(nxt)    # output becomes input
    print(enc.decode(seq))

Секвенція збільшується на один токен за кожен крок:

the agent calls the
the agent calls the model
the agent calls the model.

Один деталь є показовим. У корпусі слово „the“ послідовно супроводжується як „model“, так і „tool“ з однаковою частотою, а max залишає той варіант, який побачив першим. Реальні моделі постійно стикаються з такою майже рівною кількістю варіантів, тому налаштування вибору мають велике значення.

Запуск прикладів

Зберігайте фрагменти коду в одному скрипті, наприклад examples/part01_tokens.py, разом із файлом requirements.txt, у якому вказаний tiktoken. Цей скрипт виводить розбиття на токени, обчислює необхідні показники та запускає простий цикл приблизно за секунду, після чого працює офлайн після збереження даних токенізатора у кеші. Потім змініть корпус та спостерігайте за зміною результату.

pip install -r requirements.txt
python examples/part01_tokens.py

Основні висновки

  • LLM — це зафіксована функція, яка перетворює послідовність токенів на розподіл наступних токенів, що працює в циклі зворотного зв’язку.
  • Він знає лише свої ваги та розмір вікна контексту та ніколи не навчається на вашому запиті.
  • Різноманітність досягається шляхом вибірки даних, яка контролюється параметром температури.
  • Техніки агентів визначають, які токени будуть використані та що станеться з токенами, які виходять.
  • Пов’язана література