如何通过Flask框架对接Jupyter Notebook中LLM生成MCQ题目的代码并实现前端展示
如何通过Flask框架对接Jupyter Notebook中LLM生成MCQ题目的代码并实现前端展示
我来帮你梳理下怎么把这段生成MCQ的LangChain代码和Flask结合,把题目展示到前端——其实核心就是把你的RAG逻辑封装成Flask的API接口,再写个简单的前端页面调用它就行,一步步来:
第一步:重构代码为Flask应用结构
首先把你原来的Jupyter代码改成适合Flask运行的结构,核心是把生成MCQ的逻辑封装成API接口,同时保留你的RAG链逻辑。注意要补充你原来代码里省略的retriever、mcq_prompt、llm的定义(比如你用的向量库、LLM模型配置)。
from langchain.schema.runnable import RunnableParallel, RunnableLambda import json import re from flask import Flask, request, jsonify, render_template # 初始化Flask应用 app = Flask(__name__) # ------------------- 这里补充你原来的配置 ------------------- # 比如向量检索器(Chroma/FAISS等)、LLM模型、MCQ提示词的定义 # 示例(根据你实际使用的工具调整): # from langchain.vectorstores import Chroma # from langchain.embeddings import OpenAIEmbeddings # from langchain.chat_models import ChatOpenAI # from langchain.prompts import ChatPromptTemplate # 配置LLM(确保设置好API密钥,比如通过环境变量) # llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.7) # 配置向量检索器 # retriever = Chroma(persist_directory="./your_vector_db_path", embedding_function=OpenAIEmbeddings()).as_retriever() # 定义MCQ生成的提示词(mcq_prompt) # mcq_prompt = ChatPromptTemplate.from_template(""" # 你是一个专业的MCQ出题老师,根据给定的科目、知识点和上下文生成符合要求的MCQ题目,输出格式为JSON数组... # """) # --------------------------------------------------------- # 原来的retrieve_context函数保留 def retrieve_context(inputs): query = f"{inputs['subject']} - {', '.join(inputs['topics'])}" retrieved_docs = retriever.invoke(query) if not retrieved_docs: return "No relevant documents found." return "\n\n".join([doc.page_content for doc in retrieved_docs]) # 构建你的RAG链 rag_chain = ( RunnableParallel({ "subject": lambda x: x["subject"], "topics": lambda x: x["topics"], "context": RunnableLambda(retrieve_context), }) | mcq_prompt | llm ) # 定义生成MCQ的API接口(接收POST请求) @app.route('/generate-mcq', methods=['POST']) def generate_mcq(): # 获取前端传过来的科目和知识点 data = request.get_json() subject = data.get('subject') topics = data.get('topics', []) # 参数校验 if not subject or not topics: return jsonify({"error": "科目和知识点不能为空!"}), 400 try: # 调用RAG链生成MCQ response = rag_chain.invoke({"subject": subject, "topics": topics}) # 提取并解析JSON结果(你原来的正则提取逻辑保留) json_match = re.search(r"\[\s*{.*}\s*\]", response.content, re.DOTALL) if not json_match: return jsonify({"error": "LLM返回结果中未找到JSON格式的题目数据"}), 500 json_str = json_match.group(0) mcq_data = json.loads(json_str) # 转换成前端友好的字典格式 mcq_dict = {f"Q{i+1}": item for i, item in enumerate(mcq_data)} return jsonify(mcq_dict) except Exception as e: return jsonify({"error": f"生成MCQ失败:{str(e)}"}), 500 # 定义前端页面的路由 @app.route('/') def index(): # 渲染前端页面 return render_template('index.html') if __name__ == '__main__': # 运行Flask应用(开发环境用debug模式,生产环境要关闭) app.run(debug=True)
第二步:编写前端展示页面
在Flask项目的templates文件夹下创建index.html,这个页面提供输入表单,调用API生成并展示MCQ题目:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>MCQ题目生成器</title> <style> .container { max-width: 800px; margin: 20px auto; padding: 0 20px; } .input-group { margin: 15px 0; } .input-group label { display: block; margin-bottom: 5px; font-weight: bold; } .input-group input { width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; } button { padding: 10px 20px; background-color: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; margin-right: 10px; } button:hover { background-color: #0056b3; } .mcq-question { margin: 20px 0; padding: 15px; border: 1px solid #eee; border-radius: 8px; background-color: #f9f9f9; } .option { margin: 8px 0; padding-left: 5px; } .correct-answer { margin-top: 10px; font-weight: bold; color: #28a745; } #results { margin-top: 30px; display: none; } </style> </head> <body> <div class="container"> <h1>生成MCQ练习题</h1> <div class="input-group"> <label for="subject">科目:</label> <input type="text" id="subject" placeholder="例如:Chemistry"> </div> <div class="input-group"> <label>知识点(可添加多个):</label> <div id="topics-container"> <input type="text" class="topic-input" placeholder="例如:structure of benzene"> </div> <button onclick="addTopicInput()">添加更多知识点</button> </div> <button onclick="generateMCQ()">生成题目</button> <div id="results"> <h2>生成的MCQ题目</h2> <div id="questions-list"></div> </div> </div> <script> // 动态添加知识点输入框 function addTopicInput() { const container = document.getElementById('topics-container'); const input = document.createElement('input'); input.type = 'text'; input.className = 'topic-input'; input.placeholder = '例如:Aromatic Hydrocarbon'; container.appendChild(input); } // 调用API生成MCQ并展示 async function generateMCQ() { const subject = document.getElementById('subject').value.trim(); const topicInputs = document.querySelectorAll('.topic-input'); const topics = Array.from(topicInputs) .map(input => input.value.trim()) .filter(topic => topic); // 过滤空输入 // 参数校验 if (!subject || topics.length === 0) { alert('请填写科目和至少一个知识点!'); return; } try { // 调用后端API const response = await fetch('/generate-mcq', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ subject, topics }) }); const data = await response.json(); if (response.ok) { displayQuestions(data); } else { alert(`生成失败:${data.error}`); } } catch (err) { alert('连接服务器失败,请检查Flask应用是否正常运行!'); console.error(err); } } // 展示生成的题目 function displayQuestions(mcqData) { const resultsDiv = document.getElementById('results'); const questionsList = document.getElementById('questions-list'); questionsList.innerHTML = ''; // 遍历题目数据,渲染到页面 Object.entries(mcqData).forEach(([qNum, qDetails]) => { const questionDiv = document.createElement('div'); questionDiv.className = 'mcq-question'; // 题目标题 const qTitle = document.createElement('h3'); qTitle.textContent = `${qNum}: ${qDetails.question}`; questionDiv.appendChild(qTitle); // 选项列表 Object.entries(qDetails.options).forEach(([optKey, optValue]) => { const optDiv = document.createElement('div'); optDiv.className = 'option'; optDiv.textContent = `${optKey}. ${optValue}`; questionDiv.appendChild(optDiv); }); // 正确答案 const answerDiv = document.createElement('div'); answerDiv.className = 'correct-answer'; answerDiv.textContent = `正确答案:${qDetails.correct_answer}`; questionDiv.appendChild(answerDiv); questionsList.appendChild(questionDiv); }); // 显示结果区域 resultsDiv.style.display = 'block'; } </script> </body> </html>
第三步:项目结构与运行步骤
你的项目文件夹要按照Flask的要求组织:
mcq-generator/ ├── app.py # Flask应用主文件 ├── templates/ │ └── index.html # 前端页面 └── your_vector_db/ # 你的向量数据库文件夹(比如Chroma的persist目录)
运行步骤:
- 安装依赖:根据你使用的工具安装对应的包,比如:
pip install flask langchain openai chromadb - 补充
app.py中省略的retriever、mcq_prompt、llm的配置(确保和你原来Jupyter里的配置一致) - 运行Flask应用:
python app.py - 打开浏览器访问
http://localhost:5000,输入科目和知识点,点击「生成题目」就能看到结果了!
一些需要注意的细节
- JSON格式稳定性:用正则提取JSON的方式不太可靠,建议改用LangChain的
PydanticOutputParser来强制LLM生成符合格式的输出,这样能避免正则匹配失败的问题。 - API密钥配置:如果用OpenAI等需要密钥的LLM,建议通过环境变量设置密钥,不要硬编码到代码里。
- 生产环境部署:开发环境用
debug=True没问题,生产环境要关闭debug模式,用Gunicorn等WSGI服务器部署。 - 错误处理:可以根据实际情况增加更多的错误处理逻辑,比如LLM调用超时、向量库连接失败等。
备注:内容来源于stack exchange,提问作者Umadevi S
相关产品推荐
相关产品推荐

