← 全部极客知识库

大模型通识 / 大模型应用开发入门

1. 从聊天窗口到 API:完成第一次 DeepSeek 调用

原文备份 · 第 3 / 19 篇 · 查看极客时间原知识库 ↗

本篇目录 · 8 节

来源:大模型应用开发入门

你在网页里输入一段笔记,DeepSeek 能告诉你第二章改到了周六。现在,你希望自己写的程序也能做这件事:读取输入,发送请求,接收回答,再把结果交给后续页面或功能。

这就是本部分的起点。今天先完成一个很小但完整的闭环:运行一份 Python 脚本,向 DeepSeek 官方 API 发送一条短请求,把响应保存到本地,并独立核对答案。

不需要先读完前两部分,也不需要先学习框架。你需要一台能上网的电脑、Python 3.11 或更新的稳定版,以及自己的 DeepSeek 开放平台账户。真正发送请求可能产生 API 费用;本文先提供一个不读取密钥、不联网的预演步骤。

代码已做本地语法和模拟响应测试,未使用个人密钥进行真实付费调用。文中的示例回答用于说明预期形式,不是线上实测记录。

一、聊天产品、模型和 API,分别负责什么

聊天产品已经替你做好输入框、历史记录和回答展示。API 则是程序与模型服务交换数据的接口。通过 API,你要明确告诉服务:“这次用哪个模型、有哪些消息、怎样返回结果。”

本例的路径是:

flowchart LR
    A[你的 Python 程序] -->|HTTPS请求:消息和参数| B[DeepSeek 官方 API]
    B --> C[模型生成]
    C -->|JSON响应| A
    A --> D[终端显示与本地响应文件]

Python 程序在你的电脑上运行,模型仍在远端服务运行。这不要求你的电脑有能装下大模型的显卡,也不等于把模型权重下载到本机。

先认识四个值:

项目 本篇使用的值或含义
服务基础地址 https://api.deepseek.com
本次操作路径 /chat/completions,用于本例的聊天生成
模型标识 deepseek-flash,让服务选择模型
API Key 你自己的访问凭据,不能用聊天密码代替

截至 2026 年 10 月 4 日,官方首次调用文档列出的 Flash 调用标识是 deepseek-flash。不要从旧教程复制模型名后假定它一直有效;阅读本篇较晚时,应先核对官方文档。DeepSeek:首次 API 调用

这里采用兼容 OpenAI 格式的聊天接口。请求仍发给 DeepSeek,凭据也必须来自 DeepSeek;“协议兼容”不是把两个平台的账户或余额连在一起。本篇直接用 Python 标准库发送 HTTP 请求,下一篇再用 SDK 整理项目。

二、准备自己的账户和凭据

打开 DeepSeek 开放平台,登录自己的账户,找到 API Keys(API 密钥)管理入口,创建一枚用于本课程的密钥。界面名称和布局可能调整,入口用途是管理供程序调用的访问凭据。

再检查平台显示的可用余额和 官方价格页。没有可用余额时,按自己愿意承担的预算决定是否充值;本文不要求固定充值金额,也不假设账户一定有赠送额度。API 用量由平台按规则扣费,不能仅凭聊天页面可以使用,就判断程序调用也免费。

本篇只发一次很短的文本请求,并限制输出长度。密钥在程序运行时通过隐藏输入读取,不需要贴进代码、聊天记录或截图。请把密钥保存在自己使用的密码管理工具等安全位置;程序运行时再粘贴。

如果把密钥误发给他人或提交进公开仓库,应在平台撤销并重新创建。删除截图或最新一行代码,不会让已经泄露的密钥重新安全。

三、确认电脑能运行 Python

先在系统终端检查版本。macOS 打开“终端”,Windows 打开 PowerShell;不要把下面的命令粘贴进出现 >>> 的 Python 交互窗口。

macOS / Linux:

python3 --version

Windows PowerShell:

py -3 --version

