第一次接 DeepSeek,最容易卡的不是模型本身,而是流程里的碎步骤:Key 存在哪、Base URL 写哪一行、请求用什么字段名、返回是不是流式、报错代码去哪查。这篇按「取 Key → 发第一次请求 → 看返回 → 排错 → 加保护」的顺序走一遍,每步给可对照的动作,不牵扯价格与版本号,数字类信息一律指到站内页面现查。
第一次接 DeepSeek,卡住你的往往不是模型本身,而是流程里那些碎步骤:Key 存哪、Base URL 写哪一行、请求体字段名叫什么、返回是不是流式、报错代码翻哪里。这篇按「取 Key → 发第一次请求 → 看返回 → 排错 → 加保护」的顺序走一遍,每步给能照着做的动作。
全文不写死价格、版本号、跑分这类会过期的数字,遇到必须看数字的地方,一律指到站内对应页面现查。你按顺序做完,应该能拿到一条自己跑通的最小请求,并知道它出问题时先看哪。
第一步:拿到 Key,然后决定它放在哪
- 创建 Key在官方控制台创建 API Key,记得创建后只显示一次,复制完立刻存进密码管理器,不要留在聊天记录、截图或便签里。
- 决定存放位置本地开发放进环境变量或 .env 文件,并把 .env 加进 .gitignore;线上放平台的密钥管理服务或网关侧,绝不写进前端代码和打包产物。
- 异常时吊销重建Key 是账号级凭证,泄露等于别人用你的额度跑任务。一旦怀疑外泄,先去控制台吊销再重建,不要抱着侥幸继续用。
- 确认额度口径「取 Key」和「充额度」是两件事,额度与计费口径不要照抄别人文章里的旧值,到 /official-api/providers/deepseek 核对当时的数字。
| 存放方式 | 适不适合 | 注意点 |
|---|---|---|
| 环境变量 / .env | 本地开发适合 | .env 必须进 .gitignore |
| 平台密钥管理 | 线上推荐 | 权限最小化,按服务分 Key |
| 前端代码 / 打包产物 | 不要用 | 打包后可被任何人翻出来 |
| 聊天记录 / 截图 | 不要用 | 分享即泄露,无法收回 |
第二步:把第一次请求的四个要素凑齐
一次请求能发出去,靠的是四个要素凑齐:Base URL、路径、鉴权头、请求体字段。先确认你走的是原生地址还是兼容层,两者路径和字段名可能不一样,写混了直接 404 或 400,跟模型能力没关系。
- 请求体先用最小可用集:model、messages(里面是 role 加 content),其余参数一律先不写,先把一次最朴素的对话跑通。
- 用 curl 先在终端验一遍服务端是否可达,再回代码里调;代码报错时你分不清是网络、鉴权还是参数,curl 能一刀切开。
- 把这条能跑通的最小请求原样存成 fixture 文件,后面换 SDK、改 base url、接中转站,都拿它做回归对照。
- 鉴权头格式照着官方文档抄,注意 Key 是否要带前缀、有没有多余空格和换行,这类小问题最容易伪装成 401。
curl -sS -X POST "$BASE_URL/chat/completions" \
-H "Authorization: Bearer $DEEPSEEK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"<填你控制台里的模型名>","messages":[{"role":"user","content":"你好"}]}'第三步:发出去,看返回里到底有什么
非流式返回里,内容在 choices 里,附带 usage 记录输入输出 token 数。流式返回是一串分片,最后一片可能才带 usage,写解析逻辑时别假设每一片都完整。判断流式能不能用,要看你所在通道的兼容情况,不确定就先按非流式写,跑通后再切。
- 首次请求把原始响应体整个打进日志(Key 脱敏后),出问题时比对你拼出来的对象和原始 JSON 的差异,很多「字段读不到」都是层级看错。
- 首字延迟和总耗时是两回事:非流式只能看总耗时,流式才能量首字,基线自己去 /tools/speed-test 那类页面量一次。
- 解析时对 choices 为空、内容为 null 的情况加兜底判断,别让一次异常返回直接把整个功能崩掉。
- 把模型名单独提成一个配置项,别散落在代码各处,换通道时才知道要改哪几行。
第四步:跑不通时的排查顺序
排错最忌乱改,按固定顺序查能省大量时间:域名能否解析 → TLS 是否握手成功 → 是否 401 → 是否 404 → 是否 400 → 是否 429。每过一关再动下一关,跳着改只会把问题叠加。
| 现象 | 先怀疑什么 | 下一步动作 |
|---|---|---|
| 域名解析失败 | Base URL 写错或本地网络 | 换网络后用 curl 重试一次 |
| 401 | 鉴权头格式、Key 前缀、多余空格 | 按文档逐字符比对鉴权头 |
| 404 | 路径拼错或走了不匹配的兼容层 | 确认路径与 base url 是否同一套 |
| 400 | 请求体字段类型或结构不符 | 只留最小可用集再发一次 |
| 429 | 频率或并发被限 | 看返回里的限流提示,先降并发 |
- 401 和 403 是两回事,别混着改:前者多半是凭证问题,后者常是权限或区域限制,具体区别看站内那篇专讲两者差异的文章。
- 超时类报错要分清连接超时和读取超时,模型响应慢是读取超时,网络不通是连接超时,两者设不同的值,别只设一个总超时。
- 每次失败把完整请求信息落日志:URL、状态码、响应体前若干字符,只记「调用失败」等于没记。
- 重放问题请求时先去掉所有附加参数,用最小请求复现,能把参数问题和环境问题分开。
第五步:上线前先加四道保护
- 超时
- 连接、读取、整体三层分别设,不用默认无限等待,分档参考站内讲 timeout 的文章按场景取。
- 重试
- 只对超时、429、5xx 重试,带指数退避加随机抖动;参数错误、鉴权错误重试再多次也没用。
- 并发
- 先低并发跑通再往上压,遇到 429 看返回里的限流提示,而不是无脑加机器。
- 降级
- 准备一条备用路径(切备用模型或返回兜底话术),主通道挂掉时别让整个功能一起挂。
- 日志
- 至少记请求 ID、模型名、耗时、token 数、状态码五个字段,事后才复盘得出哪次慢、哪次贵。
一个常见误区是把重试和幂等混为一谈:写操作被重试可能产生重复副作用,读类请求才适合无脑重试。判断标准很简单,问一句「这次调用重放一遍会不会改变业务状态」,会就加去重键,不会才放心重试。
下一步去站内通道检测与价格追踪页面,看看你正在用的通道当前状态和数字口径,再决定要不要准备备用路径。→常见问题
第一次调用一定要用官方 SDK 吗?
不一定。先用 curl 跑通最能暴露问题,因为 SDK 会帮你藏掉 URL 拼接和请求头,出错了你反而看不到原始信息。等 curl 能稳定返回,再换官方 SDK 或 OpenAI 兼容客户端,边换边用之前存下来的最小请求做回归,能立刻发现是 SDK 引入的差异。
为什么我照着文档写还是报 400?
400 基本都是请求体结构问题,最常见三种:messages 不是数组、role 用了不支持的取值、多包了一层 data 或少了 content 字段。把请求体整个打印出来,跟文档示例逐字段对一遍,重点看引号、逗号和嵌套层级,比反复改代码快。
并发上不去、总是被限流怎么办?
先确认是频率限制还是并发限制,两者解法不同:频率限制靠拉长间隔和批量合并,并发限制靠排队和降并发。稳妥做法是按小批量试跑,观察返回里的限流提示逐步加,同时写好退避重试和降级路径,别用一次失败就加倍并发的方式硬顶。