Refactor: Use native json_schema structured output, remove manual schema injection

This commit is contained in:
2026-04-18 02:02:16 +02:00
parent c3bc3bbcdd
commit b0873f3ed3
4 changed files with 14 additions and 19 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -19,7 +19,6 @@ Please solve the provided question based on its type and provide the correct res
- For choice questions, output the exact index(es) of the correct answer(s).
- For text/numerical questions, provide the exact wording or number.
- For essay questions, provide a highly detailed and complete response, adapting exactly to the requested 'format' (HTML vs plain text) and building upon any 'initial_text' template if supplied.
Always output strict JSON according to the requested schema block.
`.trim();
const SYSTEM_INSTRUCTION_MESSAGE = {
+11 -15
View File
@@ -21,7 +21,8 @@ async function getChatGPTResponse(
const timeoutControler = setTimeout(() => controller.abort(), (config.timeoutValue || 20) * 1000);
// Get the content to send to chatgpt
// Including the instructions to the AI, the images as base64 if needed, the question and the past conversation if history is set to true
// Including the instructions to the AI, the images as base64 if needed,
// the question and the past conversation if history is set to true
const contentHandler = await getContentWithHistory(config, questionElement, question);
const client = new OpenAI({
@@ -40,17 +41,16 @@ async function getChatGPTResponse(
const requestPayload: any = {
model: config.model,
messages: contentHandler.messages.map(msg => ({ ...msg })),
max_completion_tokens: config.maxTokens || 2000 // Maximum length of the response,
max_completion_tokens: config.maxTokens || 2000
};
// Use the modern json_schema structured output when a schema is available.
// The model is guaranteed to return schema-valid JSON — no prompt hacks needed.
if (targetSchema) {
requestPayload.response_format = {
type: 'json_object'
type: 'json_schema',
json_schema: targetSchema
};
if (requestPayload.messages.length > 0 && requestPayload.messages[0].role === 'system') {
requestPayload.messages[0].content += `\n\nYou MUST respond in JSON strictly adhering to the following schema. Do NOT wrap the JSON in markdown code blocks. Output raw JSON only.\n\n${JSON.stringify(targetSchema, null, 2)}`;
}
}
const req = await client.chat.completions.create(fixeO(config.model, requestPayload), {
@@ -60,17 +60,13 @@ async function getChatGPTResponse(
clearTimeout(timeoutControler);
const rawResponse = req.choices[0].message.content ?? '';
let structuredResponse: MoodleQuestionResponse | null = null;
if (targetSchema) {
let structuredResponse: MoodleQuestionResponse | null = null;
if (targetSchema && rawResponse) {
try {
const cleanedResponse = rawResponse
.replace(/^```(json)?[\s\S]*?\n([\s\S]*?)```$/g, '$2')
.replace(/^```(json)?|```$/gm, '')
.trim();
structuredResponse = JSON.parse(cleanedResponse);
structuredResponse = JSON.parse(rawResponse);
} catch (e) {
console.error('Failed to parse structured JSON from GPT', e);
console.error('Failed to parse structured JSON response', e);
}
}