Skip to content
Muneo-officialPublic

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

ย 

History

194 Commits

Folders and files

Repository files navigation

MuneoAI

CI Python FastAPI MongoDB Atlas

์ธํ…Œ๋ฆฌ์–ด ๋ฆฌ๋ชจ๋ธ๋ง ๊ฐ€๊ฒฌ์  ์‚ฐ์ถœ + ๊ณ„์•ฝ์„œ ๋ฆฌ์Šคํฌ ์ง„๋‹จ API ์„œ๋ฒ„.

์‹ค์ œ ์‹œ๊ณต ์‚ฌ๋ก€ ํ†ต๊ณ„๋ฅผ ๊ทผ๊ฑฐ๋กœ ๊ฐ€๊ฒฌ์ ์„ ์‚ฐ์ถœํ•˜๊ณ , ์—…๋กœ๋“œ๋œ ๊ฒฌ์ ์„œ ์ด๋ฏธ์ง€๋ฅผ ๋ถ„์„ํ•ด ๊ณ„์•ฝ ๋ฆฌ์Šคํฌ์™€ ๊ฐ€๊ฒฉ ์ด์ƒ์น˜๋ฅผ ํƒ์ง€ํ•œ๋‹ค. ๊ฐ€๊ฒฌ์  "์ˆซ์ž" ์‚ฐ์ถœ์—๋Š” LLM์„ ์“ฐ์ง€ ์•Š๋Š”๋‹ค โ€” ์‹ ๋ขฐ์„ฑ๊ณผ ๊ฐ€๊ฒฉ ํ• ๋ฃจ์‹œ๋„ค์ด์…˜ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•œ ์˜๋„์  ์„ค๊ณ„ ๊ฒฐ์ •์ด๋‹ค.


๋ฐฐ๊ฒฝ

์ธํ…Œ๋ฆฌ์–ด ๊ฒฌ์ ์€ ํ‘œ์ค€ ๋‹จ๊ฐ€๊ฐ€ ๊ณต๊ฐœ๋ผ ์žˆ์ง€ ์•Š๊ณ  ์—…์ฒด๋ณ„ ํŽธ์ฐจ๊ฐ€ ์ปค์„œ, ์†Œ๋น„์ž๊ฐ€ "์ด ๊ฐ€๊ฒฉ์ด ํ•ฉ๋ฆฌ์ ์ธ์ง€" ํŒ๋‹จํ•  ๊ธฐ์ค€์ด ์—†๋‹ค. ์ด ํ”„๋กœ์ ํŠธ๋Š” ๋‘ ๊ฐ€์ง€ ๋ฐฉ์‹์œผ๋กœ ๊ทธ ๊ธฐ์ค€์„ ์ œ๊ณตํ•œ๋‹ค.

  1. ๊ฐ€๊ฒฌ์ : ์‹ค์ œ ๊ณ„์•ฝ ์‚ฌ๋ก€ ์ˆ˜๋ฐฑ ๊ฑด์„ ํฌ๋กค๋งํ•ด ์ง€์—ญยทํ‰์ˆ˜ยท์ž์žฌ๋“ฑ๊ธ‰ ๋“ฑ ์กฐ๊ฑด์ด ๋น„์Šทํ•œ ์‚ฌ๋ก€๋ฅผ ๊ฒ€์ƒ‰ํ•˜๊ณ , ๊ทธ ์‚ฌ๋ก€๋“ค์˜ ํ†ต๊ณ„(์ด์ƒ์น˜ ์ œ๊ฑฐ ํ›„ ๋ถ„ํฌ)๋กœ ์˜ˆ์ƒ ๋น„์šฉ ๋ฒ”์œ„๋ฅผ ๊ณ„์‚ฐํ•œ๋‹ค.
  2. ๋ฆฌ์Šคํฌ ์ง„๋‹จ: ์‚ฌ์šฉ์ž๊ฐ€ ๋ฐ›์€ ๊ฒฌ์ ์„œ ์ด๋ฏธ์ง€๋ฅผ ์—…๋กœ๋“œํ•˜๋ฉด Vision ํŒŒ์‹ฑ์œผ๋กœ ํ•ญ๋ชฉ์„ ๊ตฌ์กฐํ™”ํ•˜๊ณ , ๊ฐ™์€ ์ฝ”ํผ์Šค ๊ธฐ์ค€ ๊ฐ€๊ฒฉ๋Œ€(P10~P90)๋ฅผ ๋ฒ—์–ด๋‚˜๋Š” ํ•ญ๋ชฉ์„ ์ด์ƒ์น˜๋กœ ํ‘œ์‹œํ•œ๋‹ค.

ํ•ต์‹ฌ ์„ค๊ณ„ ๊ฒฐ์ •

๊ฒฐ์ • ์ด์œ 
๊ฐ€๊ฒฌ์  ์ˆซ์ž ์‚ฐ์ถœ์— LLM ๋ฏธ์‚ฌ์šฉ ํ†ต๊ณ„ ์ง‘๊ณ„๋Š” ๊ฒฐ์ •๋ก ์ ์ด๋ผ ์žฌํ˜„ ๊ฐ€๋Šฅํ•˜๊ณ  ๊ฐ์‚ฌ ๊ฐ€๋Šฅํ•˜๋‹ค. LLM์— ๊ฐ€๊ฒฉ ์‚ฐ์ถœ์„ ๋งก๊ธฐ๋ฉด ๊ทธ๋Ÿด๋“ฏํ•˜์ง€๋งŒ ํ‹€๋ฆฐ ์ˆซ์ž(ํ• ๋ฃจ์‹œ๋„ค์ด์…˜)๋ฅผ ๋‚ผ ์œ„ํ—˜์ด ์žˆ๊ณ , ๊ฒฌ์  ์‹œ์Šคํ…œ์—์„œ ์ด๋Š” ๊ฐ€์žฅ ์น˜๋ช…์ ์ธ ์‹คํŒจ ๋ชจ๋“œ๋‹ค. LLM์€ ์ด๋ฏธ์ง€ ํŒŒ์‹ฑยท์ž์—ฐ์–ด ๋ณด์กฐ ์—ญํ• ๋กœ๋งŒ ๊ด€์—ฌํ•œ๋‹ค.
์ ์‘ํ˜•(adaptive) RAG โ€” Stage 1~5 ์ ์ง„์  ํ•„ํ„ฐ ์™„ํ™” ํ‰์ˆ˜ยท์ง€์—ญยท์ž์žฌ๋“ฑ๊ธ‰ยท๊ณต์ข… ์กฐ๊ฑด์„ ์ „๋ถ€ ๋งŒ์กฑํ•˜๋Š” ์‚ฌ๋ก€๊ฐ€ ๋ถ€์กฑํ•˜๋ฉด ์กฐ๊ฑด์„ ๋‹จ๊ณ„์ ์œผ๋กœ ์™„ํ™”ํ•ด ์žฌ๊ฒ€์ƒ‰ํ•œ๋‹ค(self-querying ํŒจํ„ด). ์กฐ๊ฑด์„ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋А์Šจํ•˜๊ฒŒ ์žก์œผ๋ฉด ์ •ํ™•๋„๊ฐ€ ๋–จ์–ด์ง€๊ณ , ๋„ˆ๋ฌด ์—„๊ฒฉํ•˜๋ฉด ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๊ฐ€ ์—†์–ด์ง€๋Š” ๋ฌธ์ œ๋ฅผ ๋™์‹œ์— ํ•ด๊ฒฐํ•œ๋‹ค.
Chroma + MongoDB ์ด์ค‘ ๊ตฌ์กฐ โ†’ Atlas Vector Search ๋‹จ์ผํ™” ๋ฒกํ„ฐ ์ธ๋ฑ์Šค์™€ ์›๋ณธ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ถ„๋ฆฌ๋ผ ์žˆ์œผ๋ฉด ํ•œ์ชฝ๋งŒ ๊ฐฑ์‹ ๋  ๋•Œ ๊ณ ์•„ ๋ฐ์ดํ„ฐ๊ฐ€ ์ƒ๊ธด๋‹ค(์‚ฌ๋ก€๋ฅผ Mongo์—์„œ ์ง€์›Œ๋„ Chroma ๋ฒกํ„ฐ๋Š” ๋‚จ์•„ ๊ฒ€์ƒ‰๋˜๋Š” ๋“ฑ). ์ž„๋ฒ ๋”ฉ์„ ์›๋ณธ ๋ฌธ์„œ์™€ ๊ฐ™์€ ์ปฌ๋ ‰์…˜ยท๊ฐ™์€ write์— ์ €์žฅํ•ด ๋™๊ธฐํ™” ๋ฌธ์ œ๋ฅผ ๊ตฌ์กฐ์ ์œผ๋กœ ์ œ๊ฑฐํ–ˆ๋‹ค.

