개발 프로젝트/[팀 프로젝트] 냉파마스터

냉파마스터 2차 프로젝트: 장보기 리팩토링과 AI Agent 확장 기반 만들기

namerong 2026. 8. 4. 17:42

1차 프로젝트에서는 냉장고, 사전 재료, 장보기 기능의 기본 CRUD와 프론트 연동을 중심으로 구현했다.
2차 프로젝트에서는 단순 기능 추가보다는 기존 기능을 더 안정적으로 다듬고,
이후 AI Agent 기능으로 확장할 수 있는 구조를 만드는 것을 목표로 잡았다.

이번 작업 범위는 크게 세 가지였다.

첫째, 장보기 항목 중복 등록 방지
둘째, AI Agent가 사용할 Tool API 구조 정리
셋째, 냉장고와 장보기 상태를 기반으로 한 장보기 추천 MVP 구현

관련 이슈는 다음과 같다.

이슈 작업 내용
#234 장보기 항목 중복 등록 방지
#235 AI 장보기 자동화 Agent API 명세 작성
#236 Agent 냉장고/장보기 조회 Tool API 구현
#237 Agent 장보기 추가 Tool API 구현
#238 AI 장보기 추천 MVP 구현

1. 장보기 항목 중복 등록 방지

기존 장보기 기능은 같은 재료를 여러 번 추가할 수 있었다.
사용자가 직접 추가할 때는 물론이고, 이후 레시피 기반 추가나 AI 추천 추가가 붙으면 같은 재료가 반복해서 쌓일 가능성이 있었다.

그래서 동일 사용자 기준으로 다음 조건을 만족하는 장보기 항목은 중복 등록으로 판단했다.

  • 같은 사용자
  • 같은 productId
  • 삭제되지 않은 항목
  • 아직 구매 완료되지 않은 항목

즉, 사용자가 이미 “감자 1개”를 장보기 목록에 담아둔 상태에서 다시 감자를 추가하면 409 Conflict를 반환하도록 했다.

반대로 다음 경우는 재등록을 허용했다.

  • 사용자가 기존 항목을 삭제한 경우
  • 사용자가 기존 항목을 구매 완료 처리한 경우
  • 다른 사용자가 같은 재료를 담은 경우

이렇게 처리한 이유는 장보기 목록이 “현재 구매 예정인 항목”을 관리하는 기능이기 때문이다.
이미 삭제했거나 구매 완료한 항목은 현재 구매 예정 목록이 아니므로 다시 추가할 수 있어야 한다.


2. Agent API 명세 정리

2차 프로젝트의 핵심 확장 방향은 AI Agent였다.
다만 AI가 바로 DB를 수정하도록 만들면 위험하다고 판단했다.

그래서 Agent API는 다음 원칙으로 설계했다.

  • AI는 필요한 데이터를 조회할 수 있다.
  • AI는 추천 결과를 만들 수 있다.
  • 추천 결과는 DB에 바로 저장하지 않는다.
  • 사용자가 승인한 항목만 장보기 목록에 저장한다.
  • 저장 시에는 기존 ShoppingItemService 정책을 그대로 사용한다.

이 구조를 위해 API 번호는 기존 냉장고, 장보기 API와 충돌하지 않도록 700번대로 분리했다.

API ID 기능 Method URL
API-700 Agent 냉장고 조회 Tool GET /api/v1/agent/tools/fridge-items
API-701 Agent 장보기 조회 Tool GET /api/v1/agent/tools/shopping-items
API-702 AI 장보기 추천 생성 POST /api/v1/agent/shopping-recommendations
API-703 Agent 승인 항목 장보기 추가 POST /api/v1/agent/tools/shopping-items

여기서 중요한 점은 추천 생성과 저장을 분리한 것이다.

추천 API는 “이 재료를 사면 좋겠다”는 후보만 반환하고,
장보기 추가 API는 사용자가 선택한 항목만 저장한다.

