Heim  >  Artikel  >  Web-Frontend  >  Mehrere parallele KI-Streams mit dem Vercel AI SDK

Mehrere parallele KI-Streams mit dem Vercel AI SDK

WBOY
WBOYOriginal
2024-07-17 17:43:02427Durchsuche

Multiple Parallel AI Streams with the Vercel AI SDK

Das Vercel AI SDK erleichtert die Interaktion mit LLM-APIs wie OpenAI, Anthropic usw. und das Streamen der Daten, sodass sie beim Laden schnell in Ihrer Web-App angezeigt werden. In diesem Artikel erfahren Sie, wie Sie mehrere Eingabeaufforderungen gleichzeitig ausführen und ihre Ergebnisse parallel sehen.

TL;DR: GitHub Repo ist da.

Warum sollte ich das tun wollen?

Es ist nicht ungewöhnlich, dass in einer Web-App mehrere Datenabrufanforderungen gleichzeitig ausgeführt werden sollen. Wenn beispielsweise in einem hypothetischen Blogging-System die Dashboard-Oberfläche geladen wird, möchten wir möglicherweise gleichzeitig die Profildaten des Benutzers, die von ihm erstellten Beiträge und die Beiträge anderer Benutzer, die er als Favorit markiert hat, abrufen.

Wenn dasselbe Dashboard gleichzeitig Anfragen an OpenAI sendet, möchten wir OpenAI möglicherweise gleichzeitig um Tipps zur Verbesserung des Benutzerprofils und um eine Analyse seines neuesten Beitrags bitten. Theoretisch könnten wir, wenn wir wollten, Dutzende von KI-Anfragen parallel nutzen (sogar von völlig unterschiedlichen Plattformen und Modellen) und gleichzeitig Informationen analysieren, Inhalte generieren und alle möglichen anderen Aufgaben erledigen.

Installation und Einrichtung

Sie können das GitHub-Repo mit dem Endergebnis hier klonen.

So richten Sie es von Grund auf ein:

  1. Folgen Sie dem Next.js App Router Quickstart.Nur ​​die Grundlagen; Generieren Sie die App, installieren Sie Abhängigkeiten und fügen Sie Ihren OpenAI-API-Schlüssel hinzu.
  2. Shadcn/ui installieren und einrichten.

Einrichten der grundlegenden Benutzeroberfläche

Die Hauptkomponente, die die ganze Arbeit erledigt, enthält ein Formular und einige Container für die Ausgabe. Unter Verwendung einiger grundlegender Shadcn-UI-Komponenten sieht das Formular folgendermaßen aus:

export function GenerationForm() {
    // State and other info will be defined here...

        return (
        <form onSubmit={onSubmit} className="flex flex-col gap-3 w-full">
          <div className="inline-block mb-4 w-full flex flex-row gap-1">
            <Button type="submit">Generate News & Weather</Button>
          </div>

          {isGenerating ? (
            <div className="flex flex-row w-full justify-center items-center p-4 transition-all">
              <Spinner className="h-6 w-6 text-slate-900" />
            </div>
          ) : null}

          <h3 className="font-bold">Historical Weather</h3>
          <div className="mt-4 mb-8 p-4 rounded-md shadow-md bg-blue-100">
            {weather ? weather : null}
          </div>

          <h4 className="font-bold">Historical News</h4>
          <div className="mt-4 p-4 rounded-md shadow-md bg-green-100">{news ? news : null}</div>
        </form>
      )
}

Sie können sehen, dass wir hier ein paar Dinge haben:

  • Ein Formular
  • Eine Ladeanimation (und ein isGenerating-Flag zum Anzeigen/Ausblenden)
  • Ein Container zum Rendern von Wetterinhalten
  • Ein Container zum Rendern von Nachrichteninhalten

Im Moment können Sie diese Werte fest codieren; Sie werden alle aus unseren Streams entnommen.

Einrichten der React Server Components (RSCs)

Die StreamAnswer-Serveraktion übernimmt die Aufgabe, unsere Streams zu erstellen und zu aktualisieren.

Die Struktur der Aktion ist folgende:

export async function streamAnswer(question: string) {
    // Booleans for indicating whether each stream is currently streaming
  const isGeneratingStream1 = createStreamableValue(true);
  const isGeneratingStream2 = createStreamableValue(true);

  // The current stream values
  const weatherStream = createStreamableValue("");
  const newsStream = createStreamableValue("");

    // Create the first stream. Notice that we don't use await here, so that we
    //  don't block the rest of this function from running.
    streamText({
        // ... params, including the LLM prompt
  }).then(async (result) => {
          // Read from the async iterator. Set the stream value to each new word
          //  received.
      for await (const value of result.textStream) {
        weatherStream.update(value || "");
      }
    } finally {
        // Set isGenerating to false, and close that stream.
      isGeneratingStream1.update(false);
      isGeneratingStream1.done();

      // Close the given stream so the request doesn't hang.
      weatherStream.done();
    }
  });

  // Same thing for the second stream.
    streamText({
        // ... params
  }).then(async (result) => {
      // ...
  })

  // Return any streams we want to read on the client.
  return {
    isGeneratingStream1: isGeneratingStream1.value,
    isGeneratingStream2: isGeneratingStream2.value,
    weatherStream: weatherStream.value,
    newsStream: newsStream.value,
  };
}

Schreiben des Client-Codes

Der onSubmit-Handler des Formulars erledigt hier die ganze Arbeit. Hier ist die Aufschlüsselung, wie es funktioniert:

"use client";

import { SyntheticEvent, useState } from "react";
import { Button } from "./ui/button";
import { readStreamableValue, useUIState } from "ai/rsc";
import { streamAnswer } from "@/app/actions";
import { Spinner } from "./svgs/Spinner";

export function GenerationForm() {
    // State for loading flags
  const [isGeneratingStream1, setIsGeneratingStream1] = useState<boolean>(false);
  const [isGeneratingStream2, setIsGeneratingStream2] = useState<boolean>(false);

  // State for the LLM output streams
  const [weather, setWeather] = useState<string>("");
  const [news, setNews] = useState<string>("");

  // We'll hide the loader when both streams are done.
  const isGenerating = isGeneratingStream1 || isGeneratingStream2;

  async function onSubmit(e: SyntheticEvent) {
    e.preventDefault();

    // Clear previous results.
    setNews("");
    setWeather("");

        // Call the server action. The returned object will have all the streams in it.
    const result = await streamAnswer(question);

    // Translate each stream into an async iterator so we can loop through
    //  the values as they are generated.
    const isGeneratingStream1 = readStreamableValue(result.isGeneratingStream1);
    const isGeneratingStream2 = readStreamableValue(result.isGeneratingStream2);
    const weatherStream = readStreamableValue(result.weatherStream);
    const newsStream = readStreamableValue(result.newsStream);

        // Iterate through each stream, putting its values into state one by one.
        //  Notice the IIFEs again! As on the server, these allow us to prevent blocking
        //   the function, so that we can run these iterators in parallel.
    (async () => {
      for await (const value of isGeneratingStream1) {
        if (value != null) {
          setIsGeneratingStream1(value);
        }
      }
    })();

    (async () => {
      for await (const value of isGeneratingStream2) {
        if (value != null) {
          setIsGeneratingStream2(value);
        }
      }
    })();

    (async () => {
      for await (const value of weatherStream) {
        setWeather((existing) => (existing + value) as string);
      }
    })();

    (async () => {
      for await (const value of newsStream) {
        setNews((existing) => (existing + value) as string);
      }
    })();
  }

  return (
    // ... The form code from before.
  );
}

Andere lustige Dinge zum Ausprobieren

  • Streaming strukturierter JSON-Daten anstelle von Text mit streamObject()
  • Viel mehr Dinge parallel streamen
  • Gleichzeitiges Streamen von verschiedenen APIs
  • Streaming verschiedener Modelle mit den gleichen Eingabeaufforderungen zum Vergleich (z. B. Cohere, Anthropic, Gemini usw.)
  • Streamen der Benutzeroberfläche vom Server (mithilfe von createStreamableUI() )

Weiterführende Literatur & Links

  • Serveraktionen und Mutationen
  • Vercel AI SDK
  • streamText() API-Dokumente
  • Next.js App Router-Schnellstart

Das obige ist der detaillierte Inhalt vonMehrere parallele KI-Streams mit dem Vercel AI SDK. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn