135 lines
5.8 KiB
Java
135 lines
5.8 KiB
Java
package com.zioinfo.mall.rag;
|
|
|
|
import com.zioinfo.mall.admin.dto.MallSetting;
|
|
import com.zioinfo.mall.admin.mapper.SettingMapper;
|
|
import lombok.RequiredArgsConstructor;
|
|
import org.springframework.stereotype.Service;
|
|
|
|
import java.util.LinkedHashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
/**
|
|
* Mall RAG 기법/신뢰도 토글 서비스.
|
|
*
|
|
* <p>기존 {@code mall_setting}(key-value) 테이블을 재사용해 RAG 토글을 격리 저장한다(신규 테이블
|
|
* 신설 없음, admin 설정 화면과 자연 통합). 키 네임스페이스 {@code rag.*} 로 다른 설정과 충돌 회피.
|
|
*
|
|
* <p>무거운 기법(graphrag·rerank·tool_use/agent·stream)은 서버 RAM 제약상 <b>기본 off</b>.
|
|
* retrieval_mode 기본 vector, agent step 상한 강제.
|
|
*/
|
|
@Service
|
|
@RequiredArgsConstructor
|
|
public class RagToggleService {
|
|
|
|
private final SettingMapper settingMapper;
|
|
|
|
public static final String K_ENABLED = "rag.enabled";
|
|
public static final String K_MODE = "rag.retrieval_mode"; // vector|hybrid|graph
|
|
public static final String K_RERANK = "rag.rerank"; // true|false (무거움→기본 off)
|
|
public static final String K_GRAPHRAG = "rag.graphrag"; // true|false (무거움→기본 off)
|
|
public static final String K_TOOL_USE = "rag.tool_use"; // true|false (에이전틱 /agent, 무거움→off)
|
|
public static final String K_STRUCTURED = "rag.structured"; // true|false (추천/검색 결정론 JSON, 기본 on)
|
|
public static final String K_STREAM = "rag.stream"; // true|false (SSE, 기본 off)
|
|
public static final String K_TOP_K = "rag.top_k";
|
|
public static final String K_AGENT_STEPS = "rag.agent_max_steps";
|
|
public static final String K_FAITHFULNESS = "rag.faithfulness_threshold";
|
|
public static final String K_TEMPERATURE = "rag.temperature";
|
|
public static final String K_GEN_MODEL = "rag.generation_model";
|
|
|
|
/** 현재 토글 전부 조회(기본값 머지). 화면/배선 공용. */
|
|
public RagToggles current() {
|
|
Map<String, String> m = new LinkedHashMap<>();
|
|
List<MallSetting> all = settingMapper.findAll();
|
|
if (all != null) for (MallSetting s : all) m.put(s.getKey(), s.getValue());
|
|
|
|
RagToggles t = new RagToggles();
|
|
t.ragEnabled = bool(m.get(K_ENABLED), true);
|
|
t.retrievalMode = mode(m.get(K_MODE));
|
|
t.rerank = bool(m.get(K_RERANK), false); // 무거움→off 기본
|
|
t.graphrag = bool(m.get(K_GRAPHRAG), false); // 무거움→off 기본
|
|
t.toolUse = bool(m.get(K_TOOL_USE), false); // 에이전틱→off 기본(옵트인)
|
|
t.structured = bool(m.get(K_STRUCTURED), true); // 결정론 출력→on 기본
|
|
t.stream = bool(m.get(K_STREAM), false); // SSE→off 기본
|
|
t.topK = clampInt(m.get(K_TOP_K), 6, 1, 20);
|
|
t.agentMaxSteps = clampInt(m.get(K_AGENT_STEPS), 4, 1, 8);
|
|
t.faithfulnessThreshold = clampDouble(m.get(K_FAITHFULNESS), 0.5, 0.0, 1.0);
|
|
t.temperature = clampDouble(m.get(K_TEMPERATURE), 0.2, 0.0, 1.0);
|
|
t.generationModel = blankTo(m.get(K_GEN_MODEL), "llama3.2:1b");
|
|
return t;
|
|
}
|
|
|
|
/** retrieval_mode 결정: graphrag 토글 on 이면 graph 우선, 아니면 설정 mode. */
|
|
public String effectiveMode(RagToggles t) {
|
|
if (t.graphrag) return "graph";
|
|
return t.retrievalMode;
|
|
}
|
|
|
|
// ── 정규화/클램프 (상한 강제 — 폭주 차단) ───────────────────────────────
|
|
private boolean bool(String v, boolean def) {
|
|
if (v == null) return def;
|
|
return "true".equalsIgnoreCase(v.trim()) || "1".equals(v.trim()) || "on".equalsIgnoreCase(v.trim());
|
|
}
|
|
|
|
private String mode(String v) {
|
|
if (v == null) return "vector";
|
|
String s = v.trim().toLowerCase();
|
|
return (s.equals("hybrid") || s.equals("graph") || s.equals("vector")) ? s : "vector";
|
|
}
|
|
|
|
private int clampInt(String v, int def, int min, int max) {
|
|
try {
|
|
int n = Integer.parseInt(v.trim());
|
|
return Math.max(min, Math.min(max, n));
|
|
} catch (Exception e) {
|
|
return def;
|
|
}
|
|
}
|
|
|
|
private double clampDouble(String v, double def, double min, double max) {
|
|
try {
|
|
double n = Double.parseDouble(v.trim());
|
|
return Math.max(min, Math.min(max, n));
|
|
} catch (Exception e) {
|
|
return def;
|
|
}
|
|
}
|
|
|
|
private String blankTo(String v, String def) {
|
|
return (v == null || v.isBlank()) ? def : v.trim();
|
|
}
|
|
|
|
/** 토글 스냅샷 DTO(응답 metadata·화면 공용). */
|
|
public static class RagToggles {
|
|
public boolean ragEnabled = true;
|
|
public String retrievalMode = "vector";
|
|
public boolean rerank = false;
|
|
public boolean graphrag = false;
|
|
public boolean toolUse = false;
|
|
public boolean structured = true;
|
|
public boolean stream = false;
|
|
public int topK = 6;
|
|
public int agentMaxSteps = 4;
|
|
public double faithfulnessThreshold = 0.5;
|
|
public double temperature = 0.2;
|
|
public String generationModel = "llama3.2:1b";
|
|
|
|
public Map<String, Object> toMap() {
|
|
Map<String, Object> m = new LinkedHashMap<>();
|
|
m.put("ragEnabled", ragEnabled);
|
|
m.put("retrievalMode", retrievalMode);
|
|
m.put("rerank", rerank);
|
|
m.put("graphrag", graphrag);
|
|
m.put("toolUse", toolUse);
|
|
m.put("structured", structured);
|
|
m.put("stream", stream);
|
|
m.put("topK", topK);
|
|
m.put("agentMaxSteps", agentMaxSteps);
|
|
m.put("faithfulnessThreshold", faithfulnessThreshold);
|
|
m.put("temperature", temperature);
|
|
m.put("generationModel", generationModel);
|
|
return m;
|
|
}
|
|
}
|
|
}
|