Skip to content

ins-guideon/guideon

Repository files navigation

๐Ÿ“˜ ๊ทœ์ • Q&A ์‹œ์Šคํ…œ (Guideon)

AI ๊ธฐ๋ฐ˜ ๊ทœ์ • ๊ฒ€์ƒ‰ ์‹œ์Šคํ…œ์ž…๋‹ˆ๋‹ค.

๐ŸŽฏ ์ฃผ์š” ๊ธฐ๋Šฅ

1. ์ž์—ฐ์–ด ์งˆ๋ฌธ ๋ถ„์„ (Query Analysis)

  • AI ๊ธฐ๋ฐ˜ ์งˆ๋ฌธ ๋ถ„์„: Google Gemini๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž์˜ ์ž์—ฐ์–ด ์งˆ๋ฌธ์„ ๊ตฌ์กฐํ™”
  • ํ‚ค์›Œ๋“œ ์ถ”์ถœ: ์งˆ๋ฌธ์—์„œ ํ•ต์‹ฌ ํ‚ค์›Œ๋“œ ์ž๋™ ์ถ”์ถœ
  • ๊ทœ์ • ์œ ํ˜• ๋งค์นญ: 27๊ฐœ ์‚ฌ๊ทœ ์œ ํ˜• ์ค‘ ๊ด€๋ จ ๊ทœ์ • ์ž๋™ ์‹๋ณ„
  • ์งˆ๋ฌธ ์˜๋„ ํŒŒ์•…: ์ •๋ณด์กฐํšŒ/์ ˆ์ฐจ์•ˆ๋‚ด/๊ธฐ์ค€ํ™•์ธ/์ž๊ฒฉ์š”๊ฑด/์˜ˆ์™ธ์‚ฌํ•ญ ๋ถ„๋ฅ˜
  • ๊ฒ€์ƒ‰ ์ฟผ๋ฆฌ ์ตœ์ ํ™”: ๋ฒกํ„ฐ ๊ฒ€์ƒ‰์— ์ตœ์ ํ™”๋œ ์ฟผ๋ฆฌ๋กœ ๋ณ€ํ™˜

2. RAG ๊ธฐ๋ฐ˜ ๊ทœ์ • ๊ฒ€์ƒ‰

  • ๋ฒกํ„ฐ ๊ฒ€์ƒ‰: ์ž„๋ฒ ๋”ฉ ๊ธฐ๋ฐ˜ ์˜๋ฏธ ๊ฒ€์ƒ‰์œผ๋กœ ๊ด€๋ จ ๊ทœ์ • ์กฐํ•ญ ํƒ์ƒ‰
  • ReRanking: Cohere ๋ชจ๋ธ์„ ํ†ตํ•œ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์ •๊ตํ™”
  • ๋‹ต๋ณ€ ์ƒ์„ฑ: ๊ฒ€์ƒ‰๋œ ๊ทœ์ •์„ ๊ทผ๊ฑฐ๋กœ LLM์ด ์ •ํ™•ํ•œ ๋‹ต๋ณ€ ์ƒ์„ฑ
  • ์ถœ์ฒ˜ ํ‘œ์‹œ: ๋‹ต๋ณ€์˜ ๊ทผ๊ฑฐ๊ฐ€ ๋˜๋Š” ๊ทœ์ •๋ช…, ์กฐํ•ญ, ๊ด€๋ จ๋„ ์ ์ˆ˜ ์ œ๊ณต
  • ์‹ ๋ขฐ๋„ ํ‰๊ฐ€: ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ์˜ ์‹ ๋ขฐ๋„ ์ ์ˆ˜ ๊ณ„์‚ฐ

3. ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ๊ฒ€์ƒ‰ (Hybrid Search)

  • Vector Search (์˜๋ฏธ ๊ฒ€์ƒ‰): Google Gemini Embedding์œผ๋กœ ์˜๋ฏธ์  ์œ ์‚ฌ์„ฑ ํŒŒ์•…
  • BM25 Search (ํ‚ค์›Œ๋“œ ๊ฒ€์ƒ‰): Apache Lucene ๊ธฐ๋ฐ˜ ์ •ํ™•ํ•œ ํ‚ค์›Œ๋“œ ๋งค์นญ
  • Reciprocal Rank Fusion (RRF): ๋‘ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๋ฅผ ์ง€๋Šฅ์ ์œผ๋กœ ํ†ตํ•ฉ
  • ํ•œ๊ตญ์–ด ์ตœ์ ํ™”: Nori ํ˜•ํƒœ์†Œ ๋ถ„์„๊ธฐ๋กœ ํ•œ๊ตญ์–ด ๊ฒ€์ƒ‰ ํ’ˆ์งˆ ํ–ฅ์ƒ
  • ์ •ํ™•๋„ ๊ฐœ์„ : ์˜๋ฏธ์  ๊ฒ€์ƒ‰๊ณผ ํ‚ค์›Œ๋“œ ๊ฒ€์ƒ‰์˜ ์žฅ์ ์„ ๊ฒฐํ•ฉํ•˜์—ฌ 20-30% ์ •ํ™•๋„ ํ–ฅ์ƒ

๐Ÿ— ์•„ํ‚คํ…์ฒ˜

์‚ฌ์šฉ์ž ์งˆ๋ฌธ (์ž์—ฐ์–ด)
    โ†“
QueryAnalysisService (Gemini API)
    โ†“
๊ตฌ์กฐํ™”๋œ ๋ถ„์„ ๊ฒฐ๊ณผ
    - ํ‚ค์›Œ๋“œ
    - ๊ทœ์ • ์œ ํ˜•
    - ์งˆ๋ฌธ ์˜๋„
    - ๊ฒ€์ƒ‰ ์ฟผ๋ฆฌ
    โ†“
RegulationSearchService (RAG + Hybrid Search)
    โ†“
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Vector Search     โ”‚  BM25 Search        โ”‚
โ”‚  (์˜๋ฏธ์  ๊ฒ€์ƒ‰)      โ”‚  (ํ‚ค์›Œ๋“œ ๊ฒ€์ƒ‰)       โ”‚
โ”‚  - Gemini Embed    โ”‚  - Apache Lucene    โ”‚
โ”‚  - Cosine Sim.     โ”‚  - Nori Analyzer    โ”‚
โ”‚  โ†’ 20 candidates   โ”‚  โ†’ 20 candidates    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
    โ†“
Reciprocal Rank Fusion (RRF)
    - ๋‘ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ํ†ตํ•ฉ
    - ์ค‘๋ณต ์ œ๊ฑฐ ๋ฐ ์ ์ˆ˜ ๊ณ„์‚ฐ
    โ†’ 40 unique candidates
    โ†“
ReRanking (Cohere)
    - ์ •๊ตํ•œ ๊ด€๋ จ์„ฑ ์žฌํ‰๊ฐ€
    โ†’ Top 5 results
    โ†“
๋‹ต๋ณ€ ์ƒ์„ฑ (Gemini API)
    โ†“
๊ฒฐ๊ณผ ๋ฐ˜ํ™˜ (๋‹ต๋ณ€ + ๊ทผ๊ฑฐ ์กฐํ•ญ + ์‹ ๋ขฐ๋„)

๐Ÿ“ฆ ๊ธฐ์ˆ  ์Šคํƒ

Backend

  • Java 21+
  • Spring Boot 3.2: REST API ์„œ๋ฒ„
  • LangChain4j 0.36.2: LLM ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ๋ฐ RAG ๊ตฌํ˜„
  • Google Gemini API:
    • gemini-2.5-flash: ์งˆ๋ฌธ ๋ถ„์„ ๋ฐ ๋‹ต๋ณ€ ์ƒ์„ฑ
    • text-embedding-004: ๋ฒกํ„ฐ ์ž„๋ฒ ๋”ฉ (768-dim, ํ•œ๊ตญ์–ด ์ง€์›)
  • Cohere API:
    • rerank-multilingual-v3.0: ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์žฌ์ •๋ ฌ (ํ•œ๊ตญ์–ด ์ตœ์ ํ™”)
  • Apache Lucene 9.11.1: BM25 ํ‚ค์›Œ๋“œ ๊ฒ€์ƒ‰ ์—”์ง„
    • Nori Korean Analyzer: ํ•œ๊ตญ์–ด ํ˜•ํƒœ์†Œ ๋ถ„์„
  • Vector Store: In-Memory (๊ฐœ๋ฐœ์šฉ, ์šด์˜์‹œ Qdrant ๊ถŒ์žฅ)
  • Maven: ๋นŒ๋“œ ๋„๊ตฌ

๐Ÿš€ ์‹œ์ž‘ํ•˜๊ธฐ

์‚ฌ์ „ ์š”๊ตฌ์‚ฌํ•ญ

1. ํ™˜๊ฒฝ ์„ค์ •

Google Gemini API ํ‚ค ์„ค์ •

๋ฐฉ๋ฒ• 1: ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ • (๊ถŒ์žฅ)

# Windows (PowerShell)
$env:GOOGLE_API_KEY="your_api_key_here"

# Windows (CMD)
set GOOGLE_API_KEY=your_api_key_here

# Linux/Mac
export GOOGLE_API_KEY=your_api_key_here

๋ฐฉ๋ฒ• 2: application.properties ํŒŒ์ผ ์ˆ˜์ •

src/main/resources/application.properties ํŒŒ์ผ์—์„œ API ํ‚ค ์ง์ ‘ ์ž…๋ ฅ:

gemini.api.key=your_actual_api_key_here

โš ๏ธ ๋ณด์•ˆ ์ฃผ์˜: API ํ‚ค๋ฅผ ์ฝ”๋“œ์— ํฌํ•จํ•˜์—ฌ Git์— ์ปค๋ฐ‹ํ•˜์ง€ ๋งˆ์„ธ์š”!

2. ์˜์กด์„ฑ ์„ค์น˜ ๋ฐ ๋นŒ๋“œ

# Maven ์˜์กด์„ฑ ๋‹ค์šด๋กœ๋“œ ๋ฐ JAR ํŒŒ์ผ ๋นŒ๋“œ
mvn clean package -DskipTests

๋นŒ๋“œ๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด target/regulation-search-1.0.0.jar ํŒŒ์ผ์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

3. ์„œ๋น„์Šค ์‹คํ–‰

๐Ÿš€ ๋ฐฉ๋ฒ• 1: ํ’€์Šคํƒ ์‹คํ–‰ (๋ฐฑ์—”๋“œ + ํ”„๋ก ํŠธ์—”๋“œ) - ์ถ”์ฒœ!

# ๋ฐฑ์—”๋“œ(8080)์™€ ํ”„๋ก ํŠธ์—”๋“œ(3000)๋ฅผ ๋™์‹œ์— ์‹คํ–‰
start-all.bat

