老板看了竞品,眼睛发光:“我们也上 AI!用户问啥都得秒回!” 我默默算了算 OpenAI 的账单——一个月 2 万,一年 24 万,够全组去三亚团建三次。于是我干了件疯狂的事:把 AI 模型塞进用户浏览器里。不用服务器,不花一分钱 API,用户电脑自己跟自己聊天。老板看着账单上的 “0”,问我是不是偷偷充了值。
这事儿起因很简单:老板要 AI 客服。大模型 API 便宜吗?初看几分钱一次,用户一多,一个月一辆特斯拉没了。而且用户问的重复问题占 80%,每问一次就烧一次钱,像开着水龙头浇花。
我寻思:能不能把模型直接扔到用户浏览器里?现在电脑、手机性能过剩,跑个小模型绰绰有余。说干就干,我找到了Transformers.js——一个能在浏览器里跑 Hugging Face 模型的库,完全本地推理,不花一分钱 API,隐私还安全。
今天我就带你手把手在 React 里集成一个本地 AI 问答模型(用的还是微软的Phi-3 mini,效果媲美 GPT-3.5,体积只有 2GB 左右,量化后更小)。用户打开网页,模型自动下载到 IndexedDB,然后所有对话都在他电脑上完成。老板再也不用看账单了。
缺点:首次加载慢(下载模型),低端设备可能卡。但你可以用闲时下载 + 缓存策略,用户第一次访问花一分钟,之后秒开。
Transformers.js 是 Hugging Face 官方库,支持在浏览器里运行 Transformer 模型。它自动利用 WebGL 加速,比纯 CPU 快 5-10 倍。
我们要用的模型:Phi-3-mini-4k-instruct(微软出品,38 亿参数,量化后约 2GB)。太大了?别急,有128k 上下文版更小,或者用TinyLLaMA 1.1B(量产后几百 MB)。我推荐先上onnx-community/Phi-3-mini-4k-instruct-onnx,经过 ONNX 优化,体积更友好。
npm install @xenova/transformers
// hooks/useLocalLLM.js
import { pipeline, env } from '@xenova/transformers';
// 设置模型缓存路径(IndexedDB)
env.localModelPath = '/models/';
env.useBrowserCache = true;
export function useLocalLLM() {
const [generator, setGenerator] = useState(null);
const [loading, setLoading] = useState(true);
const [progress, setProgress] = useState(0);
useEffect(() => {
const loadModel = async () => {
// 加载文本生成模型(这里用Phi-3的ONNX版本)
const pipe = await pipeline('text-generation', 'onnx-community/Phi-3-mini-4k-instruct-onnx', {
progress_callback: (p) => {
if (p.status === 'downloading') {
setProgress(p.progress);
}
},
});
setGenerator(() => pipe);
setLoading(false);
};
loadModel();
}, []);
const generate = async (prompt, options = {}) => {
if (!generator) return;
const result = await generator(prompt, {
max_new_tokens: 256,
temperature: 0.7,
...options,
});
return result[0].generated_text;
};
return { generate, loading, progress };
}
function AIChat() {
const { generate, loading, progress } = useLocalLLM();
const [question, setQuestion] = useState('');
const [answer, setAnswer] = useState('');
const [isGenerating, setIsGenerating] = useState(false);
const ask = async () => {
if (!question.trim() || isGenerating) return;
setIsGenerating(true);
// Phi-3 指令格式
const prompt = `<|user|>\n${question}\n<|end|>\n<|assistant|>\n`;
const response = await generate(prompt);
setAnswer(response.replace(prompt, '').trim());
setIsGenerating(false);
};
if (loading) {
return <div>正在加载AI模型 {Math.round(progress * 100)}% ... (首次约需1分钟)</div>;
}
return (
<div>
<textarea value={question} onChange={e => setQuestion(e.target.value)} />
<button onClick={ask} disabled={isGenerating}>问AI</button>
{isGenerating && <div>AI在你电脑里拼命想...</div>}
{answer && <div className="answer">{answer}</div>}
</div>
);
}
int8或fp16版本,体积减半。我的建议:混合模式。默认用本地模型,如果用户设备太老或模型下载失败,fallback 到云端 API。既省钱又不丢用户体验。
上线后,老板问:“这月 AI 账单怎么是 0?” 我说:“我把 AI 搬到用户浏览器里了。” 他沉默了三秒:“那岂不是我们没数据了?” 我说:“要数据干嘛?又卖不掉。省下的钱给我们加鸡腿。” 老板居然同意了。
下次老板再让你接入 AI,你可以淡定地说:“本地跑,不花钱,隐私好。” 然后默默打开这篇文章——代码都给他准备好了。
评论区聊聊:你的公司花多少钱在 AI API 上?想不想省下来换新电脑?