[TIL-0509] DSPy๋ž€?

jinyยท2026๋…„ 5์›” 9์ผ

AI Agent ์‹ค์Šต

๋ชฉ๋ก ๋ณด๊ธฐ
21/21

๐ŸŒŸ ๊ฐœ์š”

โœจ ์Šคํ„ฐ๋”” ํ”„๋กœ์ ํŠธ ์†Œ๊ฐœ

์šฐ๋ฆฌ ์Šคํ„ฐ๋””์—์„œ๋Š” LangChain ๊ธฐ๋ฐ˜์˜ ์ธํ”Œ๋ฃจ์–ธ์„œ ๋งค์นญ ์—์ด์ „ํŠธ ํ”Œ๋žซํผ์„ ๋งŒ๋“ค๊ณ  ์žˆ๋‹ค.
๊ด‘๊ณ ์ฃผ๊ฐ€ ๊ด‘๊ณ  ์ปจ์…‰, ๊ด‘๊ณ  ์•„์ดํ…œ, ๊ด‘๊ณ ์ฃผ ๋ธŒ๋žœ๋“œ๋ช… ์„ธ ๊ฐ€์ง€๋ฅผ ์ž…๋ ฅํ•˜๋ฉด, ์—์ด์ „ํŠธ๊ฐ€ ์ตœ์ ์˜ ์ธํ”Œ๋ฃจ์–ธ์„œ ํ›„๋ณด๋ฅผ ์ถ”์ฒœํ•ด์ฃผ๋Š” ์‹œ์Šคํ…œ์ด๋‹ค.
์—์ด์ „ํŠธ๋Š” ๋‹ค์Œ 5๊ฐœ์˜ ๋„๊ตฌ๋ฅผ ์ž์œจ์ ์œผ๋กœ ์„ ํƒํ•˜๋ฉด์„œ ๋™์ž‘ํ•œ๋‹ค.

๋„๊ตฌ์—ญํ• 
search_influencers_by_category์นดํ…Œ๊ณ ๋ฆฌ๋กœ DB ๊ฒ€์ƒ‰
search_influencers_by_platformํ”Œ๋žซํผ์œผ๋กœ DB ๊ฒ€์ƒ‰
search_influencers_by_followersํŒ”๋กœ์›Œ ๋ฒ”์œ„๋กœ DB ๊ฒ€์ƒ‰
get_influencer_detailsํŠน์ • ์ธํ”Œ๋ฃจ์–ธ์„œ ์ƒ์„ธ ์ •๋ณด ์กฐํšŒ
calculate_match_score4์ฐจ์› ๋งค์นญ ์ ์ˆ˜ ๊ณ„์‚ฐ

๊ตฌํ˜„ ์ž์ฒด๋Š” ์–ด๋ ต์ง€ ์•Š์•˜์ง€๋งŒ, ์ด ์—์ด์ „ํŠธ๊ฐ€ ์ž˜ ์ž‘๋™ํ•˜๊ณ  ์žˆ๋Š”์ง€ ์–ด๋–ป๊ฒŒ ํ‰๊ฐ€ํ• ์ง€๊ฐ€ ๊ด€๊ฑด์ด์—ˆ๋‹ค.

๐Ÿ˜ฃ ์—์ด์ „ํŠธ ํ‰๊ฐ€์˜ ์–ด๋ ค์›€

์ผ๋ฐ˜์ ์ธ ์†Œํ”„ํŠธ์›จ์–ด๋ผ๋ฉด ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋กœ "์ž…๋ ฅ A โ†’ ์ถœ๋ ฅ B"๋ฅผ ๊ฒ€์ฆํ•˜๋ฉด ๊ทธ๋งŒ์ด๋‹ค.
๊ทธ๋Ÿฐ๋ฐ LLM ์—์ด์ „ํŠธ๋Š” ๋‹ค๋ฅด๋‹ค. ๊ฐ™์€ ์ž…๋ ฅ์„ ์ค˜๋„ ๋งค๋ฒˆ ์กฐ๊ธˆ์”ฉ ๋‹ค๋ฅธ ๊ฒฝ๋กœ๋กœ ๋„๊ตฌ๋ฅผ ํ˜ธ์ถœํ•˜๊ณ , ๋‹ค๋ฅธ ๋ฌธ์žฅ์œผ๋กœ ์‘๋‹ตํ•œ๋‹ค. ์ •ํ•ด์ง„ ์ •๋‹ต์ด ์—†๋‹ค.

๊ทธ๋ ‡๋‹ค๊ณ  ๋งค๋ฒˆ ๋ˆˆ์œผ๋กœ ์ง์ ‘ ์‘๋‹ต์„ ์ฝ์–ด๋ณด๋Š” ๋ฐฉ์‹์€ ์ง€์† ๊ฐ€๋Šฅํ•˜์ง€ ์•Š๋‹ค. ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ 10๊ฐœ๋งŒ ๋งŒ๋“ค์–ด๋„ ์ฝ”๋“œ๋ฅผ ์กฐ๊ธˆ ๋ฐ”๊ฟ€ ๋•Œ๋งˆ๋‹ค 10๋ฒˆ์„ ์ฝ์–ด์•ผ ํ•œ๋‹ค.

์ด ๋ฌธ์ œ๋ฅผ ๊ตฌ์ฒด์ ์œผ๋กœ ํ‘œํ˜„ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • ์—์ด์ „ํŠธ๊ฐ€ ์ถ”์ฒœํ•œ ์ธํ”Œ๋ฃจ์–ธ์„œ๊ฐ€ ์‹ค์ œ๋กœ DB์— ์กด์žฌํ•˜๋Š” ์‚ฌ๋žŒ์ธ๊ฐ€?
  • ์ถ”์ฒœ ์ด์œ ๊ฐ€ ์‹ค์ œ ๋ฐ์ดํ„ฐ์™€ ์ผ์น˜ํ•˜๋Š”๊ฐ€?
  • ๋ทฐํ‹ฐ ๊ด‘๊ณ ์— ๋ทฐํ‹ฐ ์นดํ…Œ๊ณ ๋ฆฌ ์ธํ”Œ๋ฃจ์–ธ์„œ๋ฅผ ์ถ”์ฒœํ–ˆ๋Š”๊ฐ€?
  • ์ถ”์ฒœ๋œ ์ธํ”Œ๋ฃจ์–ธ์„œ๊ฐ€ ๊ฒฝ์Ÿ์‚ฌ ๊ด‘๊ณ  ์ด๋ ฅ์€ ์—†๋Š”๊ฐ€?

๊ฐ ์งˆ๋ฌธ์€ "๋งž๋‹ค/ํ‹€๋ฆฌ๋‹ค"๋กœ ํŒ๋‹จํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฆ‰, ์ž๋™ํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ํ•„์š”ํ•œ ๊ฑด ์ด ์ฒดํฌ๋ฆฌ์ŠคํŠธ๋ฅผ ์ฝ”๋“œ๋กœ ํ‘œํ˜„ํ•˜๋Š” ๊ฒƒ์ด์—ˆ๋‹ค.

โœจ ๋‘ ๊ฐ€์ง€ ์ ‘๊ทผ ๋ฐฉ๋ฒ•

ํŒ€์—์„œ๋Š” ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋‘ ๊ฐ€์ง€ ๋ฐฉํ–ฅ์ด ๋– ์˜ฌ๋ž๋‹ค.

์ฒซ ๋ฒˆ์งธ๋Š” ๋‹จ๊ณ„๋ณ„ ํŒŒ์ดํ”„๋ผ์ธ ๋ฐฉ์‹์ด๋‹ค.
์—์ด์ „ํŠธ๋ฅผ ๊ทธ๋Œ€๋กœ ์‹คํ–‰ํ•˜๊ณ , ์‘๋‹ต์„ ํŒŒ์‹ฑํ•˜๊ณ , DB์™€ ๋Œ€์กฐํ•˜๊ณ , ๋ฏธ๋ฆฌ ์ •์˜ํ•œ ์ฒดํฌ๋ฆฌ์ŠคํŠธ๋กœ ์ ์ˆ˜๋ฅผ ๋‚ด๋Š” ๊ฒƒ์ด๋‹ค. ์ง๊ด€์ ์ด๊ณ  ๊ตฌํ˜„๋„ ์–ด๋ ต์ง€ ์•Š๋‹ค.

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

์ด ๊ธ€์€ ์šฐ๋ฆฌ ํŒ€์ด DSPy๋ฅผ ์–ด๋–ป๊ฒŒ ์ดํ•ดํ–ˆ๊ณ , ์‹ค์ œ๋กœ ํ”„๋กœ์ ํŠธ์— ์–ด๋–ป๊ฒŒ ์ ์šฉํ•ด๋ดค์œผ๋ฉฐ, ๊ทธ ๊ณผ์ •์—์„œ ๋ฌด์—‡์„ ๋ฐฐ์› ๋Š”์ง€์— ๋Œ€ํ•œ ๊ธฐ๋ก์ด๋‹ค.


๐ŸŒŸ DSPy๋ž€?

DSPy(Declarative Self-improving Python)๋Š” ์Šคํƒ ํผ๋“œ NLP ์—ฐ๊ตฌํŒ€์ด ๋งŒ๋“  ํ”„๋ ˆ์ž„์›Œํฌ๋กœ, ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•˜๋Š” ๋Œ€์‹  LLM ํ”„๋กœ๊ทธ๋žจ์˜ ๊ตฌ์กฐ๋ฅผ ์„ ์–ธํ•˜๊ณ  ์ตœ์ ํ™”๋ฅผ ์ž๋™ํ™”ํ•˜๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ๋กœ ํ•œ๋‹ค.
์ด๊ฒŒ ์–ด๋–ค ์˜๋ฏธ์ธ์ง€๋Š” ๊ธฐ์กด ๋ฐฉ์‹์˜ ๋ฌธ์ œ๋ฅผ ๋จผ์ € ๋ณด๋ฉด ๋” ์ž˜ ์™€๋‹ฟ๋Š”๋‹ค.

๐Ÿ’ฅ ํ”„๋กฌํ”„ํŠธ ์—”์ง€๋‹ˆ์–ด๋ง์˜ ๋ฌธ์ œ

LLM ๊ธฐ๋ฐ˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•˜๋‹ค ๋ณด๋ฉด ํ•œ ๋ฒˆ์ฏค ์ด๋Ÿฐ ๊ฒฝํ—˜์„ ํ•œ๋‹ค.

์—์ด์ „ํŠธ๊ฐ€ ์—‰๋šฑํ•œ ๋‹ต์„ ๋‚ด๋†“๋Š”๋‹ค. โ†’ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ˆ˜์ •ํ•œ๋‹ค. โ†’ ์กฐ๊ธˆ ๋‚˜์•„์ง„๋‹ค. โ†’ ๊ทธ๋Ÿฐ๋ฐ ๋‹ค๋ฅธ ์ผ€์ด์Šค์—์„œ ๋˜ ํ‹€๋ฆฐ๋‹ค. โ†’ ๋‹ค์‹œ ์ˆ˜์ •ํ•œ๋‹ค. โ†’ ๊ทธ๋Ÿฌ๋ฉด ์ฒ˜์Œ์— ์ž˜ ๋˜๋˜ ์ผ€์ด์Šค๊ฐ€ ๋ง๊ฐ€์ง„๋‹ค. โ†’ ...

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

DSPy๋Š” ์ด ๋ฌธ์ œ์— ์ •๋ฉด์œผ๋กœ ๋„์ „ํ•œ๋‹ค.

"ํ”„๋กฌํ”„ํŠธ ๋ฌธ์ž์—ด์„ ์ง์ ‘ ๋งŒ์ง€๋Š” ๋Œ€์‹ , LLM์—๊ฒŒ ๋ฌด์—‡์„ ์›ํ•˜๋Š”์ง€ ์„ ์–ธํ•˜๊ณ  ์ตœ์ ํ™”๋Š” ํ”„๋ ˆ์ž„์›Œํฌ์— ๋งก๊ฒจ๋ผ."

โœจ ๊ธฐ์กด ๋ฐฉ์‹ vs. DSPy ๋ฐฉ์‹

