effidevFlutter · Cloudflare 엣지 · 클라우드 비용 최적화
한국어

Cloudflare Workers AI와 Llama 3.3/Qwen으로 서버리스 AI Function Calling 및 챗봇 구현하기

Cloudflare Workers AI와 Llama 3.3/Qwen 기반 서버리스 Function Calling 구현

단순히 텍스트 답변만 생성하는 단순 대화형 LLM 챗봇의 시대는 끝났다. 최신 AI 애플리케이션은 **Function Calling(도구 호출, Tool Calling)**을 통해 외부 API 호출, D1 데이터베이스 조회, 실시간 날씨/주식 데이터 조회 등 실질적인 작업을 수행하는 **자율 에이전트(Autonomous Agent)**로 발전하고 있다.

과거에는 이러한 Function Calling을 구현하려면 OpenAI API에 의존하거나 대형 GPU 서버를 직접 운용해야 했다. 하지만 Cloudflare Workers AI는 Llama 3.3 70B (@cf/meta/llama-3.3-70b-instruct-fp8-fast)와 Qwen 2.5 72B (@cf/qwen/qwen2.5-72b-instruct) 같은 최신 오픈 모델을 글로벌 에지 네트워크에서 서버리스 형태로 직접 서빙하며, 네이티브 Function Calling API를 완벽히 지원한다.

이 글에서는 Cloudflare Workers AI 환경에서 JSON Schema 기반 도구(Tools)를 정의하고, 도구 실행 결과를 LLM에 피드백하는 에이전트 루프(Agent Loop) 구현법, 구조화된 출력(Structured JSON Output) 검증, 그리고 비용 최적화 전략을 실전 코드로 소개한다.

핵심 요약

  • 서버리스 엣지 AI 추론: Cloudflare Workers AI는 GPU 인프라 관리 없이 env.AI.run() 단 한 줄로 Llama 3.3 및 Qwen 2.5 모델 추론을 엣지 PoP에서 실행한다.
  • Native Function Calling 지원: tools 파라미터를 통해 LLM이 JSON Schema 형태의 도구 명세를 이해하고, 실행할 도구 이름과 인자를 정형화된 JSON 형태로 반환한다.
  • Agent Loop 구현 패턴: 유저 요청 -> LLM 분석 -> tool_calls 감지 -> Worker에서 함수 실행(D1/외부 API) -> 실행 결과를 LLM 커뮤니케이션 컨텍스트에 추가 -> 최종 답변 생성 파이프라인.
  • 비용 효율성: 1,000 Neurons당 $0.011의 서버리스 비용과 일일 10,000 Neurons 무료 제공으로, OpenAI API 대비 최고 80% 이상 비용을 절감할 수 있다.

Cloudflare Workers AI와 오픈소스 Function Calling 아키텍처

Function Calling 파이프라인의 전체 데이터 흐름은 아래와 같은 에이전트 루프 순환 구조를 가진다.

[User Prompt] -> [Cloudflare Worker]
                      |
           (1) env.AI.run(tools)
                      v
            [Workers AI (Llama 3.3 / Qwen)]
                      |
       (2) Returns { tool_calls: [...] }
                      v
             [Cloudflare Worker]
                      |
    (3) Executes Tool (D1 Query / Weather API)
                      v
           (4) env.AI.run(messages + tool_result)
                      v
            [Workers AI Final Answer] -> [User Response]

Llama 3.3 70B와 Qwen 2.5 72B 모델은 수만 개 이상의 도구 연동 벤치마크(BFCL 등)에서 GPT-4o에 필적하는 정확도로 도구를 선택하고 매개변수(Arguments)를 추출해낸다.

Workers AI 지원 대표 LLM 모델 비교

모델 ID 파라미터 수 주요 특장점 추천 유스케이스
@cf/meta/llama-3.3-70b-instruct-fp8-fast 70B (FP8) 추론 속도 최적화, 뛰어난 추론 능력 범용 에이전트, 복잡한 Function Calling
@cf/qwen/qwen2.5-72b-instruct 72B 코딩, 구조화된 JSON 출력, 다국어 강점 데이터 추출, API 파싱 에이전트
@cf/meta/llama-3.1-8b-instruct 8B 극도의 저지연(Sub-100ms), 저비용 단순 도구 분류, 실시간 챗봇

Workers AI Function Calling 실전 TypeScript 구현

다음은 날씨 정보 조회 API와 D1 재고 조회 함수를 도구로 등록하고, 유저 요청에 따라 자율적으로 도구를 실행하는 완전한 Worker 예제다.

export interface Env {
  AI: Ai;
  DB: D1Database;
}

// 1. 도구(Tools) JSON Schema 정의
const tools = [
  {
    name: "get_weather",
    description: "지정한 도시의 현재 날씨 및 기온을 조회합니다.",
    parameters: {
      type: "object",
      properties: {
        location: {
          type: "string",
          description: "도시 이름 (예: Seoul, Tokyo, New York)",
        },
        unit: {
          type: "string",
          enum: ["celsius", "fahrenheit"],
          description: "온도 단위",
        },
      },
      required: ["location"],
    },
  },
  {
    name: "check_product_stock",
    description: "D1 데이터베이스에서 상품 SKU 코드로 현재 재고 수량을 조회합니다.",
    parameters: {
      type: "object",
      properties: {
        sku: {
          type: "string",
          description: "상품 고유 SKU 코드 (예: PROD-1029)",
        },
      },
      required: ["sku"],
    },
  },
];

// 2. 실제 Worker 실행 핸들러 (Agent Loop)
export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    if (request.method !== "POST") {
      return new Response("POST 요청만 지원합니다.", { status: 405 });
    }

    const { prompt } = await request.json<{ prompt: string }>();

    // 메시지 히스토리 초기화
    const messages: Array<any> = [
      {
        role: "system",
        content: "당신은 유용한 AI 어시스턴트입니다. 필요한 경우 제공된 도구를 활용해 정확한 정보를 조회하세요.",
      },
      { role: "user", content: prompt },
    ];

    // [Step 1] Workers AI 1차 호출 (Llama 3.3 70B + Tools)
    let response = await env.AI.run(
      "@cf/meta/llama-3.3-70b-instruct-fp8-fast",
      {
        messages,
        tools,
      }
    );

    // [Step 2] 모델이 Tool Call을 요청했는지 검증
    if (response.tool_calls && response.tool_calls.length > 0) {
      for (const toolCall of response.tool_calls) {
        const toolName = toolCall.name;
        const toolArgs = toolCall.arguments;

        console.log(`[Tool Call 감지] 함수: ${toolName}, 인자:`, toolArgs);

        let toolResult: any;

        // [Step 3] 개별 도구 실제 로직 실행
        if (toolName === "get_weather") {
          // 외부 날씨 API 연동 (Mocking 예시)
          toolResult = {
            location: toolArgs.location,
            temperature: 22.5,
            condition: "Sunny",
            unit: toolArgs.unit || "celsius",
          };
        } else if (toolName === "check_product_stock") {
          // D1 데이터베이스 실제 쿼리 실행
          const queryResult = await env.DB.prepare(
            "SELECT sku, name, stock_quantity FROM products WHERE sku = ?"
          )
            .bind(toolArgs.sku)
            .first();

          toolResult = queryResult || { error: "해당 SKU 상품을 찾을 수 없습니다." };
        }

        // [Step 4] 실행 결과를 Agent 메시지 히스토리에 추가
        messages.push({
          role: "assistant",
          tool_calls: [toolCall],
        });

        messages.push({
          role: "tool",
          name: toolName,
          content: JSON.stringify(toolResult),
        });
      }

      // [Step 5] 도구 결과 컨텍스트를 포함하여 Workers AI 2차 호출
      response = await env.AI.run(
        "@cf/meta/llama-3.3-70b-instruct-fp8-fast",
        {
          messages,
        }
      );
    }

    // [Step 6] 최종 자연어 답변 반환
    return Response.json({
      answer: response.response,
      executedMessages: messages,
    });
  },
};

구조화된 JSON 출력(Structured Output) 및 Zod 검증

Function Calling 외에도, 프론트엔드 UI 렌더링에 필요한 JSON 형태(예: Card UI, Table data)로만 답변을 받으려면 response_format 또는 Qwen 2.5 모델의 Structured JSON Mode를 사용한다.

// Qwen 2.5 모델 기반 JSON 출력을 Zod로 안전하게 파싱
import { z } from "zod";

const UserProfileSchema = z.object({
  name: z.string(),
  age: z.number(),
  skills: z.array(z.string()),
});

const response = await env.AI.run("@cf/qwen/qwen2.5-72b-instruct", {
  messages: [
    { role: "system", content: "응답은 반드시 유효한 JSON 형식이어야 합니다." },
    { role: "user", content: "이름: 김철수, 나이: 29, 기술: TypeScript, Cloudflare Workers" }
  ],
  response_format: { type: "json_object" }
});

try {
  const parsedData = UserProfileSchema.parse(JSON.parse(response.response));
  console.log("검증 성공:", parsedData);
} catch (e) {
  console.error("JSON 검증 실패", e);
}

Workers AI 운영 및 비용 최적화 팁

  1. Streaming + Tool Calling 분리: 도구가 실행되기 전에는 스트리밍을 끌 수 있지만, 최종 답변 생성 시에는 stream: true를 지정하여 Server-Sent Events(SSE)로 응답 지연(TTFT)을 최소화하자.
  2. 소형 모델을 활용한 1차 분류기: 유저 질문이 도구 호출이 필요한지 여부를 먼저 8B 모델(llama-3.1-8b)로 빠르게 판단하고, 복잡한 경우에만 70B 모델로 에스컬레이션하면 Neurons 비용을 70% 절감할 수 있다.
  3. 무료 쿼터 활용: Cloudflare Workers AI는 매일 10,000 Neurons 무료를 제공하므로 소규모 챗봇이나 MVP 테스트 비용이 $0이다.

결론

Cloudflare Workers AI는 Llama 3.3 및 Qwen 2.5 지원으로 서버리스 에지 환경에서 완전 무중단, 초저지연, 고성능 AI 에이전트를 구축할 수 있는 가장 강력한 솔루션이다.