Skip to content

๐ŸŽ€ ์›ํ•˜๋Š” ์ธ์žฌ ์ฑ„์šฉ์˜ ์†Œ์šธ๋ฉ”์ดํŠธ! ์žก๋‹ค(JobDa) ๐Ÿšฉ

Notifications You must be signed in to change notification settings

prgrms-aibe-devcourse/AIBE3_FinalProject_ToDoAll_FE

Repository files navigation

๐Ÿ“‘ ์žก๋‹ค (JobDa)

์ฑ„์šฉ๊ณต๊ณ ์™€ ์ด๋ ฅ์„œ๋ฅผ ํ‘œ์ค€ํ™”ํ•ด, AI๊ฐ€ ๊ฐ€์žฅ โ€˜์ž˜ ๋งž๋Š” ์ธ์žฌโ€™๋ฅผ ์ฐพ์•„์ฃผ๋Š” ์ฑ„์šฉ ์ฝ”ํŒŒ์ผ๋Ÿฟ


๋Œ€๋ฌธ์ด๋ฏธ์ง€

๐Ÿ“ ํ”„๋กœ์ ํŠธ ์†Œ๊ฐœ

์žก๋‹ค(JobDa) ๋Š” ์ฑ„์šฉ ๋‹ด๋‹น์ž์™€ ๋ฉด์ ‘๊ด€์˜ ์—…๋ฌด ํšจ์œจ์„ ํš๊ธฐ์ ์œผ๋กœ ๋†’์ด๋Š”
AI ๊ธฐ๋ฐ˜ ์ฑ„์šฉ ์ถ”์ฒœ & ๋ฉด์ ‘ ์ง€์› ์‹œ์Šคํ…œ์ž…๋‹ˆ๋‹ค.

ํ˜„์žฌ์˜ ์ฑ„์šฉ ์‹œ์Šคํ…œ์—์„œ ์ฑ„์šฉ๋‹ด๋‹น์ž๋Š” ์ˆ˜๋ฐฑ ๊ฐœ ์ด๋ ฅ์„œ์—์„œ ์›ํ•˜๋Š” ์š”๊ตฌ์Šคํ‚ฌยท๊ฒฝ๋ ฅ ์ ํ•ฉ๋„๋ฅผ ๋น ๋ฅด๊ฒŒ ํŒ๋ณ„ํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.
๊ธฐ์กด ์ฑ„์šฉ์—์„œ๋Š” ์ด๋ ฅ์„œ์™€ ๊ณต๊ณ ์˜ ํ‘œํ˜„ ๋ฐฉ์‹์ด ์ œ๊ฐ๊ฐ์ด๋ผ ์ ํ•ฉํ•œ ์ธ์žฌ๋ฅผ ์ฐพ๊ธฐ ์–ด๋ ต๊ณ ,
๋ฉด์ ‘์€ ์งˆ๋ฌธ ๊ตฌ์„ฑ, ๊ธฐ๋ก, ํ”ผ๋“œ๋ฐฑ์ด ์ผ๊ด€๋˜์ง€ ์•Š์•„ ์ฑ„์šฉ ๊ฒฐ์ •์ด ๋น„ํšจ์œจ์ ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

์žก๋‹ค๋Š” ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค:

  • โœจ JD(์ฑ„์šฉ๊ณต๊ณ ) & ์ด๋ ฅ์„œ ์ž๋™ ํ‘œ์ค€ํ™”
  • ๐Ÿ” ๊ฒ€์ƒ‰ ์—”์ง„ ๊ธฐ๋ฐ˜์˜ ๊ฐ€์žฅ ์•Œ๋งž๋Š” ์ด๋ ฅ์„œ/ํ›„๋ณด ์ถ”์ฒœ
  • ๐Ÿค– AI ๊ธฐ๋ฐ˜ ์งˆ๋ฌธ ์„ธํŠธ ์ƒ์„ฑ + ์‹ค์‹œ๊ฐ„ ๋ฉด์ ‘ ์ง„ํ–‰
  • ๐Ÿ“Š ๊ณต๊ณ  ํ˜„ํ™ฉ/๋ฉด์ ‘ ์ผ์ • ์บ˜๋ฆฐ๋” ๋“ฑ ์‹œ๊ฐํ™”๋œ ๋Œ€์‹œ๋ณด๋“œ
  • ๐Ÿง  ๋ฉด์ ‘ ๊ธฐ๋ก ์ž๋™ ์š”์•ฝ ๋ฐ ๊ฐ•์ /๊ฐœ์„ ์  ๋„์ถœ

๐Ÿ’ก ์ด๋Ÿฐ ํŒ€์—๊ฒŒ ์ถ”์ฒœํ•ด์š”!

  • "์ ํ•ฉํ•œ ์ง€์›์ž๋ฅผ ๋น ๋ฅด๊ฒŒ ์ฐพ๊ณ  ์‹ถ์–ด์š”"
  • "๋ฉด์ ‘์„ ์ผ๊ด€๋˜๊ณ  ํšจ์œจ์ ์œผ๋กœ ์ง„ํ–‰ํ•˜๊ณ  ์‹ถ์–ด์š”"
  • "ํŒ€ ๋‚ด ์ฑ„์šฉ ํ”„๋กœ์„ธ์Šค๋ฅผ ์ •๋Ÿ‰์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ณ  ์‹ถ์–ด์š”"

๐Ÿ“— ์žก๋‹ค์™€ ํ•จ๊ป˜,

์ฑ„์šฉ์˜ ์ •ํ™•๋„๋Š” ๋†’์ด๊ณ , ์‹œ๊ฐ„์€ ์ค„์ด์„ธ์š”.
๋ฉด์ ‘๊ด€์˜ ์‹œ๊ฐ„์€ ์•„๋ผ๊ณ , ์ฑ„์šฉ์€ ํšจ์œจ์ ์œผ๋กœ ์ง„ํ–‰ํ•˜๋Š” ์ฑ„์šฉ ํ”„๋กœ์„ธ์Šค์˜ ์ง„์งœ ์ฝ”ํŒŒ์ผ๋Ÿฟ, ์žก๋‹ค(JobDa) โœจ


๐Ÿ“š ๋ชฉ์ฐจ


๐Ÿ–ผ๏ธ ์‹œ์Šคํ…œ ์•„ํ‚คํ…์ฒ˜

AIBE3_FINAL_์•„ํ‚คํ…์ณ drawio

๐Ÿงฉ ERD

ERD image