๋‘ ์ ‘๊ทผ์˜ ์ฐจ์ด๋ฅผ ์ฝ”๋“œ๋กœ ์ง์ ‘ ๋น„๊ตํ•ด๋ณด๋ฉด ๋” ๋ช…ํ™•ํ•˜๋‹ค.

  • ๊ธฐ์กด ๋ฐฉ์‹ (์ˆ˜๋™ ํ”„๋กฌํ”„ํŠธ ์—”์ง€๋‹ˆ์–ด๋ง)
    prompt = """
     ๋‹น์‹ ์€ ์ธํ”Œ๋ฃจ์–ธ์„œ ๋งค์นญ ์ „๋ฌธ๊ฐ€์ž…๋‹ˆ๋‹ค.
     ๋‹ค์Œ ๊ด‘๊ณ  ์ •๋ณด๋ฅผ ๋ถ„์„ํ•˜์—ฌ ์ ํ•ฉํ•œ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์ถ”๋ก ํ•˜์„ธ์š”.
     
     ๊ด‘๊ณ  ์ปจ์…‰: {ad_concept}
     ๊ด‘๊ณ  ์•„์ดํ…œ: {ad_item}
     ๊ด‘๊ณ ์ฃผ: {advertiser}
     
     ๋ฐ˜๋“œ์‹œ ๋‹ค์Œ ์ค‘์—์„œ๋งŒ ์„ ํƒํ•˜์„ธ์š”:
     beauty, fashion, tech, food, travel, fitness, gaming, music, education, lifestyle
     
     ์นดํ…Œ๊ณ ๋ฆฌ:
     """
     
     response = llm.invoke(prompt.format(...))
    ์ด ๋ฐฉ์‹์˜ ๋ฌธ์ œ๋Š” ํ”„๋กฌํ”„ํŠธ ๋ฌธ์ž์—ด ์ž์ฒด๊ฐ€ ๋กœ์ง์ด ๋œ๋‹ค๋Š” ์ ์ด๋‹ค. ๋ชจ๋ธ์„ ๋ฐ”๊พธ๋ฉด "๋ฐ˜๋“œ์‹œ"๋ผ๋Š” ๊ฐ•์กฐ์–ด์˜ ํšจ๊ณผ๊ฐ€ ๋‹ฌ๋ผ์ง„๋‹ค. ์ถœ๋ ฅ ํ˜•์‹์ด ์กฐ๊ธˆ๋งŒ ๋‹ฌ๋ผ์ ธ๋„ ํŒŒ์‹ฑ์ด ๊นจ์ง„๋‹ค. ์„ฑ๋Šฅ์„ ๋†’์ด๋ ค๋ฉด ์‚ฌ๋žŒ์ด ์ง์ ‘ ๋ฌธ์žฅ์„ ๊ณ ์ณ์•ผ ํ•œ๋‹ค.
  • DSPy ๋ฐฉ์‹ (์„ ์–ธํ˜• ๋ช…์„ธ)

    class InferCategories(dspy.Signature):
       """๊ด‘๊ณ  ์ •๋ณด๋ฅผ ๋ถ„์„ํ•˜์—ฌ DB ๊ฒ€์ƒ‰์— ์‚ฌ์šฉํ•  ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์ถ”๋ก ํ•ฉ๋‹ˆ๋‹ค."""
       
       ad_concept: str = dspy.InputField(desc="๊ด‘๊ณ  ์ปจ์…‰ ์„ค๋ช…")
       ad_item: str = dspy.InputField(desc="๊ด‘๊ณ  ์ƒํ’ˆ/์„œ๋น„์Šค๋ช…")
       advertiser: str = dspy.InputField(desc="๊ด‘๊ณ ์ฃผ ๋ธŒ๋žœ๋“œ๋ช…")
       categories: str = dspy.OutputField(
          desc="์‰ผํ‘œ๋กœ ๊ตฌ๋ถ„๋œ ์นดํ…Œ๊ณ ๋ฆฌ. ๋ฐ˜๋“œ์‹œ ๋‹ค์Œ ์ค‘์—์„œ๋งŒ ์„ ํƒ: beauty, fashion, ..."
       )
    
    predictor = dspy.Predict(InferCategories)
    result = predictor(ad_concept="...", ad_item="...", advertiser="...")

    ํ”„๋กฌํ”„ํŠธ ๋ฌธ์ž์—ด์ด ์‚ฌ๋ผ์กŒ๋‹ค. ๋Œ€์‹  "์–ด๋–ค ์ž…๋ ฅ์„ ๋ฐ›์•„์„œ ์–ด๋–ค ์ถœ๋ ฅ์„ ๋‚ด๋†“๋Š”๊ฐ€"๋งŒ ์„ ์–ธํ•œ๋‹ค. ์‹ค์ œ ํ”„๋กฌํ”„ํŠธ๋Š” DSPy๊ฐ€ ์ž๋™์œผ๋กœ ๊ตฌ์„ฑํ•œ๋‹ค.

โœจ DSPy๊ฐ€ ํ•ด๊ฒฐํ•˜๋Š” ๊ฒƒ: "ํ”„๋กฌํ”„ํŠธ๋ฅผ ํ•˜๋“œ์ฝ”๋”ฉํ•˜์ง€ ๋งˆ๋ผ"

๊ธฐ์กด ๋ฐฉ์‹์—์„œ ํ”„๋กฌํ”„ํŠธ๋Š” ๋ชจ๋ธ๊ณผ ๊ฐ•ํ•˜๊ฒŒ ๊ฒฐํ•ฉ๋˜์–ด ์žˆ๋‹ค. GPT-4์— ๋งž๊ฒŒ ํŠœ๋‹ํ•œ ํ”„๋กฌํ”„ํŠธ๋ฅผ Claude์— ๊ทธ๋Œ€๋กœ ์“ฐ๋ฉด ์„ฑ๋Šฅ์ด ๋‹ฌ๋ผ์ง„๋‹ค. Ollama ๋กœ์ปฌ ๋ชจ๋ธ์— ์“ฐ๋ฉด ๋” ๋‹ฌ๋ผ์ง„๋‹ค.

DSPy๋Š” ์ด ๊ฒฐํ•ฉ์„ ๋Š๋Š”๋‹ค. ๊ฐœ๋ฐœ์ž๋Š” "๋ฌด์—‡์„ ์›ํ•˜๋Š”๊ฐ€(What)"๋งŒ ์„ ์–ธํ•˜๊ณ , "์–ด๋–ป๊ฒŒ ํ‘œํ˜„ํ•  ๊ฒƒ์ธ๊ฐ€(How)"๋Š” DSPy์™€ Optimizer๊ฐ€ ๋‹ด๋‹นํ•œ๋‹ค.
๋ชจ๋ธ์ด ๋ฐ”๋€Œ๋ฉด Optimizer๋ฅผ ๋‹ค์‹œ ๋Œ๋ ค์„œ ๊ทธ ๋ชจ๋ธ์— ๋งž๋Š” ์ตœ์  ํ‘œํ˜„์„ ์ž๋™์œผ๋กœ ์ฐพ์•„๋‚ธ๋‹ค.

์ด ๊ด€์ ์—์„œ DSPy๋ฅผ ํ•œ ๋ฌธ์žฅ์œผ๋กœ ์ •์˜ํ•˜๋ฉด ์ด๋ ‡๋‹ค.

LLM ํ˜ธ์ถœ์„ ์„ ์–ธํ˜•์œผ๋กœ ๊ตฌ์กฐํ™”ํ•˜๊ณ , ํ‰๊ฐ€ ๊ธฐ์ค€(metric)์„ ์ •์˜ํ•˜๋ฉด ํ”„๋กฌํ”„ํŠธ์™€ few-shot ์˜ˆ์‹œ๋ฅผ ์ž๋™์œผ๋กœ ์ตœ์ ํ™”ํ•ด์ฃผ๋Š” ํ”„๋ ˆ์ž„์›Œํฌ

โœจ ๋จธ์‹ ๋Ÿฌ๋‹์  ๊ด€์ ์—์„œ ๋ณธ DSPy

DSPy์˜ ์„ค๊ณ„๋Š” ๋จธ์‹ ๋Ÿฌ๋‹์˜ ํ•™์Šต ๋ฃจํ”„์—์„œ ์ง์ ‘ ์˜๊ฐ์„ ๋ฐ›์•˜๋‹ค.

์ „ํ†ต์ ์ธ ML์—์„œ๋Š” ๋ชจ๋ธ ๊ฐ€์ค‘์น˜๋ฅผ ์ง์ ‘ ์ˆ˜์ •ํ•˜๋Š” ๋Œ€์‹ , ์†์‹ค ํ•จ์ˆ˜(loss function)๋ฅผ ์ •์˜ํ•˜๊ณ  ์—ญ์ „ํŒŒ๋กœ ์ตœ์ ํ™”ํ•œ๋‹ค. ๊ฐœ๋ฐœ์ž๋Š” "๋ฌด์—‡์ด ์ข‹์€ ์ถœ๋ ฅ์ธ์ง€"๋งŒ ์ •์˜ํ•˜๋ฉด ๋œ๋‹ค.

DSPy๋Š” ์ด ํŒจ๋Ÿฌ๋‹ค์ž„์„ ํ”„๋กฌํ”„ํŠธ์— ์ ์šฉํ•œ๋‹ค.

MLDSPy
๋ชจ๋ธ ๊ฐ€์ค‘์น˜ํ”„๋กฌํ”„ํŠธ & few-shot ์˜ˆ์‹œ
์†์‹ค ํ•จ์ˆ˜metric ํ•จ์ˆ˜ (0.0 ~ 1.0)
์—ญ์ „ํŒŒ + OptimizerMIPROv2 ๋“ฑ Teleprompter
ํ•™์Šต ๋ฐ์ดํ„ฐtrainset (dspy.Example ๋ชฉ๋ก)

"๊ฐ€์ค‘์น˜๋ฅผ ์ง์ ‘ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ  ์†์‹ค ํ•จ์ˆ˜๋กœ ์ตœ์ ํ™”ํ•œ๋‹ค"๋Š” ๊ฒŒ ๋”ฅ๋Ÿฌ๋‹์˜ ํ•ต์‹ฌ์ด๋“ฏ, "ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ง์ ‘ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ  metric์œผ๋กœ ์ตœ์ ํ™”ํ•œ๋‹ค"๋Š” ๊ฒŒ DSPy์˜ ํ•ต์‹ฌ์ด๋‹ค.

๐Ÿง LangChain๊ณผ์˜ ์ฐจ์ด์ 

LangChain์€ LLM ํ˜ธ์ถœ, ์ฒด์ธ ๊ตฌ์„ฑ, ๋„๊ตฌ ์—ฐ๊ฒฐ ๋“ฑ LLM ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋นŒ๋”ฉ ๋ธ”๋ก์„ ์ œ๊ณตํ•˜๋Š” ํ”„๋ ˆ์ž„์›Œํฌ์ด๋‹ค. ์–ด๋–ค ํ”„๋กฌํ”„ํŠธ๋ฅผ ์“ธ์ง€๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ๊ฒฐ์ •ํ•œ๋‹ค.

DSPy๋Š” ๊ทธ ์œ„์—์„œ ์ž‘๋™ํ•˜๋Š” ์ตœ์ ํ™” ๋ ˆ์ด์–ด์ด๋‹ค. LLM ์—ฐ๊ฒฐ์€ LangChain์ฒ˜๋Ÿผ ํ•˜๊ณ , ํ”„๋กฌํ”„ํŠธ ์ž์ฒด๋ฅผ ์–ด๋–ป๊ฒŒ ๊ตฌ์„ฑํ• ์ง€๋Š” DSPy๊ฐ€ ์ฐพ์•„์ค€๋‹ค.

๋‘˜์€ ๋Œ€์ฒด ๊ด€๊ณ„๊ฐ€ ์•„๋‹ˆ๋ผ ์—ญํ• ์ด ๋‹ค๋ฅด๋‹ค. ์‹ค์ œ๋กœ DSPy๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ LiteLLM์„ ํ†ตํ•ด OpenAI, Anthropic, Ollama ๋“ฑ ๋‹ค์–‘ํ•œ ๋ชจ๋ธ์— ์—ฐ๊ฒฐ๋œ๋‹ค. ์šฐ๋ฆฌ ํ”„๋กœ์ ํŠธ์—์„œ๋„ DSPy๊ฐ€ Ollama ์œ„์—์„œ ์ž‘๋™ํ•˜๋„๋ก ๊ตฌ์„ฑํ–ˆ๋‹ค.


๐ŸŒŸ DSPy์˜ ํ•ต์‹ฌ ๊ฐœ๋…

DSPy๋ฅผ ์ด๋ฃจ๋Š” ํ•ต์‹ฌ ๊ฐœ๋…์€ Signature, Module, Optimizer ์„ธ ๊ฐ€์ง€์ด๋‹ค. ๊ฐ๊ฐ์ด ๋ฌด์—‡์ธ์ง€, ๊ทธ๋ฆฌ๊ณ  ์šฐ๋ฆฌ ํ”„๋กœ์ ํŠธ์—์„œ ์–ด๋–ป๊ฒŒ ํ‘œํ˜„๋๋Š”์ง€๋ฅผ ํ•จ๊ป˜ ์‚ดํŽด๋ณด๊ฒ ๋‹ค.

โœจ Signature: LLM์—๊ฒŒ ๋ฌด์—‡์„ ์›ํ•˜๋Š”์ง€ ์„ ์–ธ

Signature๋Š” LLM ํ˜ธ์ถœ ํ•˜๋‚˜์˜ ์ž…์ถœ๋ ฅ ๋ช…์„ธ์ด๋‹ค. "์–ด๋–ค ์ •๋ณด๋ฅผ ์ฃผ๋ฉด ์–ด๋–ค ์ •๋ณด๋ฅผ ๋Œ๋ ค๋‹ฌ๋ผ"๋ฅผ ์ฝ”๋“œ๋กœ ์„ ์–ธํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

์ผ๋ฐ˜์ ์ธ ํ˜•ํƒœ๋Š” ์ด๋ ‡๋‹ค.

class ์‹œ๊ทธ๋‹ˆ์ฒ˜_์ด๋ฆ„(dspy.Signature):
   """์ด LLM ํ˜ธ์ถœ์˜ ๋ชฉ์ ์„ ์„ค๋ช…ํ•˜๋Š” docstring (์ž๋™์œผ๋กœ ํ”„๋กฌํ”„ํŠธ ์ง€์‹œ์‚ฌํ•ญ์ด ๋œ๋‹ค)"""
   
   ์ž…๋ ฅํ•„๋“œ: str = dspy.InputField(desc="ํ•„๋“œ ์„ค๋ช…")
   ์ถœ๋ ฅํ•„๋“œ: str = dspy.OutputField(desc="ํ•„๋“œ ์„ค๋ช…")

docstring๊ณผ ๊ฐ ํ•„๋“œ์˜ desc๊ฐ€ ๊ทธ๋Œ€๋กœ ํ”„๋กฌํ”„ํŠธ์˜ ์ง€์‹œ์‚ฌํ•ญ์œผ๋กœ ๋ณ€ํ™˜๋œ๋‹ค. ๊ฐœ๋ฐœ์ž๊ฐ€ ํ”„๋กฌํ”„ํŠธ ๋ฌธ์ž์—ด์„ ์ง์ ‘ ์ž‘์„ฑํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