๊ฒ€์ƒ‰ ํ’ˆ์งˆ ๊ฒ€์ฆ

ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ๊ฒ€์ƒ‰ยท๋ฆฌ๋žญํ‚น์„ ๋ถ™์ธ ๋’ค, ์‹ค์ œ๋กœ ํ’ˆ์งˆ์ด ๊ฐœ์„ ๋๋Š”์ง€ ground truth๋ฅผ ์ง์ ‘ ๊ตฌ์ถ•ํ•ด ์ธก์ •ํ–ˆ๋‹ค.

TREC ์Šคํƒ€์ผ pooling์œผ๋กœ 24๊ฐœ ์ฟผ๋ฆฌ์— ๋Œ€ํ•œ ๊ด€๋ จ์„ฑ ๋ผ๋ฒจ(ํ‰์ˆ˜ ยฑ5ํ‰ยท์ธ์ ‘ ์ง€์—ญยท๊ณต์ข… 1๊ฐœ ์ด์ƒ ๊ฒน์นจ์„ ์ „๋ถ€ ๋งŒ์กฑํ•ด์•ผ relevant)์„ ๋งŒ๋“ค๊ณ  ์—ฌ๋Ÿฌ ๋‹จ๊ณ„๋ฅผ ๊ฐ™์€ ๊ธฐ์ค€์œผ๋กœ ๋น„๊ตํ–ˆ๋‹ค.

๋‹จ๊ณ„ precision@15 ๋น„๊ณ 
๋ฒกํ„ฐ ๊ฒ€์ƒ‰ ๋‹จ๋… (ํ•„ํ„ฐ ์—†์Œ) 17.2% ์ˆœ์ˆ˜ ํ…์ŠคํŠธ ์œ ์‚ฌ๋„๋งŒ
+ ํ•˜์ด๋ธŒ๋ฆฌ๋“œ(BM25+RRF) + Cross-Encoder ๋ฆฌ๋žญํ‚น (ํ•„ํ„ฐ ์—†์Œ) 20.6% (+3.4%p)
+ Stage ํ•„ํ„ฐ(ํ‰์ˆ˜ยท์ง€์—ญยท๊ณต์ข…, ์ ์ง„์  ์™„ํ™”) ์ ์šฉ, ๋ฒกํ„ฐ ๋‹จ๋… 78.0% (+57.4%p)
+ Stage ํ•„ํ„ฐ + ํ•˜์ด๋ธŒ๋ฆฌ๋“œ + ๋ฆฌ๋žญํ‚น (์‹ค์ œ ์„œ๋น„์Šค ๊ฒฝ๋กœ) 82.5% (+4.5%p)
+ ์‹คํŒจ ์ฟผ๋ฆฌ ๋ถ„์„ ๊ธฐ๋ฐ˜ ํ‰์ˆ˜ ํ•„ํ„ฐ ํŠœ๋‹(ยฑ7ํ‰โ†’ยฑ5ํ‰) 93.2% (+10.7%p)
+ ํ‰์ˆ˜ ํ•„ํ„ฐ ์žฌ์กฐ์ •(ยฑ5ํ‰โ†’ยฑ6ํ‰), ๋น„์ฃผ๊ฑฐ ์ œ์™ธ ๋ฐ˜์˜ 93.2% (๊ฐ™์€ ์กฐ๊ฑด ยฑ5ํ‰ 93.1%) ์ตœ์ข… โ€” ๋น„๊ต

ํ•ต์‹ฌ ์ง€๋ ›๋Œ€๋Š” ๊ตฌ์กฐ์  ํ•„ํ„ฐ๋ง์ด๋‹ค. ๋ฒกํ„ฐ ์œ ์‚ฌ๋„๋งŒ์œผ๋กœ๋Š” ์„œ์šธ ์ฟผ๋ฆฌ์— ๋ถ€์‚ฐ ์‚ฌ๋ก€๊ฐ€ ์„ž์ด๋Š” ๋“ฑ ๊ด€๋ จ ์—†๋Š” ๊ฒฐ๊ณผ๊ฐ€ ๋งŽ์ด ์„ž์—ฌ ์ •๋ฐ€๋„๊ฐ€ 17.2%์— ๊ทธ์ณค๋Š”๋ฐ, ๊ฒ€์ƒ‰ ์ „์— ํ‰์ˆ˜ยท์ง€์—ญยท๊ณต์ข… ์กฐ๊ฑด์œผ๋กœ ํ›„๋ณด๋ฅผ ๋ฏธ๋ฆฌ ์ขํžˆ๋Š” Stage ํ•„ํ„ฐ(์กฐ๊ฑด์„ ๋‹ค ๋งŒ์กฑํ•˜๋Š” ์‚ฌ๋ก€๊ฐ€ 3๊ฑด ๋ฏธ๋งŒ์ด๋ฉด ๋‹จ๊ณ„์ ์œผ๋กœ ์™„ํ™”, SIZE_RANGEโ†’ ์ง€์—ญโ†’ํ‰์ˆ˜ ์ˆœ์œผ๋กœ relax) ํ•˜๋‚˜๋งŒ์œผ๋กœ 78.0%๊นŒ์ง€ ๋›ด๋‹ค. ํ•˜์ด๋ธŒ๋ฆฌ๋“œ+๋ฆฌ๋žญํ‚น์€ ์ด ์œ„์— ์–น์–ด๋„ ๊พธ์ค€ํžˆ ์œ ์˜๋ฏธํ•œ ๊ฐœ์„ (+4.5%p)์„ ๋ƒˆ๋‹ค.

