第 1 课
拿到 key 跑通首个请求:curl、Python、JavaScript 与计费
认清 deepseek-flash 与 deepseek-v4-pro,创建 API key,用 curl、Python、JavaScript 各发一次请求,查模型列表与余额,并看懂报错和峰谷计费。
课程目录第 1 / 3 课
学习位置仅保存在当前浏览器,有效期 180 天。
图文教材
本课按 DeepSeek 官方 首次调用 API、模型 & 价格、错误码、Lists Models 与 Get User Balance 整理(2026-10-22 核对);报错输出为 2026-10-22 实测,SDK 版本 openai 3.36.0(Python)。 目标:拿到 API key,用 curl、Python、JavaScript 各发一次请求,查清自己能用哪些模型、还剩多少余额,并看懂计费和常见报错。
你将得到什么
- 一个放在环境变量里的
DEEPSEEK_API_KEY - 一条能直接复制的 curl 请求,以及看懂响应字段的对照表
first_call.py与first_call.mjs两个可运行脚本- 查模型列表、查余额的两条命令,和一张常见报错表
一、先认清现在的两个模型名
2026 年 10 月 17 日 DeepSeek 发布 V4.1-Flash-1017,官方文档同时把 Flash 的调用名统一成 deepseek-flash。按官方「模型 & 价格」页,现在 API 只有两个模型名:
| 调用名 | 背后的模型版本 | 要点 |
|---|---|---|
deepseek-flash | DeepSeek-V4.1-Flash-1017 | 默认首选;支持图像理解;并发上限 2500 |
deepseek-v4-pro | DeepSeek-V4-Pro-0813 | 旗舰;不支持图像;并发上限 500 |
两者都是 1M 上下文、最大输出 384K,都默认开启思考模式,都支持 JSON 输出、工具调用、Anthropic 格式和 Responses API。
旧名 deepseek-v4-flash、deepseek-v4-flash-vision-exp 仍能调用,但官方已注明对应模型下线,请求实际由 V4.1-Flash-1017 处理、按 Flash 价格计费。新代码直接写 deepseek-flash。
二、创建 API key 并放进环境变量
- 打开 DeepSeek 开放平台 https://platform.deepseek.com/api_keys ,登录后点「创建 API key」,复制保存(只显示一次)。
- 在 https://platform.deepseek.com/top_up 充值。余额为 0 时请求会返回 402。
把 key 放进环境变量,后面所有命令都从这里读:
export DEEPSEEK_API_KEY="your-api-key"
Windows PowerShell 用 setx DEEPSEEK_API_KEY "your-api-key",然后重开终端。
key 只放环境变量或密钥管理器,不要写进代码、截图或提交到仓库。下文命令一律用
$DEEPSEEK_API_KEY引用你的 key;第五节故意写的not-a-real-key是假 key。
三、第一条 curl 请求
DeepSeek 用 OpenAI 兼容格式,OpenAI 格式的 base_url 是 https://api.deepseek.com。下面是官方首页的示例,开着思考模式、思考强度 high:
curl https://api.deepseek.com/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${DEEPSEEK_API_KEY}" \
-d '{
"model": "deepseek-flash",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Hello!"}
],
"thinking": {"type": "enabled"},
"reasoning_effort": "high",
"stream": false
}'
对照结果(官方 API 文档的示例响应;你的 id、时间戳和回答会不同,开着思考模式时 message 里还会多一个 reasoning_content 字段):
{
"id": "930c60df-bf64-41c9-a88e-3ec75f81e00e",
"choices": [
{
"finish_reason": "stop",
"index": 0,
"message": {
"content": "Hello! How can I help you today?",
"role": "assistant"
},
"logprobs": null
}
],
"created": 1705651092,
"model": "deepseek-flash",
"object": "chat.completion",
"system_fingerprint": "fp_7a09fdf9c2",
"usage": {
"completion_tokens": 10,
"prompt_tokens": 16,
"total_tokens": 26,
"prompt_tokens_details": {
"cached_tokens": 0
},
"prompt_cache_hit_tokens": 0,
"prompt_cache_miss_tokens": 16
}
}
| 字段 | 含义 |
|---|---|
choices[0].message.content | 最终回答 |
choices[0].finish_reason | stop 表示正常结束;length 表示被 max_tokens 截断 |
usage.prompt_cache_hit_tokens | 输入里命中硬盘缓存的 token,按缓存命中价计费 |
usage.prompt_cache_miss_tokens | 输入里未命中缓存的 token |
usage.completion_tokens | 输出 token |
想要流式输出,把 "stream": false 改成 true。
四、用 Python 和 JavaScript 各跑一次
官方 SDK 示例直接用 OpenAI 的 SDK,只改 base_url。
Python(Python 3.9+):
pip3 install openai
新建 first_call.py:
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ.get("DEEPSEEK_API_KEY"),
base_url="https://api.deepseek.com",
)
response = client.chat.completions.create(
model="deepseek-flash",
messages=[
{"role": "system", "content": "You are a helpful assistant"},
{"role": "user", "content": "Hello"},
],
stream=False,
reasoning_effort="high",
extra_body={"thinking": {"type": "enabled"}},
)
print(response.choices[0].message.content)
python3 first_call.py
对照结果:终端打印一句问候语,例如 Hello! How can I help you today?(措辞每次可能不同)。
注意 thinking 不是 OpenAI SDK 的标准参数,Python 里要放进 extra_body,这是官方文档的写法。
JavaScript(Node.js 18+):
npm install openai
新建 first_call.mjs:
import OpenAI from "openai";
const openai = new OpenAI({
baseURL: "https://api.deepseek.com",
apiKey: process.env.DEEPSEEK_API_KEY,
});
async function main() {
const completion = await openai.chat.completions.create({
messages: [{ role: "system", content: "You are a helpful assistant." }],
model: "deepseek-flash",
thinking: { type: "enabled" },
reasoning_effort: "high",
stream: false,
});
console.log(completion.choices[0].message.content);
}
main();
node first_call.mjs
对照结果:打印一段自我介绍或问候(只给了 system 消息,模型会主动打招呼)。
五、key 出错时长什么样
先认识报错,排错会快很多。下面三种情况都在 2026-10-22 实测过。
① 用假 key 调 curl:
curl -s https://api.deepseek.com/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer not-a-real-key" \
-d '{"model":"deepseek-flash","messages":[{"role":"user","content":"Hello!"}]}'
对照结果(HTTP 401,request_id 每次不同):
{"error":{"message":"Authentication Fails, Your api key: ****-key is invalid (request_id: 5b034c2f-92ef-416f-b019-43b5001243df)","type":"authentication_error","param":null,"code":"invalid_request_error"}}
② Python 脚本用假 key(DEEPSEEK_API_KEY=not-a-real-key python3 first_call.py),最后一行是:
openai.AuthenticationError: Error code: 401 - {'error': {'message': 'Authentication Fails, Your api key: ****-key is invalid (request_id: 1cbc1cdb-0587-4a43-be93-ec24cc2c509a)', 'type': 'authentication_error', 'param': None, 'code': 'invalid_request_error'}}
③ 忘了设置环境变量,Python SDK 在发请求前就会报:
openai.OpenAIError: Missing credentials. Please pass an `api_key`, `workload_identity`, `admin_api_key`, or set the `OPENAI_API_KEY` or `OPENAI_ADMIN_KEY` environment variable.
看到这句不要去设 OPENAI_API_KEY,检查 DEEPSEEK_API_KEY 有没有 export 到当前终端即可。
官方错误码表里最常见的几种:
| 状态码 | 原因 | 怎么办 |
|---|---|---|
| 400 | 请求体格式错误 | 按报错提示改请求体 |
| 401 | API key 错误 | 检查 key,或重新创建 |
| 402 | 余额不足 | 到 top_up 页面充值 |
| 422 | 参数错误 | 按报错提示改参数 |
| 429 | 请求太快或超过并发 | 降低频率;并发按账号计,与 key 无关 |
| 500 / 503 | 服务端错误或过载 | 稍等后重试 |
六、查模型列表和余额
这两个接口不消耗 token,适合做连通性自检。
curl -s https://api.deepseek.com/models \
-H "Authorization: Bearer $DEEPSEEK_API_KEY"
对照结果(官方 API 文档示例,已截短):
{
"object": "list",
"data": [
{
"id": "deepseek-flash",
"object": "model",
"owned_by": "deepseek",
"name": "DeepSeek-V4.1-Flash",
"context_window": 1048576,
"max_output_tokens": 393216,
"input_modalities": ["text", "image"],
"effort": { "supported_levels": ["low", "high", "max"], "default_level": "high" }
},
{
"id": "deepseek-v4-pro",
"object": "model",
"owned_by": "deepseek",
"name": "DeepSeek-V4-Pro",
"context_window": 1048576,
"max_output_tokens": 393216,
"input_modalities": ["text"],
"effort": { "supported_levels": ["low", "high", "max"], "default_level": "high" }
}
]
}
curl -s https://api.deepseek.com/user/balance \
-H "Authorization: Bearer $DEEPSEEK_API_KEY"
对照结果(官方示例;数字是你账号的实际余额):
{
"is_available": true,
"balance_infos": [
{
"currency": "CNY",
"total_balance": "110.00",
"granted_balance": "10.00",
"topped_up_balance": "100.00"
}
]
}
granted_balance 是赠送余额,topped_up_balance 是充值余额;两者都有时先扣赠送余额。
本课按 DeepSeek 官方 思考模式、JSON Output 与 Tool Calls 指南整理(2026-10-22 核对);代码沿用官方示例,只把 key 统一改为从环境变量读取。 目标:学会开关思考模式和调思考强度,读出思考内容并正确拼接多轮对话;让模型输出可直接解析的 JSON;写一个会自己调用函数、能跑多轮的工具循环。
你将得到什么
thinking_demo.py:同一个问题分别用「思考」和「不思考」跑一次json_demo.py:把一段文本解析成严格 JSONtool_loop.py:思考模式下的多轮工具调用循环,以及官方给出的逐轮对照输出
先修:已完成第 1 课,DEEPSEEK_API_KEY 已在环境变量中,已 pip3 install openai。
一、思考模式的开关与强度
两个模型都默认开启思考模式,默认强度 high。OpenAI 格式下用两个参数控制:
| 作用 | 参数 | 取值 |
|---|---|---|
| 开关思考 | thinking | {"type": "enabled"} 或 {"type": "disabled"} |
| 思考强度 | reasoning_effort | low / high / max |
官方还说明了几条容易踩的坑:
- 其他工具传来的强度会被映射:
minimal按low,medium和xhigh按high,ultra按max。 - 思考模式下
temperature、presence_penalty、frequency_penalty不生效(传了不报错,但没有效果)。 - 用 OpenAI 的 Python SDK 时,
thinking要放进extra_body。
新建 thinking_demo.py:
import os
from openai import OpenAI
client = OpenAI(api_key=os.environ["DEEPSEEK_API_KEY"], base_url="https://api.deepseek.com")
question = [{"role": "user", "content": "9.11 and 9.8, which is greater?"}]
# 1) 思考模式:先输出思维链 reasoning_content,再输出最终回答 content
r1 = client.chat.completions.create(
model="deepseek-flash",
messages=question,
reasoning_effort="high",
extra_body={"thinking": {"type": "enabled"}},
)
print("== thinking ==")
print("reasoning_content:", r1.choices[0].message.reasoning_content[:200], "...")
print("content:", r1.choices[0].message.content)
# 2) 非思考模式:直接回答,更快、更省 token
r2 = client.chat.completions.create(
model="deepseek-flash",
messages=question,
extra_body={"thinking": {"type": "disabled"}},
)
print("== non-thinking ==")
print("content:", r2.choices[0].message.content)
print("tokens:", r1.usage.completion_tokens, "vs", r2.usage.completion_tokens)
python3 thinking_demo.py
对照结果(结构如下,具体文字每次不同):
== thinking ==
reasoning_content: (一段英文推理:比较小数部分 0.11 和 0.8 ……)...
content: 9.8 is greater than 9.11 ...
== non-thinking ==
content: 9.8 is greater than 9.11 ...
tokens: (较大的数) vs (较小的数)
最后一行能直观看到:思考模式输出的 token 明显更多。简单问答、分类、改写可以关掉思考省钱;数学、代码、多步规划保持开启。
二、多轮对话:思考内容要不要传回去
思维链在 reasoning_content 字段里,和 content 同级。下一轮要不要把它传回去,取决于请求里有没有 tools 参数:
| 请求情况 | reasoning_content 怎么处理 |
|---|---|
不带 tools | 不需要传回;传了也会被忽略,不拼进上下文 |
带 tools | 之前所有轮次的都必须完整传回,否则返回 400 |
不带工具时,官方示例的第二轮写法是直接把上一轮的 message 追加进去:
messages.append(response.choices[0].message)
messages.append({"role": "user", "content": "How many Rs are there in the word 'strawberry'?"})
response = client.chat.completions.create(
model="deepseek-flash",
messages=messages,
reasoning_effort="high",
extra_body={"thinking": {"type": "enabled"}},
)
response.choices[0].message 里已经含有 content、reasoning_content(以及有工具调用时的 tool_calls),直接 append 最省事,带不带工具都不会错。
三、JSON Output:让模型只输出合法 JSON
官方要求同时做到四点:
- 设置
response_format={"type": "json_object"}; - system 或 user 提示词里出现 "json" 这个词,并给出期望格式的示例;
max_tokens设得够大,避免 JSON 被截断;- 官方提示该功能偶尔会返回空 content,可通过调整提示词缓解。
新建 json_demo.py(官方示例):
import json
import os
from openai import OpenAI
client = OpenAI(api_key=os.environ["DEEPSEEK_API_KEY"], base_url="https://api.deepseek.com")
system_prompt = """
The user will provide some exam text. Please parse the "question" and "answer" and output them in JSON format.
EXAMPLE INPUT:
Which is the highest mountain in the world? Mount Everest.
EXAMPLE JSON OUTPUT:
{
"question": "Which is the highest mountain in the world?",
"answer": "Mount Everest"
}
"""
user_prompt = "Which is the longest river in the world? The Nile River."
messages = [{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}]
response = client.chat.completions.create(
model="deepseek-flash",
messages=messages,
response_format={"type": "json_object"},
)
print(json.loads(response.choices[0].message.content))
python3 json_demo.py
对照结果(官方文档给出的模型输出):
{
"question": "Which is the longest river in the world?",
"answer": "The Nile River"
}
终端里打印的是 Python 字典:{'question': 'Which is the longest river in the world?', 'answer': 'The Nile River'}。如果 json.loads 报错或 content 为空,按第 4 点调整提示词后重试。
四、工具调用:让模型自己决定调哪个函数
模型本身不执行函数,它只返回「想调用哪个函数、参数是什么」,由你的代码执行后把结果以 role: "tool" 消息交回去,直到模型不再要求调用工具、给出最终回答。
下面是官方「思考模式 + 工具调用」示例,两个函数用假数据模拟。新建 tool_loop.py:
import os
import json
from datetime import datetime
from openai import OpenAI
tools = [
{
"type": "function",
"function": {
"name": "get_date",
"description": "Get the current date",
"parameters": {"type": "object", "properties": {}},
},
},
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get weather of a location, the user should supply the location and date.",
"parameters": {
"type": "object",
"properties": {
"location": {"type": "string", "description": "The city name"},
"date": {"type": "string", "description": "The date in format YYYY-mm-dd"},
},
"required": ["location", "date"],
},
},
},
]
def get_date_mock():
return datetime.now().strftime("%Y-%m-%d")
def get_weather_mock(location, date):
return "Cloudy 7~13°C"
TOOL_CALL_MAP = {"get_date": get_date_mock, "get_weather": get_weather_mock}
def run_turn(turn, messages):
sub_turn = 1
while True:
response = client.chat.completions.create(
model="deepseek-flash",
messages=messages,
tools=tools,
reasoning_effort="high",
extra_body={"thinking": {"type": "enabled"}},
)
# 整条 message 追加回去:带 tools 时 reasoning_content 必须传回
messages.append(response.choices[0].message)
reasoning_content = response.choices[0].message.reasoning_content
content = response.choices[0].message.content
tool_calls = response.choices[0].message.tool_calls
print(f"Turn {turn}.{sub_turn}\n{reasoning_content=}\n{content=}\n{tool_calls=}")
if tool_calls is None: # 没有工具调用 = 已给出最终回答
break
for tool in tool_calls:
tool_function = TOOL_CALL_MAP[tool.function.name]
tool_result = tool_function(**json.loads(tool.function.arguments))
print(f"tool result for {tool.function.name}: {tool_result}\n")
messages.append({"role": "tool", "tool_call_id": tool.id, "content": tool_result})
sub_turn += 1
print()
client = OpenAI(api_key=os.environ["DEEPSEEK_API_KEY"], base_url="https://api.deepseek.com")
messages = [{"role": "user", "content": "How's the weather in Hangzhou Tomorrow"}]
run_turn(1, messages)
messages.append({"role": "user", "content": "How's the weather in Guangzhou Tomorrow"})
run_turn(2, messages)
python3 tool_loop.py
对照结果(官方文档的样例输出,已删去 Turn 1.3 与 Turn 2.2 回答正文中的部分修饰语;日期是官方运行当天,你看到的是你的「明天」):
Turn 1.1
reasoning_content="The user is asking about the weather in Hangzhou tomorrow. I need to get tomorrow's date first, then call the weather function."
content="Let me check tomorrow's weather in Hangzhou for you. First, let me get tomorrow's date."
tool_calls=[ChatCompletionMessageFunctionToolCall(id='call_00_kw66qNnNto11bSfJVIdlV5Oo', function=Function(arguments='{}', name='get_date'), type='function', index=0)]
tool result for get_date: 2026-04-19
Turn 1.2
reasoning_content="Today is 2026-04-19, so tomorrow is 2026-04-20. Now I'll call the weather function for Hangzhou."
content=''
tool_calls=[ChatCompletionMessageFunctionToolCall(id='call_00_H2SCW6136vWJGq9SQlBuhVt4', function=Function(arguments='{"location": "Hangzhou", "date": "2026-04-20"}', name='get_weather'), type='function', index=0)]
tool result for get_weather: Cloudy 7~13°C
Turn 1.3
reasoning_content='The weather result is in. Let me share this with the user.'
content="Here's the weather forecast for **Hangzhou tomorrow (April 20, 2026)**: ..."
tool_calls=None
Turn 2.1
reasoning_content='The user is asking about the weather in Guangzhou tomorrow. Today is 2026-04-19, so tomorrow is 2026-04-20. I can directly call the weather function.'
content=''
tool_calls=[ChatCompletionMessageFunctionToolCall(id='call_00_8URkLt5NjmNkVKhDmMcNq9Mo', function=Function(arguments='{"location": "Guangzhou", "date": "2026-04-20"}', name='get_weather'), type='function', index=0)]
tool result for get_weather: Cloudy 7~13°C
Turn 2.2
reasoning_content='The weather result for Guangzhou is the same as Hangzhou. Let me share this with the user.'
content="Here's the weather forecast for **Guangzhou tomorrow (April 20, 2026)**: ..."
tool_calls=None
读这段输出要看三件事:
- Turn 1 里模型先调
get_date拿到今天日期,再调get_weather,说明它会自己规划调用顺序; - Turn 2 没有再调
get_date,因为第一轮的推理已经在上下文里(这正是带 tools 时必须传回reasoning_content的原因); tool_calls=None时循环结束,content就是最终回答。
五、两个进阶开关(按需)
- strict 模式(Beta):要求工具参数严格符合你定义的 JSON Schema。用法是把
base_url改成https://api.deepseek.com/beta,并给每个 function 加"strict": true。思考和非思考模式都支持。 - 非思考模式调工具:只把
extra_body改成{"thinking": {"type": "disabled"}},其余写法相同,适合对延迟敏感、逻辑简单的工具调用。
本课检查清单
-
thinking_demo.py两种模式都给出了正确答案,且能看出 token 差异 -
json_demo.py打印出含question和answer的字典 -
tool_loop.py跑出了与对照结果同样结构的 Turn 1.1–1.3、2.1–2.2 - 能说清楚:什么情况下必须把
reasoning_content传回
下一课:把 DeepSeek 接进 Claude Code 当编码 Agent 的大脑,再用官方 Search / Fetch 接口给自己的应用加上联网能力。
七、算清楚费用:峰谷价与缓存
官方价格按每百万 tokens 计,空闲时段是高峰时段的一半。高峰时段为北京时间周一至周五(不含法定节假日)9:00–12:00、14:00–18:00,其余时间(含周末、节假日全天)都是空闲时段。
| 每百万 tokens | deepseek-flash | deepseek-v4-pro |
|---|---|---|
| 输入·缓存命中(高峰 / 空闲) | 0.04 元 / 0.02 元 | 0.30 元 / 0.15 元 |
| 输入·缓存未命中(高峰 / 空闲) | 2 元 / 1 元 | 9 元 / 4.5 元 |
| 输出(高峰 / 空闲) | 8 元 / 4 元 | 27 元 / 13.5 元 |
两点实用结论:
- 批量任务尽量放到晚上或周末跑,价格直接减半。
- 硬盘缓存默认开启、不用改代码:多轮对话或反复用同一段长文档提问时,重复的前缀按缓存命中价计费,看响应里的
prompt_cache_hit_tokens就知道省了多少。
本课检查清单
-
echo $DEEPSEEK_API_KEY能看到你的 key - curl、
first_call.py、first_call.mjs都打印出了回答 -
/models返回了deepseek-flash和deepseek-v4-pro - 认得 401 / 402 / 429 三种报错
下一课:打开和关闭思考模式、读出思考内容,让模型输出严格 JSON,并写一个会自己调用函数的工具循环。
