OpenAI · GPT-6 Astra

GPT-6 Astra Function Calling 실전 2026: AI로 API, DB, 커스텀 툴 호출하기

2026.09.11 · 약 15분

Function Calling의 어려움은 도구 루프 오구현, 권한 미격리, Chat Completions 고착으로 호스팅 도구로 넘어가지 못하는 것이다. HTTP API 도구 스키마, 완전한 도구 루프, 읽기 전용 DB 패턴, 함수 vs 호스팅 도구 비교, 결정 매트릭스와 7단계를 정리한다.

GPT-6 Astra Function Calling 도구 루프를 디버깅하는 개발자

GPT-6 Astra Function Calling은 AI 에이전트의 핵심이다. 모델이 어떤 도구를 호출하고 어떤 인수를 전달할지 결정하면 런타임이 부작용을 실행하고 결과를 모델에 돌려줘 추론을 계속한다. 루프가 올바르면 Astra는 자율적으로 API를 호출하고, 데이터베이스를 읽고, 커스텀 로직을 실행할 수 있다. 잘못되면 루프가 막히거나 도구 권한이 제어 불능이 된다. "Function Calling이 무엇인지"는 프로토콜 비교에, "API 키를 어떻게 얻는지"는 API 튜토리얼에 있다. 이 글은 "돌아가는"에서 "안전하게 배포 가능한" 수준으로 올리는 세 가지 핵심 도구 패턴을 다룬다.

Responses
도구 호출의 유일한 경로
function_call
output 이벤트 타입
allowlist
DB 도구 보안 기준선
Responses API는 필수
Function Calling, 호스팅 도구(웹 검색, 코드 인터프리터, Computer Use), 비동기 도구 루프는 모두 Responses API가 필요하다. Chat Completions에 호스팅 도구를 추가하면 400이 반환된다. 이 글의 모든 코드는 텍스트 경로 확립을 전제로 Responses를 사용한다.

1단계: 도구 스키마 정의

도구 스키마는 모델에게 "이 도구의 이름, 목적, 파라미터"를 알려주는 JSON 객체다. 날씨 HTTP API를 호출하는 도구 예제를 보자.

도구 스키마 정의 (HTTP API 도구)
import json
from openai import OpenAI

client = OpenAI()

tools = [
    {
        "type": "function",
        "name": "get_weather",
        "description": "Get current weather for a city via HTTP API.",
        "parameters": {
            "type": "object",
            "properties": {
                "city": {
                    "type": "string",
                    "description": "City name, e.g. Tokyo, London, Shanghai",
                },
                "unit": {
                    "type": "string",
                    "enum": ["celsius", "fahrenheit"],
                    "description": "Temperature unit. Default celsius.",
                },
            },
            "required": ["city"],
            "additionalProperties": False,
        },
    }
]

description은 도구가 무엇을 하는지 동사구로 작성한다. 모델은 이 필드를 읽고 도구를 호출할지 결정한다. 필수 파라미터는 required에 나열하고, additionalProperties: false로 예기치 않은 키를 차단한다. 여러 도구를 같은 리스트에 넣어도 된다. 모델이 한 턴에 여러 도구를 병렬 호출할 수 있으므로 루프는 모든 tool_call을 처리해야 한다.

2단계: 완전한 도구 루프

요청 전송 → output의 function_call 감지 → 실행 → 결과를 input에 추가 → 재전송, function_call이 사라질 때까지 while로 반복한다. if로 한 번만 처리하면 최종 텍스트 답변이 오지 않는다.

완전한 도구 루프 (Responses API)
import json
import requests
from openai import OpenAI

client = OpenAI()

def call_weather_api(city: str, unit: str = "celsius") -> dict:
    """Replace with your real HTTP endpoint."""
    url = "https://api.example.com/weather"
    r = requests.get(url, params={"city": city, "unit": unit}, timeout=5)
    r.raise_for_status()
    return r.json()  # e.g. {"city": "Tokyo", "temp": 22, "condition": "sunny"}

# Initial request — model may call tools
response = client.responses.create(
    model="gpt-6-astra",
    input="What is the weather in Tokyo right now?",
    tools=tools,
    reasoning={"effort": "low"},
)

# Tool loop: keep going until model stops calling tools
while True:
    tool_calls = [o for o in response.output if o.type == "function_call"]
    if not tool_calls:
        break  # model is done — final answer is in response.output_text

    tool_results = []
    for call in tool_calls:
        args = json.loads(call.arguments)
        if call.name == "get_weather":
            result = call_weather_api(**args)
        else:
            result = {"error": f"Unknown tool: {call.name}"}
        tool_results.append({
            "type": "function_call_output",
            "call_id": call.call_id,
            "output": json.dumps(result, ensure_ascii=False),
        })

    # Append history + results and continue
    response = client.responses.create(
        model="gpt-6-astra",
        input=response.output + tool_results,
        tools=tools,
        reasoning={"effort": "low"},
    )

