Resolves A1/A2: bring quiz prompt + output schema in-house from Runtime. - quiz-generation.prompt.ts: system prompt with question design principles - quiz-generation.schema.ts: Zod schema (choice/fill/judge types) - Registered in PromptTemplateService with key 'quiz-generation' v1.0.0 - Executor: AiGateway call with knowledge items + generation params - Validator: per-type validation (choice options/index, judge true/false) - Engine dispatch for quiz_generation job type Co-Authored-By: Claude <noreply@anthropic.com>
73 lines
2.5 KiB
TypeScript
73 lines
2.5 KiB
TypeScript
import { Injectable, Logger } from '@nestjs/common';
|
|
import { AiGatewayService } from '../ai/gateway/ai-gateway.service';
|
|
import { QuizGenerationResultSchema } from '../ai/prompts/schemas/quiz-generation.schema';
|
|
import type { QuizGenerationSnapshot } from './quiz-generation-snapshot-builder';
|
|
|
|
/**
|
|
* M-AI-07-03: Quiz Generation Executor
|
|
*
|
|
* 将 Quiz 生成输入快照适配到统一 Job Engine 的 EXECUTE 阶段。
|
|
*
|
|
* 职责:从 Snapshot 构造模型输入、通过 AiGateway 调用、返回结构化输出。
|
|
* 不负责:写数据库、写 Job 状态、重试、Artifact、Credential。
|
|
*/
|
|
|
|
@Injectable()
|
|
export class QuizGenerationExecutor {
|
|
private readonly logger = new Logger(QuizGenerationExecutor.name);
|
|
|
|
constructor(private readonly aiGateway: AiGatewayService) {}
|
|
|
|
async execute(snapshot: QuizGenerationSnapshot, timeoutMs: number) {
|
|
const s = snapshot.snapshot;
|
|
|
|
// 构造知识点列表文本
|
|
const itemsText = s.knowledgeItems
|
|
.map((item, i) =>
|
|
`【知识点${i + 1}】${item.title}\n${item.content}`,
|
|
)
|
|
.join('\n\n');
|
|
|
|
const typeDesc = s.questionTypes.join('、');
|
|
const userMessage = [
|
|
`【知识库】${s.knowledgeBaseTitle}`,
|
|
s.knowledgeBaseDescription ? `描述:${s.knowledgeBaseDescription}` : '',
|
|
'',
|
|
itemsText,
|
|
'',
|
|
`请为以上知识点生成 ${s.questionCount} 道测验题目。`,
|
|
`题型:${typeDesc}`,
|
|
`难度:${s.difficultyLevel}`,
|
|
].filter(Boolean).join('\n');
|
|
|
|
this.logger.log(
|
|
`Quiz Generation Executor calling AI: userId=${s.userId} ` +
|
|
`kb=${s.targetId} items=${s.knowledgeItems.length} ` +
|
|
`questionCount=${s.questionCount} types=${s.questionTypes.join(',')} ` +
|
|
`difficulty=${s.difficultyLevel} modelTier=${s.modelTier} timeoutMs=${timeoutMs}`,
|
|
);
|
|
|
|
const response = await this.aiGateway.generate(
|
|
{
|
|
feature: 'quiz-generation',
|
|
userId: s.userId,
|
|
tier: s.modelTier as any,
|
|
promptKey: s.promptKey,
|
|
promptVersion: s.promptVersion,
|
|
messages: [{ role: 'user' as const, content: userMessage }],
|
|
outputSchema: QuizGenerationResultSchema,
|
|
maxTokens: 4096,
|
|
},
|
|
timeoutMs,
|
|
);
|
|
|
|
this.logger.log(
|
|
`Quiz Generation Executor completed: userId=${s.userId} ` +
|
|
`kb=${s.targetId} questions=${(response.parsed as any)?.questions?.length} ` +
|
|
`tokens=${response.usage.inputTokens}/${response.usage.outputTokens}`,
|
|
);
|
|
|
|
return response;
|
|
}
|
|
}
|