SAP BTP Generative AI Hub 실전 가이드 — AI Core 배포부터 LLM API 통합까지

Moderator · 조회 3
SAP BTP Generative AI Hub 실전 가이드 슬라이드 1 SAP BTP Generative AI Hub 실전 가이드 슬라이드 2 SAP BTP Generative AI Hub 실전 가이드 슬라이드 3

1. 개요 및 학습 목표

이 튜토리얼은 SAP BTP의 Generative AI Hub를 처음부터 끝까지 직접 구성·호출해보는 실전 가이드입니다. 단순히 "AI Core가 뭔가요?" 수준에 그치지 않고, AI Core 서비스 인스턴스 생성 → 서비스 키 발급 → OAuth2 토큰 획득 → Deployment ID 기반 Chat Completions 호출 → SDK 통합 → CAP 앱 연동까지 한 번의 흐름으로 다룹니다. 본 가이드는 SAP BTP Cloud Foundry / Kyma 환경(2025~2026 기준), AI Core 서비스 플랜 extended 또는 standard를 기준으로 작성되었습니다.

학습 체크리스트

  • AI Core / AI Launchpad / Orchestration 3개 컴포넌트 역할 구분하기
  • BTP Cockpit에서 AI Core 인스턴스와 서비스 키 발급하기
  • XSUAA clientid / clientsecret으로 Bearer Token 받기
  • Deployment ID를 사용해 Chat Completions REST API 직접 호출하기
  • generative-ai-hub-sdk로 동일 호출을 한 줄로 단축하기
  • Orchestration 서비스 파이프라인(템플릿/마스킹/필터)을 이해하기
  • CAP 또는 Node.js 백엔드에서 안전하게 LLM 호출하기

2. 선수 지식

이 글은 다음 지식을 어느 정도 알고 있다고 가정합니다.

  • SAP BTP Cockpit의 서브어카운트 / 스페이스 개념과 엔터티 활성화(Entitlement) 절차
  • XSUAA 기반 OAuth2 Client Credentials Flow (선행 글: "BTP XSUAA OAuth2 토큰 인증" 참고)
  • Python 또는 Node.js로 REST API 호출 경험 (requests, axios)
  • LLM 기본 용어 — 프롬프트, 토큰, temperature, system/user 메시지
  • YAML 매니페스트와 Docker 이미지에 대한 기초 지식 (커스텀 모델 배포 시)

3. 환경 / 버전 / 준비물

실습에 사용한 환경입니다. 버전이 다르면 엔드포인트 경로(/v2/inference/deployments)가 일부 변경될 수 있으니, 발급받은 서비스 키의 serviceurls.AI_API_URL을 우선시하세요.

  • SAP BTP: Cloud Foundry 환경, 글로벌 어카운트(Trial 또는 Enterprise)
  • SAP AI Core: 서비스 플랜 extended (Generative AI Hub는 extended 플랜에서 활성화 권장)
  • SAP AI Launchpad: subscription 형태로 별도 구독
  • Python: 3.10 이상, requests, generative-ai-hub-sdk >= 3.x
  • Node.js: 18 LTS, @sap-ai-sdk/foundation-models 또는 axios
  • btp CLI 또는 cf CLI: 인스턴스/서비스 키 자동화 시

리전은 일반적으로 EU10, US10, AP11 등에서 AI Core가 제공되며, 사용 가능한 모델 목록은 리전마다 다릅니다. help.sap.com/docs/sap-ai-core에서 최신 가용성 매트릭스를 확인하는 것이 좋습니다.

4. 핵심 개념 — Generative AI Hub 아키텍처

Generative AI Hub는 단일 서비스가 아니라 3개의 BTP 컴포넌트가 협력하는 묶음입니다. 마치 식당으로 비유하면 다음과 같습니다.

  • SAP AI Core = 주방. 실제로 모델을 배포(deployment)하고 추론(inference)을 수행하는 런타임. Kubernetes 기반이며 OpenAI/Anthropic/Google 등 외부 LLM도 "프록시 배포" 형태로 노출합니다.
  • SAP AI Launchpad = 매니저용 대시보드. 시나리오(Scenario), 설정(Configuration), 배포(Deployment)를 GUI로 관리합니다. deploymentId를 여기서 확인합니다.
  • Orchestration 서비스 = 홀 서버. 프롬프트 템플릿, 데이터 마스킹(PII 제거), 콘텐츠 필터링, 그라운딩(RAG)을 하나의 호출로 묶어 실행하는 파이프라인입니다.

