콘텐츠로 이동
ABTO 가이드
abto.app
무료로 시작

연동 가이드

Node.js JavaScript

서버의 프로바이더 요청을 ABTO Gateway로 보내고 사용자와 기능 컨텍스트를 전달하는 SDK입니다.

서버 SDK백엔드에서 실행 (Calling Key)

ABTO를 연결하면 AI 호출의 비용과 응답 속도를 확인하고, 대시보드에서 모델과 프롬프트를 바꿀 수 있습니다. OpenAI SDK를 직접 사용한다면 아래 순서로 첫 호출을 보내세요. LangChain을 사용한다면 LangChain 연결로 이동하세요. 이 페이지의 예제는 OpenAI Chat Completions용이며 Streaming과 Responses API는 지원하지 않습니다.

서버 프로젝트에서 ABTO SDK와 OpenAI SDK를 설치하세요.

Terminal window
npm install @abto-app/calling openai

ABTO Calling Key와 OpenAI 등 LLM 제공사 API 키를 서버 환경변수에 설정하세요. 브라우저용 Event Key 대신 Calling Key를 사용해야 합니다.

Terminal window
export ABTO_CALLING_KEY=your-abto-calling-key
export OPENAI_API_KEY=your-openai-api-key

featureId에는 호출을 구분할 기능 이름을 넣으세요. 예제에서는 review.summary를 사용합니다.

import type OpenAI from 'openai';
import { initAbto } from '@abto-app/calling';
const abto = initAbto({
abtoApiKey: process.env.ABTO_CALLING_KEY,
gatewayBaseURL: 'https://gateway.abto.app/v1',
providerKeys: {
openai: process.env.OPENAI_API_KEY,
},
environment: 'production',
});
const { data: completion, response } = await abto.withContext(
{
featureId: 'review.summary',
},
async () => {
const openai = await abto.openai<OpenAI>();
return openai.chat.completions
.create({
model: 'gpt-4.1-mini',
messages: [{ role: 'user', content: '이 상품의 리뷰 12개를 세 줄로 요약해 줘.' }],
})
.withResponse();
},
);
const requestId = response.headers.get('x-abto-request-id');
  • completion: 평소와 같은 OpenAI 응답 본문
  • response: Gateway가 발급한 x-abto-request-id를 읽는 자리

대시보드의 요청 목록에서 review.summary 호출을 찾아 응답, 비용, 응답 속도를 확인하세요. 호출이 실패하면 Calling Key와 OpenAI API 키가 서버에 설정되어 있는지 먼저 확인하세요. 응답은 왔지만 기록이 없다면 프로젝트, 조회 기간과 직접 폴백 실행 여부를 확인하세요. 연결이 완료되면 모델이나 프롬프트 바꿔 보기를 따라 라우팅도 확인해 보세요.

위 예제의 ABTO import 대신 다음 코드를 사용하세요. CommonJS 지원이 포함된 SDK가 필요합니다.

const { initAbto } = require('@abto-app/calling');

기본 LangChain에 ABTO를 연결하면 AI 호출을 기록하고 대시보드에서 모델과 프롬프트를 바꿀 수 있습니다. ChatOpenAI의 configuration에 ABTO 설정을 넣고, 호출할 때 기능 이름을 지정하면 됩니다.

기존 @langchain/openai 설치를 유지하고, 모델을 만드는 부분에 다음 설정을 추가하세요. 기존 configuration이 있다면 abto.openaiOptions(configuration)으로 전달합니다.

configuration: abto.openaiOptions(),

아래는 전체 연결 예제입니다. ABTO_CALLING_KEY와 OPENAI_API_KEY는 서버 환경변수로 설정합니다.

import { ChatOpenAI } from '@langchain/openai';
import { initAbto } from '@abto-app/calling';
const abto = initAbto({
abtoApiKey: process.env.ABTO_CALLING_KEY,
gatewayBaseURL: 'https://gateway.abto.app/v1',
providerKeys: { openai: process.env.OPENAI_API_KEY },
});
const model = new ChatOpenAI({
model: 'gpt-4.1-mini',
configuration: abto.openaiOptions(),
});
const reply = await abto.withContext(
{ featureId: 'review.summary' },
() => model.invoke('리뷰: 배송이 빨라요. 포장이 꼼꼼해요. 이 두 리뷰를 한 문장으로 요약해 줘.'),
);
console.log(reply.content);

