fix(exam): 修复出题批卷 API 契约一致性问题
P0: - 修复 V2 降级路径响应格式,fallback 输出经过 enrich + dedup + balance - 补充主观题 format example,要求 LLM 生成 scoring_points 评分标准 P1: - 补充多选题、判断题 format example,明确 answer 为列表格式 - 统一批卷响应格式,所有题型增加 grading_status 字段 - 出题数量不足时返回 requested_types/actual_types/warnings - 修复 _call_llm 未配置时抛异常而非静默返回 0 分 P2: - API 层增加 question_types 和 difficulty 入参校验 - 修复 generate_questions_from_content 方法名和参数类型 bug
This commit is contained in:
@@ -97,8 +97,13 @@ def grade_objective(answer: Dict) -> Dict:
|
||||
"question_id": answer.get('question_id'),
|
||||
"score": max_score if correct else 0,
|
||||
"max_score": max_score,
|
||||
"correct": correct,
|
||||
"feedback": f"正确答案: {correct_answer}" if not correct else "正确!"
|
||||
"grading_status": "success",
|
||||
"details": {
|
||||
"correct": correct,
|
||||
"student_answer": student_answer,
|
||||
"correct_answer": correct_answer,
|
||||
"feedback": f"正确答案: {correct_answer}" if not correct else "正确!"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -119,7 +124,8 @@ def grade_fill_blank(answer: Dict) -> Dict:
|
||||
"question_id": answer.get('question_id'),
|
||||
"score": 0,
|
||||
"max_score": max_score,
|
||||
"details": {"error": "答案格式错误"}
|
||||
"grading_status": "failed",
|
||||
"details": {"error": "答案格式错误,correct_answers 或 student_answer 为空"}
|
||||
}
|
||||
|
||||
# 计算每空分数
|
||||
@@ -149,9 +155,11 @@ def grade_fill_blank(answer: Dict) -> Dict:
|
||||
"question_id": answer.get('question_id'),
|
||||
"score": round(total_score, 1),
|
||||
"max_score": max_score,
|
||||
"grading_status": "success",
|
||||
"details": {
|
||||
"blank_scores": blank_scores,
|
||||
"correct_answers": correct_answers
|
||||
"total_blanks": len(correct_answers),
|
||||
"correct_blanks": sum(1 for s in blank_scores if s > 0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,22 +251,38 @@ class AnswerGrader:
|
||||
}
|
||||
|
||||
# 收集结果
|
||||
for future in as_completed(future_to_qid, timeout=60):
|
||||
qid = future_to_qid[future]
|
||||
try:
|
||||
result = future.result(timeout=15)
|
||||
results_map[qid] = result
|
||||
except Exception as e:
|
||||
# 失败时返回默认结果
|
||||
results_map[qid] = {
|
||||
"question_id": qid,
|
||||
"score": 0,
|
||||
"max_score": next(
|
||||
(a.get('max_score', 10) for a in questions if a.get('question_id') == qid),
|
||||
10
|
||||
),
|
||||
"error": str(e)
|
||||
}
|
||||
try:
|
||||
for future in as_completed(future_to_qid, timeout=60):
|
||||
qid = future_to_qid[future]
|
||||
try:
|
||||
result = future.result(timeout=15)
|
||||
results_map[qid] = result
|
||||
except Exception as e:
|
||||
# 失败时返回默认结果
|
||||
results_map[qid] = {
|
||||
"question_id": qid,
|
||||
"score": 0,
|
||||
"max_score": next(
|
||||
(a.get('max_score', 10) for a in questions if a.get('question_id') == qid),
|
||||
10
|
||||
),
|
||||
"grading_status": "failed",
|
||||
"details": {"error": str(e)}
|
||||
}
|
||||
except TimeoutError:
|
||||
# 超时:为未完成的任务设置失败状态
|
||||
for future, qid in future_to_qid.items():
|
||||
if qid not in results_map:
|
||||
results_map[qid] = {
|
||||
"question_id": qid,
|
||||
"score": 0,
|
||||
"max_score": next(
|
||||
(a.get('max_score', 10) for a in questions if a.get('question_id') == qid),
|
||||
10
|
||||
),
|
||||
"grading_status": "failed",
|
||||
"details": {"error": "批阅超时"}
|
||||
}
|
||||
|
||||
@retry(times=2, delay=1)
|
||||
def _grade_subjective(self, answer: Dict) -> Dict:
|
||||
@@ -315,8 +339,7 @@ class AnswerGrader:
|
||||
def _call_llm(self, prompt: str) -> str:
|
||||
"""调用本地 LLM"""
|
||||
if not self.client:
|
||||
# 无 LLM 客户端,返回默认评分
|
||||
return json.dumps({"score": 0, "overall_feedback": "LLM 未配置"})
|
||||
raise ValueError("LLM 未配置,无法进行主观题评分")
|
||||
|
||||
messages = [
|
||||
{"role": "system", "content": "你是一个专业的阅卷老师,请严格按照JSON格式输出评分结果。"},
|
||||
@@ -347,6 +370,7 @@ class AnswerGrader:
|
||||
"question_id": answer.get('question_id'),
|
||||
"score": score,
|
||||
"max_score": max_score,
|
||||
"grading_status": "success",
|
||||
"details": {
|
||||
"scoring_breakdown": result.get('scoring_breakdown', []),
|
||||
"highlights": result.get('highlights', []),
|
||||
@@ -360,6 +384,7 @@ class AnswerGrader:
|
||||
"question_id": answer.get('question_id'),
|
||||
"score": 0,
|
||||
"max_score": max_score,
|
||||
"grading_status": "failed",
|
||||
"details": {"error": "评分结果解析失败"}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user