์šฐ๋ฆฌ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” Signature๋ฅผ ๋‘ ๊ฐœ ์„ค๊ณ„ํ–ˆ๋‹ค.

  1. ๊ด‘๊ณ  ์ •๋ณด โ†’ ์นดํ…Œ๊ณ ๋ฆฌ ์ถ”๋ก 
    class InferCategories(dspy.Signature):
       """๊ด‘๊ณ  ์ •๋ณด๋ฅผ ๋ถ„์„ํ•˜์—ฌ DB ๊ฒ€์ƒ‰์— ์‚ฌ์šฉํ•  ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์ถ”๋ก ํ•ฉ๋‹ˆ๋‹ค.
       ๋ฐ˜๋“œ์‹œ ํ•œ๊ตญ์–ด๋กœ ๋‹ต๋ณ€ํ•˜์„ธ์š”."""
       
       ad_concept: str = dspy.InputField(desc="๊ด‘๊ณ  ์ปจ์…‰ ์„ค๋ช…")
       ad_item: str = dspy.InputField(desc="๊ด‘๊ณ  ์ƒํ’ˆ/์„œ๋น„์Šค๋ช…")
       advertiser: str = dspy.InputField(desc="๊ด‘๊ณ ์ฃผ ๋ธŒ๋žœ๋“œ๋ช…")
       categoreis: str = dspy.OutputField(
          desc=(
             "์‰ผํ‘œ๋กœ ๊ตฌ๋ถ„๋œ ์นดํ…Œ๊ณ ๋ฆฌ. ๋ฐ˜๋“œ์‹œ ๋‹ค์Œ ์ค‘์—์„œ๋งŒ ์„ ํƒ: "
             "beauty, fashion, tech, food, travel, fitness, gaming, music, education, lifestyle"
          )
       )
    โžก๏ธ "์ด๋‹ˆ์Šคํ”„๋ฆฌ ์œ ๊ธฐ๋† ์Šคํ‚จ์ผ€์–ด" ๊ด‘๊ณ ๊ฐ€ ๋“ค์–ด์˜ค๋ฉด beauty๋ฅผ ์ถœ๋ ฅํ•˜๋Š” LLM ํ˜ธ์ถœ ํ•˜๋‚˜๋ฅผ ์„ ์–ธํ•œ ๊ฒƒ์ด๋‹ค.
  1. ์ ์ˆ˜ ๊ฒฐ๊ณผ โ†’ TOP3 ์„ ์ • + ์ถ”์ฒœ๋ฌธ ์ž‘์„ฑ
    class RankAndRecommend(dspy.Signature):
       """๋งค์นญ ์ ์ˆ˜ ๊ฒฐ๊ณผ๋ฅผ ๋ถ„์„ํ•˜์—ฌ TOP3๋ฅผ ์„ ์ •ํ•˜๊ณ  ํ•œ๊ตญ์–ด ์ถ”์ฒœ ๊ฒฐ๊ณผ๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.
       ๋ฐ˜๋“œ์‹œ ํ•œ๊ตญ์–ด๋กœ๋งŒ ๋‹ต๋ณ€ํ•˜์„ธ์š”. ์ค‘๊ตญ์–ด ์‚ฌ์šฉ ์ ˆ๋Œ€ ๊ธˆ์ง€."""
       
       ad_concept: str = dspy.InputField(desc="๊ด‘๊ณ  ์ปจ์…‰")
       ad_item: str = dspy.InputField(desc="๊ด‘๊ณ  ์•„์ดํ…œ")
       scores_summary: str = dspy.InputField(
          desc="์ธํ”Œ๋ฃจ์–ธ์„œ๋ณ„ overall_grade(S>A>B>C>D)์™€ ์ฐจ์› ํ‰๊ฐ€(์ƒ/์ค‘/ํ•˜) JSON"
       )
       top3_names: list[str] = dspy.OutputField(
          desc="overall_grade ๊ธฐ์ค€ ์ƒ์œ„ 3๋ช…์˜ ์ธํ”Œ๋ฃจ์–ธ์„œ ์ด๋ฆ„ ๋ฆฌ์ŠคํŠธ (์ •ํ™•ํžˆ 3๊ฐœ)"
       )
       recommendation: str = dspy.OutputField(
          desc="ํ•œ๊ตญ์–ด ์ถ”์ฒœ ๊ฒฐ๊ณผ๋ฌธ. ๊ฐ ์ธํ”Œ๋ฃจ์–ธ์„œ๋ณ„ ์ด๋ฆ„, ์ข…ํ•ฉ ๋“ฑ๊ธ‰, ์ถ”์ฒœ ์ด์œ  ํฌํ•จ"
       )
    โžก๏ธ ์—ฌ๊ธฐ์„œ ์ฃผ๋ชฉํ•  ๊ฒƒ์ด ์žˆ๋‹ค. ์ถœ๋ ฅ ํ•„๋“œ๋กœ top3_names: list[str]์ฒ˜๋Ÿผ ํƒ€์ž…์„ ์„ ์–ธํ•˜๋ฉด DSPy๊ฐ€ LLM ์ถ”๋ ฅ์„ ํ•ด๋‹น ํƒ€์ž…์œผ๋กœ ํŒŒ์‹ฑํ•ด์ค€๋‹ค. ๊ธฐ์กด ๋ฐฉ์‹์—์„œ ์ •๊ทœ์‹์œผ๋กœ ์ด๋ฆ„์„ ์ผ์ผ์ด ์ถ”์ถœํ•˜๋˜ ์ฝ”๋“œ๊ฐ€ ํ•„์š” ์—†์–ด์ง„๋‹ค.

โœจ Module: LLM ํ˜ธ์ถœ๊ณผ Python ๋กœ์ง์„ ํ•˜๋‚˜์˜ ํ”„๋กœ๊ทธ๋žจ์œผ๋กœ

Signature๊ฐ€ LLM ํ˜ธ์ถœ ํ•˜๋‚˜๋ฅผ ์ •์˜ํ•œ๋‹ค๋ฉด, Module์€ ์—ฌ๋Ÿฌ Signature์™€ ๊ฒฐ์ •๋ก ์  Python ์ฝ”๋“œ๋ฅผ ์กฐํ•ฉํ•ด ์™„์ „ํ•œ ํ”„๋กœ๊ทธ๋žจ ํ•˜๋‚˜๋ฅผ ๋งŒ๋“œ๋Š” ๋‹จ์œ„์ด๋‹ค. PyTorch์˜ nn.Module์—์„œ ์ง์ ‘ ์˜๊ฐ์„ ๋ฐ›์€ ๊ตฌ์กฐ๋‹ค.

Module์„ ๋งŒ๋“ค ๋•Œ๋Š” ๋‘ ๊ฐ€์ง€๋ฅผ ์ •์˜ํ•œ๋‹ค.

  • __init__: ์–ด๋–ค Predictor(LLM ํ˜ธ์ถœ)๋ฅผ ์‚ฌ์šฉํ• ์ง€ ์„ ์–ธ
  • forward(): ์‹ค์ œ ์‹คํ–‰ ํ๋ฆ„ (LLM ํ˜ธ์ถœ + Python ๋กœ์ง)

์šฐ๋ฆฌ ํ”„๋กœ์ ํŠธ์˜ InfluencerMatchingModule์ด ์ด ๊ตฌ์กฐ๋ฅผ ์ž˜ ๋ณด์—ฌ์ค€๋‹ค.

class InfluencerMatchingModule(dspy.Module):

   def __init__(self, repo):
      super().__init__()
      self.repo = repo
      self.infer_categories = dspy.Predict(InferCategories) # LLM ํ˜ธ์ถœ 1
      self.rank = dspy.ChainOfThought(RankAndRecommend) # LLM ํ˜ธ์ถœ 2
      
   def forward(self, ad_concept: str, ad_item: str, advertiser: str):
   
      # -- Step 1: LLM โ†’ ์นดํ…Œ๊ณ ๋ฆฌ ์ถ”๋ก  ----------------------
      cats_pred = self.infer_categories(
         ad_concept=ad_concept, ad_item=ad_item, advertiser=advertiser
      )
      categories = [c.strip() for c in cats_pred.categories.split(",")]
      
      # -- Step 2: Python โ†’ DB ๊ฒ€์ƒ‰ (๊ฒฐ์ •๋ก ์ ) --------------
      influencers = self.repo.find_by_categories(categories)
      
      # -- Step 3: Python โ†’ ๋งค์นญ ์ ์ˆ˜ ๊ณ„์‚ฐ (๊ฒฐ์ •๋ก ์ ) --------
      scores = []
      for inf in influencers:
         result = calculate_match_score_raw(inf, categories, [])
         scores.append({ "name": inf.name, "overall_grade": result["overall_grade"], ... })
      scores.sort(key=lambda x: grade_order[x["overall_grade"]], reverse=True)
      
      # -- Step 4: LLM โ†’ TOP3 ์„ ์ • + ์ถ”์ฒœ๋ฌธ ์ƒ์„ฑ -------------
      rank_pred = self.rank(
         ad_concept=ad_concept,
         ad_item=ad_item,
         scores_summary=json.dumps(scores[:10], ensure_ascii=False),
      )
      return rank_pred

forward()์˜ ํ๋ฆ„์„ ๋ณด๋ฉด LLM์ด ๋‹ด๋‹นํ•˜๋Š” ๋ถ€๋ถ„๊ณผ Python์ด ๋‹ด๋‹นํ•˜๋Š” ๋ถ€๋ถ„์ด ๋ช…ํ™•ํ•˜๊ฒŒ ๋‚˜๋‰œ๋‹ค.

๋‹จ๊ณ„๋‹ด๋‹น์ด์œ 
์นดํ…Œ๊ณ ๋ฆฌ ์ถ”๋ก LLM์ž์—ฐ์–ด ์ดํ•ด๊ฐ€ ํ•„์š”
DB ๊ฒ€์ƒ‰Python์ •ํ™•ํ•œ ์ฟผ๋ฆฌ๊ฐ€ ํ•„์š”, LLM์ด ๊ฐœ์ž…ํ•˜๋ฉด ์˜ค๋ฅ˜ ๊ฐ€๋Šฅ์„ฑ
์ ์ˆ˜ ๊ณ„์‚ฐPython์ˆ˜์น˜ ๊ณ„์‚ฐ์€ ๊ฒฐ์ •๋ก ์ ์ด์–ด์•ผ ํ•จ
TOP3 ์„ ์ • + ์ถ”์ฒœ๋ฌธLLM์ž์—ฐ์–ด ์ƒ์„ฑ์ด ํ•„์š”

์ด๊ฒƒ์ด Module์ด ์ฃผ๋Š” ํ•ต์‹ฌ ๊ฐ€์น˜์ด๋‹ค. LLM์ด ํ•ด์•ผ ํ•  ์ผ๊ณผ Python์ด ํ•ด์•ผ ํ•  ์ผ์„ ์ฝ”๋“œ ๊ตฌ์กฐ๋กœ ๋ถ„๋ฆฌํ•œ๋‹ค. ๊ธฐ์กด ReAct ์—์ด์ „ํŠธ์ฒ˜๋Ÿผ LLM์ด ํ๋ฆ„ ์ „์ฒด๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ํ๋ฆ„์€ forward() ์ฝ”๋“œ๊ฐ€ ๊ณ ์ •ํ•˜๊ณ  LLM์€ ํ•„์š”ํ•œ ์ง€์ ์—์„œ๋งŒ ํ˜ธ์ถœ๋œ๋‹ค.

dspy.Predict์™€ dspy.ChainOfThought์˜ ์ฐจ์ด๋„ ์งš๊ณ  ๊ฐ€์ž.

  • dspy.Predict: Signature๋ฅผ ๊ทธ๋Œ€๋กœ LLM์— ์ „๋‹ฌํ•ด ์ถœ๋ ฅ์„ ๋ฐ›๋Š”๋‹ค. ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ LLM ํ˜ธ์ถœ
  • dspy.ChainOfThought: LLM์—๊ฒŒ ์ตœ์ข… ๋‹ต ์ „์— ์ถ”๋ก  ๊ณผ์ •์„ ๋จผ์ € ์“ฐ๋„๋ก ์œ ๋„ํ•œ๋‹ค. RankAndRecommend์ฒ˜๋Ÿผ ์—ฌ๋Ÿฌ ํ›„๋ณด ์ค‘ ์ˆœ์œ„๋ฅผ ๋งค๊ธฐ๋Š” ์ž‘์—…์— ์ ํ•ฉํ•˜๋‹ค.

โœจ Optimizer: metric์„ ์ •์˜ํ•˜๋ฉด ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ž๋™์œผ๋กœ ๊ฐœ์„ 

Optimizer๊ฐ€ DSPy์˜ ํ•ต์‹ฌ์ด๋‹ค. ์•ž์„œ ๋งŒ๋“  Module์„ ๋” ์ž˜ ์ž‘๋™ํ•˜๋„๋ก ํ”„๋กฌํ”„ํŠธ์™€ few-shot ์˜ˆ์‹œ๋ฅผ ์ž๋™์œผ๋กœ ์ตœ์ ํ™”ํ•ด์ฃผ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.

