์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐Ÿค– AI ์—์ด์ „ํŠธ์˜ ๋„๊ตฌ์‚ฌ์šฉ, ์™„์ „์ •๋ณต!

๐Ÿค– AI ์—์ด์ „ํŠธ์˜ ๋„๊ตฌ์‚ฌ์šฉ, ์™„์ „์ •๋ณต!

์นœ๊ตฌ์ฒ˜๋Ÿผ ์‰ฝ๊ฒŒ ์•Œ๋ ค์ฃผ๋Š” Agent Tool Use์˜ ๋ชจ๋“  ๊ฒƒ ๐Ÿ› ๏ธโœจ

์•ˆ๋…•! ๐Ÿ˜Š ์š”์ฆ˜ AI ์—์ด์ „ํŠธ๊ฐ€ ์ •๋ง ํ•ซํ•˜์ง€? ChatGPT๊ฐ€ ๊ณ„์‚ฐ๊ธฐ๋ฅผ ์“ฐ๊ณ , ๋‚ ์”จ๋ฅผ ๊ฒ€์ƒ‰ํ•˜๊ณ , ์‹ฌ์ง€์–ด ์ฝ”๋“œ๊นŒ์ง€ ์‹คํ–‰ํ•˜๋Š” ๊ฑธ ๋ณด๋ฉด "์™€, ์–ด๋–ป๊ฒŒ ์ €๋Ÿฐ ๊ฒŒ ๊ฐ€๋Šฅํ•˜์ง€?"๋ผ๋Š” ์ƒ๊ฐ์ด ๋“ค ๊ฑฐ์•ผ. ๋ฐ”๋กœ ๊ทธ ๋น„๋ฐ€์ด ๋„๊ตฌ์‚ฌ์šฉ(Tool Use)์ด๋ผ๋Š” ๊ฐœ๋…์— ์ˆจ์–ด์žˆ์–ด! ๐ŸŽฏ

์˜ค๋Š˜์€ AI ์—์ด์ „ํŠธ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”์ง€, ๊ทธ ์›๋ฆฌ๋ถ€ํ„ฐ ์‹ค์ œ ๊ตฌํ˜„ ๋ฐฉ๋ฒ•๊นŒ์ง€ ์นœ๊ตฌํ•œํ…Œ ์„ค๋ช…ํ•˜๋“ฏ์ด ์žฌ๋ฏธ์žˆ๊ฒŒ ํ’€์–ด๋ณผ๊ฒŒ. ํ”„๋กœ๊ทธ๋ž˜๋ฐ์— ๊ด€์‹ฌ ์žˆ๋Š” ์‚ฌ๋žŒ์ด๋ผ๋ฉด ๊ผญ ์•Œ์•„์•ผ ํ•  ๋‚ด์šฉ์ด๋‹ˆ๊นŒ ์ง‘์ค‘! ๐Ÿš€

AI Calculator ๐Ÿ”ข Search ๐Ÿ” Database ๐Ÿ’พ API Call ๐ŸŒ AI Agent Tool Use Architecture

๐ŸŽฏ ๋„๊ตฌ์‚ฌ์šฉ(Tool Use)์ด ๋ญ๊ธธ๋ž˜?

๋จผ์ € ๊ธฐ๋ณธ ๊ฐœ๋…๋ถ€ํ„ฐ ์žก๊ณ  ๊ฐ€์ž! AI ์—์ด์ „ํŠธ์˜ ๋„๊ตฌ์‚ฌ์šฉ(Tool Use)์€ ์‰ฝ๊ฒŒ ๋งํ•ด์„œ AI๊ฐ€ ์™ธ๋ถ€ ๊ธฐ๋Šฅ์ด๋‚˜ ํ”„๋กœ๊ทธ๋žจ์„ ํ˜ธ์ถœํ•ด์„œ ์ž์‹ ์˜ ๋Šฅ๋ ฅ์„ ํ™•์žฅํ•˜๋Š” ๊ฒƒ์ด์•ผ. ๐ŸŽช

์ƒ๊ฐํ•ด๋ด. ์ˆœ์ˆ˜ํ•œ ์–ธ์–ด ๋ชจ๋ธ(LLM)์€ ํ…์ŠคํŠธ ์ƒ์„ฑ์—๋Š” ์ฒœ์žฌ์ง€๋งŒ, ์‹ค์‹œ๊ฐ„ ์ •๋ณด๋ฅผ ๋ชจ๋ฅด๊ณ , ๊ณ„์‚ฐ๋„ ์ •ํ™•ํ•˜์ง€ ์•Š๊ณ , ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ ‘๊ทผํ•  ์ˆ˜๋„ ์—†์–ด. ๋งˆ์น˜ ์—„์ฒญ ๋˜‘๋˜‘ํ•œ๋ฐ ์†๋ฐœ์ด ์—†๋Š” ์ƒํƒœ๋ž„๊นŒ? ๐Ÿค”

๐Ÿ” ์˜ˆ์‹œ๋กœ ์ดํ•ดํ•˜๊ธฐ

์‚ฌ์šฉ์ž: "์˜ค๋Š˜ ์„œ์šธ ๋‚ ์”จ ์–ด๋•Œ?"
๋„๊ตฌ ์—†๋Š” AI: "์ฃ„์†กํ•˜์ง€๋งŒ ์‹ค์‹œ๊ฐ„ ์ •๋ณด๋Š” ์•Œ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค..." ๐Ÿ˜ข
๋„๊ตฌ ์žˆ๋Š” AI: [๋‚ ์”จ API ํ˜ธ์ถœ] โ†’ "์˜ค๋Š˜ ์„œ์šธ์€ ๋ง‘๊ณ  ๊ธฐ์˜จ์€ 18๋„์ž…๋‹ˆ๋‹ค!" โ˜€๏ธ

๋ฐ”๋กœ ์ด๊ฒŒ ๋„๊ตฌ์‚ฌ์šฉ์˜ ํ•ต์‹ฌ์ด์•ผ. AI๊ฐ€ ํ•„์š”ํ•  ๋•Œ ์ ์ ˆํ•œ ๋„๊ตฌ๋ฅผ ์„ ํƒํ•˜๊ณ , ๊ทธ ๋„๊ตฌ๋ฅผ ์‹คํ–‰ํ•ด์„œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์•„์˜ค๋Š” ๊ฑฐ์ง€. ๋งˆ์น˜ ์šฐ๋ฆฌ๊ฐ€ ๊ณ„์‚ฐํ•  ๋•Œ ๊ณ„์‚ฐ๊ธฐ๋ฅผ ๊บผ๋‚ด ์“ฐ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์•ผ! ๐Ÿ“ฑ

๐Ÿงฉ ๋„๊ตฌ์‚ฌ์šฉ์˜ ํ•ต์‹ฌ ๊ตฌ์„ฑ์š”์†Œ

AI ์—์ด์ „ํŠธ์˜ ๋„๊ตฌ์‚ฌ์šฉ ์‹œ์Šคํ…œ์€ ํฌ๊ฒŒ 4๊ฐ€์ง€ ์š”์†Œ๋กœ ๊ตฌ์„ฑ๋ผ:

1๏ธโƒฃ ๋„๊ตฌ ์ •์˜(Tool Definition)

AI์—๊ฒŒ "์ด๋Ÿฐ ๋„๊ตฌ๊ฐ€ ์žˆ์–ด!"๋ผ๊ณ  ์•Œ๋ ค์ฃผ๋Š” ๋‹จ๊ณ„์•ผ. ๊ฐ ๋„๊ตฌ์˜ ์ด๋ฆ„, ์„ค๋ช…, ํ•„์š”ํ•œ ์ž…๋ ฅ๊ฐ’(ํŒŒ๋ผ๋ฏธํ„ฐ)์„ ๋ช…ํ™•ํ•˜๊ฒŒ ์ •์˜ํ•ด์ค˜์•ผ ํ•ด.

{
  "name": "get_weather",
  "description": "ํŠน์ • ๋„์‹œ์˜ ํ˜„์žฌ ๋‚ ์”จ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค",
  "parameters": {
    "city": {
      "type": "string",
      "description": "๋‚ ์”จ๋ฅผ ํ™•์ธํ•  ๋„์‹œ ์ด๋ฆ„"
    }
  }
}

2๏ธโƒฃ ๋„๊ตฌ ์„ ํƒ(Tool Selection)

AI๊ฐ€ ์‚ฌ์šฉ์ž์˜ ์š”์ฒญ์„ ๋ถ„์„ํ•ด์„œ "์•„, ์ด ์ƒํ™ฉ์—๋Š” ์ด ๋„๊ตฌ๋ฅผ ์จ์•ผ๊ฒ ๋‹ค!"๋ผ๊ณ  ํŒ๋‹จํ•˜๋Š” ๋‹จ๊ณ„. ์ด๊ฒŒ ์ง„์งœ ์ค‘์š”ํ•œ๋ฐ, AI์˜ ์ถ”๋ก  ๋Šฅ๋ ฅ์ด ์—ฌ๊ธฐ์„œ ๋น›์„ ๋ฐœํ•ด! ๐ŸŒŸ

3๏ธโƒฃ ๋„๊ตฌ ์‹คํ–‰(Tool Execution)

์„ ํƒํ•œ ๋„๊ตฌ๋ฅผ ์‹ค์ œ๋กœ ์‹คํ–‰ํ•˜๋Š” ๋‹จ๊ณ„. API๋ฅผ ํ˜ธ์ถœํ•˜๊ฑฐ๋‚˜, ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๊ฑฐ๋‚˜, ์™ธ๋ถ€ ์‹œ์Šคํ…œ๊ณผ ํ†ต์‹ ํ•˜๋Š” ๊ณผ์ •์ด์ง€.

4๏ธโƒฃ ๊ฒฐ๊ณผ ํ†ตํ•ฉ(Result Integration)

๋„๊ตฌ ์‹คํ–‰ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์•„์„œ AI๊ฐ€ ์ดํ•ดํ•˜๊ณ , ์‚ฌ์šฉ์ž์—๊ฒŒ ์ž์—ฐ์Šค๋Ÿฌ์šด ๋‹ต๋ณ€์œผ๋กœ ๋งŒ๋“ค์–ด์ฃผ๋Š” ๋‹จ๊ณ„์•ผ. ๋‹จ์ˆœํžˆ ๊ฒฐ๊ณผ๋ฅผ ๋ณต๋ถ™ํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ๋งฅ๋ฝ์— ๋งž๊ฒŒ ๊ฐ€๊ณตํ•˜๋Š” ๊ฑฐ์ง€! โœจ

๐Ÿ”ง ๋„๊ตฌ์‚ฌ์šฉ์˜ ์ž‘๋™ ์›๋ฆฌ

์ž, ์ด์ œ ์ข€ ๋” ๊นŠ์ด ๋“ค์–ด๊ฐ€๋ณผ๊นŒ? AI ์—์ด์ „ํŠธ๊ฐ€ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ „์ฒด ํ”„๋กœ์„ธ์Šค๋ฅผ ๋‹จ๊ณ„๋ณ„๋กœ ์‚ดํŽด๋ณด์ž! ๐ŸŽฌ

๐Ÿ“‹ Step-by-Step ํ”„๋กœ์„ธ์Šค

Step 1: ์‚ฌ์šฉ์ž ์š”์ฒญ ๋ถ„์„

์‚ฌ์šฉ์ž๊ฐ€ "2024๋…„ 3์›” 15์ผ๋ถ€ํ„ฐ 20์ผ๊นŒ์ง€ ๋ฉฐ์น ์ด์•ผ?"๋ผ๊ณ  ๋ฌผ์—ˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž. AI๋Š” ๋จผ์ € ์ด ์š”์ฒญ์„ ๋ถ„์„ํ•ด:

AI์˜ ๋‚ด๋ถ€ ์‚ฌ๊ณ  ๊ณผ์ •: - ๋‚ ์งœ ๊ณ„์‚ฐ์ด ํ•„์š”ํ•˜๋„ค? ๐Ÿค”
- ์ •ํ™•ํ•œ ๊ณ„์‚ฐ์ด ํ•„์š”ํ•˜๋‹ˆ๊นŒ ๊ณ„์‚ฐ ๋„๊ตฌ๋ฅผ ์จ์•ผ๊ฒ ์–ด!
- ์‹œ์ž‘์ผ: 2024-03-15, ์ข…๋ฃŒ์ผ: 2024-03-20
- calculate_date_difference ๋„๊ตฌ๋ฅผ ํ˜ธ์ถœํ•ด์•ผ๊ฒ ๋‹ค!

Step 2: ๋„๊ตฌ ํ˜ธ์ถœ ๊ฒฐ์ • (Function Calling)

์ตœ์‹  LLM๋“ค์€ Function Calling์ด๋ผ๋Š” ํŠน๋ณ„ํ•œ ๊ธฐ๋Šฅ์„ ์ง€์›ํ•ด. ์ด๊ฑด AI๊ฐ€ ๊ตฌ์กฐํ™”๋œ ํ˜•์‹์œผ๋กœ "์ด ํ•จ์ˆ˜๋ฅผ ์ด๋ ‡๊ฒŒ ํ˜ธ์ถœํ•ด์ค˜!"๋ผ๊ณ  ์š”์ฒญํ•˜๋Š” ๊ฑฐ์•ผ.