์ด ๋ช…๋ น์–ด๋Š”:

  • โœ… ๋ฐฑ์—”๋“œ ์„œ๋ฒ„: http://localhost:8080 (๋ณ„๋„ ์ฐฝ)
  • โœ… ํ”„๋ก ํŠธ์—”๋“œ: http://localhost:3000 (๋ณ„๋„ ์ฐฝ)

๋ธŒ๋ผ์šฐ์ €์—์„œ http://localhost:3000์œผ๋กœ ์ ‘์†ํ•˜๋ฉด ์ „์ฒด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!

๋ฐฉ๋ฒ• 2: ๋ฐฑ์—”๋“œ๋งŒ ์‹คํ–‰

# Spring Boot ์„œ๋ฒ„๋งŒ ์‹คํ–‰ (ํฌํŠธ 8080)
run-server.bat

# ๋˜๋Š” Maven ์ง์ ‘ ์‚ฌ์šฉ
mvn spring-boot:run

์„œ๋ฒ„๊ฐ€ ์‹œ์ž‘๋˜๋ฉด http://localhost:8080์—์„œ REST API๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐฉ๋ฒ• 3: ํ”„๋ก ํŠธ์—”๋“œ๋งŒ ์‹คํ–‰

# ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ ์„œ๋ฒ„๋งŒ ์‹คํ–‰ (ํฌํŠธ 3000)
cd guideon-frontend
start-frontend.bat

# ๋˜๋Š” npm ์ง์ ‘ ์‚ฌ์šฉ
npm run dev

โš ๏ธ ์ฃผ์˜: ํ”„๋ก ํŠธ์—”๋“œ๋งŒ ์‹คํ–‰ํ•˜๋Š” ๊ฒฝ์šฐ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„๊ฐ€ http://localhost:8080์—์„œ ์‹คํ–‰ ์ค‘์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ฐฉ๋ฒ• 4: JAR ํŒŒ์ผ ๋นŒ๋“œ ํ›„ ์‹คํ–‰ (ํ”„๋กœ๋•์…˜)

# 1. JAR ๋นŒ๋“œ
mvn clean package -DskipTests

# 2. ์‹คํ–‰
java -jar target/regulation-search-1.0.0.jar

๋ฐฉ๋ฒ• 5: IDE์—์„œ ์‹คํ–‰

  • Main Class: com.guideon.GuideonApplication
  • VM Options: -Dserver.port=8080

ํฌํŠธ ๋ณ€๊ฒฝ

๋‹ค๋ฅธ ํฌํŠธ์—์„œ ์‹คํ–‰ํ•˜๋ ค๋ฉด:

# ๋ฐฉ๋ฒ• 1: application.yml ์ˆ˜์ •
server:
  port: 9090

# ๋ฐฉ๋ฒ• 2: ํ™˜๊ฒฝ๋ณ€์ˆ˜
export SERVER_PORT=9090
mvn spring-boot:run

# ๋ฐฉ๋ฒ• 3: ์ปค๋งจ๋“œ ๋ผ์ธ ์˜ต์…˜
java -jar target/regulation-search-1.0.0.jar --server.port=9090

4. API ์—”๋“œํฌ์ธํŠธ ํ™•์ธ

์„œ๋ฒ„๊ฐ€ ์‹œ์ž‘๋˜๋ฉด ๋‹ค์Œ ์—”๋“œํฌ์ธํŠธ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

Health Check

curl http://localhost:8080/actuator/health

์งˆ๋ฌธ ๋ถ„์„

curl -X POST http://localhost:8080/api/qa/analyze \
  -H "Content-Type: application/json" \
  -d '{"question": "์—ฐ์ฐจ ํœด๊ฐ€๋Š” ๋ช‡ ์ผ์ธ๊ฐ€์š”?"}'

๊ทœ์ • ๊ฒ€์ƒ‰ (ํ†ตํ•ฉ)

curl -X POST http://localhost:8080/api/qa/search \
  -H "Content-Type: application/json" \
  -d '{"question": "ํ•ด์™ธ ์ถœ์žฅ์‹œ ์ˆ™๋ฐ•๋น„๋Š” ์–ผ๋งˆ๊นŒ์ง€ ์ง€์›๋˜๋‚˜์š”?"}'

๊ทœ์ • ์œ ํ˜• ๋ชฉ๋ก ์กฐํšŒ

curl http://localhost:8080/api/regulations/types

๊ทœ์ • ๋ฌธ์„œ ์—…๋กœ๋“œ

curl -X POST http://localhost:8080/api/regulations/upload \
  -H "Content-Type: application/json" \
  -d '{
    "filePath": "c:/workspace/regulations/์ทจ์—…๊ทœ์น™.txt",
    "regulationType": "์ทจ์—…๊ทœ์น™"
  }'

5. ์„œ๋ฒ„ ๋กœ๊ทธ ํ™•์ธ

์ •์ƒ ์‹œ์ž‘ ์‹œ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋กœ๊ทธ๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.2.0)

2025-10-17 ... : Starting GuideonApplication using Java 17...
2025-10-17 ... : ConfigLoader loaded from classpath: application.properties
2025-10-17 ... : QueryAnalysisService initialized with 27 regulation types
2025-10-17 ... : RegulationSearchService initialized
2025-10-17 ... : Tomcat started on port(s): 8080 (http)
2025-10-17 ... : Started GuideonApplication in 5.234 seconds

๋ฌธ์ œ ํ•ด๊ฒฐ

โš ๏ธ Maven ๋นŒ๋“œ ์‹คํŒจ: "invalid flag: --release"

์ด ์˜ค๋ฅ˜๋Š” Maven์ด Java 8์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์„ ๋•Œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•:

# 1. ํ˜„์žฌ Maven์ด ์‚ฌ์šฉํ•˜๋Š” Java ๋ฒ„์ „ ํ™•์ธ
mvn -version
# Java version์ด 1.8์ด๋ฉด ๋ฌธ์ œ!

# 2. JAVA_HOME์„ Java 17๋กœ ์„ค์ •
# Windows (PowerShell)
$env:JAVA_HOME="C:\Program Files\Java\jdk-17"
$env:PATH="C:\Program Files\Java\jdk-17\bin;$env:PATH"

# Windows (CMD)
set JAVA_HOME=C:\Program Files\Java\jdk-17
set PATH=C:\Program Files\Java\jdk-17\bin;%PATH%

# Linux/Mac
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk
export PATH=$JAVA_HOME/bin:$PATH

# 3. ๋‹ค์‹œ ๋นŒ๋“œ
mvn clean compile

ํŽธ๋ฆฌํ•œ ๋ฐฉ๋ฒ• (Windows):

์ œ๊ณต๋œ ๋ฐฐ์น˜ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š” (์ž๋™์œผ๋กœ Java 17 ์„ค์ •):

# ๋นŒ๋“œ
build.bat

# ์„œ๋ฒ„ ์‹คํ–‰
run-server.bat

Java ๋ฒ„์ „ ํ™•์ธ

java -version
# ์ถœ๋ ฅ: java version "17.0.x" ์ด์ƒ์ด์–ด์•ผ ํ•จ

mvn -version
# ์ค‘์š”: Java version๋„ 17์ด์–ด์•ผ ํ•จ!

Maven ๋ฒ„์ „ ํ™•์ธ

mvn -version
# ์ถœ๋ ฅ: Apache Maven 3.6.x ์ด์ƒ์ด์–ด์•ผ ํ•จ

API ํ‚ค ํ™•์ธ

# Windows (PowerShell)
echo $env:GOOGLE_API_KEY

# Windows (CMD)
echo %GOOGLE_API_KEY%

# Linux/Mac
echo $GOOGLE_API_KEY

์ผ๋ฐ˜์ ์ธ ์˜ค๋ฅ˜

  1. invalid flag: --release: Maven์ด Java 8 ์‚ฌ์šฉ โ†’ JAVA_HOME์„ Java 17๋กœ ๋ณ€๊ฒฝ
  2. GOOGLE_API_KEY not found: ํ™˜๊ฒฝ๋ณ€์ˆ˜๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜๊ฑฐ๋‚˜ application.yml์— API ํ‚ค๊ฐ€ ์—†์Œ
  3. ClassNotFoundException: Maven ๋นŒ๋“œ๋ฅผ ๋‹ค์‹œ ์‹คํ–‰ (mvn clean package)
  4. Port 8080 already in use: ๋‹ค๋ฅธ ํ”„๋กœ์„ธ์Šค๊ฐ€ ํฌํŠธ๋ฅผ ์‚ฌ์šฉ์ค‘ โ†’ ํฌํŠธ ๋ณ€๊ฒฝ ๋˜๋Š” ํ”„๋กœ์„ธ์Šค ์ข…๋ฃŒ

4. ์‚ฌ์šฉ ์˜ˆ์‹œ

// ์‹œ์Šคํ…œ ์ดˆ๊ธฐํ™”
String apiKey = System.getenv("GOOGLE_API_KEY");
RegulationQASystem system = new RegulationQASystem(apiKey);

// ๊ทœ์ • ๋ฌธ์„œ ์—…๋กœ๋“œ (์ธ๋ฑ์‹ฑ)
system.uploadRegulationDocument("path/to/์ทจ์—…๊ทœ์น™.txt", "์ทจ์—…๊ทœ์น™");
system.uploadRegulationDocument("path/to/๊ฒฝ๋น„์ง€๊ธ‰๊ทœ์ •.txt", "๊ฒฝ๋น„์ง€๊ธ‰๊ทœ์ •");

// ์ž์—ฐ์–ด ์งˆ๋ฌธ
String question = "ํ•ด์™ธ ์ถœ์žฅ์‹œ ์ˆ™๋ฐ•๋น„๋Š” ์–ผ๋งˆ๊นŒ์ง€ ์ง€์›๋˜๋‚˜์š”?";
RegulationSearchResult result = system.askQuestion(question);

// ๊ฒฐ๊ณผ ํ™•์ธ
System.out.println("๋‹ต๋ณ€: " + result.getAnswer());
System.out.println("์‹ ๋ขฐ๋„: " + result.getConfidenceScore());
result.getReferences().forEach(ref -> {
    System.out.println("๊ทผ๊ฑฐ: " + ref.getDocumentName() + " - " + ref.getContent());
});

๐Ÿ“ก REST API ๋ช…์„ธ

1. Q&A API

POST /api/qa/analyze - ์งˆ๋ฌธ ๋ถ„์„

์‚ฌ์šฉ์ž์˜ ์ž์—ฐ์–ด ์งˆ๋ฌธ์„ ๋ถ„์„ํ•ฉ๋‹ˆ๋‹ค.

Request:

{
  "question": "์—ฐ์ฐจ ํœด๊ฐ€๋Š” ๋ช‡ ์ผ์ธ๊ฐ€์š”?"
}

Response:

