Skip to content
Draft
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
2735626
chore: env 파일 import
kjyyjk May 8, 2026
f75ad57
feat: 유저 챗 엔드포인트 및 ai 호출 구현
kjyyjk May 8, 2026
f6fa3c4
feat: llm에게 필요한 데이터 제공
kjyyjk May 9, 2026
d250287
refactor: builder에서 프롬프트 설정
kjyyjk May 9, 2026
4ecdb13
chore: advisors-vector-store 의존성 추가
kjyyjk May 9, 2026
4ac5a9a
refactor: 벡터 db 및 어드바이저 활용
kjyyjk May 9, 2026
46b20a7
chore: markdown-document-reader 의존성 추가
kjyyjk May 9, 2026
62b7aad
docs: resources/data에 layer_n 복사
kjyyjk May 9, 2026
28b3413
feat: md 파일 벡터 저장소에 저장
kjyyjk May 9, 2026
8759009
feat: 응답 content type json으로 변경
kjyyjk May 10, 2026
8ec9bac
refactor: RequestBody dto로 매핑
kjyyjk May 10, 2026
d2901a6
refactor: 테스트 incorrect 이유 글자수 2배 증가
kjyyjk May 10, 2026
64ee947
refactor: topk 2배 증가
kjyyjk May 10, 2026
aea6e10
feat: 디버깅용 엔드포인트 추가
kjyyjk May 11, 2026
e3fe990
docs: deprecated 문서 vector db에서 제거
kjyyjk May 11, 2026
071ec9b
refactor: advisor 커스텀 템플릿 설정
kjyyjk May 13, 2026
6eb21ee
refactor: 프롬프트 내 할루시네이션 방지 내용 추가
kjyyjk May 13, 2026
838f408
feat: 챗봇 응답에 token 정보 포함
kjyyjk May 15, 2026
162cb3c
feat: 디버깅 엔드포인트 응답에 token 정보 포함
kjyyjk May 15, 2026
ebaab45
refactor: controller 패키지 분리
kjyyjk May 15, 2026
ef3815c
refactor: service 분리
kjyyjk May 15, 2026
f8f89e7
feat: 대화 맥락 유지를 위한 chatmemory 추가
kjyyjk May 16, 2026
deb627d
feat: 챗봇 세션 시작/종료 엔드포인트 추가
kjyyjk May 16, 2026
2c6e041
feat: 챗봇 세션 시작/종료 엔드포인트 변경
kjyyjk May 16, 2026
9383c9a
refactor: config 설정 분리
kjyyjk May 16, 2026
3700df4
feat: 챗봇 ui 구현
kjyyjk May 16, 2026
53caf47
feat: 챗봇 ui 개선
kjyyjk May 16, 2026
71121c4
refactor: vip 연락수단 제거
kjyyjk May 16, 2026
5106f1d
refactor: 챗로그 청크 제거
kjyyjk May 17, 2026
ea159ca
chore: ai rag 의존성 추가
kjyyjk May 17, 2026
918edd4
refactor: qa 어드바이저 미사용 및 쿼리 확장 추가
kjyyjk May 18, 2026
d35b780
refactor: 미사용 코드 제거(디버깅 엔드포인트)
kjyyjk May 18, 2026
0d96e85
feat: 리랭크 구현
kjyyjk May 18, 2026
9f1ec40
refactor: 리랭크 수정 및 디버깅
kjyyjk May 18, 2026
f287a6d
refactor: 검색되 청크에 해당하는 문서 전체를 컨텍스트에 포함
kjyyjk May 19, 2026
24f09c9
refactor: 메모리 어드바이저 임시 제거
kjyyjk May 19, 2026
5f0b94c
refactor: 미사용 코드 제거
kjyyjk May 20, 2026
c5bb941
refactor: 주석 추가
kjyyjk May 20, 2026
165f724
docs: 벽 리포트 작성
kjyyjk May 20, 2026
d7f6d68
refactor: vector store 임베딩 runner 분리
kjyyjk May 28, 2026
83f9f41
docs: 미션 readme와 챗봇 readme 분리
kjyyjk May 28, 2026
0f3cc39
style: 초록 회사명 있어보이게 변경
kjyyjk May 28, 2026
d20992d
docs: readme 실행 섹션 수정
kjyyjk May 28, 2026
da03e45
refactor: 임베딩 벡터 영속화 및 임베딩 로직 runner로 분리
kjyyjk May 29, 2026
e01ede4
feat: vector 파일 gitignore
kjyyjk May 29, 2026
42b267f
docs: KPI 문서화
kjyyjk May 30, 2026
9a93fe1
docs: 직접 검수 데이터셋 생성
kjyyjk May 30, 2026
2d6ffbb
docs: 평가 수행 및 직접 검수
kjyyjk May 30, 2026
a52b816
refactor: 답변할 수 없는 질문에 대한 추가 문의 안내
kjyyjk May 30, 2026
37c1647
fix: 프롬프트 에러 수정
kjyyjk May 30, 2026
bbd8971
docs: rag 검색, 생성 평가할 wall_type null 테스트 셋
kjyyjk Jun 1, 2026
67d6ded
docs: 평가 스크립트 작성
kjyyjk Jun 1, 2026
af65f4d
docs: wall null 호출 결과 저장
kjyyjk Jun 1, 2026
c56085b
refactor: 답변에 context list 포함
kjyyjk Jun 1, 2026
091a496
chore: rag_eval git ignore
kjyyjk Jun 1, 2026
aa8bd34
refactor: 할루시네이션 방지 프롬프트 강조
kjyyjk Jun 2, 2026
5851c20
refactor: 답변 가능한데 안하는 현상 방지 프롬프트 수정
kjyyjk Jun 2, 2026
c7e50e6
docs: 테스트 실행 방법 readme 추가
kjyyjk Jun 2, 2026
b43d9c1
docs: 데이터셋에 검수된 기준 답변 추가
kjyyjk Jun 3, 2026
aac7b3d
refactor: 미사용 메서드 및 import 제거
kjyyjk Jun 3, 2026
1d10f33
feat: Query Transform 적용
kjyyjk Jun 3, 2026
399c947
feat: Translation Query Transform 적용
kjyyjk Jun 3, 2026
30eae6f
feat: Query Expander 추가
kjyyjk Jun 5, 2026
4141654
refactor: retriever, generator 분리
kjyyjk Jun 5, 2026
cd44716
refactor: 미사용 import 제거
kjyyjk Jun 5, 2026
b10b95a
chore: 임베딩 모델 small -> large 변경
kjyyjk Jun 6, 2026
7ee6e64
docs: 모델 평가 데이터 정리
kjyyjk Jun 6, 2026
3f134fc
docs: 모델 평가 데이터 정리
kjyyjk Jun 6, 2026
f86327e
refactor: topK 4로 원복
kjyyjk Jun 6, 2026
208cbf7
docs: 계정 삭제 시 미사용 포인트/쿠폰 안내 섹션 분리
kjyyjk Jun 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ dependencyManagement {
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.ai:spring-ai-starter-model-openai'
implementation 'org.springframework.ai:spring-ai-advisors-vector-store'
implementation 'org.springframework.ai:spring-ai-markdown-document-reader'
implementation 'org.projectlombok:lombok'

testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
Expand Down
2 changes: 1 addition & 1 deletion data/evaluate.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ def main():
if args.verbose:
print(f"[{qid}] {marker} ({tier}) {question_ko[:40]}...")
if score == 0:
print(f" 이유: {judgment.get('reason', '')[:80]}")
print(f" 이유: {judgment.get('reason', '')[:160]}")

# 진행률 (10개마다)
if not args.verbose and (i + 1) % 10 == 0:
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/com/cholog/bootcamp/ChatRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.cholog.bootcamp;

public record ChatRequest(
String question
) {
}
57 changes: 57 additions & 0 deletions src/main/java/com/cholog/bootcamp/ChatbotController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.cholog.bootcamp;

import java.util.Map;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.client.advisor.vectorstore.QuestionAnswerAdvisor;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.SimpleVectorStore;
import org.springframework.ai.vectorstore.VectorStore;
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 lombok.extern.slf4j.Slf4j;

@Slf4j
@RequestMapping("/api/chat")
@RestController
public class ChatbotController {

private final ChatClient chatClient;

public ChatbotController(ChatClient.Builder builder, EmbeddingModel embeddingModel, MarkdownReader markdownReader) {
VectorStore vectorStore = SimpleVectorStore.builder(embeddingModel).build();
vectorStore.add(markdownReader.loadAll());
QuestionAnswerAdvisor questionAnswerAdvisor = QuestionAnswerAdvisor.builder(vectorStore)
.searchRequest(SearchRequest.builder().topK(8).build())
.build();
this.chatClient = builder
.defaultAdvisors(questionAnswerAdvisor, new SimpleLoggerAdvisor())
.build();
}

@PostMapping
public Map<String, String> chat(@RequestBody ChatRequest request) {
String answer = chatClient.prompt()
.user(request.question())
.call()
.content();
return Map.of("answer", answer);
}

@PostMapping("/debug")
public Map<String, String> debugChat(@RequestBody ChatRequest request) {
Object RETRIEVED_DOCUMENTS = chatClient.prompt()
.user(request.question())
.call()
.chatClientResponse()
.context()
.get(QuestionAnswerAdvisor.RETRIEVED_DOCUMENTS);
log.info("RETRIEVED_DOCUMENTS: {}", RETRIEVED_DOCUMENTS);
return Map.of("answer", "answer");
Comment thread
kjyyjk marked this conversation as resolved.
Outdated
}
}
37 changes: 37 additions & 0 deletions src/main/java/com/cholog/bootcamp/MarkdownReader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.cholog.bootcamp;

import java.util.ArrayList;
import java.util.List;

import org.springframework.ai.document.Document;
import org.springframework.ai.reader.markdown.MarkdownDocumentReader;
import org.springframework.ai.reader.markdown.config.MarkdownDocumentReaderConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

@Component
class MarkdownReader {

private final Resource[] resources;

public MarkdownReader(@Value("classpath:data/**/*.md") Resource[] resources) {
this.resources = resources;
}

public List<Document> loadAll() {
List<Document> allDocuments = new ArrayList<>();
for (Resource resource : resources) {
MarkdownDocumentReaderConfig config = MarkdownDocumentReaderConfig.builder()
.withHorizontalRuleCreateDocument(true)
.withIncludeCodeBlock(false)
.withIncludeBlockquote(false)
.withAdditionalMetadata("filename", resource.getFilename())
.build();

MarkdownDocumentReader reader = new MarkdownDocumentReader(resource, config);
allDocuments.addAll(reader.get());
}
return allDocuments;
}
}
2 changes: 2 additions & 0 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
spring:
config:
import: optional:file:.env[.properties] # 루트의 .env 파일이 존재하면 .properties 형식으로 읽어 임포트
application:
name: spring-ai-bootcamp-basic
ai:
Expand Down
45 changes: 45 additions & 0 deletions src/main/resources/data/layer1_faq/account.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Account & Membership

## Cholog Corporation — Official FAQ

### What are the membership tiers and their benefits?

| Tier | Qualification | Free Shipping | Points | Extras |
|------|--------------|---------------|--------|--------|
| Standard | Default | Economy on orders ≥ 20,000 won | 1% | — |
| Plus | Spend ≥ 200,000 won/year | Economy on all orders | 3% | Birthday double-points |
| VIP | Spend ≥ 800,000 won/year | Priority on all orders | 5% | Early launch access, dedicated support line (1588-0002) |

Tier status is evaluated on January 1st each year based on the prior year's spending.
Returned items are deducted from annual spending totals and may trigger a tier downgrade.

### How does the loyalty point system work?

Points are earned at 1% (Standard), 3% (Plus), or 5% (VIP) of the pre-shipping order total.
Points are credited 7 days after delivery confirmation and expire 12 months from the date
earned. 1 point = 1 won. Minimum redemption: 1,000 points per order.

### How do I create an account?

You need a valid email address or Korean mobile number. You can also register instantly via
Kakao, Naver, or Google SSO. All new accounts start at Standard tier and receive a one-time
3,000 won welcome coupon valid for 30 days.

### How do I permanently delete my account?

Go to "Settings > Privacy > Delete My Account". After confirming with your password or
a one-time verification code, deletion is scheduled within 7 business days. All personal
data, order history, saved addresses, and payment tokens are purged under Korea's Personal
Information Protection Act (PIPA). Unused points and coupons are forfeited upon deletion.

### How do I enable two-factor authentication (2FA)?

Go to "Settings > Security > Two-Factor Authentication". Choose SMS or an authenticator
app (Google Authenticator, Authy). Once enabled, a 6-digit code is required at every login.
Recovery codes are provided during setup — store them safely.

### When do loyalty points expire?

Points expire 12 months from the date they are earned. If you return an order, the points
earned from that order are deducted within 24 hours of the refund. If your balance is
insufficient, the deficit is carried forward and deducted from future earnings.
38 changes: 38 additions & 0 deletions src/main/resources/data/layer1_faq/eco_green.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Environment & Green Initiatives

## Cholog Corporation — Official FAQ

### What is the Eco Choice certification?

Products bearing the green leaf "Eco Choice" badge meet at least one of: made from
recycled materials, certified by Korea Eco-Label (환경부 인증), carbon-neutral shipping,
or biodegradable packaging. Filter by "Eco Choice" in any product category to browse.
Eco Choice status is reviewed annually and may be revoked if the product no longer meets criteria.

### How does the Green Packaging option work?

Select "Green Packaging" at checkout to receive your order in minimal, fully recyclable
packaging with no plastic fillers. Green Packaging is free and reduces box size by up to
40%. Each order using Green Packaging earns a 200-point eco bonus credited 7 days after
delivery confirmation.

### What is the Carbon Points program?

Every completed order earns 1 Carbon Point per 1,000 won spent. Carbon Points accumulate
in your account and can be donated to verified reforestation projects (1 Carbon Point =
1 tree planted) or converted to 100 loyalty points each. Carbon Points do not expire
and are separate from loyalty points.

### How does the electronics take-back program work?

Bring used electronics to any CU convenience store collection point. You receive 2,000
loyalty points per item dropped off. For large items (TVs, appliances), free pickup can
be scheduled through "Help Center > Electronics Recycling". Items are recycled through
Korea's certified e-waste partners.

### What eco-friendly packaging materials does Cholog use?

Standard boxes are made from 80%+ recycled cardboard. Air pillows use plant-based
biodegradable film. Tape is paper-based. The Green Packaging option eliminates all
non-essential filler materials. Cholog aims to achieve 100% plastic-free packaging
by end of 2026.
29 changes: 29 additions & 0 deletions src/main/resources/data/layer1_faq/feedback.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Complaints & Feedback

## Cholog Corporation — Official FAQ

### How do I file a complaint?

Go to "Help Center > Submit Feedback" on our website or app. Select the category (product
quality, delivery issue, website bug, suggestion, etc.) and describe your experience.
Complaints receive an acknowledgment email within 2 hours and a full response from our
customer experience team within 48 hours.

### Can I leave a product review?

Yes. Only customers who have purchased and received the product can leave a review —
labeled "Verified Purchase". Photo and video reviews earn 500 bonus points. Reviews that
violate community guidelines (spam, offensive content) are removed by our moderation team.

### How do I report a counterfeit or unsafe product?

Tap "Report" on the product page and select "Counterfeit Suspected" or "Safety Concern".
Our quality assurance team investigates within 48 hours. If confirmed, the product is
removed, the seller is penalized, and all affected buyers receive a full refund plus a
10,000 won inconvenience coupon.

### What is the Cholog Community Forum?

The Community Forum at community.cholog.kr is a space for customers to ask questions,
share tips, and discuss products. Staff moderators answer questions tagged "@staff".
Active contributors earn Community Points exchangeable for coupons. Available in Korean only.
26 changes: 26 additions & 0 deletions src/main/resources/data/layer1_faq/invoice.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Tax Invoice & Receipts

## Cholog Corporation — Official FAQ

### How do I get a tax invoice (세금계산서)?

A digital receipt is automatically emailed after every purchase. For a formal tax invoice,
go to "My Orders", select the order, and tap "Request Tax Invoice". Enter your business
registration number (사업자등록번호). Tax invoices are issued within 1 business day and
sent to your registered email address.

Tax invoice requests must be made within the same calendar month as the purchase.
Requests for prior months are not accepted.

### Can I get a receipt for a corporate expense report?

Yes. The automatically issued digital receipt serves as a valid purchase receipt.
For businesses requiring a tax invoice with VAT breakdown, follow the tax invoice
request process above. Business accounts registered at b2b.cholog.kr can request
monthly consolidated invoices covering all orders in the billing period.

### What if I entered the wrong business registration number?

Contact customer support within 1 business day of the original request. We can void
and reissue a tax invoice with the correct number within the same calendar month.
After the month closes, corrections are not possible under Korean tax law.
32 changes: 32 additions & 0 deletions src/main/resources/data/layer1_faq/marketplace.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Cholog Marketplace

## Cholog Corporation — Official FAQ

### What is Cholog Marketplace?

Cholog Marketplace is our platform for verified third-party sellers. Marketplace products
are clearly labeled with the seller's name on the product page and order confirmation.
Cholog guarantees buyer protection on all Marketplace transactions up to 500,000 won.
Beyond that amount, disputes are handled directly between buyer and seller.

### Does the standard Cholog return policy apply to Marketplace items?

No. Marketplace items follow the individual seller's return policy, which may differ
significantly from Cholog's standard 14-day window. Return windows for Marketplace
sellers range from 3 to 30 days depending on the seller. Always check the seller's
policy on the product page before purchasing. Cholog's buyer protection guarantee
covers cases of item not received or item significantly not as described.

### How do I become a Marketplace seller?

Apply at seller.cholog.kr with your business registration certificate, product catalog,
and bank account details. Review takes approximately 5 business days. Approved sellers
pay a commission of 5–12% per transaction depending on the product category. Sellers
must maintain a customer satisfaction rating above 4.2 / 5.0 to remain listed.

### What if I have a dispute with a Marketplace seller?

Contact the seller directly first through the in-app messaging feature ("My Orders >
Contact Seller"). If unresolved within 3 business days, you can escalate to Cholog
Buyer Protection by selecting "Open Dispute" in "My Orders". Cholog mediates and may
issue a full refund under the buyer protection guarantee within 5 business days.
49 changes: 49 additions & 0 deletions src/main/resources/data/layer1_faq/orders.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Orders & Order Management

## Cholog Corporation — Official FAQ

### How do I cancel an order?

You can cancel an order by going to "My Orders" and tapping "Cancel Order" while the status
is "Preparing". Cancellation is instant and the full amount is refunded to your original
payment method. Once the status changes to "Shipped", cancellation is no longer possible —
you must wait for delivery and then initiate a return.

Note: Marketplace seller orders may have a shorter cancellation window. Check the seller's
policy on the product page before placing the order.

### Can I modify my order after placing it?

You can change the delivery address only if the order status is still "Preparing". Go to
"My Orders", tap the order, and select "Edit Address". Quantity changes and product swaps
are not supported after checkout — cancel the order and place a new one instead.

### How do I track my order?

After dispatch, you receive a Hanjin Express tracking number via email and KakaoTalk.
Use the "Track Shipment" feature in the Cholog app or enter the number at hanjin.kr.
Real-time GPS tracking is available for Priority shipments only.

### What is the cutoff time for same-day dispatch?

Orders confirmed before 1 PM KST on business days are handed to the courier the same
afternoon. Orders placed after 1 PM, on weekends, or on public holidays enter the dispatch
queue for the next business day morning.

### Can I combine multiple orders into one shipment?

Orders placed within 30 minutes of each other and sharing the same delivery address may be
combined automatically. To request manual consolidation, contact customer support before
the first order enters "Shipped" status. Consolidation is not available for Priority or
same-day shipments.

### What happens if my package is lost or damaged in transit?

Go to "My Orders", select the affected order, and tap "Report Issue". Upload photos of
the damage or describe the missing items. Our logistics team investigates within 2 business
days and offers a replacement shipment or full refund.

### Can I schedule delivery for a future date?

Yes. At checkout, select "Scheduled Delivery" and choose a date up to 14 days in advance.
Available for Economy and Priority shipping tiers. Same-day delivery cannot be pre-scheduled.
31 changes: 31 additions & 0 deletions src/main/resources/data/layer1_faq/packaging.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Special Packaging & Delivery Types

## Cholog Corporation — Official FAQ

### Do you ship fresh or frozen products?

Yes. Fresh and frozen items are shipped in insulated packaging with ice packs via CJ Logistics
Fresh (dedicated cold-chain courier). Cold-chain delivery is available only Monday through
Thursday to prevent weekend transit degradation. A flat cold-chain fee of 4,000 won applies
regardless of order size. Cold-chain orders cannot be combined with standard shipments.

### How are large or heavy items delivered?

Items over 20 kg or classified as "Large Item" are delivered by a Lotte Global Logistics
two-person team. Delivery includes placement in the room of your choice (ground floor).
Buildings with restricted elevator access or stair-carry requirements incur an additional
fee of 15,000 won per floor. Schedule large-item delivery at checkout or by contacting
customer support.

### What is the Green Packaging option?

Select "Green Packaging" at checkout to receive your order in minimal, fully recyclable
packaging with no plastic fillers. Green Packaging is free of charge and reduces box size
by up to 40%, lowering carbon emissions. Each Green Packaging order earns a 200-point
eco bonus credited 7 days after delivery.

### Is gift wrapping available?

Yes. Select "Gift Wrap" at checkout for 1,500 won per item. Includes a branded box,
ribbon, and a personalized message card (up to 100 characters). Gift wrapping is not
available for oversized items or Marketplace seller products.
Loading