前端转做AI程序员第一步------开发一个AI流式对话Demo
1、首先新建一个叫Demo的文件夹,文件夹下设有两个文件,server.js(服务端)和index.html(前端)
2、server.js用express框架做服务器,大模型用千问的,模型的key去网站上申请https://bailian.console.aliyun.com/cn-beijing/model/settings/api-key
3、server.js代码参考,定制一个和大模型交互的接口------"流式对话接口"
const
const cors = require('cors');
const app = express();
app.use(cors());
app.use(express.json());
// ========= 这里替换成你自己的 DashScope api key =========
const API_KEY = "sk-XXXXXXXXXXXXXXXXXX";
// ======================================================
const DASHSCOPE_URL =
'https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation';
// 流式对话接口
app.post('/api/chat-stream', async (req, res) => {
const { messages } = req.body;
// SSE响应头
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
try {
// 官方 dashscope npm 包是纯 ESM,且没有 chatStream;这里直接调官方流式 HTTP 接口
const response = await fetch(DASHSCOPE_URL, {
method: 'POST',
headers: {
Authorization: `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
'X-DashScope-SSE': 'enable',
},
body: JSON.stringify({
model: 'qwen-turbo',
input: { messages },
parameters: {
result_format: 'message',
incremental_output: true,
},
}),
});
if (!response.ok) {
const errText = await response.text();
res.write(
`data: ${JSON.stringify({ error: errText || response.statusText, done: true })}\n\n`
);
return res.end();
}
const reader = response.body.getReader();
const decoder = new TextDecoder('utf-8');
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
buffer = lines.pop() || '';
for (const line of lines) {
if (!line.startsWith('data:')) continue;
const raw = line.slice(5).trim();
if (!raw || raw === '[DONE]') continue;
try {
const json = JSON.parse(raw);
const content = json.output?.choices?.[0]?.message?.content;
if (content) {
res.write(`data: ${JSON.stringify({ content })}\n\n`);
}
if (json.code) {
res.write(
`data: ${JSON.stringify({ error: json.message || json.code, done: true })}\n\n`
);
return res.end();
}
} catch {
// 忽略无法解析的片段
}
}
}
// 流结束标记
res.write(`data: ${JSON.stringify({ done: true })}\n\n`);
res.end();
} catch (err) {
res.write(`data: ${JSON.stringify({ error: err.message, done: true })}\n\n`);
res.end();
}
});
const port = 3001;
app.listen(port, () => {
console.log(`✅ 后端服务启动成功`);
console.log(`👉 访问后端地址:http://localhost:${port}`);
});
4、index.html参考代码,构建一个对话框
js
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>AI流式对话Demo</title>
<style>
#chat-box {
width: 650px;
height: 420px;
border: 1px solid #ccc;
padding: 12px;
overflow-y: auto;
margin-bottom: 10px;
border-radius: 6px;
}
.msg {
margin: 8px 0;
line-height: 1.6;
}
.user {
color: #2563eb;
}
.ai {
color: #16a34a;
white-space: pre-wrap;
}
textarea {
width: 650px;
height: 90px;
padding: 8px;
box-sizing: border-box;
border-radius: 4px;
border: 1px solid #ccc;
}
button {
margin-top:8px;
padding:6px 16px;
cursor:pointer;
}
</style>
</head>
<body>
<div id="chat-box"></div>
<textarea id="input" placeholder="请输入你的问题..."></textarea><br>
<button onclick="sendChat()">发送</button>
<button onclick="stopGenerate()">停止生成</button>
<button onclick="clearChat()">清空对话</button>
<script>
const chatBox = document.getElementById('chat-box');
const inputEl = document.getElementById('input');
// 对话上下文
let messages = [];
let reader = null; // 流控制器,用于停止
// 发送消息
async function sendChat() {
const userText = inputEl.value.trim();
if (!userText) return;
// 追加用户消息
messages.push({ role: 'user', content: userText });
addMsg("user", userText);
inputEl.value = '';
// AI消息占位
let aiDom = addMsg("ai", "");
let aiText = "";
const resp = await fetch("http://localhost:3001/api/chat-stream", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ messages })
});
reader = resp.body.getReader();
const decoder = new TextDecoder("utf-8");
while (true) {
const { done, value } = await reader.read();
if (done) break;
const raw = decoder.decode(value);
const events = raw.split("\n\n").filter(Boolean);
for (const evt of events) {
if (evt.startsWith("data: ")) {
const data = JSON.parse(evt.replace("data: ", ""));
if (data.done) {
messages.push({ role: 'assistant', content: aiText });
reader = null;
break;
}
if(data.error){
aiDom.innerText += "\n【错误】" + data.error;
reader = null;
return;
}
aiText += data.content;
aiDom.innerText = aiText;
chatBox.scrollTop = chatBox.scrollHeight;
}
}
}
}
// 停止生成
function stopGenerate(){
if(reader){
reader.cancel();
reader = null;
}
}
// 清空全部对话
function clearChat(){
stopGenerate();
messages = [];
chatBox.innerHTML = '';
}
// 渲染单条消息
function addMsg(type, text) {
const div = document.createElement('div');
div.className = `msg ${type}`;
div.innerText = text;
chatBox.appendChild(div);
return div;
}
</script>
</body>
</html>
5.安装依赖包
diff
npm init -y
npm install express dashscope cors
- express:web 服务
- dashscope:通义官方 SDK,自带流式返回
- cors:解决跨域
6、启动web服务 node server.js 可以看到服务端口3001 服务启动 http://localhost:3001
7、双击index.html打开页面可以看到对话框,输入文字尝试调用

8、入门完成