前端初探多模态 AI:用 Vite + 通义万象,几行代码实现"以图生图"

11 阅读10分钟

前端初探多模态 AI:用 Vite + 通义万象,几行代码实现"以图生图"

前言

大家好,今天想和你聊聊前端如何调用 AI 大模型这件事。

说到 AI,很多前端同学第一反应是"这是后端的事"、"我不懂 Python"、"又要学机器学习?"。其实不然——现在各大厂商都把 AI 能力封装成了标准的 HTTP API,前端只需要发请求、传参数、拿结果,和你平时调后端接口一模一样。

本文通过一个完整的 demo,带你从零搭建一个**"以图生图"**的前端项目:给 AI 三张图片 + 一句描述,AI 自动合成一张新图。核心技术栈:

  • Vite:前端工程化脚手架
  • 通义万象(Qwen Image):阿里云的多模态图像生成模型
  • dotenv / .env:API Key 的安全管理

📌 适合人群:对 AI 感兴趣的前端同学,有 JS 基础即可,不需要任何机器学习背景。


一、先搞懂几个概念

1.1 什么是"多模态"(Multimodal)?

这是本文最重要的概念,先把它搞明白。

传统 AI 模型只能处理单一类型的数据:

  • 纯文本模型(如 GPT)→ 只能理解文字
  • 纯图像模型(如 ResNet)→ 只能理解图片

多模态模型可以同时理解多种类型的数据:文字 + 图片 + 音频 + 视频...

传统模型:
  文字 → [文本模型] → 文字输出
  图片 → [图像模型] → 图片输出

多模态模型:
  文字 + 图片 + 音频 → [一个多模态模型] → 文字/图片/音频

本文用到的**通义万象(Qwen Image)**就是一个多模态模型,它可以:

  • 🖼️ 理解你上传的图片内容
  • 📝 理解你的文字描述
  • 🎨 将文字+图片信息融合,生成一张全新的图片

知识点:多模态模型的训练数据包含"图文对"(image-text pairs),模型学到了文字和图像之间的映射关系。所以你告诉它"把图1的人穿上图2的衣服",它真的能理解并执行。

1.2 前端调用 AI 的本质是什么?

说白了就三步:

前端 → HTTP 请求 → AI 服务商的 API → 返回结果 → 前端渲染

和你调任何后端接口完全一样。区别只在于:

  • URL 变成了 AI 服务的地址
  • 参数 里多了 model(选模型)、messages(对话/指令)
  • 认证API Key 而不是 cookie/session
// 你平时调后端接口
fetch('/api/user/info', {
  headers: { 'Authorization': `Bearer ${token}` },
  body: JSON.stringify({ userId: 123 })
})

// 调 AI 接口,换汤不换药!
fetch('https://dashscope.aliyuncs.com/api/v1/services/...', {
  headers: { 'Authorization': `Bearer ${apiKey}` },
  body: JSON.stringify({
    model: 'qwen-image-2.0-pro',
    input: { messages: [...] }
  })
})

二、项目架构一览

先看整体结构,心里有个地图:

qwen-image-demo/
├── .env.local          ← API Key 放在这里,不提交 Git
├── index.html          ← 入口 HTML,挂载点 + 加载 main.js
├── package.json        ← 项目配置,只依赖 vite
├── src/
│   ├── main.js         ← 核心逻辑:调 AI 接口 + 渲染结果
│   ├── style.css       ← Vite 模板自带的样式
│   └── counter.js      ← 模板自带的计数器组件(本文不用)

项目极其轻量——只有一个核心文件 main.js,不到 60 行代码就完成了 AI 图像生成的全部逻辑。


三、第一步:Vite 搭建前端工程

3.1 Vite 是什么?

一句话:Vite 是新一代前端构建工具,由 Vue 的作者尤雨溪开发。它做了两件事:

  1. 开发时:用浏览器原生 ESM(ES Modules)加载代码,秒级启动,改了代码热更新快到飞起
  2. 打包时:用 Rollup 打包生产代码,又快又小