๊ทธ ๋‹ค์Œ, ์ •๋ฐ€๋„๊ฐ€ ๊ฐ€์žฅ ๋‚ฎ์€ ์ฟผ๋ฆฌ๋“ค์„ ์ง์ ‘ ๊นŒ๋ณธ ์‹คํŒจ ๋ถ„์„์—์„œ "ํ‰์ˆ˜์ฐจ์ด=7ํ‰(ํ•„ํ„ฐ ์ตœ๋Œ€ ๊ด€์šฉ์น˜)"์ธ ํ›„๋ณด์˜ relevant ๋น„์œจ๋งŒ ์œ ๋… 22.2%๋กœ ์ ˆ๋ฒฝ์ฒ˜๋Ÿผ ๋–จ์–ด์ง€๋Š” ๊ฑธ ๋ฐœ๊ฒฌํ–ˆ๋‹ค โ€” ํ•„ํ„ฐ ๊ด€์šฉ์น˜(ยฑ7ํ‰)๊ฐ€ ์‹ค์ œ ๋ผ๋ฒจ ๊ธฐ์ค€(ยฑ5ํ‰)๋ณด๋‹ค ๋А์Šจํ•˜๊ฒŒ ์žกํ˜€ ์žˆ๋˜ ๋ถˆ์ผ์น˜์˜€๋‹ค. ํ•„ํ„ฐ๋ฅผ ๋ผ๋ฒจ ๊ธฐ์ค€์— ๋งž์ถฐ ์ขํžˆ์ž 82.5%โ†’93.2%๋กœ ์ถ”๊ฐ€ ๊ฐœ์„ ๋๊ณ , Stage ์ฑ„ํƒ ๋ถ„ํฌ(24๊ฐœ ์ฟผ๋ฆฌ ์ค‘ ์ง€์—ญ ์กฐ๊ฑด๊นŒ์ง€ ์™„ํ™”๋œ ๊ฑด 1๊ฐœ๋ฟ)๋กœ ๋ถ€์ž‘์šฉ์ด ์—†์Œ์„ ๊ฐ™์ด ๊ฒ€์ฆํ–ˆ๋‹ค.

์ดํ›„ ๊ธ‰๋ฝ ์ง€์ ์ด ์ •ํ™•ํžˆ 6ํ‰๊ณผ 7ํ‰ ์‚ฌ์ด๋ผ๋Š” ์ ์„ ๋‹ค์‹œ ํ™•์ธํ•˜๋ ค๊ณ  ยฑ5/ยฑ6/ยฑ7์„ ๊ฐ™์€ ๋ผ๋ฒจ์…‹ยท๊ฐ™์€ ํŒŒ์ดํ”„๋ผ์ธ์œผ๋กœ ๋น„๊ตํ–ˆ๋‹ค(size_range_comparison.md). ยฑ6๊ณผ ยฑ5์˜ precision@15๋Š” 93.2% vs 93.1%๋กœ ์ฐจ์ด๊ฐ€ ๋…ธ์ด์ฆˆ ๋ฒ”์œ„(์ฟผ๋ฆฌ ๋‹จ์œ„ ๋ถ€ํŠธ์ŠคํŠธ๋žฉ 95% ๊ตฌ๊ฐ„ โˆ’5.7~+7.1%p)์˜€์ง€๋งŒ, ยฑ6์€ ์ฟผ๋ฆฌ๋‹น ํ›„๋ณด๋ฅผ ๋” ํ™•๋ณดํ•˜๊ณ (์ค‘์•™๊ฐ’ 15โ†’19๊ฑด) ์‚ฌ๋ก€ ๋ถ€์กฑ์œผ๋กœ ์ง€์—ญ ์กฐ๊ฑด๊นŒ์ง€ ํ’€๋ฆฌ๋˜ ์ฟผ๋ฆฌ๋ฅผ ์—†์• ์„œ SIZE_RANGE๋ฅผ 6์œผ๋กœ ์กฐ์ •ํ–ˆ๋‹ค. ยฑ7์€ 82.1%๋กœ ์—ฌ์ „ํžˆ 11%p ๋‚ฎ๋‹ค.

์ด ๊ณผ์ •์—์„œ ์ฝ”ํผ์Šค ์ž์ฒด์˜ ๋ฐ์ดํ„ฐ ํ’ˆ์งˆ ๋ฌธ์ œ(ํฌ๋กค๋Ÿฌ race condition์œผ๋กœ ๊ฒŒ์‹œ๊ธ€ 693/855๊ฑด์ด ์ œ๋ชฉ๊ณผ ์‹ค์ œ ์ €์žฅ ๋‚ด์šฉ์ด ๋‹ค๋ฅธ ์ƒํƒœ์˜€์Œ)์™€, ๊ธฐ์กด ํ‰๊ฐ€ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์‹ค์ œ ์„œ๋น„์Šค๊ฐ€ ์“ฐ๋Š” Stage ํ•„ํ„ฐ๋ฅผ ์ „ํ˜€ ํ…Œ์ŠคํŠธํ•˜์ง€ ์•Š๊ณ  ์žˆ๋˜ ๋ฐฉ๋ฒ•๋ก  ๊ฒฐํ•จ๋„ ํ•จ๊ป˜ ์ฐพ์•„ ๊ณ ์ณค๋‹ค โ€” ์œ„ ํ‘œ์˜ ์•ž ๋‘ ํ–‰(ํ•„ํ„ฐ ์—†์Œ)๊ณผ ๋’ค ์„ธ ํ–‰ (Stage ํ•„ํ„ฐ ํฌํ•จ, ์‹ค์ œ production ๊ฒฝ๋กœ)์ด ๊ฐˆ๋ผ์ง€๋Š” ์ง€์ ์ด ๊ทธ ๊ฒฐํ•จ์„ ๋ฐ”๋กœ์žก์€ ๊ฒฐ๊ณผ๋‹ค.

์‹คํŒจ โ†’ ์ˆ˜์ •: Swagger๋กœ ์ง์ ‘ ๊ฒ€์ฆํ•˜๋‹ค ์ฐพ์€ ๋ฒ„๊ทธ 2๊ฑด

์ •๋Ÿ‰ ์ง€ํ‘œ๋งŒ์œผ๋กœ๋Š” ์•ˆ ์žกํžˆ๋Š” ๋ฌธ์ œ๋„ ์žˆ์—ˆ๋‹ค. ์‹ค์ œ API ์‘๋‹ต์„ Swagger๋กœ ์ง์ ‘ ๊นŒ๋ณด๋‹ค๊ฐ€ "18ํ‰ ์ˆ˜๋„๊ถŒ ์ „์ฒด๋ฆฌ๋ชจ๋ธ๋ง" ์š”์ฒญ์˜ ์ฐธ๊ณ  ์‚ฌ๋ก€ ํ•˜๋‚˜๊ฐ€ ํ‰๋‹น 396๋งŒ์›(๋‹ค๋ฅธ ์‚ฌ๋ก€ ๋Œ€๋น„ 2~4๋ฐฐ)์œผ๋กœ ํŠ€๋Š” ๊ฑธ ๋ฐœ๊ฒฌํ–ˆ๋‹ค โ€” DB๋ฅผ ์—ด์–ด๋ณด๋‹ˆ ํฌ๋กค๋ง ์˜ค๋ฅ˜๊ฐ€ ์•„๋‹ˆ๋ผ ํ™”์žฌ ํ”ผํ•ด ์ƒ๊ฐ€์ฃผํƒ ์ „๋ฉด ์ฒ ๊ฑฐยท๋ณต๊ตฌ ๊ณต์‚ฌ์˜€๋‹ค. DB์— ๊ณต๊ฐ„์œ ํ˜• ํ•„๋“œ๊ฐ€ ์—†์–ด ํ‰์ˆ˜ยท์ง€์—ญยท๊ณต์ข…๋งŒ์œผ๋กœ๋Š” ์ด๋Ÿฐ ์ผ€์ด์Šค๋ฅผ ๊ฑธ๋Ÿฌ๋‚ผ ๋ฐฉ๋ฒ•์ด ์—†์—ˆ๋˜ ๊ฒƒ. ์ฝ”ํผ์Šค 709๊ฑด์„ ํ‚ค์›Œ๋“œ๋กœ ์Šค์บ”ํ•ด ์ƒ๊ฐ€/๊ณต์žฅ ๋“ฑ ๋น„์ฃผ๊ฑฐ ์‚ฌ๋ก€ 9๊ฑด์„ ํ™•์ธํ•˜๊ณ  ๊ฒ€์ƒ‰์—์„œ ํ•ญ์ƒ ์ œ์™ธํ•˜๋„๋ก ๊ณ ์ณค๋‹ค(app/repositories/case_repository.py). ๊ฐ™์€ ์ž๋ฆฌ์—์„œ "ํ‰๋‹น ๋‹จ๊ฐ€๊ฐ€ 0์œผ๋กœ ๋‚˜์˜ค๋Š”" ๋ณ„๊ฐœ ๋ฒ„๊ทธ๋„ ์ฐพ์•˜๋‹ค โ€” ingest ์‹œ์ ์— ๋ฏธ๋ฆฌ ๊ณ„์‚ฐํ•ด ์ €์žฅํ•ด๋‘” ํ•„๋“œ๋ฅผ ๊ทธ๋Œ€๋กœ ์ฝ์–ด์˜ค๋Š” ๊ตฌ์กฐ๋ผ, size_pyeong์ด ๋‚˜์ค‘์— ๋ณด์ •๋œ 116๊ฑด(16%)์€ ์ด๊ธˆ์•กยทํ‰์ˆ˜๋Š” ์ •์ƒ์ธ๋ฐ ํ‰๋‹น๋งŒ 0์œผ๋กœ ๋‚จ์•„ ์žˆ์—ˆ๋‹ค. ์ €์žฅ๊ฐ’์„ ์‹ ๋ขฐํ•˜์ง€ ์•Š๊ณ  ๋งค๋ฒˆ total_cost/size_pyeong์œผ๋กœ ๋‹ค์‹œ ๊ณ„์‚ฐํ•˜๋„๋ก ๊ณ ์ณค๋‹ค.

๊ฐ™์€ ์š”์ฒญ์„ ์ˆ˜์ • ์ „/ํ›„๋กœ ๋น„๊ตํ•˜๋ฉด ์ฐจ์ด๊ฐ€ ๊ทธ๋Œ€๋กœ ๋“œ๋Ÿฌ๋‚œ๋‹ค(POST /estimates/generate, 18ํ‰ยท์ˆ˜๋„๊ถŒยท ์ „์ฒด๋ฆฌ๋ชจ๋ธ๋งยท์ž์žฌ๋“ฑ๊ธ‰ ์ผ๋ฐ˜):

// ์ˆ˜์ • ์ „ โ€” ํ™”์žฌ๋ณต๊ตฌ ์ƒ๊ฐ€์ฃผํƒ ์‚ฌ๋ก€(article_id 902415)๊ฐ€ ์„ž์—ฌ ์ตœ๋Œ“๊ฐ’์„ ์™œ๊ณก
"์ฐธ๊ณ _์‚ฌ๋ก€_์ˆ˜": 5,
"์ฐธ๊ณ _์‚ฌ๋ก€": [
  { "article_id": "880006", "์ง€์—ญ": "๊ฒฝ๊ธฐ", "ํ‰์ˆ˜": 18, "์ด๊ธˆ์•ก": 18695700, "ํ‰๋‹น": 1038650 },
  { "article_id": "878202", "์ง€์—ญ": "๊ฒฝ๊ธฐ", "ํ‰์ˆ˜": 20, "์ด๊ธˆ์•ก": 23640000, "ํ‰๋‹น": 1182000 },
  { "article_id": "902415", "์ง€์—ญ": "๊ฒฝ๊ธฐ", "ํ‰์ˆ˜": 20, "์ด๊ธˆ์•ก": 79300000, "ํ‰๋‹น": 3965000 }, // โ† ํ™”์žฌ๋ณต๊ตฌ ์ƒ๊ฐ€์ฃผํƒ
  { "article_id": "883140", "์ง€์—ญ": "๊ฒฝ๊ธฐ", "ํ‰์ˆ˜": 21, "์ด๊ธˆ์•ก": 25340000, "ํ‰๋‹น": 1206666 },
  { "article_id": "876732", "์ง€์—ญ": "๊ฒฝ๊ธฐ", "ํ‰์ˆ˜": 22, "์ด๊ธˆ์•ก": 45490000, "ํ‰๋‹น": 2067727 }
],
"์ด_๊ฒฌ์ _๋ฒ”์œ„": { "์ตœ์†Œ": 18118936, "์ค‘๊ฐ„": 25592997, "์ตœ๋Œ€": 33067058 }

// ์ˆ˜์ • ํ›„ โ€” ๋น„์ฃผ๊ฑฐ ์‚ฌ๋ก€ ์ œ์™ธ, ๋‚˜๋จธ์ง€ 4๊ฑด์€ ํ‰๋‹น 100~200๋งŒ์›๋Œ€๋กœ ์ผ๊ด€
"์ฐธ๊ณ _์‚ฌ๋ก€_์ˆ˜": 4,
"์ฐธ๊ณ _์‚ฌ๋ก€": [
  { "article_id": "880006", "์ง€์—ญ": "๊ฒฝ๊ธฐ", "ํ‰์ˆ˜": 18, "์ด๊ธˆ์•ก": 18695700, "ํ‰๋‹น": 1038650 },
  { "article_id": "878202", "์ง€์—ญ": "๊ฒฝ๊ธฐ", "ํ‰์ˆ˜": 20, "์ด๊ธˆ์•ก": 23640000, "ํ‰๋‹น": 1182000 },
  { "article_id": "883140", "์ง€์—ญ": "๊ฒฝ๊ธฐ", "ํ‰์ˆ˜": 21, "์ด๊ธˆ์•ก": 25340000, "ํ‰๋‹น": 1206666 },
  { "article_id": "876732", "์ง€์—ญ": "๊ฒฝ๊ธฐ", "ํ‰์ˆ˜": 22, "์ด๊ธˆ์•ก": 45490000, "ํ‰๋‹น": 2067727 }
],
"์ด_๊ฒฌ์ _๋ฒ”์œ„": { "์ตœ์†Œ": 16647416, "์ค‘๊ฐ„": 25321596, "์ตœ๋Œ€": 33995776 }

