콘텐츠로 이동

Apple 단축어(Shortcuts) 연동

macOS, iPhone, iPad의 Apple 단축어(Shortcuts) 앱은 내장된 URL 내용 가져오기(Get Contents of URL) 동작을 사용하여 Backend.AI GO의 로컬 추론 API를 직접 호출할 수 있습니다. 이를 활용하면 어떤 앱에서든 선택한 텍스트를 번역하고, 클립보드나 공유 시트(Share Sheet)의 긴 글을 요약하며, 메시지 답장 초안을 작성하는 시스템 전반의 자동화 워크플로를 내 기기에서 실행되는 로컬 모델로 구축할 수 있습니다.

연동 방식 개요

Backend.AI GO는 사용하는 플랫폼과 워크플로에 따라 Apple 단축어와 연동하는 네 가지 방법을 제공합니다.

연동 방식 적합한 용도 지원 플랫폼 작동 원리
관리 REST API (/api/v1/inference/chat/completions) 단축어의 HTTP 요청 동작 (URL 내용 가져오기) macOS, iPhone, iPad 관리 API 추론 프록시(기본 포트 8001)로 OpenAI 호환 JSON 요청을 보냅니다. 별도의 라우터 설정 없이 localhost에서 바로 작동합니다.
Continuum Router API (/v1/chat/completions) 다중 모델 라우팅 및 OpenAI SDK 클라이언트 macOS, iPhone, iPad 설정 > API 서버에서 TCP 서버 활성화를 켠 뒤 Continuum Router TCP 서버(기본 포트 39080)로 요청을 보냅니다.
aigo CLI (aigo chat, aigo translate) 셸 스크립트 기반 단축어 (셸 스크립트 실행) macOS 전용 JSON 페이로드를 직접 구성하지 않고 macOS 단축어에서 번들된 aigo 명령줄 도구를 호출합니다.
URL 스킴 (aigo://) Backend.AI GO 실행 또는 설정 화면 딥링크 호출 macOS Backend.AI GO 데스크톱 앱을 열거나 노드 연결 및 엔터프라이즈 등록 대화상자(aigo://enroll?...)를 미리 채웁니다. 단축어로 추론 응답 텍스트를 반환하지는 않습니다.

Mac과 iPhone 및 iPad에서 모두 동작하는 단축어를 만들 때는 관리 REST API(POST /api/v1/inference/chat/completions)와 URL 내용 가져오기 동작을 사용하는 것이 가장 편리합니다.

사전 준비 및 설정

단축어를 만들기 전에 Backend.AI GO에서 다음 사항을 확인하세요.

  1. 모델 로드: Backend.AI GO의 모델(Models) 페이지에서 모델(예: Qwen 또는 Llama Instruct 모델)을 다운로드하고 실행(Run)을 클릭하여 추론 서버를 활성화합니다. 모델 카드에 표시된 정확한 모델 ID를 확인해 둡니다.
  2. 관리 API 상태 확인: 설정 > API 서버 > 관리 API를 엽니다. 관리 API는 기본적으로 http://127.0.0.1:8001에서 실행됩니다.
  3. 인증 설정 확인:

    • 같은 Mac에서 실행 (127.0.0.1): API 키 필요(Require API key)가 꺼져 있는 기본 상태에서는 인증 헤더 없이 http://127.0.0.1:8001/api/v1/inference/chat/completions를 호출할 수 있습니다.
    • API 키 활성화 또는 외부 기기 접속: API 키 필요가 켜져 있거나 다른 기기에서 접속할 때는 설정 > API 서버 > 액세스 키에서 Inference Write 및 Inference Read 권한(scope)을 가진 키를 생성한 뒤, 요청 헤더에 X-API-Key(또는 Authorization: Bearer <발급받은-키>)로 전달합니다.
  4. 비스트리밍(Non-streaming) 요청 사용: Apple 단축어의 URL 내용 가져오기 동작은 단일 HTTP 응답 본문이 완료될 때까지 기다리며, SSE(Server-Sent Events) 토큰 스트림을 파싱하지 못합니다. 요청 JSON에서 항상 "stream": false로 설정하거나 "stream" 필드를 생략하세요(기본값 false).

관리 API 포트와 Continuum Router 포트 비교

관리 API는 기본 포트 8001에서 수신하며 POST /api/v1/inference/chat/completions 경로로 추론 프록시를 제공합니다. 포트 39080의 Continuum Router(POST /v1/chat/completions)를 직접 호출하려면 먼저 설정 > API 서버에서 TCP 서버 활성화를 켜세요. 두 엔드포인트 모두 동일한 OpenAI 채팅 완성 JSON 형식을 받습니다.

curl로 API 테스트하기

단축어 앱에서 동작을 조립하기 전에 터미널에서 curl로 엔드포인트와 모델 이름을 먼저 테스트해 보세요.

1. 서버 상태 및 로드된 모델 확인

관리 API에 접근할 수 있는지, 그리고 실행 중인 모델이 목록에 나타나는지 확인합니다.

# 관리 API 상태 확인
curl http://127.0.0.1:8001/api/v1/health

# 추론 프록시를 통해 사용 가능한 모델 목록 조회
curl http://127.0.0.1:8001/api/v1/inference/models

API 키 필요 옵션이 켜져 있다면 각 명령에 -H "X-API-Key: YOUR_ACCESS_KEY"를 추가합니다.

2. 기본 채팅 완성 요청 보내기

curl http://127.0.0.1:8001/api/v1/inference/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen2.5-7b-instruct",
    "messages": [
      {"role": "user", "content": "한국어로 인사를 건네 주세요."}
    ],
    "stream": false
  }'