知识点:传统的 webpack 需要先把你写的所有代码"打包"成一个巨大的 bundle,才能在浏览器里跑。Vite 在开发模式下不打包——浏览器直接用 <script type="module"> 加载你的源文件,所以冷启动可以做到毫秒级。

对比一下启动速度:

webpack dev server:  🐢 启动 30s+,改一行代码等 2s
Vite dev server:    🚀 启动 < 1s,改一行代码 < 100ms

3.2 创建项目

npm create vite@latest qwen-image-demo
# 选 vanilla → JavaScript

cd qwen-image-demo
npm install

创建后的 package.json 极为简洁:

{
  "name": "qwen-image-demo",
  "version": "0.0.0",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "devDependencies": {
    "vite": "^8.0.12"
  }
}

注意两个关键配置:

  • "type": "module" → 启用 ES Module,让你能用 import.meta.env
  • devDependencies 里只有 vite → 极致的轻量

3.3 入口 HTML 的秘密

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>qwen-image-demo</title>
  </head>
  <body>
    <!-- 挂载点:JS 动态渲染的地方 -->
    <div id="app"></div>
    <!-- 关键!type="module" 告诉浏览器这是 ESM -->
    <script type="module" src="/src/main.js"></script>
  </body>
</html>

知识点<script type="module"> 是浏览器原生支持的 ES Module 加载方式。Vite 不需要你把所有 JS 打包成一个文件——浏览器会按 import 语句自己按需加载。这也是 Vite 开发模式"秒启动"的核心原因。


四、第二步:API Key 的安全管理

4.1 为什么不能写明文?

很多初学者会这样写:

// ❌ 危险!千万不要这样写!
const apiKey = 'sk-ws-H.REIHRXH.b4fF.MEUCIQC...'

这相当于把你的银行卡密码写在便利贴上贴在大街上。一旦提交到 GitHub:

  • 别人可以直接用你的 Key 疯狂调用 API
  • 阿里云会按调用量扣你账户的钱
  • 已经有专门的爬虫机器人扫描 GitHub 上的 API Key

4.2 Vite 的环境变量机制

Vite 提供了一套优雅的解决方案——环境变量

Step 1:创建 .env.local 文件,放入你的 API Key:

VITE_QWEN_API_KEY=sk-ws-H.你的真实Key

注意前缀必须是 VITE_,这是 Vite 的安全机制——只有 VITE_ 开头的变量才会暴露给前端代码。

知识点:为什么加 VITE_ 前缀?这是一种白名单机制。服务器可能有几十个环境变量(数据库密码、内部密钥等),如果全部暴露给前端就是灾难。Vite 只把 VITE_ 前缀的变量注入到 import.meta.env 中,其余的环境变量前端根本看不到。

Step 2:确认 .gitignore 里排除了 .local 文件:

node_modules
dist
*.local    ← 这一行确保 .env.local 不会被提交到 Git

Step 3:在代码中使用:

const apiKey = import.meta.env.VITE_QWEN_API_KEY;
// import.meta.env 是 Vite 在编译时注入的一个全局对象
// 类似 Webpack 的 process.env,但是基于 ESM 规范

4.3 整套流程回顾

你在 .env.local 里写 VITE_QWEN_API_KEY=xxx
             ↓
   Vite 启动时读取 .env.local
             ↓
   Vite 把 VITE_ 前缀的变量注入 import.meta.env
             ↓
   你的代码 import.meta.env.VITE_QWEN_API_KEY 拿到值
             ↓
   .gitignore 确保 .env.local 不进 Git 仓库

💡 一句话总结:VITE 就像前端项目的"大管家"——它管理着开发、构建、环境变量等一系列工程化事务,让你专心写业务代码。


五、第三步:核心代码逐行解析

下面是 main.js 的全部代码,我们逐段拆解

5.1 获取 API Key

