Zum Inhalt springen

Daten in einem persistenten Kernel erkunden

Diese Anleitung zeigt, wie du einen Agenten etwas Teures einmal laden lässt und ihm dann mehrere Fragen dazu stellst, statt den Ladevorgang bei jeder Frage erneut zu bezahlen.

Das Tool eval führt einen persistenten Interpreter aus. Variablen, Importe und geladene Daten bleiben zwischen den Aufrufen erhalten.

Ein einmaliges python -c zahlt den Aufbau bei jeder Frage. Einen DataFrame zu laden kostet Sekunden und hundert Megabyte; ihn zu zeichnen kostet Millisekunden. Kostet jede Frage den Ladevorgang, stellt ein Agent weniger Fragen, als er sollte — und jede Antwort kommt als Text zurück, den er danach neu parsen muss.

Lade data/runs.csv und sag mir die p95-Dauer je Agent.

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

Der letzte Ausdruck wird wie in einem Notebook zurückgegeben, deshalb meldet len(runs) die Zeilenzahl ohne ein print.

Dann, in einem eigenen Aufruf:

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

runs ist noch geladen. Ein pandas-Frame kommt als Tabelle zurück statt als Repr.

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

Figures werden nach der Zelle erfasst und als Bilder zurückgegeben, die das Transkript darstellt. Du siehst das Diagramm, der Agent auch.

Figures werden nach dem Erfassen geschlossen. Eine nicht eingesammelte Figure würde auch von der nächsten Zelle neu gezeichnet und noch einmal geschickt, eine Sitzung aus fünf Zellen würde das erste Diagramm also fünfmal ausgeben.

Sie werden in gewöhnlichen Code umgeschrieben, statt einen Fehler zu werfen:

Du tippst Was passiert
%pip install x Führt pip aus und leert dann den Modul-Cache, damit der nächste import es sieht
%cd path os.chdir
!command Ein Subprozess mit erfasster Ausgabe
%%bash Der Rest der Zelle als Shell-Skript
%%timeit 1000 gemessene Läufe

Das Leeren des %pip-Caches ist der Punkt, auf den es ankommt: In einen laufenden Interpreter zu installieren ändert nichts an einem Modul, das schon importiert wurde, und ohne das Leeren läuft nicht die Version, die du gerade installiert hast.

paths = tool("find", {"pattern": "**/*.dart", "path": "lib"})
for path in paths.splitlines()[:100]:
contents = tool("read", {"path": path})
...

tool(name, args) steigt wieder in die eigene Werkzeugregistrierung des Agenten ein. Eine Zelle kann sich so über hundert Dateien auffächern oder über task delegieren, ohne dass das Modell einen Turn je Element verbraucht.

Ein überbrückter Aufruf setzt das Timeout der Zelle aus, solange er aussteht. Das Budget misst Untätigkeit, nicht die Wanduhrzeit — eine Zelle, die sich auf Subagenten auffächert und vier Minuten wartet, hängt nicht, und sie mitten in der Auffächerung abzubrechen nähme den Zustand des ganzen Kernels mit.

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

Verwirft den Interpreter und startet einen sauberen. Alles Geladene ist weg, und genau das ist der Sinn.

In der Kapsel der Unterhaltung, wenn sie eine hat, sonst auf dem Host.

Ein persistenter Interpreter, den ein Modell antreibt, das ein unvertrauenswürdiges Repo liest, ist genau der Fall, für den die Ausführung nur in der Kapsel da ist: Ein einmaliger bash-Aufruf endet wenigstens, ein Kernel ist eine Shell, die sich erinnert.

Er bootet dafür keine Kapsel — dieselbe Regel, die einen Rig-Tab am automatischen Start hindert. Soll der Kernel gekapselt laufen, öffne zuerst die Shell der Unterhaltung. Siehe Einem Agenten eine Testmaschine geben.

  • Eine Zelle gleichzeitig je Kernel. Zwei Zellen, die in einem Interpreter gleichzeitig loslaufen, sind zwei Hälften zweier Programme, in einem Namespace ineinander verschachtelt.
  • Die Ausgabe ist gedeckelt. Eine Zelle in einer print-Schleife wird abgeschnitten, statt das Kontextfenster zu füllen.
  • Vier Bilder je Zelle. Eine Plot-Schleife kann je Iteration eine Figure ausgeben, und jedes Bild ist ein großer fester Kostenblock in der Anfrage, die es trägt.
  • Der Kernel stirbt mit dem Lauf. Einer, der nach dem Ende der Unterhaltung noch einen DataFrame hält, ist ein Leck.