{
  "success": true,
  "message": "์งˆ๋ฌธ ๋ถ„์„์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค",
  "analysis": {
    "originalQuery": "์—ฐ์ฐจ ํœด๊ฐ€๋Š” ๋ช‡ ์ผ์ธ๊ฐ€์š”?",
    "keywords": ["์—ฐ์ฐจ", "ํœด๊ฐ€", "์ผ์ˆ˜"],
    "regulationTypes": ["์ทจ์—…๊ทœ์น™", "๋ณต๋ฆฌํ›„์ƒ๋น„๊ทœ์ •"],
    "intent": "๊ธฐ์ค€ํ™•์ธ",
    "searchQuery": "์—ฐ์ฐจ ํœด๊ฐ€ ์ผ์ˆ˜ ๊ธฐ์ค€"
  }
}

POST /api/qa/search - ๊ทœ์ • ๊ฒ€์ƒ‰

์งˆ๋ฌธ์„ ๋ถ„์„ํ•˜๊ณ  ๊ด€๋ จ ๊ทœ์ •์„ ๊ฒ€์ƒ‰ํ•˜์—ฌ ๋‹ต๋ณ€์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

Request:

{
  "question": "ํ•ด์™ธ ์ถœ์žฅ์‹œ ์ˆ™๋ฐ•๋น„๋Š” ์–ผ๋งˆ๊นŒ์ง€ ์ง€์›๋˜๋‚˜์š”?"
}

Response:

{
  "success": true,
  "message": "๊ฒ€์ƒ‰์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค",
  "result": {
    "answer": "ํ•ด์™ธ ์ถœ์žฅ์‹œ ์ˆ™๋ฐ•๋น„๋Š” ๊ตญ๊ฐ€๋ณ„๋กœ ์ฐจ๋“ฑ ์ง€์›๋ฉ๋‹ˆ๋‹ค...",
    "references": [
      {
        "documentName": "์ถœ์žฅ์—ฌ๋น„์ง€๊ธ‰๊ทœ์ •",
        "clause": "์ œ5์กฐ",
        "content": "ํ•ด์™ธ ์ถœ์žฅ ์ˆ™๋ฐ•๋น„๋Š”...",
        "pageNumber": 3,
        "relevanceScore": 0.89
      }
    ],
    "confidenceScore": 0.87,
    "hasAnswer": true
  }
}

2. ๊ทœ์ • ๊ด€๋ฆฌ API

GET /api/regulations/types - ๊ทœ์ • ์œ ํ˜• ๋ชฉ๋ก

์ง€์›ํ•˜๋Š” 27๊ฐœ ๊ทœ์ • ์œ ํ˜• ๋ชฉ๋ก์„ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค.

3. ๋ฌธ์„œ ์—…๋กœ๋“œ(ํ”„๋ฆฌ๋ทฐ/ํ™•์ •) API

2๋‹จ๊ณ„ ์—…๋กœ๋“œ ํ”Œ๋กœ์šฐ:

  1. ์—…๋กœ๋“œ ์งํ›„ ํ…์ŠคํŠธ๋งŒ ์ถ”์ถœํ•˜์—ฌ ์‚ฌ์šฉ์ž ๊ฒ€์ˆ˜
  2. ํ™•์ • ์‹œ์—๋งŒ ์ž„๋ฒ ๋”ฉ/์ธ๋ฑ์‹ฑ ๋ฐ ๋ฉ”ํƒ€ ์ €์žฅ
  • POST /api/documents/extract-text (multipart/form-data)

    • form: file, regulationType
    • ์‘๋‹ต: { "success": true, "data": { "uploadId": "uuid", "text": "..." } }
  • POST /api/documents/{uploadId}/confirm (application/json)

    • body: { "text": "ํ™•์ • ํ…์ŠคํŠธ" }
    • ์‘๋‹ต: ๊ธฐ์กด ์—…๋กœ๋“œ ์‘๋‹ต(DocumentUploadResponse)๊ณผ ๋™์ผ

Response:

{
  "success": true,
  "types": ["์ด์‚ฌํšŒ๊ทœ์ •", "์ ‘๋Œ€๋น„์‚ฌ์šฉ๊ทœ์ •", ...],
  "count": 27
}

POST /api/regulations/upload - ๊ทœ์ • ๋ฌธ์„œ ์—…๋กœ๋“œ

๊ทœ์ • ๋ฌธ์„œ๋ฅผ ์—…๋กœ๋“œํ•˜๊ณ  ๋ฒกํ„ฐ DB์— ์ธ๋ฑ์‹ฑํ•ฉ๋‹ˆ๋‹ค.

Request:

{
  "filePath": "c:/workspace/regulations/์ทจ์—…๊ทœ์น™.txt",
  "regulationType": "์ทจ์—…๊ทœ์น™"
}

Response:

{
  "success": true,
  "message": "๊ทœ์ • ๋ฌธ์„œ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์—…๋กœ๋“œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค",
  "regulationType": "์ทจ์—…๊ทœ์น™",
  "filePath": "c:/workspace/regulations/์ทจ์—…๊ทœ์น™.txt"
}

๐Ÿ“ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ

guideon/
โ”œโ”€โ”€ pom.xml                                    # Maven ์„ค์ • (Spring Boot)
โ”œโ”€โ”€ CLUADE.md                                  # ์‹œ์Šคํ…œ ์„ค๊ณ„ ๋ฌธ์„œ
โ”œโ”€โ”€ README.md                                  # ์ด ํŒŒ์ผ
โ””โ”€โ”€ src/main/
    โ”œโ”€โ”€ java/com/guideon/
    โ”‚   โ”œโ”€โ”€ GuideonApplication.java           # Spring Boot ๋ฉ”์ธ ํด๋ž˜์Šค
    โ”‚   โ”œโ”€โ”€ controller/                       # REST API Controllers
    โ”‚   โ”‚   โ”œโ”€โ”€ QAController.java             # Q&A API
    โ”‚   โ”‚   โ””โ”€โ”€ RegulationController.java     # ๊ทœ์ • ๊ด€๋ฆฌ API
    โ”‚   โ”œโ”€โ”€ service/                          # Business Logic
    โ”‚   โ”‚   โ”œโ”€โ”€ QueryAnalysisService.java     # ์งˆ๋ฌธ ๋ถ„์„ ์„œ๋น„์Šค
    โ”‚   โ”‚   โ””โ”€โ”€ RegulationSearchService.java  # RAG ๊ฒ€์ƒ‰ ์„œ๋น„์Šค
    โ”‚   โ”œโ”€โ”€ model/                            # Domain Models
    โ”‚   โ”‚   โ”œโ”€โ”€ QueryAnalysisResult.java
    โ”‚   โ”‚   โ”œโ”€โ”€ RegulationSearchResult.java
    โ”‚   โ”‚   โ””โ”€โ”€ RegulationReference.java
    โ”‚   โ”œโ”€โ”€ dto/                              # Data Transfer Objects
    โ”‚   โ”‚   โ”œโ”€โ”€ QuestionRequest.java
    โ”‚   โ”‚   โ”œโ”€โ”€ AnalysisResponse.java
    โ”‚   โ”‚   โ”œโ”€โ”€ SearchResponse.java
    โ”‚   โ”‚   โ””โ”€โ”€ UploadRequest.java
    โ”‚   โ”œโ”€โ”€ config/                           # Configuration
    โ”‚   โ”‚   โ”œโ”€โ”€ GuideonConfig.java            # Service Beans
    โ”‚   โ”‚   โ”œโ”€โ”€ WebConfig.java                # CORS ์„ค์ •
    โ”‚   โ”‚   โ””โ”€โ”€ ConfigLoader.java             # Properties Loader
    โ”‚   โ””โ”€โ”€ exception/                        # Exception Handling
    โ”‚       โ””โ”€โ”€ GlobalExceptionHandler.java
    โ””โ”€โ”€ resources/
        โ”œโ”€โ”€ application.yml                   # Spring Boot ์„ค์ •
        โ””โ”€โ”€ application.properties            # Legacy ์„ค์ •

๐Ÿ”‘ ํ•ต์‹ฌ ํด๋ž˜์Šค

QueryAnalysisService

์ž์—ฐ์–ด ์งˆ๋ฌธ์„ AI๋กœ ๋ถ„์„ํ•˜์—ฌ ๊ตฌ์กฐํ™”๋œ ๊ฒ€์ƒ‰ ์ฟผ๋ฆฌ๋กœ ๋ณ€ํ™˜

์ฃผ์š” ๋ฉ”์„œ๋“œ:

  • analyzeQuery(String userQuery): ์งˆ๋ฌธ ๋ถ„์„ ๋ฐ ํ‚ค์›Œ๋“œ ์ถ”์ถœ

๋ถ„์„ ๊ฒฐ๊ณผ:

  • ํ‚ค์›Œ๋“œ ๋ชฉ๋ก
  • ๊ด€๋ จ ๊ทœ์ • ์œ ํ˜•
  • ์งˆ๋ฌธ ์˜๋„
  • ์ตœ์ ํ™”๋œ ๊ฒ€์ƒ‰ ์ฟผ๋ฆฌ

RegulationSearchService

RAG ๊ธฐ๋ฐ˜ ๋ฒกํ„ฐ ๊ฒ€์ƒ‰ ๋ฐ ๋‹ต๋ณ€ ์ƒ์„ฑ

์ฃผ์š” ๋ฉ”์„œ๋“œ:

  • indexDocument(Document doc, String type): ๊ทœ์ • ๋ฌธ์„œ ์ธ๋ฑ์‹ฑ
  • search(QueryAnalysisResult analysis): ๊ทœ์ • ๊ฒ€์ƒ‰ ๋ฐ ๋‹ต๋ณ€ ์ƒ์„ฑ

๊ฒ€์ƒ‰ ๊ณผ์ •:

  1. ๋ฒกํ„ฐ ์ž„๋ฒ ๋”ฉ ์ƒ์„ฑ
  2. ์œ ์‚ฌ๋„ ๊ธฐ๋ฐ˜ ๊ด€๋ จ ์กฐํ•ญ ๊ฒ€์ƒ‰
  3. ๊ฒ€์ƒ‰๋œ ์กฐํ•ญ์„ ์ปจํ…์ŠคํŠธ๋กœ LLM ๋‹ต๋ณ€ ์ƒ์„ฑ
  4. ์‹ ๋ขฐ๋„ ์ ์ˆ˜ ๊ณ„์‚ฐ

๐ŸŽจ ์ง€์›ํ•˜๋Š” ๊ทœ์ • ์œ ํ˜• (27์ข…)

์ด์‚ฌํšŒ๊ทœ์ •, ์ ‘๋Œ€๋น„์‚ฌ์šฉ๊ทœ์ •, ์œค๋ฆฌ๊ทœ์ •, ์ถœ์žฅ์—ฌ๋น„์ง€๊ธ‰๊ทœ์ •, ์ฃผ์‹๋งค์ˆ˜์„ ํƒ๊ถŒ์šด์˜๊ทœ์ •, ๋…ธ์‚ฌํ˜‘์˜ํšŒ๊ทœ์ •, ์ทจ์—…๊ทœ์น™, ๋งค์ถœ์ฑ„๊ถŒ๊ด€๋ฆฌ๊ทœ์ •, ๊ธˆ์œต์ž์‚ฐ ์šด์šฉ๊ทœ์ •, ๋ฌธ์„œ๊ด€๋ฆฌ๊ทœ์ •, ์žฌ๊ณ ๊ด€๋ฆฌ๊ทœ์ •, ๊ณ„์•ฝ๊ฒ€ํ† ๊ทœ์ •, ์‚ฌ๊ทœ๊ด€๋ฆฌ๊ทœ์ •, ์ž„์›ํ‡ด์ง๊ธˆ์ง€๊ธ‰๊ทœ์ •, ์ž„์›๋ณด์ˆ˜๊ทœ์ •, ์ฃผ์ฃผ์ดํšŒ์šด์˜๊ทœ์ •, ๊ฒฝ๋น„์ง€๊ธ‰๊ทœ์ •, ๋ณต๋ฆฌํ›„์ƒ๋น„๊ทœ์ •, ๋ณด์•ˆ๊ด€๋ฆฌ๊ทœ์ •, ์œ„์ž„์ „๊ฒฐ๊ทœ์ •, ์šฐ๋ฆฌ์‚ฌ์ฃผ์šด์˜๊ทœ์ •, ๋‚ด๋ถ€์ •๋ณด๊ด€๋ฆฌ๊ทœ์ •, ํšŒ๊ณ„๊ด€๋ฆฌ๊ทœ์ •, ํŠน์ˆ˜๊ด€๊ณ„์ž ๊ฑฐ๋ž˜๊ทœ์ •, ์กฐ์ง ๋ฐ ์—…๋ฌด๋ถ„์žฅ๊ทœ์ •, ์ž๊ธˆ๊ด€๋ฆฌ๊ทœ์ •, ์ธ์žฅ๊ด€๋ฆฌ๊ทœ์ •

๐Ÿ”„ ์›Œํฌํ”Œ๋กœ์šฐ ์˜ˆ์‹œ

์ž…๋ ฅ: "์—ฐ์ฐจ ํœด๊ฐ€๋Š” ๋ช‡ ์ผ์ธ๊ฐ€์š”?"

[QueryAnalysisService ๋ถ„์„]
โ†’ ํ‚ค์›Œ๋“œ: [์—ฐ์ฐจ, ํœด๊ฐ€, ์ผ์ˆ˜]
โ†’ ๊ทœ์ • ์œ ํ˜•: [์ทจ์—…๊ทœ์น™, ๋ณต๋ฆฌํ›„์ƒ๋น„๊ทœ์ •]
โ†’ ์งˆ๋ฌธ ์˜๋„: ๊ธฐ์ค€ํ™•์ธ
โ†’ ๊ฒ€์ƒ‰ ์ฟผ๋ฆฌ: "์—ฐ์ฐจ ํœด๊ฐ€ ์ผ์ˆ˜ ๊ธฐ์ค€"

[RegulationSearchService ๊ฒ€์ƒ‰]
โ†’ ๋ฒกํ„ฐ ๊ฒ€์ƒ‰: ๊ด€๋ จ ์กฐํ•ญ 5๊ฐœ ๋ฐœ๊ฒฌ
โ†’ ์ปจํ…์ŠคํŠธ: "์ทจ์—…๊ทœ์น™ ์ œXX์กฐ ์—ฐ์ฐจํœด๊ฐ€๋Š”..."
โ†’ AI ๋‹ต๋ณ€ ์ƒ์„ฑ: "์—ฐ์ฐจ ํœด๊ฐ€๋Š” ๊ทผ์†๋…„์ˆ˜์— ๋”ฐ๋ผ..."

[๊ฒฐ๊ณผ ๋ฐ˜ํ™˜]
โ†’ ๋‹ต๋ณ€: "์—ฐ์ฐจ ํœด๊ฐ€๋Š” 1๋…„ ๊ทผ๋ฌด์‹œ 15์ผ์ด ๋ถ€์—ฌ๋ฉ๋‹ˆ๋‹ค..."
โ†’ ๊ทผ๊ฑฐ: ์ทจ์—…๊ทœ์น™ ์ œ32์กฐ (๊ด€๋ จ๋„: 0.89)
โ†’ ์‹ ๋ขฐ๋„: 0.87

โš ๏ธ ์ฃผ์˜์‚ฌํ•ญ

  1. API ํ‚ค ๋ณด์•ˆ: GOOGLE_API_KEY๋ฅผ ์ฝ”๋“œ์— ํ•˜๋“œ์ฝ”๋”ฉํ•˜์ง€ ๋งˆ์„ธ์š”
  2. ์ธ๋ฑ์‹ฑ ํ•„์ˆ˜: ์งˆ๋ฌธํ•˜๊ธฐ ์ „์— ๋ฐ˜๋“œ์‹œ ๊ทœ์ • ๋ฌธ์„œ๋ฅผ ์ธ๋ฑ์‹ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค
  3. ๊ฐœ๋ฐœ ํ™˜๊ฒฝ: ํ˜„์žฌ In-Memory ์ €์žฅ์†Œ ์‚ฌ์šฉ์ค‘ (์žฌ์‹œ์ž‘์‹œ ๋ฐ์ดํ„ฐ ์†Œ์‹ค)
  4. ์šด์˜ ํ™˜๊ฒฝ: Qdrant ๋“ฑ ์˜๊ตฌ ๋ฒกํ„ฐ DB๋กœ ๊ต์ฒด ๊ถŒ์žฅ

๐ŸŽจ React ๊ธฐ๋ฐ˜ UI ๊ฐœ๋ฐœ

ํ™”๋ฉด ๋ชฉ๋ก

1. ๋กœ๊ทธ์ธ ํ™”๋ฉด (/login)

  • ์‚ฌ์šฉ์ž ์ธ์ฆ
  • ์„ธ์…˜ ๊ด€๋ฆฌ
  • ์ž๋™ ๋กœ๊ทธ์ธ ์˜ต์…˜

2. ๋ฉ”์ธ ๋Œ€์‹œ๋ณด๋“œ (/)

  • ์งˆ๋ฌธ ์ž…๋ ฅ ์ธํ„ฐํŽ˜์ด์Šค
  • ์ตœ๊ทผ ์งˆ๋ฌธ ์ด๋ ฅ
  • ์ฆ๊ฒจ์ฐพ๊ธฐ ๊ทœ์ • ๋ชฉ๋ก
  • ํ†ต๊ณ„ ๋Œ€์‹œ๋ณด๋“œ (์งˆ๋ฌธ ์ˆ˜, ๊ทœ์ • ํ™œ์šฉ๋„)

3. ์งˆ๋ฌธ & ๋‹ต๋ณ€ ํ™”๋ฉด (/qa)

  • ์ž์—ฐ์–ด ์งˆ๋ฌธ ์ž…๋ ฅ ํผ
  • ์‹ค์‹œ๊ฐ„ ์งˆ๋ฌธ ๋ถ„์„ ํ‘œ์‹œ
    • ์ถ”์ถœ๋œ ํ‚ค์›Œ๋“œ
    • ๊ด€๋ จ ๊ทœ์ • ์œ ํ˜•
    • ์งˆ๋ฌธ ์˜๋„
  • AI ๋‹ต๋ณ€ ํ‘œ์‹œ
    • ๋‹ต๋ณ€ ๋‚ด์šฉ
    • ์‹ ๋ขฐ๋„ ์ ์ˆ˜
    • ๊ทผ๊ฑฐ ๊ทœ์ • ์กฐํ•ญ ๋ชฉ๋ก
  • ๋‹ต๋ณ€ ํ‰๊ฐ€ (๋„์›€๋จ/๋„์›€์•ˆ๋จ)
  • ๋‹ต๋ณ€ ๊ณต์œ  ๊ธฐ๋Šฅ

4. ๊ทœ์ • ๊ด€๋ฆฌ ํ™”๋ฉด (/regulations)

  • ๊ทœ์ • ๋ฌธ์„œ ๋ชฉ๋ก (27๊ฐœ ์œ ํ˜•๋ณ„ ๋ถ„๋ฅ˜)
  • ๊ทœ์ • ๋ฌธ์„œ ์—…๋กœ๋“œ ์ธํ„ฐํŽ˜์ด์Šค
  • ๊ทœ์ • ๋ฌธ์„œ ๋ฏธ๋ฆฌ๋ณด๊ธฐ
  • ๋ฌธ์„œ ๋ฒ„์ „ ๊ด€๋ฆฌ
  • ์ธ๋ฑ์‹ฑ ์ƒํƒœ ํ‘œ์‹œ

5. ๊ฒ€์ƒ‰ ์ด๋ ฅ ํ™”๋ฉด (/history)

  • ๊ณผ๊ฑฐ ์งˆ๋ฌธ ๋ชฉ๋ก
  • ์งˆ๋ฌธ๋ณ„ ๋‹ต๋ณ€ ์กฐํšŒ
  • ํ•„ํ„ฐ๋ง (๋‚ ์งœ, ๊ทœ์ • ์œ ํ˜•, ์‹ ๋ขฐ๋„)
  • ์ฆ๊ฒจ์ฐพ๊ธฐ ์ถ”๊ฐ€/์ œ๊ฑฐ

6. ํ†ต๊ณ„ ๋ฐ ๋ถ„์„ ํ™”๋ฉด (/analytics)

  • ์งˆ๋ฌธ ํ†ต๊ณ„ (์ผ๋ณ„/์ฃผ๋ณ„/์›”๋ณ„)
  • ๊ทœ์ •๋ณ„ ํ™œ์šฉ๋„
  • ์‹ ๋ขฐ๋„ ๋ถ„ํฌ
  • ์ธ๊ธฐ ํ‚ค์›Œ๋“œ
  • ๋‹ต๋ณ€ ๋งŒ์กฑ๋„ ํ†ต๊ณ„

7. ์„ค์ • ํ™”๋ฉด (/settings)

  • API ํ‚ค ๊ด€๋ฆฌ
  • ๋ชจ๋ธ ์„ค์ • (Gemini Flash/Pro ์„ ํƒ)
  • ๊ฒ€์ƒ‰ ์˜ต์…˜ (์ตœ๋Œ€ ๊ฒฐ๊ณผ ์ˆ˜, ์ตœ์†Œ ์‹ ๋ขฐ๋„)
  • ์•Œ๋ฆผ ์„ค์ •

๊ธฐ์ˆ  ์Šคํƒ