๐Ÿ›  ๊ธฐ์ˆ  ์Šคํƒ ๋ฐ ๋„์ž… ์ด์œ 

Frontend

Category Stack ๋„์ž… ์ด์œ 
Framework React ์ปดํฌ๋„ŒํŠธ ๊ธฐ๋ฐ˜ ๊ตฌ์กฐ๋กœ ๋ณต์žกํ•œ ํ™”๋ฉด ์ƒํƒœ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ
Build Tool Vite ๋น ๋ฅธ ๊ฐœ๋ฐœ ์„œ๋ฒ„์™€ ๋นŒ๋“œ ์†๋„๋ฅผ ํ†ตํ•ด ๊ฐœ๋ฐœ ์ƒ์‚ฐ์„ฑ์„ ๋†’์ด๊ธฐ ์œ„ํ•ด ์„ ํƒ
Styling TailwindCSS ๋””์ž์ธ ์‹œ์Šคํ…œ์„ ์ผ๊ด€๋˜๊ฒŒ ์œ ์ง€ํ•˜๊ณ  ๋น ๋ฅธ UI ๊ฐœ๋ฐœ์„ ์œ„ํ•ด ๋„์ž…

Backend

Category Stack ๋„์ž… ์ด์œ 
Web Framework Spring MVC REST API ๊ธฐ๋ฐ˜ ์„œ๋น„์Šค ๊ตฌ์กฐ๋ฅผ ์„ค๊ณ„ํ•˜๊ณ  ํ™•์žฅํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ
Security Spring Security JWT ๊ธฐ๋ฐ˜ ์ธ์ฆ ๋ฐ ์—ญํ• ๋ณ„ ์ ‘๊ทผ ์ œ์–ด๋ฅผ ๋ถ„๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ๋„์ž…
Authentication JWT ๋ฌด์ƒํƒœ ์ธ์ฆ ๋ฐฉ์‹์œผ๋กœ ํ™•์žฅ์„ฑ๊ณผ ๋ณด์•ˆ์„ ๋™์‹œ์— ํ™•๋ณดํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ
Real-time Communication WebSocket ๋ฉด์ ‘๊ด€๊ณผ ์ง€์›์ž๊ฐ„์˜ ์ฑ„ํŒ… ๋“ฑ ์‹ค์‹œ๊ฐ„ ์ด๋ฒคํŠธ๋ฅผ ์ฆ‰์‹œ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ
Real-time Communication SSE ์‹ค์‹œ๊ฐ„ ์•Œ๋ฆผ ๋“ฑ ์ด๋ฒคํŠธ๋ฅผ ์ฆ‰์‹œ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ

Search & AI

Category Stack ๋„์ž… ์ด์œ 
Search Engine Elasticsearch ์ด๋ ฅ์„œ์™€ ์ฑ„์šฉ๊ณต๊ณ ๋ฅผ ๋‹จ์ˆœ ์กฐํšŒ๊ฐ€ ์•„๋‹Œ ํ‚ค์›Œ๋“œ ๊ธฐ๋ฐ˜ ์ ์ˆ˜ ๊ณ„์‚ฐ ๋ฐ ์œ ์‚ฌ๋„ ๊ฒ€์ƒ‰์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ๋„์ž…ํ•˜์—ฌ ๋Œ€๋Ÿ‰ ๋ฐ์ดํ„ฐ์—์„œ๋„ ๋น ๋ฅธ ์ถ”์ฒœ ์กฐํšŒ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋„๋ก ์„ค๊ณ„
Search Visualization Kibana ์ƒ‰์ธ ์ƒํƒœ ๋ฐ ๊ฒ€์ƒ‰ ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ์‹œ๊ฐ์ ์œผ๋กœ ํ™•์ธํ•˜๋ฉฐ ๋””๋ฒ„๊น…์— ์‚ฌ์šฉ
Cache Redis ์ถ”์ฒœ ๊ฒฐ๊ณผ, AI ์ƒ์„ฑ ๊ฒฐ๊ณผ๋ฅผ ์บ์‹ฑํ•˜์—ฌ ๋ฐ˜๋ณต ์š”์ฒญ ์‹œ ์‘๋‹ต ์†๋„๋ฅผ ๊ฐœ์„ ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ
LLM Tool Layer MCP LLM์ด ํ•„์š”ํ•œ ์‹œ์ ์—๋งŒ ๋‚ด๋ถ€ ๋ฐ์ดํ„ฐ๋ฅผ Tool๋กœ ์กฐํšŒํ•˜๋„๋ก ํ•˜์—ฌ, ํ”„๋กฌํ”„ํŠธ ๋ณต์žก๋„์™€ ์‘๋‹ต ๋น„์šฉ์„ ์ค„์ด๊ธฐ ์œ„ํ•ด ๋„์ž…
AI Framework Spring AI ์ฑ„์šฉ๊ณต๊ณ  ํ‚ค์›Œ๋“œ ์ถ”์ถœ, ์ด๋ ฅ์„œ ์š”์•ฝ, ์ถ”์ฒœ ์‚ฌ์œ  ์ƒ์„ฑ์„ ์„œ๋ฒ„ ๋กœ์ง๊ณผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๊ฒฐํ•ฉํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ

Infrastructure

Category Stack ๋„์ž… ์ด์œ 
Compute AWS EC2 WAS์™€ ๊ฒ€์ƒ‰/AI ์—ญํ• ์„ ๋ถ„๋ฆฌ ๋ฐฐํฌํ•˜์—ฌ ํŠธ๋ž˜ํ”ฝ๊ณผ ๋ฆฌ์†Œ์Šค๋ฅผ ๋…๋ฆฝ์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๋„๋ก ์‚ฌ์šฉ
Database Amazon RDS ์•ˆ์ •์ ์ธ ์šด์˜๊ณผ ๋ฐฑ์—…/๋ณต๊ตฌ๋ฅผ ์œ„ํ•ด ๊ด€๋ฆฌํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ๋„์ž…
RDBMS MySQL ์ฑ„์šฉ๊ณต๊ณ , ์ด๋ ฅ์„œ, ๋งค์นญ ๊ฒฐ๊ณผ ๋“ฑ ์ •ํ˜• ๋ฐ์ดํ„ฐ๋ฅผ ์•ˆ์ •์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ
Object Storage AWS S3 ์ด๋ ฅ์„œ ํŒŒ์ผ ์ €์žฅ ๋ฐ Presigned URL ์ œ๊ณต์„ ์œ„ํ•ด ๋„์ž…

