Ship 26 NYC - Workshop - Mini-workers

VVercel
Computing/SoftwareSmall Business/StartupsInternet Technology

Transcript

00:00:00Hallo zusammen. Mein Name ist Jonathan Clem, oder ihr könnt mich Jay Clem nennen, und ich bin Softwareentwickler bei
00:00:11Notion, wo ich an unserer Entwicklerplattform arbeite, mich aber besonders auf ein neueres Produkt konzentriere,
00:00:17von dem ihr vielleicht schon gehört habt, nämlich Notion Workers. In diesem Workshop heute möchte ich euch
00:00:23einen kleinen Überblick darüber geben, was Notion Workers sind und warum wir sie mit Vercel
00:00:28Sandbox entwickelt haben. Und danach führe ich euch durch eine Art Mini-Version von Workers,
00:00:36damit ihr ein Gefühl dafür bekommt, wie ein solches Produkt mit Vercel Sandbox aufgebaut wird.
00:00:43Falls ihr also noch nicht wisst, was Workers sind: Es handelt sich um ein SDK und eine Laufzeitumgebung, in der ihr
00:00:50eigenen Code schreiben und Notion damit erweitern könnt. Ihr könnt also Dinge tun wie Drittanbieterdaten in Notion synchronisieren,
00:00:57ihr könnt benutzerdefinierte Tool-Aufrufe für eure Agenten schreiben. Wir haben gesehen, wie Leute verrückte Dinge tun, wie zum Beispiel
00:01:04ihre Lebensmitteleinkäufe über Notion Workers zu erledigen oder ihr Smart Home zu steuern. Wir haben auch sehr komplexe Workflows gesehen,
00:01:11insbesondere aus dem IT- und Sicherheitsbereich. Das Schöne an Workers ist, dass ihr keine
00:01:17Infrastruktur verwalten müsst. Ihr schreibt einfach Code oder lasst ihn von einem Coding-Agenten schreiben, und Notion
00:01:23kümmert sich darum, dass er immer läuft, verfügbar und einsatzbereit ist. Das war ein riesiger Vorteil für Notion-
00:01:30Benutzer, insbesondere Entwickler. Sie müssen nicht länger darauf warten, dass Notion eigene
00:01:36Integrationen für sie baut. Alles, was Notion ihrer Meinung nach tun könnte, aber nicht tut, können sie einfach
00:01:42selbst schreiben. Als wir also anfingen, Notion Workers zu entwickeln, war mein Hauptanliegen
00:01:53Sicherheit. Ich habe etwas Erfahrung im Aufbau von Plattformen, auf denen nicht vertrauenswürdiger BenutzerCode ausgeführt wird.
00:01:59Ich habe zum Beispiel lange Zeit an GitHub Actions gearbeitet. Und ich war vor allem besorgt über die
00:02:04Schwierigkeit, Infrastruktur für ein solches Produkt aufzubauen, und insbesondere über die Sicherheit. Es gibt eine Menge
00:02:09Dinge, über die man sich Gedanken machen muss. Zum Beispiel möchte man sicherstellen, dass Code, der von Benutzern geschrieben wurde,
00:02:14natürlich keine Notion-Datenbanken berühren kann oder keine Notion-Dienste berühren kann, auf die sie normalerweise keinen
00:02:20Zugriff haben sollten. Man möchte auch sicherstellen, dass Benutzer andere Benutzer nicht beeinträchtigen können. Man möchte nicht, dass der Code eines Benutzers
00:02:26auf den Code eines anderen Benutzers zugreifen kann oder natürlich auf deren Geheimnisse oder irgendetwas in der Art.
00:02:31Das betrifft nicht nur die Sicherheit. Es geht auch um Fairness und Ressourcenteilung. Wenn ein Benutzer
00:02:37etwas tut, das extrem viel CPU und Speicher verbraucht, möchte man sicherstellen, dass dies nicht
00:02:42andere Benutzer unfaire Weise beeinträchtigt, die gleichzeitig Dinge tun möchten. Ich nehme mir kurz eine Minute
00:02:48und erzähle eine kleine Geschichte dazu. Das mit der Ressourcenteilung ist wirklich eine knifflige Sache.
00:02:54Das wird wahrscheinlich meine Zeit beanspruchen, aber ich mag diese Geschichte. Als wir
00:02:58GitHub Actions gebaut haben – und das ist etwas, worüber wir auch bei Workers nachgedacht haben –, sobald man eine
00:03:02Plattform für die Ausführung von beliebigem Code hat, versuchen die Leute sofort, darauf Krypto-Mining zu betreiben.
00:03:07Und ich hatte vor ein paar Wochen ein Gespräch mit jemandem, der meinte: Nun,
00:03:10wie erkennt man das? Man kann doch einfach sehen, ob eine CPU zu hundert Prozent ausgelastet ist, oder?
00:03:14Nun, nicht wirklich, denn sobald man eine erfolgreiche Plattform ist, fangen Krypto-Miner sofort an,
00:03:20Skripte untereinander auszutauschen, die die Art und Weise modifizieren, wie
00:03:26CPU-Anweisungen ausgeführt werden, so dass es wie eine völlig harmlose Aktivität aussieht, sie aber
00:03:31die absolut maximal mögliche Menge an Ressourcen verbrauchen, ohne in Ihrem System als verdächtig aufzufallen.
00:03:37Es ist also außerordentlich schwierig und erfordert viele Jahre sowie zahlreiche Sicherheits- und
00:03:42Observability-Ebenen, um das richtig hinzubekommen. Eine andere Sache, über die man sich Sorgen machen muss, ist, dass man bei einer
00:03:48Code-Ausführungsplattform befürchten muss, dass Leute Denial-of-Service-Angriffe damit durchführen
00:03:54und sie für Botnet-Command-and-Control-Netzwerke nutzen. Und wir wollten uns all diesen Kram
00:04:00bei Notion Workers nicht von Anfang an auf驮 laden. Wir wollten uns auf das konzentrieren, was wir gerne tun, nämlich
00:04:07ein Produkt zu liefern, das unsere Benutzer gerne verwenden. Aus diesem Grund haben wir uns entschieden, mit Vercel Sandbox zu bauen.
00:04:14Vercel Sandbox war, wie wir sofort sehen konnten, eine wirklich solide Infrastruktur, die viele
00:04:18dieser Probleme für uns von Haus aus löste. Ich werde euch nun eine superschnelle Demo
00:04:25davon zeigen, was Notion Workers sind. Ich habe hier einen benutzerdefinierten Agenten, und die Aufgabe dieses Agenten ist es, mir zu sagen,
00:04:33ob dieser Workshop verflucht ist oder nicht. Ich habe einen Worker namens Mercury Retrograde geschrieben. Ich weiß nicht, ob das jemandem
00:04:40ein Begriff ist, aber wenn Merkur so steht, dass er sich im rückläufigen Orbit (Retrograde) befindet, ist das normalerweise
00:04:47ein schlechtes Omen. Dieser Worker hat also einen einzigen benutzerdefinierten Tool-Aufruf, der eine von mir gefundene API nutzt, die nichts anderes tut,
00:04:54als dir zu sagen, ob Merkur rückläufig ist oder nicht. Also werde ich meinen Agenten auffordern und sagen: „Ist mein
00:05:01Workshop verflucht?“ und er wird eine Minute lang nachdenken, und dann sollten wir – solange das Internet mitspielt –
00:05:14sehen, wie er einen Tool-Aufruf tätigt. Er verwendet also meinen Merkur-im-rückläufigen-Orbit-Worker, ruft das
00:05:22einzelne Tool auf, das dieser Worker bereitstellt, findet heraus, ob Merkur rückläufig ist oder nicht, und dann wird der
00:05:27Agent uns antworten. Ich glaube, ich habe das mit so etwas wie GPT-54 nano verbunden. Daher ist es normalerweise viel
00:05:37schneller. Ich denke, das liegt leider am Internet. Falls zufällig jemand überprüft hat, ob Merkur
00:05:46rückläufig ist: Ich weiß im Voraus, dass er es ist. Und deshalb passiert das wahrscheinlich. Ich werde es einfach
00:05:53überspringen. Wir kommen in einer Minute darauf zurück und sehen nach, ob wir schließlich eine Antwort erhalten haben. Aber ich denke, wir kennen
00:05:59die Antwort ohnehin bereits. Okay, jetzt habt ihr also eine Vorstellung davon, was Notion Workers sind. Ich führe euch
00:06:05durch ein kleines Skript, das ich geschrieben habe und das viele der grundlegenden Aufgaben erledigt, die damit verbunden sind, BenutzerCode
00:06:13zu nehmen, bereitzustellen, sicher auszuführen und einem Agenten quasi von diesem Code zu erzählen, damit er
00:06:20Tool-Aufrufe daran tätigen kann. Ist das jemals fertig geworden? Oh, ja, hier ist es. Oh, ich glaube vielleicht,
00:06:28ich habe wohl die Merkur-im-Retrograde-API abgeschaltet, weil die API offensichtlich nicht geantwortet hat.
00:06:35Wie auch immer, ich muss irgendwo ein Ticket öffnen. Gut. Ich habe also ein einfaches Skript. Ich erwarte nicht,
00:06:40dass ihr vollkommen mitkommt und Code schreibt oder so etwas. Ich werde eher ein bisschen springen
00:06:44und euch einen Eindruck von einigen der Probleme vermitteln, die wir gelöst haben und die man lösen muss, wenn man ein
00:06:49solches Produkt baut. Aber wenn ihr wollt, gibt es ein Repository make notion slash for cell ship 2026 workers,
00:06:55das den gesamten Code enthält, den ich hier ausführen werde.
00:07:01Gut. Lasst mich also meine anderen Folien hier öffnen.
00:07:08Worauf arbeiten wir also hin? Wir haben einen Streaming-Chat-Agenten. Wir werden ihm erlauben, Tools aufzurufen, die
00:07:16durch benutzerdefinierten Benutzercode definiert sind, dem wir nicht vertrauen oder von dem wir nicht wissen, was sich darin befindet.
00:07:22Und wir werden dies mit Vercel Sandbox und dem Blob-Storage-Dienst von Vercel aufbauen.
00:07:26Ich werde hier also eine kurze Demo ausführen und hoffe, dass wir nicht tatsächlich verflucht sind.
00:07:31Man kann ihm im Grunde einfach eine einzige Nachricht übergeben. Ich sage Hallo und hoffe, dass wir eine Antwort
00:07:36zurückbekommen. Es wird ein wenig langsam sein, da ihr sehen werdet, dass im Hintergrund einige Bereitstellungen ablaufen.
00:07:40Es hat also diesmal ein Tool aufgerufen. Ich habe gerade ein Tool namens say hello aufgerufen und es hat beschlossen, mich zu begrüßen.
00:07:47Ich werde ihm hier eine normale Nachricht schicken und es einfach fragen, was eins plus eins ist, damit wir sehen können,
00:07:52wie es einfach eine normale Antwort streamt.
00:07:58Wenn ihr das Vercel AI SDK verwendet habt, verwendet dies einfach die Tool-Agenten-Schleife. Gut. Wir haben also eine Streaming-
00:08:04Antwort erhalten. Man kann auch viel komplexere Worker aufrufen. Ich habe also noch einen anderen hier, den ich euch zeigen werde.
00:08:14Bei diesem hier teilen wir ihm mit, dass ich mich an der Adresse dieses Gebäudes befinde.
00:08:17Ich habe 90 Minuten Zeit und möchte eine historische Stätte besuchen, und ich möchte nicht länger als 15 Minuten zu Fuß gehen.
00:08:24Dies verdeutlicht also ein wenig, warum diese manchmal gegenüber MCP-Servern bevorzugt werden. Bei einem MCP-
00:08:29Server hat man eine Reihe von unterschiedlichen Tool-Aufrufen, die man tätigen kann. Und wenn man etwas
00:08:33Komplexes tun möchte, muss man diese Schritte dem Agenten beschreiben, und er wird einen Schritt tun, einige
00:08:38Denk-Token aufwenden, einen Schritt tun. Dieser hier ruft also einen Worker auf, der eine sehr große, komplexe Art von
00:08:45Suchalgorithmus besitzt, welcher eine Reihe von Geodaten-Transitzeiten für New York City und Routenplanungs-APIs verwendet.
00:08:52Es heißt plan outing.
00:08:56Und dieser Worker wird mit einer vorgeschlagenen historischen Stätte antworten, die wir besuchen können.
00:09:00Und es sieht so aus, als hätte er das Freedom Tree Marker gefunden, ein Denkmal, das sich in der Nähe des
00:09:07City Hall Parks befindet. Gut. Schauen wir uns also an, wie das funktioniert. Was ist also ein Worker?
00:09:14Es ist Benutzercode, der in diesem Fall einfach in einer Datei definiert ist. Normalerweise würde dies von
00:09:20euren Benutzern oder irgendwo auf GitHub definiert und mit einer CLI bereitgestellt werden. Aber wir haben einfach ein paar Beispiele im
00:09:26Repository hinterlegt. Und jeder dieser Worker muss den Tool-Namen, eine Beschreibung des Tools exponieren,
00:09:34damit der Agent zum richtigen Tool routen kann, das Eingabeschema, damit der Agent weiß, welche Eingaben er
00:09:38bei jedem Aufruf dieses Tools bereitstellen muss, sowie eine Ausführungsfunktion, die besagt, welcher tatsächliche Code ausgeführt wird,
00:09:44wenn der Agent dieses Tool aufruft. Schauen wir uns also ein Beispiel an. Hier ist das Greeter-Tool, das ihr
00:09:51vorhin gesehen habt. Es ist sehr einfach. Dieser Worker besteht aus einem einzigen JavaScript-Modul hier in dieser index.ts-Datei. Es exportiert ein einziges
00:09:59Worker namens say hello. Sie werden also sehen, wie dieser Build-Prozess funktioniert. Aber in diesem Beispiel,
00:10:04sind alle unsere Modusexport-Schlüssel den Namen unserer Tools zugeordnet. Dieses Tool wird also
00:10:09say hello heißen. Und es hat eine einfache Beschreibung sowie ein Eingabeschema. In diesem Fall verwende ich einfach Zod zur Definition
00:10:16des Schemas. Und dann konvertiere ich es in ein JSON-Schema. Das ist das Format, das diese Agenten erwarten.
00:10:22Und dann gibt es eine einfache Ausführungsfunktion. Man kann jedoch viel komplexere erstellen. Wenn ich also
00:10:27den Planungs-Workflow öffnen würde, sieht man, dass er eine viel längere Beschreibung hat, die dem Agenten
00:10:34genau erklärt, wie dieses Tool funktioniert, wann es aufgerufen werden soll und was es tut. Und das Skript dafür ist viel, viel
00:10:39länger und komplexer. Ich werde das nicht alles durchgehen. Ich habe auch nur kleine Teile
00:10:45davon gelesen, aber es funktioniert ziemlich gut. So ist das eben heutzutage. Diese Worker werden also
00:10:54gebaut und im Vercel-Blobspeicher bereitgestellt. Danach erfahren wir mehr über den Inhalt der
00:10:59Worker, auf die eine oder andere Weise. Und wir stellen sie einem Agenten zur Verfügung. Und dann werden diese Tools
00:11:03sicher in einer Sandbox ausgeführt. Den Build-Teil überspringen wir erst einmal. Bei Notion Workers haben wir einen
00:11:09cloudbasierten Bereitstellungs- und Build-Prozess. In diesem Fall habe ich diese Worker einfach vorab lokal gebaut. Jeder
00:11:15Worker hat also ein Tarball, das den gesamten kompilierten TypeScript-Code, Abhängigkeiten und ähnliches enthält.
00:11:22Das ist nicht der spannendste Teil, deshalb überspringe ich ihn einfach.
00:11:26Die Frage des Tages lautet also: Wie gelangen wir von Benutzercode, den wir noch nie gesehen haben und dem wir nicht vertrauen,
00:11:34zu Tools, die vom Agenten bereitgestellt und sicher ausgeführt werden? Das besteht im Grunde aus zwei Teilen.
00:11:39Der erste Teil ist: Sobald wir diesen Benutzercode zum Beispiel im Blobspeicher haben,
00:11:43wie finden wir heraus, was in diesem Code enthalten ist? Denn wir müssen dem Agenten mitteilen können, bevor er
00:11:48das Tool überhaupt aufruft, wie das Tool heißt, wie das Eingabeschema aussieht und wie die Beschreibung
00:11:53des Tools lautet. Und die zweite Frage ist: Wenn der Agent beschließt, dieses Tool aufzurufen,
00:11:58wie führen wir es eigentlich sicher aus? Eines der Dinge, die ich an unserer Arbeit mit dem
00:12:04Notion Workers SDK liebe und die wir hier im Grunde auch gemacht haben, ist, dass der Code sich selbst beschreibt. Was wir also
00:12:11bei der Entwicklung von Notion Workers nicht wollten, war, dass Benutzer TypeScript-Code
00:12:16schreiben müssen, um ihr Tool zu definieren, und dann sagen: „Okay, jetzt muss ich noch eine statische Manifestdatei erstellen,
00:12:21die meine Worker beschreibt“ und im Grunde denselben Kram noch einmal schreiben. Wir wollten keinen umständlichen lokalen Build-Prozess,
00:12:27bei dem sie ein Skript ausführen, Analysen durchführen, es auf der Festplatte kompilieren und dann bereitstellen müssen. Wir wollten also
00:12:34mit dem beginnen, was sich wie die optimale Entwicklererfahrung anfühlt: Man schreibt einfach das Tool, und es ist dann unser
00:12:40Problem, die schwierige Aufgabe zu lösen, wie man Informationen aus diesem Code herausbekommt.
00:12:46Das ist ein sehr einfaches Diagramm, aber bevor wir uns den Code ansehen, erzähle ich Ihnen etwas darüber,
00:12:52wie wir das lösen werden. Wir haben den kompilierten Code des Benutzers im Blobspeicher.
00:12:59Wir verwenden diesen Code, um eine Sandbox zu erstellen. Wenn wir also Befehle in der Sandbox ausführen, befindet sich der
00:13:04Code dieses Benutzers im Stammverzeichnis des Workspace. Wir importieren die index.js-Datei des Benutzers, die er geschrieben hat.
00:13:11Das liefert uns dann alle Namen der Exporte sowie diese Beschreibungen und die Eingabeschemata.
00:13:19Hier wird es ein wenig seltsam, aber es funktioniert wirklich hervorragend. Wir rufen
00:13:23json.stringify für dieses Modul auf und geben es dann in der Standardausgabe aus. Das passiert alles in
00:13:29der Sandbox, und unser Bereitstellungsskript liest diese Standardausgabe ein, wertet sie aus und sagt: „Okay,
00:13:34jetzt kenne ich die Namen aller Tools dieses Workers, die Eingaben und die Beschreibung.“ Und in diesem
00:13:40Fall übergeben wir das direkt an den Agenten. Im Falle von Notion Workers ist das jedoch zum Beispiel
00:13:44Teil unserer Bereitstellungspipeline. Wir nehmen also all diese Informationen und speichern sie in einer Datenbank, sodass
00:13:49wir bei jedem Ausführen eines benutzerdefinierten Agenten diese Tool-Beschreibungen aus der
00:13:53Datenbank abrufen. Macht das soweit Sinn, wie das funktioniert? Okay. Schauen wir uns also das Bereitstellungs-
00:14:02skript an. Ich muss hier zu meinem ersten Commit zurückkehren. Dieses Skript enthält unsere gesamte Bereitstellung und das Aufrufen
00:14:12des Agenten. Es ist super einfach. In diesem Fall iterieren wir einfach über alle Verzeichnisse
00:14:18und Worker. Jedes dieser Unterverzeichnisse enthält den Workercode, den Sie vor einer Minute gesehen haben.
00:14:23Unsere Aufgabe ist es herauszufinden, wie wir alle Tool-Informationen aus jedem dieser Worker extrahieren und dieses
00:14:29tools-Objekt befüllen können. Das wird an einen Tool-Loop-Agenten übergeben. Das ist einfach Teil des von Vercel
00:14:35erstellten KI-SDKs. Und dann senden wir die Nachricht des Benutzers an diesen Agenten, streamen die Ausgabe und schreiben
00:14:42sie aus dem Skript heraus in die Standardausgabe. Das Erste, was wir herausfinden müssen, ist, wie wir einfach den Quellcode
00:14:48hochladen. Dieser Teil ist ziemlich einfach und geht recht schnell. Anstatt live zu coden, werde ich einfach
00:14:53zwischen diesen Abschnitten hin und her springen, damit Sie mir nicht beim Tippen zusehen müssen. Ich verspreche, dass ich Code schreiben kann,
00:14:59nur will das meiner Ansicht nach niemand sehen. Wenn wir also ein wenig nach vorne springen, haben wir diese Funktion
00:15:06namens upload source, auf die ich noch eingehen werde. Sie sehen jedoch, dass ich das Vercel Blob SDK importiert habe. Das ist hier
00:15:13ziemlich einfach. Wenn wir uns diese upload source-Funktion ansehen, rufen wir im Grunde nur diese put-
00:15:20Funktion auf. Und wir sagen, dass wir das Bundle dieses Benutzers unter dem Namen des Workers Schrägstrich bundle.tar.gzip speichern möchten.
00:15:29Wir streamen die Datei von der Festplatte und speichern sie im Blobspeicher. Sobald das erledigt ist,
00:15:35sind wir in der Lage, Sandboxes aus diesem Blob zu erstellen. Damit ist der Upload-Teil gelöst.
00:15:43Als Nächstes müssen wir diesen gebündelten Quellcode nehmen und daraus
00:15:49eine Sandbox erstellen. Dazu habe ich das Vercel Sandbox SDK importiert. Es gibt noch eine Hilfsfunktion
00:15:56weiter unten namens create sandbox. Ich überspringe ein paar Teile davon. Im Wesentlichen tun wir jedoch Folgendes:
00:16:03Wenn wir dieses Objekt im Blobspeicher haben, verwenden wir vor signierte URLs, die wir an den
00:16:10Sandbox-Dienst übergeben. Damit der Sandbox-Dienst – ich glaube, dies ist auf eine Ablauffrist von 10 Minuten eingestellt –
00:16:16diesen Blob aus dem Blobspeicher abrufen und zum Füllen einer Sandbox verwenden kann. Dies ist eines der
00:16:23Features, die mir an der Vercel Sandbox wirklich gefallen, nämlich dass sie mit solchen Tarballs funktioniert. Es ist einfach,
00:16:28ein Tarball aus Benutzercode zu erstellen, und ein Sandbox-Dienst, der eine Sandbox aus einem Tarball erstellen möchte,
00:16:35ruft es aus dem Speicher oder einer beliebigen URL ab und entpackt dieses Tarball automatisch im
00:16:40Stammverzeichnis des Workspaces. Alle Dateien sind also einfach da und bereit für die Arbeit. Das geschieht einfach durch den Aufruf von
00:16:46sandbox.create. Wir sind noch nicht beim super komplizierten Teil angelangt, aber wir kommen bald dorthin.
00:16:52Eine andere Sache ist, dass ich in diesem Beispiel der Kürze halber bei jedem einzelnen Ausführen
00:16:57ganz neue Sandboxes erzeuge. In der Realität möchte man Snapshotting verwenden, damit man nicht ständig – jedes Mal,
00:17:02wenn ein Tool aufgerufen wird – die Sandbox neu bereitstellt oder sie aus dem Vercel-Blobspeicher
00:17:09oder einem anderen Cloud-Blobspeicher neu streamt. In die Plattform ist im Grunde ein Caching-Mechanismus
00:17:15integriert. Ich habe ihn hier der Einfachheit halber übersprungen.
00:17:19Das ist also das Erstellen der Sandbox, und hier wird es nun interessant.
00:17:23Als Nächstes müssen wir Informationen über die Tools extrahieren,
00:17:31die in diesem Worker definiert sind, und zwar aus der soeben erstellten Sandbox.
00:17:36Ich halte hier mal ganz kurz an und habe ein paar Tipps, die ich
00:17:40verteilt habe. Generell gilt: Wenn Sie einen produktionsreifen Dienst wie diesen
00:17:44aufbauen, sollten Sie immer sicherstellen, dass Sie Ihr Bestes geben, um Ihre Sandboxes zu stoppen. Sie werden also sehen,
00:17:51was extract tools tut, aber wenn wir damit fertig sind, stellen wir sicher, dass wir die Sandbox explizit löschen.
00:17:56In der Realität möchten Sie außerdem sicherstellen, dass Sie wahrscheinlich einen asynchronen Bereinigungsjob
00:18:00oder etwas Ähnliches in die Warteschlange stellen. Sie möchten nicht, dass diese Sandboxes unbegrenzt weiterlaufen.
00:18:06Schauen wir uns also an, was die extract tools-Funktion macht. Wir haben unsere Sandbox, und ich mag diese
00:18:15Beispiele wirklich, weil es so herrlich einfach aussieht, aber es funktioniert wirklich, wirklich gut. Wir führen also einen
00:18:23Node-Befehl aus, und zwar mit der Node-Binärdatei in der Sandbox. In dem Skript importieren wir das Modul,
00:18:30das der Benutzer geschrieben hat, nämlich index.js. Wir konvertieren das Objekt in einen String und rufen dann
00:18:36console.log auf. Man muss dabei bedenken, dass Sandboxes kein Webserver sind, an den man
00:18:42eine Anfrage senden und eine Antwort erhalten kann. Die gesamte Ein- und Ausgabe erfolgt über die Ausführung eines Befehls,
00:18:48und dann kann man ihn eine Antwort an einen Dienst senden lassen, den man abruft, oder in diesem Fall lässt man ihn
00:18:52einfach in die Standardausgabe schreiben. Ein paar Tipps dazu: Normalerweise möchte man nicht einfach console.log verwenden und allen
00:19:00Ausgaben vertrauen, die man von der Sandbox erhält. Es könnte andere Pakete geben, die der Benutzer installiert hat, oder
00:19:07anderer Code, den er ausführt und der zeitgleich Dinge in den Standardausgabestream schreibt.
00:19:12Daher ist es gut, die Ausgabe in eine Art Tag einzupacken, das man parsen kann.
00:19:18Das ist wie ein XML-ähnliches Tag, das wir hier verwenden würden. Ich mache das in diesem Beispiel nur nicht.
00:19:23Sie möchten außerdem sicherstellen, dass Sie die Größe der Protokolle, die Sie verarbeiten, begrenzen. Ich sammle
00:19:29in diesem Beispiel einfach alle Ausgaben in einem Stream. In einer produktionsreifen Anwendung möchten Sie das nicht tun,
00:19:34denn das können Gigabyte an Streams sein und Ihre Server stürzen wegen Speichermangels (OOM) ab.
00:19:39Daher bietet die Sandbox-API auch Befehle zum Streamen der Protokolle an. Genau das machen wir
00:19:45bei Notion Workers: Wir konsumieren diesen Stream im Wesentlichen, bis wir den Beginn des Ausgabetokens sehen,
00:19:53das uns interessiert. Dann beginnen wir mit dem Puffern dieser Beschreibung, also dem, was wir absichtlich protokolliert haben.
00:19:58Und wir stoppen die Verarbeitung des Ausgabestreams, sobald wir unser schließendes Tag erreichen. Wenn also in der Sandbox
00:20:04etwas Seltsames schiefgeht und riesige Mengen an Daten protokolliert werden,
00:20:08wird das nicht alles im Arbeitsspeicher gesammelt. Wir können es einfach verwerfen und warten, bis wir die Daten erhalten, die uns interessieren.
00:20:14Sobald dieser Befehl also läuft, warten wir, bis er beendet ist, und greifen auf seine Standardausgabe zu.
00:20:22Und wenn Sie schon mal Zod verwendet haben, dürfte Ihnen das ziemlich bekannt vorkommen. Wir parsen den String einfach als JSON.
00:20:27Und dann haben wir hier einen Zod-Typ,
00:20:31der validiert, dass er die gewünschte Form hat.
00:20:34Es ist wirklich wichtig, diesen Daten nicht einfach zu vertrauen, da es sich um nicht vertrauenswürdigen Benutzercode handelt. Man hat keine Ahnung,
00:20:39was die Leute protokollieren könnten. Man möchte also sicherstellen,
00:20:43dass man die Größe und die allgemeine Form validiert. In diesem Fall erwarten wir also
00:20:50ein Record, dessen Schlüssel, der String, jeweils der Name unserer Tools sein wird.
00:20:57Und die Objekte werden die Beschreibung sowie das Eingangsschema sein, also jenes
00:21:02JSON-Schema. Ihnen fällt vielleicht auf, dass die Ausführungsfunktion hier nicht dabei ist. Das wird
00:21:06einfach nicht zurückgegeben, was praktisch ist, da JSON.stringify Dinge überspringt, die nicht
00:21:11serialisierbar sind. Sie werden also quasi ignoriert. Wir erhalten also nur die Beschreibung und das Eingangsschema.
00:21:18Wenn wir also hierher zurückgehen, haben wir unsere Worker-Tools, die jenes
00:21:23Record jedes Workers und jedes Tools darstellen, das in diesem Worker offengelegt wurde.
00:21:28Als Nächstes bringen wir diese Daten in das Format, das das AI SDK erwartet.
00:21:36Und wir müssen jedem dieser Tools eine Ausführungsfunktion zuordnen.
00:21:42Wir haben natürlich keine Ausführungsfunktion erhalten, als wir Dinge einfach in die Standardausgabe protokolliert haben.
00:21:46Die Frage lautet nun: Wie stellen wir, da wir diese Beschreibung des Tools haben,
00:21:51eine Funktion bereit, die das SDK jedes Mal aufrufen kann, wenn es diesen Worker oder dieses von diesem Worker bereitgestellte Tool aufrufen möchte?
00:21:58Ich habe hier diesen kleinen Wrapper namens execute tool. Schauen wir uns an, was er tut.
00:22:04Das sollte jetzt ziemlich vertraut wirken. Es ruft dieselbe create sandbox-Funktion auf, erstellt also
00:22:10eine neue Sandbox. Selbst wenn man Caching verwendet, gibt es ein Feature von Vercel Sandboxes namens
00:22:16Persistenz, bei dem jedes Mal, wenn die Sandbox angehalten oder gestoppt wird, der Status zwischengespeichert wird, wie alles auf der Festplatte.
00:22:23Für ein Feature wie dieses möchte man das eigentlich nicht. Man möchte einen Schnappschuss des Anfangszustands,
00:22:28der den gesamten Benutzercode enthält. Aber im Allgemeinen möchte man danach sicherstellen, dass jedes Mal,
00:22:33wenn dieses Tool ausgeführt wird, wahrscheinlich eine völlig frische Instanz vorliegt. Auf diese Weise verschmutzt ein Durchlauf eines Tools,
00:22:38falls etwas schiefgeht, nicht die Umgebung des Tools, das danach ausgeführt wird.
00:22:43Wir erstellen also eine neue Sandbox und führen ein weiteres Node-Skript darin aus. Das sollte ziemlich vertraut aussehen,
00:22:49unterscheidet sich aber ein wenig. Wir importieren das vom Benutzer geschriebene Modul. Wir greifen auf das Tool
00:22:56aus diesem Modul zu, bei dem es sich einfach um den Toolnamen handelt, den wir beim Erstellen dieses execute tool-Wrappers erhalten haben.
00:23:03Wir rufen diese execute-Funktion dafür auf und übergeben ihr die Eingabe,
00:23:09die vom Modell bereitgestellt wurde. Hier typisiere ich dies einfach als unknown. Das ist hier jedoch ziemlich sicher,
00:23:19weil wir folgendes bereitgestellt haben – habe ich das hier nicht gemacht? Ich habe das in diesem Beispiel womöglich übersprungen. Aber was
00:23:27man normalerweise tun würde – oh doch, ich glaube schon. Springen wir mal kurz hier nach oben. Ja. Wenn wir also
00:23:34unsere Tools bearbeiten, um sie an den Agenten zu senden, nehmen wir dieses JSON-Schema und wandeln es
00:23:39wieder in einen Zod-Typ um. Wir müssen also kein Parsing selbst vornehmen. Das AI SDK, der Tool-Loop-Agenten-Code,
00:23:46validiert jedes Mal, wenn dieses Tool aufgerufen wird, die vom Agenten kommende Eingabe für uns.
00:23:52Wir können also mehr oder weniger darauf vertrauen, dass dieser Wert dem entspricht, was wir erwarten. Wir übergeben ihn also
00:23:56hier an die execute-Funktion. Wenn diese asynchrone Funktion dann abgeschlossen ist, werden wir sie
00:24:03stringifizieren. Wir protokollieren sie in der Standardausgabe. Und dann warten wir – ich komme gleich
00:24:10auf diese Dinge hier zu sprechen. Wir warten darauf, dass dieser Befehl abgeschlossen wird. Und auch hier werden wir
00:24:14unsere Sandbox löschen und sind damit fertig. Danach parsen wir das JSON, welches den Rückgabewert
00:24:21jener vom Benutzer geschriebenen Ausführungsfunktion darstellt. Und diesen senden wir an den Tool-Loop-Agenten
00:24:26zurück. Im Wesentlichen sieht der Ablauf so aus: Der Tool-Loop-Agent sagt, ich möchte das Tool zur Routenplanung aufrufen,
00:24:35das wir vorhin gesehen haben, wo all diese Transit-APIs verwendet werden. Das ruft schließlich diese Funktion hier auf,
00:24:40mit welchen Eingaben auch immer der Agent beschließt. Wir erstellen eine Sandbox mit dem Blob, den wir zuvor aus dem
00:24:48kompilierten Code des Benutzers hochgeladen haben. Dann führen wir einen Befehl auf dieser Sandbox aus, bei dem wir die Ausführungsfunktion
00:24:55des Benutzers aufrufen. Wir warten darauf, dass diese Funktion einen Wert zurückgibt. Und dann protokollieren wir diesen Rückgabewert in der
00:25:00Standardausgabe, parsen ihn und senden ihn an den Agenten zurück, der daraufhin die Tool-Schleife fortsetzt
00:25:05und entweder einen weiteren Tool-Aufruf tätigt oder dem Benutzer antwortet. Hier noch ein paar schnelle Tipps. Dieselben
00:25:13Ausgabeverifizierungsregeln gelten in einem Produktionssystem. Auch hier möchte man sicherstellen, dass Benutzer kein Objekt zurückgeben können,
00:25:19das zum Parsen etwa zwei Gigabyte oder so benötigt. Man möchte außerdem
00:25:28wahrscheinlich ein SDK bereitstellen. Das machen wir in diesem Beispiel zwar nicht, aber im Notion Workers SDK
00:25:35sind die Typen so eingerichtet, dass der Rückgabewert dieser Ausführungsfunktion JSON-serialisierbar sein muss.
00:25:41Das ist eine wirklich leicht zu tappende Stolperfalle für Ihre Benutzer: Wenn Sie es so einrichten, dass diese Funktion
00:25:47beliebige Werte zurückgeben kann, geben sie am Ende Dinge zurück, die nicht als JSON serialisiert und dann
00:25:52über die Leitung via Standardausgabe gesendet und geparst werden können. Und sie werden sehr verwirrt sein und nicht verstehen, warum der
00:25:57Worker nicht läuft. Und das ist eine kleine Geschichte, die sich bei Notion Workers zugetragen hat: Man möchte
00:26:05auch immer sehr sorgfältig sicherstellen, dass der Prozess, der Node-Prozess, den man hier startet,
00:26:11unter allen Umständen beendet wird. Wir hatten einen Bug bei Notion, bei dem der Code von Benutzern lief und bis zum Ende
00:26:18durchlief. Aber aus irgendeinem Grund wurde dieser Node-Prozess nicht beendet. Er hing einfach fest, bis der
00:26:25Lebenszyklus der Sandbox abgelaufen war, was etwa fünf Minuten dauerte. Es war also nicht katastrophal,
00:26:30verschwendete aber Ressourcen. Und was wir herausfanden oder uns ins Gedächtnis riefen – ich hatte völlig vergessen, dass dies
00:26:38eine Eigenschaft der Node-Runtime ist –, war, dass Benutzer Code ausgeführt hatten, der Timer mit
00:26:44setInterval oder setTimeout einrichtete. Insbesondere Intervalle oder schwebende Promises tun meines Erachtens dasselbe.
00:26:52Wenn das Skript läuft und irgendwelche Intervalle oder ähnliches aktiv sind, wird der Node-Prozess
00:26:58niemals zurückkehren. Er wird sich nicht von alleine beenden, bis all diese Timer abgelaufen sind. Wenn es also ein
00:27:03Intervall ist, läuft es einfach ewig weiter, bis die Sandbox stirbt. Man möchte also immer sicherstellen, dass
00:27:08wenn der Code oder die Funktion, die man auszuführen versucht, tatsächlich abgeschlossen ist, man
00:27:14dem Prozess ausdrücklich befiehlt sich zu beenden. So wird die Sandbox gestoppt und der Prozess kehrt danach zurück.
00:27:23Das ist also im Grunde der gesamte Workflow. Ich werde ihn noch einmal ausführen und das
00:27:29Debugging aktivieren, damit Sie sehen können, was passiert.
00:27:42Wir stellen also zuerst unseren Abfahrten-Worker bereit. Ich gehe das gleich Schritt für Schritt durch. Wir stellen den
00:27:48Abfahrten-Worker bereit, indem wir zuerst dieses Bundle hochladen. Wir erstellen eine Sandbox, die wir nutzen werden, um Informationen
00:27:54über diesen Worker zu extrahieren. Wir haben diese Tools extrahiert. Das ist also das Ergebnis, wenn wir die
00:28:01Inhalte des Moduls in die Standardausgabe schreiben. Wir erhalten die Schlüssel für jedes Tool, die Beschreibung und das Eingangsschema.
00:28:08Wir machen dasselbe für den einfachen Greeter-Worker. Dann nehmen wir all das und übergeben es an den Agenten,
00:28:13damit dieser Tool-Aufrufe tätigen und dem Benutzer antworten kann. Das war's auch schon im Wesentlichen. Ein recht einfaches
00:28:19Beispiel dafür, wie man nicht vertrauenswürdigen Benutzercode nehmen, irgendwo speichern, auf sichere Weise etwas darüber lernen kann,
00:28:26sodass man ihn in einem dauerhaften Speicher ablegen oder direkt an Agenten senden kann, um diesen die sichere
00:28:31Ausführung des Codes zu ermöglichen. Uns bleiben noch etwa 10 Minuten. Wenn jemand Fragen hat, wenn Sie etwas zu
00:28:39Notion Workers, der Arbeit mit Vercel Sandbox im Allgemeinen oder der Ausführung von nicht vertrauenswürdigem Code wissen möchten,
00:28:46unterhalte ich mich gerne darüber. Danke.
00:28:56Ach ja. Und im Anschluss, falls Sie über die Notion Developer Platform im Allgemeinen sprechen möchten,
00:29:01können Sie mich oder meine Kollegin MJ hier ansprechen. Sie ist die Produktmanagerin für die Developer Platform bei Notion.
00:29:08Hi. Das ist eine operative Frage, aber wie schränkt man das ein, da Benutzer ja im Grunde alles tun können?
00:29:15Ja. Es könnten ja mehrere Benutzer ein ähnliches Tool schreiben.
00:29:20Mehrere Nutzer was? Die ein ähnliches Tool schreiben. Zum Beispiel wie das Planen einer New-York-Reise.
00:29:24Ja. Man könnte 10 verschiedene Benutzer mit 10 verschiedenen Codes haben. Ja. Die dasselbe tun.
00:29:29Ja. Gibt es etwas, das Sie tun, um das zu blockieren, oder überlässt man das einfach dem Agenten?
00:29:33Nein. Wenn mehrere Benutzer alle dasselbe tun wollen, lassen wir sie das einfach machen.
00:29:37Das ist teilweise eine Produktfrage. Wenn es sich beispielsweise um mehrere Benutzer in derselben Organisation handelt,
00:29:42will man sicherstellen – es ist also sowohl eine operative als auch eine Produktfrage.
00:29:46Man möchte sicherstellen, dass man gute Freigabeprimitiven und dergleichen hat. Sodass ich nachschauen
00:29:50und suchen kann: Gibt es bereits einen Worker, der diese Aufgabe erledigt? Damit sie sie nicht
00:29:55neu schreiben. Aber im Großen und Ganzen auf Platform-Ebene tun wir nichts dergleichen – es ist sehr unwahrscheinlich, dass Benutzer
00:30:02identischen Code bereitstellen. Und es lohnt sich einfach nicht zu versuchen, das zu deduplizieren.
00:30:19Okay. Ja, ich schätze, wir haben noch ein paar weitere. Ich bin mir nicht sicher, wer das Mikrofon hat.
00:30:24Ich habe es nicht gehört. Oh, ja. Es tut mir so leid.
00:30:29Ich dachte, das wäre über die Kopfhörer zu hören gewesen.
00:30:33Ah ja. Die gestellte Frage lautete: Wenn viele Benutzer denselben Code bereitstellen,
00:30:40tun wir dann etwas, um das irgendwie operational zu handhaben? Und das tun wir nicht. Das ist eher eine Produktfrage.
00:30:45Wir möchten sicherstellen, dass Benutzer nicht dieselbe Arbeit doppelt machen. Deshalb wünschen wir uns gute Freigabeprimitiven,
00:30:50an denen wir gerade für Notion Workers arbeiten. Aber auf Plattformebene, ganz operativ gesehen,
00:30:54ist es uns egal, wenn Leute denselben Code 50 Mal bereitstellen.
00:30:56Haben Sie Probleme damit, dass Worker in Timeouts laufen, weil die Sandbox schlicht
00:31:04ihr Ding macht und zu früh stirbt?
00:31:07Wie lautete die Frage genau bezüglich Timeouts?
00:31:10Haben Sie Probleme mit Timeouts zwischen Vercel – also anderen Produkten und Workflows
00:31:15zum Beispiel – und Ihren Sandboxes? Oder läuft einfach alles glatt?
00:31:20Ja, wir hatten damit keinerlei Probleme. Die Plattform war für uns bisher
00:31:25absolut solide. Das ist keine Schleichwerbung, ich meine das ernst. Sie war wirklich gut.
00:31:32Wir stoßen eher auf Probleme, wenn Benutzer versehentlich das Falsche tun. Im Laufe der Zeit
00:31:36geht es also eher darum, diese Stolperfallen zu beseitigen und die Plattform für Entwickler und Nicht-Entwickler
00:31:42gleichermaßen immer einfacher zu machen. Cool, das war klasse. Ich wollte fragen,
00:31:48ich schätze, wenn Sie den ursprünglichen Benutzercode stringifizieren. Ich nehme an, Sie wollen sicherstellen,
00:31:52dass er entweder sicher ist oder ausgeführt werden kann. Ich glaube – ich wollte wohl noch etwas mehr dazu fragen.
00:31:57Sie meinten, Sie stringifizieren den Code und erhalten quasi die Worker-Tags, um die gewünschten Eingaben
00:32:04für den Code des Benutzers sowie eine Beschreibung dieses Tools zu bekommen. Ist das für die Notion-Agenten,
00:32:10damit Ihr Agent den Code ausführt? Denn mir ist aufgefallen, dass Sie die Ausführungsfunktion des Benutzers
00:32:15oder den Executor ohnehin schon ausführen. Daher war ich neugierig, warum Sie – ich nenne es mal – diesen zusätzlichen Schritt tun,
00:32:21um die Eingaben und die Beschreibung des Tools selbst zu erhalten.
00:32:24Das ist eine gute Frage. Im echten Produkt ist das etwas klarer, aber hier wurde es vereinfacht.
00:32:29Die Frage lautet im Grunde: Warum führe ich den Benutzercode einmal aus, um Informationen über den
00:32:34Worker zu erhalten, und dann noch einmal, wenn der Tool-Code aufgerufen wird? Der Grund dafür ist, dass der Agent,
00:32:39bevor er das Tool überhaupt aufrufen oder von der Existenz des Tools wissen kann, erfahren muss,
00:32:45was in diesem Tool enthalten ist, um es dem Agenten dann über das SDK bereitzustellen. Was also bei Notion
00:32:50Workers passiert, wenn man beispielsweise ntn workers deploy ausführt: Wir durchlaufen die Build-Pipeline,
00:32:55die Sandbox, die den Build ausführt, nimmt das Tarball und legt es irgendwo im Speicher ab. Wir starten –
00:33:02ich glaube, das machen wir in einem neuen Worker –, wo wir den Namen der Tools, die Beschreibungen und die
00:33:09Schemata extrahieren und sie beispielsweise in DynamoDB speichern. Auf diese Weise müssen wir danach
00:33:14keine Sandboxes mehr ausführen, bis das Tool tatsächlich aufgerufen wird. Sie erwähnten das Tarball-System. Das interessiert mich schätze ich am meisten.
00:33:21Wie funktioniert das in Bezug auf die Distribution genau, wenn es um das Tarball geht?
00:33:26Gibt es im Moment so etwas wie einen offenen Marktplatz oder wie funktioniert die Distribution?
00:33:31Ach so, was im eigentlichen Tarball drin ist? Ja, genau.
00:33:33Wir haben – nun, rein mechanisch gesehen, was in dieses Tarball wandert –,
00:33:38wir verwenden im Moment einfach ES build. Die Art und Weise, wie die eigentliche Deploy-Pipeline funktioniert, ist: Man führt
00:33:47ntn workers deploy aus, ruft einen API-Endpunkt auf, der eigene Computer erhält eine signierte URL, bündelt
00:33:52den gesamten Quellcode, wir erstellen ein Tarball mit dem Quellcode, führen einen Build-Prozess mit ES build auf
00:33:58jener Sandbox aus, und die Ausgabe wird wieder im Blob-Speicher abgelegt, damit wir die eigentliche Sache von dort aus
00:34:04ausführen können. Wir haben noch keinen echten Marktplatz für Worker. Wir arbeiten vorerst an Freigabeprimitiven
00:34:11innerhalb eines Notion-Workspaces, aber es gibt definitiv Pläne für eine Art Worker-Marktplatz in der Zukunft.
00:34:18In der Zwischenzeit können Sie diese jedoch einfach auf GitHub verteilen, und das funktioniert hervorragend. Das tun die Leute heute.
00:34:23Ja, einfach ein Repo veröffentlichen, und jemand kann es klonen, ntn workers deploy ausführen und es selbst nutzen.
00:34:29Ja.
00:34:34Ich glaube, da hinten ist noch eine Frage.
00:34:37Ja, ich habe eine Frage zur Abrechnung.
00:34:40Zur Abrechnung?
00:34:40Ja, ich habe mir das gerade angeschaut – verraten Sie natürlich nicht alle Ihre Geheimnisse,
00:34:44aber ich habe eine kurze Google-Suche gemacht. Es sieht so aus, als würden benutzerdefinierte Agenten über ein Creditsystem arbeiten. Ich
00:34:48schätze, das ist an den Ressourcenverbrauch gekoppelt.
00:34:51Ja, ja.
00:34:51Wie funktioniert das im groben Überblick mit der Vercel-Plattform?
00:34:54Okay, die Frage lautet also: Wie funktioniert die Abrechnung dafür mit der Vercel-Plattform?
00:35:02Einer der Vorteile von Workern besteht darin, dass man solche schreiben kann – viele Teams konnten von
00:35:08einem riesigen Anweisungssatz mit MCP-Servern wegkommen, die sie ihren Agenten bereitgestellt haben. Und jedes Mal, wenn sie eine Aufgabe aufrufen,
00:35:16verbraucht dieser Agent Unmengen von Denk-Tokens, um im Grunde immer wieder dasselbe zu tun.
00:35:21Wenn man also diese repetitiven Aufgaben, die der Agent erledigt, nehmen und als Worker bereitstellen kann,
00:35:33wird zwar weiterhin die Ausführungszeit der Worker berechnet, aber das ist sehr viel kostengünstiger als KI-Rechen-Tokens.
00:35:40Wenn man also einen benutzerdefinierten Agenten betreibt, denkt er ein wenig nach, führt ein Tool aus und denkt dann weiter nach.
00:35:48Man bezahlt für den Token-Verbrauch im benutzerdefinierten Agenten, den dieser vor dem Aufruf des Tools erzeugt.
00:35:53Wenn das Tool läuft, wird man zu einem anderen Satz berechnet, der Credits – die Notion-AI-Credits – zu einem weitaus geringeren Satz verbraucht.
00:36:01Und dann wird wieder normal für KI-Credits abgerechnet, wenn der Agent schliesslich antwortet.
00:36:05Wenn man also Notion Custom Agents nutzt, ist dies eine Möglichkeit, bei repetitiven Aufgaben enorme Kosten einzusparen.
00:36:16Das stimmt ebenfalls. Man muss auch nicht zwingend Notion AI haben – wir zeigen hier zwar Tool-Aufrufe, die sich in Notion AI integrieren.
00:36:24Aber Worker führen auch Synchronisierungen von Drittanbietern nach Notion durch. Das erfordert keinerlei KI-Funktionen.
00:36:31Es ist also nicht nur ein KI-Produkt. Die Leute nutzen das auch für Synchronisierungen.
00:36:36Ich habe Worker, die meinen Letterboxd-Feed mit Notion synchronisieren. Das ist für mich persönlich der wichtigste.
00:36:46Gut. Noch irgendetwas?
00:36:52Gibt es noch eine Frage?
00:37:06Ah, sie über die eigene Benutzeroberfläche preiszugeben – also Notion Custom Agents über die eigene Oberfläche anzubieten.
00:37:13Das ist derzeit noch nicht möglich.
00:37:16Es tut mir leid. Danke, MJ. Die Frage lautet: Wenn man eigene Worker und Custom Agents hat,
00:37:22gibt es eine Möglichkeit, diese über die eigene Anwendung für die eigenen Verbraucher bereitzustellen?
00:37:28Und heute gibt es dafür noch keinen Weg. Wir haben eine Alphaversion einer Custom-Agent-API, mit der das
00:37:35durchaus möglich wäre. Wenn man Custom Agents und Worker oder Custom Agents in seinem Workspace definiert,
00:37:40könnte man eine API verwenden, um diese Agenten aufzurufen und eine Streaming-Antwort zu erhalten. Es ist also machbar.
00:37:46Ich glaube nicht, dass das schon unzählige Leute tun. Und das ist eine noch sehr frühe Alpha – öffentlich, aber eben ein Alpha-Feature.
00:37:57Weitere Fragen?
00:38:00Alles klar. Gut, vielen Dank, dass Sie sich die Zeit genommen haben,
00:38:04heute hierher zu kommen und zuzuhören. Und ja, wenn Sie Fragen zu Notion, Notion Workers
00:38:08oder Vercel Sandbox haben, sprechen Sie MJ oder mich an. Danke.

Description

Vercel.com

Community Posts

View all posts