看到 Python 3.11.x、3.12.x 等不低于 3.11 的稳定版即可。本文代码在 Python 3.11.8 上完成本地检查;不要求安装某一个完全相同的小版本。

如果命令不存在,按对应平台处理:

  • macOS:从 Python 官方下载页 选择稳定版 macOS 安装包,打开 .pkg 完成安装;重新打开终端,再检查 python3 --version。如后续遇到证书验证问题,官方安装包的 Python 文件夹提供 Install Certificates.command,可按 macOS 官方说明安装证书,不要改成跳过 HTTPS 验证。
  • Windows:从同一官方下载页进入 Windows 安装入口,按官方安装方式安装稳定版。重新打开 PowerShell,检查 py -3 --version;若仅 python --version 能正常显示所需版本,后续将 py -3 换成 python。安装与命令发现问题可对照 Windows 官方说明。
  • Linux:先检查发行版自带的 python3。Ubuntu / Debian 缺少时可用下方命令安装,再检查版本;若发行版提供的版本低于 3.11,需按该发行版支持的方式安装较新版本,不要直接替换系统依赖的解释器。

仅 Ubuntu / Debian 安装命令:

sudo apt update
sudo apt install python3
python3 --version

本篇只使用标准库,不需要执行 pip install。能显示正确版本,是继续之前的第一项检查。

四、保存一份可以直接运行的脚本

在你容易找到的位置创建一个空文件夹 deepseek-notes。用代码编辑器在里面新建 first_call.py,保存为 UTF-8。文件名应以 .py 结尾,不要误存成 first_call.py.txt。

你也可以下载现成的 first_call.py,放进这个文件夹。以下代码与下载文件一致:

"""Lesson 01: one DeepSeek request; --dry-run never reads a key or uses the network."""
import argparse
import getpass
import json
from pathlib import Path
from datetime import datetime
import urllib.error
import urllib.request
import warnings

ENDPOINT = "https://api.deepseek.com/chat/completions"
MODEL = "deepseek-flash"


def make_payload():
    return {
        "model": MODEL,
        "messages": [
            {"role": "system", "content": "你是复习助手。仅依据用户提供的笔记回答;缺少信息就说明缺少。"},
            {"role": "user", "content": "笔记:第二章原定周五,现改为周六复习。问题:现在安排在哪天?只回答日期表达,不补充几点。"},
        ],
        "thinking": {"type": "disabled"},
        "stream": False,
        "max_tokens": 256,
    }


def main():
    parser = argparse.ArgumentParser(description="一次 DeepSeek API 调用")
    parser.add_argument("--dry-run", action="store_true", help="只看请求,不读取密钥、不联网")
    args = parser.parse_args()
    payload = make_payload()
    if args.dry_run:
        print("POST", ENDPOINT)
        print(json.dumps(payload, ensure_ascii=False, indent=2))
        return 0

    try:
        with warnings.catch_warnings():
            warnings.simplefilter("error", getpass.GetPassWarning)
            key = getpass.getpass("粘贴 DeepSeek API Key(不显示),然后回车:").strip()
    except (getpass.GetPassWarning, EOFError):
        print("无法隐藏输入。请在系统终端中运行,不要把密钥写入代码。")
        return 1
    if not key:
        print("未输入密钥,未发送请求。")
        return 1

    request = urllib.request.Request(
        ENDPOINT,
        data=json.dumps(payload, ensure_ascii=False).encode("utf-8"),
        headers={"Content-Type": "application/json", "Authorization": "Bearer " + key},
        method="POST",
    )
    try:
        with urllib.request.urlopen(request, timeout=60) as response:
            status = response.status
            raw = response.read().decode("utf-8")
        data = json.loads(raw)
    except urllib.error.HTTPError as exc:
        print(f"HTTP {exc.code}:请求未成功,请按文章的错误表检查;本程序不会自动重试。")
        return 1
    except (urllib.error.URLError, TimeoutError):
        print("网络连接、证书或等待响应出错;未确认完成,不自动重试。")
        return 1
    except (UnicodeDecodeError, json.JSONDecodeError):
        print("响应不是预期的 UTF-8 JSON。请核对官方地址和网络环境。")
        return 1

    output = Path(__file__).resolve().parent / "responses"
    output.mkdir(exist_ok=True)
    path = output / (datetime.now().strftime("response-%Y%m%d-%H%M%S-%f") + ".json")
    path.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")
    print("HTTP", status)
    print("响应保存到:", path)
    try:
        choice = data["choices"][0]
        answer = choice["message"]["content"]
        finish = choice["finish_reason"]
        if not isinstance(answer, str) or not answer.strip():
            raise ValueError("empty content")
    except (KeyError, IndexError, TypeError, ValueError):
        print("缺少有效回答,请查看响应文件;HTTP 成功不等于内容可用。")
        return 1
    print("回答:", answer)
    print("结束原因:", finish)
    print("用量:", json.dumps(data.get("usage", {}), ensure_ascii=False))
    if finish != "stop":
        print("本次不是正常 stop 结束;不要直接当成完整答案。")
        return 1
    return 0