์œ„ ์ด_๊ฒฌ์ _๋ฒ”์œ„๋Š” ์ˆ˜์ • ๋‹น์‹œ(์—”์ง„ 1.1.0 ์ด์ „)์˜ ์ถœ๋ ฅ์ด๋‹ค. ์—”์ง„ 1.2.0๋ถ€ํ„ฐ ์ค‘๊ฐ„์€ ๋ฒ”์œ„์˜ ์ค‘์ ์ด ์•„๋‹ˆ๋ผ ์ฐธ๊ณ  ์‚ฌ๋ก€ ์ด์•ก์˜ ์ค‘์•™๊ฐ’์ด๋ผ, ๊ฐ™์€ ์š”์ฒญ์„ ์ง€๊ธˆ ์‹คํ–‰ํ•˜๋ฉด ์ค‘๊ฐ„์ด ๋” ๋‚ฎ๊ฒŒ ๋‚˜์˜จ๋‹ค.

์ฐธ๊ณ _์‚ฌ๋ก€์˜ article_id๋กœ ์‹ค์ œ ์›๋ฌธ(ํฌ๋กค๋ง ๋Œ€์ƒ ๊ธ€)์„ ๋ฐ”๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด๋‘” ๊ฒƒ๋„ ์˜๋„์  ์„ค๊ณ„๋‹ค โ€” ๊ฒ€์ƒ‰๋œ ๊ทผ๊ฑฐ๋ฅผ ๊ฐ์ถ˜ ์ฑ„ ์ตœ์ข… ์ˆซ์ž๋งŒ ๋ณด์—ฌ์ฃผ๋ฉด ์ด๋Ÿฐ ์˜ค์—ผ์„ ๋ฐœ๊ฒฌํ•  ๋ฐฉ๋ฒ•์ด ์—†๋‹ค.

๊ฒ€์ฆ ๊ณผ์ •์—์„œ "cross-encoder๊ฐ€ ๊ธด ํ…์ŠคํŠธ์— ๋” ๋†’์€ ์ ์ˆ˜๋ฅผ ์ฃผ๋Š” ํŽธํ–ฅ"์„ ํ•„๋Ÿฌ ํ…์ŠคํŠธ ํŒจ๋”ฉ ์‹คํ—˜์œผ๋กœ ์ธ๊ณผ๊ด€๊ณ„๊นŒ์ง€ ํ™•์ธํ–ˆ๊ณ , ์ดˆ๊ธฐ ์‹คํ—˜ ๊ฒฐ๊ณผ๊ฐ€ ๋’ค์ง‘ํžŒ ์›์ธ(pooling ์„ค๊ณ„ ๊ฒฐํ•จ, ์ˆœํ™˜ ๋…ผ๋ฆฌ ๋ผ๋ฒจ๋ง ์‹ค์ˆ˜)๋„ ์ฐพ์•„์„œ ์ •์ •ํ–ˆ๋‹ค. ์‹คํŒจํ•œ ์‹œ๋„(ํ†ต๊ณ„์  de-biasing ๋“ฑ)๋ฅผ ํฌํ•จํ•œ ์ „์ฒด ์กฐ์‚ฌ ๊ณผ์ •์€ eval/results/reranker_hybrid_eval.md ์ฐธ๊ณ .

๊ฐ€๊ฒฌ์  ์ •ํ™•๋„(๊ณต์ข…๋ณ„ ๊ฐ€๊ฒฉ ์˜ˆ์ธก vs ์‹ค์ œ ์‚ฌ๋ก€) ์ง„๋‹จ์€ eval/results/pricing_gap_diagnostic.md ์ฐธ๊ณ .


๋ฆฌ์Šคํฌ ์ง„๋‹จ ์‘๋‹ต ์†๋„ ๊ฐœ์„ 

/risk-detector/analyze๋Š” ์—…๋กœ๋“œ๋œ ๊ฒฌ์ ์„œ ์ด๋ฏธ์ง€๋ฅผ ์ฒญํฌ ๋‹จ์œ„๋กœ ๋‚˜๋ˆ  Vision API์— ์ˆœ์ฐจ ํ˜ธ์ถœํ•˜๋Š” ๊ตฌ์กฐ๋ผ, ์ด๋ฏธ์ง€ยท์ฒญํฌ ์ˆ˜๊ฐ€ ๋Š˜์ˆ˜๋ก ์‘๋‹ต ์‹œ๊ฐ„์ด ๊ทธ๋Œ€๋กœ ์„ ํ˜•์œผ๋กœ ๋Š˜์–ด๋‚ฌ๋‹ค. ์‹ค์ œ API๋กœ ๋‹จ๊ฑด ์‘๋‹ต์‹œ๊ฐ„์„, k6๋กœ ๋™์‹œ ์‚ฌ์šฉ์ž ๋ถ€ํ•˜๋ฅผ ์ธก์ •ํ•œ ๋’ค ํ˜ธ์ถœ์„ ๋ณ‘๋ ฌํ™”ํ–ˆ๋‹ค.

์ผ€์ด์Šค (์ฒญํฌ ์ˆ˜) ๋ณ‘๋ ฌํ™” ์ „ wall p50 ๋ณ‘๋ ฌํ™” ํ›„ wall p50
5์ฒญํฌ (์‹ค์ œ API) 196.4s 73.8s (โˆ’62%)
8์ฒญํฌ (์‹ค์ œ API) 264.5s 47.9s (โˆ’82%)
๋™์‹œ ์‚ฌ์šฉ์ž (Vision ์‘๋‹ต์„ ์‹ค์ธก ์ง€์—ฐ ๋ถ„ํฌ๋กœ ์žฌํ˜„ํ•œ mock ๊ธฐ์ค€ ๋ถ€ํ•˜ ํ…Œ์ŠคํŠธ) ๋ณ‘๋ ฌํ™” ์ „ p50 ๋ณ‘๋ ฌํ™” ํ›„ p50
1๋ช… 185.5s 57.6s
5๋ช… 167.6s 53.9s

