ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

纯HTML+JavaScript调用蓝耘MaaS平台,实战接入DeepSeek-V3.1-Terminus

2026/10/8 4:09:33 拓冰建站 浏览量
纯HTML+JavaScript调用蓝耘MaaS平台,实战接入DeepSeek-V3.1-Terminus 1. 整体设计与思路拆解1.1 为什么选蓝耘元生代MaaS平台来调DeepSeek-V3.1-Terminus先讲清楚一个现实现在大模型能力确实强但普通人想在自己网页里稳定跑起来不是填个API地址那么简单。DeepSeek-V3.1-Terminus这个模型本身的权重和推理部署门槛不低显存、算力、并发调度、负载均衡每一项都能劝退一批刚入门的人。蓝耘元生代MaaS平台做的事情就是把模型部署、推理调度、API网关、用量计费这些底层细节全包了你只需要拿一个API Key像调普通HTTP接口一样发请求就行。我当时选蓝耘元生代MaaS主要是对比了几个平台之后发现它在兼容OpenAI接口规范这块做得比较省心。也就是说你用惯了ChatGPT的API格式切过来几乎不用改代码逻辑——base_url换掉、model换掉、API Key换成蓝耘的原先的项目直接就能跑。对于只想快速验证模型效果、或者做前端Demo演示的人来说这是最省时间的一条路。另外它还支持流式输出SSE这对聊天类应用来说是刚需。因为大模型生成Token是需要时间的如果没有流式输出用户就得盯着空白页面等好几秒体验非常差。有了流式Token是一个一个蹦出来的像打字机一样产品观感完全不一样。我用HTML JavaScript写Demo的时候流式解析这块是核心后面会展开讲。1.2 为什么用纯HTML做Demo而不是上框架现在写前端的主流做法是React、Vue加一堆工程化构建工具但对于“调用大模型API”这种单页演示场景纯HTML CSS JavaScript反而是最优解。原因有几点。第一零依赖。你只需要一个文本编辑器写一个.html文件双击就能在浏览器里打开不需要Node.js、不需要npm install、不需要webpack。对很多人来说可能只是想迅速验证一下蓝耘元生代MaaS平台好不好用、DeepSeek-V3.1-Terminus回复质量怎么样搞一整套前端工程就太重了。第二好分享。一个单文件HTML直接发给同事或者扔到GitHub Pages、OSS静态托管上别人打开链接就能用。第三方便调试。浏览器F12打开控制台网络请求、响应体、报错信息一目了然排查问题比在框架里追依赖关系直接得多。当然纯HTML方案也有它的天花板比如API Key暴露在浏览器里会有安全隐患这个我会在后面的安全边界章节专门说。但作为实战Demo、学习工具、内部验证纯HTML完全够用而且上手门槛低到几乎为零。1.3 整体架构与数据流这个Demo的架构非常轻数据流也很清晰用户在页面输入框里写下问题点击发送按钮。浏览器里的JavaScript通过fetch向蓝耘元生代MaaS平台的API地址发起POST请求请求体里带上模型名称、用户消息、参数配置温度、最大Token等。平台网关转发请求到DeepSeek-V3.1-Terminus模型服务模型开始推理返回结果。如果开启了流式输出响应体是一段持续到达的SSE流前端通过ReadableStream逐步读取并实时渲染到页面上。非流式模式则等完整JSON返回后一次性渲染。整个链路里前端只做两件事发请求、渲染响应。真正的智力活全在平台侧和模型侧。这种“前端薄、平台厚”的架构模式恰恰是MaaS产品最大的价值——让模型能力触手可及而调用方只需要关心业务和体验。2. 准备阶段账号、API Key与基础配置2.1 注册账号与获取API Key在写代码之前先把平台侧的准备工作做完。去蓝耘官网注册账号然后进入控制台找到元生代MaaS平台的入口。首次使用一般需要开通服务或创建API Key流程跟绝大多数云平台类似按提示操作即可。创建API Key的时候建议给Key起一个能看明白的名字比如“html-demo”方便后续在用量明细里追踪。这里有一个实操提醒API Key的显示机会通常只有一次关闭弹窗之后就看不到了。一定要当时就复制、粘贴、保存到本地密码管理器里。我见过太多人没保存Key之后只能重新创建一个虽然不麻烦但没必要。获取到API Key之后看一下控制台里的模型列表确认你能调用的模型标识符。蓝耘元生代MaaS平台对DeepSeek-V3.1-Terminus的模型命名一般会直接标注形如deepseek-v3.1- terminus这样的字符串但因为版本和区域可能不同以控制台里的实际显示为准。后面代码里的model字段就填这个值。2.2 接口文档里的关键信息蓝耘元生代MaaS平台的接口设计兼容OpenAI格式所以核心信息就那么几个请求地址base_url加上/chat/completions一般形如https://api.xxx.com/v1/chat/completions具体域名以官方文档为准。请求方法POST。请求头Content-Type: application/jsonAuthorization: Bearer 你的API Key。请求体model、messages、stream、max_tokens、temperature等字段。messages数组的结构跟OpenAI一致是对话历史的列表每条消息包含role和content。role有三种system系统设定、user用户、assistant模型回复。多轮对话原理上就是把历史消息全部带上一起发给模型模型才能有上下文连续感。stream字段决定返回方式。默认false时服务器一次性返回JSON里面包含完整的回复内容设为true时服务器返回SSE流数据是一块一块到达的。对于聊天Demo我强烈建议开stream: true交互体验是完全不同的。2.3 前端安全边界先别踩坑纯HTML页面直接调API最大的问题就是API Key暴露。你把这个HTML发给别人别人按F12就能看到你的Key。你的Key被别人盗用去跑量产生的高额费用算在你账上——这是实打实的风险。所以必须分层处理安全问题本机学习用Key写在HTML里无所谓因为只有你自己用风险可控。分享给别人用不要直接发带Key的HTML。可以临时生成一个服务端代理前端请求你代理代理再带Key去请求蓝耘平台。正式生产项目Key必须放在服务端环境变量里前端绝不能接触。我后面提供的Demo代码默认是在本机或信任环境里学习使用。如果你要部署到公开网络务必先部署一个轻量的代理后端哪怕只是几十行的Node.js或Python代理也比Key裸奔强得多。3. 核心代码实现请求封装与流式解析3.1 非流式请求最简版本先跑通先把最简单的版本写出来验证链路是否通畅。打开文本编辑器新建一个index.html先填一个输入框和一个按钮JavaScript里用fetch发POST请求。!DOCTYPE html html langzh-cn head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title蓝耘MaaS DeepSeek-V3.1-Terminus 实战Demo/title /head body div textarea idprompt rows5 cols60 placeholder请输入你的问题.../textarea br button idsendBtn发送/button /div div idoutput stylemargin-top:20px; white-space:pre-wrap;/div script const API_KEY 你的API Key; const BASE_URL https://你的平台域名/v1/chat/completions; const MODEL deepseek-v3.1-terminus; // 以控制台实际显示为准 document.getElementById(sendBtn).addEventListener(click, async () { const prompt document.getElementById(prompt).value.trim(); if (!prompt) return; const output document.getElementById(output); output.textContent 思考中...; const response await fetch(BASE_URL, { method: POST, headers: { Content-Type: application/json, Authorization: Bearer ${API_KEY} }, body: JSON.stringify({ model: MODEL, messages: [ { role: system, content: 你是一个乐于助人的AI助手。 }, { role: user, content: prompt } ], stream: false, temperature: 0.7, max_tokens: 2048 }) }); const data await response.json(); if (data.choices data.choices.length 0) { output.textContent data.choices[0].message.content; } else { output.textContent JSON.stringify(data, null, 2); } }); /script /body /html注意几个点第一output那个div加了white-space: pre-wrap这样模型回复里的换行和缩进能原样显示。第二temperature控制随机性和创造性0到2之间取值值越大回复越多变值越小越稳定日常问答用0.7是比较中庸的选择。第三max_tokens限制回复的最大Token数256如果不够用就调大但这个Demo里我给了2048。如果这一步能在页面上正确显示模型的回复说明API Key、模型名称、网络通路都没问题链路是通的。接下来再上流式。3.2 流式请求SSE解析完整实现流式交互才是这个Demo的灵魂。一样是用fetch但body里的stream要设为true然后通过response.body拿到一个ReadableStream用getReader()读取数据块。服务器通过SSE格式发送数据每一块数据以data:开头以两个换行符结束。当所有数据发完后会有一条data: [DONE]。解析逻辑就是不断读块、按行切分、提取data:后面的JSON字符串、JSON.parse解析出增量内容然后追加到页面上。document.getElementById(sendBtn).addEventListener(click, async () { const prompt document.getElementById(prompt).value.trim(); if (!prompt) return; const output document.getElementById(output); output.textContent ; const response await fetch(BASE_URL, { method: POST, headers: { Content-Type: application/json, Authorization: Bearer ${API_KEY} }, body: JSON.stringify({ model: MODEL, messages: [ { role: system, content: 你是一个乐于助人的AI助手。 }, { role: user, content: prompt } ], stream: true, temperature: 0.7, max_tokens: 2048 }) }); 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 }); // SSE数据块通常以\n\n分隔 const lines buffer.split(\n); buffer lines.pop(); // 最后一段可能是不完整的留到下一轮再处理 for (const line of lines) { const trimmed line.trim(); if (!trimmed.startsWith(data:)) continue; const dataStr trimmed.slice(5).trim(); if (dataStr [DONE]) continue; try { const json JSON.parse(dataStr); const delta json.choices[0].delta.content; if (delta) { output.textContent delta; // 滚动到页面底部 window.scrollTo(0, document.body.scrollHeight); } } catch (e) { console.error(解析失败:, e, dataStr); } } } });流式解析的核心技巧就是那个buffer。因为网络包是切片的一次reader.read()不一定刚好读到一个完整的SSE事件可能半截、可能几个事件黏在一起。所以惯用做法是把每次读到的数据追加到buffer里按\n\n切分成若干行把最后一段不完整的留到下一次循环再拼。这个细节新手很容易忽略结果就是页面经常丢字、乱码、解析报错。还有一个细节decoder.decode(value, { stream: true })这个参数也很关键。如果不用{ stream: true }一个多字节UTF-8字符被拆到两个数据块里时第二块会解析出乱码。加上{ stream: true }之后解码器内部会缓存中间结果跨块字符也能正确拼出来。3.3 参数调优提升输出质量的几个旋钮同一个模型参数不同输出效果天差地别。我在调API的时候经常被问“为什么模型回答这么机械”或者“为什么答案太啰嗦”很多时候问题不在模型在参数。temperature日常问答0.6~0.7。写文案、头脑风暴可以拉到0.9~1.2发挥空间更大。做数据提取、代码生成这种需要确定性的任务降到0.2~0.3降低胡说八道的概率。max_tokens如果默认值是2048长文本生成会被截断。写代码、写文章这种长输出场景最好设到4096或更高具体看平台的额度上限。top_p另一个控制随机性的参数跟temperature类似但原理不同。一般只用其中一个做调节别同时大幅调整两个参数容易让输出变得奇怪。system消息很多人小看它实际上它是控制模型行为最有效的工具。跟模型说“你是一个严谨的技术专家回答要简洁、准确、分点输出”比你在问题里夹带一万个要求都管用。在Demo页面里我建议做一个参数面板把temperature做成滑块max_tokens做成数字输入框实时点击实时调整这样你能直观感受到参数对回复的影响。我记得第一次把temperature从一个极端拉到另一个极端时同一个问题问出来的回答风格差异大到像换了个人那个瞬间对“随机性参数”的理解一下子通了。4. 实战演示页面搭建4.1 HTML结构布局清晰交互顺手既然叫HTML实战Demo页面结构就不能太糊弄。我按一个极简聊天工具的标准来搭顶部是标题栏中间是消息区底部是输入区和发送按钮。没有花哨的设计但分工明确。div classchat-container header classchat-header h1蓝耘MaaS · DeepSeek-V3.1-Terminus 实战Demo/h1 span classstatus-dot idstatusDot/span /header main classchat-main idchatMain !-- 消息气泡动态渲染区 -- /main footer classchat-footer textarea idprompt rows3 placeholder输入你的问题CtrlEnter 发送/textarea button idsendBtn发送/button /footer /div消息区里的内容结构我采用最直观的方案——每条消息一个div根据角色加不同的CSS类名。用户消息靠右整块蓝色背景模型消息靠左浅灰背景。这样一眼就能分清楚是谁在说话聊天的视觉习惯也符合主流聊天工具。发送方式做了两个入口点击发送按钮以及CtrlEnter快捷键。聊天工具输完内容直接按快捷键就能发效率高很多。实现的时候给textarea加一个keydown事件监听判断event.ctrlKey event.key Enter即可。4.2 CSS样式花半小时打磨观感完全不同CSS没写很复杂一个几百行的样式表就够用。但有几个点值得单独说。消息区要独立滚动而不是整个页面滚动。这样当消息很长时浏览器不会因为滚动条乱跳而打断阅读节奏。实现方式是给.chat-main设置flex: 1加overflow-y: auto外层容器限制高度为视口的90%。模型回复里的代码块需要一个深色背景。我写了一个简单的.markdown pre样式用等宽字体加浅色背景区分正文。虽然纯前端没做完整Markdown渲染但至少让代码片段不会跟普通文字糊在一起。发送中状态要有视觉反馈。发送期间按钮变成灰色、禁用点击消息区末尾显示一个“正在输入”的动画等流式内容到达后自动消失。这个小细节直接影响用户体感没反馈的页面会让人以为卡死了。4.3 交互逻辑多轮对话、清空会话、错误提示这个Demo不止是单轮问答我还加了多轮对话支持。核心做法很简单维护一个messages数组用户每次发送的新消息push进去模型返回的assistant消息也push进去下次请求时把整个数组传给接口。这样模型就能结合上下文回复聊起来感觉像连续的人。注意历史消息越来越多时请求体也越来越大Token消耗会增加所以Demo里我做了个“清空对话”按钮一键重置防止越聊越长。错误提示也做了分类处理。网络超时、HTTP 4xx/5xx、流式中断分别给用户显示对应的中文提示。调试的时候发现在浏览器里最容易遇到的是跨域问题这个下面专门讲。5. 常见问题与排查技巧实录5.1 CORS跨域你大概率会撞上的第一面墙纯HTML文件直接双击打开用file://协议调API浏览器会报CORS错误而且这种场景下平台侧很难通过允许跨域来解决因为Origin是null。正确做法是不要用file://打开页面而是本地起一个HTTP服务。最简单的方式在页面所在目录运行python3 -m http.server 8000然后浏览器访问http://localhost:8000。如果你装了Node.js也可以npx serve。这本质上只是改变页面的加载协议却能让浏览器正常发送跨域请求。蓝耘元生代MaaS平台一般会在服务端配置允许特定域名跨域但http://localhost或具体域名是否被允许取决于平台策略要提前确认。如果平台不支持浏览器直接跨域调用那就必须走代理服务这是一个硬性约束不是前端能绕过去的。5.2 流式输出不生效先检查响应头开着stream: true但页面还是等很久才一次性出现全部内容问题多半出在服务器响应头或者网络中间层。正常SSE请求响应头的Content-Type应该是text/event-stream。你可以在浏览器控制台的Network面板里点开这条请求查看响应头确认。还有一种情况是网络代理或CDN把流式响应缓冲了导致数据攒够一定量才发给浏览器看起来就跟非流式一样。如果是本地调试可以试着关掉系统代理直接用直连。我遇到过一次是内网网关做了缓冲换了网络环境后流式立刻恢复正常。这种情况不在代码层面惯性怀疑自己写错是很常见的误导。5.3 响应解析报错和Token超长截断如果控制台报JSON.parse失败先看一眼打印出来的dataStr长什么样。SSE格式里可能有注释行:开头、空行、event:字段这些都要跳过。我写的解析逻辑只处理data:前缀的行其他行直接忽略这样能规避大部分偶发问题。如果模型回复突然断在半句并且结束得很突然没有任何错误标志大概率是max_tokens设小了。把max_tokens调大或者让模型自觉分段输出。调试长文本生成时我习惯把max_tokens直接拉到上限排除截断这个变量确认效果后再调回合理值。5.4 费用与用量管理别让Key裸奔后失控最后聊一个跟代码无关但比代码都重要的点——费用管控。API用了是要计费的流式和非流式按Token计费多轮对话和超长文本消耗尤其明显。Demo阶段建议看到效果就收不要写个死循环疯狂调接口测试。另外再次提醒API Key绝对不能提交到公开Git仓库不能贴在在线演示页面上。你辛苦写的Demo代码开源出去的同时把Key也带出去了等于免费给陌生人开通了一个自动提款通道。真要分享用后端代理、用环境变量、用变量替换占位符怎么都行别让Key裸奔。6. 扩展方向这个Demo还能往哪里走写到这里基础实战已经完整跑通了。如果你对这套HTML调用蓝耘元生代MaaS平台的方案玩熟练了后续有不少自然的扩展方向把textarea升级成支持Markdown渲染的编辑器模型回复可以呈现表格、列表、标题观感直接上一档。给页面加上语音识别接口用麦克风输入替代打字做一个语音版问答助手。加上Prompt模板管理把常用问题预置成按钮适合演示场景一键触发。或者做一个上下文历史记录的本地存储刷新页面后聊天记录不丢。就我个人的感觉把这个Demo做熟、做透的意义不只是在“学会了调一个API”而是理解了云端模型服务的基本工作方式——请求、响应、流式、Token、参数调优这套逻辑放在任何一家AI平台上都通用。蓝耘元生代MaaS平台帮你省去了部署模型的折腾但你依然需要懂这些基础知识才能用好它。