🌈 前端也能玩转大模型!WebLLM:用Fetch将DeepSeek引入你的网页

448 阅读3分钟

🌈 前端也能玩转大模型!WebLLM:用Fetch将DeepSeek引入你的网页

本文你将学到:如何使用JavaScript的Fetch API调用DeepSeek大模型,实现一个智能聊天前端。

封面图:一个前端开发者在电脑前,屏幕上显示着代码和DeepSeek的对话

引言:WebLLM,智能前端的战场

还记得Web 1.0时代吗?那时候的前端只是简单的HTML、CSS,交互全靠服务器渲染。进入Web 2.0,前端开始使用Ajax、Fetch等技术,动态获取数据,实现富交互体验。如今,AI时代来临,WebLLM(Web + Large Language Model)正成为新的战场!

什么是WebLLM? 简单来说,就是在前端直接调用大模型的能力,让网页变得"聪明"起来。比如,你可以在网页里集成一个智能助手,直接与用户对话,而这一切只需要几行JavaScript代码!

今天,我们就以DeepSeek大模型为例,教你如何用Fetch API将它引入你的前端项目。

一、传统Web应用的数据获取方式

在深入WebLLM之前,我们先回顾一下传统Web应用的数据获取方式:

1. 服务器端渲染(SSR)

  • 用户输入URL或点击链接
  • 服务器(如Node.js、Java)处理请求,从数据库获取数据
  • 服务器生成HTML字符串,返回给浏览器
  • 浏览器渲染页面

这种方式简单直接,但每次获取新数据都需要刷新页面,体验不够流畅。

举个例子来说:

  1. 用户行为:在浏览器地址栏输入https://example.com/products/123

  2. 服务器处理

    • Node.js 服务器接收到请求,解析路径参数123
    • 从数据库查询 ID 为 123 的商品数据(如名称、价格、描述)
    • 将数据填充到 HTML 模板中,生成完整的 HTML 字符串
  3. 浏览器渲染

    • 服务器返回类似这样的 HTML:

      <!DOCTYPE html>
      <html>
      <body>
        <h1>iPhone 15 Pro</h1>
        <p>价格:¥8,999</p>
        <p>颜色:钛金属灰</p>
        <!-- 其他商品信息 -->
      </body>
      </html>
      
    • 浏览器直接渲染这个完整的 HTML 页面

  4. 局限性

    • 如果用户切换到另一个商品(如 /products/456),需要重新请求服务器
    • 服务器返回全新的 HTML,页面会完全刷新,产生 "闪烁" 感

2. Fetch请求(客户端渲染)

Web 2.0时代,我们开始使用fetch

// 示例:获取GitHub仓库列表
fetch('https://api.github.com/users/shunwuyu/repos')
  .then(res => res.json())
  .then(data => {
    // 动态更新DOM
    document.querySelector('#repoList').innerHTML = data
      .map(repo => `<li>${repo.name}</li>`)
      .join('');
  });

这种方式的好处是:

  • 无需刷新页面,即可获取数据
  • 动态更新DOM,提供更流畅的用户体验
  • 适用于"加载更多"、点赞、评论等交互

二、进入AI时代:用Fetch调用DeepSeek API

现在,我们进入AI时代!大模型如DeepSeek提供了HTTP API,让我们可以像获取普通数据一样获取AI生成的内容。

DeepSeek API 简介

DeepSeek的聊天API端点(Endpoint)是:

POST https://api.deepseek.com/chat/completions

这个API遵循OpenAI的格式,主要参数包括:

  • model:使用的模型,如deepseek-chat
  • messages:对话消息数组,包含systemuserassistant三种角色

调用API的四个步骤

  1. 构建请求行:指定方法(POST)和URL
  2. 设置请求头:包括内容类型和API密钥
  3. 准备请求体:JSON格式的对话数据
  4. 发送请求并处理响应

下面是一个完整示例:

// 1. 定义API端点
const endpoint = 'https://api.deepseek.com/chat/completions';

// 2. 设置请求头
const headers = {
  'Content-Type': 'application/json',
  'Authorization': 'Bearer sk-你的API密钥' // 替换成你的真实密钥
};