{
  "function_call": {
    "name": "calculate_date_difference",
    "arguments": {
      "start_date": "2024-03-15",
      "end_date": "2024-03-20"
    }
  }
}

์ด JSON ํ˜•์‹์˜ ์ถœ๋ ฅ์ด ํ•ต์‹ฌ์ด์•ผ! AI๊ฐ€ ์ž์—ฐ์–ด๊ฐ€ ์•„๋‹Œ ํ”„๋กœ๊ทธ๋žจ์ด ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋Š” ๊ตฌ์กฐํ™”๋œ ๋ฐ์ดํ„ฐ๋กœ ์˜๋„๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ๊ฑฐ์ง€. ๐ŸŽฏ

Step 3: ์‹ค์ œ ๋„๊ตฌ ์‹คํ–‰

์ด์ œ ์—์ด์ „ํŠธ ์‹œ์Šคํ…œ(์šฐ๋ฆฌ๊ฐ€ ๋งŒ๋“  ํ”„๋กœ๊ทธ๋žจ)์ด ์ด ์š”์ฒญ์„ ๋ฐ›์•„์„œ ์‹ค์ œ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•ด:

def calculate_date_difference(start_date, end_date):
    from datetime import datetime
    
    start = datetime.strptime(start_date, "%Y-%m-%d")
    end = datetime.strptime(end_date, "%Y-%m-%d")
    
    difference = (end - start).days
    return {
        "days": difference,
        "message": f"{start_date}๋ถ€ํ„ฐ {end_date}๊นŒ์ง€๋Š” {difference}์ผ์ž…๋‹ˆ๋‹ค."
    }

์‹คํ–‰ ๊ฒฐ๊ณผ: {"days": 5, "message": "2024-03-15๋ถ€ํ„ฐ 2024-03-20๊นŒ์ง€๋Š” 5์ผ์ž…๋‹ˆ๋‹ค."}

Step 4: ๊ฒฐ๊ณผ๋ฅผ AI์—๊ฒŒ ๋‹ค์‹œ ์ „๋‹ฌ

๋„๊ตฌ ์‹คํ–‰ ๊ฒฐ๊ณผ๋ฅผ AI์—๊ฒŒ ๋Œ๋ ค์ค˜. ๊ทธ๋Ÿฌ๋ฉด AI๋Š” ์ด ๊ฒฐ๊ณผ๋ฅผ ์ž์—ฐ์Šค๋Ÿฌ์šด ๋‹ต๋ณ€์œผ๋กœ ๋งŒ๋“ค์–ด:

AI์˜ ์ตœ์ข… ๋‹ต๋ณ€: "2024๋…„ 3์›” 15์ผ๋ถ€ํ„ฐ 20์ผ๊นŒ์ง€๋Š” ์ด 5์ผ์ด์—์š”! ๐Ÿ“…"

๐Ÿ”„ ๋ฐ˜๋ณต์  ๋„๊ตฌ ์‚ฌ์šฉ (Multi-Step Reasoning)

์ง„์งœ ๋ฉ‹์ง„ ๊ฑด AI๊ฐ€ ์—ฌ๋Ÿฌ ๋„๊ตฌ๋ฅผ ์—ฐ์†์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฑฐ์•ผ! ์ด๊ฑธ ์ฒด์ธ(Chain)์ด๋ผ๊ณ  ๋ถ€๋ฅด๊ธฐ๋„ ํ•ด. ๐Ÿ”—

๐ŸŽฏ ๋ณต์žกํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค ์˜ˆ์‹œ

์‚ฌ์šฉ์ž: "์„œ์šธ์˜ ํ˜„์žฌ ๋‚ ์”จ๋ฅผ ํ™•์ธํ•˜๊ณ , ๋น„๊ฐ€ ์˜จ๋‹ค๋ฉด ์šฐ์‚ฐ ์ถ”์ฒœ ์ƒํ’ˆ์„ ๊ฒ€์ƒ‰ํ•ด์ค˜"

AI์˜ ์‹คํ–‰ ํ๋ฆ„:
1๏ธโƒฃ get_weather("์„œ์šธ") ํ˜ธ์ถœ โ†’ ๊ฒฐ๊ณผ: "๋น„, 15๋„"
2๏ธโƒฃ ๊ฒฐ๊ณผ ๋ถ„์„: "๋น„๊ฐ€ ์˜ค๋„ค!"
3๏ธโƒฃ search_products("์šฐ์‚ฐ") ํ˜ธ์ถœ โ†’ ๊ฒฐ๊ณผ: ์ƒํ’ˆ ๋ฆฌ์ŠคํŠธ
4๏ธโƒฃ ์ตœ์ข… ๋‹ต๋ณ€ ์ƒ์„ฑ: "์„œ์šธ์€ ํ˜„์žฌ ๋น„๊ฐ€ ์˜ค๊ณ  ์žˆ์–ด์š”. ์ด๋Ÿฐ ์šฐ์‚ฐ ์ƒํ’ˆ๋“ค์€ ์–ด๋– ์„ธ์š”? โ˜”"

์ด๋ ‡๊ฒŒ AI๊ฐ€ ์ƒํ™ฉ์„ ํŒ๋‹จํ•˜๊ณ , ํ•„์š”ํ•œ ๋„๊ตฌ๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋ฉด์„œ ๋ณต์žกํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฑฐ์•ผ. ๋งˆ์น˜ ์‚ฌ๋žŒ์ด ๋ฌธ์ œ๋ฅผ ๋‹จ๊ณ„๋ณ„๋กœ ํ•ด๊ฒฐํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ! ๐Ÿง 

๐Ÿ› ๏ธ ์ฃผ์š” ๋„๊ตฌ ์‚ฌ์šฉ ํŒจํ„ด

์‹ค์ œ๋กœ AI ์—์ด์ „ํŠธ๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ๋„๊ตฌ๋“ค์€ ์–ด๋–ค ์ข…๋ฅ˜๊ฐ€ ์žˆ์„๊นŒ? ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„๋กœ ์ •๋ฆฌํ•ด๋ดค์–ด! ๐Ÿ“š

์นดํ…Œ๊ณ ๋ฆฌ ๋„๊ตฌ ์˜ˆ์‹œ ์‚ฌ์šฉ ๋ชฉ์ 
์ •๋ณด ๊ฒ€์ƒ‰ ๐Ÿ” ์›น ๊ฒ€์ƒ‰, ์œ„ํ‚คํ”ผ๋””์•„, ๋‰ด์Šค API ์‹ค์‹œ๊ฐ„ ์ •๋ณด, ์ตœ์‹  ๋ฐ์ดํ„ฐ ํ™•์ธ
๊ณ„์‚ฐ/๋ถ„์„ ๐Ÿ”ข ๊ณ„์‚ฐ๊ธฐ, ํ†ต๊ณ„ ๋ถ„์„, ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ์ •ํ™•ํ•œ ์ˆ˜์น˜ ๊ณ„์‚ฐ, ๋ณต์žกํ•œ ์—ฐ์‚ฐ
๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๐Ÿ’พ SQL ์ฟผ๋ฆฌ, NoSQL ์กฐํšŒ, ๋ฒกํ„ฐDB ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ ์กฐํšŒ/์ˆ˜์ •
์™ธ๋ถ€ API ๐ŸŒ ๋‚ ์”จ, ์ง€๋„, ๋ฒˆ์—ญ, ๊ฒฐ์ œ ์™ธ๋ถ€ ์„œ๋น„์Šค ์—ฐ๋™
์ฝ”๋“œ ์‹คํ–‰ ๐Ÿ’ป Python ์ธํ„ฐํ”„๋ฆฌํ„ฐ, ์ƒŒ๋“œ๋ฐ•์Šค ๋™์  ์ฝ”๋“œ ์‹คํ–‰, ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ
ํŒŒ์ผ ์ž‘์—… ๐Ÿ“ ํŒŒ์ผ ์ฝ๊ธฐ/์“ฐ๊ธฐ, ์ด๋ฏธ์ง€ ์ƒ์„ฑ ํŒŒ์ผ ์‹œ์Šคํ…œ ์กฐ์ž‘

๐ŸŽจ ์‹ค์ „ ๋„๊ตฌ ๊ตฌํ˜„ ์˜ˆ์‹œ

์ด๋ก ๋งŒ ๋ณด๋ฉด ์žฌ๋ฏธ์—†์œผ๋‹ˆ๊นŒ, ์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„ํ•˜๋Š”์ง€ ์ฝ”๋“œ๋กœ ๋ณผ๊นŒ? Python์œผ๋กœ ๊ฐ„๋‹จํ•œ ๋„๊ตฌ ์‹œ์Šคํ…œ์„ ๋งŒ๋“ค์–ด๋ณด์ž! ๐Ÿ

๊ธฐ๋ณธ ๋„๊ตฌ ํด๋ž˜์Šค ์ •์˜

from typing import Dict, Any, Callable
import json

class Tool:
    def __init__(self, name: str, description: str, 
                 function: Callable, parameters: Dict):
        self.name = name
        self.description = description
        self.function = function
        self.parameters = parameters
    
    def to_schema(self) -> Dict:
        """AI๊ฐ€ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋Š” ์Šคํ‚ค๋งˆ ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜"""
        return {
            "name": self.name,
            "description": self.description,
            "parameters": self.parameters
        }
    
    def execute(self, **kwargs) -> Any:
        """๋„๊ตฌ ์‹คํ–‰"""
        return self.function(**kwargs)

๊ตฌ์ฒด์ ์ธ ๋„๊ตฌ ๊ตฌํ˜„

# ๋‚ ์”จ ์กฐํšŒ ๋„๊ตฌ
def get_weather_impl(city: str) -> Dict:
    # ์‹ค์ œ๋กœ๋Š” API ํ˜ธ์ถœํ•˜๊ฒ ์ง€๋งŒ, ์—ฌ๊ธฐ์„œ๋Š” ์‹œ๋ฎฌ๋ ˆ์ด์…˜
    weather_data = {
        "์„œ์šธ": {"temp": 18, "condition": "๋ง‘์Œ"},
        "๋ถ€์‚ฐ": {"temp": 20, "condition": "ํ๋ฆผ"}
    }
    return weather_data.get(city, {"temp": 0, "condition": "์ •๋ณด์—†์Œ"})

weather_tool = Tool(
    name="get_weather",
    description="ํŠน์ • ๋„์‹œ์˜ ํ˜„์žฌ ๋‚ ์”จ๋ฅผ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค",
    function=get_weather_impl,
    parameters={
        "type": "object",
        "properties": {
            "city": {
                "type": "string",
                "description": "๋‚ ์”จ๋ฅผ ํ™•์ธํ•  ๋„์‹œ ์ด๋ฆ„"
            }
        },
        "required": ["city"]
    }
)

# ๊ณ„์‚ฐ๊ธฐ ๋„๊ตฌ
def calculator_impl(expression: str) -> float:
    # ์•ˆ์ „ํ•œ ๊ณ„์‚ฐ์„ ์œ„ํ•ด eval ๋Œ€์‹  ast ์‚ฌ์šฉ ๊ถŒ์žฅ
    try:
        return eval(expression)
    except:
        return "๊ณ„์‚ฐ ์˜ค๋ฅ˜"

calculator_tool = Tool(
    name="calculator",
    description="์ˆ˜ํ•™ ๊ณ„์‚ฐ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค",
    function=calculator_impl,
    parameters={
        "type": "object",
        "properties": {
            "expression": {
                "type": "string",
                "description": "๊ณ„์‚ฐํ•  ์ˆ˜์‹ (์˜ˆ: '2 + 2', '10 * 5')"
            }
        },
        "required": ["expression"]
    }
)

๋„๊ตฌ ๊ด€๋ฆฌ์ž (Tool Manager)

class ToolManager:
    def __init__(self):
        self.tools: Dict[str, Tool] = {}
    
    def register_tool(self, tool: Tool):
        """๋„๊ตฌ ๋“ฑ๋ก"""
        self.tools[tool.name] = tool
        print(f"โœ… ๋„๊ตฌ ๋“ฑ๋ก๋จ: {tool.name}")
    
    def get_tools_schema(self) -> list:
        """๋ชจ๋“  ๋„๊ตฌ์˜ ์Šคํ‚ค๋งˆ๋ฅผ AI์—๊ฒŒ ์ „๋‹ฌํ•  ํ˜•์‹์œผ๋กœ ๋ฐ˜ํ™˜"""
        return [tool.to_schema() for tool in self.tools.values()]
    
    def execute_tool(self, tool_name: str, arguments: Dict) -> Any:
        """๋„๊ตฌ ์‹คํ–‰"""
        if tool_name not in self.tools:
            return {"error": f"๋„๊ตฌ '{tool_name}'๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค"}
        
        tool = self.tools[tool_name]
        try:
            result = tool.execute(**arguments)
            return {"success": True, "result": result}
        except Exception as e:
            return {"success": False, "error": str(e)}

