最近大家都在玩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 aiohttp
app = 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 event
if await request.is_disconnected():
break
return 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 = () =>