智谱清言背后的GLM大模型提供了开放的API服务,开发者只需要一个API密钥,就可以在自己的网页中接入对话能力。相比自己部署模型,直接调用API不仅省去了显卡和服务器的成本,还能获得持续更新的模型效果。本文将从准备工作讲起,逐步完成一个可用的网页聊天框,包括请求封装、流式输出和常见问题处理。

一、准备工作:获取API密钥
接入的第一步是到智谱AI开放平台注册账号。打开官网后完成实名认证,进入控制台找到API密钥管理页面,即可创建一个属于自己的密钥。这个密钥由一串长字符组成,是调用接口的唯一凭证,泄露后可能被人盗刷额度,务必妥善保管。
智谱的接口地址为 https://open.bigmodel.cn/api/paas/v4/chat/completions,请求方式为POST,请求体采用JSON格式。在正式写代码之前,建议先用命令行工具测试一下密钥是否可用,确认通了再进行网页端开发,这样出问题时更容易定位。
curl https://open.bigmodel.cn/api/paas/v4/chat/completions \
-H "Authorization: Bearer 你的API密钥" \
-H "Content-Type: application/json" \
-d '{
"model": "glm-4-flash",
"messages": [{"role": "user", "content": "你好"}]
}'如果返回的JSON中包含正常的回复内容,说明密钥和参数都没有问题,可以进入下一步。注意model字段可以按需选择,glm-4-flash是免费的轻量模型,适合开发调试阶段使用,正式上线时可以换成效果更强的glm-4系列。
二、编写网页聊天框的HTML结构
聊天框的界面不需要太复杂,一个消息展示区域加一个输入区域就够了。消息区域建议区分用户消息和AI回复两种样式,方便阅读。下面是一个基础的结构示例,用<div>作为容器,<input>负责接收用户输入,<button>触发发送动作。
<div class="chat-box">
<div class="messages" id="messages"></div>
<div class="input-area">
<input type="text" id="userInput" placeholder="请输入你的问题">
<button onclick="sendMessage()">发送</button>
</div>
</div>样式部分可以按自己的喜好调整,核心是让消息区域支持滚动,并且当内容超出容器高度时自动定位到最底部,这样长对话不会看不到最新回复。用户消息和AI消息可以用不同的背景色或对齐方式加以区分,整体体验会好很多。
三、用JavaScript调用接口并实现流式输出
调用接口时,messages数组要维护完整的对话历史,每次请求都把之前的上下文带上,模型才能记住前面聊了什么。请求参数中的stream字段设为true后,接口会以流的形式返回数据,浏览器端通过ReadableStream逐段读取,就能实现打字机效果。下面是完整的实现代码。
const API_KEY = '你的API密钥';
const API_URL = 'https://open.bigmodel.cn/api/paas/v4/chat/completions';
let history = [];
async function sendMessage() {
const input = document.getElementById('userInput');
const text = input.value.trim();
if (!text) return;
input.value = '';
history.push({ role: 'user', content: text });
appendMessage('user', text);
// 创建AI消息占位节点,流式内容追加到这里
const aiNode = appendMessage('ai', '');
let fullText = '';
const response = await fetch(API_URL, {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
model: 'glm-4-flash',
messages: history,
stream: true
})
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
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 data = line.slice(5).trim();
if (data === '[DONE]') continue;
try {
const json = JSON.parse(data);
const delta = json.choices[0].delta.content || '';
fullText += delta;
aiNode.textContent = fullText;
scrollToBottom();
} catch (e) { /* 忽略不完整的片段 */ }
}
}
history.push({ role: 'assistant', content: fullText });
}
function appendMessage(role, text) {
const box = document.getElementById('messages');
const div = document.createElement('div');
div.className = 'msg ' + role;
div.textContent = text;
box.appendChild(div);
scrollToBottom();
return div;
}
function scrollToBottom() {
const box = document.getElementById('messages');
box.scrollTop = box.scrollHeight;
}这段代码的关键在于流式解析。接口返回的数据每一行以data:开头,内容是JSON片段,其中的delta字段携带本次新增的文字。逐段拼接后更新到页面上,用户就能看到回复逐渐生成。等流结束后,再把完整回复写入history,作为下一轮的上下文。
四、跨域问题与密钥安全
浏览器直接调用第三方接口经常会遇到跨域限制。智谱的接口目前支持浏览器端跨域请求,如果部署环境出现跨域报错,推荐的解决方案是在自己的服务器上做一层转发代理,前端请求自己的接口,服务器再把请求转给智谱,返回结果原样传回。
更重要的一个问题是密钥安全。上面的示例为了演示方便把密钥写在了前端代码里,但正式上线时绝对不能这样做,因为任何打开浏览器控制台的人都能看到并盗用你的密钥。正确做法是通过后端接口代理请求,密钥只存在于服务器环境变量中,前端不接触任何敏感信息。用Node.js写一个简单的转发接口只需要十几行代码,这是生产环境的标准做法。
五、常见报错排查
接入过程中最常见的问题是401错误,表示鉴权失败,多半是密钥填写错误、复制时带了空格,或者密钥已被禁用,回到控制台核对即可。429错误表示请求频率超出限制,一般发生在快速连续发送消息时,前端可以做按钮禁用,等待上一次回复完成再允许发送。
如果收到模型名称相关的报错,检查model参数拼写是否正确,不同时期可用的模型列表可以在官方文档中查看。另外流式解析时偶尔会遇到JSON解析报错,这是因为一条数据被网络分片截断了,示例代码中用缓冲区按行拆分就是为了解决这个问题,遇到不完整的片段直接跳过等待下一批数据即可。
完成以上步骤后,一个具备上下文记忆和流式输出能力的网页聊天框就可以正常使用了。后续还可以在此基础上增加历史记录清空按钮、Markdown格式渲染、加载状态提示等功能,让聊天体验更加完善。