Перейти к содержимому

Исследовать данные в постоянном ядре

Это руководство показывает, как заставить агента один раз загрузить что-то дорогое, а затем задать по этому несколько вопросов, вместо того чтобы платить за загрузку при каждом вопросе.

Инструмент eval запускает постоянный интерпретатор. Переменные, импорты и загруженные данные сохраняются между вызовами.

Одноразовый python -c платит за подготовку при каждом вопросе. Загрузка датафрейма стоит секунды и сотню мегабайт, а построение по нему графика — миллисекунды. Когда каждый вопрос стоит столько же, сколько загрузка, агент задаёт меньше вопросов, чем следовало бы, — и каждый ответ возвращается текстом, который затем приходится разбирать заново.

Загрузите data/runs.csv и скажите мне p95 длительности по агентам.

import pandas as pd
runs = pd.read_csv("data/runs.csv")
len(runs)

Последнее выражение возвращается так, как это делает блокнот, поэтому len(runs) сообщает число строк без print.

Затем, в отдельном вызове:

runs.groupby("agent")["duration_ms"].quantile(0.95).sort_values()

runs всё ещё загружен. Датафрейм pandas возвращается отрисованным как таблица, а не как repr.

import matplotlib.pyplot as plt
runs.groupby("agent")["duration_ms"].mean().plot.bar()

Графики захватываются после ячейки и возвращаются изображениями, которые отрисовывает транскрипт. Вы видите график; агент тоже.

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

Они переписываются в обычный код, а не приводят к ошибке:

Вы набираете Что происходит
%pip install x Запускает pip, затем очищает кэш модулей, чтобы следующий import увидел его
%cd path os.chdir
!command Захваченный подпроцесс
%%bash Остаток ячейки как сценарий оболочки
%%timeit 1000 запусков с замером времени

Важнее всего здесь вытеснение кэша в %pip: установка в работающий интерпретатор ничего не меняет для модуля, который уже импортирован, поэтому без неё работает не та версия, которую вы только что установили.

Вызов собственных инструментов из ячейки

Заголовок раздела «Вызов собственных инструментов из ячейки»
paths = tool("find", {"pattern": "**/*.dart", "path": "lib"})
for path in paths.splitlines()[:100]:
contents = tool("read", {"path": path})
...

tool(name, args) снова входит в собственный реестр инструментов агента. Это значит, что ячейка может разветвиться по сотне файлов или делегировать через task, не тратя ход модели на каждый элемент.

Вызов через мост приостанавливает тайм-аут ячейки, пока он не завершён. Бюджет измеряет бездействие, а не время по часам, — ячейка, которая разветвляется на субагентов и ждёт четыре минуты, не зависла, а её убийство посреди разветвления потеряло бы состояние всего ядра.

eval(code: "…", reset: true, description: "Start a clean interpreter")

Отбрасывает интерпретатор и запускает чистый. Всё загруженное пропадает — в этом и смысл.

В изолированной среде разговора, если она у него есть, иначе — на хосте.

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

При этом он не запускает изолированную среду, чтобы до неё добраться, — то же правило, которое не даёт вкладке rig запуститься автоматически. Если вы хотите, чтобы ядро было изолировано, сначала откройте оболочку разговора. См. Дать агенту машину для тестов.

  • Одна ячейка за раз на ядро. Две ячейки, соревнующиеся в одном интерпретаторе, — это две половины двух программ, переплетённые в одном пространстве имён.
  • Вывод ограничен. Ячейка в цикле печати обрезается, а не заполняет окно контекста.
  • Четыре изображения на ячейку. Цикл построения графиков может выдавать график на каждой итерации, а каждое изображение — большая фиксированная плата в запросе, который его несёт.
  • Ядро умирает вместе с запуском. Ядро, всё ещё держащее датафрейм после завершения разговора, — это утечка.