이렇게 하면 AI 추천이 잘못되더라도 사용자 데이터가 자동으로 변경되지 않는다.


3. Agent 냉장고/장보기 조회 Tool API 구현

AI가 장보기 추천을 하려면 먼저 사용자의 현재 상태를 알아야 한다.

그래서 Agent Tool API로 냉장고와 장보기 목록 조회 API를 만들었다.

  • GET /api/v1/agent/tools/fridge-items
  • GET /api/v1/agent/tools/shopping-items

이 API는 새 조회 로직을 따로 만들기보다는 기존 냉장고, 장보기 Service를 재사용했다.
이미 기존 Service에는 로그인 사용자 기준 조회와 소유자 검증 흐름이 들어가 있었기 때문이다.

Agent API라고 해서 별도 정책을 다시 만들면 같은 기능이 중복되고,
나중에 정책이 바뀔 때 한쪽만 수정되는 문제가 생길 수 있다.

그래서 Agent Tool API는 컨트롤러만 분리하고,
실제 데이터 조회는 기존 Service를 사용하도록 구성했다.


4. Agent 승인 항목 장보기 추가 Tool API 구현

AI가 추천한 항목을 사용자가 승인하면 장보기 목록에 추가해야 한다.

이때도 핵심은 기존 장보기 등록 정책을 재사용하는 것이었다.

기존 ShoppingItemService에는 다음 정책이 들어가 있다.

  • 존재하지 않는 productId 차단
  • 비활성 사전 재료 차단
  • 중복 장보기 항목 차단
  • 로그인 사용자 기준 저장

Agent 승인 항목 추가 API가 별도 저장 로직을 가지면 이 정책들이 중복되거나 누락될 수 있다.
그래서 Agent API는 요청을 받은 뒤 내부적으로 기존 장보기 등록 Service를 호출하도록 했다.

즉, Agent를 통해 추가하든 사용자가 직접 추가하든 같은 정책을 타게 된다.

이 구조 덕분에 #234에서 구현한 중복 등록 방지 정책도 Agent 추가 API에 그대로 적용된다.


5. AI 장보기 추천 MVP 구현

이번 단계의 AI 장보기 추천은 LLM을 직접 호출하는 형태는 아니다.
아직 FastAPI Agent 서버나 LLM 연동 정책이 확정되지 않았기 때문에, 먼저 Spring Boot 내부에서 규칙 기반 MVP로 구현했다.

현재 추천 흐름은 다음과 같다.

  1. 로그인한 사용자를 조회한다.
  2. 사용자의 냉장고 재료 목록을 조회한다.
  3. 사용자의 장보기 목록을 조회한다.
  4. 냉장고에 이미 있는 productId를 제외 목록에 추가한다.
  5. 장보기 목록 중 미구매 상태인 productId를 제외 목록에 추가한다.
  6. 활성 상태의 사전 재료 중 제외 목록에 없는 재료를 추천한다.
  7. 추천 결과는 DB에 저장하지 않고 응답으로만 반환한다.

예를 들어 사용자의 냉장고에 두부가 있고, 장보기 목록에 감자가 있다면 추천 후보에서는 두부와 감자를 제외한다.

사전 재료 전체: 두부, 감자, 양파, 대파, 계란
냉장고 보유: 두부
장보기 예정: 감자

추천 후보: 양파, 대파, 계란

이 방식은 아직 완전한 AI 추천은 아니지만, 이후 LLM을 붙이기 위한 기반 구조로는 의미가 있다.

LLM 연동 이후에는 현재 구조를 다음처럼 확장할 수 있다.

냉장고 재료

  • 장보기 예정 재료
  • 못 먹는 재료
  • 선호 음식
  • 식단 목적
  • 제외 productId

→ FastAPI Agent 서버 전달
→ LLM 추천 생성
→ Spring Boot에서 productId 검증
→ 사용자에게 추천 목록 반환
→ 사용자가 승인한 항목만 장보기 저장

현재는 추천 이유도 고정 문구로 반환한다.