3. 시스템 프롬프트 및 생성 파라미터 테스트

system 메시지, temperature, max_tokens를 함께 지정하여 응답의 길이와 톤을 제어할 수 있습니다.

curl http://127.0.0.1:8001/api/v1/inference/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen2.5-7b-instruct",
    "messages": [
      {
        "role": "system",
        "content": "You are a concise translator. Translate the user text into English and return only the translation."
      },
      {
        "role": "user",
        "content": "로컬 LLM을 사용하면 개인정보를 안전하게 보호할 수 있습니다."
      }
    ],
    "temperature": 0.2,
    "max_tokens": 256,
    "stream": false
  }'

응답 JSON 예시:

{
  "id": "chatcmpl-8f3a9b2c",
  "object": "chat.completion",
  "created": 1710000000,
  "model": "qwen2.5-7b-instruct",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Using a local LLM keeps your personal information safe."
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 38,
    "completion_tokens": 12,
    "total_tokens": 50
  }
}

아래의 모든 Apple 단축어 예제에서는 이 응답 구조의 choices -> 첫 번째 항목 -> message -> content 경로에서 모델의 답변을 추출합니다.

단계별 단축어 제작 예제

예제 1: 선택한 텍스트 번역하기

macOS 앱에서 선택한 텍스트(빠른 동작 / 서비스 메뉴)나 iOS 공유 시트(Share Sheet)로 전달한 텍스트를 받아 로컬 LLM으로 번역한 뒤 결과를 표시하거나 클립보드에 복사하는 단축어입니다.

동작 구성 순서

  1. 새 단축어를 만들고 이름을 로컬 AI로 번역으로 지정합니다.
  2. 입력 방식을 설정합니다.

    • macOS: 단축어 세부 정보(i) 아이콘을 클릭한 뒤 빠른 동작으로 사용(Use as Quick Action)과 서비스 메뉴(Services Menu)를 체크하고, 입력 유형을 텍스트(Text)로 지정합니다(입력이 없는 경우: 텍스트 요청).
    • iPhone / iPad: 공유 시트에서 보기(Show in Share Sheet)를 켜고 입력 유형으로 텍스트(Text)를 선택합니다.
  3. URL 내용 가져오기(Get Contents of URL) 동작을 추가하고 다음과 같이 설정합니다.

