guardia-mro/backend/src/main/java/com/zioinfo/mro/rag/WiseAskController.java

51 lines
2.1 KiB
Java

package com.zioinfo.mro.rag;
import com.zioinfo.mro.common.ApiResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
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 java.util.Map;
/**
* WISE AI — Enterprise AI for Trusted Knowledge (MRO 배선).
*
* <p>{@code POST /api/wise/ask {query, retrievalMode?}} → 중앙 guardia-rag {@code /rag/answer}
* (solution=mro) 프록시. 근거+인용+환각차단(abstained) 동반. 미가용 시 degraded 안내(스택 미노출).
*
* <p>인증: SecurityConfig 의 {@code anyRequest().authenticated()} 로 로그인 사용자만 접근.
* 기존 {@code /api/mro/ai/*}(Ollama/Claude 직접) 는 불변 — 본 컨트롤러는 중앙 rag 경유 신규 경로만 추가.
*/
@Tag(name = "WISE AI (중앙 guardia-rag)", description = "근거·인용 기반 답변 — 온프레미스 전용")
@RestController
@RequestMapping("/api/wise")
@RequiredArgsConstructor
public class WiseAskController {
private final RagClient ragClient;
@Operation(summary = "WISE AI 질의 (/rag/answer 프록시 · 근거+인용+환각차단)")
@PostMapping("/ask")
public ApiResponse<Map<String, Object>> ask(@RequestBody AskRequest req) {
String query = req == null || req.query() == null ? "" : req.query().trim();
if (query.isEmpty()) {
return ApiResponse.ok(Map.of(
"answer", "질문을 입력해 주세요.",
"sources", java.util.List.of(),
"grounded", false,
"abstained", false,
"degraded", true,
"degraded_reason", "empty_query"));
}
return ApiResponse.ok(ragClient.answer(query, req.retrievalMode()));
}
/** WISE AI 질의 요청 — retrievalMode: vector|hybrid|graph (선택). */
public record AskRequest(String query, String retrievalMode) {
}
}