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。
- 價格為每 1M 輸入 token $0.15,每 1M 輸出 token $0.50。
安裝並發送第一個請求
此服務並非官方的 DeepSeek API。它是一個託管的 OpenAI 相容端點,運行單一開放權重模型,ID 為 uncensored,由獨立供應商營運。由於它遵循 OpenAI 格式,標準 Python SDK 僅需修改 URL 和金鑰即可運作。
pip install openai
從 API 金鑰頁面取得金鑰。註冊後,你可以按一下即可領取 $0.50 的免費試用額度,無需信用卡,有效期 7 天。將金鑰儲存在環境變數中,而非原始碼檔案中:
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)
這兩個用量數字是你計費的依據。將它們乘以價格即可得知任何呼叫的成本:輸入 token 數乘以 $0.15,輸出 token 數乘以 $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 中的一小段文字。要求用量意味著最後一個區塊會報告 token 計數。
# 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"])
請將 try/except 包在 json.loads 周圍。若回覆因 token 限制被截斷則無法解析,因此避免對 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。錯誤程式碼會告知是哪種限制:rate_limited 代表每分鐘請求數(完整金鑰為 300,試用金鑰為 60),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."))
每個回合都會重新傳送所有內容,因此輸入 token 數會隨著回合增加。一旦列表變長,請刪除舊訊息,或要求模型摘要早期部分並取代它。雖然 100,000-token 上下文視窗空間充足,但帳單會隨著歷史記錄增長,因此修剪過的列表成本更低。
選擇採樣值
程式碼和提取請使用 temperature 0 到 0.3,一般聊天約為 0.7,小說則更高。top_p、stop、seed 以及頻率和存在懲罰都會被傳遞,因此行為與 OpenAI 文件所述一致。一次只更改一項並進行比較。
規劃成本與上下文
上下文視窗為 100,000 個 token(包含提示詞與完成內容),請求主體限制為 8 MB。完成內容可使用視窗剩餘的任何空間,max_tokens 是可選的。為批次作業設定它仍是良好的實踐。
一個實作範例:1,000 個摘要的批次,每個包含 1,500 個輸入 token 和 200 個輸出 token。
- 輸入:1,000 × 1,500 = 1,500,000 個 token,即 1.5 × $0.15 = $0.225
- 輸出:1,000 × 200 = 200,000 個 token,即 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,並加入包含 include_usage 的 stream_options,以便在最後一個區塊取得 token 計數。
我該如何處理 429 錯誤?
捕獲 openai.RateLimitError,讀取 Retry-After 標頭,並在重試前等待。錯誤程式碼會告知是速率限制還是並行限制。
我可以先測試再付費嗎?
是的。註冊後,在 API 金鑰頁面按一下即可獲得 $0.50 的免費試用額度,有效期 7 天,無需信用卡。