|
|
|
@ -216,15 +216,27 @@ public class AiTrainingEvaluationServiceImpl implements AiTrainingEvaluationServ
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private AiTrainingEvaluationView runAssessment(EvaluationContext context, JwtUser actor, AiTrainingEvaluation evaluation) {
|
|
|
|
private AiTrainingEvaluationView runAssessment(EvaluationContext context, JwtUser actor, AiTrainingEvaluation evaluation) {
|
|
|
|
|
|
|
|
long startedAt = System.currentTimeMillis();
|
|
|
|
String answerSnapshot = answerSnapshot(context.answer);
|
|
|
|
String answerSnapshot = answerSnapshot(context.answer);
|
|
|
|
String taskSnapshot = taskSnapshot(context.effectiveContent);
|
|
|
|
String taskSnapshot = taskSnapshot(context.effectiveContent);
|
|
|
|
List<AssessmentCriterionPlan> criterionPlan = assessmentCriterionPlan(context.effectiveContent.getSteps());
|
|
|
|
List<AssessmentCriterionPlan> criterionPlan = assessmentCriterionPlan(context.effectiveContent.getSteps());
|
|
|
|
String rawResponse = null;
|
|
|
|
String rawResponse = null;
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
|
|
|
|
long knowledgeStartedAt = System.currentTimeMillis();
|
|
|
|
String knowledgeContext = knowledgeContext(context, actor, "");
|
|
|
|
String knowledgeContext = knowledgeContext(context, actor, "");
|
|
|
|
|
|
|
|
long knowledgeCost = System.currentTimeMillis() - knowledgeStartedAt;
|
|
|
|
String choiceQuestionContext = choiceQuestionContext(context.effectiveContent, context.answer);
|
|
|
|
String choiceQuestionContext = choiceQuestionContext(context.effectiveContent, context.answer);
|
|
|
|
|
|
|
|
long modelStartedAt = System.currentTimeMillis();
|
|
|
|
rawResponse = qwenChatClient.completeJson(assessmentSystemPrompt(criterionPlan),
|
|
|
|
rawResponse = qwenChatClient.completeJson(assessmentSystemPrompt(criterionPlan),
|
|
|
|
assessmentUserPrompt(taskSnapshot, answerSnapshot, knowledgeContext, choiceQuestionContext));
|
|
|
|
assessmentUserPrompt(taskSnapshot, answerSnapshot, knowledgeContext, choiceQuestionContext));
|
|
|
|
|
|
|
|
long modelCost = System.currentTimeMillis() - modelStartedAt;
|
|
|
|
|
|
|
|
// AI 评分过慢排查:分段记录知识检索与模型调用耗时(prompt 长度一并输出)
|
|
|
|
|
|
|
|
log.info("AI assessment timing, evaluationId={}, knowledgeContext={} ms, modelCall={} ms, total={} ms, "
|
|
|
|
|
|
|
|
+ "knowledgeContextChars={}, answerSnapshotChars={}, promptChars={}",
|
|
|
|
|
|
|
|
evaluation.getId(), knowledgeCost, modelCost, System.currentTimeMillis() - startedAt,
|
|
|
|
|
|
|
|
knowledgeContext.length(), answerSnapshot.length(),
|
|
|
|
|
|
|
|
assessmentSystemPrompt(criterionPlan).length()
|
|
|
|
|
|
|
|
+ assessmentUserPrompt(taskSnapshot, answerSnapshot, knowledgeContext, choiceQuestionContext).length());
|
|
|
|
JsonNode assessmentReport = object(rawResponse);
|
|
|
|
JsonNode assessmentReport = object(rawResponse);
|
|
|
|
int score = validateAssessment(assessmentReport, criterionPlan);
|
|
|
|
int score = validateAssessment(assessmentReport, criterionPlan);
|
|
|
|
compactAssessmentRationales(assessmentReport);
|
|
|
|
compactAssessmentRationales(assessmentReport);
|
|
|
|
@ -302,20 +314,34 @@ public class AiTrainingEvaluationServiceImpl implements AiTrainingEvaluationServ
|
|
|
|
// AI 评分报告是评语的主要依据;助学报告只做补充,没有也能生成
|
|
|
|
// AI 评分报告是评语的主要依据;助学报告只做补充,没有也能生成
|
|
|
|
throw new ServiceException(HttpStatus.BAD_REQUEST, "该学生还没有AI评分数据,请先执行AI评分");
|
|
|
|
throw new ServiceException(HttpStatus.BAD_REQUEST, "该学生还没有AI评分数据,请先执行AI评分");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
String comment = normalizeTeacherComment(generateCommentOnce(assessmentReport, helpReport, ""));
|
|
|
|
|
|
|
|
if (comment.codePointCount(0, comment.length()) < 30) {
|
|
|
|
|
|
|
|
// 验收要求 30-50 字;过短时带纠正指令重写一次,取更长的那条
|
|
|
|
|
|
|
|
String instruction = " 上一次生成的评语只有" + comment.codePointCount(0, comment.length())
|
|
|
|
|
|
|
|
+ "个字,太短;重新生成的评语必须不少于30个字、不超过50个字。";
|
|
|
|
|
|
|
|
String retried = normalizeTeacherComment(generateCommentOnce(assessmentReport, helpReport, instruction));
|
|
|
|
|
|
|
|
if (retried.codePointCount(0, retried.length()) > comment.codePointCount(0, comment.length())) {
|
|
|
|
|
|
|
|
comment = retried;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return Collections.singletonMap("comment", comment);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private String generateCommentOnce(String assessmentReport, String helpReport, String extraInstruction) {
|
|
|
|
String rawResponse = qwenChatClient.completeJson(commentSystemPrompt(),
|
|
|
|
String rawResponse = qwenChatClient.completeJson(commentSystemPrompt(),
|
|
|
|
commentUserPrompt(assessmentReport, helpReport));
|
|
|
|
commentUserPrompt(assessmentReport, helpReport) + StringUtils.trimToEmpty(extraInstruction));
|
|
|
|
JsonNode report = object(rawResponse);
|
|
|
|
JsonNode report = object(rawResponse);
|
|
|
|
JsonNode commentNode = report.get("comment");
|
|
|
|
JsonNode commentNode = report.get("comment");
|
|
|
|
if (commentNode == null || !commentNode.isTextual() || StringUtils.isBlank(commentNode.textValue())) {
|
|
|
|
if (commentNode == null || !commentNode.isTextual()) {
|
|
|
|
throw invalidReport();
|
|
|
|
throw invalidReport();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Collections.singletonMap("comment", normalizeTeacherComment(commentNode.textValue()));
|
|
|
|
return commentNode.textValue();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private String commentSystemPrompt() {
|
|
|
|
private String commentSystemPrompt() {
|
|
|
|
return "You are a vocational school teacher writing feedback for one student's training task. "
|
|
|
|
return "You are a vocational school teacher writing feedback for one student's training task. "
|
|
|
|
+ "Based on the given AI scoring report (and AI tutoring report if present), write ONE Chinese teacher comment. "
|
|
|
|
+ "Based on the given AI scoring report (and AI tutoring report if present), write ONE Chinese teacher comment. "
|
|
|
|
+ "Requirements: 10 to 50 Chinese characters; a single short paragraph; objective, specific and encouraging; "
|
|
|
|
+ "Requirements: 30 to 50 Chinese characters; a single short paragraph; objective, specific and encouraging; "
|
|
|
|
+ "comment on the performance and give one improvement direction; "
|
|
|
|
+ "comment on the performance and give one improvement direction; "
|
|
|
|
+ "no bullet points, no quotes, no salutation, no prefix or suffix such as 评语. "
|
|
|
|
+ "no bullet points, no quotes, no salutation, no prefix or suffix such as 评语. "
|
|
|
|
+ "Return only JSON: {\"comment\":\"...\"}";
|
|
|
|
+ "Return only JSON: {\"comment\":\"...\"}";
|
|
|
|
|