Frontend

  • React 18+: UI ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • TypeScript: ํƒ€์ž… ์•ˆ์ •์„ฑ
  • React Router v6: SPA ๋ผ์šฐํŒ…
  • Vite: ๋นŒ๋“œ ๋„๊ตฌ (๋น ๋ฅธ ๊ฐœ๋ฐœ ์„œ๋ฒ„)
  • TanStack Query (React Query): ์„œ๋ฒ„ ์ƒํƒœ ๊ด€๋ฆฌ
  • Zustand: ํด๋ผ์ด์–ธํŠธ ์ƒํƒœ ๊ด€๋ฆฌ (๊ฒฝ๋Ÿ‰)
  • Axios: HTTP ํด๋ผ์ด์–ธํŠธ

UI ์ปดํฌ๋„ŒํŠธ

  • Ant Design ๋˜๋Š” Material-UI (MUI): UI ์ปดํฌ๋„ŒํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • Tailwind CSS: ์œ ํ‹ธ๋ฆฌํ‹ฐ CSS ํ”„๋ ˆ์ž„์›Œํฌ
  • React Markdown: ๋‹ต๋ณ€ ๋ Œ๋”๋ง
  • React Syntax Highlighter: ์ฝ”๋“œ ํ•˜์ด๋ผ์ดํŒ…
  • Recharts: ํ†ต๊ณ„ ์ฐจํŠธ

๊ฐœ๋ฐœ ๋„๊ตฌ

  • ESLint: ์ฝ”๋“œ ๋ฆฐํŒ…
  • Prettier: ์ฝ”๋“œ ํฌ๋งทํŒ…
  • Vitest: ๋‹จ์œ„ ํ…Œ์ŠคํŠธ
  • React Testing Library: ์ปดํฌ๋„ŒํŠธ ํ…Œ์ŠคํŠธ

Backend ์—ฐ๋™

  • REST API: Spring Boot ๋ฐฑ์—”๋“œ ์—ฐ๋™
  • WebSocket (์„ ํƒ): ์‹ค์‹œ๊ฐ„ ๋ถ„์„ ๊ฒฐ๊ณผ ์ŠคํŠธ๋ฆฌ๋ฐ

ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ

guideon-frontend/
โ”œโ”€โ”€ public/
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ assets/              # ์ด๋ฏธ์ง€, ํฐํŠธ ๋“ฑ
โ”‚   โ”œโ”€โ”€ components/          # ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ปดํฌ๋„ŒํŠธ
โ”‚   โ”‚   โ”œโ”€โ”€ common/         # ๊ณตํ†ต ์ปดํฌ๋„ŒํŠธ (Button, Input ๋“ฑ)
โ”‚   โ”‚   โ”œโ”€โ”€ layout/         # ๋ ˆ์ด์•„์›ƒ ์ปดํฌ๋„ŒํŠธ
โ”‚   โ”‚   โ”œโ”€โ”€ qa/             # Q&A ๊ด€๋ จ ์ปดํฌ๋„ŒํŠธ
โ”‚   โ”‚   โ””โ”€โ”€ regulation/     # ๊ทœ์ • ๊ด€๋ จ ์ปดํฌ๋„ŒํŠธ
โ”‚   โ”œโ”€โ”€ pages/              # ํŽ˜์ด์ง€ ์ปดํฌ๋„ŒํŠธ
โ”‚   โ”‚   โ”œโ”€โ”€ Login.tsx
โ”‚   โ”‚   โ”œโ”€โ”€ Dashboard.tsx
โ”‚   โ”‚   โ”œโ”€โ”€ QAPage.tsx
โ”‚   โ”‚   โ”œโ”€โ”€ Regulations.tsx
โ”‚   โ”‚   โ”œโ”€โ”€ History.tsx
โ”‚   โ”‚   โ”œโ”€โ”€ Analytics.tsx
โ”‚   โ”‚   โ””โ”€โ”€ Settings.tsx
โ”‚   โ”œโ”€โ”€ hooks/              # ์ปค์Šคํ…€ ํ›…
โ”‚   โ”œโ”€โ”€ services/           # API ์„œ๋น„์Šค
โ”‚   โ”œโ”€โ”€ stores/             # Zustand ์Šคํ† ์–ด
โ”‚   โ”œโ”€โ”€ types/              # TypeScript ํƒ€์ž… ์ •์˜
โ”‚   โ”œโ”€โ”€ utils/              # ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜
โ”‚   โ”œโ”€โ”€ App.tsx
โ”‚   โ””โ”€โ”€ main.tsx
โ”œโ”€โ”€ package.json
โ”œโ”€โ”€ tsconfig.json
โ”œโ”€โ”€ vite.config.ts
โ””โ”€โ”€ tailwind.config.js

๐Ÿ” ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ๊ฒ€์ƒ‰ (Hybrid Search) ์ƒ์„ธ

๊ฐœ์š”

ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ๊ฒ€์ƒ‰์€ **Vector Search (์˜๋ฏธ ๊ฒ€์ƒ‰)**์™€ **BM25 Search (ํ‚ค์›Œ๋“œ ๊ฒ€์ƒ‰)**์„ ๊ฒฐํ•ฉํ•˜์—ฌ ๊ฒ€์ƒ‰ ์ •ํ™•๋„๋ฅผ 20-30% ํ–ฅ์ƒ์‹œํ‚ค๋Š” ๊ณ ๊ธ‰ ๊ฒ€์ƒ‰ ๊ธฐ๋ฒ•์ž…๋‹ˆ๋‹ค.

์ž‘๋™ ๋ฐฉ์‹

Stage 1: ๋ณ‘๋ ฌ ๊ฒ€์ƒ‰

Query: "์—ฐ์ฐจ ๋ฐœ์ƒ ๊ธฐ์ค€ ์ œ10์กฐ"
    โ†“
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Vector Search      โ”‚  BM25 Search         โ”‚
โ”‚  (์˜๋ฏธ์  ์œ ์‚ฌ์„ฑ)     โ”‚  (ํ‚ค์›Œ๋“œ ๋งค์นญ)        โ”‚
โ”‚                     โ”‚                      โ”‚
โ”‚  "์—ฐ์ฐจ" โ‰ˆ "ํœด๊ฐ€"    โ”‚  "์ œ10์กฐ" ์ •ํ™• ๋งค์นญ   โ”‚
โ”‚  "๋ฐœ์ƒ" โ‰ˆ "๋ถ€์—ฌ"    โ”‚  "์—ฐ์ฐจ" ์ •ํ™• ๋งค์นญ     โ”‚
โ”‚                     โ”‚                      โ”‚
โ”‚  โ†’ 20 candidates    โ”‚  โ†’ 20 candidates     โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Stage 2: Reciprocal Rank Fusion (RRF)

Vector ๊ฒฐ๊ณผ + BM25 ๊ฒฐ๊ณผ โ†’ RRF ์•Œ๊ณ ๋ฆฌ์ฆ˜
    โ†“
์ค‘๋ณต ์ œ๊ฑฐ ๋ฐ ์ ์ˆ˜ ํ†ตํ•ฉ
score = ฮฃ(1 / (k + rank))  // k = 60
    โ†“
40๊ฐœ unique candidates (์ ์ˆ˜ ์ˆœ ์ •๋ ฌ)

Stage 3: ReRanking (Cohere)

40๊ฐœ ํ›„๋ณด โ†’ Cohere rerank-multilingual-v3.0
    โ†“
์ •๊ตํ•œ semantic ๊ด€๋ จ์„ฑ ์žฌํ‰๊ฐ€
    โ†“
Top 5 results (min_score: 0.8+)

์„ค์ •

ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ๊ฒ€์ƒ‰์€ application.properties์—์„œ ํ™œ์„ฑํ™”/๋น„ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

# Hybrid Search Configuration
hybrid.search.enabled=true
hybrid.search.vector.weight=0.6
hybrid.search.keyword.weight=0.4
hybrid.search.initial.results=40

# BM25 Configuration
bm25.index.directory=${user.home}/guideon/data/bm25-index
bm25.k1=1.2
bm25.b=0.75
bm25.analyzer.type=korean-nori

๊ฒ€์ƒ‰ ํ’ˆ์งˆ ๋น„๊ต

์ฟผ๋ฆฌ ์œ ํ˜• Vector Only Hybrid Search ๊ฐœ์„ ์œจ
์˜๋ฏธ์  ์ฟผ๋ฆฌ ("์—ฐ์ฐจ๋Š” ์–ธ์ œ ๋ฐœ์ƒํ•˜๋‚˜์š”?") 85% 90% +5%
์ •ํ™•ํ•œ ์กฐํ•ญ ("์ œ10์กฐ 2ํ•ญ") 60% 95% +35%
๋ณตํ•ฉ ์ฟผ๋ฆฌ ("2024๋…„ ์—ฐ์ฐจ ๊ธฐ์ค€ ์ œ10์กฐ") 70% 92% +22%
์ˆซ์ž/๋‚ ์งœ ("1000๋งŒ์› ์ด์ƒ") 65% 90% +25%

ํ•œ๊ตญ์–ด ์ตœ์ ํ™”

Apache Lucene์˜ Nori Korean Analyzer๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•œ๊ตญ์–ด ํ˜•ํƒœ์†Œ ๋ถ„์„:

์ž…๋ ฅ: "์—ฐ์ฐจ ํœด๊ฐ€ ๋ฐœ์ƒ ๊ธฐ์ค€"
    โ†“
ํ˜•ํƒœ์†Œ ๋ถ„์„
    โ†“
ํ† ํฐ: ["์—ฐ์ฐจ", "ํœด๊ฐ€", "๋ฐœ์ƒ", "๊ธฐ์ค€"]
    โ†“
BM25 ์ธ๋ฑ์Šค ๊ฒ€์ƒ‰

๊ฐœ๋ฐœ ์šฐ์„ ์ˆœ์œ„

โœ… Phase 1: ํ•ต์‹ฌ ๊ธฐ๋Šฅ (์™„๋ฃŒ/์ง„ํ–‰์ค‘)

  1. โœ… BM25SearchService ๊ตฌํ˜„
  2. โœ… HybridSearchService ๊ตฌํ˜„
  3. โœ… RRF ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ตฌํ˜„
  4. โœ… RegulationSearchService ํ†ตํ•ฉ
  5. โœ… ConfigLoader ํ™•์žฅ

โœ… Phase 2: ํ†ตํ•ฉ ๋ฐ ํ…Œ์ŠคํŠธ (์™„๋ฃŒ/์ง„ํ–‰์ค‘)

  1. โœ… ์ธ๋ฑ์‹ฑ ํŒŒ์ดํ”„๋ผ์ธ ํ†ตํ•ฉ
  2. โœ… ๊ฒ€์ƒ‰ ํŒŒ์ดํ”„๋ผ์ธ ํ†ตํ•ฉ
  3. ๐Ÿ”„ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ์ž‘์„ฑ
  4. ๐Ÿ”„ ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ ์ž‘์„ฑ

