Chatbot Router Refactoring: Out-of-Scope Guard ๋„์ž…๊ธฐ

ํ˜„์žฌ ์šด์˜ ์ค‘์ธ ์ฑ—๋ด‡์˜ ๊ธฐ๋ณธ ํ๋ฆ„์€ ์‚ฌ์šฉ์ž์˜ ์งˆ๋ฌธ์ด ์œ„์น˜ ๊ธฐ๋ฐ˜(Location) ์ธ์ง€ ์—ฌ๋ถ€๋ฅผ ํŒ๋ณ„ํ•œ ๋’ค, ๊ทธ์— ๋”ฐ๋ผ ๋ฒกํ„ฐ ๊ฒ€์ƒ‰ ๋…ธ๋“œ ๋˜๋Š” ๋‹ต๋ณ€ ์ƒ์„ฑ ๋…ธ๋“œ๋กœ ๋ผ์šฐํŒ…๋œ๋‹ค. ํ•˜์ง€๋งŒ ๊ธฐ์กด ๊ตฌ์กฐ์—์„œ๋Š” ์œ„์น˜ ๊ธฐ๋ฐ˜์ด ์•„๋‹Œ ์งˆ๋ฌธ๋„ ๋ฌด์กฐ๊ฑด ๋ฒกํ„ฐ ๊ฒ€์ƒ‰์„ ๊ฑฐ์น˜๋„๋ก ์„ค๊ณ„๋˜์–ด ์žˆ์—ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด โ€œWhat is my name? ๊ฐ™์€ ๋‹จ์ˆœํ•œ ์งˆ์˜์กฐ์ฐจ ๋ฒกํ„ฐ ๊ฒ€์ƒ‰์„ ํ†ตํ•ด ๋ถˆํ•„์š”ํ•œ ๋ฌธ์„œ๋ฅผ LLM ์ž…๋ ฅ์— ์ถ”๊ฐ€ํ–ˆ๊ณ , ๊ทธ ๊ฒฐ๊ณผ ์‘๋‹ต ์†๋„๊ฐ€ ๋А๋ ค์ง€๊ณ  ํ† ํฐ ์‚ฌ์šฉ๋Ÿ‰์ด ์ฆ๊ฐ€ํ–ˆ๋‹ค.

์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด classify_query() ๋กœ์ง์„ ํ™•์žฅํ–ˆ๋‹ค. ๊ธฐ์กด์—๋Š” โ€œlocationโ€๊ณผ โ€œcommonโ€ ๋‘ ๊ฐ€์ง€ ํƒ€์ž…์œผ๋กœ๋งŒ ๋ถ„๋ฅ˜ํ–ˆ์ง€๋งŒ, ์—ฌ๊ธฐ์— โ€œvisaโ€ ์™€ โ€œfallbackโ€ ํƒ€์ž…์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค. ์ƒˆ๋กœ์šด ๋ผ์šฐํŒ… ๊ทœ์น™์— ๋”ฐ๋ผ ๋„๋ฉ”์ธ ๋ฐ–(fallback) ์งˆ๋ฌธ์€ ๋ฌธ์„œ ๊ฒ€์ƒ‰์„ ์ƒ๋žตํ•˜๊ณ  ๋ฐ”๋กœ ๋‹ต๋ณ€ ์ƒ์„ฑ ๋…ธ๋“œ๋กœ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๊ฒŒ ํ–ˆ๋‹ค. ๊ทธ ๊ฒฐ๊ณผ, ๊ธฐ์กด ํ…Œ์ŠคํŠธ ์‹คํ–‰ ์‹œ๊ฐ„์ด 310.05์ดˆ โ†’ 241.72์ดˆ๋กœ ์•ฝ 22% ๋‹จ์ถ•๋˜์—ˆ๋‹ค.

๋ฒ”์œ„ ๋ฐ– ์งˆ๋ฌธ ๋ฌธ์ œ์™€ Out-of-Scope Guard