“냉장고와 장보기 목록에 없는 재료입니다.”

이후 LLM이 붙으면 추천 이유를 더 자연스럽게 만들 수 있다.

예를 들어:

“현재 냉장고에 양파와 두부가 있어 된장찌개 조리에 필요한 애호박을 추천합니다.”

이런 식으로 사용자 상태 기반 추천 이유까지 제공할 수 있다.


6. 추천 결과를 바로 저장하지 않은 이유

AI 추천 기능에서 가장 조심해야 할 부분은 자동 저장이다.

AI가 추천한 결과를 바로 장보기 목록에 저장하면 사용자가 원하지 않는 재료가 목록에 들어갈 수 있다.
특히 장보기 목록은 실제 구매 행동으로 이어지는 기능이기 때문에, 사용자의 승인 단계가 필요하다고 봤다.

그래서 이번 구조는 다음처럼 나눴다.

추천 생성 API
→ 추천 목록만 반환
→ DB 저장 없음

승인 항목 추가 API
→ 사용자가 선택한 항목만 저장
→ 기존 장보기 등록 정책 적용

이렇게 분리하면 AI 기능을 붙이더라도 사용자 데이터 변경은 항상 사용자의 선택을 거치게 된다.


7. 테스트

이번 작업에서는 AI 장보기 추천 Service 테스트를 추가했다.

테스트한 내용은 다음과 같다.

  • 냉장고 보유 재료는 추천에서 제외된다.
  • 미구매 장보기 항목은 추천에서 제외된다.
  • 추천 결과는 요청 limit 이하로 반환된다.
  • limit 값이 없으면 기본값이 적용된다.
  • 존재하지 않는 회원이면 추천에 실패한다.

테스트 중 한 번 실패한 부분도 있었다.

처음에는 테스트에서 새로 만든 추천 가능 재료가 반드시 결과에 포함될 것이라고 기대했다.
하지만 로컬 DB에는 이미 활성 사전 재료가 많이 존재하고, 추천 결과는 limit 개수만큼 잘려 반환된다.
따라서 새로 만든 재료가 추천 후보에는 포함될 수 있어도, limit 안에 반드시 들어온다고 보장할 수 없었다.

그래서 테스트 기준을 다음처럼 수정했다.

  • 제외되어야 하는 재료가 실제로 제외되는지 확인
  • 추천 결과 개수가 limit을 넘지 않는지 확인

이렇게 수정하니 테스트가 실제 추천 로직의 목적과 더 잘 맞았다.


8. 현재 한계와 다음 단계

현재 #238은 LLM 연동 전 규칙 기반 MVP다.
따라서 다음 내용은 아직 남아 있다.

  • FastAPI Agent 서버 연동
  • LLM 호출 구조 구현
  • LLM 실패 시 예외 처리
  • 추천 이유 생성 고도화
  • PREMIUM/FREE 권한 정책 연결
  • 추천 결과 정렬 기준 개선

현재 프로젝트에는 아직 PREMIUM/FREE 구독 권한 구조가 없기 때문에, 무료/유료 사용자 분기는 바로 구현하지 않았다.
이 부분은 결제 또는 구독 정책이 확정된 뒤 연결하는 것이 맞다고 판단했다.


9. 정리

이번 작업은 단순히 AI 추천 API 하나를 만든 작업이라기보다는,
기존 장보기 기능을 AI Agent가 안전하게 사용할 수 있도록 기반을 만든 작업이었다.

특히 다음 세 가지를 중요하게 봤다.

  • 기존 Service 정책 재사용
  • 추천과 저장 흐름 분리
  • 사용자 데이터 자동 변경 방지

아직 LLM이 붙은 완성형 AI 기능은 아니지만,
냉장고와 장보기 상태를 기반으로 추천 후보를 만들고,
사용자가 승인한 항목만 장보기 목록에 저장하는 구조를 만들었다는 점에서 2차 프로젝트의 출발점으로 의미가 있었다.