# ์‚ฌ์šฉ ์˜ˆ์‹œ
manager = ToolManager()
manager.register_tool(weather_tool)
manager.register_tool(calculator_tool)

# ๋„๊ตฌ ์‹คํ–‰
result = manager.execute_tool("get_weather", {"city": "์„œ์šธ"})
print(result)  # {'success': True, 'result': {'temp': 18, 'condition': '๋ง‘์Œ'}}

์ด๋ ‡๊ฒŒ ๋„๊ตฌ๋ฅผ ์ฒด๊ณ„์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๋ฉด, AI ์—์ด์ „ํŠธ๊ฐ€ ํ•„์š”ํ•  ๋•Œ ์‰ฝ๊ฒŒ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์–ด! ๐ŸŽ‰

๐Ÿค– ์ฃผ์š” ํ”„๋ ˆ์ž„์›Œํฌ์™€ ๊ตฌํ˜„ ๋ฐฉ๋ฒ•

์ง์ ‘ ๋‹ค ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ์ด๋ฏธ ์ž˜ ๋งŒ๋“ค์–ด์ง„ ํ”„๋ ˆ์ž„์›Œํฌ๋“ค์ด ๋งŽ์•„. ์‹ค๋ฌด์—์„œ ๋งŽ์ด ์“ฐ์ด๋Š” ๊ฒƒ๋“ค์„ ์†Œ๊ฐœํ• ๊ฒŒ! ๐ŸŒŸ

1๏ธโƒฃ LangChain - ๊ฐ€์žฅ ์ธ๊ธฐ ์žˆ๋Š” ํ”„๋ ˆ์ž„์›Œํฌ

LangChain์€ AI ์—์ด์ „ํŠธ ๊ฐœ๋ฐœ์˜ ํ‘œ์ค€์ฒ˜๋Ÿผ ์ž๋ฆฌ์žก์€ ํ”„๋ ˆ์ž„์›Œํฌ์•ผ. ๋„๊ตฌ ์‚ฌ์šฉ์„ ์ •๋ง ์‰ฝ๊ฒŒ ๋งŒ๋“ค์–ด์ค˜! ๐Ÿฆœ

from langchain.agents import initialize_agent, Tool
from langchain.agents import AgentType
from langchain.llms import OpenAI

# ๋„๊ตฌ ์ •์˜
tools = [
    Tool(
        name="Calculator",
        func=lambda x: eval(x),
        description="์ˆ˜ํ•™ ๊ณ„์‚ฐ์— ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ž…๋ ฅ์€ ์ˆ˜์‹์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค."
    ),
    Tool(
        name="Search",
        func=search_function,  # ์‹ค์ œ ๊ฒ€์ƒ‰ ํ•จ์ˆ˜
        description="์ตœ์‹  ์ •๋ณด๋ฅผ ๊ฒ€์ƒ‰ํ•  ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค."
    )
]

# ์—์ด์ „ํŠธ ์ดˆ๊ธฐํ™”
llm = OpenAI(temperature=0)
agent = initialize_agent(
    tools, 
    llm, 
    agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
    verbose=True
)

# ์‹คํ–‰
response = agent.run("2024๋…„ ์˜ฌ๋ฆผํ”ฝ์€ ์–ด๋””์„œ ์—ด๋ฆฌ๋‚˜์š”? ๊ทธ๋ฆฌ๊ณ  123 * 456์„ ๊ณ„์‚ฐํ•ด์ฃผ์„ธ์š”")
print(response)

๐ŸŽฏ LangChain์˜ ์žฅ์ :
โœ… ๋‹ค์–‘ํ•œ LLM ์ง€์› (OpenAI, Anthropic, Hugging Face ๋“ฑ)
โœ… ํ’๋ถ€ํ•œ ๋‚ด์žฅ ๋„๊ตฌ๋“ค
โœ… ์ฒด์ธ(Chain) ๊ตฌ์„ฑ์ด ์ง๊ด€์ 
โœ… ์ปค๋ฎค๋‹ˆํ‹ฐ๊ฐ€ ํ™œ๋ฐœํ•˜๊ณ  ๋ฌธ์„œ๊ฐ€ ์ž˜ ๋˜์–ด์žˆ์Œ

2๏ธโƒฃ OpenAI Function Calling

OpenAI๊ฐ€ ์ง์ ‘ ์ œ๊ณตํ•˜๋Š” Function Calling ๊ธฐ๋Šฅ์€ ์ •๋ง ๊ฐ•๋ ฅํ•ด! GPT-4, GPT-3.5-turbo ๋ชจ๋ธ์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜์ง€. ๐Ÿš€

import openai

# ํ•จ์ˆ˜ ์ •์˜
functions = [
    {
        "name": "get_current_weather",
        "description": "ํŠน์ • ์œ„์น˜์˜ ํ˜„์žฌ ๋‚ ์”จ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค",
        "parameters": {
            "type": "object",
            "properties": {
                "location": {
                    "type": "string",
                    "description": "๋„์‹œ ์ด๋ฆ„, ์˜ˆ: Seoul"
                },
                "unit": {
                    "type": "string",
                    "enum": ["celsius", "fahrenheit"]
                }
            },
            "required": ["location"]
        }
    }
]

# API ํ˜ธ์ถœ
response = openai.ChatCompletion.create(
    model="gpt-4",
    messages=[
        {"role": "user", "content": "์„œ์šธ ๋‚ ์”จ ์–ด๋•Œ?"}
    ],
    functions=functions,
    function_call="auto"
)

# ์‘๋‹ต ์ฒ˜๋ฆฌ
message = response["choices"][0]["message"]

if message.get("function_call"):
    function_name = message["function_call"]["name"]
    arguments = json.loads(message["function_call"]["arguments"])
    
    # ์‹ค์ œ ํ•จ์ˆ˜ ์‹คํ–‰
    if function_name == "get_current_weather":
        weather_result = get_current_weather(**arguments)
        
        # ๊ฒฐ๊ณผ๋ฅผ ๋‹ค์‹œ AI์—๊ฒŒ ์ „๋‹ฌ
        second_response = openai.ChatCompletion.create(
            model="gpt-4",
            messages=[
                {"role": "user", "content": "์„œ์šธ ๋‚ ์”จ ์–ด๋•Œ?"},
                message,
                {
                    "role": "function",
                    "name": function_name,
                    "content": json.dumps(weather_result)
                }
            ]
        )
        
        print(second_response["choices"][0]["message"]["content"])

๐Ÿ’ก ํ•ต์‹ฌ ํฌ์ธํŠธ:
- AI๊ฐ€ function_call ํ•„๋“œ๋กœ ์–ด๋–ค ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ• ์ง€ ๊ฒฐ์ •
- ์šฐ๋ฆฌ๊ฐ€ ์‹ค์ œ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๋‹ค์‹œ ์ „๋‹ฌ
- AI๊ฐ€ ๊ฒฐ๊ณผ๋ฅผ ์ž์—ฐ์–ด๋กœ ๋ณ€ํ™˜ํ•ด์„œ ๋‹ต๋ณ€

3๏ธโƒฃ Anthropic Claude Tool Use

Claude๋„ ์ตœ๊ทผ ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ ์‚ฌ์šฉ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ–ˆ์–ด! ํŠนํžˆ ์ •ํ™•๋„๊ฐ€ ๋†’๋‹ค๊ณ  ํ‰๊ฐ€๋ฐ›๊ณ  ์žˆ์ง€. ๐ŸŽฏ

import anthropic

client = anthropic.Anthropic(api_key="your-api-key")

tools = [
    {
        "name": "get_weather",
        "description": "๋‚ ์”จ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค",
        "input_schema": {
            "type": "object",
            "properties": {
                "location": {
                    "type": "string",
                    "description": "๋„์‹œ ์ด๋ฆ„"
                }
            },
            "required": ["location"]
        }
    }
]

message = client.messages.create(
    model="claude-3-opus-20240229",
    max_tokens=1024,
    tools=tools,
    messages=[
        {"role": "user", "content": "์„œ์šธ ๋‚ ์”จ ์•Œ๋ ค์ค˜"}
    ]
)

# Tool use ์ฒ˜๋ฆฌ
if message.stop_reason == "tool_use":
    tool_use = next(block for block in message.content if block.type == "tool_use")
    tool_name = tool_use.name
    tool_input = tool_use.input
    
    # ๋„๊ตฌ ์‹คํ–‰ ๋ฐ ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜...

4๏ธโƒฃ AutoGPT / BabyAGI ์Šคํƒ€์ผ

์ข€ ๋” ์ž์œจ์ ์ธ ์—์ด์ „ํŠธ๋ฅผ ์›ํ•œ๋‹ค๋ฉด AutoGPT ์Šคํƒ€์ผ๋„ ์žˆ์–ด. ์ด๊ฑด AI๊ฐ€ ์Šค์Šค๋กœ ๋ชฉํ‘œ๋ฅผ ์„ค์ •ํ•˜๊ณ , ํ•„์š”ํ•œ ๋„๊ตฌ๋ฅผ ์„ ํƒํ•ด์„œ ์ž‘์—…์„ ์™„์ˆ˜ํ•˜๋Š” ๋ฐฉ์‹์ด์•ผ! ๐Ÿค–

๐Ÿ’ก ํ”„๋ ˆ์ž„์›Œํฌ ์„ ํƒ ๊ฐ€์ด๋“œ LangChain: ๋ณต์žกํ•œ ์ฒด์ธ๊ณผ ๋‹ค์–‘ํ•œ ๋„๊ตฌ ํ†ตํ•ฉ์ด ํ•„์š”ํ•  ๋•Œ
OpenAI Function Calling: GPT ๋ชจ๋ธ ์‚ฌ์šฉ + ๊ฐ„๋‹จํ•œ ๋„๊ตฌ ํ†ตํ•ฉ
Claude Tool Use: ๋†’์€ ์ •ํ™•๋„์™€ ์•ˆ์ •์„ฑ์ด ์ค‘์š”ํ•  ๋•Œ
์ง์ ‘ ๊ตฌํ˜„: ์™„์ „ํ•œ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•๊ณผ ์„ธ๋ฐ€ํ•œ ์ œ์–ด๊ฐ€ ํ•„์š”ํ•  ๋•Œ

๐ŸŽฏ ์‹ค์ „ ํ™œ์šฉ ์‚ฌ๋ก€

์ด๋ก ์€ ์ถฉ๋ถ„ํžˆ ๋ดค์œผ๋‹ˆ, ์ด์ œ ์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ํ™œ์šฉ๋˜๋Š”์ง€ ๊ตฌ์ฒด์ ์ธ ์‚ฌ๋ก€๋“ค์„ ๋ณผ๊นŒ? ๐Ÿ’ผ

๐Ÿ“Š Case 1: ๋ฐ์ดํ„ฐ ๋ถ„์„ ์—์ด์ „ํŠธ

์‹œ๋‚˜๋ฆฌ์˜ค: ์‚ฌ์šฉ์ž๊ฐ€ "์ง€๋‚œ 3๊ฐœ์›” ๋งค์ถœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถ„์„ํ•˜๊ณ  ์‹œ๊ฐํ™”ํ•ด์ค˜"๋ผ๊ณ  ์š”์ฒญ

์—์ด์ „ํŠธ์˜ ์ž‘์—… ํ๋ฆ„:

1๏ธโƒฃ query_database ๋„๊ตฌ๋กœ ๋งค์ถœ ๋ฐ์ดํ„ฐ ์กฐํšŒ
2๏ธโƒฃ pandas_analysis ๋„๊ตฌ๋กœ ํ†ต๊ณ„ ๋ถ„์„ (ํ‰๊ท , ์ถ”์„ธ ๋“ฑ)
3๏ธโƒฃ create_chart ๋„๊ตฌ๋กœ ๊ทธ๋ž˜ํ”„ ์ƒ์„ฑ
4๏ธโƒฃ generate_report ๋„๊ตฌ๋กœ ๋ถ„์„ ๋ฆฌํฌํŠธ ์ž‘์„ฑ

# ์‹ค์ œ ๊ตฌํ˜„ ์˜ˆ์‹œ
class DataAnalysisAgent:
    def __init__(self):
        self.tools = {
            "query_database": self.query_db,
            "analyze_data": self.analyze,
            "create_chart": self.visualize,
            "generate_report": self.report
        }
    
    def query_db(self, query: str):
        # SQL ์‹คํ–‰
        return pd.read_sql(query, connection)
    
    def analyze(self, data: pd.DataFrame):
        return {
            "mean": data.mean(),
            "trend": calculate_trend(data),
            "insights": generate_insights(data)
        }
    
    def visualize(self, data: pd.DataFrame, chart_type: str):
        # ์ฐจํŠธ ์ƒ์„ฑ
        plt.figure(figsize=(10, 6))
        # ... ์ฐจํŠธ ๊ทธ๋ฆฌ๊ธฐ
        return "chart.png"
    
    def report(self, analysis: dict, chart_path: str):
        # ๋ฆฌํฌํŠธ ์ƒ์„ฑ
        return f"""
        ## ๋งค์ถœ ๋ถ„์„ ๋ฆฌํฌํŠธ
        
        ํ‰๊ท  ๋งค์ถœ: {analysis['mean']}
        ์ถ”์„ธ: {analysis['trend']}
        
        ![์ฐจํŠธ]({chart_path})
        
        ์ฃผ์š” ์ธ์‚ฌ์ดํŠธ:
        {analysis['insights']}
        """