const apiKey = import.meta.env.VITE_QWEN_API_KEY;
const root = document.querySelector('#app');
  • import.meta.env.VITE_QWEN_API_KEY → Vite 提供的编译时环境变量
  • document.querySelector('#app') → 拿到 HTML 里的挂载点 <div id="app">

5.2 调用 AI 接口

const generateImage = async () => {
  const res = await fetch(
    'https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation',
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${apiKey}`,
      },
      body: JSON.stringify({
        "model": "qwen-image-2.0-pro",
        "input": {
          "messages": [
            {
              "role": "user",
              "content": [
                {
                  "image": "https://help-static-aliyun-doc.aliyuncs.com/.../input1.png"
                },
                {
                  "image": "https://help-static-aliyun-doc.aliyuncs.com/.../input2.png"
                },
                {
                  "image": "https://help-static-aliyun-doc.aliyuncs.com/.../input3.png"
                },
                {
                  "text": "图1的女生穿着图2中的黑色裙子按图3的姿势坐下"
                }
              ]
            }
          ]
        },
        "parameters": {
          "n": 1,
          "size": "1024*1536"
        }
      })
    }
  )
  const data = await res.json();
  console.log(data);
  return data.output.choices[0].message.content[0].image;
}

这段是本文的灵魂代码,我们拆开细说:

📌 接口地址
https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation

这是阿里云 DashScope(百炼平台)的多模态生成接口。"dashscope" 是阿里的 AI 模型服务平台,类似于 OpenAI 的 platform.openai.com。

📌 认证方式
'Authorization': `Bearer ${apiKey}`

Bearer Token 是 AI API 最常用的认证方式。你的 API Key 就是"通行证",放到请求头的 Authorization 字段里即可。

知识点:Bearer Token vs API Key

  • API Key 通常是一个固定字符串,直接用来标识"谁在调用"
  • Bearer Token 是 OAuth 2.0 标准中的一种令牌类型,放在 Authorization: Bearer xxx 头里
  • 实际使用中,多数 AI 服务商把 API Key 直接当 Bearer Token 用
📌 请求体结构
body: JSON.stringify({...})

知识点:HTTP 请求体在传输过程中是二进制字节流。JSON.stringify() 的作用是把 JS 对象序列化成 JSON 字符串,然后浏览器会把这个字符串编码为二进制发送。服务端收到后做反向操作——反序列化,还原成对象。

整个请求体分为三部分:

部分作用
model指定用哪个模型。这里用的是 qwen-image-2.0-pro(通义万象 2.0 Pro 版)
input.messages传给 AI 的"提示词",格式类似 ChatGPT 的对话结构
parameters生成参数。n: 1 生成一张,size 指定图片尺寸
📌 messages 的格式——多模态的关键
"content": [
  { "image": "https://...图片1的URL" },   // 图1:一个女生
  { "image": "https://...图片2的URL" },   // 图2:一条黑色裙子
  { "image": "https://...图片3的URL" },   // 图3:一个坐姿
  { "text": "图1的女生穿着图2中的黑色裙子按图3的姿势坐下" }  // 文字指令
]

注意 content 是一个数组而不是字符串!这是多模态模型的标志性特征:

  • 纯文本模型:content: "你好"(字符串)
  • 多模态模型:content: [{image: "..."}, {text: "..."}](数组,可以混合多种类型)

AI 会理解:

  1. 图1 里有谁 → 一个女生
  2. 图2 里有什么 → 一条黑色裙子
  3. 图3 是什么姿势 → 一个坐着的姿势
  4. 文字说什么 → 把这三者组合起来

然后生成一张融合了三张参考图 + 文字指令的全新图片。这就是多模态的魅力。

📌 解析返回结果
const data = await res.json();
return data.output.choices[0].message.content[0].image;

返回的 JSON 结构大概是这样:

{
  "output": {
    "choices": [
      {
        "message": {
          "content": [
            { "image": "https://...生成的图片URL" }
          ]
        }
      }
    ]
  }
}

路径拆解:

  • output.choices → AI 生成的候选结果列表
  • [0] → 取第一个(我们 n:1 所以只有一个)
  • message.content → 多模态返回的内容数组
  • [0].image → 第一项内容的图片 URL

5.3 渲染结果

const renderImage = (imageUrl) => {
  root.innerHTML = `<img src="${imageUrl}" />`
}

拿到 AI 返回的图片 URL 后,动态插入到页面中。简单直接。

5.4 入口

const main = async () => {
  const imageUrl = await generateImage();  // 调 AI 生成图片
  renderImage(imageUrl);                   // 把图片显示到页面上
}
main();

六、完整数据流

把整个流程串起来看:

┌──────────────────────────────────────────────┐
│                  浏览器                        │
│                                              │
│  1. 加载 index.html                          │
│  2. <script type="module"> 加载 main.js      │
│  3. import.meta.env 读取 API Key              │
│  4. fetch() 发 POST 请求到阿里云               │
│     ↓                                        │
│  5. 阿里云收到请求,通义万象模型处理            │
│     - 分析图1、图2、图3的内容                  │
│     - 理解文字指令                            │
│     - 融合生成新图片                           │
│     ↓                                        │
│  6. 返回生成的图片 URL 给浏览器                 │
│  7. renderImage() 把图片渲染到 <div id="app"> │
└──────────────────────────────────────────────┘

七、关键知识点总结

7.1 前端工程化

概念一句话解释
Vite新一代前端构建工具,开发秒启动,打包用 Rollup
ESM(ES Module)浏览器原生模块化方案,import/export 语法
<script type="module">告诉浏览器这个脚本是 ESM 模块
import.meta.envVite 注入的全局环境变量对象,只有 VITE_ 前缀的变量能用
.env.local本地环境变量文件,不提交 Git

7.2 AI / 多模态

概念一句话解释
多模态(Multimodal)一个模型同时处理文字、图片、音频等多种类型的数据
通义万象(Qwen Image)阿里云的多模态图像生成模型
API Key调用 AI 服务的"通行证",需要保密
messages传给 AI 的对话/指令,多模态模型的 content 是数组格式
Bearer TokenHTTP 认证方式,把 Key 放在 Authorization: Bearer xxx 头里

7.3 安全

概念一句话解释
.gitignore告诉 Git 哪些文件不提交,.env.local 必须在里面
VITE_ 前缀Vite 的安全机制,只有这个前缀的变量才暴露给前端
不要在代码里写明文 Key写在 .env 文件里,用环境变量读取

八、动手实践建议

读到这里,建议你现在就动手试试——看懂和能写是两回事

  1. 跑通这个 demo:去阿里云百炼平台申请 API Key → 创建 Vite 项目 → 换成你自己的 Key → npm run dev 跑起来
  2. 改一改:换几张参考图片,换一段文字描述,看 AI 生成的结果有什么变化
  3. 拓展思考
    • 如果想把生成的图片展示得更美观,CSS 怎么写?
    • 如果想加上 loading 状态和错误处理,代码怎么改?
    • 如果用户能自己上传图片,你打算怎么做?

🌟 进阶提示:AI 接口的返回值通常需要 5-30 秒(图片生成特别慢),实际项目中记得加 loading 状态和超时处理。另外,真正上线的项目应该把 API 调用放在后端做代理——这样 API Key 完全不会暴露到浏览器里。


写在最后

前端做 AI 开发没有想象中那么遥不可及。现在的 AI 服务商(阿里、OpenAI、Claude 等)都把能力封装成了标准的 HTTP API——会用 fetch 就能写 AI 应用

本文只是一个起点。从这个 demo 出发,你可以:

  • 接入文本生成(GPT/文心一言/通义千问)→ 做智能客服、文章摘要
  • 接入语音识别 → 做语音助手
  • 接入视频理解 → 做视频内容分析

AI 时代的门槛是 API 调用,而不是微调模型。 前端大有可为,一起加油 💪


如果你觉得这篇文章有帮助,欢迎点赞、收藏、关注~ 有疑问欢迎在评论区交流!