如何使用LangChain实现Next.js 13路由处理器的流式API端点?

f2uvfpb9  于 2023-05-28  发布在  其他
关注(0)|答案(1)|浏览(279)

我正在尝试使用Nextjs 13的新路由处理器解决方案创建一个API端点。此API使用LangChain,并将响应流回前端。当调用OpenAI Package 器类时,我传入Streaming属性,并提供回调函数。然后,该回调函数将流作为块(即块)提供。我想将这些令牌流到前端,以便在生成AI响应时输出它。
我能够使用“旧”API路由解决方案通过以下代码实现这一点:

import { OpenAI } from "langchain/llms/openai";

export default async function handler(req, res) {
  const chat = new OpenAI({
    modelName: "gpt-3.5-turbo",
    streaming: true,
    callbacks: [
      {
        handleLLMNewToken(token) {
          res.write(token);
        },
      },
    ],
  });

  await chat.call("Write me a song about sparkling water.");

  res.end();
}

我正在尝试将此代码转换为新的路由处理程序解决方案,但我无法使其工作。
我尝试了很多不同的方法,但都没有成功。
例如:

import { NextResponse } from "next/server";

import { OpenAI } from "langchain/llms/openai";

export const dynamic = "force-dynamic";
export const revalidate = true;

export async function GET(req, res) {
  const chat = new OpenAI({
    modelName: "gpt-3.5-turbo",
    streaming: true,
    callbacks: [
      {
        handleLLMNewToken(token) {
          // res.write(token);
          return new NextResponse.json(token);
        },
      },
    ],
  });

  await chat.call("Write me a song about sparkling water.");
}

似乎没有办法将令牌“写入”响应,因为它们被流式传输到路由处理程序的响应中。
任何帮助将不胜感激。

uttx8gqw

uttx8gqw1#

我想我可能有办法。
在路由处理程序中,我使用TransformStream类创建了一个新的流对象。然后在生成令牌时将它们写入这个流对象。因为流期望向其传输字节,所以我使用TextEncoder将令牌编码为Uint8Array值。
最后,我在API响应中返回流的可读属性。这似乎可以解决问题,尽管比旧的API路由方法的解决方案稍微复杂一些。

import { OpenAI } from "langchain/llms/openai";

export const dynamic = "force-dynamic";
export const revalidate = true;

async function runLLMChain() {
  // Create encoding to convert token (string) to Uint8Array
  const encoder = new TextEncoder();

  // Create a TransformStream for writing the response as the tokens as generated
  const stream = new TransformStream();
  const writer = stream.writable.getWriter();

  const chat = new OpenAI({
    modelName: "gpt-3.5-turbo",
    streaming: true,
    callbacks: [
      {
        async handleLLMNewToken(token) {
          await writer.ready;
          await writer.write(encoder.encode(`${token}`));
        },
        async handleLLMEnd() {
          await writer.ready;
          await writer.close();
        },
      },
    ],
  });
  chat.call("Write me a song about sparkling water.");

  // Return the readable stream
  return stream.readable;
}

export async function GET(req) {
  const stream = runLLMChain();
  return new Response(await stream);
}

相关问题