diff --git a/src/main/java/com/sztzjy/linkCommerce/service/impl/AiTrainingEvaluationServiceImpl.java b/src/main/java/com/sztzjy/linkCommerce/service/impl/AiTrainingEvaluationServiceImpl.java index c5845d2..7f87931 100644 --- a/src/main/java/com/sztzjy/linkCommerce/service/impl/AiTrainingEvaluationServiceImpl.java +++ b/src/main/java/com/sztzjy/linkCommerce/service/impl/AiTrainingEvaluationServiceImpl.java @@ -216,15 +216,27 @@ public class AiTrainingEvaluationServiceImpl implements AiTrainingEvaluationServ } private AiTrainingEvaluationView runAssessment(EvaluationContext context, JwtUser actor, AiTrainingEvaluation evaluation) { + long startedAt = System.currentTimeMillis(); String answerSnapshot = answerSnapshot(context.answer); String taskSnapshot = taskSnapshot(context.effectiveContent); List criterionPlan = assessmentCriterionPlan(context.effectiveContent.getSteps()); String rawResponse = null; try { + long knowledgeStartedAt = System.currentTimeMillis(); String knowledgeContext = knowledgeContext(context, actor, ""); + long knowledgeCost = System.currentTimeMillis() - knowledgeStartedAt; String choiceQuestionContext = choiceQuestionContext(context.effectiveContent, context.answer); + long modelStartedAt = System.currentTimeMillis(); rawResponse = qwenChatClient.completeJson(assessmentSystemPrompt(criterionPlan), 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); int score = validateAssessment(assessmentReport, criterionPlan); compactAssessmentRationales(assessmentReport); @@ -302,20 +314,34 @@ public class AiTrainingEvaluationServiceImpl implements AiTrainingEvaluationServ // 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(), - commentUserPrompt(assessmentReport, helpReport)); + commentUserPrompt(assessmentReport, helpReport) + StringUtils.trimToEmpty(extraInstruction)); JsonNode report = object(rawResponse); JsonNode commentNode = report.get("comment"); - if (commentNode == null || !commentNode.isTextual() || StringUtils.isBlank(commentNode.textValue())) { + if (commentNode == null || !commentNode.isTextual()) { throw invalidReport(); } - return Collections.singletonMap("comment", normalizeTeacherComment(commentNode.textValue())); + return commentNode.textValue(); } private String commentSystemPrompt() { 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. " - + "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; " + "no bullet points, no quotes, no salutation, no prefix or suffix such as 评语. " + "Return only JSON: {\"comment\":\"...\"}";