// 3. 准备请求体(payload)
const payload = {
  model: 'deepseek-chat',
  messages: [
    { role: 'system', content: '你是一个有用的助手' },
    { role: 'user', content: '你好,DeepSeek!' }
  ]
};

// 4. 发送Fetch请求
fetch(endpoint, {
  method: 'POST',
  headers: headers,
  body: JSON.stringify(payload) // 注意:body必须是字符串
})
.then(response => response.json())
.then(data => {
  // 提取AI回复
  const aiReply = data.choices[0].message.content;
  document.querySelector('#reply').innerHTML = aiReply;
});

三、解剖HTTP请求:请求行、头、体

HTTP请求就像一封信✉️,它由三个主要部分组成:

1. 请求行(Request Line)

POST /chat/completions HTTP/1.1
  • 方法POST(因为我们发送数据给服务器)
  • 路径/chat/completions(API的具体路径)
  • 协议HTTP/1.1

2. 请求头(Headers)

请求头就像信封上的"备注信息",告诉服务器如何处理这封信。我们设置了两个关键头:

{
  'Content-Type': 'application/json', // 告诉服务器:内容是JSON格式
  'Authorization': 'Bearer sk-xxx'    // 身份验证令牌
}

接下来我将介绍如何获取你自己的身份令牌:

进入这个网址 DeepSeek 开放平台

在这之前要耗费巨款1元,获得使用资格(问一次问题大概耗费0.001元,反正可以用挺久的)

image.png

注意要实名认证

image.png 点击创建api key

image.png 然后你就会获得一个key,将key放入'Bearer sk-xxx' sk-xxx这个位置即可

3. 请求体(Body)

请求体是信的具体内容。对于DeepSeek API,我们发送一个JSON对象:

{
  "model": "deepseek-chat",
  "messages": [
    {"role": "system", "content": "你是一个有用的助手"},
    {"role": "user", "content": "你好DeepSeek!"}
  ]
}

注意:在Fetch中,body必须是字符串,所以我们要用JSON.stringify()转换。

messages数组中的role字段支持以下几种角色,且有不同的使用规则:

