欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 培训 > Next.js 连接 Angthing llm 实现本地大模型的流式传输

Next.js 连接 Angthing llm 实现本地大模型的流式传输

2025/5/11 9:39:12 来源:https://blog.csdn.net/weixin_72949205/article/details/146056696  浏览:    关键词:Next.js 连接 Angthing llm 实现本地大模型的流式传输

网上针对 Angthing llm 的流式传输教程比较少,几乎都是 Next.js 用  fetch-event-source 连接 Openai 的api

经过我的摸索,终于不用  fetch-event-source 完成了对接本地部署的大模型,特此记录共勉

这里说一下我的需求,如果你想直接看解决方案,请跳过此部分

我使用 Lm Studio 做的 deepseek 本地大模型部署,使用 Angthing llm 进行 RAG 检索

最后需要调用 Angthing llm 的 api 完成对话

首先,为了预防跨域问题,我们把请求封装到后端调用

在 app/api/chat 文件夹下新建 route.js 文件

使用 ReadableStream 来处理流式响应,代码如下

import { NextResponse } from "next/server";
export async function POST(req) {// 构建请求体const apiKey = "HDJF33W-0PN9N2D-H8JCXM9-M92E6MY"; // 这里换成你的api keyconst workspace = "yuwen"; // 这里换成你的工作区名称const ip = "http://localhost:3001"   // 这里换成你的端口const url = `${ip}/api/v1/workspace/${workspace}/stream-chat`;const headers = {"Authorization": `Bearer ${apiKey}`,"Content-Type": "application/json",};const body = await req.json();const response = await fetch(url, {method: "POST",headers: headers,body: JSON.stringify(body),});// 检查响应状态if (!response.ok) {throw new Error(`Server responded with status ${response.status}`);}// 创建一个 ReadableStream 来处理流式响应const stream = new ReadableStream({start(controller) {const reader = response.body.getReader();const decoder = new TextDecoder();const read = () => {reader.read().then(({ done, value }) => {if (done) {controller.close();return;}const chunk = decoder.decode(value, { stream: true });controller.enqueue(chunk);read();});};read();},});return new NextResponse(stream, {headers: {"Content-Type": "text/event-stream","Cache-Control": "no-cache",},});
}

在 app 文件夹下的 page.tsx 中添加点击发送按钮实现对话的功能(这里我默认你已经实现了和ai对话的前端)

流式传输的数据如下所示

我们需要对每行的数据去掉前面的“data:”,让它变成 json 格式,方便提取 textResponse 中的文本

具体代码如下,实现了点击按钮提交用户输入的函数,关键是中间部分对流式数据的读取和处理

        const [studentInput, setStudentInput] = useState("")const handleStudentSubmit = async (e: React.FormEvent) => {e.preventDefault();if (studentInput.trim()) {const newUserMessage = { role: "user", content: studentInput };const userInput = studentInput;setStudentInput("");const newStuMessage = { role: "assistant", content: "正在思考中..." };setStudentMessages([...studentMessages,newUserMessage, newStuMessage]);try {const response = await fetch("/api/chat", {method: "POST",headers: {"Content-Type": "application/json",},body: JSON.stringify({ message: userInput, mode: "chat" }), });// 检查 response.body 是否为 nullif (response.body === null) {throw new Error("响应体为空,无法读取数据");}const reader = response.body.getReader();const decoder = new TextDecoder();// 标记是否是第一次读取数据var mark = false;while (true) {const { done, value } = await reader.read();if (done) break;const chunk = decoder.decode(value);// 按换行符分割字符串const lines = chunk.split("\n");// 遍历每一行for (const line of lines) {if (line.trim()) {// 去除每行开头的 "data: "const jsonStr = line.replace("data: ", "");try {// 解析 JSON 字符串const data = JSON.parse(jsonStr);// 提取 textResponse 字段的值if (data.textResponse) {if(mark){setStudentMessages((prevMessages) => {return [...prevMessages.slice(0, -1),{role: "assistant",content:prevMessages[prevMessages.length - 1].content +data.textResponse,},];}); }else{mark = true;setStudentMessages((prevMessages) => {return [...prevMessages.slice(0, -1),{role: "assistant",content: data.textResponse,},];});}}} catch (error) {console.error("解析 JSON 时出错:", error);}}}}} catch (error) {console.error("Error:", error);}}};

现在就已经实现了流式传输,而且没有跨域问题

还有可以优化的点,就是前端要支持 markdown 的文本格式,这样更美观一些

你可以使用 react-markdown 库,需要安装这个库:

npm install react-markdown remark-gfm

remark-gfm 是一个插件,用于支持 GitHub Flavored Markdown(GFM),包含表格、任务列表等扩展语法

然后,在你的 page.tsx 文件中引入并使用 react-markdown

// ... existing code ...
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
// ... existing code ...{studentMessages.map((message, index) => (<div key={index} className={`flex ${message.role === "user" ? "justify-end" : "justify-start"}`}><divclassName={`max-w-[80%] rounded-lg p-3 ${message.role === "user" ? "bg-primary text-primary-foreground" : "bg-background"}`}>{/* 修改为使用 ReactMarkdown 解析 Markdown 文本 */}<ReactMarkdown remarkPlugins={[remarkGfm]}>{message.content}</ReactMarkdown></div></div>))}
// ... existing code ...

其实就是加了一个 <ReactMarkdown> 包装

最后的效果如下

我使用的模型是 deepseek-r1-distill-qwen-14b@q5_k_m ,显存 12G ,使用 Lm Studio 本地部署的

特别夸一下:Angthing llm 的 RAG 确实好用,很赞!!!!

最后大家有什么不懂的欢迎私信我,我看到会解答的,就这样啦!

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词