DevOps & Monitoring

Category Stack ๋„์ž… ์ด์œ 
Reverse Proxy Nginx HTTPS ์ฒ˜๋ฆฌ ๋ฐ ํŠธ๋ž˜ํ”ฝ ๋ผ์šฐํŒ…์„ ์•ˆ์ •์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ
Container Docker ํ™˜๊ฒฝ ์ฐจ์ด ์—†์ด ๋™์ผํ•œ ์‹คํ–‰ ํ™˜๊ฒฝ์„ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•ด ์ปจํ…Œ์ด๋„ˆ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ฐฐํฌ
CI/CD GitHub Actions ํ…Œ์ŠคํŠธ ๋ฐ ๋ฐฐํฌ๋ฅผ ์ž๋™ํ™”ํ•˜์—ฌ ์•ˆ์ •์ ์ธ ๋ฆด๋ฆฌ์ฆˆ๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉ
Monitoring Grafana ์„œ๋ฒ„ ์ž์›๊ณผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ƒํƒœ๋ฅผ ์‹œ๊ฐ์ ์œผ๋กœ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ
Metrics Prometheus ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฉ”ํŠธ๋ฆญ์„ ์ˆ˜์ง‘ํ•˜์—ฌ ์„ฑ๋Šฅ ์ด์ƒ ์—ฌ๋ถ€๋ฅผ ์กฐ๊ธฐ์— ํŒŒ์•…ํ•˜๊ธฐ ์œ„ํ•ด ๋„์ž…

โœจ ํ•ต์‹ฌ ๊ธฐ๋Šฅ ์†Œ๊ฐœ

๐Ÿ”” SSE

์‹ค์‹œ๊ฐ„ ์•Œ๋ฆผ
EC958CEBA6BC-2

๐Ÿ’ฌ ์ฑ„ํŒ…

์‹ค์‹œ๊ฐ„ ์ฑ„ํŒ…
KakaoTalk_Photo_2025-12-16-12-08-03

๐Ÿ”Ž ELS

์ถ”์ฒœ ์ง€์›์ž ์กฐํšŒ
elasticsearch-7

๐Ÿค– MCP

๋ฉด์ ‘ ์งˆ๋ฌธ ์ƒ์„ฑ
KakaoTalk_Video_2025-12-16-10-58-56
AI ๋ฉด์ ‘ ์š”์•ฝ
แ„†แ…งแ†ซแ„Œแ…ฅแ†ธแ„‹แ…ญแ„‹แ…ฃแ†จ-แ„€แ…กแ†ผแ„Œแ…ฉ

๐Ÿ›  ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ…

1. Elasticsearch ์ถ”์ฒœ/๊ฒ€์ƒ‰ ์„ฑ๋Šฅ ๊ฐœ์„ 

๐Ÿ“Œ ๋ฌธ์ œ ์ƒํ™ฉ

์ด๋ ฅ์„œ ์ถ”์ฒœ API ํ˜ธ์ถœ ์‹œ, ๋งค ์š”์ฒญ๋งˆ๋‹ค ๋™์ผํ•œ ์ถ”์ฒœ ๋กœ์ง๊ณผ AI ํ˜ธ์ถœ์ด ๋ฐ˜๋ณต๋˜๋ฉฐ ์ดˆ๊ธฐ ์‘๋‹ต ์‹œ๊ฐ„์ด 5์ดˆ ์ด์ƒ (5400ms) ์†Œ์š”๋˜๋Š” ์„ฑ๋Šฅ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒ

ํŠนํžˆ:

  • Elasticsearch ๊ฒ€์ƒ‰
  • ๋‹ค์ˆ˜์˜ JPA ์—ฐ๊ด€ ์—”ํ‹ฐํ‹ฐ ์กฐํšŒ
  • JD ํ‚ค์›Œ๋“œ ์ถ”์ถœ / ์ด๋ ฅ์„œ ์š”์•ฝ / ์ถ”์ฒœ ์‚ฌ์œ  ์ƒ์„ฑ ๋“ฑ OpenAI ๊ธฐ๋ฐ˜ ์—ฐ์‚ฐ ์ด ํ•œ ์š”์ฒญ ์•ˆ์—์„œ ๋ชจ๋‘ ์ˆ˜ํ–‰๋˜๋ฉฐ ์‘๋‹ต ์†๋„ ์ธก๋ฉด์—์„œ ๋ฌธ์ œ๊ฐ€ ๋ช…ํ™•ํžˆ ๋“œ๋Ÿฌ๋‚ฌ์Œ.

๐Ÿ” ์›์ธ ๋ถ„์„

  1. ์ค‘๋ณต ์—ฐ์‚ฐ ๋ฌธ์ œ
  2. ๋™์ผ JD์— ๋Œ€ํ•ด ์ถ”์ฒœ ๊ฒฐ๊ณผ๊ฐ€ ๋งค๋ฒˆ ์ƒˆ๋กœ ๊ณ„์‚ฐ๋จ
  3. N+1 ๋ฌธ์ œ
  4. Resume ์กฐํšŒ ์‹œ ๋‹ค์ˆ˜์˜ ์—ฐ๊ด€ ์—”ํ‹ฐํ‹ฐ๊ฐ€ Lazy ๋กœ๋”ฉ
  5. AI ํ˜ธ์ถœ ๋น„์šฉ - ์ฒซ ํ˜ธ์ถœ ์‹œ OpenAI ๊ธฐ๋ฐ˜ ์—ฐ์‚ฐ์ด ๋‹ค์ˆ˜ ํฌํ•จ๋˜์–ด ์ตœ์†Œ 3์ดˆ ์ด์ƒ ์†Œ์š”

1๏ธโƒฃ 1์ฐจ ๊ฐœ์„  โ€” Redis ์บ์‹œ ๋„์ž… (์ถ”์ฒœ ๊ฒฐ๊ณผ ์บ์‹ฑ)

โœ”๏ธ ์ ์šฉ ๋‚ด์šฉ

  • JD ๊ธฐ์ค€ ์ถ”์ฒœ ๊ฒฐ๊ณผ๋ฅผ Redis์— ์บ์‹ฑ
  • ๋‘ ๋ฒˆ์งธ ํ˜ธ์ถœ๋ถ€ํ„ฐ๋Š” ๊ณ„์‚ฐ ์—†์ด ์ฆ‰์‹œ ๋ฐ˜ํ™˜
redisTemplate.opsForValue().set("recommend:jd_" + jdId, data, TTL);

