[Developer] #424 use GPT 5.4 mini for VPD explanations
This commit is contained in:
@@ -32,7 +32,7 @@ export BACKOFFICE_ORDS_TIMEOUT_SECONDS="10"
|
||||
# --- (2c) OpenAI 호환 AI 호출 (MCP-style Reasoning 탭) ---
|
||||
export BACKOFFICE_AI_ENABLED="false"
|
||||
export BACKOFFICE_AI_BASE_URL="" # 예: https://inference.generativeai.us-chicago-1.oci.oraclecloud.com
|
||||
export BACKOFFICE_AI_MODEL="" # 예: meta.llama-3.3-70b-instruct
|
||||
export BACKOFFICE_AI_MODEL="" # 예: openai.gpt-5.4-mini
|
||||
export BACKOFFICE_AI_API_KEY=""
|
||||
export BACKOFFICE_AI_TIMEOUT_SECONDS="30"
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.cloudhandson.vpdbackoffice.domain.vpd;
|
||||
|
||||
public record VpdPolicyExplanation(
|
||||
String status,
|
||||
String modelName,
|
||||
String answer,
|
||||
String prompt,
|
||||
VpdPolicyDetail detail,
|
||||
|
||||
@@ -41,6 +41,11 @@ public class OpenAiCompatibleClient {
|
||||
&& hasText(ai.apiKey());
|
||||
}
|
||||
|
||||
public String modelName() {
|
||||
BackofficeProperties.Ai ai = properties.ai();
|
||||
return ai == null ? "" : ai.model();
|
||||
}
|
||||
|
||||
public String chat(String systemPrompt, String userPrompt) {
|
||||
if (!configured()) {
|
||||
throw new AppException("AI 호출 설정이 없습니다.");
|
||||
@@ -50,7 +55,11 @@ public class OpenAiCompatibleClient {
|
||||
ObjectNode request = objectMapper.createObjectNode();
|
||||
request.put("model", ai.model());
|
||||
request.put("temperature", 0.1);
|
||||
if (usesCompletionTokenLimit(ai.model())) {
|
||||
request.put("max_completion_tokens", 1200);
|
||||
} else {
|
||||
request.put("max_tokens", 1200);
|
||||
}
|
||||
ArrayNode messages = request.putArray("messages");
|
||||
messages.add(message("system", systemPrompt));
|
||||
messages.add(message("user", userPrompt));
|
||||
@@ -91,6 +100,10 @@ public class OpenAiCompatibleClient {
|
||||
return URI.create(withoutSlash + "/v1/chat/completions");
|
||||
}
|
||||
|
||||
private boolean usesCompletionTokenLimit(String model) {
|
||||
return model != null && model.startsWith("openai.gpt-5.4");
|
||||
}
|
||||
|
||||
private String extractAnswer(String body) {
|
||||
try {
|
||||
JsonNode root = objectMapper.readTree(body);
|
||||
|
||||
@@ -57,6 +57,7 @@ public class VpdPolicyService {
|
||||
if (!aiClient.configured()) {
|
||||
return new VpdPolicyExplanation(
|
||||
"AI_NOT_CONFIGURED",
|
||||
aiClient.modelName(),
|
||||
"AI base URL/API Key 설정이 없어 모델 호출은 건너뛰었습니다. 아래 Prompt와 function source를 기준으로 policy/filter 내용을 확인하세요.",
|
||||
prompt,
|
||||
detail,
|
||||
@@ -65,10 +66,11 @@ public class VpdPolicyService {
|
||||
}
|
||||
try {
|
||||
String answer = aiClient.chat(vpdSystemPrompt(), prompt);
|
||||
return new VpdPolicyExplanation("SUCCESS", answer, prompt, detail, functionSource);
|
||||
return new VpdPolicyExplanation("SUCCESS", aiClient.modelName(), answer, prompt, detail, functionSource);
|
||||
} catch (Exception e) {
|
||||
return new VpdPolicyExplanation(
|
||||
"AI_CALL_FAILED",
|
||||
aiClient.modelName(),
|
||||
"AI 호출은 실패했지만 policy/filter 근거는 수집했습니다. 상세: " + e.getMessage(),
|
||||
prompt,
|
||||
detail,
|
||||
|
||||
@@ -6,10 +6,13 @@
|
||||
<div th:if="${explanation}">
|
||||
<div class="section-heading mb-2">
|
||||
<h2>LLM 설명</h2>
|
||||
<div class="action-stack">
|
||||
<span class="badge text-bg-secondary" th:text="${explanation.modelName()} ?: 'model not configured'">model</span>
|
||||
<span class="badge"
|
||||
th:classappend="${explanation.status() == 'SUCCESS'} ? ' text-bg-success' : ' text-bg-warning'"
|
||||
th:text="${explanation.status()}">SUCCESS</span>
|
||||
</div>
|
||||
</div>
|
||||
<section class="ai-answer">
|
||||
<h3>Answer</h3>
|
||||
<pre th:text="${explanation.answer()}">answer</pre>
|
||||
|
||||
Reference in New Issue
Block a user