if __name__ == "__main__":
    try:
        raise SystemExit(main())
    except KeyboardInterrupt:
        print("\n已中断;若请求已发出,不能据此断定服务端没有处理或计费。")
        raise SystemExit(130)

代码看起来不短,是因为它同时交代了读取密钥、处理常见失败和保存结果。你暂时不需要背下每一行,先沿着三个部分理解:

make_payload() 定义发给服务的内容。 messages 是消息列表,system 说明任务要求,user 提供具体笔记和问题。这里的笔记是教学构造,正确答案能由原文独立判断。

Request 和 urlopen 负责发送。 Python 字典先转成 UTF-8 JSON 字节,再通过 HTTPS POST 交给接口;Authorization 请求头带访问凭据。timeout=60 为阻塞网络操作设置超时,不是保证整个任务严格在 60 秒内结束。Python:urllib.request

后半段解析并保存响应。 它从 choices[0].message.content 取第一项回答,检查是否有内容,读取结束原因,并把原始 JSON 保存下来。这样你不必只相信终端最后一句“看起来成功”。

thinking 在这里显式设为 disabled。当前官方文档说明思考模式默认开启;第一次只是从短笔记取日期,不需要把更多模式一起引入。后面会单独比较什么时候需要它。DeepSeek:思考模式

stream: false 表示本篇一次接收完整响应;max_tokens: 256 是输出 Token 上限,不是“256 个汉字”,也不是要求必须输出这么长。DeepSeek:聊天接口参数

五、先预演,再发送一次真实请求

在终端切换到 deepseek-notes 文件夹。可以在编辑器中打开该文件夹,再打开它的集成终端;用下面命令确认当前文件夹里确实有脚本。

macOS / Linux:

ls
python3 first_call.py --dry-run

Windows PowerShell:

Get-ChildItem
py -3 first_call.py --dry-run

预演会显示 POST https://api.deepseek.com/chat/completions 和请求 JSON。它不读取密钥、不联网、不产生 API 用量。检查三件事:目标域名正确、模型标识正确、消息里是本篇的短笔记。

确认后去掉 --dry-run。下面这一步会向官方服务发送请求,可能产生费用。

macOS / Linux:

python3 first_call.py

Windows PowerShell:

py -3 first_call.py

出现“粘贴 DeepSeek API Key”提示时粘贴自己的密钥,再按回车。输入时通常没有星号,也看不到字符,这不意味着粘贴失败。隐藏输入由标准库 getpass 提供;如果运行环境无法隐藏,脚本会停止,而不是改成把密钥显示出来。Python:getpass

这一版没有自动重试。若要中断,可以按 Ctrl+C;请求已经发出时,中断本地程序不等于远端一定没有处理,也不能据此断定不会计费。

六、怎样判断这次真正成功了

下面是示意输出,文件名、文字和实际用量以你的运行结果为准:

HTTP 200
响应保存到:…/deepseek-notes/responses/response-日期-时间.json
回答:周六
结束原因:stop
用量:{这里会显示服务实际返回的用量字段}