๐Ÿ“Š ๊ฒฐ๊ณผ

ํ˜ธ์ถœ ํšŸ์ˆ˜ ์‹คํ–‰ ์‹œ๊ฐ„
์ฒซ ํ˜ธ์ถœ 5409ms
๋‘ ๋ฒˆ์งธ ํ˜ธ์ถœ 737ms
์„ธ ๋ฒˆ์งธ ํ˜ธ์ถœ 592ms

๐Ÿ‘‰ ์บ์‹œ ํšจ๊ณผ๋Š” ๋ช…ํ™•ํ–ˆ์ง€๋งŒ, ์ฒซ ํ˜ธ์ถœ์ด ์—ฌ์ „ํžˆ ๋А๋ฆผ

2๏ธโƒฃ 2์ฐจ ๊ฐœ์„  โ€” N+1 ๋ฌธ์ œ ํ•ด๊ฒฐ ์‹œ๋„ (Fetch Join) โœ”๏ธ ์‹œ๋„

์—ฐ๊ด€ ์—”ํ‹ฐํ‹ฐ๋ฅผ ํ•œ ๋ฒˆ์— ๋กœ๋”ฉํ•˜๊ธฐ ์œ„ํ•ด Fetch Join ์ ์šฉ

@Query("""
    SELECT r FROM Resume r
    LEFT JOIN FETCH r.educations
    LEFT JOIN FETCH r.experiences
    LEFT JOIN FETCH r.skills
    WHERE r.id = :resumeId
""")

โŒ ๋ฌธ์ œ ๋ฐœ์ƒ

MultipleBagFetchException:
cannot simultaneously fetch multiple bags
  • Hibernate๋Š” 2๊ฐœ ์ด์ƒ์˜ List ์ปฌ๋ ‰์…˜ Fetch Join์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š์Œ

โœ”๏ธ ์ตœ์ข… ํ•ด๊ฒฐ

  • 1๊ฐœ ์ปฌ๋ ‰์…˜๋งŒ Fetch Join
  • ๋‚˜๋จธ์ง€๋Š” @BatchSize ์ ์šฉ
@Query("""
    SELECT DISTINCT r FROM Resume r
    LEFT JOIN FETCH r.experiences
    WHERE r.id = :resumeId
""")
Optional<Resume> findWithEssentialDetailsById(Long resumeId);

3๏ธโƒฃ ํ•ต์‹ฌ ํ•ด๊ฒฐ โ€” ๋น„๋™๊ธฐ ์บ์‹ฑ + Lazy ์ถ”์ฒœ ์ œ๊ณต

๐Ÿ’ก ์„ค๊ณ„ ์ „ํ™˜ -> โ€œ์ฒซ ์š”์ฒญ์—์„œ ๋ชจ๋“  ๊ฑธ ๊ณ„์‚ฐํ•˜์ง€ ๋ง์žโ€

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

  • ์š”์ฒญ โ†’ ๋ชจ๋“  ๊ณ„์‚ฐ ์ˆ˜ํ–‰ โ†’ ์‘๋‹ต

๊ฐœ์„  ๋ฐฉ์‹

Client Request
   โ†“
Redis Cache ํ™•์ธ
   โ†“        โ†˜
Cache Hit โ†’ ์ฆ‰์‹œ ๋ฐ˜ํ™˜
   โ†“
Cache Miss โ†’ ๋น„๋™๊ธฐ ์ถ”์ฒœ ๊ณ„์‚ฐ ์‹œ์ž‘
            โ†’ "์ถ”์ฒœ ์ค€๋น„ ์ค‘" ์‘๋‹ต

โœ”๏ธ ๋น„๋™๊ธฐ ์บ์‹ฑ ์ ์šฉ

@Async
public void warmUpRecommendation(Long jdId) {
    List<ResumeRecommendationDto> result =
        recommendationCoreService.calculateRecommendations(jdId);
    redisRecommendationCacheService.saveRecommendations(jdId, result);
}

๐Ÿ“Š ์ตœ์ข… ์„ฑ๋Šฅ ๊ฒฐ๊ณผ

์‹œ์  ์‹คํ–‰ ์‹œ๊ฐ„
์ฒซ ์š”์ฒญ (๋น„๋™๊ธฐ ํŠธ๋ฆฌ๊ฑฐ) ~1700ms
๋‘ ๋ฒˆ์งธ ํ˜ธ์ถœ 102ms
์„ธ ๋ฒˆ์งธ ํ˜ธ์ถœ 14ms

๐Ÿ‘‰ ์ฒด๊ฐ ์„ฑ๋Šฅ ๋Œ€ํญ ๊ฐœ์„  + ์„œ๋ฒ„ ๋ถ€ํ•˜ ๊ฐ์†Œ

4๏ธโƒฃ ์ถ”๊ฐ€ ๋ฆฌํŒฉํ† ๋ง โ€” AI ๊ฒฐ๊ณผ ์˜์†์„ฑ ๊ฐœ์„  ๐Ÿง  ๋ฌธ์ œ ์ธ์‹

  • JD ํ‚ค์›Œ๋“œ, ์ด๋ ฅ์„œ ์š”์•ฝ, ์ถ”์ฒœ ์‚ฌ์œ ๋Š” ์˜์†์„ฑ์ด ๋†’์€ ๋ฐ์ดํ„ฐ๋กœ, Redis์—๋งŒ ์ €์žฅํ•˜๋Š” ๊ตฌ์กฐ๋Š” ์ ์ ˆํ•˜์ง€ ์•Š์Œ

โœ”๏ธ ๊ฐœ์„  ๊ตฌ์กฐ

์š”์ฒญ
 โ†“
Redis ์กฐํšŒ
 โ†“        โ†˜
HIT      MISS
 โ†“        โ†“
๋ฐ˜ํ™˜     DB ์กฐํšŒ
          โ†“        โ†˜
         HIT       MISS
          โ†“         โ†“
     Redis ์บ์‹ฑ     AI ํ˜ธ์ถœ
                    โ†“
                 DB ์ €์žฅ + Redis ์บ์‹ฑ

โœ”๏ธ ํšจ๊ณผ

  • AI ํ˜ธ์ถœ ํšŸ์ˆ˜ ์ตœ์†Œํ™”
  • ์žฌ์‹œ์ž‘/TTL ๋งŒ๋ฃŒ์—๋„ ๋ฐ์ดํ„ฐ ์œ ์ง€
  • Redis๋Š” ๊ฐ€์† ๋ ˆ์ด์–ด ์—ญํ• ๋งŒ ์ˆ˜ํ–‰