기존 모델의 다른 옵션과 invoke(), 체인, 파서, 콜백은 그대로 사용하세요. 요청은 LangChain에서 ABTO Gateway를 거쳐 모델 제공사로 전달됩니다. 호출 후 대시보드의 요청 목록에서 review.summary 기록을 확인할 수 있습니다.

구매나 페이지 조회, 클릭과 같은 사용자 행동과 AI 호출을 연결하려면 브라우저 SDK의 getIdentity().deviceId를 서버로 전달하세요. withContext에 { featureId: 'review.summary', deviceId }를 넣으면 됩니다. 백그라운드 작업은 작업 데이터에 이 값을 함께 저장해 전달하세요.

이미 사용 중인 콜백과 추적 설정을 그대로 유지하세요. ABTO를 연결하기 위해 기존 추적 도구를 교체할 필요는 없습니다.

추적 도구에는 앱에서 보낸 요청이 기록됩니다. 대시보드에서 모델, 프롬프트, 파라미터를 바꿨다면 실제 실행 내용은 ABTO 요청 기록에서 확인하세요. 추적 도구에 표시되는 모델명은 사용하는 버전에 따라 다를 수 있습니다.

연동 전에 확인할 사항
  • 이 예제는 OpenAI Chat Completions용입니다. Streaming과 Responses API는 지원하지 않습니다.
  • @langchain/openai의 0.2.7과 1.5.13에서 연결을 확인했습니다. 다른 버전은 사용 중인 호출 방식과 호환성을 확인하세요.
  • @langchain/[email protected]과 [email protected]를 함께 쓴다면 요청마다 Langfuse 핸들러를 만드세요. 동시 요청이 하나의 핸들러를 공유하면 기록이 합쳐질 수 있습니다.
  • API 키와 ABTO 설정은 서버에만 두세요. ABTO Calling Key는 모델 설정에 노출하지 않지만, 직접 추가한 비밀정보까지 자동으로 숨기지는 않습니다.
  • 다른 라우터의 URL이나 인증 헤더를 그대로 전달하지 마세요. openaiOptions()는 요청 목적지를 ABTO로 바꾸며, 다른 라우터를 함께 거치는 기능은 제공하지 않습니다.
  • 고객 추적 헤더는 Gateway까지 유지됩니다. 제공사까지의 추적 연결이나 organization과 project 전달은 보장하지 않습니다.
  • 직접 폴백을 설정하면 Gateway 장애 시 OpenAI로 호출할 수 있습니다. 이때는 ABTO의 라우팅과 호출 기록이 적용되지 않습니다.
SDK 입력Gateway 헤더의미
abtoApiKeyAuthorization: Bearer …ABTO Calling Key
providerKeys.openaix-abto-key-openai직접 계약한 OpenAI provider key
providerKeys.geminix-abto-key-gemini직접 계약한 Gemini provider key
providerKeys.anthropicx-abto-key-anthropic직접 계약한 Anthropic provider key
providerKeys.deepseekx-abto-key-deepseek직접 계약한 DeepSeek provider key
providerKeys.kimix-abto-key-kimi직접 계약한 Kimi provider key
featureIdx-abto-feature-id기능 ID
nodeIdx-abto-node-id기능 안의 노드 (선택)
deviceIdx-abto-device-id사용자 기기 식별자 (선택)
traceIdx-abto-trace-id실행 ID (넣지 않으면 자동)

providerKeys의 성격과 취급:

  • Gateway에 키를 등록하는 설정이 아니라, 서버에 보관한 credential을 요청마다 헤더로 실어 보내는 입력
  • 요청 범위로만 전달. 호출 기록에는 미저장
  • 라우팅된 provider의 키가 없으면 Gateway가 그 요청을 거절
  • 문자열 대신 함수를 주면 요청마다 다시 평가. key rotation과 provider별 credential resolver에 사용

