Урок 01 · База

Без циклов нет агента

Весь секрет Клода Кода можно записать в одной строке: while stop_reason == "tool_use"

⏱ ~10 мин · 📝 3 интерактивных компонента · 🧑‍💻 На основе shareAI-lab · s01_agent_loop.py

Что именно делает агент?

Когда вы запускаете Claude Code в терминале и позволяете ему «организовать все комментарии TODO в список», вы видите следующее: он самостоятельно решает сначала grep, затем cat несколько файлов, а затем вывести Markdown. Модель сама не выполняет код — она только запрашивает выполнение. Что действительно придает ему вид «с руками и ногами», так это около 30 строк кода склейки вокруг него.

Этот урок состоит в том, чтобы разобрать клейкий круг и ясно увидеть. Он называется агентский цикл (цикл агента), и его структура такова:

 while response.stop_reason == "tool_use":
    ответ = LLM(сообщения, инструменты) # 1. спросить модель
    execute_tools(response.tool_calls) # 2. выполнить то, что запросили
    messages.append(tool_results) # 3. вернуть результаты

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

Ключевая интуиция: каждый раз, когда модель отвечает, это либо «Я хочу настроить инструмент», либо «Я закончила». Цикл продолжается до тех пор, пока он находится в предыдущем состоянии; как только он входит в последнее состояние, цикл завершается. Критерием является поле stop_reason в ответе.

См. сообщения[] растут шаг за шагом

Задача следующего моделирования цикла: "Какие файлы находятся в текущем каталоге? Затем прочитайте package.json". Нажмите Шаг. Каждый раз, когда вы нажимаете ее, вы продвигаетесь на одно действие в цикле. Слева — речевой пузырь, видимый человеком, справа — фактический массив messages[], встроенный в модель — обратите внимание, как он растет.

Результаты работы инструмента необходимо повторно ввести в историю сообщений.

Самая простая ошибка для новичков — рассматривать «инструмент выполнения» как побочный эффект: как только он будет запущен, он будет готов. Однако модель может видеть сообщения[] только в следующем раунде вывода и она не знает, что произошло то, чего в ней нет. Без шага добавления весь цикл был бы неправильным.

Не все ошибки одинаковы. Два распространенных типа:

<ул>
  • Забудьте о добавлении: модель не увидит результаты в следующий раз, она снова запросит тот же инструмент — и вы получите бесконечный цикл.
  • Добавить, но потерять tool_use_id: Anthropic API напрямую сообщит об ошибке, tool_result должен иметь Tool_use_id, и цикл завершится на этапе вызова API.
  • То же задание: "Посчитать, сколько файлов Python в проекте". Запустите две версии рядом, чтобы увидеть разницу в концовках.

    Понять stop_reason

    Каждый раз, когда модель возвращается, она возвращает stop_reason. Чтобы решить, продолжать ли цикл, просто посмотрите на это поле:

    <ул>
  • tool_use — модель хочет настроить инструмент, продолжить цикл.
  • end_turn — модель чувствует, что завершила работу, и выходит из цикла.
  • max_tokens — когда генерируется верхний предел токенов, он усекается и выходит из цикла (обычно обрабатывается как исключение, сообщающее пользователю, что вывод неполный).
  • stop_sequence — при обнаружении пользовательской последовательности остановки выйдите из цикла.
  • Неправильное написание фразы «продолжать до тех пор, пока нет tool_use» или игнорирование max_tokens и прямая обработка его как нормального завершения — это распространенные ошибки.

    Примите меры и бегите

    Локальный клон shareAI-lab/learn-claude-code:

    клон git https://github.com/shareAI-lab/learn-claude-code
    cd Learn-Claude-code
    pip install -r требования.txt
    cp .env.example .env # заполните ANTHROPIC_API_KEY
    агенты Python/s01_agent_loop.py

    Тогда позвольте ему сделать что-нибудь реальное: Помогите мне посчитать, сколько файлов .py в этом репозитории. Вы увидите, что он отправляет ls -R, смотрите вывод, отправляете еще один find . -имя "*.py" | wc -l, а затем сообщим вам ответ. Весь процесс представляет собой этот цикл.

    Интерактив

    Виджет 1 · Loop Stepper · рост сообщений[]

    Поймите: результаты инструмента вставляются обратно в сообщения в специальном формате (блок tool_result с tool_use_id); это единственный способ узнать модель, что «инструмент был выполнен и результатом является X» в следующем раунде вывода.

    对话视图未开始
    点 Step 开始 →
    messages[] JSONlength: 0
    []
    stop_reason:
    Интерактив

    Виджет 2 · Разорвать цикл · Исправить или забыл добавить

    Поймите: пока отсутствует одна строка, messages.append(tool_results), весь агент больше не является агентом — он становится читающей машиной, которая забывает предыдущую в каждом раунде.

    while True:
        resp = LLM(msgs, tools)
        msgs.append({"role":"assistant",
                     "content": resp.content})
        if resp.stop_reason != "tool_use":
            return
        results = execute(resp.tool_uses)
        msgs.append({"role":"user",
                     "content": results})
    模拟运行
    while True:
        resp = LLM(msgs, tools)
        msgs.append({"role":"assistant",
                     "content": resp.content})
        if resp.stop_reason != "tool_use":
            return
        results = execute(resp.tool_uses)
        # BUG: forgot to append results
        # msgs.append(...)
    模拟运行
    Интерактив

    Виджет 3 · Найди стоп-причину · Оцени 4 верных ответа

    Каждый из них представляет собой фрагмент реального возможного ответа модели. Нажмите «Продолжить» или «Выход», чтобы узнать, правы вы или нет.

    答对 0 / 4