์ž‘๋™ ์›๋ฆฌ๋ฅผ ์ดํ•ดํ•˜๋ ค๋ฉด ๋จผ์ € ๋‘ ๊ฐ€์ง€๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

  1. trainset: ์ตœ์ ํ™”์˜ ๊ธฐ์ค€์ด ๋˜๋Š” ์˜ˆ์‹œ ๋ฐ์ดํ„ฐ

    def _make_example(tc: TestCase) -> dspy.Example:
       return dspy.Example(
          ad_concept=tc.ad_concept,
          ad_item=tc.ad_item,
          advertiser=tc.advertiser,
          expected_categories=tc.expected_categories,
          competitor_brands=tc.competitor_brands,
       ).with_inputs("ad_concept", "ad_item", "advertiser")
    
    trainset = [_make_example(tc) for tc in TEST_CASES] # 10๊ฐœ

    ์šฐ๋ฆฌ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ์ด๋‹ˆ์Šคํ”„๋ฆฌ, bhc, ์‚ผ์„ฑ์ „์ž ๋“ฑ ์‹ค์ œ ํ•œ๊ตญ ๋ธŒ๋žœ๋“œ 10๊ฐœ๋ฅผ trainset์œผ๋กœ ๊ตฌ์„ฑํ–ˆ๋‹ค.

  1. metric ํ•จ์ˆ˜: "์ด ์˜ˆ์ธก์ด ์–ผ๋งˆ๋‚˜ ์ข‹์€๊ฐ€"๋ฅผ 0.0~1.0์œผ๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜
    def matching_metric(example, prediction, trace=None) -> float:
       recommended_names = list(prediction.top3_names or [])
       
       # evidence_pack ๊ตฌ์„ฑ ํ›„ 4๊ฐœ ๋ฉ”ํŠธ๋ฆญ ๊ณ„์‚ฐ
       results = [
          calculate_evidence_coverage(evidence_pack),  # ๋ฐ์ดํ„ฐ ์™„์ „์„ฑ
          calculate_semantic_relevance(evidence_pack), # ๊ด‘๊ณ  ์ ํ•ฉ๋„
          calculate_groundedness(evidence_pack),       # ํ• ๋ฃจ์‹œ๋„ค์ด์…˜ ์—ฌ๋ถ€
          calculate_competitor_check(evidence_pack),   # ๊ฒฝ์Ÿ์‚ฌ ์ด๋ ฅ ์—ฌ๋ถ€
       ]
       passed = sum(r["passed"] for r in results)
       return passed / len(results)  # 0.0 ~ 1.0
    4๊ฐœ ๋ฉ”ํŠธ๋ฆญ ์ค‘ ๋ช‡ ๊ฐœ๋ฅผ ํ†ต๊ณผํ–ˆ๋Š”์ง€ ๋น„์œจ๋กœ ๋ฐ˜ํ™˜ํ•œ๋‹ค. 4๊ฐœ ๋ชจ๋‘ ํ†ต๊ณผํ•˜๋ฉด 1.0, ํ•˜๋‚˜๋„ ๋ชป ํ†ต๊ณผํ•˜๋ฉด 0.0์ด๋‹ค.

์ด ๋‘ ๊ฐ€์ง€๊ฐ€ ์ค€๋น„๋˜๋ฉด Optimizer๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

from dspy.teleprompt import MIPROv2

optimizer = MIPROv2(
   metric=metric,
   auto="light",  # ํƒ์ƒ‰ ์˜ˆ์‚ฐ: light / medium / heavy
   num_threads=1,
)

optimized_module = optimizer.compile(
   module,
   trainset=trainset,
)

optimized_module.save("outputs/dspy_optimized.json")

MIPROv2๊ฐ€ ํ•˜๋Š” ์ผ์„ ๋‹จ๊ณ„๋ณ„๋กœ ํ’€๋ฉด ์ด๋ ‡๋‹ค.

  1. ํ˜„์žฌ Module์„ trainset์— ๋Œ๋ ค์„œ ๊ฐ ์˜ˆ์‹œ์˜ metric ์ ์ˆ˜๋ฅผ ์ธก์ •ํ•œ๋‹ค.
  2. ์ ์ˆ˜๊ฐ€ ๋‚ฎ์€ ์ง€์ ์„ ๋ถ„์„ํ•ด ๋” ๋‚˜์€ ํ”„๋กฌํ”„ํŠธ ํ›„๋ณด๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ ์ƒ์„ฑํ•œ๋‹ค.
  3. ํ›„๋ณด๋“ค์„ ๋‹ค์‹œ trainset์— ๋Œ๋ ค์„œ ์ ์ˆ˜๋ฅผ ๋น„๊ตํ•œ๋‹ค.
  4. ๊ฐ€์žฅ ๋†’์€ ์ ์ˆ˜์˜ ํ”„๋กฌํ”„ํŠธ ์กฐํ•ฉ์„ ์ตœ์ข… ๊ฒฐ๊ณผ๋กœ ์ €์žฅํ•œ๋‹ค.

์ด ๊ณผ์ •์—์„œ ๊ฐœ๋ฐœ์ž๊ฐ€ ํ•˜๋Š” ์ผ์€ ์—†๋‹ค. metric์„ ์ •์˜ํ•˜๊ณ  compile()์„ ํ˜ธ์ถœํ•˜๋ฉด ๋‚˜๋จธ์ง€๋Š” ์ž๋™์ด๋‹ค.

์ตœ์ ํ™” ๊ฒฐ๊ณผ๋Š” JSON ํŒŒ์ผ๋กœ ์ €์žฅ๋˜๊ณ , ์ดํ›„์—๋Š” Module์„ ๋กœ๋“œํ•ด์„œ ๋ฐ”๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

optimized_module = InfluencerMatchingModule(repo)
optimized_module.load("outputs/dspy_optimized.json")

result = optimized_module(
   ad_concept="๊ฑด๊ฐ•ํ•˜๊ณ  ์ž์—ฐ์Šค๋Ÿฌ์šด ์ด๋ฏธ์ง€์˜ ๋ทฐํ‹ฐ ์ œํ’ˆ",
   ad_item="์œ ๊ธฐ๋† ์Šคํ‚จ์ผ€์–ด ๋ผ์ธ",
   advertiser="์ด๋‹ˆ์Šคํ”„๋ฆฌ",
)
print(result.top3_names)  # ['ํ™์„œ์—ฐ', '๊น€๋ฏผ์ค€', '์ด์ˆ˜์ง„']
print(result.recommendation)  # ํ•œ๊ตญ์–ด ์ถ”์ฒœ ๊ฒฐ๊ณผ๋ฌธ

โœจ ์„ธ ๊ฐœ๋…์˜ ๊ด€๊ณ„ ์ •๋ฆฌ

Signature๋Š” ๋ถ€ํ’ˆ, Module์€ ์™„์„ฑํ’ˆ, Optimizer๋Š” ์™„์„ฑํ’ˆ์„ ๋” ์ž˜ ๋งŒ๋“ค์–ด์ฃผ๋Š” ๊ณต์žฅ์ด๋‹ค.


๐ŸŒŸ ํ”„๋กœ์ ํŠธ์— DSPy ๋„์ž…

๐Ÿง ๊ธฐ์กด ์—์ด์ „ํŠธ ๊ตฌ์กฐ ๋‹ค์‹œ ๋ณด๊ธฐ

์šฐ๋ฆฌ ํ”„๋กœ์ ํŠธ์˜ ์—์ด์ „ํŠธ๋Š” ReAct(Reasoning + Acting) ํŒจํ„ด ๊ธฐ๋ฐ˜์œผ๋กœ, LangChain์œผ๋กœ ๊ตฌํ˜„๋˜์–ด ์žˆ๋‹ค. ์—์ด์ „ํŠธ๋Š” 5๊ฐœ์˜ ๋„๊ตฌ๋ฅผ ์ž์œ ๋กญ๊ฒŒ ์„ ํƒํ•˜๋ฉด์„œ ๋™์ž‘ํ•œ๋‹ค.์ด ๊ตฌ์กฐ์˜ ํŠน์ง•์€ LLM์ด ํ๋ฆ„์„ ์ง์ ‘ ๊ฒฐ์ •ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ์–ด๋–ค ๋„๊ตฌ๋ฅผ ๋ช‡ ๋ฒˆ ํ˜ธ์ถœํ• ์ง€, ์–ด๋–ค ์ˆœ์„œ๋กœ ์ง„ํ–‰ํ• ์ง€๋ฅผ ๋ชจ๋‘ LLM์ด ํŒ๋‹จํ•œ๋‹ค.
๋•๋ถ„์— ์œ ์—ฐํ•˜์ง€๋งŒ, ๊ทธ ์œ ์—ฐํ•จ์ด ํ‰๊ฐ€๋ฅผ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ ๋‹ค. ์‹คํ–‰ํ•  ๋•Œ๋งˆ๋‹ค ๊ฒฝ๋กœ๊ฐ€ ๋‹ฌ๋ผ์ง€๊ณ , ์ตœ์ข… ์‘๋‹ต์˜ ํ˜•์‹๋„ ์ผ์ •ํ•˜์ง€ ์•Š๋‹ค.

โœจ ๊ธฐ์กด ์ฝ”๋“œ์™€ DSPy ๊ฐœ๋…์˜ 1:1 ๋งคํ•‘

์ด ์—์ด์ „ํŠธ๋ฅผ DSPy๋กœ ์žฌ์„ค๊ณ„ํ•  ๋•Œ, ๊ธฐ์กด ์ฝ”๋“œ์˜ ๊ฐ ์š”์†Œ๊ฐ€ DSPy์˜ ์–ด๋–ค ๊ฐœ๋…์— ๋Œ€์‘๋˜๋Š”์ง€๋ฅผ ๋จผ์ € ์ •๋ฆฌํ–ˆ๋‹ค.

๊ธฐ์กด ์ฝ”๋“œDSPy ๊ฐœ๋…์—ญํ• 
AGENT_SYSTEM_PROMPT (๋ฌธ์ž์—ด)SignatureLLM ํ˜ธ์ถœ์˜ ์ž…์ถœ๋ ฅ ๋ช…์„ธ
AgentService (LangChain)InfluencerMatchingModule์ „์ฒด ์‹คํ–‰ ํ๋ฆ„
TEST_CASES ๋ฆฌ์ŠคํŠธtrainset์ตœ์ ํ™” ๊ธฐ์ค€ ๋ฐ์ดํ„ฐ
metrics.py 4๊ฐœ ํ•จ์ˆ˜matching_metric์˜ˆ์ธก ํ’ˆ์งˆ ์ธก์ • ํ•จ์ˆ˜
์ˆ˜๋™ ํ”„๋กฌํ”„ํŠธ ์ˆ˜์ •MIPROv2์ž๋™ ์ตœ์ ํ™”

ํ•ต์‹ฌ์€ ๋งˆ์ง€๋ง‰ ํ–‰์ด๋‹ค. ๊ธฐ์กด์—๋Š” ์—์ด์ „ํŠธ๊ฐ€ ์ž˜๋ชป๋œ ๊ฒฐ๊ณผ๋ฅผ ๋‚ด๋†“์œผ๋ฉด AGENT_SYSTEM_PROMPT๋ฅผ ์—ด์–ด์„œ ์ง์ ‘ ๋ฌธ์žฅ์„ ์ˆ˜์ •ํ–ˆ๋‹ค. DSPy์—์„œ๋Š” ๊ทธ ์ž‘์—…์„ MIPROv2๊ฐ€ ๋Œ€์‹ ํ•œ๋‹ค.

โœจ ์•„ํ‚คํ…์ฒ˜์˜ ๊ทผ๋ณธ์ ์ธ ์ฐจ์ด

๋งคํ•‘ ํ‘œ๋ณด๋‹ค ์ค‘์š”ํ•œ ๊ฒƒ์€, DSPy ๋ฐฉ์‹์ด ๊ธฐ์กด ์—์ด์ „ํŠธ์™€ ๊ตฌ์กฐ์ ์œผ๋กœ ์–ด๋–ป๊ฒŒ ๋‹ค๋ฅธ๊ฐ€์ด๋‹ค.

  • ๊ธฐ์กด LangChain ReAct ์—์ด์ „ํŠธ: LLM์ด ํ๋ฆ„์„ ๊ฒฐ์ •ํ•œ๋‹ค.

  • DSPy InfluencerMatchingModule: ์ฝ”๋“œ๊ฐ€ ํ๋ฆ„์„ ๊ฒฐ์ •ํ•˜๊ณ , LLM์€ ์ง€์ •๋œ ์ง€์ ์—์„œ๋งŒ ํ˜ธ์ถœ๋œ๋‹ค.

ReAct ์—์ด์ „ํŠธ๋„ DB ๊ฒ€์ƒ‰๊ณผ ์ ์ˆ˜ ๊ณ„์‚ฐ์€ Python์œผ๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค. search_influencers_by_category๋‚˜ calculate_match_score๋Š” ๋ชจ๋‘ Python ํ•จ์ˆ˜๋‹ค. ์ฐจ์ด๋Š” ๊ทธ Python ํ•จ์ˆ˜๊ฐ€ ์–ด๋–ป๊ฒŒ ํ˜ธ์ถœ๋˜๋А๋ƒ์— ์žˆ๋‹ค.

ReAct์—์„œ๋Š” LLM์ด "์ง€๊ธˆ ์ด ๋„๊ตฌ๋ฅผ ์จ์•ผ๊ฒ ๋‹ค"๊ณ  ํŒ๋‹จํ•ด์•ผ Python ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋œ๋‹ค. LLM์ด ํ๋ฆ„์˜ ์ฃผ๋„๊ถŒ์„ ๊ฐ–๊ณ  ์žˆ์–ด์„œ, ์–ด๋–ค ๋„๊ตฌ๋ฅผ ๋ช‡ ๋ฒˆ ํ˜ธ์ถœํ• ์ง€, ์–ด๋–ค ์ˆœ์„œ๋กœ ์ง„ํ–‰ํ• ์ง€๊ฐ€ ์‹คํ–‰ํ•  ๋•Œ๋งˆ๋‹ค ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ๋‹ค.

