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

如何基于输入文本自动生成有意义的选择题?(附Transformer代码)

基于输入文本自动生成选择题的优化方案

问题背景

需要实现基于输入文本自动生成有意义的选择题,无需手动编写题目模板。目前已能通过代码识别关键词的词性(名词、动词、副词、形容词),但仍依赖手动模板生成问题,现基于Transformers框架的T5模型寻求优化方案。

原代码

from transformers import T5ForConditionalGeneration, T5Tokenizer
import nltk
import random

# Load the T5 model and tokenizer
model_name = 't5-base'
model = T5ForConditionalGeneration.from_pretrained(model_name)
tokenizer = T5Tokenizer.from_pretrained(model_name)

while True:
    # Ask the user for input text
    input_text = input("Enter the input text (or 'exit' to quit): ")

    if input_text.lower() == 'exit':
        break

    # Tokenize the input text
    words = nltk.word_tokenize(input_text)

    # Remove stopwords
    stop_words = set(nltk.corpus.stopwords.words('english'))
    filtered_words = [word for word in words if word.lower() not in stop_words]

    # Extract key terms (nouns and proper nouns)
    key_terms = [word for word, pos in nltk.pos_tag(filtered_words) if pos in ['NN', 'NNS', 'NNP', 'NNPS']]

    # Shuffle the key terms
    random.shuffle(key_terms)

    # Generate 5 multiple-choice questions
    questions = []
    for term in key_terms[:5]:  # Limit to 5 key terms
        options = random.sample(key_terms, 4)
        options.append(term)
        random.shuffle(options)
        correct_answer = options.index(term)

        # Identify the part of speech
        pos = nltk.pos_tag([term])[0][1]

        if pos.startswith('N'):
            question = f"What is the noun '{term}'?"
        elif pos.startswith('V'):
            question = f"How important is the verb '{term}'?"
        elif pos.startswith('R'):
            question = f"What is the adverb describing '{term}'?"
        elif pos.startswith('J'):
            question = f"What is the adjective describing '{term}'?"
        else:
            question = f"What is '{term}'?"

        questions.append((question, options, correct_answer))

    # Print the generated questions
    for i, (question, options, correct_answer) in enumerate(questions):
        print(f"Question {i + 1}: {question}")
        for j, option in enumerate(options):
            print(f"   {chr(65 + j)}. {option}")
        print(f"Correct Answer: {chr(65 + correct_answer)}\n")

# Exiting the loop
print("Goodbye!")

优化方案

1. 利用T5模型自动生成语境化问题

替换生硬的手动模板,通过设计针对性prompt让T5结合原文语境生成问题,使题目更贴合文本内容,避免脱离上下文的无效提问。

修改后的问题生成逻辑示例:

def generate_question(model, tokenizer, input_text, term):
    # 明确任务prompt,引导模型生成符合要求的选择题题干
    prompt = f"Generate a clear multiple-choice question asking about the term '{term}' based on this text: {input_text}"
    inputs = tokenizer(prompt, return_tensors="pt", max_length=512, truncation=True)
    outputs = model.generate(**inputs, max_length=128, num_beams=4, early_stopping=True)
    return tokenizer.decode(outputs[0], skip_special_tokens=True)

2. 生成语义相关的干扰项

原代码随机选取关键词作为干扰项,易出现选项与问题无关的情况。优化为:

  • 针对目标关键词,使用WordNet获取同词性的同义词/近义词作为干扰项
  • 若同义词数量不足,补充语义领域相近的词汇,或用原关键词池的其他词汇填充

示例代码(基于WordNet):

from nltk.corpus import wordnet

def generate_distractors(term, pos, key_terms, num_distractors=3):
    distractors = set()
    # 映射NLTK词性到WordNet词性
    pos_map = {'N': wordnet.NOUN, 'V': wordnet.VERB, 'J': wordnet.ADJ, 'R': wordnet.ADV}
    wordnet_pos = pos_map.get(pos[0], wordnet.NOUN)
    
    # 从同义词、上下位词中提取干扰项
    for syn in wordnet.synsets(term, pos=wordnet_pos):
        for lemma in syn.lemmas():
            lemma_name = lemma.name().replace('_', ' ')
            if lemma_name.lower() != term.lower():
                distractors.add(lemma_name)
        for hypernym in syn.hypernyms():
            for lemma in hypernym.lemmas():
                lemma_name = lemma.name().replace('_', ' ')
                if lemma_name.lower() != term.lower():
                    distractors.add(lemma_name)
    
    # 取指定数量干扰项,不足则从关键词池补充
    distractors = list(distractors)[:num_distractors]
    if len(distractors) < num_distractors:
        extra = random.sample([t for t in key_terms if t.lower() != term.lower()], num_distractors - len(distractors))
        distractors.extend(extra)
    return distractors