๋ฐ”๋€ ๊ฒƒ

  • ๋ชจ๋“  ์ด๋ฏธ์ง€ยท์ฒญํฌ Vision ํ˜ธ์ถœ์„ ์ˆœ์ฐจ ๋Œ€์‹  asyncio.gather๋กœ ๋™์‹œ ์‹คํ–‰ํ•˜๊ณ , ๊ฒฐ๊ณผ๋Š” ์›๋ž˜ (์ด๋ฏธ์ง€, ์ฒญํฌ) ์ˆœ์„œ๋กœ ์žฌ์กฐํ•ฉํ•ด ๊ธฐ์กด ๋ณ‘ํ•ฉ ๋กœ์ง์€ ๊ทธ๋Œ€๋กœ ์œ ์ง€
  • ๋™๊ธฐ ํด๋ผ์ด์–ธํŠธ+์Šค๋ ˆ๋“œํ’€ ๋Œ€์‹  AsyncAnthropic์œผ๋กœ ๊ต์ฒด โ€” ํ˜ธ์ถœ๋‹น ์Šค๋ ˆ๋“œ๋ฅผ ์ ์œ ํ•˜๋Š” ๊ตฌ์กฐ๋ผ ๋™์‹œ ์š”์ฒญ์ด ๋Š˜๋ฉด API ์‘๋‹ต๋ณด๋‹ค ์Šค๋ ˆ๋“œํ’€ ํฌํ™”๊ฐ€ ๋จผ์ € ๋ณ‘๋ชฉ์ด ๋์Œ
  • ๋™์‹œ ํ˜ธ์ถœ ์ƒํ•œ์„ ํ”„๋กœ์„ธ์Šค ์ „์ฒด/์š”์ฒญ๋‹น ๋‘ ๋‹จ๊ณ„๋กœ ๋‘ฌ(risk_vision_max_concurrency, risk_vision_max_concurrency_per_request) ์ƒ๋ฅ˜ API ๋ ˆ์ดํŠธ๋ฆฌ๋ฐ‹ ์ดˆ๊ณผ๋ฅผ ๋ฐฉ์ง€
  • ์ฒญํฌ ํ•˜๋‚˜๋ผ๋„ ์‹คํŒจํ•˜๋ฉด ๋‚˜๋จธ์ง€ ํ˜ธ์ถœ์„ ์ทจ์†Œํ•ด ๋ถˆํ•„์š”ํ•œ API ๋น„์šฉ ์ง€์ถœ์„ ๋ง‰์Œ
  • ์ด๋ฏธ์ง€ ๋ฆฌ์‚ฌ์ด์ฆˆยท์ธ์ฝ”๋”ฉ(CPU ๋ฐ”์šด๋“œ ์ž‘์—…)์„ ์Šค๋ ˆ๋“œํ’€๋กœ ์˜ฎ๊ฒจ ์ด๋ฒคํŠธ ๋ฃจํ”„ ๋ธ”๋กœํ‚น ์ œ๊ฑฐ

๋™์‹œ 10๋ช… ์ด์ƒ๋ถ€ํ„ฐ๋Š” ์ „์—ญ ๋™์‹œ ํ˜ธ์ถœ ์ƒํ•œ(๊ธฐ๋ณธ 20)์ด ์ฒ˜๋ฆฌ๋Ÿ‰์„ ๊ฒฐ์ •ํ•˜๋ฏ€๋กœ, ์‹ค์ œ ํŠธ๋ž˜ํ”ฝ ๊ทœ๋ชจ์— ๋งž์ถฐ ์กฐ์ •์ด ํ•„์š”ํ•˜๋‹ค.

์ธก์ • ๋ฐฉ๋ฒ•(๋ฒ ์ด์Šค๋ผ์ธ ๊ณ„์ธก, ํ…Œ์ŠคํŠธ์…‹ ์„ ์ •, k6 ๋ถ€ํ•˜ ์„ค๊ณ„)๊ณผ ์ „์ฒด ๊ฒฐ๊ณผ๋Š” pipeline/results/risk_detector_latency_optimization.md ์ฐธ๊ณ .


๋ฆฌ์Šคํฌ ์ง„๋‹จ ๋น„์šฉ ์ ˆ๊ฐ

๊ณ„์ธกํ•ด ๋ณด๋‹ˆ ๋ฆฌ์Šคํฌ ์ง„๋‹จ ๋น„์šฉ์˜ ์•ฝ 80%๊ฐ€ Vision ์ถœ๋ ฅ ํ† ํฐ์ด์—ˆ๋‹ค. ๋ฃฐ์ด ์“ฐ์ง€ ์•Š๋Š” ํ•„๋“œ๋ฅผ ์ถœ๋ ฅ์—์„œ ๋นผ๋Š” ๋ฆฌ์Šคํฌ ์ง„๋‹จ ์ „์šฉ ์Šคํ‚ค๋งˆ๋ฅผ ๋งŒ๋“ค๊ณ , ์‹ค์ธก ์›๋ณธ ์ถœ๋ ฅ์„ ์บก์ฒ˜ํ•ด ์ •ํ™•๋„ ๋ณ€ํ™”๋ฅผ ์ถ”์ ํ–ˆ๋‹ค.

์ผ€์ด์Šค (์ฒญํฌ ์ˆ˜, ์‹ค์ œ API) ์š”์ฒญ๋‹น ๋น„์šฉ wall p50
1์ฒญํฌ $0.047 โ†’ $0.034 (โˆ’29%) 34.1s โ†’ 25.5s
2์ฒญํฌ $0.125 โ†’ $0.097 (โˆ’23%) 58.8s โ†’ 47.8s
5์ฒญํฌ $0.252 โ†’ $0.206 (โˆ’18%) 71.5s โ†’ 62.9s

๋ฐ”๋€ ๊ฒƒ

  • ํ•„๋“œ๋ณ„ ์‚ฌ์šฉ์ฒ˜๋ฅผ ์กฐ์‚ฌํ•˜๊ณ  ์ฝ”ํผ์Šค 571๊ฑด์œผ๋กœ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ํ•ด unitยทquantity๋งŒ ์ œ๊ฑฐ. code(์ฒญํฌ ์ค‘๋ณต ์ œ๊ฑฐ์˜ ํ–‰ ์‹๋ณ„์ž)์™€ unit_price(๋‹จ๊ฐ€ ๋ˆ„๋ฝ ๋ฃฐ์˜ ํŠธ๋ฆฌ๊ฑฐ)๋Š” ๋นผ๋ฉด ๊ฒฐ๊ณผ๊ฐ€ ๊นจ์ ธ์„œ ์œ ์ง€
  • ํฌ๋กค๋ง ์ˆ˜์ง‘ ๊ฒฝ๋กœ๋Š” ๊ธฐ์กด ์Šคํ‚ค๋งˆ ๊ทธ๋Œ€๋กœ โ€” ์ˆ˜์ง‘ ๋ฐ์ดํ„ฐ๋Š” ๊ฐ€๊ฒฌ์  ์ฝ”ํผ์Šค๊ฐ€ ๋˜๋ฏ€๋กœ
  • ํ•„๋“œ๋ฅผ ๋นผ์ž ๋ชจ๋ธ์ด ํ•œ ์ฒญํฌ์˜ code๋ฅผ ์ƒ๋žตํ•ด ์ค‘๋ณต์ด ์ƒˆ๊ณ , ์• ๋งคํ•œ ํ•ญ๋ชฉ์˜ ๊ณต์ข… ๋ถ„๋ฅ˜๊ฐ€ ๋’ค์ง‘ํžˆ๋Š” ๊ฒƒ์„ ์›๋ณธ ์ถœ๋ ฅ ์บก์ฒ˜๋กœ ์ถ”์  โ†’ code ํ•„์ˆ˜ํ™”์™€ ํ•„๋ฆ„ ๋ถ„๋ฅ˜ ๊ทœ์น™ ํ•œ ์ค„๋กœ ๋Œ€์‘
  • ๋ถ„๋ฅ˜ ์ •ํ™•๋„๋Š” "๊ธฐ์กด๊ณผ ๊ฐ™์€๊ฐ€"๊ฐ€ ์•„๋‹ˆ๋ผ ์ •๋‹ต์„ ๋ถ™์—ฌ ์ฑ„์ : ํ”๋“ค๋ฆฐ 40๊ฐœ ํ•ญ๋ชฉ ๊ธฐ์ค€ 60% โ†’ 82%