DSPy Module์—์„œ๋Š” forward() ์ฝ”๋“œ๊ฐ€ ํ๋ฆ„์„ ์ฒ˜์Œ๋ถ€ํ„ฐ ๊ณ ์ •ํ•œ๋‹ค. DB ๊ฒ€์ƒ‰๊ณผ ์ ์ˆ˜ ๊ณ„์‚ฐ์€ LLM์˜ ํŒ๋‹จ์„ ๊ฑฐ์น˜์ง€ ์•Š๊ณ  ์ฝ”๋“œ๊ฐ€ ์ง์ ‘ ํ˜ธ์ถœํ•œ๋‹ค. LLM์€ "์ž์—ฐ์–ด๋กœ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์ถ”๋ก ํ•˜๋Š” ๊ฒƒ"๊ณผ "์ž์—ฐ์–ด๋กœ ์ถ”์ฒœ๋ฌธ์„ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ", ๋”ฑ ๋‘ ์ง€์ ์—์„œ๋งŒ ๊ฐœ์ž…ํ•œ๋‹ค.

๊ฒฐ๊ตญ ๋‘ ๋ฐฉ์‹ ๋ชจ๋‘ Python์ด ๊ณ„์‚ฐํ•˜๋Š” ๊ฑด ๊ฐ™์ง€๋งŒ, ๋‹ฌ๋ผ์ง€๋Š” ๊ฒƒ์€ ๊ทธ ๊ณ„์‚ฐ์„ LLM์˜ ๊ฒฐ์ •์— ์˜ํ•ด ํŠธ๋ฆฌ๊ฑฐํ•˜๋А๋ƒ, ์ฝ”๋“œ๊ฐ€ ์ง์ ‘ ํŠธ๋ฆฌ๊ฑฐํ•˜๋А๋ƒ๋‹ค.

โœจ ํ‰๊ฐ€ ๊ธฐ์ค€ - 4๊ฐœ์˜ Metric ์„ค๊ณ„

DSPy Optimizer๊ฐ€ ์ž‘๋™ํ•˜๋ ค๋ฉด "์ข‹์€ ์ถ”์ฒœ์ด๋ž€ ๋ฌด์—‡์ธ๊ฐ€"๋ฅผ ์ฝ”๋“œ๋กœ ์ •์˜ํ•ด์•ผ ํ•œ๋‹ค. ์šฐ๋ฆฌ๋Š” ์ด๋ฅผ 4๊ฐœ์˜ ๋ฉ”ํŠธ๋ฆญ์œผ๋กœ ํ‘œํ˜„ํ–ˆ๋‹ค.

  1. Evidence Coverage: ๋ฐ์ดํ„ฐ ์™„์ „์„ฑ (์ž„๊ณ„๊ฐ’ 60%)
    ์ถ”์ฒœ๋œ ์ธํ”Œ๋ฃจ์–ธ์„œ๊ฐ€ DB์— ์‹ค์ œ๋กœ ์กด์žฌํ•˜๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ํŒ”๋กœ์›Œ ์ˆ˜ยท์ฐธ์—ฌ์œจยทํ”Œ๋žซํผยท์นดํ…Œ๊ณ ๋ฆฌ ๋“ฑ ํ•„์ˆ˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ–์ถ”๊ณ  ์žˆ๋Š”์ง€ 5๊ฐœ ํ•ญ๋ชฉ์œผ๋กœ ์ ๊ฒ€ํ•œ๋‹ค.
    • has_followers: ํŒ”๋กœ์›Œ ์ˆ˜ > 0
    • has_engagement: ์ฐธ์—ฌ์œจ ๋ฐ์ดํ„ฐ ์กด์žฌ
    • has_platform: ํ”Œ๋žซํผ ์ •๋ณด ์กด์žฌ
    • has_description: ์†Œ๊ฐœ ํ…์ŠคํŠธ ์กด์žฌ
    • category_fit: ๊ธฐ๋Œ€ ์นดํ…Œ๊ณ ๋ฆฌ์™€ ์ผ์น˜
  1. Semantic Relevance: ๊ด‘๊ณ  ์ ํ•ฉ๋„ (์ž„๊ณ„๊ฐ’ 0.2)
    ๊ด‘๊ณ  ํ…์ŠคํŠธ์˜ ํ‚ค์›Œ๋“œ์™€ ์ธํ”Œ๋ฃจ์–ธ์„œ ์„ค๋ช…์˜ ํ‚ค์›Œ๋“œ๊ฐ€ ์–ผ๋งˆ๋‚˜ ๊ฒน์น˜๋Š”์ง€๋ฅผ ์ธก์ •ํ•œ๋‹ค. ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ์™„์ „ํžˆ ์ผ์น˜ํ•˜๋ฉด +0.3 ๋ณด๋„ˆ์Šค๋ฅผ ์ค€๋‹ค.

    similarity = |๊ด‘๊ณ  ํ‚ค์›Œ๋“œ โˆฉ ์ธํ”Œ๋ฃจ์–ธ์„œ ํ‚ค์›Œ๋“œ| / |๊ด‘๊ณ  ํ‚ค์›Œ๋“œ|

  1. Groundedness: ํ• ๋ฃจ์‹œ๋„ค์ด์…˜ ์ฒดํฌ (์ž„๊ณ„๊ฐ’ 66%)
    ์—์ด์ „ํŠธ๊ฐ€ ์‘๋‹ต์— ์ ์€ ๋‚ด์šฉ์ด ์‹ค์ œ DB ๋ฐ์ดํ„ฐ์™€ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.
    • name_in_db: ์ถ”์ฒœ ์ด๋ฆ„์ด DB์— ์‹ค์ œ๋กœ ์กด์žฌ
    • category_mentioned: ์‘๋‹ต์— ํ•ด๋‹น ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ์–ธ๊ธ‰๋จ
    • follower_data_exists: ํŒ”๋กœ์›Œ ์ˆ˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์‹ค์ œ๋กœ ์žˆ์Œ
  1. Competitor Check: ๊ฒฝ์Ÿ์‚ฌ ์ด๋ ฅ (HIGH ๋ฆฌ์Šคํฌ 0๋ช…)
    ์ถ”์ฒœ๋œ ์ธํ”Œ๋ฃจ์–ธ์„œ์˜ ๊ณผ๊ฑฐ ๊ด‘๊ณ  ์ด๋ ฅ์—์„œ ๊ฒฝ์Ÿ์‚ฌ ์ด๋ ฅ์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.
    • LOW: ์ด๋ ฅ ์—†์Œ
    • MEDIUM: ๋™์ผ ์นดํ…Œ๊ณ ๋ฆฌ ๊ด‘๊ณ  ์ด๋ ฅ ์žˆ์Œ
    • HIGH: ๊ฒฝ์Ÿ์‚ฌ ์ง์ ‘ ๊ด‘๊ณ  ์ด๋ ฅ ์žˆ์Œ โ†’ FAIL

์ด 4๊ฐœ ์ค‘ ๋ช‡ ๊ฐœ๋ฅผ ํ†ต๊ณผํ–ˆ๋Š”์ง€ ๋น„์œจ์ด MIPROv2์— ์ „๋‹ฌ๋˜๋Š” ์ตœ์ข… ์ ์ˆ˜์ด๋‹ค. Optimizer๋Š” ์ด ์ ์ˆ˜๋ฅผ ๋†’์ด๋Š” ๋ฐฉํ–ฅ์œผ๋กœ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ž๋™์œผ๋กœ ์กฐ์ •ํ•œ๋‹ค.

โœจ Trainset / Testset ๋ถ„๋ฆฌ ์ „๋žต

ML์—์„œ ํ•™์Šต ๋ฐ์ดํ„ฐ์™€ ๊ฒ€์ฆ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถ„๋ฆฌํ•˜๋“ฏ, DSPy์—์„œ๋„ ๊ฐ™์€ ์›์น™์„ ์ ์šฉํ–ˆ๋‹ค.

# TEST_CASES (10๊ฐœ) - MIPROv2 ์ตœ์ ํ™”์— ์‚ฌ์šฉํ•˜๋Š” trainset
# ์ด๋‹ˆ์Šคํ”„๋ฆฌ, bhc, ์‚ผ์„ฑ์ „์ž, ๋‚˜์ดํ‚ค, ์—์–ด๋น„์•ค๋น„ ๋“ฑ

# TEST_SET (3๊ฐœ) - ์ตœ์ ํ™” ์™„๋ฃŒ ํ›„ ์ตœ์ข… ์„ฑ๋Šฅ ๊ฒ€์ฆ์—๋งŒ ์‚ฌ์šฉํ•˜๋Š” held-out testset
# ๋‹ค์ด์Šจ, ์ œ์ฃผํ•ญ๊ณต, GS25

held-out testset์˜ ์—ญํ• ์ด ์ค‘์š”ํ•˜๋‹ค. Optimizer๊ฐ€ trainset 10๊ฐœ์˜ ์ ์ˆ˜๋ฅผ ๋†’์ด๋Š” ๊ณผ์ •์—์„œ ๊ทธ ๋ฐ์ดํ„ฐ์— ๊ณผ์ ํ•ฉ๋  ์ˆ˜ ์žˆ๋‹ค. ์ตœ์ ํ™”์— ํ•œ ๋ฒˆ๋„ ๋…ธ์ถœ๋˜์ง€ ์•Š์€ 3๊ฐœ ์ผ€์ด์Šค๋กœ ์ตœ์ข… ์„ฑ๋Šฅ์„ ๊ฒ€์ฆํ•ด์•ผ ์‹ค์ œ ์ผ๋ฐ˜ํ™” ์„ฑ๋Šฅ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ’ฅ ์„ค๊ณ„ ๊ณผ์ •์—์„œ ๋“œ๋Ÿฌ๋‚œ ๊ตฌ์กฐ์  ๊ธด์žฅ

์„ค๊ณ„๋ฅผ ๋งˆ๋ฌด๋ฆฌํ•˜๊ณ  ์ฝ”๋“œ๋ฅผ ๋Œ๋ ค๋ณด๋ฉด์„œ ํฅ๋ฏธ๋กœ์šด ๋ฌธ์ œ ํ•˜๋‚˜๊ฐ€ ๋“œ๋Ÿฌ๋‚ฌ๋‹ค. RankAndRecommend์—์„œ LLM์—๊ฒŒ ์ƒ์œ„ 10๋ช…์˜ ์ ์ˆ˜ ์š”์•ฝ JSON์„ ๋„˜๊ธฐ๊ณ  TOP3 ์ด๋ฆ„์„ ๋ฝ‘์•„๋‹ฌ๋ผ๊ณ  ํ–ˆ๋Š”๋ฐ, LLM์ด ๊ฐ€๋” JSON์— ์—†๋Š” ์ด๋ฆ„์„ ๋งŒ๋“ค์–ด๋ƒˆ๋‹ค.

# LLM์ด ์ ์ˆ˜ ๊ธฐ์ค€ TOP3 ์•ˆ์— ์—†๋Š” ์ด๋ฆ„์„ ํฌํ•จํ•˜๋ฉด DB ๊ธฐ์ค€์œผ๋กœ ๋Œ€์ฒด
valid_names = {s["name"] for s in scores}
final_top3 = [n for n in llm_top3 if n in valid_names][:3]

if len(final_top3) < 3:
   for name in db_top3:
     if name not in final_top3:
        final_top3.append(name)
     if len(final_top3) == 3:
        break

์ด ๋ฐฉ์–ด ์ฝ”๋“œ๋Š” DSPy๋ฅผ ๋„์ž…ํ•˜๋ฉด์„œ ์ƒ๊ธด ๊ฒƒ์ด๋‹ค. ๊ธฐ์กด ReAct ์—์ด์ „ํŠธ๋Š” ๋„๊ตฌ๋ฅผ ํ†ตํ•ด DB ๊ฒฐ๊ณผ๋ฅผ ์ง์ ‘ ๋ฐ›์•„์˜ค๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Ÿฐ ์ข…๋ฅ˜์˜ ํ• ๋ฃจ์‹œ๋„ค์ด์…˜์ด ๊ตฌ์กฐ์ ์œผ๋กœ ์ฐจ๋‹จ๋œ๋‹ค. ๋ฐ˜๋ฉด DSPy ๋ฐฉ์‹์—์„œ๋Š” LLM์—๊ฒŒ "์ ์ˆ˜ ์š”์•ฝ ํ…์ŠคํŠธ"๋ฅผ ๊ฑด๋„ค๋ฉด์„œ ์ƒˆ๋กœ์šด ํ• ๋ฃจ์‹œ๋„ค์ด์…˜ ๊ฒฝ๋กœ๋ฅผ ๋งŒ๋“ค์–ด๋ฒ„๋ ธ๋‹ค.


๐ŸŒŸ ์‹ค์ œ๋กœ ๋ถ€๋”ชํžŒ ๋ฌธ์ œ๋“ค

๐Ÿšจ ๋ฌธ์ œ 1: ์—์ด์ „ํŠธ๋ฅผ ํ‰๊ฐ€ํ•œ ๊ฒŒ ์•„๋‹ˆ๋ผ ๊ต์ฒดํ•œ ๊ฒƒ์ด์—ˆ๋‹ค

๊ฐ€์žฅ ๊ทผ๋ณธ์ ์ธ ๋ฌธ์ œ์˜€๋‹ค.

์ฒ˜์Œ ์˜๋„๋Š” "๊ธฐ์กด LangChain ์—์ด์ „ํŠธ๋ฅผ DSPy๋กœ ํ‰๊ฐ€ํ•˜๊ณ , MIPROv2๋กœ ํ”„๋กฌํ”„ํŠธ๋กค ์ตœ์ ํ™”ํ•ด์„œ ์—์ด์ „ํŠธ ์„ฑ๋Šฅ์„ ๋†’์ด์ž"๋Š” ๊ฒƒ์ด์—ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์‹ค์ œ๋กœ ๋งŒ๋“ค์–ด์ง„ ๊ฒƒ์„ ๋‹ค์‹œ ๋“ค์—ฌ๋‹ค๋ณด๋‹ˆ ๊ทธ๊ฒŒ ์•„๋‹ˆ์—ˆ๋‹ค.

