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

Next.js+ai npm包调用OpenAI API,流式响应无换行如何格式化?

解决流式返回内容不换行的问题

前端渲染层处理

HTML默认会将文本中的换行符(\n)合并为空格,可通过以下两种方式修复:

  1. CSS样式快速处理
    给消息容器添加white-space: pre-line样式,该样式会保留换行符并自动合并连续空格,适合纯文本格式的内容:
// 修改page.js中的消息渲染部分
{messages.map(m => (
  <div key={m.id} style={{ whiteSpace: 'pre-line' }}>
    {m.role}: {m.content}
  </div>
))}
  1. 转换为HTML标签精确控制
    如果需要区分单换行和段落分隔的双换行,可以将文本中的换行符替换为<br>标签,通过dangerouslySetInnerHTML渲染:
{messages.map(m => (
  <div key={m.id}>
    <span>{m.role}: </span>
    <span dangerouslySetInnerHTML={{ 
      __html: m.content.replace(/\n\n/g, '<br><br>').replace(/\n/g, '<br>') 
    }} />
  </div>
))}

注意:使用dangerouslySetInnerHTML时需确保内容可信,避免XSS风险。

借助OpenAI的格式化输出

可以通过以下方式让OpenAI返回结构化的格式化内容:

  1. Prompt指定输出格式
    在对话消息中明确要求模型返回Markdown格式,例如在系统消息中添加:
请使用Markdown格式回复,段落之间用空行分隔。

之后前端使用react-markdown库渲染Markdown内容:

// 先安装依赖:npm install react-markdown
import ReactMarkdown from 'react-markdown';

// 渲染消息时
{messages.map(m => (
  <div key={m.id}>
    {m.role}: <ReactMarkdown>{m.content}</ReactMarkdown>
  </div>
))}
  1. 使用Response Format参数(GPT-4-1106-preview+)
    对于支持的模型,可通过response_format参数指定输出为JSON结构,再由前端解析渲染:
// 修改API路由中的调用逻辑
const response = await openai.chat.completions.create({
  model: 'gpt-4-1106-preview',
  stream: true,
  messages: [
    { role: 'system', content: '请返回包含paragraphs数组的JSON,每个元素是一段文本。' },
    ...messages
  ],
  response_format: { type: 'json_object' },
});

修改后的完整示例代码

API路由(app/api/chat/route.js)

import OpenAI from 'openai';
import { OpenAIStream, StreamingTextResponse } from 'ai';

const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
});

export const runtime = 'edge';

export async function POST(req) {
  const { messages } = await req.json();
  const formattedMessages = [
    { role: 'system', content: '请使用Markdown格式回复,段落之间用空行分隔。' },
    ...messages
  ];
  const response = await openai.chat.completions.create({
    model: 'gpt-4',
    stream: true,
    messages: formattedMessages,
  });
  const stream = OpenAIStream(response);
  return new StreamingTextResponse(stream);
}

前端页面(app/page.js)

'use client';

import { useChat } from 'ai/react';
import ReactMarkdown from 'react-markdown';

export default function Chat() {
  const { messages, input, handleInputChange, handleSubmit } = useChat();

  return (
    <div>
      {messages.map(m => (
        <div key={m.id} style={{ margin: '1rem 0' }}>
          <strong>{m.role}:</strong>
          <ReactMarkdown style={{ marginTop: '0.5rem' }}>{m.content}</ReactMarkdown>
        </div>
      ))}

      <form onSubmit={handleSubmit} style={{ marginTop: '2rem' }}>
        <input
          value={input}
          placeholder="Say something..."
          onChange={handleInputChange}
          style={{ padding: '0.5rem', width: '300px' }}
        />
        <button type="submit" style={{ marginLeft: '0.5rem', padding: '0.5rem 1rem' }}>发送</button>
      </form>
    </div>
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 02:25:37