在大模型盛行的当下,AI早已融入我们的工作与生活,无论是前端开发者还是后端开发者,掌握AI相关知识都成为了必备技能。作为前端开发者,今天就来和大家分享一下,纯前端如何与AI实现高效结合。
单纯的前端开发与AI的直接结合空间确实有限,但这并不意味着JS/TS与AI的联系不够紧密。事实上,现在很多AI相关工具(比如Claude Code)都是基于JS/TS开发的。不过今天我们重点聚焦,纯前端层面如何与AI对接、交互。
一、前端如何发起AI请求
前端与AI的结合,核心本质就是调用AI的API服务------这些API既可以来自大模型服务厂商,也可以来自后端代理,本质上都是通过接口请求实现交互。下面我们直接讲解两种最常见的请求方式,从基础到实战逐步拆解。
第一种,调用自己后端搭建的AI服务接口:
javascript
// 后端服务地址
const url = "http://localhost:8081/api/ai/generate"
const res = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
messages: [{ role: "user", content: prompt }],
...... // 可添加更多请求参数,后续详细说明
}),
})
第二种,前端直接调用模型提供商的API(以魔搭社区为例,其提供免费请求次数,非常适合学习使用):
javascript
const url = 'https://api-inference.modelscope.cn/v1/chat/completions';
const apiKey = ''; // 替换为你的个人Token
const modelId = 'MiniMax/MiniMax-M2.5'; // 替换为你选择的Model-Id
const res = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${apiKey}` // 注意:此处需使用Bearer认证
},
body: JSON.stringify({
model: modelId,
messages: [
{ role: 'system', content: 'You are a helpful assistant.' },
{ role: 'user', content: '你好' }
],
})
});
两种方式的核心逻辑基本一致,最大的区别在于:纯前端直接调用厂商API时,模型地址、Model-Id,尤其是apiKey会直接暴露在前端,存在被盗用滥用的风险,进而可能造成不必要的损失,这一点需要特别注意。
二、如何解析AI的流式响应(SSE)
我们日常使用的AI工具,大多采用"流式响应"(SSE技术)返回结果,也就是逐字、逐段展示回复,提升用户体验。作为前端开发者,掌握SSE响应的解析方法是必备技能。
先看一段标准的SSE响应格式:
json
data: {"type":"reasoning","content":"我们"}
data: {"type":"reasoning","content":"用户"}
data: {"type":"reasoning","content":"说"}
data: {"type":"reasoning","content":"""}
data: {"type":"reasoning","content":"你好"}
data: {"type":"reasoning","content":"啊"}
data: {"type":"reasoning","content":"","}
data: {"type":"reasoning","content":"这是一个"}
data: {"type":"reasoning","content":"简单的"}
data: {"type":"reasoning","content":"问候"}
data: {"type":"reasoning","content":","}
...
data: [DONE]
解析这类流式响应,我们需要用到"读取器(Reader)"和"文本解码器(TextDecoder)",核心逻辑是逐段读取响应数据、解码并拼接,完整代码如下:
javascript
// 后端服务地址
const url = "http://localhost:8081/api/ai/generate"
export async function chat(prompt: string, onMessage?: (content: string) => void) {
const res = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
messages: [{ role: "user", content: prompt }],
}),
})
const reader = res.body.getReader(); // 创建读取器,读取流式响应
const decoder = new TextDecoder("utf-8"); // 创建文本解码器,解析响应数据
let buffer = ""; // 存储最终解析后的完整响应内容
while (true) {
const { done, value } = await reader.read();
if (done) {
break; // 响应读取完毕,终止循环
}
// 解析当前读取到的流式数据
const newContent = transformStreamToText(decoder.decode(value, { stream: true }));
buffer += newContent;
// 若传入回调函数,实时返回每一段解析后的内容
if (onMessage && newContent) {
onMessage(newContent);
}
}
console.log(buffer);
return buffer;
}
// 流式数据解析工具函数
function transformStreamToText(buffer: string): string {
let result = "";
const lines = buffer.split("\n"); // 按换行符分割每一段响应
for (const line of lines) {
if (line.startsWith("data: ")) { // 筛选出有效响应数据
try {
const jsonStr = line.slice(6); // 截取"data: "后的JSON字符串
const json = JSON.parse(jsonStr);
// 提取响应中的文本内容,兼容不同返回格式
const text = json.content || json.data?.content || "";
result += text;
} catch (error) {
console.warn("解析数据失败:", line, error);
}
}
}
return result;
}
下面是在React项目中实际使用的示例,实现AI响应的实时流式展示:
javascript
import { chat } from './utils/ai' // 记得替换为你的实际文件路径
import { useEffect, useState } from 'react'
function App() {
const [text, setText] = useState('') // 定义状态,存储AI的流式回复
// 页面加载后自动发起AI请求
useEffect(() => {
// 调用chat函数,传入提示词和实时更新回调
chat("你好", (newChunk) => {
// 每次收到一段响应,追加到状态中,实现实时展示
setText(prev => prev + newChunk)
})
}, [])
// 渲染页面,展示AI回复
return (
<div style={{ padding: 20 }}>
<h1>AI 回复:</h1>
<div style={{ whiteSpace: 'pre-wrap' }}>
{text}
</div>
</div>
)
}
export default App
到这里,我们就掌握了前端解析AI流式响应的基础用法,能够实现AI回复的实时展示效果。
三、AI请求的高级用法
前面我们实现的是最基础的AI交互,接下来我们补充一些细节优化和高级用法,让前端与AI的结合更灵活、更贴合实际需求。
1. 关闭流式响应
并非所有场景都需要流式响应,我们可以通过一个简单的参数(stream: false),让AI完整生成回复后再一次性返回,无需逐段展示。
javascript
const url = 'https://api-inference.modelscope.cn/v1/chat/completions';
const apiKey = ''; // 替换为你的Token
const modelId = 'MiniMax/MiniMax-M2.5'; // 替换为你的Model-Id
const res = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${apiKey}`
},
body: JSON.stringify({
model: modelId,
messages: [
{ role: 'system', content: 'You are a helpful assistant.' },
{ role: 'user', content: '你好' }
],
stream: false // 关闭流式响应,完整生成后返回
})
});
关闭流式响应后,AI会返回完整的JSON结构数据,包含请求ID、模型信息、回复内容、Token消耗等详细信息,示例如下(以DeepSeek模型为例):
json
{
"id": "79c45daa-59e8-4072-a1c8-6e41c27f3e6a",
// [字符串] 本次请求的唯一标识符。如果接口报错,你可以把这个 ID 发给客服或开发者进行排查。
"object": "chat.completion",
// [字符串] 对象类型。固定值,表示这是一个聊天补全(Chat Completion)的响应对象。
"created": 1777898203,
// [整数] Unix 时间戳(秒)。表示这条回复生成的具体时间。
"model": "deepseek-v4-flash",
// [字符串] 实际处理请求的模型名称。这里使用的是 DeepSeek 的 V4 Flash 版本。
"choices": [
// [数组] 生成的回复选项列表。通常只有一个选项,除非你设置了 n > 1 要求生成多个回答。
{
"index": 0,
// [整数] 当前选项在列表中的索引,从 0 开始。
"message": {
// [对象] 具体的消息内容。
"role": "assistant",
// [字符串] 消息发送者的角色。这里是 "assistant",表示这是 AI 生成的回复。
"content": "你好呀!很高兴见到你!😊\n\n我是DeepSeek,由深度求索公司创造的AI助手。我可以帮你解答各种问题、进行创作、分析资料、或者只是陪你聊聊天。无论是工作学习上的难题,还是生活中有趣的疑问,或者只是想找人说说话,我都在这里!\n\n有什么我可以帮你的吗?尽管说,我会全力以赴帮你解答的!✨",
// [字符串] AI 最终展示给用户看的文本内容。
"reasoning_content": "好的,用户打了一个简单的招呼"你好"。这是一个非常常见的开场白,通常表示用户初次接触或准备开始对话。\n\n我需要一个友好、热情的回应来建立良好的互动氛围。可以自然地介绍自己,并表达愿意提供帮助的立场,这样能引导用户提出后续的具体问题。\n\n想到了用"你好呀"来体现亲切感,然后进行自我介绍,最后加上一个开放性的询问,邀请用户提出需求。这样既完成了礼貌回应,又为后续对话打开了通道。"
// [字符串] 模型的"内心独白"或"思维链"。
// 这是 DeepSeek 等推理模型特有的字段,展示了 AI 在生成最终答案前的思考过程。
},
"finish_reason": "stop",
// [字符串] 模型停止生成的原因。
// "stop" 表示自然结束(说完了);"length" 表示达到长度限制;"tool_calls" 表示去调用工具了。
"content_filter_results": {
// [对象] 内容安全过滤的检测结果。
"hate": { "filtered": false }, // 仇恨言论:未过滤
"self_harm": { "filtered": false }, // 自残内容:未过滤
"sexual": { "filtered": false }, // 色情内容:未过滤
"violence": { "filtered": false }, // 暴力内容:未过滤
"jailbreak": { "filtered": false, "detected": false }, // 越狱攻击:未检测到
"profanity": { "filtered": false, "detected": false } // 脏话:未检测到
}
}
],
"usage": {
// [对象] Token 消耗统计,用于计费和监控。
"prompt_tokens": 5,
// [整数] 你发送给模型的输入(提示词)消耗了 5 个 token。
"completion_tokens": 182,
// [整数] 模型生成的输出消耗了 182 个 token。
"total_tokens": 187,
// [整数] 总消耗 token 数(输入 + 输出)。
"prompt_tokens_details": {
// [对象] 输入 Token 的详细构成。
"audio_tokens": 0, // 音频输入消耗的 token
"cached_tokens": 0 // 命中缓存的 token(命中缓存通常更便宜或更快)
},
"completion_tokens_details": {
// [对象] 输出 Token 的详细构成。
"audio_tokens": 0, // 音频输出消耗的 token
"reasoning_tokens": 100, // 【重点】用于"思考"的 token。
// 注意:这 100 个 token 包含在上面的 completion_tokens (182) 中,
// 对应上面 message 里的 reasoning_content 部分。
"accepted_prediction_tokens": 0, // 接受的预测 token(通常与推测解码技术有关)
"rejected_prediction_tokens": 0 // 拒绝的预测 token
}
},
"system_fingerprint": "fp_058df29938_prod0820_fp8_kvcache_20260402"
// [字符串] 系统指纹。代表模型运行时的后端配置版本。
// 如果这个值变了,说明模型底层的部署环境或参数发生了变化,可能会影响结果的稳定性。
}
2. 常用请求参数补充
除了stream参数,AI API还支持很多实用参数,用于控制回复风格、长度、逻辑等,下面给大家分享常用参数及代码示例,方便直接套用:
| 参数名 | 类型 | 默认值 | 作用详解 | 建议设置 |
|---|---|---|---|---|
| model | String | - | 指定模型,指定服务端使用哪个大模型进行回答,例如 gpt-4o、qwen-plus、deepseek-v3 等 | 必填项,按业务场景自行选择合适模型 |
| temperature | Number | 1 | 控制AI创造力与随机性: • 0 ~ 0.3:严谨、确定性高,适合数学计算、代码生成 • 0.7 ~ 1.0:自然流畅,适合日常聊天、文案写作 • > 1.0:发散性极强,容易逻辑混乱、胡编乱造 | 写代码/做题设 0;聊天写文案设 0.8 |
| max_tokens | Number | 无限制 | 限制AI最大输出 Token 数量,1 Token 约等于 0.7 个汉字,避免回复过长冗余 | 常规场景建议设置 2000 ~ 4000 |
| top_p | Number | 1 | 核采样,是另一种控制随机度的方式,一般和 temperature 二选一调整,不建议同时修改 | 日常开发保持默认 1.0 即可 |
| response_format | Object | - | 强制指定AI输出格式,可设置为 {"type": "json_object"},强制只返回标准JSON,方便前端直接解析自动化处理 |
需要结构化数据、接口对接时设为 json_object |
| frequency_penalty | Number | - | 频率惩罚,取值范围 0~2;数值越大,越抑制重复词汇、重复句式出现,避免AI复读 | AI频繁重复话术时,设置 0.5 即可 |
| presence_penalty | Number | - | 话题惩罚,取值范围 0~2;数值越大,越鼓励AI拓展新话题,不局限上下文内容 | 需要话题发散、自由创作时设置 0.5 |
| stop | Array | - | 停止生成符;AI生成内容遇到数组内指定字符/字符串时,立刻终止输出 | 例:设置 ["\n\n"],遇到空行自动停止 |
| stream | Boolean | - | 流式输出开关;true 为打字机逐字返回,false 等待完整生成后一次性返回 | 聊天对话页面设 true;接口一次性取数据设 false |
| tools | Array | - | 工具调用配置;定义AI可调用的外部函数(天气查询、计算器、接口请求等),AI会返回调用指令而非直接回答 | 需要函数调用、联网能力时配置 |
| user | String | - | 自定义用户唯一ID,用于大模型厂商风控、监控接口滥用、区分不同会话用户 | 传入项目内用户唯一标识即可 |
代码示例
javascript
const body = JSON.stringify({
// 1. 基础信息
model: "qwen-plus", // 指定调用的AI模型
messages: [
{ role: "system", content: "你是一个严谨的数学老师。" },
{ role: "user", content: "1+1等于几?" }
],
// 2. 控制回复风格与长度
temperature: 0.2, // 取值0-1,值越低越严谨,避免随机发挥
max_tokens: 500, // 限制回复最大Token数,防止内容过长
// 3. 控制回复逻辑
frequency_penalty: 0.5, // 惩罚重复内容,避免冗余
response_format: { type: "text" } // 强制输出纯文本(默认值)
// 4. 流式响应开关(按需开启/关闭)
stream: true
});
3. 重点参数详解
下面重点讲解两个高频实用的参数,帮助大家更好地控制AI回复效果:
(1)response_format:强制JSON输出
该参数用于让AI仅返回JSON格式数据,避免多余的客套话和Markdown格式,方便前端直接解析使用,尤其适合需要AI返回结构化数据的场景。
javascript
// 假设用户提问:"返回一个包含name和age的JSON"
// 1. 不加 response_format 的结果(含多余内容,无法直接解析)
const result1 = `好的,这是你要的数据:
\`\`\`json
{
"name": "张三",
"age": 18
}
\`\`\`
`;
// ❌ 错误:JSON.parse(result1) 会报错
// 2. 加上 response_format: { type: "json_object" } 的结果(纯JSON)
const result2 = `{"name": "张三", "age": 18}`;
// ✅ 正确:JSON.parse(result2) 可直接解析成功
(2)tools:工具调用(Function Calling)
工具调用是AI的高级功能,我们可以自定义工具(如天气查询、接口调用等),让AI根据用户提问,判断是否需要调用工具获取数据后再生成回复。注意:AI仅会返回工具调用指令,不会主动执行工具,需要前端自行判断并执行。
第一步:定义工具(告诉AI可调用的工具及参数)
javascript
// 1. 工具定义:描述工具功能和参数要求
const tools = [{
type: "function",
function: {
name: "get_weather",
description: "获取指定城市的天气",
parameters: {
type: "object",
properties: { city: { type: "string" } },
required: ["city"]
}
}
}];
// 2. 工具实现:前端本地编写工具执行逻辑
const mockRunTool = (name, args) => {
if (name === "get_weather") return `北京今天晴天,25度`;
return "未知工具";
};
第二步:判断AI是否需要调用工具
javascript
// 假设用户提问:"帮我查一下北京的天气"
// 1. AI 决定调用工具时的返回结果
const toolCallResult = {
role: "assistant",
content: null, // 注意:调用工具时,content为空
tool_calls: [ // 工具调用指令,包含函数名和参数
{
id: "call_abc123",
type: "function",
function: {
name: "get_weather",
arguments: "{\"city\": \"北京\"}"
}
}
]
};
// 🤖 AI 指令:请执行get_weather函数,参数为北京
// 2. AI 直接回答时的返回结果
const normalResult = {
role: "assistant",
content: "北京今天天气晴朗,气温 25 度。", // 直接返回文字内容
tool_calls: undefined // 无工具调用指令
};
// 💬 AI 直接给出答案,无需调用工具
第三步:前端执行工具调用逻辑
javascript
// 假设这是fetch返回的AI响应结果
const message = response.choices[0].message;
// 核心逻辑:判断AI是否需要调用工具,决定下一步操作
if (message.tool_calls) {
// 情况A:AI返回工具调用指令,执行对应工具
console.log("🤖 AI 决定调用工具,正在解析参数...");
const call = message.tool_calls[0];
const name = call.function.name; // 拿到工具函数名:get_weather
const args = JSON.parse(call.function.arguments); // 拿到参数:{city: "北京"}
// 执行工具函数,获取结果(AI不执行,前端自行执行)
const result = mockRunTool(name, args);
// 可选:将工具执行结果回传给AI,让AI生成最终回复
// ... (后续可发起第二轮请求,将result传入messages)
} else {
// 情况B:AI直接返回答案,直接展示给用户
console.log("💬 AI 直接回答了:", message.content);
renderText(message.content);
}
四、前端与AI结合的常见问题与解决方案
前端对接AI API开发中,整理4个高频问题+精简解决方案,新手直接避坑。
1. API调用失败(跨域、401/403)
跨域问题
前端直连魔搭、OpenAI 等第三方AI接口必遇跨域,浏览器报 Access-Control-Allow-Origin。
- 推荐方案:后端代理转发 ,同时隐藏
apiKey - 备选方案:个人学习可让厂商配置跨域白名单,不适合生产
401/403 权限错误
大多是 apiKey 错误/过期、Model-Id 不匹配。
- 检查
apiKey正误、区分测试/正式密钥 - 核对
Model-Id与接口域名一致,密钥过期重新申请
2. 流式响应解析异常(卡顿、乱码)
常见问题:解析卡顿、中文乱码、丢内容。
根因:编码不对、流式数据分割不规范。
解决要点:
- 强制使用 UTF-8 解码
- 过滤空行、捕获异常、忽略
[DONE]标记
javascript
// 优化后的流式解析函数(增加异常过滤)
function transformStreamToText(buffer: string): string {
let result = "";
const lines = buffer.split("\n").filter(line => line.trim() !== "");
for (const line of lines) {
if (line.startsWith("data: ")) {
try {
const jsonStr = line.slice(6);
if (jsonStr.trim() === "[DONE]") return result;
const json = JSON.parse(jsonStr);
const text = json.content || json.data?.content || "";
result += text;
} catch (error) {
console.warn("解析单条数据失败:", line, error);
continue;
}
}
}
return result;
}
3. apiKey 泄露风险防控
前端硬编码 apiKey 极易被盗刷、扣费。
- 方案一(推荐)后端代理
密钥、模型ID全存在后端,前端只调自己业务接口,杜绝泄露,还能做限流、请求日志。 - 方案二(临时过渡)
无后端时用临时密钥,控制台限制IP访问、每日调用次数,仅适合学习,禁止上线。
4. 响应速度优化
三点实用优化:
- 合理配置 max_tokens,限制最大输出长度,减少冗余与耗时
- 对固定问答开启前端本地缓存,重复请求不走AI接口
- 按需选型模型:简单场景用轻量小模型,复杂任务再用大模型
五、前端与AI结合实际应用场景
1. 智能客服 / 聊天机器人
网站、APP 对话问答,搭配SSE流式输出实现打字机效果;通过 system 角色限定回答范围,结合工具调用可实现订单、天气查询。
2. 富文本AI增强编辑
集成文本纠错、润色、翻译、内容摘要,输入内容交给AI处理,实时回显到编辑器,适合博客、文案后台。
3. AI 可视化生成
自然语言描述生成图表、代码、简单海报;AI 返回配置/代码,前端用 ECharts、Canvas 直接渲染。
4. 个性化内容推荐
基于用户浏览行为,用AI分析兴趣标签,前端动态渲染文章、商品推荐,提升留存。
5.简单的工作流
可以使用ai进行搭建一些简单的工作流,我最近就在做这样的一个项目,由我个人主导开发,到时候开发完毕会进行开源分享,感兴趣的朋友可以点个关注等候一下
六、总结与后续学习方向
前端和AI结合的核心就三点:接口调用 + 流式数据解析 + 业务场景落地。
后续学习建议:
- 吃透各大平台AI API 差异,熟练掌握 temperature、top_p、response_format 等常用参数
- 在 React / Vue 中封装通用AI请求、流式Hook,减少重复造轮子
- 学习 TensorFlow.js 前端本地轻量化模型,实现离线AI能力,不依赖第三方接口
只要多动手实战,把接口、流式解析、参数配置练熟,就能把AI能力无缝集成到任何前端项目中。