โœ… ์ตœ์ข… ์ •๋ฆฌ

  • Redis ์บ์‹ฑ์œผ๋กœ ์ค‘๋ณต ์—ฐ์‚ฐ ์ œ๊ฑฐ
  • Fetch Join + BatchSize๋กœ N+1 ๋ฌธ์ œ ์™„ํ™”
  • ๋น„๋™๊ธฐ ์บ์‹ฑ์œผ๋กœ ์ฒซ ํ˜ธ์ถœ ์ฒด๊ฐ ์„ฑ๋Šฅ ๊ฐœ์„ 
  • AI ๊ฒฐ๊ณผ๋Š” DB์— ์˜์† ์ €์žฅํ•˜์—ฌ ๊ตฌ์กฐ์  ์•ˆ์ •์„ฑ ํ™•๋ณด

2. SSE ์‹ค์‹œ๊ฐ„ ์•Œ๋ฆผ ๋ฐ˜์˜ ์ด์Šˆ ํ•ด๊ฒฐ (Vercel + Nginx)

๐Ÿ“Œ ๋ฌธ์ œ ์ƒํ™ฉ

๋กœ์ปฌ ํ™˜๊ฒฝ์—์„œ๋Š” ์ •์ƒ ๋™์ž‘ํ•˜๋˜ SSE(Server-Sent Events) ์•Œ๋ฆผ์ด ๋ฐฐํฌ ํ™˜๊ฒฝ(Vercel + Nginx Reverse Proxy)์—์„œ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ฐ˜์˜๋˜์ง€ ์•Š๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค.

  • ์•Œ๋ฆผ์ด ์ฆ‰์‹œ ์ˆ˜์‹ ๋˜์ง€ ์•Š์Œ
  • ํŽ˜์ด์ง€ ์ƒˆ๋กœ๊ณ ์นจ ์‹œ์—๋งŒ ์•Œ๋ฆผ์ด ๋„์ฐฉ
  • ์„œ๋ฒ„ ๋กœ๊ทธ ์ƒ ์ด๋ฒคํŠธ๋Š” ์ •์ƒ์ ์œผ๋กœ ๋ฐœํ–‰๋จ

๐Ÿ‘‰ ํ”„๋ก ํŠธ/๋ฐฑ์—”๋“œ ์ฝ”๋“œ์—๋Š” ๋ฌธ์ œ๊ฐ€ ์—†์–ด ๋ณด์˜€์ง€๋งŒ, ์‹ค์ œ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์€ ์‹ค์‹œ๊ฐ„์ด ์•„๋‹ˆ์—ˆ์Œ


๐Ÿ” ์›์ธ ๋ถ„์„

1๏ธโƒฃ ๋ฐฐํฌ ํ™˜๊ฒฝ์—์„œ๋งŒ ๋ฐœ์ƒํ•˜๋Š” ํ˜„์ƒ

  • ๋กœ์ปฌ(Spring Boot ์ง์ ‘ ์—ฐ๊ฒฐ) โ†’ ์ •์ƒ
  • ๋ฐฐํฌ(Vercel โ†’ Nginx โ†’ Spring Boot) โ†’ ์ง€์—ฐ ๋ฐœ์ƒ

โ†’ ์ธํ”„๋ผ ๋ ˆ๋ฒจ ์ด์Šˆ ๊ฐ€๋Šฅ์„ฑ ํŒ๋‹จ

2๏ธโƒฃ Nginx Reverse Proxy ๊ธฐ๋ณธ ๋™์ž‘

  • Nginx๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์‘๋‹ต ๋ฒ„ํผ๋ง(proxy buffering)์„ ํ™œ์„ฑํ™”
  • ์ผ์ • ํฌ๊ธฐ ๋˜๋Š” ์กฐ๊ฑด์ด ์ถฉ์กฑ๋  ๋•Œ๊นŒ์ง€ ์‘๋‹ต์„ ๋ชจ์•„์„œ ์ „์†ก

3๏ธโƒฃ SSE ํŠน์„ฑ๊ณผ์˜ ์ถฉ๋Œ

  • SSE๋Š” ์ŠคํŠธ๋ฆฌ๋ฐ ๋ฐฉ์‹์œผ๋กœ ์ด๋ฒคํŠธ๋ฅผ ์ฆ‰์‹œ ์ „์†กํ•ด์•ผ ํ•จ

  • ๊ทธ๋Ÿฌ๋‚˜:

    • ์•Œ๋ฆผ payload๊ฐ€ ์ž‘์Œ
    • ๋ฒ„ํผ ์กฐ๊ฑด์„ ์ถฉ์กฑํ•˜์ง€ ๋ชปํ•ด ์ „์†ก์ด ์ง€์—ฐ
    • ๊ฒฐ๊ณผ์ ์œผ๋กœ โ€œ์•ˆ ์˜ค๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๋Š”โ€ ํ˜„์ƒ ๋ฐœ์ƒ

๐Ÿ“Œ SSE๋Š” ์„œ๋ฒ„ ์ฝ”๋“œ๋ฟ ์•„๋‹ˆ๋ผ ํ”„๋ก์‹œ ์„ค์ •์— ๊ฐ•ํ•˜๊ฒŒ ์˜์กดํ•˜๋Š” ๊ธฐ์ˆ 


๐Ÿ›  ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

Nginx SSE ์ „์šฉ ์„ค์ • ๋ถ„๋ฆฌ

SSE ์—”๋“œํฌ์ธํŠธ(/api/v1/sse/subscribe)์— ๋Œ€ํ•ด์„œ๋งŒ ์‘๋‹ต ๋ฒ„ํผ๋ง ๋น„ํ™œ์„ฑํ™” ๋ฐ ์ŠคํŠธ๋ฆฌ๋ฐ ์„ค์ • ์ ์šฉ

location /api/v1/sse/subscribe {
    proxy_pass http://backend;
    proxy_buffering off;
    proxy_cache off;

    proxy_set_header Connection keep-alive;
    proxy_set_header Cache-Control no-cache;
    proxy_set_header X-Accel-Buffering no;
}