항목 설정 값
URL http://127.0.0.1:8001/api/v1/inference/chat/completions
방법(Method) POST
헤더(Headers) Content-Type: application/json
X-API-Key: YOUR_ACCESS_KEY (API 키 인증을 사용하는 경우에만 추가)
요청 본문(Request Body) JSON
  1. URL 내용 가져오기의 JSON 본문에 다음 키를 추가합니다(입력 텍스트 이스케이프 관련 팁은 아래 입력 텍스트 안전하게 처리하기를 참고하세요).

    • model (텍스트): qwen2.5-7b-instruct (실제 로드한 모델 ID로 변경)
    • temperature (숫자): 0.2
    • max_tokens (숫자): 1024
    • stream (불리언): false
    • messages (배열, 딕셔너리 2개 포함):

      • 항목 1 (딕셔너리): role = system, content = You are a professional translator. Translate the user's text into Korean. Output only the translated text without explanations.
      • 항목 2 (딕셔너리): role = user, content = 단축어 입력(Shortcut Input) 변수

동일한 JSON 페이로드 구조는 다음과 같습니다.

{
  "model": "qwen2.5-7b-instruct",
  "messages": [
    {
      "role": "system",
      "content": "You are a professional translator. Translate the user's text into Korean. Output only the translated text without explanations."
    },
    {
      "role": "user",
      "content": "<단축어 입력>"
    }
  ],
  "temperature": 0.2,
  "max_tokens": 1024,
  "stream": false
}
  1. URL 내용 가져오기 바로 아래에 응답 파싱을 위한 네 개의 동작을 순서대로 추가합니다.

    1. 사전 값 가져오기(Get Dictionary Value): URL 내용에서 choices의 값 가져오기
    2. 목록에서 항목 가져오기(Get Item from List): 사전 값에서 첫 번째 항목(First Item) 가져오기
    3. 사전 값 가져오기(Get Dictionary Value): 목록의 항목에서 message의 값 가져오기
    4. 사전 값 가져오기(Get Dictionary Value): 사전 값에서 content의 값 가져오기
  2. 마지막 사전 값을 받는 클립보드에 복사(Copy to Clipboard)와 결과 보기(Show Result) 동작을 추가하여 번역 결과를 즉시 확인하고 붙여넣을 수 있게 합니다.


예제 2: 메시지 또는 클립보드 요약하기

클립보드나 공유 시트에서 긴 텍스트를 읽어 핵심 요점을 글머리 기호로 요약한 뒤 화면에 표시하는 단축어입니다.

동작 구성 순서

  1. 새 단축어를 만들고 이름을 클립보드 요약으로 지정합니다.
  2. 클립보드 가져오기(Get Clipboard) 동작을 추가합니다(또는 공유 시트에서 텍스트 입력을 받도록 설정합니다).
  3. URL 내용 가져오기(Get Contents of URL) 동작을 추가하고 다음과 같이 구성합니다.

    • URL: http://127.0.0.1:8001/api/v1/inference/chat/completions
    • 방법(Method): POST
    • 헤더(Headers): Content-Type: application/json
    • 요청 본문(Request Body): JSON

동일한 JSON 페이로드 구조는 다음과 같습니다.

{
  "model": "qwen2.5-7b-instruct",
  "messages": [
    {
      "role": "system",
      "content": "다음 텍스트의 핵심 사실과 실행 항목을 중심으로 한국어 글머리 기호 3~5개로 간결하게 요약하세요."
    },
    {
      "role": "user",
      "content": "<클립보드>"
    }
  ],
  "temperature": 0.3,
  "max_tokens": 512,
  "stream": false
}
  1. 앞선 예제와 동일한 네 단계로 응답 텍스트를 추출합니다.

    1. 사전 값 가져오기 -> URL 내용에서 choices
    2. 목록에서 항목 가져오기 -> 첫 번째 항목
    3. 사전 값 가져오기 -> message
    4. 사전 값 가져오기 -> content
  2. 마지막 사전 값을 전달받는 결과 보기(Show Result) 동작을 추가하여 화면에 요약본을 띄웁니다.


예제 3: 답장 초안 작성하기