1. 系统角色(system

  • 作用:设定助手的行为和身份,提供全局指令或背景信息。

  • 限制

    • 通常只需设置一次,放在messages数组的第一个元素。
    • 部分 API 允许多次使用system(如 OpenAI 的 GPT-4),但后续的system可能覆盖或补充之前的指令。
  • 示例

    {"role": "system", "content": "你是一个精通编程的助手,用简洁易懂的语言回答问题。"}
    

2. 用户角色(user

  • 作用:表示用户的输入或提问。

  • 使用频率:可多次出现(每轮对话至少一次)。

  • 示例

    {"role": "user", "content": "如何用Python实现快速排序?"}
    

3. 助手角色(assistant

  • 作用:存储模型之前的回复,用于上下文对话。

  • 使用场景

    • 在多轮对话中,需要将历史对话的assistant回复加入messages数组。
    • 例如,用户连续提问时,API 需要知道之前的回复内容才能保持连贯。
  • 示例

    {"role": "assistant", "content": "可以使用Python的内置函数sorted():\n```python\narr = [3, 1, 4, 1, 5]\nprint(sorted(arr))  # 输出: [1, 1, 3, 4, 5]\n```"}
    

4. 函数调用角色(function_call

  • 作用:当模型需要调用外部函数时,会返回此角色。

  • 结构:包含函数名和参数。

  • 示例

    {
      "role": "assistant",
      "function_call": {
        "name": "get_weather",
        "parameters": {
          "location": "北京",
          "date": "2023-10-01"
        }
      }
    }
    

    这种情况下,用户需要调用对应的函数(如get_weather),并将结果作为新的user消息返回给模型。

多轮对话示例

{
  "model": "deepseek-chat",
  "messages": [
    {"role": "system", "content": "你是一个翻译助手,将中文翻译成英文。"},
    {"role": "user", "content": "你好"},
    {"role": "assistant", "content": "Hello"},
    {"role": "user", "content": "谢谢"},
    // 模型会基于历史对话,生成新的回复
  ]
}

关键规则总结

  1. system通常只需一次,但某些 API 允许多次使用(需查阅文档)。

  2. 历史对话需完整保留:多轮对话时,messages数组要包含所有userassistant的历史记录。

  3. 函数调用需特殊处理:若模型返回function_call,需调用函数并将结果作为新的user消息。

四、实战:构建一个WebLLM聊天应用

现在,让我们动手实现一个简单的聊天界面!

HTML结构

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>DeepSeek Web聊天</title>
  <style>
    /* 简单样式 */
    body { font-family: Arial, sans-serif; }
    #chatbox { height: 400px; overflow-y: auto; border: 1px solid #ccc; padding: 10px; }
    #input { width: 80%; padding: 10px; }
    button { padding: 10px; }
  </style>
</head>
<body>
  <h1>🤖 DeepSeek 聊天机器人</h1>
  <div id="chatbox"></div>
  <input type="text" id="input" placeholder="输入消息...">
  <button onclick="sendMessage()">发送</button>

  <script src="app.js"></script>
</body>
</html>

JavaScript代码 (app.js)

const endpoint = 'https://api.deepseek.com/chat/completions';
const apiKey = 'sk-你的API密钥'; // 替换成你的真实密钥
//挂载点
const chatbox = document.getElementById('chatbox');
const input = document.getElementById('input');

// 初始系统消息
const messages = [
  { role: 'system', content: '你是一个乐于助人的AI助手,回答简洁明了。' }
];

// 发送消息函数
function sendMessage() {
  const userMessage = input.value;
  
  //输入验证逻辑,用于检查用户输入是否为空或仅包含空白字符
  if (!userMessage.trim()) return;
  
  // 添加用户消息
  messages.push({ role: 'user', content: userMessage });
  updateChatbox();
  
  // 清空输入框
  input.value = '';
  
  // 调用DeepSeek API
  fetch(endpoint, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${apiKey}`
    },
    body: JSON.stringify({
      model: 'deepseek-chat',
      messages: messages
    })
  })
 // 处理API响应,需要时间,所以使用.then()异步处理
  .then(response => response.json())
  .then(data => {
    const aiReply = data.choices[0].message.content;  // 提取AI回复
    messages.push({ role: 'assistant', content: aiReply });  // 存储到消息历史
    updateChatbox();  // 更新聊天框
  });
}

// 更新聊天框
function updateChatbox() {
  // 清空当前聊天内容(避免重复追加)
  chatbox.innerHTML = '';

  // 遍历所有消息记录
  messages.forEach(msg => {
    // 过滤系统提示消息(仅后台使用)
    if (msg.role === 'system') return;

    // 创建消息容器div
    const div = document.createElement('div');
    // 设置CSS类(便于区分用户/AI样式)
    div.className = msg.role;
    
    // 构建消息文本内容
    div.textContent = `${ 
      msg.role === 'user' 
        ? '👤 你'  // 用户消息前缀
        : '🤖 AI'  // AI消息前缀
    }: ${msg.content}`;

    // 将消息元素添加到聊天框
    chatbox.appendChild(div);
  });

  // 自动滚动到底部(显示最新消息)
  chatbox.scrollTop = chatbox.scrollHeight;
}

效果图

image.png

五、安全提示:保护你的API密钥

⚠️ 重要提醒:在前端代码中直接暴露API密钥(如sk-xxx)是非常危险的!恶意用户可能窃取你的密钥并滥用。

解决方案

  1. 对于学习项目,可以使用临时密钥。
  2. 生产环境中,应该通过自己的后端服务器转发请求:
    • 前端发送请求到你的服务器
    • 服务器添加密钥后转发给DeepSeek
    • 服务器将响应返回给前端

结语:智能前端的未来已来

通过本文,你已经学会了如何用Fetch API将DeepSeek大模型引入前端。这只是一个起点,WebLLM的世界充满无限可能:

  • 在表单中集成AI辅助输入
  • 创建实时翻译聊天室
  • 开发智能代码助手

💡 思考题:你能用DeepSeek的代码模型(deepseek-coder)做一个在线代码解释器吗?

让我们的网页,从此拥有智慧!


相关阅读

欢迎在评论区分享你的WebLLM作品! 🚀