print(response.output_text)

구현 주의사항. ① response.output은 여러 타입이 섞인 리스트다. type == "function_call"만 필터링한다. ② 계속할 때는 response.output + tool_results를 input으로 전달한다. 이력 없이 tool_results만 전달하면 모델이 컨텍스트를 잃는다. ③ call_id는 tool_call과 tool_result에서 일치해야 한다. ④ 반환값은 json.dumps로 문자열화한다.

보안: 도구 allowlist + 실행 격리
도구가 무엇을 할 수 있는지는 런타임이 결정한다. name 필드를 알려진 allowlist로 검증하고, 인수를 타입 체크하고, HTTP 도구에는 타임아웃과 도메인 allowlist를 추가한다. DB 도구는 사전 정의된 SQL만 실행하며 모델 출력을 SQL에 이어붙이지 않는다. 디스크 쓰기나 셸 실행 도구는 원격 Mac에서 격리 실행한다.

3단계: 읽기 전용 데이터베이스 도구

안전한 DB 도구의 3요소: 읽기 전용 권한(INSERT/UPDATE/DELETE 금지), 파라미터화된 쿼리(인젝션 방지), SQL allowlist(임의 쿼리 방지).

읽기 전용 DB 도구 (allowlist + 파라미터화)
import sqlite3
from typing import Any

# Only these parameterized queries can be executed — no raw user SQL
ALLOWED_QUERIES: dict[str, str] = {
    "get_order":   "SELECT id, status, total, created_at FROM orders WHERE id = ?",
    "list_orders": "SELECT id, status, total FROM orders WHERE user_id = ? LIMIT 20",
}

def query_db(query_name: str, params: list[Any]) -> list[dict]:
    """Execute an allowlisted, parameterized read-only query.
    Never accepts raw SQL strings from the model.
    """
    sql = ALLOWED_QUERIES.get(query_name)
    if sql is None:
        raise ValueError(f"Query '{query_name}' not in allowlist")
    con = sqlite3.connect("orders.db", check_same_thread=False)
    con.row_factory = sqlite3.Row
    try:
        rows = con.execute(sql, params).fetchall()
        return [dict(r) for r in rows]
    finally:
        con.close()

# Schema exposed to the model
db_tool = {
    "type": "function",
    "name": "query_db",
    "description": "Query the orders DB. Only read-only allowlisted queries.",
    "parameters": {
        "type": "object",
        "properties": {
            "query_name": {
                "type": "string",
                "enum": list(ALLOWED_QUERIES.keys()),
                "description": "Name of the allowlisted query",
            },
            "params": {
                "type": "array",
                "items": {"type": ["string", "number"]},
                "description": "Positional parameters for the query",
            },
        },
        "required": ["query_name", "params"],
    },
}

운영 환경에서는 커넥션 풀, 쿼리 타임아웃, SQL에 하드코딩된 행 수 제한, 민감 컬럼 마스킹이 필요하다. 모델에 반환하는 것은 요약이어야 하며, 테이블 전체의 raw dump가 아니다.

함수 도구 vs 호스팅 도구

차원함수 도구 (type: function)호스팅 도구 (OpenAI 운영)
실행 위치내 런타임 (로컬 / 원격 Mac)OpenAI 인프라
적합한 경우프라이빗 API, 내부 DB, 커스텀 로직웹 검색, 파일 검색, 코드 실행, shell, Computer Use
개발 비용스키마 + 실행 함수 + 루프를 직접 구현도구 이름만 지정하면 OpenAI가 실행
과금토큰만토큰 + 도구 호출 추가 요금
격리 요건쓰기 도구는 실행 환경 격리 필요OpenAI가 샌드박스 관리

두 타입을 같은 요청에서 혼합할 수 있다. 호스팅 도구 결과는 자동으로 컨텍스트에 들어가므로 수동 제출 불필요. 함수 도구 결과는 function_call_output으로 수동 제출해야 한다.

결정 매트릭스

필요한 것선택이유
사내 REST API 호출함수 도구프라이빗 네트워크는 OpenAI 인프라에서 도달 불가
내부 DB 쿼리 (읽기 전용)함수 도구 + SQL allowlist프라이빗 데이터. 접근 권한은 직접 관리
공개 웹 실시간 검색호스팅 web_search_preview크롤링과 랭킹은 OpenAI가 담당
모델에 Python 실행 요청호스팅 code_interpreterOpenAI 샌드박스에서 실행. 로컬 리소스 불필요
모델이 데스크톱/브라우저 제어호스팅 computer_use + 격리 Mac가시 데스크톱 필요. 오작동 방지를 위해 격리
디스크 쓰기 shell 명령 실행함수 도구 + 원격 Mac 격리쓰기 권한은 폐기 가능한 환경에만