받은 메시지를 입력으로 받아 어떤 의도나 톤으로 답장할지 간단히 물어본 뒤, 로컬 모델로 자연스러운 답장 초안을 작성하여 클립보드에 복사하는 단축어입니다.

동작 구성 순서

  1. 새 단축어를 만들고 이름을 로컬 AI 답장 초안으로 지정합니다.
  2. 클립보드 가져오기(또는 빠른 동작 / 공유 시트 텍스트 입력)를 추가하고, 변수 설정(Set Variable) 동작으로 변수 이름을 OriginalMessage로 저장합니다.
  3. 입력 요청(Ask for Input) 동작을 추가하여 프롬프트를 "답장의 핵심 내용이나 원하는 톤을 입력하세요"(예: "정중하게 거절하고 다음 주 화요일로 일정을 제안")로 설정한 뒤, 변수 설정 동작으로 ReplyIntent에 저장합니다.
  4. URL 내용 가져오기(Get Contents of URL) 동작을 추가하고 다음과 같이 설정합니다.

    • URL: http://127.0.0.1:8001/api/v1/inference/chat/completions
    • 방법(Method): POST
    • 헤더(Headers): Content-Type: application/json
    • 요청 본문(Request Body): JSON

동일한 JSON 페이로드 구조는 다음과 같습니다.

{
  "model": "qwen2.5-7b-instruct",
  "messages": [
    {
      "role": "system",
      "content": "당신은 명확하고 정중한 비즈니스 및 일상 메시지 답장을 작성하는 비서입니다. 원본 메시지와 사용자의 답장 의도를 바탕으로 바로 보낼 수 있는 답장 본문만 작성하세요."
    },
    {
      "role": "user",
      "content": "원본 메시지:\n<OriginalMessage>\n\n답장 의도:\n<ReplyIntent>"
    }
  ],
  "temperature": 0.5,
  "max_tokens": 512,
  "stream": false
}
  1. 응답에서 본문을 추출합니다.

    1. 사전 값 가져오기 -> URL 내용에서 choices
    2. 목록에서 항목 가져오기 -> 첫 번째 항목
    3. 사전 값 가져오기 -> message
    4. 사전 값 가져오기 -> content
  2. 클립보드에 복사(Copy to Clipboard)와 결과 보기(Show Result)(또는 훑어보기(Quick Look))를 추가하여 작성된 답장 초안을 확인하고 바로 붙여넣습니다.


macOS 대안: aigo CLI와 셸 스크립트 실행 사용하기

macOS에서는 HTTP 요청과 JSON 파싱 과정을 거치지 않고 셸 스크립트 실행(Run Shell Script) 동작에서 번들된 aigo CLI를 바로 호출할 수도 있습니다.

  1. 텍스트 입력 받기 동작을 추가합니다.
  2. 셸 스크립트 실행(Run Shell Script) 동작을 추가합니다(셸: /bin/zsh, 입력 전달 방식: 표준 입력(stdin)).
  3. aigo chat 명령에 시스템 프롬프트를 지정하여 실행합니다.
input_text="$(cat)"
aigo chat --system "사용자의 텍스트를 한국어로 번역하고 번역 결과만 출력하세요." "$input_text"
  1. 결과 보기 또는 클립보드에 복사 동작을 연결합니다.

aigo chat과 aigo translate의 전체 옵션은 CLI 레퍼런스를 참고하세요.

iPhone 및 iPad에서 사용하기

iPhone이나 iPad에서 127.0.0.1 및 localhost는 Backend.AI GO가 실행 중인 Mac이 아니라 모바일 기기 자신을 가리킵니다. Backend.AI GO는 기본적으로 API 서버를 127.0.0.1에만 바인딩하므로, 모바일 기기의 단축어에서 Mac의 로컬 모델을 호출하려면 네트워크 접근을 구성해야 합니다.

환경에 따라 다음 두 가지 방법 중 하나를 선택할 수 있습니다.

방법 1: 로컬 Wi-Fi(LAN 바인딩) 사용