์ธก์ • ๊ณผ์ •ยทํŒ๋‹จ ๊ทผ๊ฑฐยทํ•œ๊ณ„๋Š” pipeline/results/risk_detector_cost_optimization.md ์ฐธ๊ณ .


์•„ํ‚คํ…์ฒ˜

flowchart LR
    Client -->|"POST /estimates/generate"| API[app/api/routers]
    API --> Domain[app/domain\nEstimateEngine]
    Domain -->|"Stage 1~5 ํ•„ํ„ฐ ์™„ํ™”\n$vectorSearch"| Repo[app/repositories\ncase_repository]
    Domain -->|"BM25+RRF โ†’ Cross-Encoder"| Rerank[ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ๋ฆฌ๋žญํ‚น]
    Repo --> Mongo[(MongoDB Atlas\nVector Search)]

    Client2[Client] -->|"POST /risk-detector/analyze\n(๊ฒฌ์ ์„œ ์ด๋ฏธ์ง€)"| API2[app/api/routers]
    API2 --> RiskSvc[app/domain\nRiskDetectorService]
    RiskSvc -->|Vision ํŒŒ์‹ฑ| Anthropic[Anthropic API]
    RiskSvc -->|"์ฝ”ํผ์Šค ๊ธฐ์ค€ P10~P90"| Repo
Loading
app/
โ”œโ”€โ”€ api/routers/       # HTTP ์š”์ฒญ/์‘๋‹ต (์–‡๊ฒŒ ์œ ์ง€)
โ”œโ”€โ”€ domain/             # ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง โ€” DB ํด๋ผ์ด์–ธํŠธ๋ฅผ ๋ชจ๋ฅธ๋‹ค
โ”œโ”€โ”€ repositories/       # DB ์ ‘๊ทผ ์บก์Аํ™” ($vectorSearch ๋“ฑ)
โ”œโ”€โ”€ schemas/            # Pydantic ์š”์ฒญ/์‘๋‹ต ๋ชจ๋ธ
โ””โ”€โ”€ core/               # ์„ค์ •(pydantic-settings), DI(lifespan), ๋กœ๊น…, rate limit

pipeline/   # ํฌ๋กค๋งยท์ด๋ฏธ์ง€ ํŒŒ์‹ฑยท๋ฐ์ดํ„ฐ ์ ์žฌ
eval/       # ๊ฒ€์ƒ‰ ํ’ˆ์งˆ/๊ฐ€๊ฒฌ์  ์ •ํ™•๋„ ์ •๋Ÿ‰ ํ‰๊ฐ€ (ํ”„๋กœ๋•์…˜ eval๊ณผ ๋ถ„๋ฆฌ)
scripts/    # ๋ฐฑํ•„, ์ธ๋ฑ์Šค ์„ธํŒ… ๋“ฑ ์šด์˜ ์Šคํฌ๋ฆฝํŠธ
tests/      # pytest ๋‹จ์œ„/ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ (154๊ฐœ)
  • DB: MongoDB Atlas ํ•˜๋‚˜๋กœ ํ†ตํ•ฉ (Vector Search๋กœ ๋ฒกํ„ฐ ๊ฒ€์ƒ‰๊นŒ์ง€ ์ฒ˜๋ฆฌ, Chroma ์—†์Œ)
  • ๊ฒ€์ƒ‰: $vectorSearch ํ•„ํ„ฐ ๊ธฐ๋ฐ˜ ์ ์ง„์  ํด๋ฐฑ(Stage 1~5) โ†’ BM25+RRF ํ•˜์ด๋ธŒ๋ฆฌ๋“œ โ†’ (์„ ํƒ) Cross-encoder(Dongjin-kr/ko-reranker) ๋ฆฌ๋žญํ‚น โ€” USE_RERANKER๋กœ ์ผœ๊ณ  ๋ˆ๋‹ค
  • ๋ณด์ •๊ณ„์ˆ˜: correction_coefficients ์ปฌ๋ ‰์…˜์—์„œ ๋ฒ„์ „ ๊ด€๋ฆฌ (์•ฑ ์‹œ์ž‘ ์‹œ 1ํšŒ ๋กœ๋“œ)
  • LLM: ๊ฐ€๊ฒฌ์  ์ˆซ์ž ์‚ฐ์ถœ์—” ๊ด€์—ฌํ•˜์ง€ ์•Š์Œ. ๊ฒฌ์ ์„œ ์ด๋ฏธ์ง€ Vision ํŒŒ์‹ฑ, ํ–ฅํ›„ ์ž์—ฐ์–ด ์š”์•ฝ ๋“ฑ ๋ณด์กฐ ์—ญํ• ๋กœ๋งŒ ํ™•์žฅ ์˜ˆ์ •

๊ธฐ๋Šฅ

๊ฐ€๊ฒฌ์  (/estimates)

  • ๊ณต์ข…(๋„๋ฐฐ/๋งˆ๋ฃจ/์š•์‹ค/์ฃผ๋ฐฉ ๋“ฑ)ยทํ‰์ˆ˜ยท์ง€์—ญยท์ž์žฌ๋“ฑ๊ธ‰ ๋“ฑ ๊ตฌ์กฐํ™” ์ž…๋ ฅ โ†’ ์œ ์‚ฌ ์‹œ๊ณต ์‚ฌ๋ก€ ๊ฒ€์ƒ‰ โ†’ ํ†ต๊ณ„ ๊ธฐ๋ฐ˜ ์˜ˆ์ƒ ๋น„์šฉ ๋ฒ”์œ„ ์‚ฐ์ถœ
  • ๊ฒฌ์  ์ €์žฅ/์กฐํšŒ/์‚ญ์ œ, ์‹ค์ œ ๊ณ„์•ฝ ๊ธˆ์•ก ํ”ผ๋“œ๋ฐฑ ๊ธฐ๋ก

๋ฆฌ์Šคํฌ ์ง„๋‹จ (/risk-detector)

  • ๊ฒฌ์ ์„œ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ โ†’ Vision API๋กœ ํ•ญ๋ชฉ ํŒŒ์‹ฑ โ†’ ์ฝ”ํผ์Šค ๊ธฐ์ค€ ๊ฐ€๊ฒฉ ๋ถ„ํฌ(P10~P90) ๋Œ€๋น„ ์ด์ƒ์น˜ ํ•ญ๋ชฉ ํƒ์ง€
  • ์ง„๋‹จ ๊ฒฐ๊ณผ ์ €์žฅ/์กฐํšŒ/์‚ญ์ œ