先看四层结果:

  1. 网络和接口:没有连接错误,HTTP 返回成功。
  2. 响应结构:存在有效回答内容,而不是空字符串或缺少 choices。
  3. 生成结束:本例应当正常 stop;若是 length 等其他状态,先检查是否截断或异常结束。
  4. 任务结果:答案确实是周六,没有凭空添加 19:00、教材或新安排。

stop 只说明生成正常停止,不证明答案正确。前三层通过、第四层失败时,接口仍然可能已经正常调用并计费,只是模型没有完成你想要的任务。DeepSeek:响应及结束原因

接着打开脚本旁的 responses 文件夹,用文本编辑器打开最新 JSON。找到 choices、message、content,确认它与终端显示一致;再找到 usage,查看服务实际记录的输入输出用量。这是对程序显示的一次独立复核。

文件由脚本按本地日期时间创建,每次成功解析响应都会生成新文件,不覆盖前一次。脚本没有把请求头或密钥主动写入文件,但真实响应可能包含你的私人资料;本课先用公开的构造笔记,后续不要随意分享原始响应目录。

如果打开的不是最新文件,或者你在别的目录运行了脚本,按终端打印的完整路径查找。保存位置固定在脚本旁,不取决于启动时恰好在哪个文件夹。

七、失败时,先按现象查

现象 首先检查什么 本轮怎样处理
找不到 first_call.py 当前文件夹、扩展名 回到脚本所在目录,重新列出文件
隐藏输入不可用 是否在不支持交互的运行面板 改用系统终端;不要把密钥粘进源码
HTTP 401 密钥错误、撤销、复制不完整 回开放平台确认,重新运行并输入
HTTP 402 可用余额 查看平台账户余额,决定是否补充
HTTP 400 / 422 JSON格式、模型名、参数 对照请求预演与当前文档,不凭猜测改一堆参数
HTTP 429 请求频率或服务限制 停下来稍后再试,不连续启动很多次
HTTP 500 / 503 服务端错误或繁忙 稍后人工重试,保留错误类型
网络、证书或等待错误 网络能否访问官方服务,证书配置 排查网络和系统证书;不要禁用验证
HTTP成功但回答缺失或非stop 响应文件中的内容与结束原因 查看保存文件,不直接当完整答案使用

其中状态码对应原因来自 DeepSeek 官方错误说明。本篇先把常见问题分清,第 08 篇再做有上限、分类型的程序重试。

如果出现文件权限或磁盘空间错误,可能是响应已经收到,但本地保存失败。把脚本放在自己可写的项目目录,检查磁盘空间;不要因为保存失败就认为服务一定没有计费。

八、做一个小改动,确认你真的理解了

把 user 消息里的笔记改成:

第二章原定周六,现改为周日复习。问题:现在安排在哪天?只回答日期表达,不补充几点。

先运行 --dry-run,确认送出的文本已经改变,再决定是否执行第二次真实调用。预期应改答周日;它能检验你修改的是实际请求,而不是只改了页面上的说明。

再做三个不用联网的判断:

  • 把模型标识改成自己的密钥,可以完成认证吗? 不可以。模型标识选择服务里的模型,认证凭据放在请求头,两者作用不同。
  • 预演显示了请求 JSON,能说模型已经回答了吗? 不能。预演没有发出网络请求。
  • 返回“周日 19:00”,HTTP和结束状态都正常,算本题通过吗? 不算。19:00没有依据,接口成功与任务正确是两件事。

今天得到的是一个可以检查输入、发送请求、保存响应的小脚本。下一篇会把它整理成可维护的项目:建立虚拟环境,管理依赖和配置,用 SDK 封装请求,让后续多轮对话不必反复写这些连接代码。


本部分大纲 · 可运行脚本 · 第二部分:大模型原理

文档核查日期:2026 年 10 月 4 日。示例本地离线验证通过;真实账户权限、余额、网络和当时服务行为需由读者实际运行核对。