Mac과 iPhone 또는 iPad가 신뢰할 수 있는 동일한 가정용·사내용 Wi-Fi 네트워크에 연결되어 있을 때 적합한 방법입니다.

  1. Mac의 Backend.AI GO에서 설정 > API 서버 > 액세스 키로 이동합니다.
  2. 키 만들기(Create Key)를 클릭하고 이름(예: iPhone Shortcuts)을 입력한 뒤, Inference Read 및 Inference Write 권한을 선택하여 키를 생성하고 복사합니다.
  3. 설정 > API 서버 > 관리 API로 이동하여 다음 두 옵션을 켭니다.

    • API 키 필요(Require API key) 켜기
    • 다른 기기에서 접근 허용(Allow access from other devices) 켜기 (관리 API가 포트 8001의 0.0.0.0에 바인딩됩니다)
  4. macOS 시스템 설정 > Wi-Fi > 세부사항에서 Mac의 로컬 LAN IP 주소(예: 192.168.1.50)를 확인합니다.

  5. iPhone 또는 iPad 단축어의 URL 내용 가져오기 동작을 다음과 같이 변경합니다.

    • URL: http://192.168.1.50:8001/api/v1/inference/chat/completions
    • 헤더(Headers): X-API-Key: <발급받은-액세스-키> 추가

Continuum Router 포트를 대신 사용하는 경우