๐Ÿ›’ Case 2: ์‡ผํ•‘ ์–ด์‹œ์Šคํ„ดํŠธ

์‹œ๋‚˜๋ฆฌ์˜ค: "30๋งŒ์› ์ดํ•˜ ๋…ธํŠธ๋ถ ์ถ”์ฒœํ•ด์ฃผ๊ณ , ๊ฐ€์žฅ ์ €๋ ดํ•œ ๊ณณ์—์„œ ๊ตฌ๋งค ๋งํฌ ์•Œ๋ ค์ค˜"

๋„๊ตฌ ์‚ฌ์šฉ ์ฒด์ธ:

1๏ธโƒฃ search_products: ์กฐ๊ฑด์— ๋งž๋Š” ์ œํ’ˆ ๊ฒ€์ƒ‰
2๏ธโƒฃ compare_prices: ์—ฌ๋Ÿฌ ์‡ผํ•‘๋ชฐ ๊ฐ€๊ฒฉ ๋น„๊ต
3๏ธโƒฃ get_reviews: ๋ฆฌ๋ทฐ ์ ์ˆ˜ ํ™•์ธ
4๏ธโƒฃ generate_recommendation: ์ตœ์  ์ œํ’ˆ ์ถ”์ฒœ

์ด๋Ÿฐ ์‹์œผ๋กœ ์—ฌ๋Ÿฌ ๋„๊ตฌ๋ฅผ ์กฐํ•ฉํ•ด์„œ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ตœ์ƒ์˜ ์‡ผํ•‘ ๊ฒฝํ—˜์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์–ด! ๐Ÿ›๏ธ

๐Ÿ“ง Case 3: ์ด๋ฉ”์ผ ์ž๋™ํ™” ์—์ด์ „ํŠธ

์‹œ๋‚˜๋ฆฌ์˜ค: "์ค‘์š”ํ•œ ์ด๋ฉ”์ผ๋งŒ ์š”์•ฝํ•ด์„œ ์Šฌ๋ž™์œผ๋กœ ๋ณด๋‚ด์ค˜"

์ž‘์—… ํ๋ฆ„:

1๏ธโƒฃ fetch_emails: Gmail API๋กœ ์ƒˆ ์ด๋ฉ”์ผ ๊ฐ€์ ธ์˜ค๊ธฐ
2๏ธโƒฃ classify_importance: AI๋กœ ์ค‘์š”๋„ ํŒ๋‹จ
3๏ธโƒฃ summarize_content: ์ด๋ฉ”์ผ ๋‚ด์šฉ ์š”์•ฝ
4๏ธโƒฃ send_slack_message: ์Šฌ๋ž™์œผ๋กœ ์•Œ๋ฆผ ์ „์†ก

async def email_automation_agent(user_id):
    # 1. ์ด๋ฉ”์ผ ๊ฐ€์ ธ์˜ค๊ธฐ
    emails = await fetch_emails(user_id, unread=True)
    
    for email in emails:
        # 2. ์ค‘์š”๋„ ํŒ๋‹จ
        importance = await classify_importance(email)
        
        if importance > 0.7:  # ์ค‘์š”ํ•œ ์ด๋ฉ”์ผ๋งŒ
            # 3. ์š”์•ฝ
            summary = await summarize_content(email.body)
            
            # 4. ์Šฌ๋ž™ ์ „์†ก
            await send_slack_message(
                channel=user_id,
                message=f"""
                ๐Ÿ“ง ์ค‘์š” ์ด๋ฉ”์ผ ๋„์ฐฉ!
                
                ๋ฐœ์‹ : {email.sender}
                ์ œ๋ชฉ: {email.subject}
                ์š”์•ฝ: {summary}
                
                [์ด๋ฉ”์ผ ๋ณด๊ธฐ]({email.link})
                """
            )

์ด๋Ÿฐ ์‹์œผ๋กœ AI ์—์ด์ „ํŠธ๋Š” ๋ฐ˜๋ณต์ ์ด๊ณ  ์‹œ๊ฐ„ ์†Œ๋ชจ์ ์ธ ์ž‘์—…์„ ์ž๋™ํ™”ํ•ด์ค„ ์ˆ˜ ์žˆ์–ด. ์ƒ์‚ฐ์„ฑ์ด ์—„์ฒญ ์˜ฌ๋ผ๊ฐ€์ง€! ๐Ÿ“ˆ

โš ๏ธ ๋„๊ตฌ์‚ฌ์šฉ ์‹œ ์ฃผ์˜์‚ฌํ•ญ๊ณผ ๋ฒ ์ŠคํŠธ ํ”„๋ž™ํ‹ฐ์Šค

๋„๊ตฌ์‚ฌ์šฉ์€ ๊ฐ•๋ ฅํ•˜์ง€๋งŒ, ์ž˜๋ชป ์‚ฌ์šฉํ•˜๋ฉด ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ์–ด. ์‹ค์ „์—์„œ ๊ผญ ์•Œ์•„์•ผ ํ•  ์ฃผ์˜์‚ฌํ•ญ๋“ค์„ ์ •๋ฆฌํ–ˆ์–ด! ๐Ÿšจ

๐Ÿ”’ ๋ณด์•ˆ ๊ณ ๋ ค์‚ฌํ•ญ

โš ๏ธ ์œ„ํ—˜ํ•œ ํŒจํ„ด๋“ค

1. ๋ฌด์ œํ•œ ์ฝ”๋“œ ์‹คํ–‰
โŒ ๋‚˜์œ ์˜ˆ: eval(user_input)
โœ… ์ข‹์€ ์˜ˆ: ์ƒŒ๋“œ๋ฐ•์Šค ํ™˜๊ฒฝ์—์„œ ์ œํ•œ๋œ ๋ช…๋ น์–ด๋งŒ ์‹คํ–‰

2. ๋ฏผ๊ฐํ•œ ์ •๋ณด ๋…ธ์ถœ
โŒ API ํ‚ค๋ฅผ ๋„๊ตฌ ์„ค๋ช…์— ํฌํ•จ
โœ… ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋กœ ๊ด€๋ฆฌํ•˜๊ณ  ๋กœ๊ทธ์— ๋‚จ๊ธฐ์ง€ ์•Š๊ธฐ

3. ๋ฌดํ•œ ๋ฃจํ”„ ์œ„ํ—˜
โŒ ๋„๊ตฌ๊ฐ€ ๋„๊ตฌ๋ฅผ ๊ณ„์† ํ˜ธ์ถœ
โœ… ์ตœ๋Œ€ ์‹คํ–‰ ํšŸ์ˆ˜ ์ œํ•œ ์„ค์ •

์•ˆ์ „ํ•œ ๋„๊ตฌ ์‹คํ–‰ ํŒจํ„ด

class SafeToolExecutor:
    def __init__(self, max_iterations=10, timeout=30):
        self.max_iterations = max_iterations
        self.timeout = timeout
        self.execution_count = 0
    
    def execute_with_safety(self, tool, arguments):
        # 1. ์‹คํ–‰ ํšŸ์ˆ˜ ์ฒดํฌ
        if self.execution_count >= self.max_iterations:
            raise Exception("์ตœ๋Œ€ ์‹คํ–‰ ํšŸ์ˆ˜ ์ดˆ๊ณผ")
        
        # 2. ์ž…๋ ฅ ๊ฒ€์ฆ
        validated_args = self.validate_arguments(arguments)
        
        # 3. ํƒ€์ž„์•„์›ƒ ์„ค์ •
        with timeout_context(self.timeout):
            try:
                result = tool.execute(**validated_args)
                self.execution_count += 1
                
                # 4. ๊ฒฐ๊ณผ ๊ฒ€์ฆ
                return self.validate_result(result)
            except Exception as e:
                # 5. ์—๋Ÿฌ ์ฒ˜๋ฆฌ
                return self.handle_error(e)
    
    def validate_arguments(self, args):
        # SQL Injection ๋ฐฉ์ง€
        # XSS ๋ฐฉ์ง€
        # ํŒŒ์ผ ๊ฒฝ๋กœ ๊ฒ€์ฆ ๋“ฑ
        return sanitized_args
    
    def validate_result(self, result):
        # ๋ฏผ๊ฐํ•œ ์ •๋ณด ํ•„ํ„ฐ๋ง
        # ํฌ๊ธฐ ์ œํ•œ
        return filtered_result

๐ŸŽฏ ํšจ์œจ์ ์ธ ๋„๊ตฌ ์„ค๊ณ„

โœจ ์ข‹์€ ๋„๊ตฌ์˜ ํŠน์ง•

1. ๋ช…ํ™•ํ•œ ๋‹จ์ผ ์ฑ…์ž„
ํ•˜๋‚˜์˜ ๋„๊ตฌ๋Š” ํ•˜๋‚˜์˜ ์ผ๋งŒ ์ž˜ํ•ด์•ผ ํ•ด. "๋ชจ๋“  ๊ฑธ ๋‹ค ํ•˜๋Š” ๋„๊ตฌ"๋Š” AI๊ฐ€ ์–ธ์ œ ์‚ฌ์šฉํ•ด์•ผ ํ• ์ง€ ํ˜ผ๋ž€์Šค๋Ÿฌ์›Œํ•ด.

โŒ ๋‚˜์œ ์˜ˆ: do_everything(action, data, options...)
โœ… ์ข‹์€ ์˜ˆ: search_products(query), get_product_details(id)

2. ์ž์„ธํ•œ ์„ค๋ช…(Description)
AI๊ฐ€ ๋„๊ตฌ๋ฅผ ์„ ํƒํ•  ๋•Œ ์„ค๋ช…์„ ์ฝ๊ณ  ํŒ๋‹จํ•ด. ๋ช…ํ™•ํ•˜๊ณ  ๊ตฌ์ฒด์ ์œผ๋กœ ์ž‘์„ฑํ•ด์•ผ ํ•ด!

โŒ ๋‚˜์œ ์„ค๋ช…: "๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค"

โœ… ์ข‹์€ ์„ค๋ช…: "๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค. 
์ด๋ฉ”์ผ, ์ด๋ฆ„, ๊ฐ€์ž…์ผ ๋“ฑ์˜ ์ •๋ณด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, 
user_id ๋˜๋Š” email๋กœ ๊ฒ€์ƒ‰ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค."

3. ๋ช…ํ™•ํ•œ ํŒŒ๋ผ๋ฏธํ„ฐ ์ •์˜
ํƒ€์ž…, ํ•„์ˆ˜ ์—ฌ๋ถ€, ๊ธฐ๋ณธ๊ฐ’, ์˜ˆ์‹œ๋ฅผ ๋ชจ๋‘ ๋ช…์‹œํ•ด์ค˜.

{
  "name": "send_email",
  "parameters": {
    "to": {
      "type": "string",
      "description": "์ˆ˜์‹ ์ž ์ด๋ฉ”์ผ ์ฃผ์†Œ",
      "required": true,
      "example": "user@example.com"
    },
    "subject": {
      "type": "string",
      "description": "์ด๋ฉ”์ผ ์ œ๋ชฉ",
      "required": true
    },
    "body": {
      "type": "string",
      "description": "์ด๋ฉ”์ผ ๋ณธ๋ฌธ (HTML ์ง€์›)",
      "required": true
    },
    "priority": {
      "type": "string",
      "enum": ["low", "normal", "high"],
      "default": "normal",
      "description": "์ด๋ฉ”์ผ ์šฐ์„ ์ˆœ์œ„"
    }
  }
}

๐Ÿ” ๋””๋ฒ„๊น…๊ณผ ๋ชจ๋‹ˆํ„ฐ๋ง

AI ์—์ด์ „ํŠธ๋Š” ๋ธ”๋ž™๋ฐ•์Šค์ฒ˜๋Ÿผ ๋А๊ปด์งˆ ์ˆ˜ ์žˆ์–ด. ๊ทธ๋ž˜์„œ ๋กœ๊น…๊ณผ ๋ชจ๋‹ˆํ„ฐ๋ง์ด ์ •๋ง ์ค‘์š”ํ•ด! ๐Ÿ“Š

import logging
from datetime import datetime

class ToolLogger:
    def __init__(self):
        self.logger = logging.getLogger("AgentTools")
        self.execution_history = []
    
    def log_tool_call(self, tool_name, arguments, result, duration):
        log_entry = {
            "timestamp": datetime.now().isoformat(),
            "tool": tool_name,
            "arguments": arguments,
            "result": result,
            "duration_ms": duration,
            "success": result.get("success", False)
        }
        
        self.execution_history.append(log_entry)
        
        # ์ฝ˜์†” ์ถœ๋ ฅ
        self.logger.info(f"""
        ๐Ÿ”ง ๋„๊ตฌ ์‹คํ–‰: {tool_name}
        ๐Ÿ“ฅ ์ž…๋ ฅ: {arguments}
        ๐Ÿ“ค ์ถœ๋ ฅ: {result}
        โฑ๏ธ ์†Œ์š”์‹œ๊ฐ„: {duration}ms
        """)
        
        # ์‹คํŒจ ์‹œ ์•Œ๋ฆผ
        if not result.get("success"):
            self.logger.error(f"๋„๊ตฌ ์‹คํ–‰ ์‹คํŒจ: {tool_name}")
            self.send_alert(log_entry)
    
    def get_statistics(self):
        """๋„๊ตฌ ์‚ฌ์šฉ ํ†ต๊ณ„"""
        return {
            "total_calls": len(self.execution_history),
            "success_rate": self.calculate_success_rate(),
            "avg_duration": self.calculate_avg_duration(),
            "most_used_tool": self.get_most_used_tool()
        }