์ ์šฉ ํฌ์ธํŠธ

  • proxy_buffering off : ์‘๋‹ต ์ฆ‰์‹œ ์ „๋‹ฌ
  • X-Accel-Buffering: no : Nginx ๋‚ด๋ถ€ ๋ฒ„ํผ๋ง ์™„์ „ ์ฐจ๋‹จ
  • Connection: keep-alive : SSE ์—ฐ๊ฒฐ ์œ ์ง€
  • ์ผ๋ฐ˜ API์™€ SSE ์„ค์ •์„ ๋ถ„๋ฆฌํ•˜์—ฌ ์˜ํ–ฅ ์ตœ์†Œํ™”

โœ… ๊ฒฐ๊ณผ

ํ•ญ๋ชฉ ๊ฐœ์„  ์ „ ๊ฐœ์„  ํ›„
์•Œ๋ฆผ ์ˆ˜์‹  ์‹œ์  ์ƒˆ๋กœ๊ณ ์นจ ํ•„์š” ์ฆ‰์‹œ ์ˆ˜์‹ 
SSE ์—ฐ๊ฒฐ ์•ˆ์ •์„ฑ ๋ถˆ์•ˆ์ • ์•ˆ์ •์  ์œ ์ง€
๋กœ์ปฌ/๋ฐฐํฌ ํ™˜๊ฒฝ ๋™์ž‘ ๋ถˆ์ผ์น˜ ๋™์ž‘ ๋™์ผ

๐Ÿ‘‰ ๋ฐฐํฌ ํ™˜๊ฒฝ์—์„œ๋„ SSE ์‹ค์‹œ๊ฐ„ ์•Œ๋ฆผ ์ •์ƒ ๋™์ž‘ ํ™•์ธ


๐Ÿ’ก ๋ฐฐ์šด ์ 

  • SSE๋Š” ๋ฐฑ์—”๋“œ ์ฝ”๋“œ๋งŒ์œผ๋กœ ์™„์„ฑ๋˜์ง€ ์•Š๋Š” ๊ธฐ์ˆ 
  • ํ”„๋ก์‹œยท๋„คํŠธ์›Œํฌยท์ธํ”„๋ผ ์„ค์ •์ด ํ•ต์‹ฌ ์š”์†Œ
  • ๋กœ์ปฌ ํ…Œ์ŠคํŠธ๋งŒ์œผ๋กœ๋Š” ์‹ค์‹œ๊ฐ„ ๊ธฐ๋Šฅ์˜ ์™„์„ฑ๋„๋ฅผ ๋ณด์žฅํ•  ์ˆ˜ ์—†์Œ
  • ์‹ค์‹œ๊ฐ„ ๊ธฐ๋Šฅ(SSE, WebSocket)์€ ๋ฐ˜๋“œ์‹œ ๋ฐฐํฌ ํ™˜๊ฒฝ ๊ธฐ์ค€์œผ๋กœ ๊ฒ€์ฆํ•ด์•ผ ํ•จ

โœ… ์ตœ์ข… ์ •๋ฆฌ

  • ๋ฌธ์ œ ์›์ธ์€ ์ฝ”๋“œ๊ฐ€ ์•„๋‹Œ Nginx Reverse Proxy ์‘๋‹ต ๋ฒ„ํผ๋ง
  • SSE ์—”๋“œํฌ์ธํŠธ์— ํ•œํ•ด ์ŠคํŠธ๋ฆฌ๋ฐ ์„ค์ • ๋ถ„๋ฆฌ ์ ์šฉ
  • ๋ฐฐํฌ ํ™˜๊ฒฝ์—์„œ๋„ ์‹ค์‹œ๊ฐ„ ์•Œ๋ฆผ ์•ˆ์ •ํ™”
  • ์‹ค์‹œ๊ฐ„ ์‹œ์Šคํ…œ ์„ค๊ณ„ ์‹œ ์ธํ”„๋ผ๊นŒ์ง€ ํฌํ•จํ•œ ๊ด€์ ์˜ ์ค‘์š”์„ฑ ์ฒด๊ฐ

3. MCP Tool Calling ๋ฐฐํฌ ํ™˜๊ฒฝ ๋ถˆ์•ˆ์ • ์ด์Šˆ ํ•ด๊ฒฐ

๐Ÿ“Œ ๋ฌธ์ œ ์ƒํ™ฉ

๋กœ์ปฌ์—์„œ๋Š” ๋ฉด์ ‘ ์ƒ์„ฑ/์ข…๋ฃŒ ์‹œ AI๊ฐ€ MCP tool์„ ํ˜ธ์ถœํ•ด ์งˆ๋ฌธ/์š”์•ฝ์„ ์ €์žฅํ•˜๋Š” ํ๋ฆ„์ด ์ •์ƒ์ธ๋ฐ, ๋ฐฐํฌ ํ™˜๊ฒฝ์—์„œ ๊ฐ„ํ—์ ์œผ๋กœ ํ๋ฆ„์ด ๊นจ์กŒ๋‹ค.

  • LLM์ด get_interview_context, save_interview_questions ๊ฐ™์€ tool์„ ์•ˆ ๋ถ€๋ฅด๊ณ  ํ…์ŠคํŠธ๋กœ๋งŒ ๋‹ตํ•จ(์‹ค์ œ๋ก  tool ํ˜ธ์ถœ ์‹คํŒจ/๋ฏธ์ ์šฉ์œผ๋กœ ๋ณด์ž„)
  • ๋กœ์ปฌ์€ ์ •์ƒ์ธ๋ฐ ๋ฐฐํฌ์—์„œ๋งŒ ๊ฐ„ํ— ์‹คํŒจ
  • tool calling์€ ์™•๋ณต์ด ๋งŽ์•„ ์ฒด๊ฐ ์ง€์—ฐ์ด ์ปค์ง
  • ์–ด๋””์„œ ๋ง‰ํžˆ๋Š”์ง€ ์ถ”์ ์ด ์–ด๋ ค์›€(ํ”„๋ก ํŠธ/ํ”„๋ก์‹œ/๋ฐฑ์—”๋“œ/LLM/์›๊ฒฉ MCP)

๐Ÿ” ์›์ธ ๋ถ„์„

1๏ธโƒฃ ์ธ์ฆ/์„ธ์…˜ ์ „๋‹ฌ ๋‹จ์ ˆ (CORS + Cookie/SameSite + ํ”„๋ก์‹œ ํ—ค๋”)

๋ฐฐํฌ ํ™˜๊ฒฝ์—์„œ๋Š” ์š”์ฒญ์ด ํฌ๋กœ์Šค ์‚ฌ์ดํŠธ + ํ”„๋ก์‹œ ๊ฒฝ์œ ๊ฐ€ ๋˜๋ฉด์„œ, ๋กœ์ปฌ์—์„  ๋ฌธ์ œ ์—†๋˜ ์ธ์ฆ ์ „๋‹ฌ์ด tool ๊ตฌ๊ฐ„์—์„œ๋งŒ ๋Š๊ฒผ๋‹ค.

