首頁  >  文章  >  web前端  >  使用 Vercel AI SDK 實現多個平行 AI 串流

使用 Vercel AI SDK 實現多個平行 AI 串流

WBOY
WBOY原創
2024-07-17 17:43:02421瀏覽

Multiple Parallel AI Streams with the Vercel AI SDK

Vercel AI SDK 可以輕鬆與 OpenAI、Anthropic 等 LLM API 進行交互,並傳輸數據,以便在加載時快速顯示在您的 Web 應用程式中。在本文中,我們將學習如何同時執行多個提示並並行查看它們的結果。

TL;DR:GitHub 儲存庫在這裡。

我為什麼要這樣做?

在 Web 應用程式中同時執行多個資料取得請求的情況並不罕見。例如,在假設的部落格系統中,當儀表板介面載入時,我們可能希望同時取得使用者的個人資料資料、他們創建的貼文以及他們收藏的其他使用者的貼文。

如果同一個儀表板同時向 OpenAI 發出請求,我們可能希望同時向 OpenAI 詢問有關改善用戶個人資料的提示,並同時分析他們的最新帖子。理論上,如果我們願意的話,我們可以並行使用數十個人工智慧請求(即使來自完全不同的平台和模型),並分析資訊、生成內容並同時執行所有類型的其他任務。

安裝與設定

您可以在此處複製包含最終結果的 GitHub 儲存庫。

從頭開始設定:

  1. 遵循Next.js App Router 快速入門。 只是基礎知識;產生應用程式、安裝依賴項並添加您的 OpenAI API 金鑰。
  2. 安裝並設定 shadcn/ui。

設定基本 UI

完成所有工作的主要元件將包含一個表單和一些用於輸出的容器。使用一些基本的 shadcn-ui 元件,表單將如下所示:

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>
      )
}

你可以看到我們這裡有一些東西:

  • 表格
  • 載入動畫(以及用於顯示/隱藏它的 isGenerate 標誌)
  • 用來渲染天氣內容的容器
  • 用來渲染新聞內容的容器

現在您可以對這些值進行硬編碼;它們都會從我們的資訊流中刪除。

設定 React 伺服器元件 (RSC)

streamAnswer 伺服器操作將完成建立和更新我們的流程的工作。

動作的結構是這樣的:

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,
  };
}

編寫客戶端程式碼

表單的 onSubmit 處理程序將完成這裡的所有工作。以下是其工作原理的詳細說明:

"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.
  );
}

其他有趣的事情可以嘗試

  • 使用streamObject()串流結構化JSON資料而不是文字
  • 並行傳輸更多內容
  • 同時從不同的 API 進行串流
  • 使用相同的提示串流不同模型進行比較(例如,Cohere、Anthropic、Gemini 等)
  • 從伺服器串流 UI(使用 createStreamableUI() )

進一步閱讀和鏈接

  • 伺服器操作與突變
  • Vercel AI SDK
  • StreamText() API 文件
  • Next.js 應用程式路由器快速入門

以上是使用 Vercel AI SDK 實現多個平行 AI 串流的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn