是的,你已经成功完成了第4天的任务! 🎉
你现在拥有的成果:
- ✅ 支持从
knowledge_base文件夹批量加载多个.txt文档 - ✅ 智能按段落切分文本(并处理长段落)
- ✅ 基于 ChromaDB 的向量检索
- ✅ FastAPI 提供的
/rag接口,能基于私有知识回答问题
从你的测试输出看,模型正确回答了"用了哪些技术"和"核心功能",说明整个 RAG 流程运转正常。
第5天任务预告:增加对话记忆 + 简易前端
让系统支持多轮对话 (记住上下文),并做一个极简的 Web 界面方便演示。
今日目标
- 对话记忆:同一个 session 内能记住之前的问答。
- Gradio 前端:10分钟搭建一个可视化的聊天界面。
预计时间
- 对话记忆改造:15分钟
- Gradio 前端:15分钟
第5天详细步骤
一、安装 Gradio
bash
pip install gradio
二、修改 app_rag.py,增加对话记忆
在现有代码基础上,增加一个字典来存储每个 session 的历史对话,并修改 /rag 接口接收 session_id。
关键改动(在原有代码中添加/修改):
python
# 在文件开头添加
from typing import List, Dict
# 存储对话历史 {session_id: [{"role": "user", "content": "..."}, {"role": "assistant", ...}]}
conversations: Dict[str, List[dict]] = {}
# 修改 RAGRequest 类
class RAGRequest(BaseModel):
question: str
session_id: str = "default"
top_k: int = 3
max_tokens: int = 200
temperature: float = 0.7
# 修改 rag_endpoint 函数,在构造 prompt 时加入历史对话
@app.post("/rag")
async def rag_endpoint(request: RAGRequest):
# 检索
question_embedding = embedder.encode(request.question).tolist()
results = collection.query(query_embeddings=[question_embedding], n_results=request.top_k)
retrieved_docs = results['documents'][0] if results['documents'] else []
# 获取最近3轮对话历史
history = conversations.get(request.session_id, [])
last_exchanges = history[-6:] # 最多保留3轮(每轮2条)
history_text = ""
for turn in last_exchanges:
history_text += f"{turn['role']}: {turn['content']}\n"
context = "\n".join(retrieved_docs) if retrieved_docs else "无相关文档。"
prompt = f"""基于以下已知信息和对话历史,回答用户问题。如果无法从已知信息中找到答案,请说"根据已有信息无法回答"。
已知信息:
{context}
对话历史:
{history_text}
用户:{request.question}
助手:"""
# 生成回答... (与之前相同)
# ... 生成 assistant_response ...
# 保存历史
conversations.setdefault(request.session_id, []).append({"role": "user", "content": request.question})
conversations[request.session_id].append({"role": "assistant", "content": assistant_response})
return {
"answer": assistant_response,
"retrieved_docs": retrieved_docs,
"session_id": request.session_id
}
三、创建独立的 Gradio 前端文件 ui.py
python
import gradio as gr
import requests
API_URL = "http://127.0.0.1:8000/rag"
def chat_with_bot(message, history):
"""发送消息到后端 RAG API,并返回回复"""
# 使用 gradio 自带的 session hash 作为 session_id
session_id = str(gr.get_session_id())
try:
resp = requests.post(API_URL, json={
"question": message,
"session_id": session_id,
"top_k": 3,
"max_tokens": 200,
"temperature": 0.7
})
if resp.status_code == 200:
answer = resp.json()["answer"]
else:
answer = f"API 错误: {resp.status_code}"
except Exception as e:
answer = f"连接失败: {str(e)}"
return answer
# 构建界面
with gr.Blocks(title="私有知识库问答系统") as demo:
gr.Markdown("# 📚 基于本地大模型的 RAG 问答系统")
gr.Markdown("上传文档到 `knowledge_base` 文件夹,然后向我提问吧!")
chatbot = gr.Chatbot(height=500)
msg = gr.Textbox(label="输入问题", placeholder="例如:我的项目用了哪些技术?")
clear = gr.Button("清空对话")
def respond(message, chat_history):
bot_message = chat_with_bot(message, chat_history)
chat_history.append((message, bot_message))
return "", chat_history
msg.submit(respond, [msg, chatbot], [msg, chatbot])
clear.click(lambda: None, None, chatbot, queue=False)
if __name__ == "__main__":
demo.launch(server_name="127.0.0.1", server_port=7860)
上述代码有兼容性问题,改成了下面的代码
python
import gradio as gr
import requests
API_URL = "http://127.0.0.1:8000/rag"
def predict(message, history):
"""发送消息并返回回答"""
try:
resp = requests.post(API_URL, json={
"question": message,
"top_k": 3,
"max_tokens": 200,
"temperature": 0.7
})
if resp.status_code == 200:
return resp.json()["answer"]
else:
return f"API 错误: {resp.status_code}"
except Exception as e:
return f"连接失败: {str(e)}"
# 创建界面(兼容旧版 Gradio)
iface = gr.ChatInterface(fn=predict, title="RAG 问答系统")
iface.launch(server_name="127.0.0.1", server_port=7860)
四、运行
-
确保后端服务已启动 (
uvicorn app_rag:app --reload --port 8000) -
新开一个终端 ,激活
ai_env,运行:bashpython ui.py -
浏览器会自动打开
http://127.0.0.1:7860,即可进行多轮对话。
今日产出
- 支持多轮对话的 RAG 后端
- 一个漂亮的 Web 聊天界面
完成这一步,你就拥有一个完整的、可演示的私有知识库问答系统了。继续加油!如果遇到问题,请随时截图。