A — 개인 개발자: 로컬 + 함수 도구 (HTTP API, 디스크 비쓰기). 스키마와 루프를 확립하고 call_id를 로깅한다. 단일 도구 루프가 안정되면 멀티 도구로 확장한다.

B — 소규모 팀: 함수 도구는 내부 서비스에 토큰 인증으로 연결. DB 도구는 읽기 전용 + 커넥션 풀 + 쿼리 타임아웃. 호스팅 도구는 태스크 유형별로 활성화. 도구 실행 로직은 단위 테스트로 커버.

C — 엔터프라이즈: 함수 도구는 API 게이트웨이 경유 + 감사 로그. DB는 읽기 전용 레플리카 + 행 수준 보안. Computer Use는 폐기 가능한 격리 Mac 노드에서 실행. 노드 월 비용은 가격 페이지, 계정은 고객센터.

흔한 실수

  1. 루프를 한 번만 실행 (if 사용): 최종 텍스트 답변이 도달하지 않는다.
  2. 이력 없이 결과 제출: input에 tool_results만 전달하면 모델이 컨텍스트를 잃는다.
  3. 모델 출력을 SQL/셸에 직접 연결: allowlist + 파라미터화된 쿼리로 방지한다.
  4. HTTP 도구 타임아웃 미설정: 다운스트림 서비스가 멈추면 에이전트 전체가 중단된다.
  5. 도구가 대용량 데이터 반환: 결과가 컨텍스트에 들어가 272K 요금 업리프트를 유발한다.

액션 플랜: 7단계

  1. 텍스트 경로가 먼저 동작하는지 확인 (API 튜토리얼 참조).
  2. 첫 함수 도구 스키마 작성. description은 동사구, required 설정, additionalProperties: false.
  3. 도구 실행 함수 구현. HTTP 도구에 타임아웃, DB 도구에 allowlist + 파라미터화 쿼리.
  4. tools 파라미터 포함해 Responses 요청을 보내고 response.output에 function_call이 나타나는지 확인.
  5. while True 루프 구현. call_id 일치시켜 function_call_output 제출, input에 이력 포함.
  6. 호스팅 도구 (web_search, code_interpreter) 필요 시 추가. 그 결과는 수동 제출 불필요.
  7. 디스크 쓰기, 셸 실행, 브라우저 제어 도구는 격리 원격 Mac으로 이동, 세션 종료 후 폐기.

FAQ

Function Calling은 Responses API가 필수인가?

예. 도구 호출, 호스팅 도구, 비동기 루프는 Responses API가 필수다.

요청당 도구 수 한도는?

엄격한 소수 제한은 없지만 도구가 많을수록 프롬프트 토큰 비용이 오른다. 현재 태스크에 필요한 도구만 전달하라.

SQL 인젝션을 방지하려면?

? 플레이스홀더 파라미터화 쿼리와 SQL allowlist를 조합한다. 모델 출력을 SQL에 직접 이어붙이지 마라.

함수 도구와 호스팅 도구의 선택 기준은?

프라이빗 API, 내부 DB, 커스텀 로직은 함수 도구. 웹 검색, 코드 실행, Computer Use는 호스팅 도구.

도구 호출 후 최종 답변을 스트리밍할 수 있나?

가능하다. 비스트리밍 루프를 먼저 안정화한 후 stream=True를 추가하라.

결론

GPT-6 Astra Function Calling의 핵심 세 가지: 명확한 description의 스키마, 이력 포함 결과 제출 while 루프, allowlist + 파라미터화 쿼리의 DB 도구와 쓰기 도구 격리. 원격 Mac 노드는 대여 페이지가격 페이지에서, 계정 문의는 고객센터.

더 읽기

실제 API를 호출하는 도구는 격리된 Cloud Mac에서 실행

HTTP API 호출은 로컬도 괜찮다. 디스크 쓰기, 레포 수정, 브라우저 제어가 포함된 도구는 일상 데스크톱과 공유하면 안 된다. 원격 Mac은 세션 단위로 워크스페이스를 격리한다.

지금 주문 · 가격 보기

GPT-6 Astra Function Calling

실제 API를 호출하는 도구는 격리된 Cloud Mac에서 실행

Cloud Mac · isolated agent runtime

지금 주문
Mac 지금 주문