๐Ÿ’ฐ ๋น„์šฉ ์ตœ์ ํ™”

AI API๋Š” ํ† ํฐ ๋‹จ์œ„๋กœ ๊ณผ๊ธˆ๋˜๋‹ˆ๊นŒ, ๋„๊ตฌ ์‚ฌ์šฉ์„ ์ตœ์ ํ™”ํ•˜๋ฉด ๋น„์šฉ์„ ํฌ๊ฒŒ ์ค„์ผ ์ˆ˜ ์žˆ์–ด! ๐Ÿ’ธ

๐Ÿ’ก ๋น„์šฉ ์ ˆ๊ฐ ํŒ

1. ์บ์‹ฑ ํ™œ์šฉ
๊ฐ™์€ ์š”์ฒญ์€ ์บ์‹œ์—์„œ ๊ฐ€์ ธ์˜ค๊ธฐ. ํŠนํžˆ ๋‚ ์”จ, ํ™˜์œจ ๊ฐ™์€ ์ž์ฃผ ์กฐํšŒ๋˜๋Š” ๋ฐ์ดํ„ฐ!

from functools import lru_cache
from datetime import datetime, timedelta

class CachedTool:
    def __init__(self, ttl_seconds=300):
        self.cache = {}
        self.ttl = ttl_seconds
    
    def get_cached(self, key):
        if key in self.cache:
            value, timestamp = self.cache[key]
            if datetime.now() - timestamp < timedelta(seconds=self.ttl):
                return value
        return None
    
    def set_cache(self, key, value):
        self.cache[key] = (value, datetime.now())

2. ๋ฐฐ์น˜ ์ฒ˜๋ฆฌ
์—ฌ๋Ÿฌ ๊ฐœ์˜ ์š”์ฒญ์„ ํ•œ ๋ฒˆ์— ์ฒ˜๋ฆฌํ•˜๋ฉด API ํ˜ธ์ถœ ํšŸ์ˆ˜๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ์–ด.

3. ๊ฒฐ๊ณผ ํฌ๊ธฐ ์ œํ•œ
ํ•„์š”ํ•œ ์ •๋ณด๋งŒ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ์ œํ•œ. ๊ธด ํ…์ŠคํŠธ๋Š” ์š”์•ฝํ•ด์„œ ์ „๋‹ฌ!

๐Ÿš€ ๊ณ ๊ธ‰ ํŒจํ„ด๊ณผ ๊ธฐ๋ฒ•

๊ธฐ๋ณธ์„ ๋„˜์–ด์„œ ์ข€ ๋” ๊ณ ๊ธ‰ ๊ธฐ์ˆ ๋“ค์„ ์•Œ์•„๋ณผ๊นŒ? ์ด๋Ÿฐ ํŒจํ„ด๋“ค์„ ์•Œ๋ฉด ์ง„์งœ ํ”„๋กœ์ฒ˜๋Ÿผ AI ์—์ด์ „ํŠธ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด! ๐ŸŽ“

๐Ÿ”„ ReAct ํŒจํ„ด (Reasoning + Acting)

ReAct๋Š” AI๊ฐ€ ์ƒ๊ฐ(Reasoning)ํ•˜๊ณ  ํ–‰๋™(Acting)ํ•˜๋Š” ๊ณผ์ •์„ ๋ฐ˜๋ณตํ•˜๋Š” ํŒจํ„ด์ด์•ผ. ๋งˆ์น˜ ์‚ฌ๋žŒ์ด ๋ฌธ์ œ๋ฅผ ํ‘ธ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ!

๐Ÿง  ReAct ์‚ฌ๊ณ  ๊ณผ์ • ์˜ˆ์‹œ

์‚ฌ์šฉ์ž: "2024๋…„ ํŒŒ๋ฆฌ ์˜ฌ๋ฆผํ”ฝ ๊ธˆ๋ฉ”๋‹ฌ 1์œ„ ๊ตญ๊ฐ€์™€ ๊ทธ ๋‚˜๋ผ์˜ ์ˆ˜๋„๋ฅผ ์•Œ๋ ค์ค˜"

Thought 1: ๋จผ์ € 2024 ํŒŒ๋ฆฌ ์˜ฌ๋ฆผํ”ฝ ๊ธˆ๋ฉ”๋‹ฌ ์ˆœ์œ„๋ฅผ ๊ฒ€์ƒ‰ํ•ด์•ผ๊ฒ ๋‹ค.
Action 1: search("2024 ํŒŒ๋ฆฌ ์˜ฌ๋ฆผํ”ฝ ๊ธˆ๋ฉ”๋‹ฌ ์ˆœ์œ„")
Observation 1: ๋ฏธ๊ตญ์ด 40๊ฐœ๋กœ 1์œ„์ž…๋‹ˆ๋‹ค.

Thought 2: ๋ฏธ๊ตญ์˜ ์ˆ˜๋„๋ฅผ ํ™•์ธํ•ด์•ผ๊ฒ ๋‹ค.
Action 2: search("๋ฏธ๊ตญ ์ˆ˜๋„")
Observation 2: ์›Œ์‹ฑํ„ด D.C.์ž…๋‹ˆ๋‹ค.

Thought 3: ์ด์ œ ๋‹ต๋ณ€ํ•  ์ˆ˜ ์žˆ๋‹ค!
Final Answer: 2024๋…„ ํŒŒ๋ฆฌ ์˜ฌ๋ฆผํ”ฝ ๊ธˆ๋ฉ”๋‹ฌ 1์œ„๋Š” ๋ฏธ๊ตญ(40๊ฐœ)์ด๋ฉฐ, 
๋ฏธ๊ตญ์˜ ์ˆ˜๋„๋Š” ์›Œ์‹ฑํ„ด D.C.์ž…๋‹ˆ๋‹ค.

์ด ํŒจํ„ด์˜ ํ•ต์‹ฌ์€ AI๊ฐ€ ๊ฐ ๋‹จ๊ณ„์—์„œ ์™œ ๊ทธ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”์ง€ ์„ค๋ช…ํ•œ๋‹ค๋Š” ๊ฑฐ์•ผ. ๋””๋ฒ„๊น…ํ•  ๋•Œ ์—„์ฒญ ์œ ์šฉํ•ด! ๐Ÿ”

๐ŸŽญ Multi-Agent ํ˜‘์—…

์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ „๋ฌธํ™”๋œ ์—์ด์ „ํŠธ๊ฐ€ ํ˜‘๋ ฅํ•˜๋Š” ํŒจํ„ด๋„ ์žˆ์–ด. ๊ฐ์ž ์ž˜ํ•˜๋Š” ๋ถ„์•ผ๊ฐ€ ๋‹ค๋ฅธ ๊ฑฐ์ง€!

์˜ˆ์‹œ: ์ฝ˜ํ…์ธ  ์ œ์ž‘ ํŒ€

๐ŸŽจ Designer Agent: ์ด๋ฏธ์ง€ ์ƒ์„ฑ, ๋ ˆ์ด์•„์›ƒ ๋””์ž์ธ
โœ๏ธ Writer Agent: ํ…์ŠคํŠธ ์ž‘์„ฑ, ํŽธ์ง‘
๐Ÿ“Š Analyst Agent: ๋ฐ์ดํ„ฐ ๋ถ„์„, ํŠธ๋ Œ๋“œ ํŒŒ์•…
๐ŸŽฏ Manager Agent: ์ „์ฒด ์กฐ์œจ, ์ตœ์ข… ๊ฒฐ์ •

class MultiAgentSystem:
    def __init__(self):
        self.agents = {
            "designer": DesignerAgent(),
            "writer": WriterAgent(),
            "analyst": AnalystAgent(),
            "manager": ManagerAgent()
        }
    
    async def create_content(self, topic):
        # 1. ๋ถ„์„๊ฐ€๊ฐ€ ํŠธ๋ Œ๋“œ ๋ถ„์„
        trends = await self.agents["analyst"].analyze_trends(topic)
        
        # 2. ์ž‘๊ฐ€๊ฐ€ ์ดˆ์•ˆ ์ž‘์„ฑ
        draft = await self.agents["writer"].write_draft(topic, trends)
        
        # 3. ๋””์ž์ด๋„ˆ๊ฐ€ ์ด๋ฏธ์ง€ ์ƒ์„ฑ
        images = await self.agents["designer"].create_images(draft)
        
        # 4. ๋งค๋‹ˆ์ €๊ฐ€ ์ตœ์ข… ๊ฒ€ํ†  ๋ฐ ์กฐํ•ฉ
        final_content = await self.agents["manager"].finalize(
            draft, images, trends
        )
        
        return final_content

๐Ÿงฉ Tool Composition (๋„๊ตฌ ์กฐํ•ฉ)

๊ธฐ๋ณธ ๋„๊ตฌ๋“ค์„ ์กฐํ•ฉํ•ด์„œ ๋” ๋ณต์žกํ•œ ๋„๊ตฌ๋ฅผ ๋งŒ๋“œ๋Š” ๊ธฐ๋ฒ•์ด์•ผ. ๋ ˆ๊ณ  ๋ธ”๋ก์ฒ˜๋Ÿผ! ๐Ÿงฑ

class ComposedTool:
    def __init__(self, name, steps):
        self.name = name
        self.steps = steps  # ์‹คํ–‰ํ•  ๋„๊ตฌ๋“ค์˜ ์ˆœ์„œ
    
    async def execute(self, initial_input):
        result = initial_input
        
        for step in self.steps:
            tool = step["tool"]
            transform = step.get("transform", lambda x: x)
            
            # ์ด์ „ ๊ฒฐ๊ณผ๋ฅผ ๋ณ€ํ™˜ํ•ด์„œ ๋‹ค์Œ ๋„๊ตฌ์˜ ์ž…๋ ฅ์œผ๋กœ
            tool_input = transform(result)
            result = await tool.execute(tool_input)
        
        return result

# ์‚ฌ์šฉ ์˜ˆ์‹œ: "์›นํŽ˜์ด์ง€ ์š”์•ฝ" ๋„๊ตฌ
summarize_webpage = ComposedTool(
    name="summarize_webpage",
    steps=[
        {
            "tool": fetch_webpage_tool,
            "transform": lambda url: {"url": url}
        },
        {
            "tool": extract_text_tool,
            "transform": lambda html: {"html": html}
        },
        {
            "tool": summarize_text_tool,
            "transform": lambda text: {"text": text, "max_length": 200}
        }
    ]
)

# ์‹คํ–‰
summary = await summarize_webpage.execute("https://example.com")

๐ŸŽฏ Conditional Tool Use (์กฐ๊ฑด๋ถ€ ๋„๊ตฌ ์‚ฌ์šฉ)

์ƒํ™ฉ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํŒจํ„ด์ด์•ผ. if-else์ฒ˜๋Ÿผ!

class ConditionalAgent:
    async def process_request(self, user_input):
        # ์˜๋„ ํŒŒ์•…
        intent = await self.classify_intent(user_input)
        
        if intent == "calculation":
            return await self.calculator_tool.execute(user_input)
        
        elif intent == "search":
            # ๊ฒ€์ƒ‰ ์ข…๋ฅ˜๋„ ์„ธ๋ถ„ํ™”
            search_type = await self.classify_search_type(user_input)
            
            if search_type == "recent_news":
                return await self.news_search_tool.execute(user_input)
            elif search_type == "product":
                return await self.product_search_tool.execute(user_input)
            else:
                return await self.web_search_tool.execute(user_input)
        
        elif intent == "data_analysis":
            # ๋ฐ์ดํ„ฐ ํฌ๊ธฐ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ๋„๊ตฌ ์‚ฌ์šฉ
            data_size = await self.estimate_data_size(user_input)
            
            if data_size > 1000000:
                return await self.big_data_tool.execute(user_input)
            else:
                return await self.simple_analysis_tool.execute(user_input)
        
        else:
            return "์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. ์š”์ฒญ์„ ์ดํ•ดํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค."

๐ŸŒ ์‹ค์ œ ์„œ๋น„์Šค ๊ตฌ์ถ•ํ•˜๊ธฐ

์ด๋ก ๊ณผ ์˜ˆ์ œ๋Š” ์ถฉ๋ถ„ํžˆ ๋ดค์œผ๋‹ˆ, ์ด์ œ ์‹ค์ œ๋กœ ์„œ๋น„์Šค๋ฅผ ๋งŒ๋“ค์–ด๋ณผ๊นŒ? ๊ฐ„๋‹จํ•œ AI ์–ด์‹œ์Šคํ„ดํŠธ API๋ฅผ ๊ตฌ์ถ•ํ•ด๋ณด์ž! ๐Ÿ—๏ธ

๐Ÿ›๏ธ ์ „์ฒด ์•„ํ‚คํ…์ฒ˜

AI Agent Service Architecture User Interface Web / Mobile / API Agent Orchestrator Request Routing LLM Service GPT-4 / Claude Tool Manager Tool Registry Memory Store Redis / Vector DB Logger Monitoring External APIs Database File System Code Executor Search Engine

๐Ÿ’ป FastAPI๋กœ ๊ตฌํ˜„ํ•˜๊ธฐ

1. ๊ธฐ๋ณธ ์„œ๋ฒ„ ๊ตฌ์กฐ

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List, Dict, Optional
import asyncio

app = FastAPI(title="AI Agent API")

class ChatRequest(BaseModel):
    message: str
    user_id: str
    session_id: Optional[str] = None

class ChatResponse(BaseModel):
    response: str
    tools_used: List[str]
    execution_time: float

# ์ „์—ญ ์—์ด์ „ํŠธ ์ธ์Šคํ„ด์Šค
agent = AIAgent()

@app.post("/chat", response_model=ChatResponse)
async def chat(request: ChatRequest):
    """๋ฉ”์ธ ์ฑ„ํŒ… ์—”๋“œํฌ์ธํŠธ"""
    try:
        start_time = time.time()
        
        # ์—์ด์ „ํŠธ ์‹คํ–‰
        result = await agent.process(
            message=request.message,
            user_id=request.user_id,
            session_id=request.session_id
        )
        
        execution_time = time.time() - start_time
        
        return ChatResponse(
            response=result["response"],
            tools_used=result["tools_used"],
            execution_time=execution_time
        )
    
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@app.get("/tools")
async def list_tools():
    """์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋„๊ตฌ ๋ชฉ๋ก"""
    return {
        "tools": agent.get_available_tools()
    }

@app.post("/tools/{tool_name}/execute")
async def execute_tool(tool_name: str, arguments: Dict):
    """ํŠน์ • ๋„๊ตฌ ์ง์ ‘ ์‹คํ–‰ (ํ…Œ์ŠคํŠธ์šฉ)"""
    try:
        result = await agent.execute_tool(tool_name, arguments)
        return {"success": True, "result": result}
    except Exception as e:
        return {"success": False, "error": str(e)}

2. ์—์ด์ „ํŠธ ์ฝ”์–ด ๊ตฌํ˜„

import openai
from typing import List, Dict, Any

class AIAgent:
    def __init__(self):
        self.tool_manager = ToolManager()
        self.memory = ConversationMemory()
        self.logger = AgentLogger()
        
        # ๋„๊ตฌ ๋“ฑ๋ก
        self._register_tools()
    
    def _register_tools(self):
        """๋ชจ๋“  ๋„๊ตฌ ๋“ฑ๋ก"""
        self.tool_manager.register(WeatherTool())
        self.tool_manager.register(CalculatorTool())
        self.tool_manager.register(SearchTool())
        self.tool_manager.register(DatabaseTool())
        # ... ๋” ๋งŽ์€ ๋„๊ตฌ๋“ค
    
    async def process(self, message: str, user_id: str, 
                     session_id: str = None) -> Dict:
        """๋ฉ”์ธ ์ฒ˜๋ฆฌ ๋กœ์ง"""
        
        # 1. ๋Œ€ํ™” ๊ธฐ๋ก ๋กœ๋“œ
        history = await self.memory.get_history(session_id)
        
        # 2. ๋„๊ตฌ ์Šคํ‚ค๋งˆ ์ค€๋น„
        tools_schema = self.tool_manager.get_schemas()
        
        # 3. LLM ํ˜ธ์ถœ
        messages = self._build_messages(message, history)
        
        response = await openai.ChatCompletion.acreate(
            model="gpt-4",
            messages=messages,
            functions=tools_schema,
            function_call="auto"
        )
        
        # 4. ๋„๊ตฌ ํ˜ธ์ถœ์ด ํ•„์š”ํ•œ์ง€ ํ™•์ธ
        message_obj = response["choices"][0]["message"]
        
        if message_obj.get("function_call"):
            # ๋„๊ตฌ ์‹คํ–‰
            result = await self._execute_tool_call(message_obj)
            
            # ๊ฒฐ๊ณผ๋ฅผ ๋‹ค์‹œ LLM์— ์ „๋‹ฌ
            final_response = await self._get_final_response(
                messages, message_obj, result
            )
            
            tools_used = [message_obj["function_call"]["name"]]
        else:
            final_response = message_obj["content"]
            tools_used = []
        
        # 5. ๋Œ€ํ™” ๊ธฐ๋ก ์ €์žฅ
        await self.memory.save_turn(
            session_id, message, final_response
        )
        
        # 6. ๋กœ๊น…
        self.logger.log_interaction(
            user_id, message, final_response, tools_used
        )
        
        return {
            "response": final_response,
            "tools_used": tools_used
        }
    
    async def _execute_tool_call(self, message_obj):
        """๋„๊ตฌ ์‹คํ–‰"""
        function_name = message_obj["function_call"]["name"]
        arguments = json.loads(
            message_obj["function_call"]["arguments"]
        )
        
        return await self.tool_manager.execute(
            function_name, arguments
        )
    
    def _build_messages(self, current_message, history):
        """๋ฉ”์‹œ์ง€ ๊ตฌ์„ฑ"""
        messages = [
            {
                "role": "system",
                "content": """๋‹น์‹ ์€ ๋„์›€์ด ๋˜๋Š” AI ์–ด์‹œ์Šคํ„ดํŠธ์ž…๋‹ˆ๋‹ค.
                ํ•„์š”ํ•  ๋•Œ ์ œ๊ณต๋œ ๋„๊ตฌ๋“ค์„ ์‚ฌ์šฉํ•˜์„ธ์š”."""
            }
        ]
        
        # ์ด์ „ ๋Œ€ํ™” ์ถ”๊ฐ€
        messages.extend(history)
        
        # ํ˜„์žฌ ๋ฉ”์‹œ์ง€ ์ถ”๊ฐ€
        messages.append({
            "role": "user",
            "content": current_message
        })
        
        return messages

๐Ÿ—„๏ธ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ

๋Œ€ํ™” ๊ธฐ๋ก์„ ์ €์žฅํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ๋„ ์ค‘์š”ํ•ด! Redis๋ฅผ ์‚ฌ์šฉํ•œ ์˜ˆ์‹œ๋ฅผ ๋ณผ๊ฒŒ.

import redis
import json
from datetime import timedelta

class ConversationMemory:
    def __init__(self):
        self.redis_client = redis.Redis(
            host='localhost',
            port=6379,
            decode_responses=True
        )
        self.ttl = timedelta(hours=24)  # 24์‹œ๊ฐ„ ํ›„ ์ž๋™ ์‚ญ์ œ
    
    async def get_history(self, session_id: str, 
                         max_turns: int = 10) -> List[Dict]:
        """๋Œ€ํ™” ๊ธฐ๋ก ์กฐํšŒ"""
        key = f"conversation:{session_id}"
        history_json = self.redis_client.get(key)
        
        if not history_json:
            return []
        
        history = json.loads(history_json)
        
        # ์ตœ๊ทผ N๊ฐœ๋งŒ ๋ฐ˜ํ™˜ (ํ† ํฐ ์ ˆ์•ฝ)
        return history[-max_turns * 2:]  # user + assistant ์Œ
    
    async def save_turn(self, session_id: str, 
                       user_message: str, 
                       assistant_message: str):
        """๋Œ€ํ™” ํ„ด ์ €์žฅ"""
        key = f"conversation:{session_id}"
        
        # ๊ธฐ์กด ๊ธฐ๋ก ๊ฐ€์ ธ์˜ค๊ธฐ
        history = await self.get_history(session_id)
        
        # ์ƒˆ ํ„ด ์ถ”๊ฐ€
        history.extend([
            {"role": "user", "content": user_message},
            {"role": "assistant", "content": assistant_message}
        ])
        
        # ์ €์žฅ (TTL ์„ค์ •)
        self.redis_client.setex(
            key,
            self.ttl,
            json.dumps(history)
        )
    
    async def clear_history(self, session_id: str):
        """๋Œ€ํ™” ๊ธฐ๋ก ์‚ญ์ œ"""
        key = f"conversation:{session_id}"
        self.redis_client.delete(key)

๐Ÿ“Š ์„ฑ๋Šฅ ์ตœ์ ํ™”์™€ ์Šค์ผ€์ผ๋ง

์„œ๋น„์Šค๊ฐ€ ์ปค์ง€๋ฉด ์„ฑ๋Šฅ์ด ์ค‘์š”ํ•ด์ ธ. ์‹ค์ „ ์ตœ์ ํ™” ๊ธฐ๋ฒ•๋“ค์„ ์•Œ์•„๋ณด์ž! โšก

๐Ÿš€ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ

์—ฌ๋Ÿฌ ๋„๊ตฌ๋ฅผ ๋™์‹œ์— ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์†๋„๊ฐ€ ์—„์ฒญ ๋นจ๋ผ์ ธ!

import asyncio

class ParallelAgent:
    async def process_parallel_tools(self, tool_calls: List[Dict]):
        """์—ฌ๋Ÿฌ ๋„๊ตฌ๋ฅผ ๋™์‹œ์— ์‹คํ–‰"""
        
        # ๊ฐ ๋„๊ตฌ ํ˜ธ์ถœ์„ ๋น„๋™๊ธฐ ํƒœ์Šคํฌ๋กœ ์ƒ์„ฑ
        tasks = [
            self.execute_tool(call["name"], call["arguments"])
            for call in tool_calls
        ]
        
        # ๋ชจ๋“  ํƒœ์Šคํฌ๋ฅผ ๋™์‹œ์— ์‹คํ–‰
        results = await asyncio.gather(*tasks, return_exceptions=True)
        
        # ๊ฒฐ๊ณผ ์ฒ˜๋ฆฌ
        processed_results = []
        for i, result in enumerate(results):
            if isinstance(result, Exception):
                processed_results.append({
                    "tool": tool_calls[i]["name"],
                    "success": False,
                    "error": str(result)
                })
            else:
                processed_results.append({
                    "tool": tool_calls[i]["name"],
                    "success": True,
                    "result": result
                })
        
        return processed_results

# ์‚ฌ์šฉ ์˜ˆ์‹œ
tool_calls = [
    {"name": "get_weather", "arguments": {"city": "์„œ์šธ"}},
    {"name": "get_weather", "arguments": {"city": "๋ถ€์‚ฐ"}},
    {"name": "get_weather", "arguments": {"city": "๋Œ€๊ตฌ"}}
]

# ์ˆœ์ฐจ ์‹คํ–‰: 3์ดˆ (๊ฐ 1์ดˆ์”ฉ)
# ๋ณ‘๋ ฌ ์‹คํ–‰: 1์ดˆ (๋™์‹œ์—!)
results = await agent.process_parallel_tools(tool_calls)

๐Ÿ’พ ์Šค๋งˆํŠธ ์บ์‹ฑ

from functools import wraps
import hashlib

def cached_tool(ttl_seconds=300):
    """๋„๊ตฌ ๊ฒฐ๊ณผ๋ฅผ ์บ์‹ฑํ•˜๋Š” ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ"""
    def decorator(func):
        cache = {}
        
        @wraps(func)
        async def wrapper(*args, **kwargs):
            # ์บ์‹œ ํ‚ค ์ƒ์„ฑ
            cache_key = hashlib.md5(
                f"{func.__name__}:{args}:{kwargs}".encode()
            ).hexdigest()
            
            # ์บ์‹œ ํ™•์ธ
            if cache_key in cache:
                cached_value, timestamp = cache[cache_key]
                if time.time() - timestamp < ttl_seconds:
                    print(f"โœ… ์บ์‹œ ํžˆํŠธ: {func.__name__}")
                    return cached_value
            
            # ์บ์‹œ ๋ฏธ์Šค - ์‹ค์ œ ์‹คํ–‰
            result = await func(*args, **kwargs)
            cache[cache_key] = (result, time.time())
            
            return result
        
        return wrapper
    return decorator

# ์‚ฌ์šฉ ์˜ˆ์‹œ
@cached_tool(ttl_seconds=600)  # 10๋ถ„ ์บ์‹ฑ
async def get_weather(city: str):
    # API ํ˜ธ์ถœ (๋น„์šฉ ๋ฐœ์ƒ)
    return await weather_api.fetch(city)

๐Ÿ“ˆ ๋กœ๋“œ ๋ฐธ๋Ÿฐ์‹ฑ

์—ฌ๋Ÿฌ LLM ์ œ๊ณต์ž๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋ถ€ํ•˜๋ฅผ ๋ถ„์‚ฐ์‹œํ‚ฌ ์ˆ˜๋„ ์žˆ์–ด!

class LLMLoadBalancer:
    def __init__(self):
        self.providers = [
            {"name": "openai", "client": openai_client, "weight": 0.6},
            {"name": "anthropic", "client": anthropic_client, "weight": 0.3},
            {"name": "cohere", "client": cohere_client, "weight": 0.1}
        ]
        self.current_loads = {p["name"]: 0 for p in self.providers}
    
    async def get_completion(self, messages, **kwargs):
        """๊ฐ€์žฅ ๋ถ€ํ•˜๊ฐ€ ์ ์€ ์ œ๊ณต์ž ์„ ํƒ"""
        
        # ๊ฐ€์ค‘์น˜์™€ ํ˜„์žฌ ๋ถ€ํ•˜๋ฅผ ๊ณ ๋ คํ•ด์„œ ์„ ํƒ
        selected = min(
            self.providers,
            key=lambda p: self.current_loads[p["name"]] / p["weight"]
        )
        
        self.current_loads[selected["name"]] += 1
        
        try:
            result = await selected["client"].complete(messages, **kwargs)
            return result
        finally:
            self.current_loads[selected["name"]] -= 1

๐ŸŽ“ ํ•™์Šต ์ž๋ฃŒ์™€ ์ปค๋ฎค๋‹ˆํ‹ฐ

AI ์—์ด์ „ํŠธ ๊ฐœ๋ฐœ์„ ๋” ๊นŠ์ด ๊ณต๋ถ€ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด? ์ด๋Ÿฐ ์ž๋ฃŒ๋“ค์„ ์ถ”์ฒœํ•ด! ๐Ÿ“š

๐ŸŒŸ ์ถ”์ฒœ ํ•™์Šต ๊ฒฝ๋กœ

1๋‹จ๊ณ„: ๊ธฐ์ดˆ ๋‹ค์ง€๊ธฐ
- LangChain ๊ณต์‹ ๋ฌธ์„œ (langchain.com)
- OpenAI Cookbook (github.com/openai/openai-cookbook)
- Anthropic Claude ๋ฌธ์„œ

2๋‹จ๊ณ„: ์‹ค์ „ ํ”„๋กœ์ ํŠธ
- ๊ฐ„๋‹จํ•œ ์ฑ—๋ด‡ ๋งŒ๋“ค๊ธฐ
- ๋ฐ์ดํ„ฐ ๋ถ„์„ ์—์ด์ „ํŠธ ๊ตฌ์ถ•
- ์ž๋™ํ™” ์›Œํฌํ”Œ๋กœ์šฐ ๊ฐœ๋ฐœ

3๋‹จ๊ณ„: ๊ณ ๊ธ‰ ์ฃผ์ œ
- Multi-Agent Systems
- Reinforcement Learning from Human Feedback (RLHF)
- Agent ํ‰๊ฐ€ ๋ฐ ๋ฒค์น˜๋งˆํ‚น

๐Ÿ’ก ์ปค๋ฎค๋‹ˆํ‹ฐ ์ฐธ์—ฌํ•˜๊ธฐ

ํ˜ผ์ž ๊ณต๋ถ€ํ•˜๊ธฐ ํž˜๋“ค๋‹ค๋ฉด ์ปค๋ฎค๋‹ˆํ‹ฐ์— ์ฐธ์—ฌํ•ด๋ด!

- LangChain Discord
- r/MachineLearning (Reddit)
- AI Agent ๊ด€๋ จ GitHub ํ”„๋กœ์ ํŠธ๋“ค
- ํ•œ๊ตญ AI ๊ฐœ๋ฐœ์ž ์ปค๋ฎค๋‹ˆํ‹ฐ

๊ทธ๋ฆฌ๊ณ  ์žฌ๋Šฅ๋„ท(jaenung.net)์—์„œ๋„ AI ๊ฐœ๋ฐœ ๊ด€๋ จ ์žฌ๋Šฅ์„ ๊ณต์œ ํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์ด ๋งŽ์•„! ๋ฉ˜ํ† ๋ง์„ ๋ฐ›๊ฑฐ๋‚˜, ํ”„๋กœ์ ํŠธ๋ฅผ ์˜๋ขฐํ•˜๊ฑฐ๋‚˜, ์ž์‹ ์˜ ์ง€์‹์„ ๋‚˜๋ˆŒ ์ˆ˜๋„ ์žˆ์ง€. ๐Ÿค

๐ŸŽฏ ์‹ค์ „ ํ”„๋กœ์ ํŠธ ์•„์ด๋””์–ด

์ด๋ก ์€ ์ถฉ๋ถ„ํžˆ ๋ฐฐ์› ์œผ๋‹ˆ, ์ด์ œ ์ง์ ‘ ๋งŒ๋“ค์–ด๋ณผ ์ฐจ๋ก€! ๋‚œ์ด๋„๋ณ„๋กœ ํ”„๋กœ์ ํŠธ ์•„์ด๋””์–ด๋ฅผ ์ •๋ฆฌํ•ด๋ดค์–ด. ๐Ÿš€

๐ŸŒฑ ์ดˆ๊ธ‰ ํ”„๋กœ์ ํŠธ

1. ๋‚ ์”จ ์•Œ๋ฆผ ๋ด‡ ๋งค์ผ ์•„์นจ ๋‚ ์”จ๋ฅผ ํ™•์ธํ•˜๊ณ , ์šฐ์‚ฐ์ด ํ•„์š”ํ•œ์ง€ ์•Œ๋ ค์ฃผ๋Š” ๋ด‡

์‚ฌ์šฉ ๋„๊ตฌ:
- ๋‚ ์”จ API
- ์Šค์ผ€์ค„๋Ÿฌ
- ๋ฉ”์‹œ์ง€ ์ „์†ก (์Šฌ๋ž™/ํ…”๋ ˆ๊ทธ๋žจ)

2. ๊ฐ„๋‹จํ•œ ๊ณ„์‚ฐ ์–ด์‹œ์Šคํ„ดํŠธ
์ž์—ฐ์–ด๋กœ ์ˆ˜ํ•™ ๋ฌธ์ œ๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ๊ณ„์‚ฐํ•ด์ฃผ๋Š” ๋ด‡

์‚ฌ์šฉ ๋„๊ตฌ:
- ๊ณ„์‚ฐ๊ธฐ
- ๋‹จ์œ„ ๋ณ€ํ™˜๊ธฐ
- ์ˆ˜์‹ ํŒŒ์„œ

๐ŸŒฟ ์ค‘๊ธ‰ ํ”„๋กœ์ ํŠธ

1. ๊ฐœ์ธ ๋น„์„œ ์—์ด์ „ํŠธ ์ผ์ • ๊ด€๋ฆฌ, ์ด๋ฉ”์ผ ์š”์•ฝ, ํ•  ์ผ ์ถ”์ ์„ ํ•ด์ฃผ๋Š” ์ข…ํ•ฉ ๋น„์„œ

์‚ฌ์šฉ ๋„๊ตฌ:
- Google Calendar API
- Gmail API
- Notion API
- ๋ฆฌ๋งˆ์ธ๋” ์‹œ์Šคํ…œ

2. ์‡ผํ•‘ ๋น„๊ต ์—์ด์ „ํŠธ
์—ฌ๋Ÿฌ ์‡ผํ•‘๋ชฐ์—์„œ ๊ฐ€๊ฒฉ์„ ๋น„๊ตํ•˜๊ณ  ์ตœ์ €๊ฐ€๋ฅผ ์ฐพ์•„์ฃผ๋Š” ์—์ด์ „ํŠธ

์‚ฌ์šฉ ๋„๊ตฌ:
- ์›น ์Šคํฌ๋ž˜ํ•‘
- ๊ฐ€๊ฒฉ ๋น„๊ต API
- ์•Œ๋ฆผ ์‹œ์Šคํ…œ
- ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค

๐ŸŒณ ๊ณ ๊ธ‰ ํ”„๋กœ์ ํŠธ

1. ์ฝ”๋“œ ๋ฆฌ๋ทฐ ์—์ด์ „ํŠธ GitHub PR์„ ์ž๋™์œผ๋กœ ๋ถ„์„ํ•˜๊ณ  ๋ฆฌ๋ทฐ ์ฝ”๋ฉ˜ํŠธ๋ฅผ ๋‹ฌ์•„์ฃผ๋Š” ์—์ด์ „ํŠธ

์‚ฌ์šฉ ๋„๊ตฌ:
- GitHub API
- ์ฝ”๋“œ ๋ถ„์„ ๋„๊ตฌ
- ์ •์  ๋ถ„์„๊ธฐ
- ํ…Œ์ŠคํŠธ ์‹คํ–‰๊ธฐ

2. ๋ฐ์ดํ„ฐ ๋ถ„์„ ํ”Œ๋žซํผ
์ž์—ฐ์–ด๋กœ ์งˆ๋ฌธํ•˜๋ฉด ๋ฐ์ดํ„ฐ๋ฅผ ๋ถ„์„ํ•˜๊ณ  ์‹œ๊ฐํ™”ํ•ด์ฃผ๋Š” ํ”Œ๋žซํผ

์‚ฌ์šฉ ๋„๊ตฌ:
- SQL ์ƒ์„ฑ๊ธฐ
- Pandas ์‹คํ–‰๊ธฐ
- ์ฐจํŠธ ์ƒ์„ฑ๊ธฐ
- ๋ฆฌํฌํŠธ ์ƒ์„ฑ๊ธฐ

3. Multi-Agent ํ˜‘์—… ์‹œ์Šคํ…œ
์—ฌ๋Ÿฌ ์ „๋ฌธ ์—์ด์ „ํŠธ๊ฐ€ ํ˜‘๋ ฅํ•ด์„œ ๋ณต์žกํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰

๊ตฌ์„ฑ ์š”์†Œ:
- ๋ฆฌ์„œ์น˜ ์—์ด์ „ํŠธ
- ์ž‘์„ฑ ์—์ด์ „ํŠธ
- ๊ฒ€์ฆ ์—์ด์ „ํŠธ
- ์กฐ์œจ ์—์ด์ „ํŠธ

๐Ÿ”ฎ ๋ฏธ๋ž˜ ์ „๋ง๊ณผ ํŠธ๋ Œ๋“œ

AI ์—์ด์ „ํŠธ ๊ธฐ์ˆ ์€ ์ •๋ง ๋น ๋ฅด๊ฒŒ ๋ฐœ์ „ํ•˜๊ณ  ์žˆ์–ด. ์•ž์œผ๋กœ ์–ด๋–ป๊ฒŒ ๋ ๊นŒ? ๐Ÿš€

๐Ÿ“ˆ ์ฃผ์š” ํŠธ๋ Œ๋“œ

1. ๋” ๋˜‘๋˜‘ํ•œ ๋„๊ตฌ ์„ ํƒ AI๊ฐ€ ์ƒํ™ฉ์— ๋งž๋Š” ๋„๊ตฌ๋ฅผ ๋” ์ •ํ™•ํ•˜๊ฒŒ ์„ ํƒํ•˜๊ฒŒ ๋  ๊ฑฐ์•ผ. ์ง€๊ธˆ๋„ ์ข‹์ง€๋งŒ, ์•ž์œผ๋กœ๋Š” ๊ฑฐ์˜ ์™„๋ฒฝํ•ด์งˆ ๊ฑฐ๋ผ๊ณ !

2. ์žฅ๊ธฐ ๊ธฐ์–ต ๋Šฅ๋ ฅ
ํ˜„์žฌ๋Š” ๋Œ€ํ™” ๊ธฐ๋ก์ด ์ œํ•œ์ ์ด์ง€๋งŒ, ์•ž์œผ๋กœ๋Š” ๋ช‡ ๋‹ฌ, ๋ช‡ ๋…„์น˜ ๊ธฐ์–ต์„ ์œ ์ง€ํ•˜๋ฉด์„œ ๋” ๊ฐœ์ธํ™”๋œ ์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•  ๊ฑฐ์•ผ. ๐Ÿง 

3. ์ž์œจ์„ฑ ์ฆ๊ฐ€
์‚ฌ๋žŒ์˜ ๊ฐœ์ž… ์—†์ด ๋ณต์žกํ•œ ์ž‘์—…์„ ์™„์ „ํžˆ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ์—์ด์ „ํŠธ๊ฐ€ ๋Š˜์–ด๋‚  ๊ฑฐ์•ผ. AutoGPT๊ฐ€ ์‹œ์ž‘์ผ ๋ฟ!

4. ๋ฉ€ํ‹ฐ๋ชจ๋‹ฌ ํ†ตํ•ฉ
ํ…์ŠคํŠธ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ด๋ฏธ์ง€, ์Œ์„ฑ, ๋น„๋””์˜ค๋ฅผ ๋ชจ๋‘ ์ดํ•ดํ•˜๊ณ  ์ƒ์„ฑํ•˜๋Š” ์—์ด์ „ํŠธ๊ฐ€ ํ‘œ์ค€์ด ๋  ๊ฑฐ์•ผ. ๐Ÿ“ธ๐ŸŽต๐ŸŽฌ