호출자가 넣은 헤더의 처리:

  • abto.openai()가 만든 client에서는 extra_headers로 x-abto-key-*를 덮어쓰지 마세요.
  • Calling SDK가 호출자의 Authorization, x-abto-key-*, x-abto-feature-id, x-abto-node-id, x-abto-device-id, x-abto-trace-id를 제거하고 initAbto의 신뢰된 설정과 context로 다시 구성합니다.
  • Calling SDK 없이 기존 OpenAI SDK를 직접 쓴다면 같은 헤더를 각 요청의 extra_headers에 직접 넣습니다. 직접 연결 예시를 참고하세요.

필드 이름은 SDK 안의 표기이고, 실제 요청에서는 헤더로 나갑니다.

  • featureId: 기능 ID(예: review.summary). x-abto-feature-id로 전송
  • nodeId: 기능 안에서 LLM을 부르는 지점(예: review.draft). 없으면 기능 ID가 노드 이름이 됨. x-abto-node-id로 전송
    • 예: withContext({ featureId: 'review.summary', nodeId: 'review.draft' }, ...)
    • 한 기능이 LLM을 여러 번 부르면 호출 지점마다 다른 값을 넣어, 라우팅에서 노드마다 에이전트 설정을 따로 고를 수 있음
    • 안쪽 withContext에서 바깥과 다른 featureId를 넣고 nodeId를 넣지 않으면, 바깥의 nodeId를 물려받지 않음
  • deviceId: x-abto-device-id로 전송. 제품 행동과 잇기 위해 브라우저가 만든 device_id(browserAbto.getIdentity().deviceId)를 백엔드로 받아 그대로 전달
    • 임의의 로그인 id를 넣으면 브라우저의 device_id와 달라 제품 행동과 사용자별 고정 배정이 연결되지 않음
  • traceId: 에이전트나 워크플로 실행 한 번이 만든 호출을 하나로 묶는 실행 ID. x-abto-trace-id로 전송
    • 넣지 않으면 가장 바깥 withContext가 새 실행 ID를 만들고, 안쪽 withContext는 그 값을 물려받음
    • 실행 하나를 통째로 withContext 하나로 감싸야 그 안의 모든 호출이 같은 실행으로 묶임. 호출마다 따로 감싸면 호출마다 실행이 나뉨
    • withContext 밖에서 나간 호출은 호출마다 새 실행 ID를 받음
    • context를 직접 넘길 때 traceId를 비우면 감싼 withContext의 값을 씀
    • 다른 서비스가 넘겨준 실행을 이어 갈 때만 가장 바깥 withContext에 그 값을 직접 넣음
    • 200자 이하의 출력 가능한 ASCII(영문, 숫자, 공백, 기호)만 받음. 비어 있거나 규칙을 벗어난 값은 Gateway가 오류 없이 무시함
    • 요청의 traceparent는 실행 ID로 쓰지 않음

식별자를 다루는 규칙:

  • 클라이언트가 보낸 deviceId, featureId는 애플리케이션의 기존 요청 스키마로 검증
  • Calling Key와 provider key는 클라이언트 요청에서 받지 않고 서버 환경 변수나 서버 전용 credential resolver에서만 읽기
  • abtoApiKey는 브라우저 번들, 정적 문서, URL에 넣지 않기

응답을 브라우저와 모바일 행동과 잇는 방법:

  • Gateway가 응답에 x-abto-request-id를 발급
  • 위 예제처럼 .withResponse()로 읽고, 백엔드 응답에 그대로 포함해 Browser 또는 Mobile SDK의 LLM trace에 연결

기존 추적 도구가 보낸 traceparent와 tracestate는 ABTO 호출과 직접 폴백에서도 유지됩니다. ABTO는 고객의 추적 ID를 덮어쓰지 않고 기능과 기기 정보를 별도로 추가합니다.

이 동작은 1.1.2부터 지원합니다. 추적 도구의 요청 헤더 설정은 유지하세요. ABTO가 추적 도구를 자동으로 설정하거나 제공사까지 추적을 연결하지는 않습니다.

실행 ID인 traceId는 traceparent로 바꾸지 않고 x-abto-trace-id로만 보냅니다.

  • 데이터 경로는 현재 OpenAI Chat Completions
  • user 메시지의 인라인 base64 이미지와 PDF 지원
  • Function tool calling 지원. tool 결과를 되돌려 보낼 때 tool_call_id는 응답의 message.tool_calls[].id를 그대로 사용(최상위 id가 아님)
  • Streaming, 원격 이미지 URL, audio 등 미지원 필드는 조용히 무시하지 않고 400으로 거절
  • 정확한 필드 목록은 Gateway Chat Completions 참고
