最近大家都在玩LLM,我也凑了热闹,简单实现了一个本地LLM应用,分享给大家,百分百可以用哦~^ - ^
先介绍下我使用的三种工具:
- Ollama:一个免费的开源框架,可以让大模型很容易的运行在本地电脑上
- FastAPI:是一个用于构建 API 的现代、快速(高性能)的 web 框架,使用 Python 并基于标准的 Python 类型提示
- React:通过组件来构建用户界面的库
简单来说就类似于LLM(数据库)+FastAPI(服务端)+React(前端)
开始搭建
1、下载Ollama之后使用Ollama完成大模型的本地下载和的运行
ollama run llama3:8b
这里我下载了最新的llama3:8b,电脑配置不高的话10b以内可以无痛运行,当然啦你也可以多下几个大模型,对比一下,我还下载了qwen,对比下来同一模型越大越聪慧,国内模型对中文支持度普遍好一点。
2、模型运行之后就可以调用了
curl http://localhost:11434/api/generate -d '{
"model": "llama3:8b",
"prompt": "Why is the sky blue?",
"stream": false
}'
3、新建一个python项目,实现代码如下:
import uvicorn
from fastapi import FastAPI, Request, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
import json
import requests
from sse_starlette.sse import EventSourceResponse
import asyncio
import aiohttpapp = FastAPI(debug=True)origins = ["http://localhost",# 输入自己前端项目的地址
]# 设置跨域
app.add_middleware(CORSMiddleware,allow_origins=origins,allow_credentials=True,allow_methods=["*"],allow_headers=["*"],
)urls = ["http://localhost:11434/api/generate"]llm_list = [ {'label': 'qwen:latest', "value": 'qwen:latest'},{'label': 'llama3:8b', "value": 'llama3:8b'}, ]# 获取模型列表
@app.get("/llm/list")
def read_llm(model: str = 'qwen:latest'):return {"data": llm_list}# 这是一个异步生成器函数,它发送请求到 Ollama,并逐行读取响应内容,生成事件流。
async def stream_ollama_response(model_name, prompt):if model_name:url = urls[0]payload = {"model": model_name,"prompt": prompt,"stream": True}async with aiohttp.ClientSession() as session:async with session.post(url, json=payload) as response:async for line in response.content:if line:data = line.decode('utf-8').strip()if data:yield {"event": "message", "data": json.loads(data)["response"]}# 开始对话,接收 model_name 和 prompt 参数。它调用 event_generator 函数,启动与 Ollama 的交互,并通过 EventSourceResponse 返回事件流
@app.get("/chat")
async def generate(request: Request, model_name: str = 'qwen:latest',prompt: str = '请用中文介绍下中国古代四大名著之一的《红楼梦》'):async def event_generator():async for event in stream_ollama_response(model_name, prompt):yield eventif await request.is_disconnected():breakreturn EventSourceResponse(event_generator())if __name__ == '__main__':uvicorn.run(app="app", host="127.0.0.1", port=8000, reload=True)
这是用SSE形式实现流式输出的demo,下一篇我再讲讲如何用WebSocket实现。
4、新建一个react项目,我用了antd大礼包+@microsoft/fetch-event-source这个微软的sse插件实现,代码如下:
import { Input, Dropdown, Select, Form, Button, Space } from 'antd';
import { useEffect, useState } from 'react';
import { getList, chat } from './service';
import { useRequest } from '@umijs/max';
import { fetchEventSource } from '@microsoft/fetch-event-source';const { TextArea } = Input;# 不能走代理哦,走了代理流式就失效了,?- ?
export const getHost = () => {const isDev = process.env.NODE_ENV === 'development';if (isDev) {return 'http://127.0.0.1:8000';} else {return '';}
};export default () => {const [form] = Form.useForm();const { data = [] } = useRequest(getList);const [value, setValue] = useState('');const [start, setStart] = useState(null);const [end, setEnd] = useState(null);const [selected, setSelected] = useState(false);const [controller, setController] = useState(new AbortController());const sharedProps = {style: { width: '100%' },autoSize: { minRows: 3, maxRows: 20 },onChange: (e) => {setValue(e.target.value);setStart(e.target.selectionStart);},onClick: (e) => {setStart(e.target.selectionStart);},onSelect: (e) => {setStart(e.target.selectionStart);setEnd(e.target.selectionEnd);setSelected(e.target.value.substring(e.target.selectionStart, e.target.selectionEnd));},};const items = [{label: '重写这句话',key: '3',},{label: '把这句话翻译成中文',key: '4',},];const menuClick = ({ key }) => {switch (key) {case '3':return reWrite();case '4':return reWrite('zh-CN');}};const reWrite = async (type) => {if (!selected) {return;}setValue(value.slice(0, start) + '重写中。。。' + value.slice(end));const res = await chat({model: form.getFieldValue('model'),prompt: type? `${selected}”把“”中的这句话或单词翻译成中文,返回不要带格式,直接返回翻译结果`: selected,});setValue(value.slice(0, start) + res.data + value.slice(end));};# 获取数据流const fetchData = async (url) => {await fetchEventSource(url, {method: 'GET',signal: controller.signal,onopen(res) {if (res.ok && res.status === 200) {console.log('Connection made ', res);} else if (res.status >= 400 && res.status < 500 && res.status !== 429) {errorHandler(res);console.log('Client side error ', res);}},onmessage(event) {console.log(event);setValue((data) => [...data, event.data].join(''));},onclose() {console.log('Connection closed by the server');},onerror(err) {console.log('There was an error from server', err);},});};const onFinish = (values) => {fetchData(`${getHost()}/chat?model_name=${values.model_name}&prompt=${values.prompt}`);};return (<div><Form onFinish={onFinish} form={form}><Form.Item name="model_name" label="模型"><Select style={{ width: 200 }} options={[...data]} /></Form.Item><Form.Item name="prompt" label="提问"><Input /></Form.Item><Form.Item><Space><Button type="primary" htmlType="submit">提交</Button><Button onClick={() => controller.abort()}>暂停</Button></Space></Form.Item></Form><Dropdown menu={{ items, onClick: menuClick }} trigger={['contextMenu']}><TextArea value={value} {...sharedProps} /></Dropdown></div>);
};
界面比较简陋,大家随便看一下:
前端代码还加了些小功能,比如右键支持某句话的替换和翻译,因为用了input,所以可以获取光标的位置从而把文本插入或者替换选中文本。不过还有个弊端就是没办法支持markdown输出了,这个问题暂时还不知道怎么解决,要么再添加个预览模式。
最后的最后
感谢你们的阅读和喜欢,我收藏了很多技术干货,可以共享给喜欢我文章的朋友们,如果你肯花时间沉下心去学习,它们一定能帮到你。
因为这个行业不同于其他行业,知识体系实在是过于庞大,知识更新也非常快。作为一个普通人,无法全部学完,所以我们在提升技术的时候,首先需要明确一个目标,然后制定好完整的计划,同时找到好的学习方法,这样才能更快的提升自己。
这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费
】
一、全套AGI大模型学习路线
AI大模型时代的学习之旅:从基础到前沿,掌握人工智能的核心技能!
二、640套AI大模型报告合集
这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。
三、AI大模型经典PDF籍
随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。
四、AI大模型商业化落地方案
五、面试资料
我们学习AI大模型必然是想找到高薪的工作,下面这些面试题都是总结当前最新、最热、最高频的面试题,并且每道题都有详细的答案,面试前刷完这套面试题资料,小小offer,不在话下。
这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费
】