API & SDK가이드
OpenAI 호환 API로 Python에서 함수 호출하기
tools를 보내고, tool_calls를 읽고, role tool로 결과를 반환하세요: MiniMax-M2.7을 사용한 Python의 2단계 함수 호출 루프.

이 페이지의 내용
함수 호출(도구 호출)을 사용하면 모델이 코드에 함수 실행을 요청할 수 있습니다. 요청과 함께 tools 목록을 보내면 모델은 텍스트 대신 tool_calls로 응답하고, 여러분이 직접 함수를 실행한 뒤 그 결과를 role: tool 역할의 메시지로 다시 보냅니다. 그러면 모델이 최종 답변을 작성합니다. 이 가이드에서는 OpenAI 호환 엔드포인트 https:/에 대해 MiniMax-M2.7(id MiniMaxAI/, 180K 컨텍스트, 답변당 최대 8,192 출력 토큰)을 사용하는 전체 루프를 Python으로 보여줍니다.
도구 호출은 카탈로그의 모든 모델에서 지원되는 것으로 나열되어 있습니다(CheapTokens 문서, 2026년 10월 22일 확인). API 키가 필요합니다. 아직 요청을 보내본 적이 없다면 첫 API 요청부터 시작하세요.
함수 호출의 작동 방식#
모델은 아무것도 실행하지 않습니다. 모델은 "{\"city\": \"Paris\"}로 get_weather을 호출하라"는 구조화된 요청만 생성합니다. 실제 작업은 여러분의 프로그램이 수행하고 결과를 보고합니다. 따라서 두 번의 요청으로 이루어진 루프가 만들어집니다:
- 요청 1. 사용자 메시지와
tools목록을 보냅니다. 모델은 텍스트로 답하거나 하나 이상의tool_calls을 반환합니다. - 여러분의 코드. 각 호출을 파싱하고, 일치하는 함수를 실행하고, 결과를 수집합니다.
- 요청 2. 전체 대화를 다시 보냅니다: 원래 메시지,
tool_calls이 포함된 어시스턴트 메시지, 그리고 호출마다 하나씩role: tool메시지. 모델은 이 결과를 사용해 최종 답변을 작성합니다.
모든 요청은 전체 기록을 다시 보내므로, 도구 루프는 단일 질문보다 입력 토큰을 더 많이 사용합니다. 이 개념이 처음이라면 토큰이란 무엇인가를 읽어보세요.
클라이언트 설정#
OpenAI SDK(pip install openai)를 설치하고 키를 소스 코드 대신 환경 변수에 넣으세요:
export CHEAPTOKENS_API_KEY="your-key-here"base URL은 https:/입니다. 모델 id는 CheapTokens 문서에서 가져오세요. 제공자마다 같은 모델을 다르게 부릅니다. 이 가이드에서는 MiniMaxAI/을 사용합니다.
함수 선언 및 첫 요청 보내기#
함수는 tools 배열에 기술됩니다. 각 항목에는 type: function와, name, description, 그리고 JSON Schema로 작성된 parameters을 담은 function 객체가 있습니다. 설명은 모델이 함수를 언제 호출할지 결정하기 위해 읽는 내용이므로, 짧고 구체적인 문장으로 작성하세요.
아래는 완전한 스크립트입니다. 날씨 함수는 가짜 데이터를 사용하는 스텁이므로 예제에 추가 서비스가 필요하지 않습니다:
import json
import os
from openai import OpenAI
client = OpenAI(
base_url='https://api.cheaptokens.dev/v1',
api_key=os.environ['CHEAPTOKENS_API_KEY'],
)
MODEL = 'MiniMaxAI/MiniMax-M2.7'
def get_weather(city: str) -> dict:
# Stub with fake data: replace with a real lookup
fake = {'Paris': 14, 'Tokyo': 19}
return {'city': city, 'temp_c': fake.get(city, 10)}
FUNCTIONS = {'get_weather': get_weather}
tools = [
{
'type': 'function',
'function': {
'name': 'get_weather',
'description': 'Get the current temperature in Celsius for a city.',
'parameters': {
'type': 'object',
'properties': {
'city': {'type': 'string', 'description': 'City name, for example Paris'},
},
'required': ['city'],
},
},
}
]
messages = [{'role': 'user', 'content': 'What is the weather in Paris right now?'}]
# Step 1: the model decides whether to call a function
first = client.chat.completions.create(model=MODEL, messages=messages, tools=tools)
message = first.choices[0].message
if not message.tool_calls:
print(message.content)
raise SystemExit
# Step 2: run every requested call and send the results back
messages.append(message)
for call in message.tool_calls:
args = json.loads(call.function.arguments)
result = FUNCTIONS[call.function.name](**args)
messages.append({
'role': 'tool',
'tool_call_id': call.id,
'content': json.dumps(result),
})
final = client.chat.completions.create(model=MODEL, messages=messages, tools=tools)
print(final.choices[0].message.content)루프의 작동 여부를 결정하는 세 가지 세부 사항이 있습니다:
call.는 딕셔너리가 아닌 JSON 문자열입니다.function. arguments json.loads으로 파싱하세요.- 각
role: tool메시지는 응답하는 호출의tool_call_id을 반드시 포함해야 하며, 이는call.id입니다. - 도구 메시지의
content은 문자열입니다. 구조화된 결과에는json.dumps을 사용하세요.
예상되는 출력#
첫 요청 후 필드를 출력하면 다음과 같습니다(호출 id는 실행할 때마다 다릅니다):
finish_reason: tool_calls
call.id: call_abc123
call.function.name: get_weather
call.function.arguments: {"city": "Paris"}그런 다음 스크립트는 "It is currently 14 °C in Paris."와 같은 평범한 문장인 최종 답변을 출력합니다. 문구는 실행할 때마다 바뀌지만, 숫자는 여러분의 함수에서 나옵니다.
여러 호출과 더 긴 루프#
모델은 예를 들어 두 도시의 날씨를 물을 때처럼 단일 응답에서 둘 이상의 호출을 반환할 수 있습니다. 그래서 예제에서는 message.을 순회하며 각 호출에 고유한 id로 응답합니다. OpenAI의 함수 호출 가이드도 같은 동작을 설명합니다: 기본 auto의 tool_choice를 사용하면 모델은 0개, 1개 또는 여러 함수를 호출할 수 있습니다(OpenAI 문서, 2026년 10월 22일 확인; 해당 페이지에는 최종 업데이트 날짜가 없으며 더 새로운 Responses API 형태를 설명하는 반면, 이 가이드는 / 엔드포인트의 Chat Completions 형태를 사용합니다).
에이전트는 모델이 도구를 요청하지 않을 때까지 두 단계를 반복합니다. 요청을 루프로 감싸고 항상 단계 제한을 설정하세요:
for _ in range(5): # safety limit against endless loops
response = client.chat.completions.create(model=MODEL, messages=messages, tools=tools)
message = response.choices[0].message
if not message.tool_calls:
print(message.content)
break
messages.append(message)
for call in message.tool_calls:
args = json.loads(call.function.arguments)
result = FUNCTIONS[call.function.name](**args)
messages.append({'role': 'tool', 'tool_call_id': call.id, 'content': json.dumps(result)})답변이 토큰 단위로 나타나게 하려면 Python에서의 스트리밍과 함께 사용하세요.
MiniMax-M2.7이 도구 루프에 적합한 이유#
도구 루프는 기록이 점점 늘어나는 많은 요청을 보냅니다. 이러한 패턴을 위해 CheapTokens는 MiniMax-M2.7을 제공합니다: 180K 컨텍스트, 답변당 최대 8,192 출력 토큰, 피크 시간 없이 하루 중 언제든 동일한 가격, 모든 모델에 하나의 잔액. 입력과 출력을 합산하면 OpenRouter의 기준 가격보다 저렴합니다(CheapTokens 가격 비교, 2026년 10월 31일 확인).
현재 1M 토큰당 가격: 입력 $0.05, 출력 $0.15. 예시 워크로드(측정값 아님)로, 위의 두 번 요청 왕복에서 총 약 2,700 입력 토큰과 350 출력 토큰의 비용은 $0.00019입니다. 전체 가격 목록은 가격 페이지에 있습니다.
다른 모델을 사용해 보려면 id만 변경하세요. id 목록은 모델 페이지에 있습니다.
작동하지 않을 때#
message.가tool_ calls None입니다. 모델이 텍스트로 답했습니다. 함수description을 더 구체적으로 만들고, 질문이 실제로 그 함수를 필요로 하는지 확인하세요.arguments에서json.. 모델이 잘못된 JSON을 생성했습니다.JSONDecodeError json.loads를try/except로 감싸고 오류 텍스트를 도구 결과로 다시 보내면, 모델이 수정된 인수로 재시도할 수 있습니다.- 두 번째 요청이 실패하거나 모델이 결과를 무시합니다. 모든 호출에 일치하는
tool_call_id를 가진role: tool메시지가 정확히 하나씩 있는지, 그리고tool_calls이 포함된 어시스턴트 메시지가 그 앞에 기록에 있는지 확인하세요. FUNCTIONS[...]에서KeyError. 모델이 등록하지 않은 함수를 지정했습니다. 크래시 대신 짧은 오류 문자열을 도구 결과로 반환하세요.- 답변이 잘립니다.
finish_reason을 확인하세요: 값length은 출력 토큰 한도에 도달했음을 의미합니다. AI 답변이 문장 중간에 멈추는 이유를 참고하세요. - 401 또는 인증 오류. 키가
CHEAPTOKENS_에 있는지, base URL이API_ KEY /v1로 끝나는지 확인하세요.
다음 단계#
스텁을 실제 함수로 교체하세요: 데이터베이스 쿼리, 검색 호출 또는 계산기. tools과 FUNCTIONS에 항목을 더 추가하고, 모든 함수 결과는 이후 요청마다 기록으로 다시 들어가므로 짧게 유지하세요. 키를 발급받고 첫 호출을 하려면 CheapTokens 문서를 여세요.



