body = Map.of("model", useModel, "prompt", prompt, "stream", false);
Map res = builder.baseUrl(ollamaUrl).build()
.post().uri("/api/generate")
.bodyValue(body)
diff --git a/backend/src/main/java/com/zioinfo/mes/ai/controller/AiConfigController.java b/backend/src/main/java/com/zioinfo/mes/ai/controller/AiConfigController.java
new file mode 100644
index 0000000..63b4070
--- /dev/null
+++ b/backend/src/main/java/com/zioinfo/mes/ai/controller/AiConfigController.java
@@ -0,0 +1,54 @@
+package com.zioinfo.mes.ai.controller;
+
+import com.zioinfo.mes.admin.AuditService;
+import com.zioinfo.mes.ai.dto.AiConfigDto;
+import com.zioinfo.mes.ai.dto.AiConfigUpdateRequest;
+import com.zioinfo.mes.ai.service.AiConfigService;
+import com.zioinfo.mes.common.ApiResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * AI 플랫폼(LLM provider) 설정 관리(ADMIN). [GUARDiA-MES]
+ * SecurityConfig {@code /api/admin/** hasRole(SUPERADMIN)} 게이트로 보호된다.
+ *
+ * mes_setting(key='ai.*')에 저장된 런타임 설정을 조회/갱신/테스트한다. API 키는 환경변수
+ * (ANTHROPIC_API_KEY)로만 주입되어 응답·로그에 노출되지 않는다(GET 은 {@code claudeKeySet} 불리언만).
+ * 설정 변경은 재기동 없이 다음 AI 호출부터 반영된다.
+ *
+ *
+ * - GET /api/admin/ai-config 현재 효과 설정(키 값 제외, keySet 불리언만)
+ * - PUT /api/admin/ai-config provider/모델 갱신(화이트리스트 검증)
+ * - POST /api/admin/ai-config/test 저장 설정 기준 선택 provider 연결 테스트(요약 결과만)
+ *
+ */
+@RestController
+@RequestMapping("/api/admin/ai-config")
+@RequiredArgsConstructor
+public class AiConfigController {
+
+ private final AiConfigService service;
+
+ @GetMapping
+ public ApiResponse get() {
+ return ApiResponse.ok(service.getConfig());
+ }
+
+ @PutMapping
+ public ApiResponse update(@RequestBody AiConfigUpdateRequest req) {
+ return ApiResponse.ok(service.update(req, AuditService.currentActor()));
+ }
+
+ @PostMapping("/test")
+ public ApiResponse test() {
+ AiConfigService.TestResult result = service.test();
+ return result.ok()
+ ? ApiResponse.ok(result)
+ : new ApiResponse<>(false, result.message(), result);
+ }
+}
diff --git a/backend/src/main/java/com/zioinfo/mes/ai/dto/AiConfigDto.java b/backend/src/main/java/com/zioinfo/mes/ai/dto/AiConfigDto.java
new file mode 100644
index 0000000..7371a38
--- /dev/null
+++ b/backend/src/main/java/com/zioinfo/mes/ai/dto/AiConfigDto.java
@@ -0,0 +1,18 @@
+package com.zioinfo.mes.ai.dto;
+
+/**
+ * AI 설정 조회 DTO — API 키 값 미반환(claudeKeySet 으로 설정 여부만). [GUARDiA-MES]
+ *
+ * @param provider 효과 provider(ollama/claude/qwen3/deepseek/glm)
+ * @param ollamaTextModel 효과 Ollama 텍스트 모델(provider 별 해석 결과)
+ * @param claudeModel 효과 Claude 모델 ID
+ * @param claudeKeySet 서버 환경변수 ANTHROPIC_API_KEY 존재 여부(값/길이/마스킹 일절 미포함)
+ * @param aiEnabled 전역 AI 사용 여부(off 시 규칙 기반 degraded)
+ */
+public record AiConfigDto(
+ String provider,
+ String ollamaTextModel,
+ String claudeModel,
+ boolean claudeKeySet,
+ boolean aiEnabled) {
+}
diff --git a/backend/src/main/java/com/zioinfo/mes/ai/dto/AiConfigUpdateRequest.java b/backend/src/main/java/com/zioinfo/mes/ai/dto/AiConfigUpdateRequest.java
new file mode 100644
index 0000000..57d5748
--- /dev/null
+++ b/backend/src/main/java/com/zioinfo/mes/ai/dto/AiConfigUpdateRequest.java
@@ -0,0 +1,14 @@
+package com.zioinfo.mes.ai.dto;
+
+/**
+ * AI 설정 저장 요청 — 화이트리스트 검증. [GUARDiA-MES]
+ *
+ * @param provider ollama/claude/qwen3/deepseek/glm (필수)
+ * @param claudeModel Claude 모델 ID(선택, 미제공 시 기존 유지)
+ * @param ollamaTextModel Ollama 텍스트 모델(선택, 미제공 시 기존 유지)
+ */
+public record AiConfigUpdateRequest(
+ String provider,
+ String claudeModel,
+ String ollamaTextModel) {
+}
diff --git a/backend/src/main/java/com/zioinfo/mes/ai/learning/AiFeedbackController.java b/backend/src/main/java/com/zioinfo/mes/ai/learning/AiFeedbackController.java
new file mode 100644
index 0000000..89ed5bf
--- /dev/null
+++ b/backend/src/main/java/com/zioinfo/mes/ai/learning/AiFeedbackController.java
@@ -0,0 +1,97 @@
+package com.zioinfo.mes.ai.learning;
+
+import com.zioinfo.mes.admin.AuditService;
+import com.zioinfo.mes.common.ApiResponse;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.reactive.function.client.WebClient;
+
+import java.time.Duration;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * AI 답변 피드백 수집(👍/👎 + 교정). [GUARDiA-MES]
+ *
+ * {@code POST /api/ai/feedback} — ① 로컬 DuckDB({@link AiLearningStore}) 적재(오프라인 AI 분석/학습셋)
+ * + ② 중앙 guardia-rag {@code /feedback} 전달(통합 학습·평가 게이트). 둘 중 하나가 실패해도 200 을 유지한다.
+ *
+ *
인증: {@code /api/ai/**} 는 SecurityConfig 의 {@code anyRequest().authenticated()} 로 로그인 사용자면
+ * 누구나 피드백 가능(관리자 전용 아님). PII/자격증명은 로컬 적재 전 마스킹된다.
+ * 보안 불변: 중앙 rag 는 온프레미스 루프백 전용. 외부 전달 없음. 응답에 키/스택트레이스 미포함.
+ */
+@Slf4j
+@RestController
+@RequestMapping("/api/ai/feedback")
+@RequiredArgsConstructor
+public class AiFeedbackController {
+
+ private final AiLearningStore store;
+ private final WebClient.Builder webClientBuilder;
+
+ @Value("${guardia.rag.base-url:http://127.0.0.1:8020}")
+ private String ragBaseUrl;
+
+ @Value("${guardia.rag.enabled:true}")
+ private boolean ragEnabled;
+
+ @PostMapping
+ public ApiResponse