๋Œ€ํ‘œ ํŒจํ„ด:

  • credentials๊ฐ€ ํฌํ•จ๋œ CORS ์„ค์ • ๋ฏธํก(Origin/Allow-Credentials ๋ถˆ์ผ์น˜)
  • Cookie๊ฐ€ SameSite/Secure ์กฐ๊ฑด ๋•Œ๋ฌธ์— ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ „์†ก๋˜์ง€ ์•Š์Œ
  • Nginx๊ฐ€ Authorization, Cookie, X-Forwarded-* ๊ฐ™์€ ํ—ค๋”๋ฅผ ์ œ๋Œ€๋กœ ์ „๋‹ฌํ•˜์ง€ ์•Š์•„ ๋ฐฑ์—”๋“œ์—์„œ ์ธ์ฆ ์‹คํŒจ โ†’ tool endpoint ์ง„์ž… ์‹œ 401/403 ์—๋Ÿฌ โ†’ LLM์€ tool ๊ฒฐ๊ณผ๋ฅผ ๋ชป ๋ฐ›์•„ fallback ๋‹ต๋ณ€ ์ƒ์„ฑ

2๏ธโƒฃ ์ถ”๊ฐ€ HTTP ์™•๋ณต์œผ๋กœ ์ธํ•œ ์ง€์—ฐ/ํƒ€์ž„์•„์›ƒ (tool calling ๊ตฌ์กฐ์  ํŠน์„ฑ)

tool calling์€ ์ผ๋ฐ˜ LLM ํ˜ธ์ถœ ๋Œ€๋น„ ์™•๋ณต์ด ํฌ๊ฒŒ ๋Š˜์–ด๋‚œ๋‹ค.

๋กœ์ปฌ์—์„  ๋„คํŠธ์›Œํฌ/ํ”„๋ก์‹œ๊ฐ€ ์—†์œผ๋‹ˆ ๋ฒ„ํ…ผ์ง€๋งŒ, ๋ฐฐํฌ์—์„  ์•„๋ž˜๊ฐ€ ๋™์‹œ์— ํ„ฐ์กŒ๋‹ค.

  • LLM ์‘๋‹ต โ†’ tool ํ˜ธ์ถœ โ†’ ๋‚ด๋ถ€ API/DB ์กฐํšŒ โ†’ ๋‹ค์‹œ LLM๋กœ ๊ฒฐ๊ณผ ์ „๋‹ฌ

    ์ด ์ฒด์ธ์—์„œ ํ•œ ๊ตฐ๋ฐ๋งŒ ๋А๋ ค๋„ ์ „์ฒด๊ฐ€ timeout ๋˜๋Š” ํ˜„์ƒ

  • Nginx ๊ธฐ๋ณธ timeout(proxy_read_timeout ๋“ฑ) / upstream timeout์ด tool ์™•๋ณต ์‹œ๊ฐ„์„ ๋ชป ๋ฒ„ํŒ€

  • ๋กœ๊ทธ๊ฐ€ ๋ถ„์‚ฐ๋˜์–ด โ€œ์–ด๋””์„œ ๋А๋ ค์กŒ๋Š”์ง€โ€ ํ•œ ๋ฒˆ์— ์•ˆ ๋ณด์ž„ โ†’ timeout/์žฌ์‹œ๋„/๊ฐ„ํ— ์‹คํŒจ โ†’ โ€œ๋ฐฐํฌ์—์„œ๋งŒ ํ๋ฆ„์ด ๊นจ์งโ€์œผ๋กœ ์ฒด๊ฐ


๐Ÿ›  ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

1๏ธโƒฃ ์ธ์ฆ ์ „๋‹ฌ ์•ˆ์ •ํ™” (๋ฐฐํฌ ๊ธฐ์ค€์œผ๋กœ ๊ณ ์ •)

  • CORS: ํŠน์ • Origin ๋ช…์‹œ + allowCredentials(true) ์ •๋ฆฌ
  • Cookie ์ •์ฑ…: ํฌ๋กœ์Šค ์‚ฌ์ดํŠธ ์š”๊ตฌ์‚ฌํ•ญ์— ๋งž๊ฒŒ SameSite=None; Secure ๋“ฑ ์ •๋ฆฌ(์‚ฌ์šฉ ๊ตฌ์กฐ์— ๋งž์ถฐ)
  • Nginx ํ”„๋ก์‹œ ํ—ค๋” ์ „๋‹ฌ ๊ฐ•ํ™”
    • Authorization, Cookie, X-Forwarded-Proto, X-Forwarded-For, Host ๋“ฑ ์ „๋‹ฌ ๋ˆ„๋ฝ ๋ฐฉ์ง€
  • tool endpoint์—์„œ ์ธ์ฆ ์‹คํŒจ ์‹œ ์ฆ‰์‹œ ์‹๋ณ„๋˜๊ฒŒ ์—๋Ÿฌ/๋กœ๊ทธ ๋ณด๊ฐ•

2๏ธโƒฃ ํƒ€์ž„์•„์›ƒ/์™•๋ณต ๋Œ€์‘ (tool route ์ค‘์‹ฌ์œผ๋กœ)

  • Nginx / ๋ฐฑ์—”๋“œ timeout ์ƒํ–ฅ(ํŠนํžˆ tool ํ˜ธ์ถœ ๊ฒฝ๋กœ)
  • keep-alive ๋ฐ upstream ์„ค์ • ์ •๋ฆฌ
  • ๋กœ๊ทธ ์ถ”์  ์žฅ์น˜ ์ถ”๊ฐ€
    • ์š”์ฒญ ๋‹จ์œ„ Correlation ID
    • tool ํ˜ธ์ถœ ์‹œ์ž‘/์ข…๋ฃŒ/์†Œ์š”์‹œ๊ฐ„ ๋กœ๊ทธ
    • ์™ธ๋ถ€ ํ˜ธ์ถœ(OpenAI/๋‚ด๋ถ€ API) ์†Œ์š”์‹œ๊ฐ„ ๋ถ„๋ฆฌ ๋กœ๊น…

