DeepSeek은 2026년 8월 12일 V4 Pro의 프리뷰를 종료했으며, 출시 보도에서는 코딩, 도구 사용, 그리고 여러 단계를 거쳐도 맥락을 잃지 않는 장기 작업과 같은 에이전트 워크플로우를 주요 내용으로 다룹니다. 이러한 포지셔닝으로 인해 다른 어떤 API 기능보다도 함수 호출(function calling)이 중요해지지만, 출시 주간 가이드에서는 이 기능을 다루지 않았습니다. 지금까지의 모든 튜토리얼은 채팅 완성(chat completions)에서 멈춰있습니다.
이 문서는 더 나아갑니다: 도구 스키마를 정의하고, 표준 Python openai SDK로 첫 도구 호출을 수행하며, 완전한 에이전트 루프를 구축한 다음, 에이전트를 배포하기 전에 Apidog에서 전체를 테스트합니다. 아직 DeepSeek API 키가 없다면, DeepSeek V4 API 사용 방법에 대한 저희 가이드를 통해 설정한 후 다시 돌아오세요.
세 줄 요약
deepseek-v4-pro(GA 빌드 DeepSeek-V4-Pro-0813)는 OpenAI 스타일의 함수 호출을 지원합니다:tools배열을 보내고,tool_calls를 받으며, 결과를tool메시지로 반환합니다. 표준openaiSDK는https://api.deepseek.com에 대해 작동합니다.- 완전한 에이전트 루프는 약 30줄의 Python 코드로 구성됩니다: 모델이 도구 요청을 중단할 때까지 호출, 실행, 추가를 반복합니다. 병렬 호출과 구조화된 출력이 지원됩니다; 사고 모드는
reasoning_content를 추가합니다. - 자동 접두사 캐싱(prefix caching)은 캐시 히트 입력 토큰 백만 개당 $0.003625로 가격이 책정되어, 캐시 미스보다 120배 저렴합니다. 이것이 심층 에이전트 루프를 저렴하게 만드는 이유입니다.
- 도구 호출 품질은 사용자의 하네스(harness)와 스키마에 따라 달라집니다. 벤치마크가 아닌 실제 도구를 라이브 모델에 대해 테스트하십시오.
함수 호출이 V4 Pro의 핵심 사용 사례인 이유
DeepSeek은 에이전트를 위해 V4 Pro를 구축했으며, 사양서는 에이전트 런타임 체크리스트처럼 읽힙니다:
| 사양 | DeepSeek V4 Pro |
|---|---|
| 아키텍처 | Sparse MoE: 총 1.6T 파라미터, 토큰당 49B 활성 파라미터 |
| 컨텍스트 윈도우 | 1M 토큰 |
| 최대 출력 | 384K 토큰 |
| 입력 가격 | $0.435/M 토큰 (캐시 미스), $0.003625/M (캐시 히트) |
| 출력 가격 | $0.87/M 토큰 |
| 함수 호출 | OpenAI 호환 tools 배열 및 tool_calls 응답 |
| 다른 인터페이스 | Anthropic Messages 형식, DeepSeek Responses API |
각 라인은 에이전트 문제를 나타냅니다: 1M 토큰 윈도우는 긴 에이전트의 전체 도구 결과 이력을 담고, 384K 출력 한도는 큰 구조화된 페이로드를 위한 공간을 남기며, 접두사 캐싱은 루프 경제성을 확보합니다. 이 모델은 공급자 비교를 위해 OpenRouter에 deepseek-v4-pro-0813으로 등재되어 있습니다.
코드를 시작하기 전에 한 가지 주의할 점이 있습니다. Hacker News 출시 토론에서, 개발자들은 도구 호출 성능이 하네스(harness)에 매우 민감하다고 보고했습니다: 동일한 모델이라도 프레임워크, 프롬프트 스캐폴딩, 스키마 스타일에 따라 성능이 더 좋거나 나쁠 수 있습니다. 벤치마크는 사용자의 도구 스키마를 어떻게 처리하는지 알려주지 않습니다. 실제 정의로 테스트하십시오.
DeepSeek 함수 호출 작동 방식
함수 호출은 모델이 어떤 것도 실행한다는 의미가 아닙니다. 모델은 산문 대신 "{"order_id": "ORD-10442"}로 get_order를 호출하세요"와 같은 구조화된 요청으로 응답합니다. 사용자의 코드가 함수를 실행하고 결과를 반환하면, 모델은 실제 데이터로 계속 진행합니다. 사이클은 다음과 같습니다:
messages와 JSON 스키마로 각 함수를 설명하는tools배열을 보냅니다.- 모델은 도구가 필요하다고 판단하고
tool_calls와finish_reason: "tool_calls"로 응답합니다. - 사용자 코드가 인수를 파싱하고 실제 함수를 실행합니다.
- 호출 ID에 연결된
role: "tool"메시지로 결과를 추가합니다. - 모델은 다른 도구를 요청하거나 최종 답변을 생성합니다.
OpenAI 함수 호출과 작업해 본 적이 있다면, 이것은 동일한 통신 형식입니다; 대부분의 에이전트 코드는 기본 URL과 모델 이름을 변경하여 포팅됩니다. 공식 DeepSeek 문서는 Anthropic 호환 Messages 엔드포인트와 Responses API도 다루지만, 이 가이드는 OpenAI 호환 인터페이스에 중점을 둡니다.
1단계: 클라이언트 설정
SDK를 설치하고 DeepSeek을 가리킵니다:
pip install openai
export DEEPSEEK_API_KEY="sk-..."
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["DEEPSEEK_API_KEY"],
base_url="https://api.deepseek.com",
)
이것이 전체 설정입니다. 모든 예제는 GA 빌드 DeepSeek-V4-Pro-0813로 해석되는 model="deepseek-v4-pro"를 사용합니다.
2단계: 도구 스키마 정의
온라인 상점을 위한 지원 에이전트를 구축할 것입니다. 첫 번째 도구는 주문을 조회합니다. 도구 정의는 이름, 설명, 매개변수에 대한 JSON 스키마 세 부분으로 구성됩니다.
tools = [
{
"type": "function",
"function": {
"name": "get_order",
"description": (
"ID로 고객 주문을 조회합니다. 주문 상태, 운송업체, "
"추적 번호, 예상 배송 날짜를 반환합니다. 사용자가 "
"주문의 위치나 상태를 물을 때마다 사용하십시오."
),
"parameters": {
"type": "object",
"properties": {
"order_id": {
"type": "string",
"description": "주문 ID, 'ORD-10442'와 같은 형식입니다.",
}
},
"required": ["order_id"],
},
},
}
]
설명은 장식이 아닙니다: 모델은 설명을 읽어 도구를 언제 호출할지 결정합니다. 모호한 설명은 모델이 도구를 무시하거나 잘못된 도구를 선택하는 가장 큰 이유입니다.
스키마가 설명하는 로컬 함수(실제 주문 서비스를 위한 스텁):
def get_order(order_id: str) -> dict:
"""실제 주문 서비스를 위한 스텁입니다."""
fake_db = {
"ORD-10442": {
"status": "shipped",
"carrier": "DHL",
"tracking_number": "4281337005",
"estimated_delivery": "2026-08-15",
},
"ORD-10587": {
"status": "processing",
"estimated_ship_date": "2026-08-14",
},
}
return fake_db.get(order_id, {"error": f"알 수 없는 주문 ID: {order_id}"})
3단계: 첫 도구 호출 수행
도구 없이는 모델이 답할 수 없는 질문을 보냅니다:
messages = [
{"role": "system", "content": "당신은 온라인 상점의 지원 에이전트입니다."},
{"role": "user", "content": "내 주문 ORD-10442는 어디에 있나요?"},
]
response = client.chat.completions.create(
model="deepseek-v4-pro",
messages=messages,
tools=tools,
)
message = response.choices[0].message
print(message.tool_calls[0].function.name) # get_order
print(message.tool_calls[0].function.arguments) # {"order_id": "ORD-10442"}
모델은 답변 대신 get_order를 실행하도록 요청합니다. 원시 응답 페이로드는 다음과 같습니다:
{
"id": "chatcmpl-8f3a1c",
"object": "chat.completion",
"model": "deepseek-v4-pro",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "",
"tool_calls": [
{
"id": "call_0_f1c29a44",
"type": "function",
"function": {
"name": "get_order",
"arguments": "{\"order_id\": \"ORD-10442\"}"
}
}
]
},
"finish_reason": "tool_calls"
}
],
"usage": {
"prompt_tokens": 312,
"completion_tokens": 24,
"total_tokens": 336,
"prompt_cache_hit_tokens": 0,
"prompt_cache_miss_tokens": 312
}
}
세 가지 세부 사항이 중요합니다. finish_reason이 "tool_calls"이며, 이는 루프에 모델이 실행을 원한다는 것을 알려줍니다. 각 호출은 결과와 함께 다시 반환해야 하는 id를 가집니다. 그리고 arguments는 JSON 문자열이므로 직접 파싱해야 하며, 때때로 형식이 잘못될 수 있습니다.
4단계: 함수 실행 및 결과 반환
함수를 실행한 다음, 두 개의 메시지를 추가합니다: tool_calls를 포함하는 조수(assistant)의 응답과 결과를 담고 있는 tool 메시지입니다.
import json
tool_call = message.tool_calls[0]
args = json.loads(tool_call.function.arguments)
result = get_order(args)
messages.append(message) # tool_calls를 포함하는 조수(assistant)의 응답
messages.append({
"role": "tool",
"tool_call_id": tool_call.id, # 응답의 id와 일치해야 합니다.
"content": json.dumps(result),
})
final = client.chat.completions.create(
model="deepseek-v4-pro",
messages=messages,
tools=tools,
)
print(final.choices[0].message.content)
# 귀하의 주문 ORD-10442는 DHL로 배송되었으며
# 2026년 8월 15일에 도착할 것으로 예상됩니다. 추적 번호: 4281337005.
tool_call_id 링크는 엄격합니다: 다음 모델 응답 전에 모든 tool_calls 항목에는 일치하는 tool 메시지가 필요하며, 그렇지 않으면 요청이 실패합니다.
5단계: 완전한 에이전트 루프
실제 에이전트는 호출을 연결합니다: 주문을 조회하고, 환불 정책을 확인하고, 이메일을 작성하는 등 각 단계가 이전 단계에 의존합니다. 패턴은 모델이 정상적인 답변을 반환할 때까지 모델을 계속 호출하고 모델이 요청하는 모든 것을 실행하는 것입니다.
TOOLS_BY_NAME = {"get_order": get_order}
def run_agent(client, messages, tools, max_rounds=10):
"""최종 답변이 생성되거나 한도에 도달할 때까지 모델을 실행합니다."""
for _ in range(max_rounds):
response = client.chat.completions.create(
model="deepseek-v4-pro",
messages=messages,
tools=tools,
)
message = response.choices[0].message
messages.append(message)
if not message.tool_calls: # 도구 요청이 없으면 완료
return message.content
for tool_call in message.tool_calls:
fn = TOOLS_BY_NAME.get(tool_call.function.name)
try:
if fn is None:
raise ValueError(f"알 수 없는 도구: {tool_call.function.name}")
args = json.loads(tool_call.function.arguments)
result = fn(args)
except Exception as exc:
result = {"error": str(exc)} # 실패를 모델에 다시 전달
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps(result),
})
raise RuntimeError(f"에이전트가 {max_rounds} 라운드 내에 완료되지 않았습니다.")
프레임워크와 에이전트 SDK는 이 루프를 정교하게 만든 것입니다. max_rounds 한도는 실패하는 도구를 계속 호출하여 멈춘 모델을 무한한 청구 대신 깔끔한 실패로 전환합니다.
병렬 도구 호출
"ORD-10442와 ORD-10587의 상태를 비교해줘"와 같이 두 개의 조회를 요청하면, V4 Pro는 종종 두 가지를 하나의 응답으로 묶습니다:
"tool_calls": [
{
"id": "call_0_a7d1",
"type": "function",
"function": { "name": "get_order", "arguments": "{\"order_id\": \"ORD-10442\"}" }
},
{
"id": "call_1_b3e9",
"type": "function",
"function": { "name": "get_order", "arguments": "{\"order_id\": \"ORD-10587\"}" }
}
]
run_agent 루프는 이미 이를 처리합니다: 내부 for 루프는 각 호출에 자체 tool_call_id로 응답하며 (다음 턴 전에 모든 호출에는 일치하는 결과가 필요함), 배치를 동시에 실행할 수 있습니다. 이는 모델이 샌드박스에서 오케스트레이션 코드를 작성하는 GPT-5.6의 프로그래밍 방식 도구 호출과는 다른 철학입니다; DeepSeek은 실행과 신뢰 경계를 사용자 런타임에 유지합니다.
사고 모드 + 도구
V4 Pro는 세 가지 사고 모드를 제공하므로, 어려운 계획 단계에서는 추론 노력을 높이고 일상적인 조회에서는 건너뛸 수 있습니다 (모드 이름 및 기본값은 공식 문서 참조). 사고 모드가 활성화되면, API는 도구 호출과 함께 모델의 추적(trace)을 reasoning_content로 반환합니다:
response = client.chat.completions.create(
model="deepseek-v4-pro",
messages=messages,
tools=tools,
extra_body={"thinking": {"type": "enabled"}},
)
message = response.choices[0].message
print(message.reasoning_content) # 계획 추적
print(message.tool_calls) # 결정된 호출
추적은 모델이 도구를 선택한 이유를 보여주며, 이는 일반적으로 잘못된 스키마가 드러나는 지점입니다. 기록에 조수(assistant)의 응답을 추가하기 전에 reasoning_content를 제거하고, 계획 위주의 응답에만 사고 모드를 사용하십시오. 추론은 출력으로 $0.87/M로 청구됩니다.
오류 처리: 모델이 호출을 잘못했을 때
형식이 잘못된 도구 호출은 드물지만, 에이전트 루프는 모든 실패 모드를 증폭시킵니다. 핵심 패턴은 다음과 같습니다: 잘못된 호출로 인해 절대 중단하지 말고, 문제를 도구 결과로 반환하여 모델이 다시 시도하도록 합니다. 이는 json.loads가 실패하는 인수뿐만 아니라 비즈니스 규칙을 위반하는 값도 다룹니다:
from jsonschema import ValidationError, validate
schema = tools[0]["function"]["parameters"]
try:
args = json.loads(tool_call.function.arguments)
validate(instance=args, schema=schema)
result = get_order(**args)
except (json.JSONDecodeError, ValidationError) as exc:
result = {
"error": f"잘못된 인수: {exc}",
"hint": "'ORD-10442'와 같은 order_id 문자열로 get_order를 다시 호출하십시오.",
}
hint 필드가 중요합니다: 한 줄의 수정으로 다음 라운드에서 보통 수정된 재시도가 발생합니다. 에이전트 오류를 보안 이벤트로도 취급하십시오. 공격자가 제공한 인수로 delete_order를 호출하도록 설득된 모델은 뒤에 있는 키만큼만 위험하며, 이는 AI 에이전트를 위한 최소 권한 API 키의 경우입니다. 잘못된 호출이 사고가 되지 않도록 자격 증명 범위를 지정하십시오.
배포 전에 Apidog로 도구 호출 테스트 및 디버그
모든 도구는 API를 둘러싼 얇은 래퍼이며, 모델은 이제 해당 API의 소비자입니다. 백엔드 엔드포인트가 모호하거나 불안정하면 모델도 모든 것을 상속받습니다. 여기서 Apidog가 루프에서 제 역할을 합니다:
- 백엔드 API를 먼저 설계하십시오. Apidog의 시각적 디자이너에서
GET /orders/{order_id}를 사양으로 정의하십시오; 도구의 JSON 스키마는 사양에서 직접 파생되므로, 둘이 조용히 달라질 수 없습니다. - 백엔드가 존재하기 전에 모의(mock)하십시오. Apidog의 스마트 모의는 스키마에서 현실적인 응답을 제공하므로, 실제 서비스가 아직 구축 중인 동안 에이전트 루프는
get_order에 대해 실행됩니다. - 원시 페이로드를 검사하십시오. Apidog에서 동일한
messages+tools본문을https://api.deepseek.com으로 보내고 원시tool_callsJSON을 직접 읽어보십시오. 잘못 중첩된properties나 이중으로 인코딩된 인수가 한 번의 검사로 드러납니다. - 대화를 테스트 시나리오로 바꾸십시오.
finish_reason및 인수 형식을 단언하고, 모든 스키마 변경 시 스위트를 실행하십시오; Hacker News에서 보고된 하네스 민감도를 고려할 때, 실제 스키마에 대한 회귀 테스트 스위트는 프로덕션을 예측하는 벤치마크입니다. 더 심층적인 패턴은 AI 에이전트를 Apidog 테스트 하네스에 연결하기를 참조하십시오.
Apidog를 무료로 다운로드하여 따라해보세요; 모의 서버 및 테스트 시나리오는 무료 티어에 포함되어 있습니다.
에이전트 루프 비용 (그리고 캐싱이 결정하는 이유)
에이전트 루프는 매 라운드마다 전체 대화를 다시 읽습니다: 10라운드째에는 시스템 프롬프트, 도구 스키마, 그리고 9라운드의 결과가 열 번째로 청구됩니다. V4 Pro의 자동 접두사 캐싱은 이 곡선을 깨뜨립니다. 각 라운드의 입력은 이전 라운드에 조금 더 추가된 것이므로, 거의 전체 접두사가 $0.435/M 대신 $0.003625/M로 청구됩니다. 100K 토큰 대화를 다시 읽는 비용은 캐시되지 않은 경우 약 $0.0435이지만 캐시된 경우 약 $0.0004입니다; 사용량 블록의 prompt_cache_hit_tokens는 실제 캐시 히트율을 보여줍니다.
이 비율을 높게 유지하려면, 이전 메시지를 절대 변경하지 말고, tools 배열을 라운드 전체에서 바이트 단위로 안정적으로 유지하십시오. 프롬프트 캐싱이란 무엇인가에 대한 저희 입문서는 메커니즘을 다룹니다. 그리고 $0.14/$0.28의 deepseek-v4-flash가 매력적으로 보인다면: 단일 호출 도구 라우팅에는 좋지만, 10개 이상의 호출을 연결하는 루프에서는 성능이 저하되어 재시도가 절감 효과를 상쇄하므로, 에이전트에게는 Pro가 더 안전한 기본값입니다.
FAQ
도구 정의에 토큰 비용이 발생하나요?
예, tools 배열은 모든 요청의 입력입니다. 안정적으로 유지하면 첫 라운드 후 캐시된 접두사에 포함되어, 그 이후부터는 캐시 히트 요율로 청구됩니다.
함수 호출을 구조화된 출력과 결합할 수 있나요?
예. 일반적인 패턴은 다음과 같습니다: 도구가 중간 데이터를 가져오고, 구조화된 출력 스키마가 최종 답변을 형식화하여, 다운스트림 코드가 산문을 파싱할 필요가 없도록 합니다.
마무리
DeepSeek V4 Pro의 함수 호출 구현은 의도적으로 단순합니다: OpenAI 호환 스키마, tool_calls 배열, ID가 있는 tool 메시지. 5단계의 루프는 전체 아키텍처이며, 캐시 히트 가격 덕분에 대부분의 팀이 예상하는 것보다 저렴합니다. 벤치마크로는 모델이 사용자 스키마에 대해 어떻게 작동하는지 알 수 없으므로, 백엔드 API를 신중하게 설계하고, 일찍 모의(mock)하며, 스키마 변경이 에이전트를 조용히 망가뜨리지 않도록 Apidog에서 도구 호출 시나리오의 회귀 테스트 스위트를 유지하십시오.