InfluencerMatchingModule์€ ๊ธฐ์กด AgentService๋ฅผ ๊ฐ์‹ผ ๋ž˜ํผ๊ฐ€ ์•„๋‹ˆ์—ˆ๋‹ค. ์™„์ „ํžˆ ๋‹ค๋ฅธ ์•„ํ‚คํ…์ฒ˜์˜€๋‹ค.MIPROv2๊ฐ€ ์ตœ์ ํ™”ํ•˜๋Š” ๋Œ€์ƒ์€ InferCategories์™€ RankAndRecommend, ๋‘ Signature์˜ ํ”„๋กฌํ”„ํŠธ์ด๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ด ํ”„๋กฌํ”„ํŠธ๋Š” ์‹ค์ œ๋กœ ๋ฐฐํฌ๋œ ์—์ด์ „ํŠธ์˜ AGENT_SYSTEM_PROMPT์™€ ์•„๋ฌด ๊ด€๋ จ์ด ์—†๋‹ค. DSPy Module ์•ˆ์—์„œ๋งŒ ์กด์žฌํ•˜๋Š” ๋ณ„๋„์˜ ํ”„๋กฌํ”„ํŠธ์ด๋‹ค.

์ฆ‰, MIPROv2 ์ตœ์ ํ™”๋ฅผ ์•„๋ฌด๋ฆฌ ๋Œ๋ ค๋„ ์‹ค์ œ ์„œ๋น„์Šค ์ค‘์ธ LangChain ์—์ด์ „ํŠธ๋Š” ํ•œ ๊ธ€์ž๋„ ๊ฐœ์„ ๋˜์ง€ ์•Š๋Š”๋‹ค. ์šฐ๋ฆฌ๋Š” ์—์ด์ „ํŠธ๋ฅผ ๋” ์ข‹๊ฒŒ ๋งŒ๋“ค๋ ค๊ณ  ํ–ˆ๋Š”๋ฐ, ๊ธฐ์กด ์—์ด์ „ํŠธ๋ฅผ ์•„์˜ˆ ์•ˆ ์“ฐ๊ณ  ์—์ด์ „ํŠธ๋ฅผ ๋‹ค๋ฅธ ๊ฒƒ์œผ๋กœ ๊ฐˆ์•„์น˜์šด ๋‹ค์Œ ๊ทธ๊ฒƒ์„ ์ตœ์ ํ™”ํ•˜๊ณ  ์žˆ์—ˆ๋‹ค.

๐Ÿšจ ๋ฌธ์ œ 2: ํ• ๋ฃจ์‹œ๋„ค์ด์…˜ ๊ฒฝ๋กœ๋ฅผ ์ƒˆ๋กœ ๋งŒ๋“ค์—ˆ๋‹ค

๊ธฐ์กด ReAct ์—์ด์ „ํŠธ์—์„œ๋Š” ์ด๋Ÿฐ ์ข…๋ฅ˜์˜ ํ• ๋ฃจ์‹œ๋„ค์ด์…˜์ด ๊ตฌ์กฐ์ ์œผ๋กœ ๋ง‰ํ˜€์žˆ๋‹ค. get_influencer_details ๋„๊ตฌ๊ฐ€ DB์—์„œ ์ง์ ‘ ์ธํ”Œ๋ฃจ์–ธ์„œ ๊ฐ์ฒด๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ๋•Œ๋ฌธ์—, ์—์ด์ „ํŠธ๊ฐ€ ์ตœ์ข… ์‘๋‹ต์— ์“ฐ๋Š” ์ด๋ฆ„์€ ๋„๊ตฌ ํ˜ธ์ถœ ๊ฒฐ๊ณผ์—์„œ ์˜จ ๊ฒƒ์ด๋‹ค. LLM์ด ์ด๋ฆ„์„ ์ง€์–ด๋‚ผ ์—ฌ์ง€๊ฐ€ ์—†๋‹ค.

๋ฐ˜๋ฉด DSPy Module์˜ RankAndRecommend๋Š” LLM์—๊ฒŒ ์ ์ˆ˜ ์š”์•ฝ JSON ํ…์ŠคํŠธ๋ฅผ ๋„˜๊ธฐ๊ณ , ๊ฑฐ๊ธฐ์„œ TOP3 ์ด๋ฆ„์„ ๋ฝ‘์•„๋‹ฌ๋ผ๊ณ  ์š”์ฒญํ•œ๋‹ค.

scores_summary = json.dumps(scores[:10], ensure_ascii=False, indent=2)

rank_pred = self.rank(
   ad_concept=ad_concept,
   ad_item=ad_item,
   scores_summary=scores_summary,  # ํ…์ŠคํŠธ๋กœ ์ „๋‹ฌ
)

# LLM์ด ๋ฐ˜ํ™˜ํ•œ ์ด๋ฆ„: rank_pred.top3_names

๋ฌธ์ œ๋Š” LLM์ด ์ด JSON์„ ์ฝ๊ณ  TOP3์„ ๊ณ ๋ฅด๋Š” ๊ณผ์ •์—์„œ ๊ฐ€๋” JSON์— ์—†๋Š” ์ด๋ฆ„์„ ๋งŒ๋“ค์–ด๋ƒˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. "ํ™์„œ์—ฐ"์ด ์—†๋Š”๋ฐ "ํ™์„œ์—ฐ"์ด top3_names์— ํฌํ•จ๋˜๋Š” ์‹์ด๋‹ค.

๊ฒฐ๊ตญ ์ด๋ฅผ ๋ง‰๊ธฐ ์œ„ํ•œ ๋ฐฉ์–ด ์ฝ”๋“œ๊ฐ€ ์ƒ๊ฒผ๋‹ค.

valid_names = {s["name"] for s in scores}
final_top3 = [n for n in llm_top3 if n in valid_names][:3]

# LLM์ด ๋ฝ‘์€ ์ด๋ฆ„์ด 3๊ฐœ๊ฐ€ ์•ˆ ๋˜๋ฉด ์ ์ˆ˜ ๊ธฐ์ค€ ์ƒ์œ„ ์ด๋ฆ„์œผ๋กœ ์ฑ„์›€
if len(final_top3) < 3:
   for name in db_top3:
      if name not in final_top3:
         final_top3.append(name)
      if len(final_top3) == 3:
         break

์ด ์ฝ”๋“œ์˜ ์กด์žฌ ์ž์ฒด๊ฐ€ ๋ฌธ์ œ๋ฅผ ๋“œ๋Ÿฌ๋‚ธ๋‹ค. DSPy๋ฅผ ๋„์ž…ํ•˜๋ฉด์„œ "LLM์ด ์ž์—ฐ์–ด ํ…์ŠคํŠธ๋ฅผ ๋ณด๊ณ  ์ด๋ฆ„์„ ์„ ํƒํ•œ๋‹ค"๋Š” ์ƒˆ๋กœ์šด ๋‹จ๊ณ„๋ฅผ ๋งŒ๋“ค์—ˆ๊ณ , ๊ทธ ๋‹จ๊ณ„๊ฐ€ ์ƒˆ๋กœ์šด ํ• ๋ฃจ์‹œ๋„ค์ด์…˜ ๊ฒฝ๋กœ๊ฐ€ ๋๋‹ค. ํ•ด๊ฒฐํ•˜๋ ค๋˜ ๋ฌธ์ œ๋ฅผ ๋” ๋ณต์žกํ•˜๊ฒŒ ๋งŒ๋“  ์…ˆ์ด๋‹ค.

๐Ÿšจ ๋ฌธ์ œ 3: ๋กœ์ปฌ Ollama์—์„œ MIPROv2๋Š” ํ˜„์‹ค์ ์œผ๋กœ ๋„ˆ๋ฌด ๋А๋ฆฌ๋‹ค

DSPy์˜ ๊ฐ€์žฅ ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ์€ MIPROv2์˜ ์ตœ์ ํ™”์ธ๋ฐ, ์ด๊ฒŒ ๋กœ์ปฌ ํ™˜๊ฒฝ์—์„œ๋Š” ์“ฐ๊ธฐ ์–ด๋ ค์› ๋‹ค.

MIPROv2๊ฐ€ ํ•˜๋Š” ์ผ์„ ๋‹จ์ˆœํ™”ํ•˜๋ฉด ์ด๋ ‡๋‹ค. ํ”„๋กฌํ”„ํŠธ ํ›„๋ณด๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ ๋งŒ๋“ค๊ณ , ๊ฐ ํ›„๋ณด๋ฅผ trainset ์ „์ฒด์— ๋Œ๋ ค๋ณด๊ณ , ์ ์ˆ˜๋ฅผ ๋น„๊ตํ•ด์„œ ๊ฐ€์žฅ ์ข‹์€ ๊ฒƒ์„ ์„ ํƒœํ•œ๋‹ค. ์ด ๊ณผ์ •์„ ์—ฌ๋Ÿฌ ๋ผ์šด๋“œ ๋ฐ˜๋ณตํ•œ๋‹ค.

๊ฐ€์žฅ ๊ฐ€๋ฒผ์šด ์„ค์ •์ธ auto="light"๋กœ ํ•ด๋„ LLM ํ˜ธ์ถœ์ด ์ˆ˜์‹ญ ๋ฒˆ ๋ฐœ์ƒํ•œ๋‹ค. ์—ฌ๊ธฐ์— trainset 10๊ฐœ๋ฅผ ๊ณฑํ•˜๋ฉด ์ด ํ˜ธ์ถœ ์ˆ˜๊ฐ€ ์ˆ˜๋ฐฑ ๋ฒˆ์— ์ด๋ฅธ๋‹ค.

optimizer = MIPROv2(
   metric=metric,
   auto="light",
   num_threads=1,  # ๋กœ์ปฌ Ollama: ๋ณ‘๋ ฌ 1๊ฐœ (API ์‚ฌ์šฉ ์‹œ ๋Š˜๋ ค๋„ ๋จ)
)

num_threads=1์ด๋ผ๋Š” ์ฃผ์„์ด ์ƒํ™ฉ์„ ์ž˜ ๋ณด์—ฌ์ค€๋‹ค. OpenAI๋‚˜ Anthropic API๋ฅผ ์“ฐ๋ฉด ์Šค๋ ˆ๋“œ๋ฅผ ๋Š˜๋ ค์„œ ๋ณ‘๋ ฌ๋กœ ๋Œ๋ฆด ์ˆ˜ ์žˆ๋Š”๋ฐ, ๋กœ์ปฌ Ollama๋Š” ๊ทธ๊ฒŒ ์•ˆ ๋œ๋‹ค. ์š”์ฒญ์„ ํ•˜๋‚˜์”ฉ ์ˆœ์ฐจ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๊ณ , ๊ฐ ํ˜ธ์ถœ์— ๋ช‡ ์ดˆ์”ฉ ๊ฑธ๋ฆฌ๋ฉด ์ „์ฒด ์ตœ์ ํ™”๊ฐ€ ๋ช‡ ์‹œ๊ฐ„์ด ๋  ์ˆ˜ ์žˆ๋‹ค.

์Šคํ„ฐ๋”” ํŠน์„ฑ์ƒ ์‹คํ—˜์„ ๋น ๋ฅด๊ฒŒ ๋Œ๋ ค๋ณด๊ณ  ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•˜๋Š” ๊ฒŒ ์ค‘์š”ํ•œ๋ฐ, ํ•œ ๋ฒˆ ์ตœ์ ํ™” ์‹คํ–‰์— ๋ช‡ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฌ๋Š” ๋ฐฉ์‹์€ ์ง€์†ํ•˜๊ธฐ ์–ด๋ ค์› ๋‹ค.

๐Ÿšจ ์„ธ ๋ฌธ์ œ์˜ ๊ด€๊ณ„

์„ธ ๋ฌธ์ œ๋Š” ๊ฐ๊ฐ ๋…๋ฆฝ์ ์ธ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ ํ•˜๋‚˜์˜ ๊ณตํ†ต๋œ ์›์ธ์—์„œ ์ถœ๋ฐœํ•œ๋‹ค.

DSPy๊ฐ€ ์ง„์งœ ํž˜์„ ๋ฐœํœ˜ํ•˜๋Š” ์ƒํ™ฉ์€ ์ด๋ ‡๋‹ค. LLM ํ˜ธ์ถœ์ด 2~3๊ฐœ๋กœ ๊ตฌ์„ฑ๋œ ๋ช…ํ™•ํ•œ ํŒŒ์ดํ”„๋ผ์ธ์ด ์žˆ๊ณ , ๊ฐ ํ˜ธ์ถœ์˜ ์ž…์ถœ๋ ฅ์ด ์ž˜ ์ •์˜๋˜์–ด ์žˆ์œผ๋ฉฐ, ์ถฉ๋ถ„ํ•œ trainset๊ณผ ๋น ๋ฅธ ์ถ”๋ก  ํ™˜๊ฒฝ์ด ๊ฐ–์ถฐ์ ธ ์žˆ์„ ๋•Œ๋‹ค.