3. 扩展关键词提取范围并优化精度

原代码仅提取名词,可扩展支持动词、形容词、副词等关键词性;同时用spaCy替代NLTK的基础分词,提升关键词提取的准确性:

import spacy

nlp = spacy.load("en_core_web_sm")

def extract_key_terms(input_text):
    doc = nlp(input_text)
    key_terms = []
    # 提取核心词性词汇并过滤停用词
    for token in doc:
        if token.pos_ in ['NOUN', 'PROPN', 'VERB', 'ADJ', 'ADV'] and not token.is_stop:
            key_terms.append(token.text)
    # 去重
    return list(set(key_terms))

4. 整合优化后的完整代码

将上述优化点整合,替换原代码对应部分,实现自动生成语境化题目和合理干扰项:

from transformers import T5ForConditionalGeneration, T5Tokenizer
import nltk
import random
from nltk.corpus import wordnet
import spacy

# 加载模型、分词器和NLP工具
model_name = 't5-base'
model = T5ForConditionalGeneration.from_pretrained(model_name)
tokenizer = T5Tokenizer.from_pretrained(model_name)
nlp = spacy.load("en_core_web_sm")
nltk.download('wordnet')
nltk.download('averaged_perceptron_tagger')

def generate_question(model, tokenizer, input_text, term):
    prompt = f"Generate a clear multiple-choice question asking about the term '{term}' based on this text: {input_text}"
    inputs = tokenizer(prompt, return_tensors="pt", max_length=512, truncation=True)
    outputs = model.generate(**inputs, max_length=128, num_beams=4, early_stopping=True)
    return tokenizer.decode(outputs[0], skip_special_tokens=True)

def generate_distractors(term, pos, key_terms, num_distractors=3):
    distractors = set()
    pos_map = {'N': wordnet.NOUN, 'V': wordnet.VERB, 'J': wordnet.ADJ, 'R': wordnet.ADV}
    wordnet_pos = pos_map.get(pos[0], wordnet.NOUN)
    
    for syn in wordnet.synsets(term, pos=wordnet_pos):
        for lemma in syn.lemmas():
            lemma_name = lemma.name().replace('_', ' ')
            if lemma_name.lower() != term.lower():
                distractors.add(lemma_name)
        for hypernym in syn.hypernyms():
            for lemma in hypernym.lemmas():
                lemma_name = lemma.name().replace('_', ' ')
                if lemma_name.lower() != term.lower():
                    distractors.add(lemma_name)
    
    distractors = list(distractors)[:num_distractors]
    if len(distractors) < num_distractors:
        extra = random.sample([t for t in key_terms if t.lower() != term.lower()], num_distractors - len(distractors))
        distractors.extend(extra)
    return distractors

def extract_key_terms(input_text):
    doc = nlp(input_text)
    key_terms = []
    for token in doc:
        if token.pos_ in ['NOUN', 'PROPN', 'VERB', 'ADJ', 'ADV'] and not token.is_stop:
            key_terms.append(token.text)
    return list(set(key_terms))

while True:
    input_text = input("输入文本(输入'exit'退出):")
    if input_text.lower() == 'exit':
        break
    
    key_terms = extract_key_terms(input_text)
    if not key_terms:
        print("未提取到有效关键词,请输入更丰富的文本。")
        continue
    
    random.shuffle(key_terms)
    questions = []
    for term in key_terms[:5]:
        pos = nltk.pos_tag([term])[0][1]
        # 生成问题
        question = generate_question(model, tokenizer, input_text, term)
        # 生成干扰项
        distractors = generate_distractors(term, pos, key_terms)
        options = distractors + [term]
        random.shuffle(options)
        correct_answer = options.index(term)
        questions.append((question, options, correct_answer))
    
    # 输出题目
    for i, (question, options, correct_answer) in enumerate(questions):
        print(f"题目 {i + 1}: {question}")
        for j, option in enumerate(options):
            print(f"   {chr(65 + j)}. {option}")
        print(f"正确答案: {chr(65 + correct_answer)}\n")

print("再见!")

额外优化建议

  • 使用t5-large等更大的模型可提升问题生成质量,但会增加推理时间
  • 可添加过滤逻辑,排除生成的无效问题(如表述模糊、选项重复等)
  • 支持批量处理文本,一次性生成多组题目

内容的提问来源于stack exchange,提问作者Pramit

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 16:44:54