You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何借助StreamingTextResponse传递消息元数据至useChat?

解决方案

服务端修改

问题出在你直接使用BytesOutputParser传递原始流,且提前关闭了StreamData。正确做法是结合LangChain的流式回调,将文本内容与元数据分开处理:

import { NextRequest, NextResponse } from "next/server";
import { experimental_StreamData, Message as VercelChatMessage, StreamingTextResponse } from "ai";
import { ChatOpenAI } from "langchain/chat_models/openai";
import { PromptTemplate } from "langchain/prompts";

export async function POST(req: NextRequest) {
  try {
    const body = await req.json();
    const messages: VercelChatMessage[] = body.messages ?? [];
    const currentMessageContent = messages[messages.length - 1].content;

    const model = new ChatOpenAI({
      temperature: 0,
      streaming: true,
    });
    const prompt = PromptTemplate.fromTemplate(`
      You are a cheerful bot that should respond to all questions in an upbeat manner.
      
      User input: {input}
      
      AI response:
    `);

    const formattedPrompt = await prompt.format({ input: currentMessageContent });
    const data = new experimental_StreamData();
    
    // 发送元数据(可在流开始/过程中随时发送)
    data.append({ timestamp: new Date().toISOString() });

    // 创建可读流处理模型输出
    const stream = new ReadableStream({
      async start(controller) {
        const encoder = new TextEncoder();
        try {
          await model.stream(formattedPrompt, {
            onChunk(chunk) {
              // 将文本片段写入响应流
              controller.enqueue(encoder.encode(chunk.content));
            },
            onEnd() {
              // 流结束后关闭元数据通道
              data.close();
              controller.close();
            },
          });
        } catch (e) {
          controller.error(e);
        }
      },
    });

    return new StreamingTextResponse(stream, {}, data);
  } catch (e: any) {
    return NextResponse.json({ error: e.message }, { status: 500 });
  }
}

客户端处理

使用useChat时,可通过message.data直接获取传递的元数据:

"use client";

import { useChat } from "ai/react";

export default function ChatComponent() {
  const { messages, input, handleInputChange, handleSubmit } = useChat({
    api: "/api/chat",
    // 消息更新时获取元数据
    onMessageUpdate: (message) => {
      if (message.data) {
        console.log("实时元数据:", message.data);
      }
    },
    // 消息完成时获取元数据
    onFinish: (message) => {
      if (message.data) {
        console.log("最终元数据:", message.data);
      }
    },
  });

  return (
    <div>
      {messages.map((m) => (
        <div key={m.id}>
          <p>{m.role}: {m.content}</p>
          {m.data && <p>元数据: {JSON.stringify(m.data)}</p>}
        </div>
      ))}
      <form onSubmit={handleSubmit}>
        <input
          value={input}
          onChange={handleInputChange}
          placeholder="输入问题..."
        />
        <button type="submit">发送</button>
      </form>
    </div>
  );
}

关键注意点

  1. 不要提前调用data.close(),需等到模型流结束后再关闭,保证元数据通道与文本流同步。
  2. 避免使用BytesOutputParser,手动处理流式chunk可确保响应格式符合StreamingTextResponse要求。
  3. useChat会自动解析StreamData并挂载到message.data,无需手动处理流的底层格式。

内容的提问来源于stack exchange,提问作者Aram Boyajyan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 12:25:14