const openai = await abto.openai({
clientOptions: { maxRetries: 2 },
});
  • 공식 OpenAI SDK의 maxRetries를 그대로 씁니다. ABTO는 이 값을 덮어쓰지 않습니다
  • 설정하지 않으면 공식 OpenAI SDK의 기본값을 그대로 사용
  • Calling SDK는 자체 재시도 횟수를 두지 않습니다
  • direct fallback에는 횟수 대신 재전송 여부 스위치 fallback.onTimeout 하나만 존재. 기본값은 꺼짐
  • baseURL과 apiKey는 신뢰된 라우팅을 위해 ABTO 설정이 우선하고, 그 밖의 공식 client option은 보존
  • clientOptions.fetch는 버려지지 않고 ABTO wrapper 아래의 실제 전송 구현으로 합성

ABTO 도입 이전에 쓰던 엔드포인트로 되돌아가는 비상 경로입니다. 그래서 목적지를 fallback.baseURL에 직접 지정해야 하며, 기본값은 없습니다. OpenAI에서 직접 키를 발급받아 공식 SDK를 쓰던 고객이라면 그 주소가 https://api.openai.com/v1입니다.

const abto = initAbto({
abtoApiKey: process.env.ABTO_CALLING_KEY,
providerKeys: { openai: process.env.OPENAI_API_KEY },
fallback: {
// ABTO를 붙이기 전 이 코드가 호출하던 주소를 그대로 적습니다.
baseURL: 'https://api.openai.com/v1',
timeoutMs: 30000,
onTimeout: false,
},
});

원본 Chat Completions body와 model을 그대로 그 주소로 보내며, Gateway의 provider/model 정책을 클라이언트에서 재현하지 않습니다.

현재 요청을 direct로 보내는 경우

  • ABTO에 요청이 닿지 못한 경우
  • 닿았어도 provider를 부르기 전에 거절된 경우

즉 provider가 실행되지 않은 것이 확실할 때만 전환합니다. 이중 실행과 이중 과금을 만들지 않습니다.

현재 요청을 폴백하지 않는 경우

  • timeout과 전송 여부가 모호한 disconnect. Gateway가 이미 provider를 실행했을 가능성
  • provider와 transport 오류, 결정적인 4xx와 429, caller abort, streaming 시작 이후
  • 이때 direct circuit도 열지 않으며, 공식 OpenAI SDK가 재시도하면 다시 Gateway를 호출

설정

  • baseURL: 필수. ABTO 이전에 쓰던 주소. OpenAI 요청 경로와 Authorization: Bearer를 받는 엔드포인트여야 합니다
    • 이 값을 적는 것이 폴백을 켜는 방법입니다. 별도의 활성 플래그는 없습니다
    • 목적지 없이 fallback: true만 주거나, OpenAI key 없이 목적지만 주면 initAbto가 오류를 던집니다
  • timeoutMs: 로컬 dispatcher 대기부터 Gateway 응답 헤더까지의 end-to-end 상한. direct 요청은 OpenAI client의 timeout을 유지
  • onTimeout: true: timeout 난 현재 요청까지 재전송. 중복 실행과 과금 위험을 감수하는 명시적 선택
  • fallback: false: 기능 전체 해제

경계

  • transport는 SDK attempt마다 Gateway 판단과 direct 전송을 각각 한 번만 수행
  • direct 호출은 Gateway policy, ABTO telemetry, request_id를 거치지 않음. model 은 그 엔드포인트가 지원하는 것으로 제한
  • OpenAI에 필요한 header만 전달하고 Cookie, proxy credential, 사용자 정의 Gateway header는 제거
  • direct 전환 뒤의 응답과 오류는 공식 OpenAI SDK로 그대로 반환하며 재시도 여부는 그 SDK 설정이 결정
  • Anthropic과 Gemini key는 Gateway 라우팅 후보일 뿐, 현재 SDK의 네이티브 direct fallback 대상이 아님