๊ณตํ†ต

  • ์š”์ฒญ ID ๊ธฐ๋ฐ˜ ๊ตฌ์กฐํ™” ๋กœ๊น…, ์ „์—ญ ์˜ˆ์™ธ ํ•ธ๋“ค๋Ÿฌ
  • ์—”๋“œํฌ์ธํŠธ๋ณ„ rate limit (slowapi)

๊ธฐ์ˆ  ์Šคํƒ

์˜์—ญ ์„ ํƒ
API FastAPI, Pydantic v2, pydantic-settings
DB MongoDB Atlas ($vectorSearch, motor/pymongo)
๊ฒ€์ƒ‰ sentence-transformers(์ž„๋ฒ ๋”ฉ), rank-bm25(RRF), Dongjin-kr/ko-reranker(Cross-Encoder)
LLM Anthropic API (๊ฒฌ์ ์„œ ์ด๋ฏธ์ง€ Vision ํŒŒ์‹ฑ ์ „์šฉ)
ํฌ๋กค๋ง Selenium, BeautifulSoup
ํ…Œ์ŠคํŠธ/๋ฆฐํŠธ pytest, pytest-asyncio, httpx, ruff
์ธํ”„๋ผ Docker, docker-compose, GitHub Actions

API ๊ฐœ์š”

Method Path ์„ค๋ช…
POST /estimates/generate ์กฐ๊ฑด ์ž…๋ ฅ โ†’ ๊ฐ€๊ฒฌ์  ์‚ฐ์ถœ
POST /estimates/save ๊ฐ€๊ฒฌ์  ๊ฒฐ๊ณผ ์ €์žฅ
GET /estimates ์ €์žฅ๋œ ๊ฐ€๊ฒฌ์  ๋ชฉ๋ก
DELETE /estimates/{id} ๊ฐ€๊ฒฌ์  ์‚ญ์ œ
POST /estimates/{id}/feedback ์‹ค์ œ ๊ณ„์•ฝ ๊ธˆ์•ก ํ”ผ๋“œ๋ฐฑ ๊ธฐ๋ก
POST /risk-detector/analyze ๊ฒฌ์ ์„œ ์ด๋ฏธ์ง€ โ†’ ๋ฆฌ์Šคํฌ ์ง„๋‹จ
POST /risk-detector/save ์ง„๋‹จ ๊ฒฐ๊ณผ ์ €์žฅ
GET /risk-detector ์ €์žฅ๋œ ์ง„๋‹จ ๋ชฉ๋ก
DELETE /risk-detector/{id} ์ง„๋‹จ ์‚ญ์ œ
GET /health ํ—ฌ์Šค์ฒดํฌ

์ „์ฒด Swagger ๋ฌธ์„œ๋Š” ์„œ๋ฒ„ ์‹คํ–‰ ํ›„ http://localhost:8000/docs. ์š”์ฒญ ์˜ˆ์‹œ๋Š” docs/API_TEST_EXAMPLES.md ์ฐธ๊ณ .

curl -X POST http://localhost:8000/estimates/generate \
  -H "Content-Type: application/json" \
  -H "x-user-id: test-user-1" \
  -d '{"๊ณต์ข…": ["์ „๊ธฐ/์กฐ๋ช…", "๋„์žฅ"], "ํ‰์ˆ˜": 20}'

๋กœ์ปฌ ์‹คํ–‰

Docker Compose (๊ถŒ์žฅ)

cp .env.example .env   # ANTHROPIC_API_KEY, MONGO_URI(Atlas) ์ฑ„์šฐ๊ธฐ
docker compose up --build

docker-compose.yml์˜ mongo ์„œ๋น„์Šค๋Š” ๋กœ์ปฌ ๊ฐœ๋ฐœ ํŽธ์˜์šฉ ์ปจํ…Œ์ด๋„ˆ๋‹ค. Vector Search ๊ธฐ๋Šฅ์„ ์“ฐ๋ ค๋ฉด MONGO_URI๊ฐ€ ์‹ค์ œ Atlas ํด๋Ÿฌ์Šคํ„ฐ(Search Index ์„ค์ • ์™„๋ฃŒ)๋ฅผ ๊ฐ€๋ฆฌ์ผœ์•ผ ํ•œ๋‹ค.

๋กœ์ปฌ venv

python -m venv .venv && source .venv/bin/activate  # Windows: .venv\Scripts\activate
pip install torch --index-url https://download.pytorch.org/whl/cpu
pip install -r requirements.txt
cp .env.example .env
uvicorn app.main:app --reload

ํ™˜๊ฒฝ๋ณ€์ˆ˜

๋ณ€์ˆ˜ ์„ค๋ช…
ANTHROPIC_API_KEY ๊ฒฌ์ ์„œ ์ด๋ฏธ์ง€ Vision ํŒŒ์‹ฑ์šฉ
MONGO_URI MongoDB Atlas ์—ฐ๊ฒฐ ๋ฌธ์ž์—ด (Vector Search Index ํ•„์š”)
USE_RERANKER Cross-encoder ๋ฆฌ๋žญํ‚น ์‚ฌ์šฉ ์—ฌ๋ถ€(๊ธฐ๋ณธ false). true๋ฉด ์›Œ์ปค๋‹น RAM +2.2GB ํ•„์š”

ํ…Œ์ŠคํŠธ & CI

ruff check app tests scripts eval
pytest -q

tests/ 154๊ฐœ ๋‹จ์œ„/ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ, GitHub Actions์—์„œ push/PR๋งˆ๋‹ค lint + test ์ž๋™ ์‹คํ–‰ (.github/workflows/ci.yml). ๊ฒ€์ƒ‰ ํ’ˆ์งˆ/๊ฐ€๊ฒฌ์  ์ •ํ™•๋„ ํ‰๊ฐ€๋Š” eval/์— ๋ณ„๋„๋กœ ๋ถ„๋ฆฌ(ํ”„๋กœ๋•์…˜ ์ฝ”๋“œ ํšŒ๊ท€ ํ…Œ์ŠคํŠธ๊ฐ€ ์•„๋‹ˆ๋ผ ๋ชจ๋ธยทํŒŒ์ดํ”„๋ผ์ธ ์„ฑ๋Šฅ ์ธก์ •์šฉ).


๋กœ๋“œ๋งต

  • ์‹ค์ œ ๊ณ„์•ฝ ๊ธˆ์•ก ํ”ผ๋“œ๋ฐฑ ๋ฃจํ”„๋กœ ์˜จ๋ผ์ธ ์ •ํ™•๋„(MAPE) ์ธก์ •
  • ๋ณด์ •๊ณ„์ˆ˜(correction_coefficients) ๋ฒ„์ „ ์ถ”์  + ์žฌํ˜„์„ฑ ํ•„๋“œ(engine_version)
  • BM25/๋ฆฌ๋žญํ‚น ์™„ํ™”์ฑ…(ํ…์ŠคํŠธ ์บก ์ถ•์†Œ ๋“ฑ) ํ”„๋กœ๋•์…˜ ๋ฐ˜์˜ ์—ฌ๋ถ€ ๊ฒฐ์ •

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages