저는 3개월 전 이커머스 플랫폼에서 AI 고객 서비스 챗봇을 개발할 때 큰壁にぶつ였습니다. 초기에는 OpenAI GPT-4로(function calling) 구현했지만, 비용 문제로 Claude와 Gemini로 교체를 검토했죠. 그런데 각 모델의 function calling 포맷이 완전히 달랐습니다. 이 경험을 계기로 어떤 AI 모델이든 동일한 코드로 동작하는 model-agnostic function calling 시스템을 구축했습니다. 이 글에서 그 방법을 상세히 공유하겠습니다.

왜 Model-Agnostic Function Calling인가?

현재 주요 AI 모델들은 function calling를 지원하지만, 구현 방식이 크게 다릅니다:

HolySheep AI를 사용하면 이러한 다양한 모델들을 단일 API 키로 접근하면서, 추상화 레이어를 통해 코드 변경 없이 모델을 전환할 수 있습니다. 현재 HolySheep AI에서 지원하는 모델별 가격은 다음과 같습니다:

핵심 구현 아키텍처

Model-agnostic function calling의 핵심은 세 가지 레이어로 분리하는 것입니다:

┌─────────────────────────────────────────────────────────┐
│                  Application Layer                       │
│         (Business Logic - 동일한 코드 유지)               │
├─────────────────────────────────────────────────────────┤
│              Function Registry Layer                      │
│      (함수 정의, 파라미터 검증, 응답 정규화)              │
├─────────────────────────────────────────────────────────┤
│               Provider Adapter Layer                      │
│    (OpenAI / Claude / Gemini / DeepSeek 호환)            │
└─────────────────────────────────────────────────────────┘

1단계: 범용 함수 레지스트리 정의

먼저 모든 모델에서 사용할 수 있는 범용 함수 스키마를 정의합니다:

// function-registry.ts
// HolySheep AI를 위한 범용 함수 정의 시스템

interface FunctionParameter {
  type: string;
  description: string;
  enum?: string[];
  required?: boolean;
  properties?: Record<string, FunctionParameter>;
}

interface FunctionDefinition {
  name: string;
  description: string;
  parameters: {
    type: string;
    properties: Record<string, FunctionParameter>;
    required: string[];
  };
}

class FunctionRegistry {
  private functions: Map<string, FunctionDefinition> = new Map();
  private handlers: Map<string, Function> = new Map();

  // 함수 등록
  register(
    name: string,
    description: string,
    parameters: FunctionDefinition['parameters'],
    handler: Function
  ): void {
    this.functions.set(name, { name, description, parameters });
    this.handlers.set(name, handler);
  }

  // OpenAI 포맷 변환
  toOpenAIFormat(): any[] {
    return Array.from(this.functions.values()).map(fn => ({
      type: 'function',
      function: {
        name: fn.name,
        description: fn.description,
        parameters: fn.parameters
      }
    }));
  }

  // Claude 포맷 변환
  toClaudeFormat(): any[] {
    return Array.from(this.functions.values()).map(fn => ({
      name: fn.name,
      description: fn.description,
      input_schema: fn.parameters
    }));
  }

  // Gemini 포맷 변환
  toGeminiFormat(): any[] {
    return Array.from(this.functions.values()).map(fn => ({
      functionDeclarations: [{
        name: fn.name,
        description: fn.description,
        parameters: fn.parameters
      }]
    }));
  }

  // 함수 실행
  async execute(functionName: string, arguments_: any): Promise<any> {
    const handler = this.handlers.get(functionName);
    if (!handler) {
      throw new Error(함수 ${functionName}을 찾을 수 없습니다);
    }
    return await handler(arguments_);
  }

  getFunctionNames(): string[] {
    return Array.from(this.functions.keys());
  }
}

export const registry = new FunctionRegistry();

2단계: HolySheep AI 프로바이더 어댑터

이제 HolySheep AI API를 통해 다양한 모델에 접근하는 어댑터를 구현합니다:

// holysheep-adapter.ts
// HolySheep AI Model-Agnostic API 어댑터

import { registry } from './function-registry';

type ModelProvider = 'openai' | 'anthropic' | 'gemini' | 'deepseek';

interface AIClientConfig {
  apiKey: string;
  model: string;
  provider: ModelProvider;
  baseUrl?: string;
}

interface ChatMessage {
  role: 'user' | 'assistant' | 'system';
  content: string;
}

interface FunctionCallResult {
  function_name: string;
  arguments: any;
  raw_response: any;
}

class HolySheepAIClient {
  private apiKey: string;
  private model: string;
  private provider: ModelProvider;
  private baseUrl = 'https://api.holysheep.ai/v1';
  private messages: ChatMessage[] = [];

  constructor(config: AIClientConfig) {
    this.apiKey = config.apiKey;
    this.model = config.model;
    this.provider = config.provider;
  }

  // 모델별 함수 포맷 변환
  private formatToolsForProvider(): any {
    switch (this.provider) {
      case 'openai':
        return registry.toOpenAIFormat();
      case 'anthropic':
        return registry.toClaudeFormat();
      case 'gemini':
        return registry.toGeminiFormat();
      case 'deepseek':
        return registry.toOpenAIFormat(); // DeepSeek는 OpenAI 호환
      default:
        throw new Error(지원하지 않는 프로바이더: ${this.provider});
    }
  }

  // 함수 호출 응답 파싱 (모델별 차이 처리)
  private parseFunctionCalls(response: any): FunctionCallResult[] {
    switch (this.provider) {
      case 'openai':
      case 'deepseek':
        // OpenAI/DeepSeek 포맷: tool_calls
        if (response.tool_calls) {
          return response.tool_calls.map((tool: any) => ({
            function_name: tool.function.name,
            arguments: JSON.parse(tool.function.arguments),
            raw_response: tool
          }));
        }
        break;
      
      case 'anthropic':
        // Claude 포맷: tool_use
        if (response.content) {
          const toolUses = response.content.filter(
            (c: any) => c.type === 'tool_use'
          );
          return toolUses.map((tool: any) => ({
            function_name: tool.name,