在本地搭建RAG系统自主开发前端


当然可以!如果不需要集成 Open WebUI,你可以完全自主开发 Web 前端。以下是完整的解决方案:


1. 技术选型

  • 前端:React/Vue.js + Axios(HTTP请求)
  • 后端:FastAPI(Python)
  • RAG核心:LangChain + Chroma + Ollama(或其他本地LLM)

2. 实现步骤(附代码)

步骤1:确保RAG服务已运行

使用之前的 rag_api.py,启动 FastAPI 服务:

1
uvicorn rag_api:app --host 0.0.0.0 --port 5000

步骤2:创建基础前端

以 React 为例,快速搭建:

1
2
3
npx create-react-app rag-frontend
cd rag-frontend
npm install axios @mui/material @mui/icons-material

步骤3:核心前端代码

修改 src/App.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import React, { useState } from 'react';
import axios from 'axios';
import { Box, TextField, Button, CircularProgress, Typography } from '@mui/material';

function App() {
const [query, setQuery] = useState('');
const [answer, setAnswer] = useState('');
const [loading, setLoading] = useState(false);

const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
try {
const response = await axios.post('http://localhost:5000/generate', {
text: query
});
setAnswer(response.data.answer);
} catch (error) {
setAnswer(`错误: ${error.message}`);
}
setLoading(false);
};

return (
<Box sx={{ maxWidth: 800, margin: '2rem auto', padding: 3 }}>
<form onSubmit={handleSubmit}>
<TextField
fullWidth
variant="outlined"
label="输入你的问题"
value={query}
onChange={(e) => setQuery(e.target.value)}
disabled={loading}
/>
<Button
type="submit"
variant="contained"
sx={{ mt: 2 }}
disabled={loading}
>
{loading ? <CircularProgress size={24} /> : '提交'}
</Button>
</form>

{answer && (
<Box sx={{ mt: 4, p: 3, bgcolor: '#f5f5f5', borderRadius: 2 }}>
<Typography variant="h6" gutterBottom>回答:</Typography>
<Typography>{answer}</Typography>
</Box>
)}
</Box>
);
}

export default App;

步骤4:启动前端

1
npm start

访问 http://localhost:3000 即可使用。


3. 进阶功能扩展

功能1:对话历史记录

1
2
3
4
5
6
7
8
// 在 App.js 中添加状态
const [history, setHistory] = useState([]);

// 提交后记录历史
const handleSubmit = async (e) => {
// ...原有代码...
setHistory(prev => [...prev, { question: query, answer: response.data.answer }]);
};

功能2:文件上传接口

后端新增端点(rag_api.py):

1
2
3
4
5
6
7
from fastapi import UploadFile, File

@app.post("/upload")
async def upload_file(file: UploadFile = File(...)):
with open(f"./docs/{file.filename}", "wb") as f:
f.write(await file.read())
return {"status": "文件已更新,请重新执行向量化"}

前端添加上传组件:

1
2
3
4
5
6
<input type="file" onChange={async (e) => {
const file = e.target.files[0];
const formData = new FormData();
formData.append('file', file);
await axios.post('http://localhost:5000/upload', formData);
}} />

功能3:流式输出

后端修改(SSE实现):

1
2
3
4
5
6
7
8
9
10
from sse_starlette.sse import EventSourceResponse

@app.get("/stream-generate")
async def stream_generate(query: str):
async def event_generator():
result = qa_chain.run(query)
for word in result.split():
yield {"data": word}
await asyncio.sleep(0.1)
return EventSourceResponse(event_generator())

前端使用 EventSource:

1
2
3
4
5
6
7
const eventSource = new EventSource(
`http://localhost:5000/stream-generate?query=${encodeURIComponent(query)}`
);

eventSource.onmessage = (e) => {
setAnswer(prev => prev + e.data + ' ');
};

4. 部署优化

生产环境部署

1
2
3
4
5
# 前端构建
npm run build

# 使用Nginx托管
docker run -d -p 80:80 -v $(pwd)/build:/usr/share/nginx/html nginx

性能优化

1
2
3
4
5
# 后端添加缓存
from fastapi_cache import FastAPICache
from fastapi_cache.backends.inmemory import InMemoryBackend

FastAPICache.init(InMemoryBackend())

5. 自主开发 vs Open WebUI 对比

特性 自主开发前端 Open WebUI
定制灵活性 ⭐⭐⭐⭐⭐ ⭐⭐
开发成本 需要前端开发能力 零成本快速集成
功能扩展性 无限制 受限于项目功能
多模型支持 需自行实现 原生支持
适合场景 企业级定制/特殊需求 快速原型/个人使用

6. 自研前端的核心优势

  1. 完全控制UI/UX:可自定义交互流程和视觉风格
  2. 深度集成业务逻辑:添加审批流程、权限控制等企业特性
  3. 数据隔离:敏感数据无需经过第三方界面
  4. 性能优化:针对特定场景做前端专项优化

通过上述方案,你可以用约 100 行代码实现一个基础但完整的前端,后续可根据需求逐步扩展功能。自主开发的关键优势在于能精准匹配业务需求,特别适合需要高度定制化的场景。