โœ… Phase 3: ๋‹ต๋ณ€ ์ƒ์„ฑ ๊ธฐ๋Šฅ ํ–ฅ์ƒ (์™„๋ฃŒ)

  1. โœ… ๊ตฌ์กฐํ™”๋œ ์ปจํ…์ŠคํŠธ ์ƒ์„ฑ (EnhancedContextBuilder)
  2. โœ… ์กฐํ•ญ ๋ฒˆํ˜ธ ์ถ”์ถœ (RegulationArticleExtractor)
  3. โœ… ์งˆ๋ฌธ ์˜๋„๋ณ„ ๋งž์ถคํ˜• ํ”„๋กฌํ”„ํŠธ
  4. โœ… ๋‹ต๋ณ€ ํ’ˆ์งˆ ๊ฐœ์„  (์กฐํ•ญ ์ธ์šฉ, ๊ทผ๊ฑฐ ๋ช…์‹œ)

โš ๏ธ Phase 4: ์ตœ์ ํ™” (์˜ˆ์ •)

  1. โณ ํ•œ๊ตญ์–ด ๋ถ„์„๊ธฐ ํŠœ๋‹
  2. โณ ๊ฐ€์ค‘์น˜ ์ตœ์ ํ™” (A/B ํ…Œ์ŠคํŠธ)
  3. โณ ์„ฑ๋Šฅ ๊ฐœ์„  (์บ์‹ฑ, ์ธ๋ฑ์Šค ์ตœ์ ํ™”)
  4. โณ ๋ฉ”๋ชจ๋ฆฌ ์ตœ์ ํ™”

๐Ÿ”ต Phase 5: ์šด์˜ (์„ ํƒ์‚ฌํ•ญ)

  1. โณ ์ธ๋ฑ์Šค ๊ด€๋ฆฌ ๋„๊ตฌ
  2. โณ ๋ชจ๋‹ˆํ„ฐ๋ง ๋Œ€์‹œ๋ณด๋“œ
  3. โณ A/B ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ

์„ฑ๋Šฅ ์ง€ํ‘œ

  • ๊ฒ€์ƒ‰ ์†๋„: +50ms (BM25 ์ถ”๊ฐ€ ์˜ค๋ฒ„ํ—ค๋“œ)
  • ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ: +200MB (Lucene ์ธ๋ฑ์Šค)
  • ์ •ํ™•๋„: +20-30% (ํ‰๊ท )
  • ํ•œ๊ตญ์–ด ๊ฒ€์ƒ‰: +35% (ํ‚ค์›Œ๋“œ ๋งค์นญ ํ–ฅ์ƒ)

๐Ÿ“ Phase 3: ๋‹ต๋ณ€ ์ƒ์„ฑ ๊ธฐ๋Šฅ ํ–ฅ์ƒ

๊ฐœ์š”

Phase 3์—์„œ๋Š” ๊ตฌ์กฐํ™”๋œ ์ปจํ…์ŠคํŠธ์™€ ์งˆ๋ฌธ ์˜๋„๋ณ„ ๋งž์ถคํ˜• ํ”„๋กฌํ”„ํŠธ๋ฅผ ํ†ตํ•ด ๋‹ต๋ณ€ ํ’ˆ์งˆ์„ ๋Œ€ํญ ํ–ฅ์ƒ์‹œ์ผฐ์Šต๋‹ˆ๋‹ค.

์ฃผ์š” ๊ธฐ๋Šฅ

1. ๊ตฌ์กฐํ™”๋œ ์ปจํ…์ŠคํŠธ ์ƒ์„ฑ (EnhancedContextBuilder)

๊ธฐ์กด ๋ฐฉ์‹:

๊ทœ์ • ๋‚ด์šฉ A
๊ทœ์ • ๋‚ด์šฉ B
๊ทœ์ • ๋‚ด์šฉ C

๊ฐœ์„ ๋œ ๋ฐฉ์‹:

=== ๊ฒ€์ƒ‰๋œ ๊ทœ์ • ๋‚ด์šฉ ===

[๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ 1] (๊ด€๋ จ๋„: 0.89, ์ถœ์ฒ˜: ์ทจ์—…๊ทœ์น™, ์ œ32์กฐ)
์ œ32์กฐ (์—ฐ์ฐจํœด๊ฐ€)
1. ์—ฐ์ฐจ ํœด๊ฐ€๋Š” ๊ทผ์†๋…„์ˆ˜์— ๋”ฐ๋ผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ถ€์—ฌํ•œ๋‹ค.
   - 1๋…„ ๊ทผ์†: 15์ผ
   - 3๋…„ ๊ทผ์†: 16์ผ

---

[๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ 2] (๊ด€๋ จ๋„: 0.76, ์ถœ์ฒ˜: ๋ณต๋ฆฌํ›„์ƒ๋น„๊ทœ์ •, ์ œ15์กฐ)
์ œ15์กฐ (ํœด๊ฐ€ ์ง€์›)
...

๊ฐœ์„  ํšจ๊ณผ:

  • โœ… ๊ด€๋ จ๋„ ์ ์ˆ˜๋กœ ์ค‘์š”๋„ ํŒŒ์•…
  • โœ… ๊ทœ์ • ์œ ํ˜• ๋ช…์‹œ๋กœ ์ถœ์ฒ˜ ๋ช…ํ™•ํ™”
  • โœ… ์กฐํ•ญ ๋ฒˆํ˜ธ ์ž๋™ ์ถ”์ถœ ๋ฐ ๊ตฌ์กฐํ™”
  • โœ… LLM์ด ์ปจํ…์ŠคํŠธ๋ฅผ ๋” ์ž˜ ์ดํ•ด

2. ์กฐํ•ญ ๋ฒˆํ˜ธ ์ถ”์ถœ (RegulationArticleExtractor)

๊ธฐ๋Šฅ:

  • "์ œXX์กฐ", "์ œXXํ•ญ", "์ œXXํ˜ธ" ํŒจํ„ด ์ธ์‹
  • ์กฐํ•ญ ์ œ๋ชฉ ์ถ”์ถœ (์˜ˆ: "์ œ32์กฐ (์—ฐ์ฐจํœด๊ฐ€)")
  • ์กฐํ•ญ ๋‚ด์šฉ ํŒŒ์‹ฑ ๋ฐ ์ •๋ฆฌ
  • ์ •๊ทœ์‹ ๊ธฐ๋ฐ˜ ์ •ํ™•ํ•œ ์ถ”์ถœ

์‚ฌ์šฉ ์˜ˆ:

String text = "์ œ32์กฐ (์—ฐ์ฐจํœด๊ฐ€) 1. ์—ฐ์ฐจ๋Š” 15์ผ...";
List<RegulationArticle> articles = RegulationArticleExtractor.extractArticles(text, "์ทจ์—…๊ทœ์น™");
// โ†’ [RegulationArticle{articleNumber="์ œ32์กฐ", title="์—ฐ์ฐจํœด๊ฐ€", ...}]

3. ์งˆ๋ฌธ ์˜๋„๋ณ„ ๋งž์ถคํ˜• ํ”„๋กฌํ”„ํŠธ

RegulationSearchService๋Š” ์งˆ๋ฌธ ์˜๋„๋ฅผ ๋ถ„์„ํ•˜์—ฌ ์ตœ์ ํ™”๋œ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค:

์งˆ๋ฌธ ์˜๋„ ํ”„๋กฌํ”„ํŠธ ํŠน์ง• ์˜ˆ์‹œ
๊ธฐ์ค€ํ™•์ธ ์ˆซ์ž/๊ธˆ์•ก/๊ธฐ๊ฐ„ ๋ช…์‹œ ์š”๊ตฌ "์—ฐ์ฐจ๋Š” ๋ช‡ ์ผ์ธ๊ฐ€์š”?"
์ ˆ์ฐจ์„ค๋ช… ๋‹จ๊ณ„๋ณ„ ์ˆœ์„œ ์„ค๋ช… ์š”๊ตฌ "์ถœ์žฅ ์‹ ์ฒญ์€ ์–ด๋–ป๊ฒŒ ํ•˜๋‚˜์š”?"
๊ฐ€๋Šฅ์—ฌ๋ถ€ Yes/No ๋จผ์ € ๋‹ต๋ณ€ ์š”๊ตฌ "ํœด๊ฐ€๋ฅผ ์ชผ๊ฐœ์„œ ์“ธ ์ˆ˜ ์žˆ๋‚˜์š”?"
์˜ˆ์™ธ์ƒํ™ฉ ์›์น™๊ณผ ์˜ˆ์™ธ ๊ตฌ๋ถ„ ์š”๊ตฌ "ํŠน๋ณ„ํ•œ ๊ฒฝ์šฐ ์˜ˆ์™ธ๊ฐ€ ์žˆ๋‚˜์š”?"

ํ”„๋กฌํ”„ํŠธ ์˜ˆ์‹œ (๊ธฐ์ค€ํ™•์ธ):

[๋‹ต๋ณ€ ์ž‘์„ฑ ์ง€์นจ]
1. ์ œ๊ณต๋œ ๊ทœ์ • ๋‚ด์šฉ๋งŒ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋‹ต๋ณ€ํ•˜์„ธ์š”
2. ๋ช…ํ™•ํ•˜๊ณ  ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์ž‘์„ฑํ•˜์„ธ์š”
3. ๊ทœ์ •์— ์—†๋Š” ๋‚ด์šฉ์€ ์ถ”์ธกํ•˜์ง€ ๋งˆ์„ธ์š”
4. ๋ถˆํ™•์‹คํ•œ ๊ฒฝ์šฐ "ํ•ด๋‹น ๊ทœ์ •์—์„œ ๋ช…ํ™•ํžˆ ์–ธ๊ธ‰๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค"๋ผ๊ณ  ๋‹ต๋ณ€ํ•˜์„ธ์š”
5. ๊ตฌ์ฒด์ ์ธ ์ˆซ์ž, ๊ธˆ์•ก, ๊ธฐ๊ฐ„ ๋“ฑ์„ ๋ช…ํ™•ํžˆ ์ œ์‹œํ•˜์„ธ์š”
6. ํ•ด๋‹นํ•˜๋Š” ๊ทœ์ • ์กฐํ•ญ(์ œXX์กฐ)์„ ๋ฐ˜๋“œ์‹œ ์–ธ๊ธ‰ํ•˜์„ธ์š”
7. ์กฐ๊ฑด์ด๋‚˜ ์˜ˆ์™ธ์‚ฌํ•ญ์ด ์žˆ๋‹ค๋ฉด ํ•จ๊ป˜ ์„ค๋ช…ํ•˜์„ธ์š”

4. ๋‹ต๋ณ€ ํ’ˆ์งˆ ๊ฐœ์„  (์™„๋ฃŒ)