์šฐ๋ฆฌ ํ”„๋กœ์ ํŠธ์˜ ์ƒํ™ฉ์€ ๋‹ฌ๋ž๋‹ค. ํ‰๊ฐ€ํ•˜๋ ค๋Š” ๋Œ€์ƒ์€ ReAct ์—์ด์ „ํŠธ, ์ฆ‰ LLM์ด ํ๋ฆ„์„ ์ž์œจ์ ์œผ๋กœ ๊ฒฐ์ •ํ•˜๋Š” ๋ฐฉ์‹์ด์—ˆ๋‹ค. ์ด ๊ตฌ์กฐ๋Š” forward()๋กœ ๊ณ ์ •๋œ ํ๋ฆ„์„ ์ „์ œํ•˜๋Š” DSPy Module๊ณผ ๋งž์ง€ ์•Š์•˜๋‹ค. ๋งž์ถ”๋ ค๋‹ค ๋ณด๋‹ˆ ์—์ด์ „ํŠธ๋ฅผ ๊ต์ฒดํ•˜๋Š” ๊ฒฐ๊ณผ๊ฐ€ ๋๊ณ , ๊ต์ฒด ๊ณผ์ •์—์„œ ์˜คํžˆ๋ ค ์ƒˆ๋กœ์šด ๋ฌธ์ œ๊ฐ€ ์ƒ๊ฒผ์œผ๋ฉฐ, ์ตœ์ ํ™”๋ฅผ ๋Œ๋ฆฌ๊ธฐ์—๋Š” ํ™˜๊ฒฝ์ด ๋„ˆ๋ฌด ๋А๋ ธ๋‹ค.


๐ŸŒŸ ๋‹จ๊ณ„๋ณ„ ํŒŒ์ดํ”„๋ผ์ธ์œผ๋กœ ๋Œ์•„์˜จ ์ด์œ 

โœจ ๋‹จ๊ณ„๋ณ„ ํŒŒ์ดํ”„๋ผ์ธ์ด ํ•˜๋Š” ์ผ

๋‹จ๊ณ„๋ณ„ ํŒŒ์ดํ”„๋ผ์ธ์€ ๊ตฌ์กฐ๊ฐ€ ๋‹จ์ˆœํ•˜๋‹ค. ๊ธฐ์กด LangChain ์—์ด์ „ํŠธ๋ฅผ ๊ทธ๋Œ€๋กœ ์‹คํ–‰ํ•˜๊ณ , ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ์ธก์ •ํ•œ๋‹ค.

  1. ์—์ด์ „ํŠธ ์‹คํ–‰
    • AgentService.run_matching() ํ˜ธ์ถœ (์‹ค์ œ ์—์ด์ „ํŠธ)
    • ๊ฒฐ๊ณผ๋ฅผ outputs/step1_results.json์— ์ €์žฅ
  1. Evidence ์ˆ˜์ง‘
    • ์—์ด์ „ํŠธ๊ฐ€ ์ถ”์ฒœํ•œ ์ธํ”Œ๋ฃจ์–ธ์„œ ์ด๋ฆ„์„ ์‘๋‹ต ํ…์ŠคํŠธ์—์„œ ํŒŒ์‹ฑ
    • DB์™€ CSV์—์„œ ์‹ค์ œ ๋ฐ์ดํ„ฐ ์กฐํšŒ
    • ๊ฒฐ๊ณผ๋ฅผ outputs/step2_evidence.json์— ์ €์žฅ
  1. ๋ฉ”ํŠธ๋ฆญ ๊ณ„์‚ฐ
    • 4๊ฐœ ๋ฉ”ํŠธ๋ฆญ ๊ณ„์‚ฐ (Evidence Coverage, Semantic Relevance, Groundedness, Competitor Check)
    • ๊ฒฐ๊ณผ๋ฅผ outputs/step3_metrics.json์— ์ €์žฅ
  1. ๋ฆฌํฌํŠธ ์ƒ์„ฑ
    • ์ „์ฒด ๊ฒฐ๊ณผ๋ฅผ ์ฝ๊ธฐ ์ข‹์€ ํ…์ŠคํŠธ ๋ฆฌํฌํŠธ๋กœ ์ถœ๋ ฅ
    • ๊ฒฐ๊ณผ๋ฅผ evaluation/reports/ ํด๋”์— ์ €์žฅ

DSPy Module์ด ์—์ด์ „ํŠธ๋ฅผ ๊ต์ฒดํ–ˆ๋˜ ๊ฒƒ๊ณผ ๋‹ฌ๋ฆฌ, ์—ฌ๊ธฐ์„œ๋Š” ์—์ด์ „ํŠธ๊ฐ€ ๋ฐ”๋€Œ์ง€ ์•Š๋Š”๋‹ค. Step 1์—์„œ ์‹ค์ œ๋กœ AgentService๊ฐ€ ์‹คํ–‰๋˜๊ณ , Step 2~4๋Š” ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋ถ„์„ํ•  ๋ฟ์ด๋‹ค. ํ‰๊ฐ€ ํŒŒ์ดํ”„๋ผ์ธ์ด ์—์ด์ „ํŠธ์˜ ๋‚ด๋ถ€ ๊ตฌ์กฐ์— ์ „ํ˜€ ๊ฐœ์ž…ํ•˜์ง€ ์•Š๋Š”๋‹ค.

โœจ JSON์œผ๋กœ ๋‹จ๊ณ„๋ฅผ ์ด์–ด๋ถ™์ธ ์„ค๊ณ„์˜ ๊ฐ€์น˜

๊ฐ ๋‹จ๊ณ„๊ฐ€ JSON ํŒŒ์ผ๋กœ ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•˜๊ณ  ๋‹ค์Œ ๋‹จ๊ณ„๊ฐ€ ๊ทธ๊ฒƒ์„ ์ฝ๋Š” ๊ตฌ์กฐ๊ฐ€ ์ฒ˜์Œ์—๋Š” ๋‹จ์ˆœํ•œ ํŽธ์˜ ์„ค๊ณ„์ฒ˜๋Ÿผ ๋ณด์ผ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์‹ค์ œ๋กœ ์จ๋ณด๋ฉด ์ด๊ฒŒ ๊ฝค ์ค‘์š”ํ•˜๋‹ค.

LLM ํ˜ธ์ถœ์ด ํฌํ•จ๋œ Step 1์€ ๋А๋ฆฌ๊ณ  ๋น„์šฉ์ด ๋“ ๋‹ค. 10๊ฐœ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ์ „๋ถ€ ๋Œ๋ฆฌ๋ฉด ๋ช‡ ๋ถ„์ด ๊ฑธ๋ฆฐ๋‹ค. ๋ฐ˜๋ฉด Step 2~4๋Š” ์ €์žฅ๋œ JSON์„ ์ฝ์–ด์„œ ์ฒ˜๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ฑฐ์˜ ์ฆ‰์‹œ ๋๋‚œ๋‹ค.

๋ฉ”ํŠธ๋ฆญ ๊ณ„์‚ฐ ๋กœ์ง์„ ์กฐ๊ธˆ ๋ฐ”๊พธ๊ณ  ์‹ถ์„ ๋•Œ Step 1์„ ๋‹ค์‹œ ๋Œ๋ฆด ํ•„์š” ์—†์ด, Step 3๋งŒ ๋‹ค์‹œ ์‹คํ–‰ํ•˜๋ฉด ๋œ๋‹ค. ๋ฆฌํฌํŠธ ํ˜•์‹์„ ๋ฐ”๊พธ๊ณ  ์‹ถ์œผ๋ฉด Step 4๋งŒ ๋‹ค์‹œ ์‹คํ–‰ํ•˜๋ฉด ๋œ๋‹ค. MIPROv2๊ฐ€ ๋ชจ๋“  ๊ณผ์ •์„ ํ•œ ๋ฒˆ์— ์ฒ˜๋ฆฌํ•˜๋ฉด์„œ ์ค‘๊ฐ„ ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•˜๊ธฐ ์–ด๋ ค์› ๋˜ ๊ฒƒ๊ณผ ๋Œ€์กฐ์ ์ด๋‹ค.

โœจ ๋‘ ๋ฐฉ์‹์ด ๊ฐ๊ฐ ์ž˜ ๋งž๋Š” ๋ฌธ์ œ๊ฐ€ ๋‹ฌ๋ž๋‹ค

DSPy ๋ฐฉ์‹๊ณผ ๋‹จ๊ณ„๋ณ„ ํŒŒ์ดํ”„๋ผ์ธ ๋ฐฉ์‹์€ ์• ์ดˆ์— ํ•ด๊ฒฐํ•˜๋ ค๋Š” ๋ฌธ์ œ์˜ ์„ฑ๊ฒฉ์ด ๋‹ฌ๋ž๋‹ค.

DSPy์™€ MIPROv2๊ฐ€ ์ง„์งœ ํž˜์„ ๋ฐœํœ˜ํ•˜๋Š” ์ƒํ™ฉ์€ ๋ช…ํ™•ํ•˜๊ฒŒ ์ •์˜๋œ LLM ํŒŒ์ดํ”„๋ผ์ธ์ด ์žˆ๊ณ , ์ง€๊ธˆ ๊ทธ ํŒŒ์ดํ”„๋ผ์ธ์˜ ํ”„๋กฌํ”„ํŠธ๋ฅผ ๋” ์ข‹๊ฒŒ ๋งŒ๋“ค๊ณ  ์‹ถ์„ ๋•Œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด "๋ถ„๋ฅ˜ ์ •ํ™•๋„๋ฅผ ๋†’์ด๊ณ  ์‹ถ๋‹ค", "์š”์•ฝ ํ’ˆ์งˆ์„ ๋†’์ด๊ณ  ์‹ถ๋‹ค"์ฒ˜๋Ÿผ LLM ํ˜ธ์ถœ ์ž์ฒด๋ฅผ ์ตœ์ ํ™”ํ•˜๋Š” ๊ฒŒ ๋ชฉํ‘œ์ผ ๋•Œ ๊ฐ•๋ ฅํ•˜๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ์‹ค์ œ๋กœ ํ•„์š”ํ–ˆ๋˜ ๊ฒƒ์€ ๋‹ฌ๋ž๋‹ค. ์—์ด์ „ํŠธ๊ฐ€ ์ง€๊ธˆ ์ž˜ ์ž‘๋™ํ•˜๊ณ  ์žˆ๋Š”์ง€ ์ธก์ •ํ•˜๋Š” ๊ฒƒ, ์ฆ‰ ํ‰๊ฐ€๊ฐ€ ๋จผ์ €์˜€๋‹ค. ๋ฌด์—‡์ด ๋ฌธ์ œ์ธ์ง€๋„ ๋ชจ๋ฅด๋Š” ์ƒํƒœ์—์„œ ์ตœ์ ํ™”๋ถ€ํ„ฐ ํ•˜๋ ค ํ–ˆ๋˜ ๊ฒƒ์ด๋‹ค.

DSPy + MIPROv2๋‹จ๊ณ„๋ณ„ ํŒŒ์ดํ”„๋ผ์ธ
๋ชฉ์ LLM ํŒŒ์ดํ”„๋ผ์ธ ํ”„๋กฌํ”„ํŠธ ์ž๋™ ์ตœ์ ํ™”๊ธฐ์กด ์—์ด์ „ํŠธ ํ’ˆ์งˆ ์ธก์ •
๋Œ€์ƒDSPy๋กœ ์ƒˆ๋กœ ์„ค๊ณ„ํ•œ ๋ณ„๋„ ์‹œ์Šคํ…œ์‹ค์ œ ๋ฐฐํฌ ์ค‘์ธ ์—์ด์ „ํŠธ
์‹คํ–‰ ํ™˜๊ฒฝ๋กœ์ปฌ Ollama์—์„œ ์ตœ์ ํ™” ์‹คํ–‰์ด ๋น„ํ˜„์‹ค์ ๋กœ์ปฌ Ollama์—์„œ ์ถฉ๋ถ„ํžˆ ๋™์ž‘
๊ฒฐ๊ณผ ํ•ด์„์ตœ์ ํ™” ์™„๋ฃŒ๊นŒ์ง€ ๊ฒฐ๊ณผ ํ™•์ธ ์–ด๋ ค์›€๋‹จ๊ณ„๋ณ„ JSON์œผ๋กœ ์ค‘๊ฐ„ ํ™•์ธ ๊ฐ€๋Šฅ
์—์ด์ „ํŠธ ์ฝ”๋“œ ๋ณ€๊ฒฝ์—์ด์ „ํŠธ ์ž์ฒด๊ฐ€ ๊ต์ฒด๋จ์—†์Œ

DSPy๋กœ๋Š” ๊ธฐ์กด LangChain ์—์ด์ „ํŠธ๋ฅผ ์ตœ์ ํ™”ํ•  ๋ฐฉ๋ฒ•์ด ์—†๋‹ค.
MIPROv2๊ฐ€ ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ตœ์ ํ™”ํ•˜๋ ค๋ฉด "์–ด๋–ค ํ”„๋กฌํ”„ํŠธ๋ฅผ ๋ฐ”๊ฟ”์•ผ ํ•˜๋Š”์ง€" ์•Œ์•„์•ผ ํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋Ÿฌ๋ฉด ์‹œ์Šคํ…œ ์•ˆ์— DSPy์˜ Signature๊ณผ Predictor๊ฐ€ ์žˆ์–ด์•ผ ํ•œ๋‹ค. MIPROv2๋Š” ๊ทธ๊ฒƒ๋“ค์„ ์ฐพ์•„์„œ ํŠœ๋‹ํ•œ๋‹ค.

LangChain ReAct ์—์ด์ „ํŠธ๋Š” DSPy์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์ง„ ๋ธ”๋ž™๋ฐ•์Šค์ด๋‹ค. MIPROv2 ์ž…์žฅ์—์„œ๋Š” ๋‚ด๋ถ€๋ฅผ ๋“ค์—ฌ๋‹ค๋ณผ ์ˆ˜๊ฐ€ ์—†๋‹ค.