요청 흐름을 도식으로 보면 다음과 같습니다.

[Client App]
   │  1) POST /oauth/token  (XSUAA)
   ▼
[XSUAA] ── Bearer Token ──▶ [Client App]
   │
   │  2) POST /v2/inference/deployments/{id}/chat/completions
   ▼
[AI Core Runtime] ── routes to ──▶ [GPT-4o / Claude / Gemini / Mistral ...]
   │
   ▲  (선택) Orchestration 경로
[Orchestration] ── template + masking + filter ──▶ LLM

핵심은 두 가지입니다. 첫째, 모든 모델은 Deployment 단위로 추상화되어 동일한 REST 인터페이스(OpenAI 호환)로 호출됩니다. 둘째, 인증은 XSUAA Client Credentials로 통일되어 모델별 API 키를 앱이 직접 갖지 않습니다 — 즉 Anthropic 키 따로, OpenAI 키 따로 관리할 필요가 없습니다.

현재(2026년 기준) Generative AI Hub에서 일반적으로 제공되는 모델군은 OpenAI gpt-4o, gpt-4o-mini, Anthropic claude-3.5-sonnet, Google gemini-1.5-pro, Mistral, Meta llama-3, 그리고 Amazon Titan Embedding 등이 있으며, 신규 모델은 리전별로 단계적으로 추가됩니다.

5. 실전 코드 3단계

5-1단계 — 기본 예제: 토큰 발급 + Chat Completions REST 직접 호출

BTP Cockpit에서 AI Core 인스턴스를 만든 뒤 "Service Keys"에서 키를 생성하면 다음과 같은 JSON을 받습니다. 이 값을 환경변수로 옮기는 것이 첫걸음입니다.

{
  "clientid": "sb-xxxx!b1234|aicore!b540",
  "clientsecret": "abcd-efgh-...",
  "url": "https://your-subaccount.authentication.sap.hana.ondemand.com",
  "serviceurls": {
    "AI_API_URL": "https://api.ai.prod.eu-central-1.aws.ml.hana.ondemand.com"
  },
  "identityzone": "your-subaccount"
}

이 키를 사용해 Python으로 토큰을 받고, deployment_id를 통해 GPT-4o에게 메시지를 보내봅니다.

import os
import requests

CLIENT_ID     = os.environ["AICORE_CLIENT_ID"]
CLIENT_SECRET = os.environ["AICORE_CLIENT_SECRET"]
AUTH_URL      = os.environ["AICORE_AUTH_URL"]      # ...authentication.sap.hana.ondemand.com
API_BASE      = os.environ["AICORE_BASE_URL"]      # serviceurls.AI_API_URL
RESOURCE_GROUP = "default"
DEPLOYMENT_ID  = os.environ["AICORE_DEPLOYMENT_ID"]  # AI Launchpad에서 확인

# 1) OAuth2 Client Credentials 토큰 발급
token_res = requests.post(
    f"{AUTH_URL}/oauth/token",
    data={"grant_type": "client_credentials"},
    auth=(CLIENT_ID, CLIENT_SECRET),
    timeout=10,
)
token_res.raise_for_status()
access_token = token_res.json()["access_token"]

# 2) Chat Completions 호출 (OpenAI 호환 스키마)
url = f"{API_BASE}/v2/inference/deployments/{DEPLOYMENT_ID}/chat/completions?api-version=2024-08-01-preview"
headers = {
    "Authorization": f"Bearer {access_token}",
    "AI-Resource-Group": RESOURCE_GROUP,
    "Content-Type": "application/json",
}
body = {
    "messages": [
        {"role": "system", "content": "You are a concise SAP BTP assistant."},
        {"role": "user",   "content": "AI Core의 Deployment ID는 어디서 확인하나요?"}
    ],
    "max_tokens": 300,
    "temperature": 0.2,
}
res = requests.post(url, headers=headers, json=body, timeout=30)
res.raise_for_status()
print(res.json()["choices"][0]["message"]["content"])

핵심 포인트는 AI-Resource-Group 헤더입니다. AI Core는 멀티테넌시를 위해 리소스 그룹을 분리하므로, 운영/개발을 다른 그룹으로 두는 것이 일반적으로 권장됩니다.

5-2단계 — 실무 시나리오: SDK 사용 + 에러 핸들링 + 로깅

매번 토큰 갱신, 헤더 구성, 재시도를 직접 짜기는 번거롭습니다. SAP가 제공하는 generative-ai-hub-sdk를 사용하면 거의 OpenAI Python SDK처럼 호출할 수 있습니다.

import logging
import json
from gen_ai_hub.proxy.native.openai import chat
from gen_ai_hub.proxy.core.proxy_clients import get_proxy_client

logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
log = logging.getLogger("aihub")

# aicore_service_key.json 경로를 환경변수로 지정해두면 자동 로드됨
# export AICORE_SERVICE_KEY=/secrets/aicore_service_key.json
proxy_client = get_proxy_client("gen-ai-hub")

def ask_llm(prompt: str, model: str = "gpt-4o", retries: int = 2) -> str:
    last_err = None
    for attempt in range(1, retries + 2):
        try:
            response = chat.completions.create(
                model_name=model,
                messages=[
                    {"role": "system", "content": "You are an SAP BTP expert."},
                    {"role": "user",   "content": prompt},
                ],
                temperature=0.3,
                max_tokens=500,
            )
            usage = response.usage
            log.info("model=%s prompt_tokens=%s completion_tokens=%s",
                     model, usage.prompt_tokens, usage.completion_tokens)
            return response.choices[0].message.content
        except Exception as e:
            last_err = e
            log.warning("attempt %d failed: %s", attempt, e)
    raise RuntimeError(f"LLM 호출 실패: {last_err}")

if __name__ == "__main__":
    answer = ask_llm("CAP 서비스에서 AI Hub 호출 시 주의점 3가지를 알려줘.")
    print(answer)

실무에서는 토큰 사용량(usage)을 반드시 로깅해두어야 비용 관리를 할 수 있습니다. SDK는 내부적으로 토큰 캐시 + 자동 갱신을 처리하지만, 네트워크 오류는 호출자가 재시도해야 합니다.

5-3단계 — 프로덕션: Orchestration + CAP/Node.js 통합

Orchestration 서비스는 "프롬프트 템플릿 + 데이터 마스킹 + 콘텐츠 필터링 + 모델 호출"을 한 번의 요청으로 묶어줍니다. PII가 포함될 수 있는 사용자 입력을 처리할 때 특히 유용합니다.

// CAP / Node.js 서비스에서 Orchestration 호출
// package.json: "@sap-cloud-sdk/connectivity", "axios"
const axios = require("axios");
const xsenv = require("@sap/xsenv");

async function getToken(creds) {
  const { data } = await axios.post(
    `${creds.url}/oauth/token`,
    "grant_type=client_credentials",
    {
      auth: { username: creds.clientid, password: creds.clientsecret },
      headers: { "Content-Type": "application/x-www-form-urlencoded" },
      timeout: 10000,
    }
  );
  return data.access_token;
}

module.exports = cds.service.impl(async function () {
  const aicore = xsenv.getServices({ aicore: { tag: "aicore" } }).aicore;

  this.on("askInvoiceBot", async (req) => {
    const userQuestion = req.data.question;
    const token = await getToken(aicore);

    const url = `${aicore.serviceurls.AI_API_URL}/v2/inference/deployments/${process.env.ORCH_DEPLOYMENT_ID}/completion`;
    const payload = {
      orchestration_config: {
        module_configurations: {
          templating_module_config: {
            template: [
              { role: "system", content: "You are an invoice support agent." },
              { role: "user",   content: "{{?user_query}}" },
            ],
          },
          llm_module_config: {
            model_name: "gpt-4o",
            model_params: { max_tokens: 400, temperature: 0.2 },
          },
          filtering_module_config: {
            input:  { filters: [{ type: "azure_content_safety" }] },
            output: { filters: [{ type: "azure_content_safety" }] },
          },
          masking_module_config: {
            masking_providers: [
              { type: "sap_data_privacy_integration",
                method: "anonymization",
                entities: [{ type: "profile-email" }, { type: "profile-phone" }] },
            ],
          },
        },
      },
      input_params: { user_query: userQuestion },
    };

    try {
      const { data } = await axios.post(url, payload, {
        headers: {
          Authorization: `Bearer ${token}`,
          "AI-Resource-Group": "default",
          "Content-Type": "application/json",
        },
        timeout: 30000,
      });
      return data.orchestration_result.choices[0].message.content;
    } catch (e) {
      req.error(502, `AI Hub 호출 실패: ${e.response?.status || e.code}`);
    }
  });
});

프로덕션에서는 다음 4가지를 추가로 권장합니다.

  • 서비스 키를 코드에 두지 말 것 — BTP Credential Store 또는 환경 바인딩 사용
  • 요청별 timeout을 30~60초로 설정 (LLM은 응답이 느릴 수 있음)
  • Rate Limit 대비 — 큐잉 또는 백오프 (HTTP 429 처리)
  • 개인정보 마스킹은 Orchestration의 masking_module_config로 일원화

6. 흔한 실수 / 트러블슈팅

Q1. 401 Unauthorized가 계속 발생합니다.
A. 토큰 자체는 발급되는데 401이 나면 거의 AI-Resource-Group 헤더 누락 또는 잘못된 리소스 그룹입니다. AI Launchpad의 Workspaces에서 실제 그룹 ID를 확인하세요. 또한 토큰 만료(보통 12시간)도 확인 — SDK 미사용 시 캐싱한 토큰을 재사용하다 만료된 경우가 많습니다.

Q2. 404 Deployment not found가 납니다.
A. (1) Deployment가 RUNNING 상태인지, (2) deployment_id가 configuration_id와 헷갈리지 않았는지, (3) 호출하는 리전(AI_API_URL)이 Deployment가 존재하는 리전과 같은지 확인해야 합니다. 같은 BTP 어카운트라도 EU10과 US10 인스턴스는 별개입니다.

Q3. SDK에서 aicore_service_key를 못 찾는다고 합니다.
A. generative-ai-hub-sdk는 환경변수 AICORE_SERVICE_KEY (파일 경로) 또는 개별 변수 AICORE_AUTH_URL, AICORE_CLIENT_ID, AICORE_CLIENT_SECRET, AICORE_BASE_URL, AICORE_RESOURCE_GROUP을 읽습니다. CF 환경에서는 VCAP_SERVICES에서 자동 추출되도록 바인딩하는 것이 가장 깔끔합니다.

Q4. 응답이 갑자기 잘리거나 빈 문자열이 옵니다.
A. finish_reasonlength이면 max_tokens 부족입니다. content_filter이면 입력/출력이 콘텐츠 필터에 걸린 경우 — Orchestration의 필터 임계값을 조정하거나 사용자 입력 정제(sanitize) 단계를 추가하세요.

Q5. 비용이 예상보다 빠르게 소진됩니다.
A. usage.prompt_tokens를 로깅하지 않으면 잡기 어렵습니다. 시스템 프롬프트가 매 호출마다 길게 반복되는 경우가 흔하므로, 시스템 프롬프트는 짧게 유지하고 RAG 컨텍스트는 필요한 만큼만 주입하는 것이 일반적으로 권장됩니다.

7. 다음 단계 / 관련 주제

이 가이드를 마쳤다면 다음 주제로 확장해보세요.

  • Embedding + HANA Cloud Vector Engine으로 RAG 파이프라인 구축 — text-embedding-3-large + HANA REAL_VECTOR
  • Function Calling / Tool Use — AI Hub 모델로 OData 서비스 호출 자동화
  • Joule와의 연계 — SAP Joule가 내부적으로 AI Hub를 호출하는 구조 이해
  • Custom Model 배포 — Hugging Face 모델을 AI Core Workflow Template으로 배포
  • BTP API Management로 AI Hub 호출 게이트웨이화 — 쿼터·로깅·캐싱(이전 글 "BTP API Management 입문" 참고)

8. 참고 자료

본 글의 코드는 학습용 예제이며, 실제 프로덕션 적용 시에는 조직의 보안 정책(키 관리, 데이터 잔존 정책, 모델 사용 약관)을 별도로 검토하는 것이 권장됩니다.