๋ผ์šฐํŒ… ๊ฐœ์„  ํ›„์—๋„, ๋ฒ”์œ„ ๋ฐ– ์งˆ๋ฌธ(์˜ˆ: โ€œTell me a jokeโ€)์— ๋Œ€ํ•ด LLM์ด ๋ฒ”์šฉ ๋‹ต๋ณ€์„ ํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋‚จ์•˜๋‹ค. ์ด๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด, generate ๋…ธ๋“œ ์ž…๊ตฌ์—์„œ ๋„๋ฉ”์ธ ํŒ๋ณ„์„ ๊ฑฐ์ณ OOS(Out-of-Scope) ์‹œ ์ฆ‰์‹œ ์•ˆ๋‚ด ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” Guard Layer๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค. ์ด Guard๋Š” ๋‘ ๊ฐ€์ง€ ๊ธฐ์ˆ ์„ ์กฐํ•ฉํ–ˆ๋‹ค.

  1. Config-driven ๋ฃฐ ๊ธฐ๋ฐ˜ ํ•„ํ„ฐ
    • YAML/JSON ํŒŒ์ผ์— Allow(๋„๋ฉ”์ธ) / Deny(์Šค๋ชฐํ†ก) ๋ฌธ๊ตฌ๋ฅผ ์ •์˜
    • ํ•ซ๋ฆฌ๋กœ๋“œ ์ง€์› โ†’ ์šด์˜ ์ค‘์—๋„ ์ฆ‰์‹œ ๋ฐ˜์˜ ๊ฐ€๋Šฅ
  2. ๋‹ค๊ตญ์–ด ์ž„๋ฒ ๋”ฉ ์•ต์ปค ๋งค์นญ
    • ๋ฉ€ํ‹ฐ๋ง๊ตฌ์–ผ ์ž„๋ฒ ๋”ฉ ๋ชจ๋ธ(multilingual-e5, bge-m3)์„ ์‚ฌ์šฉํ•ด ์–ธ์–ดยทํ‘œํ˜„์ด ๋‹ฌ๋ผ๋„ ์˜๋ฏธ ์œ ์‚ฌ๋„๋ฅผ ํŒ๋‹จ
    • ์ฟผ๋ฆฌ์™€ Allow/Deny ์•ต์ปค๋ฅผ ์ž„๋ฒ ๋”ฉ ํ›„ dot product๋กœ ์œ ์‚ฌ๋„ ๊ณ„์‚ฐ
    • ์ž„๊ณ„๊ฐ’(allow/deny threshold) ์กฐ์ •์œผ๋กœ ๋ฏผ๊ฐ๋„ ์ œ์–ด

์ด ๋ฐฉ์‹์„ ์ฑ„ํƒํ•œ ์ด์œ ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • ์–ธ์–ด ํ™•์žฅ์„ฑ: ํ‚ค์›Œ๋“œ ๋งค์นญ๋งŒ์œผ๋กœ๋Š” ๋‹ค๊ตญ์–ด/ํŒจ๋Ÿฌํ”„๋ ˆ์ด์ฆˆ ๋Œ€์‘์ด ์–ด๋ ต๋‹ค.
  • ์šด์˜ ํŽธ์˜: ์‹œ๊ทธ๋„ ์ถ”๊ฐ€ยท์ˆ˜์ •์ด ์ฆ‰์‹œ ๋ฐ˜์˜๋˜๋ฉฐ ์žฌ๋ฐฐํฌ๊ฐ€ ๋ถˆํ•„์š”ํ•˜๋‹ค.
  • ์œ„ํ—˜ ์ตœ์†Œํ™”: Generate ๋‹จ๊ณ„ ์ž…๊ตฌ์—์„œ๋งŒ ์ฐจ๋‹จํ•˜๋ฏ€๋กœ ํšŒ๊ท€ ๋ฆฌ์Šคํฌ๊ฐ€ ์ ๋‹ค.
  • ๋น„์šฉ/์ง€์—ฐ ์ตœ์ ํ™”: ์†Œํ˜• ์ž„๋ฒ ๋”ฉ 1ํšŒ + ์ฝ”์‚ฌ์ธ ์œ ์‚ฌ๋„ ๊ณ„์‚ฐ๋งŒ ์ถ”๊ฐ€, ์บ์‹ฑ ์‹œ ์ง€์—ฐ ๊ฑฐ์˜ ์—†์Œ

