본문 바로가기
AI2024년 12월 18일8분 읽기

OpenAI Function Calling 실전 — AI에게 도구 사용 능력 부여

YS
김영삼
조회 150

Function Calling이란?

Function Calling은 LLM이 사용자 요청을 분석하여 적절한 함수(도구)를 선택하고, 필요한 인자를 JSON 형태로 생성하는 기능입니다. AI가 날씨 조회, DB 검색, 이메일 전송 등 외부 시스템과 상호작용할 수 있게 해주는 핵심 메커니즘입니다.

함수 정의와 호출 흐름

const OpenAI = require('openai');
const openai = new OpenAI();

const tools = [
  {
    type: "function",
    function: {
      name: "get_weather",
      description: "지정한 도시의 현재 날씨를 조회합니다",
      parameters: {
        type: "object",
        properties: {
          city: { type: "string", description: "도시명 (예: Seoul, Tokyo)" },
          unit: { type: "string", enum: ["celsius", "fahrenheit"], description: "온도 단위" }
        },
        required: ["city"]
      }
    }
  },
  {
    type: "function",
    function: {
      name: "search_products",
      description: "상품을 검색합니다",
      parameters: {
        type: "object",
        properties: {
          query: { type: "string", description: "검색어" },
          category: { type: "string", description: "카테고리" },
          max_price: { type: "number", description: "최대 가격" }
        },
        required: ["query"]
      }
    }
  },
  {
    type: "function",
    function: {
      name: "send_email",
      description: "이메일을 전송합니다",
      parameters: {
        type: "object",
        properties: {
          to: { type: "string", description: "수신자 이메일" },
          subject: { type: "string", description: "제목" },
          body: { type: "string", description: "본문" }
        },
        required: ["to", "subject", "body"]
      }
    }
  }
];

실제 함수 구현과 실행 루프

const functions = {
  get_weather: async ({ city, unit = "celsius" }) => {
    const data = await fetch(
      'https://api.weather.com/v1?city=' + city + '&unit=' + unit
    ).then(r => r.json());
    return JSON.stringify(data);
  },
  search_products: async ({ query, category, max_price }) => {
    const results = await db.products.findMany({
      where: { name: { contains: query }, category, price: { lte: max_price } },
      take: 5
    });
    return JSON.stringify(results);
  },
  send_email: async ({ to, subject, body }) => {
    await transporter.sendMail({ to, subject, text: body });
    return JSON.stringify({ success: true, message: "이메일 전송 완료" });
  }
};

async function runAgent(userMessage) {
  const messages = [
    { role: "system", content: "당신은 유능한 비서입니다. 필요 시 도구를 사용하세요." },
    { role: "user", content: userMessage }
  ];

  while (true) {
    const response = await openai.chat.completions.create({
      model: "gpt-4-turbo",
      messages,
      tools,
      tool_choice: "auto",
    });

    const msg = response.choices[0].message;
    messages.push(msg);

    if (!msg.tool_calls) return msg.content;

    const results = await Promise.all(
      msg.tool_calls.map(async (call) => {
        const fn = functions[call.function.name];
        const args = JSON.parse(call.function.arguments);
        const result = await fn(args);
        return {
          role: "tool",
          tool_call_id: call.id,
          content: result
        };
      })
    );
    messages.push(...results);
  }
}

const answer = await runAgent("서울 날씨 알려주고, 우산 검색해줘");
console.log(answer);

Parallel Function Calling

GPT-4 Turbo는 여러 함수를 동시에 호출할 수 있습니다. 위 예시에서 "서울 날씨 알려주고, 우산 검색해줘"라고 하면 get_weathersearch_products를 한 번의 응답에서 동시에 호출합니다.

핵심 포인트

  • 함수의 description을 명확하게 작성하면 모델이 적절한 함수를 더 정확하게 선택합니다
  • tool_choice: "auto"는 모델이 판단하고, "required"는 반드시 함수를 호출합니다
  • 함수 실행 결과는 role: "tool"로 반환하며, tool_call_id를 반드시 포함해야 합니다
  • 에러 발생 시에도 에러 메시지를 tool 응답으로 반환하면 모델이 적절히 처리합니다
  • 보안상 AI가 호출하는 함수에 반드시 권한 검증과 입력 검증을 적용하세요

댓글 0

아직 댓글이 없습니다.
Ctrl+Enter로 등록