[LLM] RAG 지역 기반 필터링 검색 추가 및 PIPELINE+LLM 파트 통합#23
Conversation
- AreaCode, ContentType enum 추가로 코드 변환 추가 - 사용자 입력 location 기반 areaCode 추출 및 필터 적용 - 유사도 검색 시 지역 필터 반영으로 추천 결과 정확도 향상
[feat] 지역 기반 필터링 도입 및 추천 정확도 향상을 위한 구조 개선
- 시군구 enum 추가 - sigunguCode metadata에 추가 저장
… feat/regionSearch2
- RecommendController를 RecommendServiceImpl로 분리 - PromptGeneratorServiceImpl 일부 수정(, 오류) - PipelineController를 통한 LLM 파트와 통합
[feat] PIPELINE+LLM 파트 통합 및 RecommendController 로직 분리
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
Summary by CodeRabbit
Walkthrough이번 변경 사항에서는 추천 로직의 구조적 리팩토링과 관련 유틸리티 기능의 확장이 이루어졌습니다. 추천 컨트롤러는 추천 서비스로 로직을 위임하도록 수정되었고, 추천 서비스 인터페이스 및 구현체가 새롭게 추가되었습니다. 행정구역 코드와 콘텐츠 유형을 다루는 enum이 도입되어 데이터 표준화가 강화되었습니다. 임베딩 서비스와 벡터스토어 서비스의 텍스트 준비, 문서 생성, 로깅 기능이 개선되었으며, 파이프라인 컨트롤러는 JSON 기반 프롬프트 파싱 및 추천 서비스 연동 방식으로 변경되었습니다. 프론트엔드 폼에도 입력 필드 명칭 및 옵션이 추가되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant RecommendController
participant RecommendServiceImpl
participant VectorStoreService
participant ChatService
User->>RecommendController: 추천 요청 (promptMap)
RecommendController->>RecommendServiceImpl: recommend(promptMap)
RecommendServiceImpl->>RecommendServiceImpl: buildPrompt(promptMap)
RecommendServiceImpl->>RecommendServiceImpl: buildRegion(promptMap)
RecommendServiceImpl->>VectorStoreService: findSimilarWithFilter(query, k, filter)
VectorStoreService-->>RecommendServiceImpl: 유사 문서 리스트 반환
RecommendServiceImpl->>ChatService: generate(prompt, 유사 문서)
ChatService-->>RecommendServiceImpl: 추천 결과 반환
RecommendServiceImpl-->>RecommendController: 추천 결과 반환
RecommendController-->>User: 추천 결과 응답
Possibly related PRs
Poem
✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (10)
src/main/java/io/github/petty/llm/common/AreaCode.java (1)
41-47: 이름 기반 지역 매핑 메서드에 개선 가능한 부분이 있습니다.현재 구현은 지역명이 포함되는 경우 첫 번째로 매칭되는 지역을 반환합니다. 그러나 일부 지역명이 다른 지역명에 포함될 수 있어 모호성이 발생할 수 있습니다(예: "경기도 부산시"와 같이 입력되면 "경기도"가 반환됨).
정확한 매칭을 위해 다음과 같은 개선을 고려해보세요:
public static AreaCode fromName(String name) { + if (name == null) return ETC; + + // 정확한 일치 먼저 시도 + for (AreaCode a : values()) { + if (name.equals(a.name)) + return a; + } + + // 포함 관계로 검색 for (AreaCode a : values()) { - if (name != null && name.contains(a.name)) + if (name.contains(a.name)) return a; } return ETC; }src/main/java/io/github/petty/llm/service/RecommendService.java (1)
5-7: 인터페이스 구조 및 문서화 개선 제안인터페이스가 간결하게 설계되어 있어 좋습니다. 그러나 메서드와 파라미터에 대한 Javadoc 문서화가 없어 해당 서비스의 용도와 입출력 규격을 이해하기 어렵습니다. 또한 Map<String, String>은 유연하지만 타입 안전성이 떨어집니다.
다음과 같이 문서화와 함께 필요한 경우 별도 DTO 클래스 도입을 고려해보세요:
public interface RecommendService { + /** + * 사용자의 입력 프롬프트를 바탕으로 추천 결과를 생성합니다. + * + * @param promptMap 사용자 입력 프롬프트 정보를 담은 맵 (species, location, weight 등) + * @return 생성된 추천 결과 문자열 + */ String recommend(Map<String, String> promptMap); }장기적으로는 다음과 같은 DTO 클래스 사용을 고려해보세요:
public record RecommendRequest( String species, String location, String weight, Boolean isDanger, String info ) {}src/main/resources/templates/recommend.html (1)
77-82: 맹견 여부 필드 추가 적절맹견 여부를 체크하는 드롭다운 추가는 추천 시스템에 중요한 맥락 정보를 제공합니다. 다만 사용자 입력 값 검증 로직이 누락되어 있습니다.
폼 제출 전 클라이언트 측 유효성 검사를 추가하는 것이 좋습니다:
form.addEventListener("submit", async function(e) { e.preventDefault(); + + const formData = new FormData(form); + // 필수 입력 필드 검증 + if (!formData.get('species') || !formData.get('location')) { + alert('종과 위치는 필수 입력 항목입니다.'); + return; + } - const formData = new FormData(form); const json = Object.fromEntries(formData.entries());src/main/java/io/github/petty/llm/service/VectorStoreService.java (1)
51-68: 필터링 기능 및 로깅 개선 구현 적절필터 표현식을 사용한 유사 콘텐츠 검색 기능이 잘 구현되었습니다. 상세한 로깅을 추가한 것도 디버깅과 문제 해결에 도움이 될 것입니다. 다만 몇 가지 개선점이 있습니다:
- filterExpression 파라미터에 대한 문서화가 부족합니다.
- 대량의 결과를 로깅할 경우 성능 영향이 있을 수 있습니다.
다음과 같이 개선해보세요:
+ /** + * 필터 조건을 사용한 유사 콘텐츠 검색 + * + * @param query 검색 쿼리 + * @param k 반환할 최대 결과 수 + * @param filterExpression 필터 표현식 (예: "metadata.areaCode=='1'") + * @return 필터링된 유사 문서 목록 + */ public List<Document> findSimilarWithFilter(String query, int k, String filterExpression) { SearchRequest searchRequest = SearchRequest.builder() .query(query) .topK(k) .similarityThreshold(0.1) .filterExpression(filterExpression) .build(); List<Document> results = vectorStore.similaritySearch(searchRequest); - log.info("유사 콘텐츠 검색 결과"); + if (log.isDebugEnabled()) { + log.debug("유사 콘텐츠 검색 결과 (총 {}개)", results.size()); + for (int i = 0; i < results.size(); i++) { + Document doc = results.get(i); + log.debug("▶ 결과 {}: ID={}, Metadata={}, Content={}", + i + 1, doc.getId(), doc.getMetadata(), doc.getText()); + } + } else { + log.info("유사 콘텐츠 검색 결과: {}개 항목 검색됨", results.size()); + } - for (int i = 0; i < results.size(); i++) { - Document doc = results.get(i); - log.info("▶ 결과 {}: ID={}, Metadata={}, Content={}", - i + 1, doc.getId(), doc.getMetadata(), doc.getText()); - } return results; }src/main/java/io/github/petty/llm/service/RecommendServiceImpl.java (2)
7-9: 불필요한 컨트롤러 관련 임포트가 있습니다.서비스 클래스에서 컨트롤러 관련 어노테이션이나 클래스는 필요하지 않습니다. 다음 임포트를 제거해주세요:
-import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody;
67-78: 지역 필터링 로직 개선 가능성현재
buildRegion메서드는 위치 문자열의 첫 번째 부분만 처리하고 있어 도시나 구체적인 지역 정보가 무시됩니다. 더 세분화된 지역 필터링을 위해 개선이 필요합니다.private String buildRegion(String location) { // ETC (지역 없을 때 대비) if (location == null || location.isBlank()) return "areaCode == 0"; String[] parts = location.trim().split(" "); if (parts.length == 0) return "areaCode == 0"; String areaName = parts[0]; AreaCode areaCode = AreaCode.fromName(areaName); + + // 시/군/구 정보가 있는 경우 추가 필터링 로직 + if (parts.length > 1) { + // TODO: 시/군/구 코드로 추가 필터링 구현 + // 예: return "areaCode == %d AND sigunguCode == %d".formatted(areaCode.getCode(), sigunguCode); + } return "areaCode == %d".formatted(areaCode.getCode()); }시/군/구 기반 필터링을 추가하는 것이 향후 계획에 맞는지 확인해주세요. PR 목표에 따르면 지역 기반 필터링 기능을 추가하고 있으며, 지구 코드와 주소 정보를 포함한 메타데이터를 추가하여 지구 기반 검색의 향후 확장을 지원한다고 합니다.
src/main/java/io/github/petty/llm/controller/RecommendController.java (1)
3-5: 사용하지 않는 임포트가 있습니다.
AreaCode를 임포트했지만 컨트롤러에서 사용하지 않습니다. 사용하지 않는 임포트는 제거해주세요.-import io.github.petty.llm.common.AreaCode;src/main/java/io/github/petty/llm/service/EmbeddingService.java (3)
37-41: 잠재적인 NullPointerException 위험이 감소했습니다.변수 추출과 null 체크를 통해 코드의 안정성이 향상되었습니다. 변수명의 일관성을 위해 소문자로 시작하는 것이 좋겠습니다.
String title = content.getTitle(); String addr1 = content.getAddr1() != null ? content.getAddr1() : ""; String addr2 = content.getAddr2() != null ? content.getAddr2() : ""; -String ContentTypeName = ContentType.fromCode(content.getContentTypeId()).getName(); +String contentTypeName = ContentType.fromCode(content.getContentTypeId()).getName();
44-45: 자연스러운 텍스트 생성 방식이 개선되었습니다.장소와 관련된 정보를 자연스러운 문장으로 구성하는 방식이 사용자 경험을 향상시킵니다. 한 가지 개선점은 한글의 조사 처리입니다.
-sb.append("%s은/는 %s %s에 위치한 %s 장소입니다.\n" +sb.append("%s%s %s %s에 위치한 %s 장소입니다.\n" - .formatted(title, addr1, addr2, ContentTypeName)); + .formatted(title, getJosaForKorean(title), addr1, addr2, contentTypeName)); // 추가할 메서드 private String getJosaForKorean(String word) { if (word == null || word.isEmpty()) return "은/는"; char lastChar = word.charAt(word.length() - 1); // 한글의 유니코드 범위 내에 있는지 확인 if (lastChar >= '가' && lastChar <= '힣') { // 받침이 있는지 확인 (유니코드 값을 이용) if ((lastChar - '가') % 28 == 0) return "는"; // 받침 없음 else return "은"; // 받침 있음 } return "은/는"; // 한글이 아닌 경우 기본값 }
79-101: 메타데이터를 풍부하게 포함한 문서 생성 로직이 추가되었습니다.문서 생성 시 지역 코드, 시군구 코드, 주소 등의 메타데이터를 포함하여 향후 지역 기반 필터링을 위한 기반이 잘 마련되었습니다. 지역 코드와 콘텐츠 타입에 대한 상수 사용을 고려해보세요.
// 메타데이터에 원본 ID, 관련 데이터 저장 Map<String, Object> metadata = new HashMap<>(); metadata.put("contentId", result.contentId()); metadata.put("title", content.getTitle()); // areaCode (지역 관련 추가) -metadata.put("areaCode", content.getAreaCode()); +metadata.put("areaCode", content.getAreaCode()); // 상수 키 사용 고려: MetadataKeys.AREA_CODE // sigunguCode (시군구 추가) -metadata.put("sigunguCode", content.getSigunguCode()); +metadata.put("sigunguCode", content.getSigunguCode()); // 상수 키 사용 고려: MetadataKeys.SIGUNGU_CODE // 지역 String 추가 -metadata.put("address", content.getAddr1()); +metadata.put("address", content.getAddr1()); // 상수 키 사용 고려: MetadataKeys.ADDRESS // contentType (콘텐츠 관련 추가) -metadata.put("contentType", content.getContentTypeId()); +metadata.put("contentType", content.getContentTypeId()); // 상수 키 사용 고려: MetadataKeys.CONTENT_TYPE다음과 같은 상수 클래스 추가를 고려해보세요:
public final class MetadataKeys { private MetadataKeys() {} // 인스턴스화 방지 public static final String CONTENT_ID = "contentId"; public static final String TITLE = "title"; public static final String AREA_CODE = "areaCode"; public static final String SIGUNGU_CODE = "sigunguCode"; public static final String ADDRESS = "address"; public static final String CONTENT_TYPE = "contentType"; }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
build.gradle(1 hunks)src/main/java/io/github/petty/llm/common/AreaCode.java(1 hunks)src/main/java/io/github/petty/llm/common/ContentType.java(1 hunks)src/main/java/io/github/petty/llm/controller/RecommendController.java(2 hunks)src/main/java/io/github/petty/llm/service/EmbeddingService.java(2 hunks)src/main/java/io/github/petty/llm/service/RecommendService.java(1 hunks)src/main/java/io/github/petty/llm/service/RecommendServiceImpl.java(1 hunks)src/main/java/io/github/petty/llm/service/VectorStoreService.java(4 hunks)src/main/java/io/github/petty/pipeline/controller/PipelineController.java(3 hunks)src/main/java/io/github/petty/pipeline/service/PromptGeneratorServiceImpl.java(1 hunks)src/main/java/io/github/petty/tour/repository/ContentRepository.java(1 hunks)src/main/resources/templates/recommend.html(2 hunks)
🔇 Additional comments (11)
build.gradle (1)
69-69: 빌드스크립트에 영향 없는 공백 제거
파일 말미의 개행 문자가 제거되었으며, 의존성이나 빌드 로직에는 전혀 영향이 없습니다. 포맷 수정만 승인합니다.src/main/java/io/github/petty/pipeline/service/PromptGeneratorServiceImpl.java (1)
16-18: JSON 구문 오류 수정이 잘 이루어졌습니다.포맷 문자열에 콤마가 추가되어 JSON 구문 오류를 해결했습니다. 이전에는
extractedPetInfoJson과 "location" 필드 사이에 콤마가 없어 JSON 파싱 오류가 발생했을 것입니다.src/main/java/io/github/petty/llm/common/ContentType.java (1)
1-30: 콘텐츠 타입 열거형 구현이 잘 되었습니다.콘텐츠 타입을 표준화하는 열거형을 추가하여 코드와 이름을 매핑하는 방식이 적절합니다.
fromCode메서드는 코드가 없거나 일치하는 값이 없을 때 ETC로 기본 반환하여 안정성을 확보했습니다.src/main/java/io/github/petty/llm/common/AreaCode.java (2)
1-30: 지역 코드 열거형이 잘 구현되었습니다.한국 행정구역을 표준화하는 열거형을 추가하여 코드와 이름을 매핑하는 방식이 적절합니다. Lombok 어노테이션을 활용한 코드 간소화도 좋습니다.
31-39: 코드 기반 지역 매핑 메서드가 잘 구현되었습니다.코드값을 통해 지역 열거형을 조회하는 메서드가 적절히 구현되었습니다. null 체크와 기본값 처리가 잘 되어 있습니다.
src/main/java/io/github/petty/tour/repository/ContentRepository.java (1)
27-28: 테스트 데이터 수 증가가 적절히 이루어졌습니다.테스트에 사용되는 콘텐츠 조회 수를 10개에서 20개로 증가시켰습니다. 이는 지역 기반 필터링 구현과 관련하여 더 다양한 테스트 데이터를 확보하기 위한 적절한 변경으로 보입니다.
src/main/resources/templates/recommend.html (2)
3-3: 접근성 향상을 위한 언어 속성 추가 적절HTML 태그에
lang="ko"속성을 추가한 것은 접근성과 SEO 측면에서 좋은 변경입니다.
74-74: 필드명 변경 적절
type에서species로 변경한 것은 의미적으로 더 명확하고 적절합니다.src/main/java/io/github/petty/pipeline/controller/PipelineController.java (1)
3-6: RecommendService 의존성 주입 적절RecommendService 인터페이스를 주입받아 사용하는 구조로 변경한 것은 관심사 분리와 책임 위임 측면에서 좋은 접근입니다. 필요한 import들도 적절히 추가되었습니다.
Also applies to: 15-16, 23-23
src/main/java/io/github/petty/llm/service/VectorStoreService.java (1)
39-39: 메서드 주석 변경 적절메서드 주석을 "유사한 콘텐츠 검색 (SearchRequest 기반)"에서 "유사도 검색"으로 간결하게 변경한 것은 적절합니다.
src/main/java/io/github/petty/llm/controller/RecommendController.java (1)
22-28: 서비스 위임 패턴이 잘 적용되었습니다.컨트롤러에서 비즈니스 로직을 분리하여 서비스 계층으로 위임하는 좋은 예입니다. 이렇게 하면 책임이 명확하게 분리되고 테스트가 용이해집니다.
| // String prompt = togetherPromptBuilder.buildPrompt(visionReport, location); | ||
| String jsonPrompt = togetherPromptBuilder.buildPrompt(visionReport, location); | ||
| log.info(jsonPrompt); | ||
| ObjectMapper objectMapper = new ObjectMapper(); | ||
| Map<String, String> promptMapper = objectMapper.readValue(jsonPrompt, new TypeReference<>() {}); | ||
| log.info(promptMapper.toString()); | ||
| String prompt = recommendService.recommend(promptMapper); | ||
| model.addAttribute("recommendation", prompt); |
There was a problem hiding this comment.
🛠️ Refactor suggestion
JSON 파싱 및 서비스 위임 로직 개선 필요
JSON 프롬프트를 파싱하고 RecommendService로 위임하는 로직은 적절하나, 몇 가지 개선이 필요합니다:
- 주석 처리된 코드는 제거하는 것이 좋습니다.
- JSON 파싱 예외 처리가 세분화되어 있지 않습니다.
- ObjectMapper는 클래스 필드로 선언하는 것이 효율적입니다.
다음과 같이 개선해보세요:
-// String prompt = togetherPromptBuilder.buildPrompt(visionReport, location);
- String jsonPrompt = togetherPromptBuilder.buildPrompt(visionReport, location);
- log.info(jsonPrompt);
- ObjectMapper objectMapper = new ObjectMapper();
- Map<String, String> promptMapper = objectMapper.readValue(jsonPrompt, new TypeReference<>() {});
- log.info(promptMapper.toString());
- String prompt = recommendService.recommend(promptMapper);
+ String jsonPrompt = togetherPromptBuilder.buildPrompt(visionReport, location);
+ log.info("생성된 JSON 프롬프트: {}", jsonPrompt);
+
+ try {
+ ObjectMapper objectMapper = new ObjectMapper();
+ Map<String, String> promptMapper = objectMapper.readValue(jsonPrompt, new TypeReference<>() {});
+ log.info("파싱된 프롬프트 맵: {}", promptMapper);
+
+ String prompt = recommendService.recommend(promptMapper);
+ model.addAttribute("recommendation", prompt);
+ return "pipeline";
+ } catch (JsonProcessingException e) {
+ log.error("JSON 프롬프트 파싱 중 오류 발생", e);
+ model.addAttribute("error", "프롬프트 형식이 올바르지 않습니다.");
+ return "pipeline";
+ }또는 ObjectMapper를 클래스 필드로 선언하는 방식:
public class PipelineController {
private final TogetherPromptBuilder togetherPromptBuilder;
private final RecommendService recommendService;
+ private final ObjectMapper objectMapper = new ObjectMapper();| @@ -1,5 +1,6 @@ | |||
| package io.github.petty.llm.service; | |||
|
|
|||
| import groovy.util.logging.Slf4j; | |||
There was a problem hiding this comment.
중복된 로깅 어노테이션 제거 필요
Slf4j 어노테이션이 두 가지 다른 패키지(groovy.util.logging.Slf4j와 lombok.extern.slf4j.Slf4j)에서 중복 import 및 사용되고 있습니다. 이는 혼란을 야기할 수 있습니다.
다음과 같이 수정해주세요:
-import groovy.util.logging.Slf4j;
+import lombok.extern.slf4j.Slf4j;
import io.github.petty.tour.entity.Content;
import lombok.RequiredArgsConstructor;
import org.springframework.ai.document.Document;
import org.springframework.ai.embedding.EmbeddingModel;
...
-@lombok.extern.slf4j.Slf4j
@Slf4j
@Service
@RequiredArgsConstructorAlso applies to: 18-19
| try { | ||
| String result = chatService.generateFromPrompt(userPrompt, docs); | ||
| return result; | ||
| } catch (Exception e) { | ||
| throw new RuntimeException(e); | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
예외 처리를 개선해야 합니다.
현재 모든 예외를 RuntimeException으로 래핑하고 있어 원인 파악이 어렵습니다. 구체적인 예외 타입을 사용하고 의미 있는 메시지를 추가하세요.
try {
String result = chatService.generateFromPrompt(userPrompt, docs);
return result;
} catch (Exception e) {
- throw new RuntimeException(e);
+ throw new RuntimeException("추천 생성 중 오류가 발생했습니다: " + e.getMessage(), e);
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| try { | |
| String result = chatService.generateFromPrompt(userPrompt, docs); | |
| return result; | |
| } catch (Exception e) { | |
| throw new RuntimeException(e); | |
| } | |
| try { | |
| String result = chatService.generateFromPrompt(userPrompt, docs); | |
| return result; | |
| } catch (Exception e) { | |
| - throw new RuntimeException(e); | |
| + throw new RuntimeException("추천 생성 중 오류가 발생했습니다: " + e.getMessage(), e); | |
| } |
| if(isDanger.equals("true")) { | ||
| sb.append("맹견이에요\n"); | ||
| } else { | ||
| sb.append("소형견, 중형견이에요\n"); | ||
| } |
There was a problem hiding this comment.
NullPointerException 발생 가능성이 있습니다.
isDanger 변수가 null일 경우 equals() 메서드 호출 시 NullPointerException이 발생할 수 있습니다. null 체크 로직을 추가하세요.
-if(isDanger.equals("true")) {
+if("true".equals(isDanger)) {
sb.append("맹견이에요\n");
} else {
sb.append("소형견, 중형견이에요\n");
}또는 null 체크를 명시적으로 추가:
-if(isDanger.equals("true")) {
+if(isDanger != null && isDanger.equals("true")) {
sb.append("맹견이에요\n");
} else {
sb.append("소형견, 중형견이에요\n");
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if(isDanger.equals("true")) { | |
| sb.append("맹견이에요\n"); | |
| } else { | |
| sb.append("소형견, 중형견이에요\n"); | |
| } | |
| if("true".equals(isDanger)) { | |
| sb.append("맹견이에요\n"); | |
| } else { | |
| sb.append("소형견, 중형견이에요\n"); | |
| } |
리뷰
제안
좋은 코드 작성해주셔서 감사합니다 고생 많으셨습니다. |
확인했습니다, null 예외 처리를 전반적으로 추가하도록 하겠습니다! 더불어 CodeRabbit 리뷰에서, PipelineController 개선 부분도 제안하여 함께 최종 수정 거치면 될 것 같습니다. |
✅ 코드 리뷰
전반적으로 기능 추가와 구조 개선이 잘 된 것을 확인했습니다. 세부 로직과 코드 품질 측면에서 보완하면 더욱 완성도 높은 코드가 될 것 같습니다. |
확인했습니다! 금요일까지 추가할 수 있도록 해보겠습니다 |
📜 PR 내용 요약
⚒️ 작업 및 변경 내용(상세하게)
Part1. RAG 지역 기반 필터링 검색
🧷 Spring AI Vector DB의 filterExpression 관련 Docs
AreaCode,ContentType: enum을 도입하여 DB의 areaCode와 실제 지역 이름 매칭 재사용 가능하게 구성Part2. PIPELINE + LLM 파트 통합
RecommendController를RecommendServiceImpl,RecommendService로 분리,이 없어 JSON 출력 결과 파싱이 제대로 되지 않는 이슈를 해결했습니다.📚 기타 참고 사항 및 리뷰 포인트
RecommendController에서 처리하던 추천 로직을 PIPELINE 파트와 통합을 위하여 서비스 위임하여 분리했습니다. 이 부분에서 오류가 없는지 확인 부탁드립니다.🔧 추후 확장 예정