You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过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目录)

运行步骤:

  1. 安装依赖:根据你使用的工具安装对应的包,比如:
    pip install flask langchain openai chromadb
    
  2. 补充app.py中省略的retriever、mcq_prompt、llm的配置(确保和你原来Jupyter里的配置一致)
  3. 运行Flask应用:
    python app.py
    
  4. 打开浏览器访问http://localhost:5000,输入科目和知识点,点击「生成题目」就能看到结果了!

一些需要注意的细节

  1. JSON格式稳定性:用正则提取JSON的方式不太可靠,建议改用LangChain的PydanticOutputParser来强制LLM生成符合格式的输出,这样能避免正则匹配失败的问题。
  2. API密钥配置:如果用OpenAI等需要密钥的LLM,建议通过环境变量设置密钥,不要硬编码到代码里。
  3. 生产环境部署:开发环境用debug=True没问题,生产环境要关闭debug模式,用Gunicorn等WSGI服务器部署。
  4. 错误处理:可以根据实际情况增加更多的错误处理逻辑,比如LLM调用超时、向量库连接失败等。

备注:内容来源于stack exchange,提问作者Umadevi S

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.13 19:50:27