์‹œ๋ฆฌ์ฆˆ: LLM Tool Calling ๋‚ด๋ถ€ ์›๋ฆฌ๋ถ€ํ„ฐ ์—์ด์ „ํŠธ ์ง์ ‘ ๊ตฌํ˜„๊นŒ์ง€

์ด ์‹œ๋ฆฌ์ฆˆ๋Š” ์‚ฌ์šฉ์ž์˜ ์ž์—ฐ์–ด ํ•œ ์ค„์ด tool ์‹คํ–‰์œผ๋กœ ๋ฐ”๋€Œ๋Š” ๋‚ด๋ถ€ ์ฒ˜๋ฆฌ ๊ณผ์ •์„ ๋‹จ๊ณ„๋ณ„๋กœ ํ•ด๋ถ€ํ•˜๊ณ , ์ตœ์ข…์ ์œผ๋กœ ์˜คํ”ˆ์†Œ์Šค ๋ชจ๋ธ + ์ž์ฒด middleware๋กœ ๋‚˜๋งŒ์˜ ์—์ด์ „ํŠธ๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ๊นŒ์ง€ ๋„๋‹ฌํ•˜๋Š” ๊ณผ์ •์ด๋‹ค.

ํŽธ๋‚ด์šฉํ•ต์‹ฌ
1ํŽธ์ „์ฒด ์กฐ๊ฐ๋„์ž์—ฐ์–ด โ†’ tool ์‹คํ–‰๊นŒ์ง€ 5๊ฐœ ๋ ˆ์ด์–ด์˜ ์กด์žฌ๋ฅผ ํ™•์ธ
2ํŽธChat TemplateJSON์ด ๋ชจ๋ธ์— ์ง์ ‘ ๋“ค์–ด๊ฐ€์ง€ ์•Š๋Š”๋‹ค
3ํŽธTokenization๋ชจ๋ธ์€ ํ…์ŠคํŠธ๋ฅผ ์ฝ์ง€ ๋ชปํ•œ๋‹ค - ํ† ํฐ ID์™€ control token
4ํŽธ๋ชจ๋ธ ์ถ”๋ก โ€tool์„ ์“ธ๊นŒ ๋ง๊นŒโ€ ํŒ๋‹จ๊ณผ constrained decoding
5ํŽธ (๋ณธ๋ฌธ)Tool ์‹คํ–‰tool_use๋ฅผ ๋ฐ›์€ ํด๋ผ์ด์–ธํŠธ์˜ ์‹คํ–‰ ๋ฃจํ”„
6ํŽธNative vs Non-native๊ฐ™์€ ๊ธฐ๋Šฅ, ๋‹ค๋ฅธ ๊ตฌ์กฐ โ†’ Middleware
7ํŽธMiddleware ๋งŒ๋“ค๊ธฐํ”„๋กฌํ”„ํŠธ ์กฐ๋ฆฝ + ์ถœ๋ ฅ ํŒŒ์‹ฑ + ์‹คํ–‰ ๋ฃจํ”„ ์ง์ ‘ ๊ตฌํ˜„
8ํŽธ์˜คํ”ˆ์†Œ์Šค ๋ชจ๋ธ ๋กœ์ปฌ ๊ตฌ์ถ•Ollama/vLLM์œผ๋กœ ๋กœ์ปฌ LLM ์„œ๋น™
9ํŽธ๋‚˜๋งŒ์˜ ์—์ด์ „ํŠธ๋ชจ๋ธ + Middleware = ์—์ด์ „ํŠธ ์™„์„ฑ

  • Tool ์‹คํ–‰์€ ๋ชจ๋ธ์ด ๋ฐ˜ํ™˜ํ•œ tool_use ์‘๋‹ต์„ ํด๋ผ์ด์–ธํŠธ(๊ฐœ๋ฐœ์ž์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜)๊ฐ€ ๋ฐ›์•„ ์‹ค์ œ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๊ณ , ๊ฒฐ๊ณผ๋ฅผ ๋‹ค์‹œ ๋ชจ๋ธ์— ์ „๋‹ฌํ•˜๋Š” ๊ณผ์ •
  • LLM์€ tool์„ ์ง์ ‘ ์‹คํ–‰ํ•˜์ง€ ์•Š์œผ๋ฉฐ, โ€œ์–ด๋–ค tool์„, ์–ด๋–ค ์ธ์ž๋กœ ํ˜ธ์ถœํ•ด์•ผ ํ•˜๋Š”์ง€โ€๋ฅผ ๊ธฐ์ˆ ํ•œ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋ฅผ ๋ฐ˜ํ™˜ํ•  ๋ฟ์ธ ๊ตฌ์กฐ์  ๋ถ„๋ฆฌ
  • ์ด ๊ณผ์ •์€ ํ•œ ๋ฒˆ์œผ๋กœ ๋๋‚˜์ง€ ์•Š๊ณ , ๋ชจ๋ธ์ด ์ถ”๊ฐ€ tool call์„ ์š”์ฒญํ•˜๋ฉด ๋ฐ˜๋ณต๋˜๋Š” ์‹คํ–‰ ๋ฃจํ”„

ํ•ด๋‹น ๊ฐœ๋…์ด ํ•„์š”ํ•œ ์ด์œ 

  • 4ํŽธ์—์„œ ๋ชจ๋ธ์ด tool_use: get_weather("Seoul")์„ ์ƒ์„ฑํ•˜๋Š” ๊ณผ์ •๊นŒ์ง€ ํ™•์ธํ–ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด ์‘๋‹ต์ด ์‚ฌ์šฉ์ž์˜ PC์— ๋„์ฐฉํ•œ ํ›„ ๋ˆ„๊ฐ€, ์–ด๋””์„œ, ์–ด๋–ป๊ฒŒ ์‹ค์ œ๋กœ ์‹คํ–‰ํ•˜๋Š”์ง€๋Š” ์•„์ง ๋‹ค๋ฃจ์ง€ ์•Š์•˜๋‹ค
  • Claude Code์—์„œ ํŒŒ์ผ์„ ์ฝ๊ฑฐ๋‚˜, MCP server์—์„œ tool์„ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด ๋ชจ๋‘ ์ด ๋‹จ๊ณ„์—์„œ ์ผ์–ด๋‚œ๋‹ค
  • ์ด ์‹คํ–‰ ๋ฃจํ”„๋ฅผ ์ดํ•ดํ•ด์•ผ 6ํŽธ์—์„œ โ€œ์ด ๋ ˆ์ด์–ด๊ฐ€ ์—†๋Š” ๋ชจ๋ธโ€์˜ ์˜๋ฏธ๋ฅผ ์ •ํ™•ํžˆ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ๋‹ค

AS-IS

sequenceDiagram
    autonumber
    box ๊ฐœ๋ฐœ์ž ์˜์—ญ
        participant App as ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜
    end
    box AI ์„œ๋น„์Šค ์˜์—ญ
        participant LLM as LLM
    end

    App->>LLM: "์„œ์šธ ๋‚ ์”จ ์•Œ๋ ค์ค˜"
    LLM-->>App: tool_use: get_weather("Seoul")
    Note over App: tool์„ ์‹คํ–‰ํ•ด์„œ tool_result๋ฅผ<br/>์–ด๋–ป๊ฒŒ ๋ชจ๋ธ์— ๋Œ๋ ค์ฃผ์ง€?

TO-BE

sequenceDiagram
    autonumber
    box ๊ฐœ๋ฐœ์ž ์˜์—ญ
        participant App as ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜
        participant Tool as tool ํ•จ์ˆ˜
    end
    box AI ์„œ๋น„์Šค ์˜์—ญ
        participant LLM as LLM
    end

    App->>LLM: "์„œ์šธ ๋‚ ์”จ ์•Œ๋ ค์ค˜"
    LLM-->>App: stop_reason: "tool_use"<br/>name: "get_weather", input: {location: "Seoul"}
    App->>App: tool ์ด๋ฆ„์œผ๋กœ ํ•จ์ˆ˜ ๋งคํ•‘
    App->>Tool: get_weather("Seoul") ์‹คํ–‰
    Tool-->>App: { temperature: "15ยฐC", condition: "๋ง‘์Œ" }
    App->>LLM: tool_result ์ „๋‹ฌ
    LLM-->>App: "์„œ์šธ์˜ ํ˜„์žฌ ๋‚ ์”จ๋Š” 15ยฐC์ด๋ฉฐ ๋ง‘์Šต๋‹ˆ๋‹ค"

tool_use ์‘๋‹ต์˜ ๊ตฌ์กฐ

4ํŽธ์—์„œ ๋ชจ๋ธ์ด ์ƒ์„ฑํ•œ tool_use ์‘๋‹ต์€ ์ด๋Ÿฐ ํ˜•ํƒœ๋‹ค:

{
  "id": "msg_01Aq9w938a90dw8q",
  "stop_reason": "tool_use",
  "content": [
    {
      "type": "text",
      "text": "์„œ์šธ์˜ ๋‚ ์”จ๋ฅผ ํ™•์ธํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค."
    },
    {
      "type": "tool_use",
      "id": "toolu_01A09q90qw90lq917835lq9",
      "name": "get_weather",
      "input": { "location": "Seoul", "unit": "celsius" }
    }
  ]
}

ํ•ต์‹ฌ ํ•„๋“œ 3๊ฐ€์ง€:

  • name: ์–ด๋–ค tool์„ ํ˜ธ์ถœํ• ์ง€
  • id: ์ด ํ˜ธ์ถœ์˜ ๊ณ ์œ  ์‹๋ณ„์ž (๊ฒฐ๊ณผ ๋ฐ˜ํ™˜ ์‹œ ๋งค์นญ์šฉ)
  • input: tool์— ์ „๋‹ฌํ•  ์ธ์ž

stop_reason: "tool_use"๊ฐ€ ๋ฐ˜ํ™˜๋˜์—ˆ๋‹ค๋Š” ๊ฒƒ์€, ๋ชจ๋ธ์ด โ€œ๋‚˜๋Š” ์—ฌ๊ธฐ์„œ ๋ฉˆ์ถ”๊ณ , ์ด tool์˜ ์‹คํ–‰ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๊ฒ ๋‹คโ€๋Š” ์˜๋ฏธ๋‹ค.

๋ชจ๋“  tool์ด ํด๋ผ์ด์–ธํŠธ์—์„œ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค

์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ๊ตฌ๋ถ„์ด ์žˆ๋‹ค. Claude API์—์„œ tool์€ ์‹คํ–‰ ์œ„์น˜์— ๋”ฐ๋ผ ๋‘ ์ข…๋ฅ˜๋กœ ๋‚˜๋‰œ๋‹ค:

Client ToolServer Tool
์‹คํ–‰ ์œ„์น˜๊ฐœ๋ฐœ์ž์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ (ํด๋ผ์ด์–ธํŠธ)Anthropic ์„œ๋ฒ„
๋ˆ„๊ฐ€ ๋งŒ๋“œ๋Š”๊ฐ€๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์ •์˜ + ์‹คํ–‰ ํ•จ์ˆ˜ ๊ตฌํ˜„Anthropic์ด ๋ฏธ๋ฆฌ ๊ตฌํ˜„
์˜ˆ์‹œget_weather, Read, Bash, MCP toolweb_search, web_fetch
๋™์ž‘ ๋ฐฉ์‹stop_reason: "tool_use" ๋ฐ˜ํ™˜ โ†’ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์‹คํ–‰ โ†’ tool_result ๋ฐ˜ํ™˜๋ชจ๋ธ์ด ํ˜ธ์ถœํ•˜๋ฉด ์„œ๋ฒ„๊ฐ€ ์ž๋™ ์‹คํ–‰, ๊ฒฐ๊ณผ๊ฐ€ ์‘๋‹ต์— ํฌํ•จ
๊ฐœ๋ฐœ์ž ์—ญํ• tool ์ •์˜ + ์‹คํ–‰ ํ•จ์ˆ˜ ๊ตฌํ˜„API ์š”์ฒญ์— tool ํƒ€์ž…๋งŒ ๋ช…์‹œ

์ฆ‰, Claude์—๊ฒŒ โ€œ์„œ์šธ ๋‚ ์”จ ๊ฒ€์ƒ‰ํ•ด์ค˜โ€๋ผ๊ณ  ํ•˜๋ฉด:

  • web_search๋Š” Anthropic ์„œ๋ฒ„์—์„œ ์‹คํ–‰๋œ๋‹ค. ๊ฐœ๋ฐœ์ž๊ฐ€ ๊ฒ€์ƒ‰ ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•  ํ•„์š” ์—†์ด, ์„œ๋ฒ„๊ฐ€ ์•Œ์•„์„œ ์‹คํ–‰ํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ์‘๋‹ต์— ํฌํ•จํ•œ๋‹ค.
  • get_weather ๊ฐ™์€ ์ปค์Šคํ…€ tool์€ ํด๋ผ์ด์–ธํŠธ์—์„œ ์‹คํ–‰๋œ๋‹ค. ๊ฐœ๋ฐœ์ž๊ฐ€ ์‹คํ–‰ ํ•จ์ˆ˜๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค.

Claude Code์—์„œ Read, Bash, Grep ๊ฐ™์€ tool์€? ์ด๊ฒƒ๋“ค์€ client tool์ด๋‹ค. Claude Code ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ด tool๋“ค์˜ ์‹คํ–‰ ํ•จ์ˆ˜๋ฅผ ๋ฏธ๋ฆฌ ๊ตฌํ˜„ํ•ด๋‘” ๊ฒƒ์ด๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ๋งŒ๋“  ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ, ์‹คํ–‰์€ ์‚ฌ์šฉ์ž์˜ PC(Claude Code ํ”„๋กœ์„ธ์Šค)์—์„œ ์ด๋ฃจ์–ด์ง„๋‹ค.

ํด๋ผ์ด์–ธํŠธ์˜ tool ์‹คํ–‰ ๋ฃจํ”„ (Client Tool)

tool_use ์‘๋‹ต์„ ๋ฐ›์€ ํด๋ผ์ด์–ธํŠธ๋Š” ๋‹ค์Œ ๊ณผ์ •์„ ์ˆ˜ํ–‰ํ•œ๋‹ค:

1๋‹จ๊ณ„: tool ์ด๋ฆ„์œผ๋กœ ํ•จ์ˆ˜ ๋งคํ•‘

// tool ์ด๋ฆ„ โ†’ ์‹ค์ œ ํ•จ์ˆ˜ ๋งคํ•‘
const tools: Record<string, (input: any) => Promise<string>> = {
  get_weather: async ({ location, unit }) => {
    const res = await fetch(`https://api.weather.com?city=${location}&unit=${unit}`);
    return JSON.stringify(await res.json());
  },
  get_time: async ({ timezone }) => {
    return new Date().toLocaleString("ko-KR", { timeZone: timezone });
  },
};

2๋‹จ๊ณ„: tool ์‹คํ–‰

// ์‘๋‹ต์—์„œ tool_use ๋ธ”๋ก ์ถ”์ถœ
const toolUseBlock = response.content.find((block) => block.type === "tool_use");
 
// ๋งคํ•‘๋œ ํ•จ์ˆ˜ ์‹คํ–‰
const toolFunction = tools[toolUseBlock.name];
const result = await toolFunction(toolUseBlock.input);

3๋‹จ๊ณ„: tool_result๋ฅผ ๋ชจ๋ธ์— ๋ฐ˜ํ™˜

// tool ์‹คํ–‰ ๊ฒฐ๊ณผ๋ฅผ ๋‹ค์‹œ ๋ชจ๋ธ์— ์ „๋‹ฌ
const followUp = await anthropic.messages.create({
  model: "claude-opus-4-6",
  max_tokens: 1024,
  tools: [/* ๊ฐ™์€ tool ์ •์˜ */],
  messages: [
    // ๊ธฐ์กด ๋Œ€ํ™” ์ด๋ ฅ
    { role: "user", content: "์„œ์šธ ๋‚ ์”จ ์•Œ๋ ค์ค˜" },
    // ๋ชจ๋ธ์˜ tool_use ์‘๋‹ต (๊ทธ๋Œ€๋กœ ํฌํ•จ)
    { role: "assistant", content: response.content },
    // tool ์‹คํ–‰ ๊ฒฐ๊ณผ
    {
      role: "user",
      content: [{
        type: "tool_result",
        tool_use_id: toolUseBlock.id,  // tool_use์˜ id์™€ ๋งค์นญ
        content: result,
      }],
    },
  ],
});
// followUp โ†’ "์„œ์šธ์˜ ํ˜„์žฌ ๋‚ ์”จ๋Š” 15ยฐC์ด๋ฉฐ ๋ง‘์Šต๋‹ˆ๋‹ค"

tool_use_id๋กœ ์–ด๋–ค tool call์— ๋Œ€ํ•œ ๊ฒฐ๊ณผ์ธ์ง€ ๋งค์นญํ•œ๋‹ค. 3ํŽธ์—์„œ ๋ณธ Mistral V3์˜ call_id์™€ ๋™์ผํ•œ ์—ญํ• ์ด๋‹ค.

๋ฉ€ํ‹ฐํ„ด Tool Calling

tool ์‹คํ–‰์€ ํ•œ ๋ฒˆ์œผ๋กœ ๋๋‚˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค. ๋ชจ๋ธ์ด ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์€ ํ›„ ์ถ”๊ฐ€ tool call์„ ์š”์ฒญํ•  ์ˆ˜ ์žˆ๋‹ค:

sequenceDiagram
    autonumber
    box ๊ฐœ๋ฐœ์ž ์˜์—ญ
        participant App as ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜
    end
    box AI ์„œ๋น„์Šค ์˜์—ญ
        participant LLM as LLM
    end

    App->>LLM: "์„œ์šธ๊ณผ ๋„์ฟ„ ๋‚ ์”จ ๋น„๊ตํ•ด์ค˜"
    LLM-->>App: tool_use: get_weather("Seoul")
    Note over App: get_weather("Seoul") ์‹คํ–‰
    App->>LLM: tool_result: "15ยฐC, ๋ง‘์Œ"
    LLM-->>App: tool_use: get_weather("Tokyo")
    Note over App: get_weather("Tokyo") ์‹คํ–‰
    App->>LLM: tool_result: "22ยฐC, ํ๋ฆผ"
    LLM-->>App: stop_reason: "end_turn"<br/>"์„œ์šธ์€ 15ยฐC, ๋„์ฟ„๋Š” 22ยฐC. ๋„์ฟ„๊ฐ€ 7๋„ ๋” ๋”ฐ๋œปํ•ฉ๋‹ˆ๋‹ค."

์ด ๋ฃจํ”„๊ฐ€ ๋ฐ˜๋ณต๋˜๋Š” ์กฐ๊ฑด:

  • stop_reason === "tool_use" โ†’ tool ์‹คํ–‰ ํ›„ ๊ฒฐ๊ณผ๋ฅผ ๋‹ค์‹œ ์ „๋‹ฌ
  • stop_reason === "end_turn" โ†’ ๋ชจ๋ธ์ด ์ตœ์ข… ์‘๋‹ต์„ ์™„๋ฃŒ, ๋ฃจํ”„ ์ข…๋ฃŒ

SDK๊ฐ€ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ์‹คํ–‰ ๋ฃจํ”„

์œ„์˜ ์ˆ˜๋™ ๋ฃจํ”„๋ฅผ ๋งค๋ฒˆ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์€ ๋ฒˆ๊ฑฐ๋กญ๋‹ค. Anthropic SDK์™€ Vercel AI SDK๋Š” ์ด ๊ณผ์ •์„ ์ž๋™ํ™”ํ•œ๋‹ค.

Anthropic SDK - Tool Runner (beta)

import { Anthropic } from "@anthropic-ai/sdk";
import { betaZodTool } from "@anthropic-ai/sdk/helpers/beta/zod";
import { z } from "zod";
 
const anthropic = new Anthropic();
 
// tool ์ •์˜ + ์‹คํ–‰ ํ•จ์ˆ˜๋ฅผ ํ•จ๊ป˜ ๋“ฑ๋ก
const getWeatherTool = betaZodTool({
  name: "get_weather",
  description: "Get the current weather in a given location",
  inputSchema: z.object({
    location: z.string().describe("City name"),
    unit: z.enum(["celsius", "fahrenheit"]).default("celsius"),
  }),
  run: async (input) => {
    // ์‹ค์ œ API ํ˜ธ์ถœ
    return JSON.stringify({ temperature: "15ยฐC", condition: "Sunny" });
  },
});
 
// toolRunner๊ฐ€ ์‹คํ–‰ ๋ฃจํ”„๋ฅผ ์ž๋™ ์ฒ˜๋ฆฌ
const runner = anthropic.beta.messages.toolRunner({
  model: "claude-opus-4-6",
  max_tokens: 1024,
  tools: [getWeatherTool],
  messages: [{ role: "user", content: "์„œ์šธ ๋‚ ์”จ ์•Œ๋ ค์ค˜" }],
});
 
for await (const message of runner) {
  console.log(message.content[0].text);
}

Vercel AI SDK - generateText

import { generateText, tool } from "ai";
import { anthropic } from "@ai-sdk/anthropic";
import { z } from "zod";
import { stepCountIs } from "ai";
 
const result = await generateText({
  model: anthropic("claude-opus-4-6"),
  tools: {
    weather: tool({
      description: "Get the weather in a location",
      parameters: z.object({ location: z.string() }),
      execute: async ({ location }) => ({
        location,
        temperature: 15,
        condition: "๋ง‘์Œ",
      }),
    }),
  },
  stopWhen: stepCountIs(5),  // ์ตœ๋Œ€ 5๋‹จ๊ณ„๊นŒ์ง€ ์ž๋™ ๋ฐ˜๋ณต
  prompt: "์„œ์šธ ๋‚ ์”จ ์•Œ๋ ค์ค˜",
});

๋‘ SDK ๋ชจ๋‘ ํ•ต์‹ฌ์€ ๊ฐ™๋‹ค: tool ์ •์˜์™€ ์‹คํ–‰ ํ•จ์ˆ˜๋ฅผ ํ•จ๊ป˜ ๋“ฑ๋กํ•˜๋ฉด, stop_reason: "tool_use" ๊ฐ์ง€ โ†’ ํ•จ์ˆ˜ ์‹คํ–‰ โ†’ ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜ โ†’ ์ถ”๊ฐ€ ํ˜ธ์ถœ ํ™•์ธ์˜ ๋ฃจํ”„๋ฅผ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค.

MCP Server์—์„œ์˜ Tool ์‹คํ–‰

Claude Code๋‚˜ Cursor ๊ฐ™์€ ํด๋ผ์ด์–ธํŠธ์—์„œ MCP server๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, tool ์‹คํ–‰์ด ํ•œ ๋‹จ๊ณ„ ๋” ์œ„์ž„๋œ๋‹ค:

sequenceDiagram
    autonumber
    box ํด๋ผ์ด์–ธํŠธ ์˜์—ญ
        participant Client as Claude Code
    end
    box MCP Server ์˜์—ญ
        participant MCP as MCP Server
        participant Tool as tool ํ•จ์ˆ˜
    end
    box AI ์„œ๋น„์Šค ์˜์—ญ
        participant LLM as LLM
    end

    Client->>LLM: tools ์ •์˜ + ์‚ฌ์šฉ์ž ์งˆ๋ฌธ
    LLM-->>Client: tool_use: get_weather("Seoul")
    Client->>MCP: call_tool("get_weather", {location: "Seoul"})
    MCP->>Tool: ์‹ค์ œ ํ•จ์ˆ˜ ์‹คํ–‰
    Tool-->>MCP: ๊ฒฐ๊ณผ
    MCP-->>Client: tool_result
    Client->>LLM: tool_result ์ „๋‹ฌ
    LLM-->>Client: ์ตœ์ข… ์‘๋‹ต

ํด๋ผ์ด์–ธํŠธ(Claude Code)๋Š” tool์„ ์ง์ ‘ ์‹คํ–‰ํ•˜์ง€ ์•Š๊ณ , MCP server์— ์‹คํ–‰์„ ์œ„์ž„ํ•œ๋‹ค. ์ด๊ฒƒ์ด MCP์˜ ํ•ต์‹ฌ ๊ฐ€์น˜๋‹ค: tool ์ •์˜์™€ ์‹คํ–‰์„ ์™ธ๋ถ€ ์„œ๋ฒ„๋กœ ๋ถ„๋ฆฌํ•˜์—ฌ, ํด๋ผ์ด์–ธํŠธ๋Š” ํ”„๋กœํ† ์ฝœ๋งŒ ์•Œ๋ฉด ๋œ๋‹ค.

๋‹ค์Œ ํŽธ: ์ด ๋ชจ๋“  ๋ ˆ์ด์–ด๊ฐ€ ํ•ญ์ƒ ์žˆ๋Š” ๊ฑด๊ฐ€?

1~5ํŽธ์— ๊ฑธ์ณ ์ž์—ฐ์–ด โ†’ Chat Template โ†’ Tokenization โ†’ ๋ชจ๋ธ ์ถ”๋ก  โ†’ Tool ์‹คํ–‰์˜ ์ „์ฒด ํŒŒ์ดํ”„๋ผ์ธ์„ ํ™•์ธํ–ˆ๋‹ค. Claude, GPT ๊ฐ™์€ ์ƒ์šฉ ๋ชจ๋ธ API๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด ๋ชจ๋“  ๋ ˆ์ด์–ด๊ฐ€ ๋‚ด์žฅ๋˜์–ด ์žˆ๋‹ค.

ํ•˜์ง€๋งŒ ์˜คํ”ˆ์†Œ์Šค ๋ชจ๋ธ(Llama, Gemma ๋“ฑ)์„ ๋กœ์ปฌ์—์„œ ์‹คํ–‰ํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ? ์ด ๋ ˆ์ด์–ด๋“ค์ด ์ „๋ถ€ ๋˜๋Š” ์ผ๋ถ€ ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋Ÿฌ๋ฉด tool calling์„ ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„ํ• ๊นŒ?

๋‹ค์Œ ํŽธ์—์„œ Native tool calling ๋ชจ๋ธ๊ณผ Non-native ๋ชจ๋ธ์˜ ๊ตฌ์กฐ์  ์ฐจ์ด๋ฅผ ๋น„๊ตํ•œ๋‹ค.

์ฐธ๊ณ  ๋ฌธ์„œ