5. ์‚ฐ์—…๋ณ„ ํŠนํ™”
์˜๋ฃŒ, ๋ฒ•๋ฅ , ๊ธˆ์œต ๋“ฑ ๊ฐ ์‚ฐ์—…์— ํŠนํ™”๋œ ์ „๋ฌธ ์—์ด์ „ํŠธ๋“ค์ด ๋“ฑ์žฅํ•  ๊ฑฐ์•ผ. ์ผ๋ฐ˜ ์—์ด์ „ํŠธ๋ณด๋‹ค ํ›จ์”ฌ ์ •ํ™•ํ•˜๊ณ  ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ์ง€!

โšก ์ƒˆ๋กœ์šด ๊ธฐ์ˆ ๋“ค

๐Ÿ”ฅ ์ฃผ๋ชฉํ•  ๋งŒํ•œ ๊ธฐ์ˆ 

Function Calling 2.0
๋” ๋ณต์žกํ•œ ํŒŒ๋ผ๋ฏธํ„ฐ, ์ค‘์ฒฉ๋œ ํ•จ์ˆ˜ ํ˜ธ์ถœ, ์กฐ๊ฑด๋ถ€ ์‹คํ–‰ ๋“ฑ์ด ๊ฐ€๋Šฅํ•ด์งˆ ๊ฑฐ์•ผ.

Agent-to-Agent Communication
์—์ด์ „ํŠธ๋ผ๋ฆฌ ์ง์ ‘ ๋Œ€ํ™”ํ•˜๊ณ  ํ˜‘๋ ฅํ•˜๋Š” ํ”„๋กœํ† ์ฝœ์ด ํ‘œ์ค€ํ™”๋  ๊ฑฐ์•ผ.

Self-Improving Agents
์‚ฌ์šฉํ•˜๋ฉด์„œ ์Šค์Šค๋กœ ํ•™์Šตํ•˜๊ณ  ๊ฐœ์„ ๋˜๋Š” ์—์ด์ „ํŠธ. ๊ฐ•ํ™”ํ•™์Šต์˜ ์ง„ํ™”!

Verifiable Agents
์—์ด์ „ํŠธ์˜ ํ–‰๋™์„ ๊ฒ€์ฆํ•˜๊ณ  ์ถ”์ ํ•  ์ˆ˜ ์žˆ๋Š” ์‹œ์Šคํ…œ. ์‹ ๋ขฐ์„ฑ๊ณผ ์•ˆ์ „์„ฑ์ด ํ•ต์‹ฌ!

๐Ÿ’ผ ๋น„์ฆˆ๋‹ˆ์Šค ํ™œ์šฉ๊ณผ ์ˆ˜์ตํ™”

AI ์—์ด์ „ํŠธ๋กœ ์–ด๋–ป๊ฒŒ ๋ˆ์„ ๋ฒŒ ์ˆ˜ ์žˆ์„๊นŒ? ์‹ค์ œ ๋น„์ฆˆ๋‹ˆ์Šค ๋ชจ๋ธ๋“ค์„ ์‚ดํŽด๋ณด์ž! ๐Ÿ’ฐ

๐ŸŽฏ ์ˆ˜์ต ๋ชจ๋ธ

1. SaaS ๊ตฌ๋… ๋ชจ๋ธ ์›” ๊ตฌ๋…๋ฃŒ๋ฅผ ๋ฐ›๊ณ  ์—์ด์ „ํŠธ ์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•˜๋Š” ๋ฐฉ์‹. ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ด์ง€!

์˜ˆ์‹œ:
- ๊ธฐ๋ณธ: ์›” $9.99 (์ œํ•œ๋œ ๊ธฐ๋Šฅ)
- ํ”„๋กœ: ์›” $29.99 (๋ชจ๋“  ๊ธฐ๋Šฅ)
- ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ: ๋งž์ถค ๊ฐ€๊ฒฉ (์ „์šฉ ์ง€์›)

2. API ์ข…๋Ÿ‰์ œ
API ํ˜ธ์ถœ ํšŸ์ˆ˜๋‚˜ ์‚ฌ์šฉ๋Ÿ‰์— ๋”ฐ๋ผ ๊ณผ๊ธˆํ•˜๋Š” ๋ฐฉ์‹.

์˜ˆ์‹œ:
- 1,000 ์š”์ฒญ: $10
- 10,000 ์š”์ฒญ: $80 (20% ํ• ์ธ)
- 100,000 ์š”์ฒญ: $600 (40% ํ• ์ธ)

3. ํ”„๋ฆฌ๋ฏธ์—„ ๋„๊ตฌ ํŒ๋งค
๊ธฐ๋ณธ ์—์ด์ „ํŠธ๋Š” ๋ฌด๋ฃŒ, ํŠน์ˆ˜ ๋„๊ตฌ๋Š” ์œ ๋ฃŒ๋กœ ์ œ๊ณต.

4. ์ปจ์„คํŒ… & ์ปค์Šคํ„ฐ๋งˆ์ด์ง•
๊ธฐ์—… ๋งž์ถคํ˜• ์—์ด์ „ํŠธ ๊ฐœ๋ฐœ ์„œ๋น„์Šค. ๊ณ ์ˆ˜์ต!

๐Ÿ’ก ์žฌ๋Šฅ๋„ท์—์„œ AI ์—์ด์ „ํŠธ ์„œ๋น„์Šค ์ œ๊ณตํ•˜๊ธฐ

AI ์—์ด์ „ํŠธ ๊ฐœ๋ฐœ ๋Šฅ๋ ฅ์ด ์žˆ๋‹ค๋ฉด ์žฌ๋Šฅ๋„ท์—์„œ ๋‹ค์–‘ํ•œ ๋ฐฉ์‹์œผ๋กœ ์ˆ˜์ต์„ ์ฐฝ์ถœํ•  ์ˆ˜ ์žˆ์–ด:

โœ… AI ์ฑ—๋ด‡ ๊ฐœ๋ฐœ ์„œ๋น„์Šค
โœ… ์ž๋™ํ™” ์›Œํฌํ”Œ๋กœ์šฐ ๊ตฌ์ถ•
โœ… ๋งž์ถคํ˜• ์—์ด์ „ํŠธ ์ œ์ž‘
โœ… AI ๋„๊ตฌ ํ†ตํ•ฉ ์ปจ์„คํŒ…
โœ… ์—์ด์ „ํŠธ ์œ ์ง€๋ณด์ˆ˜ ์„œ๋น„์Šค

ํŠนํžˆ ์ค‘์†Œ๊ธฐ์—…์ด๋‚˜ ์Šคํƒ€ํŠธ์—…์€ AI ์ž๋™ํ™”์— ๋Œ€ํ•œ ์ˆ˜์š”๊ฐ€ ๋งŽ์€๋ฐ, ์ง์ ‘ ๊ฐœ๋ฐœํ•  ์ธ๋ ฅ์ด ๋ถ€์กฑํ•œ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์•„. ์ด๋Ÿฐ ์‹œ์žฅ์„ ๋…ธ๋ ค๋ณด๋Š” ๊ฒƒ๋„ ์ข‹์€ ์ „๋žต์ด์•ผ! ๐ŸŽฏ

๐ŸŽฌ ๋งˆ๋ฌด๋ฆฌํ•˜๋ฉฐ

์™€, ์—ฌ๊ธฐ๊นŒ์ง€ ์ฝ์—ˆ๋‹ค๋ฉด ์ •๋ง ๋Œ€๋‹จํ•ด! ๐Ÿ‘ AI ์—์ด์ „ํŠธ์˜ ๋„๊ตฌ์‚ฌ์šฉ์— ๋Œ€ํ•ด ์ •๋ง ๋งŽ์€ ๊ฑธ ๋ฐฐ์› ์„ ๊ฑฐ์•ผ.

ํ•ต์‹ฌ์„ ๋‹ค์‹œ ํ•œ๋ฒˆ ์ •๋ฆฌํ•˜๋ฉด:

๐ŸŽฏ ํ•ต์‹ฌ ์š”์•ฝ

โœ… ๋„๊ตฌ์‚ฌ์šฉ์€ AI๊ฐ€ ์™ธ๋ถ€ ๊ธฐ๋Šฅ์„ ํ˜ธ์ถœํ•ด์„œ ๋Šฅ๋ ฅ์„ ํ™•์žฅํ•˜๋Š” ๊ฒƒ
โœ… Function Calling์œผ๋กœ ๊ตฌ์กฐํ™”๋œ ๋„๊ตฌ ํ˜ธ์ถœ์ด ๊ฐ€๋Šฅ
โœ… ReAct ํŒจํ„ด์œผ๋กœ ์ถ”๋ก ๊ณผ ํ–‰๋™์„ ๋ฐ˜๋ณต
โœ… LangChain, OpenAI, Claude ๋“ฑ ๋‹ค์–‘ํ•œ ํ”„๋ ˆ์ž„์›Œํฌ ํ™œ์šฉ
โœ… ๋ณด์•ˆ, ์„ฑ๋Šฅ, ๋น„์šฉ์„ ํ•ญ์ƒ ๊ณ ๋ คํ•ด์•ผ ํ•จ
โœ… ์‹ค์ „ ํ”„๋กœ์ ํŠธ๋กœ ๊ฒฝํ—˜์„ ์Œ“๋Š” ๊ฒŒ ์ค‘์š”
โœ… ์ปค๋ฎค๋‹ˆํ‹ฐ์™€ ํ•จ๊ป˜ ์„ฑ์žฅํ•˜์ž!

AI ์—์ด์ „ํŠธ ๊ธฐ์ˆ ์€ ์ •๋ง ๋น ๋ฅด๊ฒŒ ๋ฐœ์ „ํ•˜๊ณ  ์žˆ์–ด. ์ง€๊ธˆ ์‹œ์ž‘ํ•˜๋ฉด ์ถฉ๋ถ„ํžˆ ๋”ฐ๋ผ์žก์„ ์ˆ˜ ์žˆ๊ณ , ์•ž์œผ๋กœ ์—„์ฒญ๋‚œ ๊ธฐํšŒ๊ฐ€ ์žˆ์„ ๊ฑฐ์•ผ! ๐Ÿš€

ํ˜น์‹œ ๋ง‰ํžˆ๋Š” ๋ถ€๋ถ„์ด ์žˆ๊ฑฐ๋‚˜, ๋” ๊นŠ์ด ๋ฐฐ์šฐ๊ณ  ์‹ถ๋‹ค๋ฉด ์ปค๋ฎค๋‹ˆํ‹ฐ์— ์งˆ๋ฌธํ•˜๊ฑฐ๋‚˜, ์žฌ๋Šฅ๋„ท์—์„œ ๋ฉ˜ํ† ๋ฅผ ์ฐพ์•„๋ณด๋Š” ๊ฒƒ๋„ ์ข‹์€ ๋ฐฉ๋ฒ•์ด์•ผ. ํ•จ๊ป˜ ์„ฑ์žฅํ•˜๋Š” ๊ฒŒ ์ œ์ผ ๋น ๋ฅด๊ฑฐ๋“ ! ๐Ÿ’ช

์ž, ์ด์ œ ์ง์ ‘ ๋งŒ๋“ค์–ด๋ณผ ์‹œ๊ฐ„์ด์•ผ! ๊ฐ„๋‹จํ•œ ํ”„๋กœ์ ํŠธ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด์„œ ์ ์  ๋ณต์žกํ•œ ์—์ด์ „ํŠธ๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž. ์‹คํŒจํ•ด๋„ ๊ดœ์ฐฎ์•„. ๊ทธ๊ฒŒ ๋ฐฐ์šฐ๋Š” ๊ณผ์ •์ด๋‹ˆ๊นŒ! ๐Ÿ˜Š

๐ŸŽ‰ Happy Coding! ๐Ÿค–โœจ

AI ์—์ด์ „ํŠธ์™€ ํ•จ๊ป˜ํ•˜๋Š” ๋ฉ‹์ง„ ๋ฏธ๋ž˜๋ฅผ ๋งŒ๋“ค์–ด๊ฐ€์ž! ๐Ÿš€

๐Ÿ“š ๋” ์•Œ์•„๋ณด๊ธฐ

์ด ๊ธ€์ด ๋„์›€์ด ๋˜์—ˆ๋‹ค๋ฉด, ์žฌ๋Šฅ๋„ท์—์„œ ๋” ๋งŽ์€ AI ๊ฐœ๋ฐœ ์ง€์‹์„ ํƒํ—˜ํ•ด๋ณด์„ธ์š”!
์—ฌ๋Ÿฌ๋ถ„์˜ ์žฌ๋Šฅ์„ ๋‚˜๋ˆ„๊ณ , ์ƒˆ๋กœ์šด ์žฌ๋Šฅ์„ ๋ฐฐ์šธ ์ˆ˜ ์žˆ๋Š” ๊ณณ์ž…๋‹ˆ๋‹ค. ๐ŸŒŸ

๋Œ“๊ธ€ ์ž‘์„ฑ

์ด ๊ธ€์— ๋Œ€ํ•œ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ƒ๊ฐ์„ ๋“ค๋ ค์ฃผ์„ธ์š”

๋Œ“๊ธ€ 0
๋Œ“๊ธ€์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘์ž…๋‹ˆ๋‹ค.

์•„์ง ๋Œ“๊ธ€์ด ์—†์Šต๋‹ˆ๋‹ค.