DeepSeek API Python 예제: 채팅, 스트리밍, 도구
DeepSeek API Python 설정에는 공식 OpenAI 패키지, Base URL, 키 및 모델 ID만 필요합니다. 아래 예시는 일반 요청, 스트리밍, JSON 모드, 함수 호출 및 재시도를 다룹니다. 모든 예시는 OpenAI 호환 엔드포인트를 대상으로 합니다.

주요 포인트
- openai를 설치한 후 base_url을 https://api.deepseekapi.top/v1로 설정하고 모델을 uncensored로 설정합니다.
- 스트리밍, JSON 모드 및 도구 호출은 일반 SDK 매개변수를 통해 작동합니다.
- Retry-After를 읽고 다시 시도하여 HTTP 429를 처리합니다.
- 가격은 입력 토큰 100만 개당 $0.15, 출력 토큰 100만 개당 $0.50입니다.
설치 및 첫 번째 요청 보내기
이 서비스는 공식 DeepSeek API가 아닙니다. 독립적인 제공자가 운영하는 하나의 오픈 웨이트 모델(ID uncensored)을 실행하는 호스팅된 OpenAI 호환 엔드포인트입니다. OpenAI 형식을 따르므로 URL과 키 외에 표준 Python SDK가 변경 없이 작동합니다.
pip install openai
API 키 페이지에서 키를 얻으세요. 가입 후 카드를 사용하지 않고 한 번의 클릭으로 7일 유효한 $0.50의 무료 체험 크레딧을 청구할 수 있습니다. 키를 소스 파일이 아닌 환경 변수에 저장하세요:
export API_KEY="YOUR_KEY"
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.deepseekapi.top/v1",
api_key=os.environ["API_KEY"],
)
resp = client.chat.completions.create(
model="uncensored",
messages=[
{"role": "system", "content": "You are a concise assistant."},
{"role": "user", "content": "Explain list comprehensions in two sentences."},
],
temperature=0.7,
)
print(resp.choices[0].message.content)
print(resp.usage.prompt_tokens, resp.usage.completion_tokens)
두 사용량 숫자가 청구 기준입니다. 가격에 곱하여 호출 비용을 확인하세요: 입력 토큰 × $0.15 및 출력 토큰 × $0.50, 각각 1,000,000으로 나눕니다.
비동기 클라이언트 사용
웹 서버 및 많은 사용자를 처리하는 경우 비동기 클라이언트를 사용하세요. 동기식 클라이언트와 동일한 매개변수를 가지며 대부분의 코드에서 대체 가능한 변경입니다.
import asyncio
import os
from openai import AsyncOpenAI
client = AsyncOpenAI(
base_url="https://api.deepseekapi.top/v1",
api_key=os.environ["API_KEY"],
)
sem = asyncio.Semaphore(8)
async def ask(prompt):
async with sem:
r = await client.chat.completions.create(
model="uncensored",
messages=[{"role": "user", "content": prompt}],
)
return r.choices[0].message.content
async def main():
prompts = ["Define idempotent.", "Define monotonic.", "Define pure function."]
answers = await asyncio.gather(*(ask(p) for p in prompts))
for a in answers:
print(a)
asyncio.run(main())
세마포어는 전체 키의 동시성인 8로 설정됩니다. 체험 키의 경우 2를 사용하세요. 제한 없이 작업이 급증하면 각 요청이 유효하더라도 concurrency 오류가 발생할 수 있습니다.
스트리밍 응답
stream=True를 설정하면 엔드포인트가 서버 전송 이벤트를 보냅니다. 각 청크는 delta.content에 작은 텍스트 조각을 포함합니다. 사용량을 요청하면 마지막 청크가 토큰 개수를 보고합니다.
# client = OpenAI(base_url="https://api.deepseekapi.top/v1", ...) as above
stream = client.chat.completions.create(
model="uncensored",
messages=[{"role": "user", "content": "Write a haiku about debugging."}],
stream=True,
stream_options={"include_usage": True},
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
if chunk.usage:
print("\n", chunk.usage.prompt_tokens, chunk.usage.completion_tokens)
두 가지 세부 사항에서 실수가 자주 발생합니다. 마지막 사용량 청크에는 빈 choices 목록이 있을 수 있으므로 루프에서 먼저 chunk.choices을 확인합니다. 스트리밍 요청은 스트림이 끝날 때까지 동시성 슬롯을 유지하므로 루프를 깨끗하게 종료하고 버린 스트림을 닫으세요. 전체 키는 8개의 동시 요청을 허용하며, 체험 키는 2개를 허용합니다.
JSON 모드
프로그램이 구문 분석할 출력의 경우 response_format을 json_object과 함께 사용하세요. 프롬프트에 JSON이라는 단어를 명시하고 원하는 형태를 설명하세요. 모델에는 해당 지침이 필요합니다. 플래그만으로는 스키마가 제공되지 않습니다.
# client = OpenAI(base_url="https://api.deepseekapi.top/v1", ...) as above
import json
resp = client.chat.completions.create(
model="uncensored",
messages=[
{"role": "system", "content": "Reply with JSON only: {\"title\": str, \"tags\": [str]}"},
{"role": "user", "content": "Summarize: a guide to caching HTTP responses."},
],
response_format={"type": "json_object"},
temperature=0,
)
data = json.loads(resp.choices[0].message.content)
print(data["title"], data["tags"])
json.loads를 try/except로 감싸세요. 토큰 제한으로 인해 응답이 잘리면 구문 분석되지 않으므로 JSON에 작은 max_tokens을 설정하지 마세요. temperature을 0으로 설정하고 seed을 사용하면 둘 다 전달되므로 재실행이 더 반복 가능해집니다.
함수 호출
API는 tools 및 tool_choice을 받아들이며 어시스턴트 메시지에 tool_calls을 반환합니다. 함수를 직접 실행하고 role: "tool" 메시지로 결과를 다시 전송합니다.
# client = OpenAI(base_url="https://api.deepseekapi.top/v1", ...) as above
import json
tools = [{
"type": "function",
"function": {
"name": "add",
"description": "Add two numbers.",
"parameters": {
"type": "object",
"properties": {"a": {"type": "number"}, "b": {"type": "number"}},
"required": ["a", "b"],
},
},
}]
messages = [{"role": "user", "content": "What is 17.5 plus 24.25?"}]
first = client.chat.completions.create(
model="uncensored", messages=messages, tools=tools, tool_choice="auto"
)
msg = first.choices[0].message
if msg.tool_calls:
messages.append(msg)
for call in msg.tool_calls:
args = json.loads(call.function.arguments)
result = args["a"] + args["b"]
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": str(result),
})
final = client.chat.completions.create(
model="uncensored", messages=messages, tools=tools
)
print(final.choices[0].message.content)
else:
print(msg.content)
arguments를 항상 방어적으로 구문 분석하세요. 이는 모델이 생성한 JSON 문자열이며 잘못된 문자열이 발생할 수 있습니다. 파일이나 데이터베이스에 접근하는 함수의 경우 특히 유효성을 검사한 후 실행하세요.
오류, 제한 및 재시도
제한을 초과하는 요청은 HTTP 429를 반환합니다. 오류 코드로 다음 제한을 알 수 있습니다: 분당 요청 수(전체 키는 300, 체험 키는 60)에 대한 rate_limited 및 동시성(너무 많은 요청)에 대한 concurrency. 일시적 과부하 시에도 Retry-After: 5와 함께 429를 받습니다. SDK는 openai.RateLimitError를 발생시킵니다.
# client = OpenAI(base_url="https://api.deepseekapi.top/v1", ...) as above
import time
import openai
def ask(prompt, tries=4):
for attempt in range(tries):
try:
r = client.chat.completions.create(
model="uncensored",
messages=[{"role": "user", "content": prompt}],
)
return r.choices[0].message.content
except openai.RateLimitError as e:
wait = int(e.response.headers.get("Retry-After", 5))
time.sleep(wait * (attempt + 1))
raise RuntimeError("still rate limited")
print(ask("Name three Python web frameworks."))
많은 요청을 보내는 경우 세마포어 또는 8개의 작업자 스레드 풀로 자체 동시성을 제한하세요(체험 키의 경우 2). 이렇게 하면 재시도로 버티는 대신 concurrency 오류를 처음부터 피할 수 있습니다.
헤더 읽기
각 응답에는 X-Request-Id, X-Balance-USD, X-RateLimit-Limit-Requests 및 X-RateLimit-Limit-Concurrency이 포함됩니다. SDK는 원본 응답을 통해 이를 노출합니다:
# client = OpenAI(base_url="https://api.deepseekapi.top/v1", ...) as above
raw = client.chat.completions.with_raw_response.create(
model="uncensored",
messages=[{"role": "user", "content": "ping"}],
)
print(raw.headers.get("X-Balance-USD"), raw.headers.get("X-Request-Id"))
completion = raw.parse()
모든 실패에 요청 ID를 로깅하면 지원 문의 답변이 훨씬 쉬워집니다. 실패하거나 거부된 요청에는 요금이 부과되지 않습니다.
대화 유지하기
API는 상태가 없습니다. 이전 요청을 기억하지 않으므로 다중 턴 채팅은 매번 전체 이력을 전송해야 함을 의미합니다. 목록을 유지하고 여기에 추가하세요:
# client = OpenAI(base_url="https://api.deepseekapi.top/v1", ...) as above
history = [{"role": "system", "content": "You are a helpful tutor."}]
def chat(user_text):
history.append({"role": "user", "content": user_text})
r = client.chat.completions.create(model="uncensored", messages=history)
reply = r.choices[0].message.content
history.append({"role": "assistant", "content": reply})
return reply
print(chat("What is a closure?"))
print(chat("Show me one in Python."))
각 턴은 모든 내용을 다시 보내므로 입력 토큰은 턴마다 증가합니다. 목록이 길어지면 오래된 메시지를 정리하거나 모델에 초기 부분을 요약하도록 요청하여 대체하세요. 100,000개의 토큰 컨텍스트 창이 있으므로 여유가 있지만 이력이 늘어나면 요금이 증가하므로 정리된 목록이 더 저렴합니다.
샘플링 값 선택
코드 및 추출에는 temperature 0~0.3, 일반 채팅에는 약 0.7, 소설에는 더 높은 값을 사용하세요. top_p, stop, seed 및 빈도 및 존재 패널티는 전달되므로 OpenAI 설명서에서 설명하는 대로 동작합니다. 한 번에 하나씩 변경하고 비교하세요.
비용 및 컨텍스트 계획
컨텍스트 창은 프롬프트 및 완성문을 합쳐 100,000개의 토큰이며 요청 본문 크기 제한은 8 MB입니다. 완성문은 창의 남은 부분을 모두 사용할 수 있으며 max_tokens은 선택 사항입니다. 배치 작업의 경우 설정하는 것이 여전히 좋은 관행입니다.
작업 예시: 1,000개의 요약문 배치, 각 항목은 1,500개의 입력 토큰과 200개의 출력 토큰 포함
- 입력: 1,000 × 1,500 = 1,500,000 토큰, 이는 1.5 × $0.15 = $0.225
- 출력: 1,000 × 200 = 200,000 토큰, 이는 0.2 × $0.50 = $0.10
- 합계: $0.325
요금은 선불 크레딧에서 사용한 만큼 차감되며 구독이 없으며 크레딧은 만료되지 않습니다. 충전은 $20부터 $500까지 전체 금액으로 이루어지며, $50부터 +5%, $100부터 +10%, $200부터 +15% 보너스가 제공되며 카드 또는 암호화폐로 결제할 수 있습니다. 가격 페이지 및 curl 및 Node 예제에 대한 빠른 시작 문서를 참조하세요. 키 위치만 확인해야 하는 경우 API 키 개요를 참조하세요.
프롬프트는 학습에 사용되지 않습니다. 이 서비스는 텍스트 전용입니다: 이미지, 오디오, 임베딩 또는 파인튜닝이 없으므로 해당 엔드포인트를 계획에 포함하지 마세요.
더 많은 가이드
질문과 답변
특별한 DeepSeek 라이브러리가 필요한가요?
아니요. openai 패키지를 설치하고 base_url을 https://api.deepseekapi.top/v1로 설정한 후 모델 ID uncensored를 사용하세요. 이는 공식 DeepSeek API가 아닙니다.
Python SDK에서 스트리밍을 지원하나요?
네. stream=True를 전달하고 stream_options에 include_usage를 추가하여 마지막 청크에서 토큰 수를 확인하세요.
429 오류를 어떻게 처리하나요?
openai.RateLimitError를 캐치하고 Retry-After 헤더를 읽은 후 재시도 전에 대기하세요. 오류 코드로 속도 제한 또는 동시성 문제인지 알 수 있습니다.
결제 없이 테스트할 수 있습니까?
네. 가입 후 API 키 페이지에서 한 번의 클릭으로 7일 유효한 $0.50의 무료 체험 크레딧이 추가되며, 카드가 필요하지 않습니다.