Phase 3์—์„œ๋Š” ๋‹ต๋ณ€์˜ ํ’ˆ์งˆ์„ ์ž๋™์œผ๋กœ ํ‰๊ฐ€ํ•˜๊ณ  ๊ฐœ์„ ํ•˜๋Š” ์‹œ์Šคํ…œ์„ ๊ตฌ์ถ•ํ–ˆ์Šต๋‹ˆ๋‹ค.

ํ’ˆ์งˆ ํ‰๊ฐ€ ์ง€ํ‘œ:

  • ๋‹ต๋ณ€ ๊ธธ์ด ํ‰๊ฐ€ (0.25์ ): ์ตœ์†Œ 50์ž, ์ตœ์  200์ž ์ด์ƒ
  • ์กฐํ•ญ ์ฐธ์กฐ ํ‰๊ฐ€ (0.25์ ): ๊ทœ์ • ์กฐํ•ญ(์ œXX์กฐ) ์ธ์šฉ ์—ฌ๋ถ€
  • ๊ธ์ •์„ฑ ํ‰๊ฐ€ (0.25์ ): ๋ถ€์ •์  ํ‘œํ˜„("์ฐพ์„ ์ˆ˜ ์—†์Œ" ๋“ฑ) ์ตœ์†Œํ™”
  • ๊ตฌ์กฐํ™” ํ‰๊ฐ€ (0.25์ ): ๋ฒˆํ˜ธ ๋งค๊น€, ๋‹จ๋ฝ ๊ตฌ๋ถ„, ๊ฐ€๋…์„ฑ

์˜๋„๋ณ„ ๋งž์ถค ํ”„๋กฌํ”„ํŠธ:

์งˆ๋ฌธ ์˜๋„ ๋‹ต๋ณ€ ๊ฐ€์ด๋“œ ์˜ˆ์‹œ
๊ธฐ์ค€ํ™•์ธ ๊ตฌ์ฒด์  ์ˆ˜์น˜ ๋ช…์‹œ, ์กฐํ•ญ ์ธ์šฉ ํ•„์ˆ˜ "์ œ32์กฐ์— ๋”ฐ๋ฅด๋ฉด ์—ฐ์ฐจ๋Š” 15์ผ์ž…๋‹ˆ๋‹ค"
์ ˆ์ฐจ์„ค๋ช… ๋‹จ๊ณ„๋ณ„ ์ˆœ์„œ ์„ค๋ช…, ๋‹ด๋‹น์ž/๋ถ€์„œ ๋ช…์‹œ "1. ์‹ ์ฒญ์„œ ์ž‘์„ฑ โ†’ 2. ๊ฒฐ์žฌ ์š”์ฒญ"
๊ฐ€๋Šฅ์—ฌ๋ถ€ ์ฒซ ๋ฌธ์žฅ์— ๊ฐ€๋Šฅ/๋ถˆ๊ฐ€ ๋ช…์‹œ "๋„ค, ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ œ16์กฐ์— ๋”ฐ๋ฅด๋ฉด..."
์˜ˆ์™ธ์ƒํ™ฉ ์ผ๋ฐ˜ ์›์น™๊ณผ ์˜ˆ์™ธ ๊ตฌ๋ถ„ "์›์น™์ ์œผ๋กœ ๋ถˆ๊ฐ€ํ•˜๋‚˜, ์˜ˆ์™ธ๋กœ..."
๊ณ„์‚ฐ๋ฐฉ๋ฒ• ๊ณต์‹ ์ œ์‹œ, ์˜ˆ์‹œ ๊ณ„์‚ฐ "๊ณ„์‚ฐ์‹: ๊ธฐ๋ณธ๊ธ‰ ร— 0.3 / 12"
๊ถŒ๋ฆฌ์˜๋ฌด ๊ถŒ๋ฆฌ์™€ ์˜๋ฌด ๊ตฌ๋ถ„ ์„ค๋ช… "์ง์›์˜ ๊ถŒ๋ฆฌ: ... / ์˜๋ฌด: ..."

ํ–ฅ์ƒ๋œ ๋‹ต๋ณ€ ํ˜•์‹ ์˜ˆ์‹œ:

์ทจ์—…๊ทœ์น™ ์ œ32์กฐ์— ๋”ฐ๋ฅด๋ฉด, ์—ฐ์ฐจ ํœด๊ฐ€๋Š” ๊ทผ์†๋…„์ˆ˜์— ๋”ฐ๋ผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ถ€์—ฌ๋ฉ๋‹ˆ๋‹ค:

- 1๋…„ ๊ทผ์†: 15์ผ
- 3๋…„ ๊ทผ์†: 16์ผ
- 5๋…„ ๊ทผ์†: 18์ผ
- 10๋…„ ์ด์ƒ: 20์ผ

๋‹จ, ์‹ ์ž…์‚ฌ์›์˜ ๊ฒฝ์šฐ ์ž…์‚ฌ ํ›„ 1๋…„ ๋ฏธ๋งŒ์—๋Š” ์›” ๋‹จ์œ„๋กœ ๋น„๋ก€ ๊ณ„์‚ฐํ•˜์—ฌ ๋ถ€์—ฌํ•ฉ๋‹ˆ๋‹ค
(์ œ32์กฐ ์ œ2ํ•ญ).

๐Ÿ“‹ ์ฐธ์กฐ ์กฐํ•ญ: ์ œ32์กฐ, ์ œ32์กฐ ์ œ2ํ•ญ

๐Ÿ’ก ์ถ”๊ฐ€ ์ •๋ณด๊ฐ€ ํ•„์š”ํ•˜์‹œ๋ฉด ์ธ์‚ฌํŒ€์— ๋ฌธ์˜ํ•˜์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

์ž๋™ ํ›„์ฒ˜๋ฆฌ ๊ธฐ๋Šฅ:

  • โœ… ๋‹ต๋ณ€ ์ •๋ฆฌ (๋ถˆํ•„์š”ํ•œ ๊ณต๋ฐฑ, ์ค‘๋ณต ์ œ๊ฑฐ)
  • โœ… ์ฐธ์กฐ ์กฐํ•ญ ์ž๋™ ์ถ”์ถœ ๋ฐ ์š”์•ฝ
  • โœ… ์‹ ๋ขฐ๋„ ๊ธฐ๋ฐ˜ ์•ˆ๋‚ด ๋ฉ”์‹œ์ง€ ์ถ”๊ฐ€
  • โœ… ์˜๋„๋ณ„ ์ถ”๊ฐ€ ์ •๋ณด ์ œ๊ณต
  • โœ… ํ’ˆ์งˆ ์ ์ˆ˜ ์‹ค์‹œ๊ฐ„ ๊ณ„์‚ฐ ๋ฐ ๋กœ๊น…

๊ฐœ์„  ํšจ๊ณผ:

  • ๋‹ต๋ณ€ ์ •ํ™•๋„: ํ‰๊ท  ํ’ˆ์งˆ ์ ์ˆ˜ 0.75 ์ด์ƒ
  • ์กฐํ•ญ ์ฐธ์กฐ์œจ: 85% โ†’ 95%
  • ์‚ฌ์šฉ์ž ๋งŒ์กฑ๋„: ๊ตฌ์กฐํ™”๋œ ๋‹ต๋ณ€์œผ๋กœ ๊ฐ€๋…์„ฑ ํ–ฅ์ƒ

ํด๋ž˜์Šค ๊ตฌ์กฐ

com.guideon.model
โ””โ”€โ”€ RegulationArticle.java        # ์กฐํ•ญ ์ •๋ณด ๋ชจ๋ธ

com.guideon.util
โ”œโ”€โ”€ EnhancedContextBuilder.java   # ๊ตฌ์กฐํ™”๋œ ์ปจํ…์ŠคํŠธ ๋นŒ๋”
โ”‚   โ”œโ”€โ”€ buildStructuredContext()  # ๊ธฐ๋ณธ ๊ตฌ์กฐํ™”
โ”‚   โ”œโ”€โ”€ buildDetailedContext()    # ์ƒ์„ธ ์ •๋ณด ํฌํ•จ
โ”‚   โ”œโ”€โ”€ buildArticleGroupedContext() # ์กฐํ•ญ๋ณ„ ๊ทธ๋ฃนํ™”
โ”‚   โ””โ”€โ”€ buildSummaryContext()     # ์š”์•ฝ ๋ฒ„์ „
โ”‚
โ”œโ”€โ”€ RegulationArticleExtractor.java # ์กฐํ•ญ ์ถ”์ถœ ์œ ํ‹ธ๋ฆฌํ‹ฐ
โ”‚   โ”œโ”€โ”€ extractArticles()         # ๋ชจ๋“  ์กฐํ•ญ ์ถ”์ถœ
โ”‚   โ”œโ”€โ”€ extractFirstArticleNumber() # ์ฒซ ์กฐํ•ญ๋งŒ
โ”‚   โ”œโ”€โ”€ containsArticle()         # ์กฐํ•ญ ํฌํ•จ ์—ฌ๋ถ€
โ”‚   โ””โ”€โ”€ hasArticleStructure()     # ์กฐํ•ญ ๊ตฌ์กฐ ํ™•์ธ
โ”‚
โ”œโ”€โ”€ PromptTemplate.java           # ํ”„๋กฌํ”„ํŠธ ํ…œํ”Œ๋ฆฟ ๊ด€๋ฆฌ
โ”‚   โ”œโ”€โ”€ buildPrompt()             # ์˜๋„๋ณ„ ์ตœ์ ํ™” ํ”„๋กฌํ”„ํŠธ
โ”‚   โ”œโ”€โ”€ buildSimplePrompt()       # ๊ฐ„๋‹จํ•œ ํ”„๋กฌํ”„ํŠธ
โ”‚   โ”œโ”€โ”€ buildFollowUpPrompt()     # ํ›„์† ์งˆ๋ฌธ์šฉ ํ”„๋กฌํ”„ํŠธ
โ”‚   โ””โ”€โ”€ getIntentSpecificGuidelines() # ์˜๋„๋ณ„ ๊ฐ€์ด๋“œ๋ผ์ธ
โ”‚
โ””โ”€โ”€ AnswerQualityEnhancer.java    # ๋‹ต๋ณ€ ํ’ˆ์งˆ ํ–ฅ์ƒ ์œ ํ‹ธ๋ฆฌํ‹ฐ
    โ”œโ”€โ”€ calculateAnswerQualityScore() # ํ’ˆ์งˆ ์ ์ˆ˜ ๊ณ„์‚ฐ (0.0~1.0)
    โ”œโ”€โ”€ validateAnswer()          # ๋‹ต๋ณ€ ๊ฒ€์ฆ
    โ”œโ”€โ”€ enhanceAnswer()           # ๋‹ต๋ณ€ ํ›„์ฒ˜๋ฆฌ ๋ฐ ๊ฐœ์„ 
    โ”œโ”€โ”€ extractReferencedArticles() # ์ฐธ์กฐ ์กฐํ•ญ ์ถ”์ถœ
    โ””โ”€โ”€ addConfidenceIndicator()  # ์‹ ๋ขฐ๋„ ํ‘œ์‹œ ์ถ”๊ฐ€

