[Spring AI + Ollama + Rag 도입기] 자동화 창고 챗봇 서비스 구현 ②

양현지·2026년 5월 14일

연구

목록 보기
19/26

사용자 질문

├─ 재고/위치/수량 관련 → DB 직접 조회 (JdbcTemplate)

└─ 매뉴얼/규정/FAQ 관련 → Chroma 벡터 검색 (PDF, PPTX 등)

→ 두 결과를 합쳐서 LLM에 주입 → 답변 생성

터미널에 직접 질의 던져도 느리다.

PS C:\Project\wms-rag-service> $body = '{"model":"llama3.2:3b","prompt":"안녕","stream":false}'
PS C:\Project\wms-rag-service> Invoke-RestMethod -Method POST `
>   -Uri "http://localhost:11434/api/generate" `
>   -ContentType "application/json" `
>   -Body $body

ollama 버전 다운그레이드 후 재시도해본다.

응답 OK !

이번에는 데이터베이스 설계 문서를 토대로 동적 쿼리를 생성하고 응답을 생성해보자

1. 데이터 벡터화

1-1. build.gradle 설정

.pptx .pdf 등 설계 문서 데이터를 처리하기 위한 의존성을 추가하도록 한다.

  • 📍 build.gradle
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'

    // Spring AI 1.1.6 stable
    implementation 'org.springframework.ai:spring-ai-starter-model-ollama'

    // Chroma Vector Store
    implementation 'org.springframework.ai:spring-ai-starter-vector-store-chroma'

    // MSSQL JDBC Driver
    implementation 'com.microsoft.sqlserver:mssql-jdbc:12.6.3.jre11'

    // JPA
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

    // Lombok
    compileOnly 'org.projectlombok:lombok:1.18.38'
    annotationProcessor 'org.projectlombok:lombok:1.18.38'

    // Java 21 + ClosedChannelException 해결
    implementation 'com.squareup.okhttp3:okhttp:4.12.0'

    // ❗ PDF 읽기
    implementation 'org.springframework.ai:spring-ai-pdf-document-reader'

    // ❗ PPTX / 다양한 문서 형식 (Tika 기반)
    implementation 'org.springframework.ai:spring-ai-tika-document-reader'

    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

1-2. DocumentVectorService.java 수정 (PDF + PPTX 벡터화 하기)

1-3. 설계서 업로드 (rag/documnets/upload)

&# curl.exe 사용 (Windows 10/11 기본 내장)
curl.exe -X POST "http://localhost:8081/rag/documents/upload" `
-F "file=@C:\Users\HJ-YANG\Downloads\kctc_dbschema.pptx"

💡 혹시 MaxUploadSizeExceededException: Maximum upload size exceeded 이러한 오류가 뜬다면, Application.yml에서 maximum size를 증가시켜주자.

  • 📍 Application.yml

    spring:
    servlet:
    multipart:
    max-file-size: 100MB # 파일 하나 최대 크기
    max-request-size: 100MB # 요청 전체 최대 크기

위와 같이 적용해도 안된다면, application.properties와 충돌 여부를 체크

  • 📍 Application.properties
spring.application.name=wms-rag-service
*# Ollama Configuration
spring.ai.ollama.chat.options.model=llama3.2:3b
spring.ai.ollama.base-url=http://localhost:11434
*# ChromaDB Vector Store Configuration
spring.ai.vectorstore.chroma.client.host=http://localhost
spring.ai.vectorstore.chroma.client.port=8000
spring.ai.vectorstore.chroma.collection.name=wms-rag-collection

properties에 정의된 host와 port가 있고, yml에 정의된 base-url 키 이름이 달라 충돌이 발생한다.

결국 properties와 yml 중 하나로 통일해서 쓰는 것을 추천한다.
(properties <- 설정이 적은 경우 / yml <- Spring AI 처럼 구조 복잡도가 있는 경우)

결론
properties를 yml로 통합하고 properties는 삭제 ❗

  • 📍 Application.yml
spring:
  servlet:
    multipart:
      max-file-size: 100MB
      max-request-size: 100MB

그리고 clean 후 bootRun 시도 ❗

./gradlew clean build -x test
./gradlew bootRun

PS C:\Project\wms-rag-service> curl.exe -X POST "http://localhost:8081/rag/documents/upload" `

-F "file=@C:\Users\HJ-YANG\Downloads\kctc_dbschema.pptx"
업로드 완료: kctc_dbschema.pptx

1-4. RAG 기반 질의 시작

# 1. 벡터 저장 건수 확인
PS C:\Project\wms-rag-service> Invoke-RestMethod -Uri "http://localhost:8000/api/v2/tenants/SpringAiTenant/databases/SpringAiDatabase/collections/82977eae-5e2e-47ae-bbdc-3735b506cf0a/count"
>> 3180

# 2. 질문 (인코딩 설정 먼저)
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$OutputEncoding = [System.Text.Encoding]::UTF8

$response = Invoke-RestMethod -Method POST `
  -Uri "http://localhost:8081/rag/ask" `
  -ContentType "application/json; charset=utf-8" `
  -Body ([System.Text.Encoding]::UTF8.GetBytes('{"question":"T_DATA_SKU 테이블 데이터를 요약 알려줘"}'))

# 3. 응답 출력
$response.answer

>>> T_DATA_SKU 테이블 데이터 요약:

1. T_DATA_SKU 테이블은 재고 정보를 담고 있습니다.
2. 테이블의 컬럼은 다음과 같습니다.

| 컬럼 | 명칭 |
| --- | --- |
| INV_ID | 재고 ID |
| T_DATA_SKU | 재고 SKU |
| 수량 | 수량 |
| 수정일시 | 수정일시 |
| 수정자 | 수정자 |

3. 테이블의 데이터는 다음과 같습니다.

* INV_ID=1847, T_DATA_SKU=6973, 수량=1
* INV_ID=1917, T_DATA_SKU=6903, 수량=1
* INV_ID=1934, T_DATA_SKU=6886, 수량=1

4. 테이블의 데이터는 3 개의 rows로 구성되어 있습니다.

5. 테이블의 데이터를 요약한 결과는 다음과 같습니다.

| 재고 ID | 재고 SKU | 수량 |
| --- | --- | --- |
| 1847 | 6973 | 1 |
| 1917 | 6903 | 1 |
| 1934 | 6886 | 1 |

이러한 데이터를 요약한 결과로, T_DATA_SKU 테이블의 데재고 정보를 담고 있으며, 재고 SKU, 수량, 수정일시 및  포함되어 있습니다.

이로써 pptx 임베딩(chromadb) + mssql 소스 데이터 연결 + ollama 기반 로컬 llm으로 동작하는 RAG+Text-to-SQL 파이프 라인까지 완성해보았다.

아무래도 ① 경량화된 ollama 모델 사용 + ② 가비지 데이터가 포함된 설계 문서 + ③ 소스데이터의불충분 + ④ 질의의 퀄리티 등의 이유로 아직 답변이 불안정하긴하다.

다음파트에서는 본격적으로 프롬프트 UI/UX를 넣어보고 터미널이 아닌 UX로 파일을 첨부하고 질의 응답을 생성해보고자 한다.

0개의 댓글