설정 > API 서버에서 TCP 서버 활성화와 외부 액세스 허용을 켜면 Continuum Router(http://192.168.1.50:39080/v1/chat/completions)로 직접 연결할 수도 있습니다. 라우터에서 외부 액세스를 켜면 Inference Read 또는 Inference Write 권한이 있는 액세스 키가 자동으로 요구됩니다. 자세한 설정은 외부 접속 설정을 참고하세요.

방법 2: Tailscale 또는 WireGuard VPN 사용 (권장)

외부에서 모바일 데이터로 접속하거나 클라이언트 격리(AP Isolation)가 적용된 네트워크를 사용할 때는, 공유기 포트 포워딩 없이 종단간 암호화 연결을 제공하는 Tailscale 같은 메시 VPN을 권장합니다.

  1. Mac과 iPhone 또는 iPad 양쪽에 Tailscale을 설치하고 동일한 계정(Tailnet)으로 로그인합니다.
  2. Mac의 Backend.AI GO에서 설정 > API 서버 > 관리 API의 API 키 필요와 다른 기기에서 접근 허용을 켜고, Inference Write 권한이 포함된 액세스 키를 발급합니다.
  3. Tailscale 메뉴 막대 앱에서 Mac의 Tailscale IPv4 주소(100.x.y.z) 또는 MagicDNS 호스트 이름을 복사합니다.
  4. iPhone 또는 iPad 단축어의 URL을 http://100.x.y.z:8001/api/v1/inference/chat/completions로 지정하고 헤더에 X-API-Key를 추가합니다.

원격 접속 시 보안 유의 사항

  • 항상 API 키 요구: Backend.AI GO는 API 키 필요가 켜져 있지 않으면 관리 API의 다른 기기에서 접근 허용을 활성화할 수 없도록 보호합니다.
  • 최소 권한 부여: 단축어 전용 액세스 키에는 Admin 대신 Inference Read와 Inference Write 권한만 부여하세요.
  • 공용 인터넷에 직접 포트 노출 금지: 공유기에서 8001이나 39080 포트를 외부 인터넷으로 포트 포워딩하지 마세요. 외부 접속에는 Tailscale이나 VPN을 사용하세요.
  • 노출된 키 즉시 폐기: API 키가 하드코딩된 단축어 파일을 다른 사람에게 공유했다면 설정 > API 서버 > 액세스 키에서 해당 키를 즉시 삭제하고 새로 발급하세요.

팁 및 문제 해결

입력 텍스트 안전하게 처리하기

클립보드나 선택 영역에서 가져온 텍스트에 큰따옴표(")나 줄바꿈이 포함되어 있을 때, 이를 일반 텍스트(Text) 모드의 JSON 문자열 안에 그대로 끼워 넣으면 JSON 구문 오류가 발생할 수 있습니다. URL 내용 가져오기에서 요청 본문 유형을 JSON으로 두고 기본 내장된 사전(Dictionary) 입력 필드의 content 값에 단축어 입력 토큰을 넣으면, Apple 단축어가 따옴표와 줄바꿈, 역슬래시를 자동으로 안전하게 이스케이프해 줍니다.

요청 전 서버 상태 확인하기

Backend.AI GO가 꺼져 있거나 로드된 모델이 없을 때 단축어가 친절한 안내 메시지를 띄우도록 하려면 단축어 맨 앞에 상태 확인 동작을 추가할 수 있습니다.

  1. http://127.0.0.1:8001/api/v1/inference/status(또는 /api/v1/inference/models)에 대해 URL 내용 가져오기를 실행합니다.
  2. 사전 값 가져오기와 조건(If) 동작으로 running이 true인지(또는 data 목록이 비어 있지 않은지) 확인한 뒤 채팅 완성 요청을 보냅니다.

모델 크기별 성능 가이드

단축어는 사용자가 결과를 바로 기다리는 대화형 작업이므로 모델 크기에 따른 응답 지연 시간을 고려하는 것이 좋습니다.

  • 소형 모델 (1B~4B 파라미터): Apple Silicon Mac에서 보통 1~3초 이내에 응답합니다. 짧은 문장 번역이나 간단한 답장 초안에 가장 적합합니다.
  • 중형 모델 (7B~14B 파라미터): 더 높은 요약 품질과 자연스러운 문장 작성 능력을 제공하며, 입력 길이에 따라 보통 3~10초 정도 소요됩니다.
  • 대형 또는 추론(Reasoning) 모델 (30B 이상 또는 사고형 모델): 비스트리밍 요청에서는 전체 답변 생성이 끝날 때까지 15초 이상 걸릴 수 있습니다. 단축어의 HTTP 타임아웃을 피하려면 max_tokens를 적당한 크기(예: 512)로 제한하세요.

자주 발생하는 문제

증상 원인 해결 방법
서버에 연결할 수 없음 (Could not connect to the server) Backend.AI GO가 실행 중이 아니거나, 포트 번호가 다르거나, iPhone/iPad에서 127.0.0.1을 호출함 Backend.AI GO 실행 여부를 확인하세요. Mac에서는 포트 8001(관리 API)을 사용하거나 39080의 TCP 서버를 활성화하세요. iPhone/iPad에서는 Mac의 LAN 또는 Tailscale IP를 사용하고 다른 기기에서 접근 허용을 켜세요.
401 Unauthorized 또는 403 Forbidden API 키 인증이 켜져 있거나 키에 필요한 권한이 없음 설정 > API 서버 > 액세스 키에서 Inference Write 권한이 있는 키를 생성하고 헤더에 X-API-Key: <발급받은-키>를 추가하세요.
No model loaded / Model not found (404 또는 503) 현재 실행 중인 모델이 없거나 단축어의 "model" 값이 로드된 모델 ID와 일치하지 않음 모델 페이지에서 모델을 실행하고 curl http://127.0.0.1:8001/api/v1/inference/models로 정확한 id 값을 확인하세요.
사전 대신 data: {"id":...} 형태의 텍스트가 반환됨 요청에서 SSE 스트리밍("stream": true)이 활성화되어 단축어가 단일 JSON 객체로 파싱하지 못함 JSON 요청 본문에서 "stream": false로 설정하세요.
데이터가 올바른 형식이 아니기 때문에 읽을 수 없음 입력 텍스트에 이스케이프되지 않은 따옴표·줄바꿈이 포함되었거나 서버가 오류 응답을 반환함 텍스트 블록 대신 URL 내용 가져오기의 기본 JSON 빌더를 사용하고, URL 내용 바로 뒤에 훑어보기(Quick Look)를 붙여 서버가 반환한 원본 오류 메시지를 확인하세요.

관련 페이지