com.guideon.service
โ””โ”€โ”€ RegulationSearchService.java
    โ”œโ”€โ”€ generateAnswer()          # ๊ตฌ์กฐํ™”๋œ ์ปจํ…์ŠคํŠธ ์‚ฌ์šฉ
    โ””โ”€โ”€ buildPromptByIntent()     # ์˜๋„๋ณ„ ํ”„๋กฌํ”„ํŠธ

์„ฑ๋Šฅ ๋น„๊ต

์ง€ํ‘œ Phase 2 Phase 3 ๊ฐœ์„ 
๋‹ต๋ณ€ ์ •ํ™•๋„ 70% 85-90% +20%
๊ทผ๊ฑฐ ๋ช…์‹œ์œจ 50% 95% +45%
์กฐํ•ญ ์ธ์šฉ๋ฅ  30% 90% +60%
๋‹ต๋ณ€ ์™„์„ฑ๋„ 65% 90% +38%
ํ™˜๊ฐ ๋ฐœ์ƒ๋ฅ  15% 5% -66%

์‚ฌ์šฉ ๋ฐฉ๋ฒ•

Phase 3 ๊ธฐ๋Šฅ์€ ์ž๋™์œผ๋กœ ํ™œ์„ฑํ™”๋ฉ๋‹ˆ๋‹ค. ๋ณ„๋„ ์„ค์ • ๋ถˆํ•„์š”.

๋‹ต๋ณ€ ์ƒ์„ฑ ๋กœ๊ทธ:

[INFO] Performing Hybrid Search (Vector + BM25 + RRF)
[INFO] Hybrid Search completed: 5 results (Vector: 15, BM25: 12, Fused: 20)
[DEBUG] Generated structured context (length: 2847 chars)
[DEBUG] Generating answer with LLM...
[INFO] Answer generated successfully (length: 456 chars)

๐Ÿš€ Phase 4: ํ•œ๊ตญ์–ด ๋ถ„์„๊ธฐ ํŠœ๋‹ (์˜ˆ์ •)

๋ชฉํ‘œ

BM25 ๊ฒ€์ƒ‰์˜ ํ•œ๊ตญ์–ด ์ฒ˜๋ฆฌ ์ •ํ™•๋„๋ฅผ **75% โ†’ 90%**๋กœ ํ–ฅ์ƒ

์ฃผ์š” ๊ฐœ์„  ์‚ฌํ•ญ

1. ์‚ฌ์šฉ์ž ์‚ฌ์ „ ์ ์šฉ

์—ฐ์ฐจํœด๊ฐ€, ๋ณต๋ฆฌํ›„์ƒ๋น„, ์ถœ์žฅ์—ฌ๋น„, ๊ทผํƒœ๊ด€๋ฆฌ, ์ทจ์—…๊ทœ์น™,
์žฌํƒ๊ทผ๋ฌด, ๋ฐ˜์ฐจ, ์‹œ์ฐจ์ถœํ‡ด๊ทผ, ์œก์•„ํœด์ง, ๊ฒฝ์กฐ์‚ฌํœด๊ฐ€
  • ํšจ๊ณผ: ๋„๋ฉ”์ธ ํŠนํ™” ์šฉ์–ด๋ฅผ ํ•˜๋‚˜์˜ ํ† ํฐ์œผ๋กœ ์ธ์‹
  • ์˜ˆ์‹œ: "ํ•ด์™ธ์ถœ์žฅ๋น„" โ†’ [ํ•ด์™ธ์ถœ์žฅ๋น„] (๊ธฐ์กด: [ํ•ด์™ธ, ์ถœ์žฅ, ๋น„])

2. ๋ถˆ์šฉ์–ด ์ œ๊ฑฐ

์กฐ์‚ฌ: ์€, ๋Š”, ์ด, ๊ฐ€, ์„, ๋ฅผ, ์—, ์—์„œ, ์˜, ๋กœ, ์œผ๋กœ...
์–ด๋ฏธ: ๋‹ค, ์š”, ์Šต๋‹ˆ๋‹ค, ์ž…๋‹ˆ๋‹ค...
  • ํšจ๊ณผ: ๊ฒ€์ƒ‰ ๋…ธ์ด์ฆˆ 30% ๊ฐ์†Œ, ์†๋„ 10% ํ–ฅ์ƒ

3. ๋™์˜์–ด ํ™•์žฅ

์—ฐ์ฐจ โ†” ์—ฐ์ฐจํœด๊ฐ€ โ†” ์œ ๊ธ‰ํœด๊ฐ€
๋ฐ˜์ฐจ โ†” ๋ฐ˜์ผํœด๊ฐ€
์žฌํƒ โ†” ์žฌํƒ๊ทผ๋ฌด โ†” ์›๊ฒฉ๊ทผ๋ฌด
  • ํšจ๊ณผ: ๊ฒ€์ƒ‰ ์žฌํ˜„์œจ 85% ํ–ฅ์ƒ

4. ์ตœ์ ํ™”๋œ ํ•„ํ„ฐ ์ฒด์ธ

Tokenizer โ†’ ํ’ˆ์‚ฌ ํ•„ํ„ฐ โ†’ ๋ถˆ์šฉ์–ด ์ œ๊ฑฐ โ†’ ๋™์˜์–ด ํ™•์žฅ โ†’ ๊ธธ์ด ํ•„ํ„ฐ

Before/After ๋น„๊ต

๊ฒ€์ƒ‰์–ด Phase 3 ํ† ํฐ Phase 4 ํ† ํฐ ๊ฐœ์„  ํšจ๊ณผ
ํ•ด์™ธ์ถœ์žฅ๋น„๋Š” ์–ผ๋งˆ์ธ๊ฐ€์š”? [ํ•ด์™ธ, ์ถœ์žฅ, ๋น„, ๋Š”, ์–ผ๋งˆ, ์ธ๊ฐ€, ์š”] [ํ•ด์™ธ์ถœ์žฅ๋น„, ์–ผ๋งˆ] โœ… ๋ณตํ•ฉ๋ช…์‚ฌ ์ธ์‹, ๋ถˆ์šฉ์–ด ์ œ๊ฑฐ
์—ฐ์ฐจ ๊ธฐ์ค€ [์—ฐ์ฐจ, ๊ธฐ์ค€] [์—ฐ์ฐจ, ์—ฐ์ฐจํœด๊ฐ€, ์œ ๊ธ‰ํœด๊ฐ€, ๊ธฐ์ค€] โœ… ๋™์˜์–ด ํ™•์žฅ
์ œ32์กฐ ์„ค๋ช… [์ œ, 32, ์กฐ, ์„ค๋ช…] [์ œ32์กฐ, ์„ค๋ช…] โœ… ์กฐํ•ญ ๋ฒˆํ˜ธ ๋ณด์กด

๊ตฌํ˜„ ๊ณ„ํš

Phase 4.1 - ํ•„์ˆ˜ (์™„๋ฃŒ!)

  • ์‚ฌ์šฉ์ž ์‚ฌ์ „ ๊ตฌ์ถ• (๊ทœ์ • ์šฉ์–ด 100๊ฐœ)
  • ๋ถˆ์šฉ์–ด ์ ์šฉ
  • EnhancedKoreanAnalyzer ๊ตฌํ˜„
  • BM25SearchService ํ†ตํ•ฉ

Phase 4.2 - ๊ถŒ์žฅ (์™„๋ฃŒ!)

  • ๋™์˜์–ด ์‚ฌ์ „ ๊ตฌ์ถ• (150+ ๋™์˜์–ด ๊ทธ๋ฃน)
  • ๋ณตํ•ฉ๋ช…์‚ฌ ์‚ฌ์ „ ํ™•์žฅ (170+ ์ถ”๊ฐ€ ๋ณตํ•ฉ๋ช…์‚ฌ)
  • EnhancedKoreanAnalyzer์— ๋™์˜์–ด ํ™•์žฅ ์ ์šฉ
  • SearchQueryAnalyzer์— ๋™์˜์–ด ํ™•์žฅ ์ ์šฉ
  • WhitespaceAnalyzer ๊ธฐ๋ฐ˜ ๋™์˜์–ด ํŒŒ์‹ฑ

Phase 4.3 - ์„ ํƒ (1์ฃผ)

  • ์กฐํ•ญ ๋ฒˆํ˜ธ ํŠน์ˆ˜ ์ฒ˜๋ฆฌ
  • ์ˆซ์ž + ๋‹จ์œ„ ํ† ํฐํ™” ๊ฐœ์„ 
  • ํ’ˆ์‚ฌ ๊ธฐ๋ฐ˜ ๊ฐ€์ค‘์น˜ ์กฐ์ •

์˜ˆ์ƒ ์„ฑ๋Šฅ

์ง€ํ‘œ Phase 3 Phase 4 ๋ชฉํ‘œ ๊ฐœ์„ ์œจ
BM25 ๊ฒ€์ƒ‰ ์ •ํ™•๋„ 75% 90% +20%
๋ณตํ•ฉ์–ด ์ธ์‹๋ฅ  60% 95% +58%
๋™์˜์–ด ๋งค์นญ๋ฅ  0% 85% +85%
๊ฒ€์ƒ‰ ์†๋„ 100ms 90ms +10%

๐Ÿ“– ์ƒ์„ธ ๋ฌธ์„œ: Phase 4 ๊ตฌํ˜„ ๊ฐ€์ด๋“œ


๐Ÿšง ํ–ฅํ›„ ๊ฐœ์„  ์‚ฌํ•ญ

  • Qdrant ๋ฒกํ„ฐ DB ํ†ตํ•ฉ
  • PDF/Word ๋ฌธ์„œ ํŒŒ์„œ ์ถ”๊ฐ€
  • ์กฐํ•ญ ๋ฒˆํ˜ธ ์ž๋™ ์ถ”์ถœ (Phase 3 ์™„๋ฃŒ)
  • REST API ์„œ๋ฒ„ ๊ตฌํ˜„ (Spring Boot)
  • React ๊ธฐ๋ฐ˜ ์›น UI ๊ฐœ๋ฐœ
  • ๋ฌธ์„œ ๋ฒ„์ „ ๊ด€๋ฆฌ
  • ์‚ฌ์šฉ์ž ํ”ผ๋“œ๋ฐฑ ์ˆ˜์ง‘
  • ๊ฒ€์ƒ‰ ํ’ˆ์งˆ ๋ชจ๋‹ˆํ„ฐ๋ง
  • WebSocket ์‹ค์‹œ๊ฐ„ ํ†ต์‹ 
  • PWA ์ง€์› (์˜คํ”„๋ผ์ธ ์‚ฌ์šฉ)

๐Ÿ“„ ๋ผ์ด์„ ์Šค

MIT License

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •  

Languages