์ฆ‰, DSPy + MIPROv2๋Š” ์ฒ˜์Œ๋ถ€ํ„ฐ DSPy๋กœ ์„ค๊ณ„๋œ ์‹œ์Šคํ…œ์„ ์ตœ์ ํ™”ํ•˜๋Š” ๋„๊ตฌ์ด๋‹ค. ๊ธฐ์กด์— ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ ๋งŒ๋“ค์–ด์ง„ ์—์ด์ „ํŠธ๋ฅผ ํ‰๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๊ฐœ์„ ํ•˜๋Š” ๋„๊ตฌ๊ฐ€ ์•„๋‹ˆ๋‹ค.
์šฐ๋ฆฌ ํ”„๋กœ์ ํŠธ์ฒ˜๋Ÿผ ์ด๋ฏธ LangChain์œผ๋กœ ๋งŒ๋“ค์–ด์ง„ ์—์ด์ „ํŠธ๊ฐ€ ์žˆ๋Š” ์ƒํ™ฉ์—์„œ๋Š” ์• ์ดˆ์— DSPy๊ฐ€ ๋งž๋Š” ๋„๊ตฌ๊ฐ€ ์•„๋‹ˆ์—ˆ๋˜ ๊ฑฐ๊ณ , ๊ทธ ๋ถˆ์ผ์น˜๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๋‹ค ์—์ด์ „ํŠธ๋ฅผ ๊ต์ฒดํ•˜๋Š” ๊ฒฐ๊ณผ๋กœ ์ด์–ด์ง„ ๊ฒƒ์ด๋‹ค.


๐ŸŒŸ DSPy๋Š” ์–ธ์ œ ์“ฐ๋ฉด ์ข‹์€๊ฐ€?

๐Ÿ˜€ DSPy๊ฐ€ ์ž˜ ๋งž๋Š” ์ƒํ™ฉ

  • ์ฒ˜์Œ๋ถ€ํ„ฐ DSPy๋กœ ์„ค๊ณ„ํ•  ๋•Œ
    ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์กฐ๊ฑด์ด๋‹ค. ์•ž์„œ ์‚ดํŽด๋ดค๋“ฏ์ด MIPROv2๋Š” ์‹œ์Šคํ…œ ์•ˆ์— DSPy Signature์™€ Predictor๊ฐ€ ์žˆ์–ด์•ผ ์ตœ์ ํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ธฐ์กด์— ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ ๋งŒ๋“ค์–ด์ง„ ์‹œ์Šคํ…œ์„ ๋‚˜์ค‘์— DSPy๋กœ ๊ฐœ์„ ํ•˜๋ ค ํ•˜๋ฉด ๊ฒฐ๊ตญ ๋‹ค์‹œ ๋งŒ๋“œ๋Š” ์ˆ˜๋ฐ–์— ์—†๋‹ค.
    ์ƒˆ ํ”„๋กœ์ ํŠธ๋ฅผ ์‹œ์ž‘ํ•˜๊ฑฐ๋‚˜, LLM ํŒŒ์ดํ”„๋ผ์ธ์„ ์ฒ˜์Œ ์„ค๊ณ„ํ•˜๋Š” ์‹œ์ ์ด๋ผ๋ฉด DSPy๊ฐ€ ํ›จ์”ฌ ์ž์—ฐ์Šค๋Ÿฝ๋‹ค.
  • ํŒŒ์ดํ”„๋ผ์ธ์˜ ํ๋ฆ„์ด ๊ณ ์ •๋˜์–ด ์žˆ์„ ๋•Œ
    DSPy Module์˜ forward()๋Š” ์‹คํ–‰ ํ๋ฆ„์„ ์ฝ”๋“œ๋กœ ๊ณ ์ •ํ•œ๋‹ค. ์ด ๊ตฌ์กฐ๋Š” "ํ•ญ์ƒ ๊ฐ™์€ ๋‹จ๊ณ„๋ฅผ ๊ฐ™์€ ์ˆœ์„œ๋กœ ์‹คํ–‰ํ•˜๋Š”" ํŒŒ์ดํ”„๋ผ์ธ์— ์ ํ•ฉํ•˜๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, "๋ฌธ์„œ ์š”์•ฝ โ†’ ํ•ต์‹ฌ ํ‚ค์›Œ๋“œ ์ถ”์ถœ โ†’ ์นดํ…Œ๊ณ ๋ฆฌ ๋ถ„๋ฅ˜"์ฒ˜๋Ÿผ ์ˆœ์„œ๊ฐ€ ๋ช…ํ™•ํ•˜๊ฒŒ ์ •ํ•ด์ง„ ํŒŒ์ดํ”„๋ผ์ธ์ด ์ข‹์€ ์˜ˆ๋‹ค.
    ๋ฐ˜๋ฉด ReAct ์—์ด์ „ํŠธ์ฒ˜๋Ÿผ LLM์ด ์ƒํ™ฉ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ๊ฒฝ๋กœ๋ฅผ ํƒํ•˜๋Š” ๋™์ ์ธ ๊ตฌ์กฐ๋Š” forward()๋กœ ํ‘œํ˜„ํ•˜๊ธฐ ์–ด๋ ต๊ณ , ์–ต์ง€๋กœ ๋งž์ถ”๋ฉด ์—์ด์ „ํŠธ์˜ ์œ ์—ฐํ•จ์„ ์žƒ๋Š”๋‹ค.
  • "์ข‹์€ ๊ฒฐ๊ณผ"๋ฅผ ์ฝ”๋“œ๋กœ ์ •์˜ํ•  ์ˆ˜ ์žˆ์„ ๋•Œ
    MIPROv2๋ฅผ ์“ฐ๋ ค๋ฉด metric ํ•จ์ˆ˜๊ฐ€ ์žˆ์–ด์•ผ ํ•œ๋‹ค. "์ด ์ถœ๋ ฅ์ด ์–ผ๋งˆ๋‚˜ ์ข‹์€๊ฐ€"๋ฅผ 0.0~1.0์œผ๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ฝ”๋“œ์ด๋‹ค. ์ด๊ฒŒ ์ •์˜๋˜์ง€ ์•Š์œผ๋ฉด Optimizer๊ฐ€ ๋ฌด์—‡์„ ํ–ฅํ•ด ์ตœ์ ํ™”ํ•ด์•ผ ํ• ์ง€ ๋ชจ๋ฅธ๋‹ค.
    ์šฐ๋ฆฌ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” 4๊ฐœ ๋ฉ”ํŠธ๋ฆญ์„ ์ด๋ฏธ ๊ฐ€์ง€๊ณ  ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด ์กฐ๊ฑด์€ ์ถฉ์กฑ๋๋‹ค. ํ’ˆ์งˆ ๊ธฐ์ค€์ด ๋ชจํ˜ธํ•˜๊ฑฐ๋‚˜ ์‚ฌ๋žŒ์˜ ์ฃผ๊ด€์  ํŒ๋‹จ์— ์˜์กดํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๋ผ๋ฉด metric ์„ค๊ณ„ ์ž์ฒด๊ฐ€ ๋จผ์ € ํ•ด๊ฒฐํ•ด์•ผ ํ•  ๊ณผ์ œ๊ฐ€ ๋œ๋‹ค.
  • ๋น ๋ฅธ ์ถ”๋ก  ํ™˜๊ฒฝ์ด ๊ฐ–์ถฐ์ ธ ์žˆ์„ ๋•Œ
    MIPROv2๋Š” (trainset) ร— (ํ›„๋ณด ํ”„๋กฌํ”„ํŠธ ์ˆ˜) ร— (์ตœ์ ํ™” ๋ผ์šด๋“œ)๋งŒํผ LLM์„ ํ˜ธ์ถœํ•œ๋‹ค. OpenAI๋‚˜ Anthropic API์ฒ˜๋Ÿผ ๋น ๋ฅธ ํ™˜๊ฒฝ์—์„œ๋Š” ๋ณ‘๋ ฌ ํ˜ธ์ถœ๋กœ ์ˆ˜์‹ญ ๋ถ„ ์•ˆ์— ๋๋‚ผ ์ˆ˜ ์žˆ์ง€๋งŒ, ๋กœ์ปฌ Ollama์ฒ˜๋Ÿผ ์ˆœ์ฐจ ์ฒ˜๋ฆฌ๋งŒ ๊ฐ€๋Šฅํ•œ ํ™˜๊ฒฝ์—์„œ๋Š” ๋ช‡ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆด ์ˆ˜ ์žˆ๋‹ค. ์ตœ์ ํ™”๋ฅผ ์‹ค์šฉ์ ์œผ๋กœ ์“ฐ๋ ค๋ฉด ์ถ”๋ก  ์†๋„๊ฐ€ ๋ฐ›์ณ์ค˜์•ผ ํ•œ๋‹ค.

๐Ÿฅฒ DSPy๊ฐ€ ๋งž์ง€ ์•Š๋Š” ์ƒํ™ฉ

  • ์ด๋ฏธ ๋งŒ๋“ค์–ด์ง„ ์‹œ์Šคํ…œ์„ ํ‰๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๊ฐœ์„ ํ•˜๊ณ  ์‹ถ์„ ๋•Œ
    ์šฐ๋ฆฌ๊ฐ€ ๊ฒช์€ ๋ฌธ์ œ ๊ทธ๋Œ€๋กœ๋‹ค. DSPy๋Š” ๊ธฐ์กด ์‹œ์Šคํ…œ์„ ํ‰๊ฐ€ํ•˜๋Š” ๋„๊ตฌ๊ฐ€ ์•„๋‹ˆ๋‹ค. ๊ธฐ์กด ์‹œ์Šคํ…œ์„ ๊ฐœ์„ ํ•˜๋ ค๋ฉด DSPy๋กœ ๋‹ค์‹œ ๋งŒ๋“ค์–ด์•ผ ํ•˜๋Š”๋ฐ, ๊ทธ ์ˆœ๊ฐ„ ์›๋ณธ ์‹œ์Šคํ…œ๊ณผ ๋ณ„๊ฐœ์˜ ๊ฒƒ์ด ๋œ๋‹ค.
    ์ด๋ฏธ ๋™์ž‘ํ•˜๋Š” ์—์ด์ „ํŠธ๊ฐ€ ์žˆ๊ณ  ๊ทธ๊ฒƒ์„ ์ธก์ •ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, ๋‹จ๊ณ„๋ณ„ ํ‰๊ฐ€ ํŒŒ์ดํ”„๋ผ์ธ์ฒ˜๋Ÿผ ์—์ด์ „ํŠธ๋ฅผ ๊ทธ๋Œ€๋กœ ์‹คํ–‰ํ•˜๋Š” ๋ฐฉ์‹์ด ๋” ์ ํ•ฉํ•˜๋‹ค.
  • ์ตœ์ ํ™”๋ณด๋‹ค ํ‰๊ฐ€๊ฐ€ ๋จผ์ € ํ•„์š”ํ•  ๋•Œ
    ์—์ด์ „ํŠธ๊ฐ€ ์ง€๊ธˆ ์ž˜ ์ž‘๋™ํ•˜๋Š”์ง€๋„ ๋ชจ๋ฅด๋Š” ์ƒํƒœ์—์„œ ์ตœ์ ํ™”๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๋Š” ๊ฑด ์ˆœ์„œ๊ฐ€ ๋งž์ง€ ์•Š๋Š”๋‹ค. "์ง€๊ธˆ ์–ด๋””์„œ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๋Š”๊ฐ€"๋ฅผ ๋จผ์ € ํŒŒ์•…ํ•ด์•ผ "๋ฌด์—‡์„ ์ตœ์ ํ™”ํ•ด์•ผ ํ•˜๋Š”๊ฐ€"๋ฅผ ์•Œ ์ˆ˜ ์žˆ๋‹ค. ํ‰๊ฐ€ ์—†์ด ์ตœ์ ํ™”๋ถ€ํ„ฐ ์‹œ๋„ํ•˜๋ฉด ์—‰๋šฑํ•œ ๊ฒƒ์„ ๊ฐœ์„ ํ•˜๋Š” ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

โœจ ์ •๋ฆฌ

์ ํ•ฉ๋ถ€์ ํ•ฉ
์‹œ์Šคํ…œ ์„ค๊ณ„ ์‹œ์ ์ฒ˜์Œ๋ถ€ํ„ฐ DSPy๋กœ ์„ค๊ณ„๊ธฐ์กด ์‹œ์Šคํ…œ์„ ๋‚˜์ค‘์— DSPy๋กœ ์ „ํ™˜
์—์ด์ „ํŠธ ์œ ํ˜•ํ๋ฆ„์ด ๊ณ ์ •๋œ ํŒŒ์ดํ”„๋ผ์ธ๋™์ ์œผ๋กœ ๊ฒฝ๋กœ๊ฐ€ ๋ฐ”๋€Œ๋Š” ReAct ์—์ด์ „ํŠธ
ํ’ˆ์งˆ ๊ธฐ์ค€metric์„ ์ฝ”๋“œ๋กœ ์ •์˜ ๊ฐ€๋Šฅ์ฃผ๊ด€์  ํŒ๋‹จ์— ์˜์กด
์ถ”๋ก  ํ™˜๊ฒฝAPI ๊ธฐ๋ฐ˜ (๋ณ‘๋ ฌ ํ˜ธ์ถœ ๊ฐ€๋Šฅ)๋กœ์ปฌ ๋ชจ๋ธ (์ˆœ์ฐจ ์ฒ˜๋ฆฌ๋งŒ ๊ฐ€๋Šฅ)
ํ˜„์žฌ ์ƒํƒœํ‰๊ฐ€๋Š” ๋งˆ์ณค๊ณ  ํ”„๋กฌํ”„ํŠธ๋ฅผ ์ž๋™์œผ๋กœ ์ตœ์ ํ™”ํ•˜๊ณ  ์‹ถ์„ ๋•Œํ‰๊ฐ€ ์ž์ฒด๊ฐ€ ์•„์ง ์•ˆ ๋์„ ๋•Œ

0๊ฐœ์˜ ๋Œ“๊ธ€