๊ตฌํ˜„ ๋ฐฉ์‹

OOS Guard๋Š” ๋‹ค์Œ ์ˆœ์„œ๋กœ ๋™์ž‘ํ•œ๋‹ค.

  1. ๋„๋ฉ”์ธ ๋งค์นญ
    • Allow ๋ฆฌ์ŠคํŠธ ๋งค์นญ ์‹œ ๋ฐ”๋กœ ํ†ต๊ณผ
    • ๋งค์นญ ์‹คํŒจ ์‹œ Deny ๋ฆฌ์ŠคํŠธ ๋งค์นญ + ์งง์€ ์งˆ์˜ ํœด๋ฆฌ์Šคํ‹ฑ์œผ๋กœ OOS ํ™•์ •
  2. OOS ์‘๋‹ต
    • ์ฆ‰์‹œ ๋„๋ฉ”์ธ ์œ ๋„ ์•ˆ๋‚ด ๋ฉ”์‹œ์ง€ ๋ฐ˜ํ™˜ (LLM ํ˜ธ์ถœ ์ƒ๋žต)
  3. ์ž„๊ณ„๊ฐ’ ํŠœ๋‹
    • ๋กœ๊ทธ์— Allow/Deny ์ ์ˆ˜ ๊ธฐ๋ก, ์ฃผ ๋‹จ์œ„ ๋ถ„์„์œผ๋กœ threshold ์žฌ์„ค์ •
  4. Fallback ๋ณด๊ฐ•
    • FAQ ์ธ๋ฑ์Šค(BM25/์ž„๋ฒ ๋”ฉ)๋กœ ๋น ๋ฅธ ์กฐํšŒ ํ›„ ๋งค์นญ ์‹œ ์•ˆ์ „ ์ƒ์„ฑ์„ฑ

์„ฑ๋Šฅ๊ณผ ๋ฐฐํฌ ์˜ํ–ฅ

์ดˆ๊ธฐ ๊ตฌํ˜„์—๋Š” Hugging Face์˜ SentenceTransformer๋ฅผ ์‚ฌ์šฉํ–ˆ์œผ๋‚˜, ๋ชจ๋ธ ๋‹ค์šด๋กœ๋“œ์— 30์ดˆ ์ด์ƒ ์†Œ์š”๋˜๊ณ  Docker ๋นŒ๋“œ ์‹œ๊ฐ„๋„ 10๋ถ„ ์ด์ƒ ์ฆ๊ฐ€ํ–ˆ๋‹ค. ์šด์˜ ํšจ์œจ์„ฑ์„ ์œ„ํ•ด OpenAI Embedder๋กœ ๊ธฐ๋ณธ ์„ค์ •์„ ๋ณ€๊ฒฝํ•˜์ž, ํ…Œ์ŠคํŠธ ์‹คํ–‰ ์‹œ๊ฐ„์ด 210.45์ดˆ๋กœ ๋” ์ค„์—ˆ๊ณ , Docker ๋นŒ๋“œ๋„ 94.5์ดˆ, ์ด๋ฏธ์ง€ ํฌ๊ธฐ๋Š” 1GB๋กœ ์•ˆ์ •ํ™”๋˜์—ˆ๋‹ค.

์ตœ์ข…์ ์œผ๋กœ, Out-of-Scope Guard ๋„์ž…์œผ๋กœ ์„œ๋น„์Šค ๋ฒ”์œ„ ๋ฐ– ์งˆ๋ฌธ์„ LLM ํ˜ธ์ถœ ์—†์ด ์ฒ˜๋ฆฌํ•˜๋ฉด์„œ๋„ ์„ฑ๋Šฅ ์ €ํ•˜ ์—†์ด ์•ˆ์ •์ ์ธ ๋ผ์šฐํŒ…์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

OOS ๊ฒฐ๊ณผ: