SAP BTP Generative AI Hub 실전 가이드 — AI Core 배포부터 LLM API 통합까지
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_reason이 length이면 max_tokens 부족입니다. content_filter이면 입력/출력이 콘텐츠 필터에 걸린 경우 — Orchestration의 필터 임계값을 조정하거나 사용자 입력 정제(sanitize) 단계를 추가하세요.
Q5. 비용이 예상보다 빠르게 소진됩니다.
A. usage.prompt_tokens를 로깅하지 않으면 잡기 어렵습니다. 시스템 프롬프트가 매 호출마다 길게 반복되는 경우가 흔하므로, 시스템 프롬프트는 짧게 유지하고 RAG 컨텍스트는 필요한 만큼만 주입하는 것이 일반적으로 권장됩니다.
7. 다음 단계 / 관련 주제
이 가이드를 마쳤다면 다음 주제로 확장해보세요.
- Embedding + HANA Cloud Vector Engine으로 RAG 파이프라인 구축 —
text-embedding-3-large+ HANAREAL_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. 참고 자료
- SAP AI Core 공식 문서 허브
- What is SAP AI Core — Service Guide
- Generative AI Hub in SAP AI Launchpad
- Orchestration 서비스 가이드 (help.sap.com)
- SAP Developers — AI Core Get Started Basics
- GitHub: SAP-samples/ai-core-samples
- PyPI: generative-ai-hub-sdk
- GitHub: SAP/ai-sdk-js (Node.js SDK)
본 글의 코드는 학습용 예제이며, 실제 프로덕션 적용 시에는 조직의 보안 정책(키 관리, 데이터 잔존 정책, 모델 사용 약관)을 별도로 검토하는 것이 권장됩니다.