๋ฐฐํฌ ํ™˜๊ฒฝ์—์„œ โ€œ๋„๊ตฌ๊ฐ€ ์‹ค์ œ๋กœ ๋กœ๋”ฉ/์ฃผ์ž…๋˜๋Š”์ง€โ€๋ฅผ ๋จผ์ € ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด, ์›๊ฒฉ MCP Tool ๋ชฉ๋ก์„ ๋กœ๊น…ํ•˜๊ณ  ChatClient ๊ธฐ๋ณธ ToolCallbacks๋กœ ์„ธํŒ…ํ–ˆ๋‹ค.

@Bean
public ChatClient chatClient(ChatClient.Builder builder,
                             SyncMcpToolCallbackProvider mcpToolCallbackProvider) {

    ToolCallback[] callbacks = mcpToolCallbackProvider.getToolCallbacks();
    log.info("[MCP] ์›๊ฒฉ MCP Tool ๊ฐœ์ˆ˜ = {}", callbacks.length);
    for (ToolCallback cb : callbacks) {
        log.info("[MCP] ToolCallback = {}", cb);
    }

    return builder
            .defaultToolCallbacks(callbacks)
            .defaultAdvisors(new SimpleLoggerAdvisor())
            .build();
}

์ถ”๊ฐ€๋กœ tool endpoint์—์„œ โ€œ์ง„์ž…/์„ฑ๊ณต/์‹คํŒจโ€ ๋กœ๊ทธ๋ฅผ ๊ณ ์ •ํ•ด LLM์ด ๋„๊ตฌ๋ฅผ ์•ˆ ๋ถ€๋ฅธ ๊ฑด์ง€ vs ๋ถˆ๋ €๋Š”๋ฐ ์‹คํŒจํ•œ ๊ฑด์ง€๋ฅผ ๋ถ„๋ฆฌํ–ˆ๋‹ค.

log.info("[MCP] saveInterviewQuestions called interviewId={}, rawSize={}",
        interviewId, questionList != null ? questionList.size() : -1);

try {
    ...
    interviewQuestionService.updateQuestionsBySystem(interviewId, requestDto);
    log.info("[MCP] saveInterviewQuestions success interviewId={}, savedCount={}",
            interviewId, items.size());
} catch (Exception e) {
    log.error("[MCP] saveInterviewQuestions FAILED interviewId={}, reason={}",
            interviewId, e.getMessage(), e);
    throw e;
}

โœ… ๊ฒฐ๊ณผ

  • ๋ฐฐํฌ ํ™˜๊ฒฝ์—์„œ tool calling ํฌํ•จ ์š”์ฒญ์˜ 401/403/timeout ๋นˆ๋„ ๊ฐ์†Œ
  • LLM์ด tool ๊ฒฐ๊ณผ๋ฅผ ์ •์ƒ ์ˆ˜์‹ ํ•˜๋ฉด์„œ โ€œ์ž„์˜ ๋‹ต๋ณ€ ์ƒ์„ฑโ€ ํ˜„์ƒ ํ•ด์†Œ
  • ๋ณ‘๋ชฉ ๊ตฌ๊ฐ„์ด ๋กœ๊ทธ๋กœ ๋ถ„ํ•ด๋˜์–ด, ์ดํ›„ ์„ฑ๋Šฅ/์•ˆ์ •ํ™” ์ž‘์—…์ด ๊ฐ€๋Šฅํ•ด์ง

๐Ÿ’ก ๋ฐฐ์šด ์ 

  • tool calling์€ โ€œ๋ชจ๋ธ ๊ธฐ๋Šฅโ€์ด ์•„๋‹ˆ๋ผ โ€œ๋ถ„์‚ฐ ์š”์ฒญ ์ฒด์ธโ€์ด๋‹ค
  • ๋กœ์ปฌ ์„ฑ๊ณต์€ ์˜๋ฏธ๊ฐ€ ์•ฝํ•˜๊ณ , ๋ฐฐํฌ ํ™˜๊ฒฝ(CORS/์ฟ ํ‚ค/ํ”„๋ก์‹œ/timeout)์ด ์‹ค์ œ ์ •๋‹ต์ด๋‹ค
  • tool ๊ธฐ๋ฐ˜ ๊ธฐ๋Šฅ์€ ๊ด€์ธก(๋กœ๊ทธ/์‹œ๊ฐ„์ธก์ •/ID ์ถ”์ ) ์—†์œผ๋ฉด ๋””๋ฒ„๊น…์ด ๊ฑฐ์˜ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค

โœ… ์ตœ์ข… ์ •๋ฆฌ

  • ๋ฐฐํฌ ํ™˜๊ฒฝ์—์„œ ๋Š๊ธฐ๋˜ ์ธ์ฆ/์„ธ์…˜ ์ „๋‹ฌ(CORS, Cookie SameSite/Secure, ํ”„๋ก์‹œ ํ—ค๋”)์„ ์ •๋ฆฌํ•ด tool endpoint์˜ 401/403์„ ์ œ๊ฑฐ
  • ์›๊ฒฉ MCP ToolCallback ๋กœ๋”ฉ ์—ฌ๋ถ€๋ฅผ ๋กœ๊น…ํ•ด โ€œ๋„๊ตฌ๊ฐ€ ๋ถ™์—ˆ๋Š”์ง€โ€๋ฅผ ๋ฐฐํฌ์—์„œ ์ฆ‰์‹œ ๊ฒ€์ฆ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•จ
  • ๊ฒฐ๊ณผ์ ์œผ๋กœ ๋ฐฐํฌ ํ™˜๊ฒฝ์—์„œ๋„ tool calling ํ๋ฆ„์ด ์•ˆ์ •ํ™”๋˜์–ด ์งˆ๋ฌธ/์š”์•ฝ ์ž๋™ ์ƒ์„ฑ ํŒŒ์ดํ”„๋ผ์ธ์„ ์ผ๊ด€๋˜๊ฒŒ ์œ ์ง€

๐Ÿ“Œ ํŒ€์› ๊ตฌ์„ฑ

์œ ์Šน์ธ (ํŒ€์žฅ) ๊น€์ •ํ˜ธ ๊น€์ง€์œค ์‹ฌ์ˆ˜๋ฏผ ์œ ์Šน์žฌ ์ •๋‹ค์†”
FE, BE FE, BE FE, BE FE, BE FE, BE FE, BE

About

๐ŸŽ€ ์›ํ•˜๋Š” ์ธ์žฌ ์ฑ„์šฉ์˜ ์†Œ์šธ๋ฉ”์ดํŠธ! ์žก๋‹ค(JobDa) ๐Ÿšฉ

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 6

Languages