
简介这是一份面向开发者的 DeepSeek API 调用示例压缩包特别适合刚接触大模型接口接入、希望快速跑通调用流程的 Python 使用者。资源以两个 Python 脚本为主体分别演示单次请求与循环调用两种典型场景并附带许可证与忽略文件兼顾开源合规与工程化配置。压缩包共四个文件大小约14KB体量轻量便于逐行阅读和直接修改。截至目前已有二百八十三人学习下载适合作为接口接入初期的参考样板。通过示例代码读者可以直观了解密钥加载、请求构造、响应解析以及常见错误处理等关键步骤循环调用脚本还展示了批量请求与速率控制思路有助于进一步完善自有调用工具。整体思路覆盖文档阅读、请求头设计、参数拼接、异常捕获与测试要点能够快速迁移到实际项目开发之中。1. DeepSeek API 调用demo 在手先别急着跑代码很多第一次接触 DeepSeek API 的人卡住的并不是模型能力而是调用方式本身拿到 key 不知道填在哪、base_url 和模型名抄错、返回 401 或 400 后对着报错发懵。这个 deepseek-demo-master 资源包做的事情就是把一个可以跑通的 DeepSeek API 调用示例放到你面前——从构造对话、发请求、解析响应到流式输出每一步都有可运行的代码。它适合两类人一是要在自己项目里快速接入 DeepSeek 对话能力的开发者二是想搞明白 chat/completions 这个接口协议细节、避免把时间耗在试错上的学习者。接下来我按自己拆这个 demo 的顺序从目录结构、调用方式、参数调整到坑点排查一层层说透。2. 拆包看结构demo 里到底装了哪些能用的东西2.1 目录结构一眼看懂入口、依赖与配置分离设计解压 deepseek-demo-master.zip 之后常见的顶层结构是这样的deepseek-demo-master/ ├── main.py # 程序入口负责发起调用并打印结果 ├── config.py # 集中管理 api_key、base_url、model 等常量 ├── requirements.txt # 第三方依赖清单requests、openai 等 ├── utils.py # 工具函数读 key、格式化消息 └── README.md # 运行说明与参数说明我拿到这类包的第一步永远是看requirements.txt和config.py而不是先开main.py。原因很简单依赖清单决定了你能不能一行命令跑起来配置项决定了你的 key 该往哪里填。多数 demo 包会要求你手动把 API key 写进config.py而正规一点的做法则是读环境变量——用os.getenv(DEEPSEEK_API_KEY)取代硬编码避免 key 被误提交到 Git 仓库。main.py里的调用逻辑并不复杂通常就做三件事拼 messages、发请求、解析 response。把这三个动作拆开来看整个接口的黑匣子感会消失大半。2.2 核心请求链路从 messages 到 response 的三步转换main.py去掉装饰性代码后骨架大致如下import requests from config import API_KEY, BASE_URL, MODEL_NAME def chat(messages): resp requests.post( urlf{BASE_URL}/chat/completions, headers{ Authorization: fBearer {API_KEY}, Content-Type: application/json, }, json{ model: MODEL_NAME, messages: messages, stream: False, }, timeout30, ) resp.raise_for_status() data resp.json() return data[choices][0][message][content]这段代码背后的协议逻辑值得展开说POST /chat/completions是对话补全接口的统一入口请求体里的messages是一个数组数组里每个元素带 role 和 content 两个字段。role 有三种——system设定助手行为user是用户输入assistant是历史回复整个数组按时间顺序排列服务端会把它当作完整上下文来理解。stream: false表示关闭流式输出服务端会在全部 token 生成完后一次性返回完整 JSON。这种非流式模式最适合验证链路通不通报错与否一眼可见解析也简单。timeout30是给请求设的底线避免网络故障时程序无限挂起。这里没有用官方 SDK只依赖requests目的是把协议细节暴露出来——用 SDK 时很多坑被封装掉了出了问题反而说不清是哪一步不对。3. 把调用真正跑通连接串、请求体与流式输出逐项落地3.1 选对连接串Base URL、模型名与鉴权头一次到位DeepSeek API 的调用方式与业界常见的 chat completions 协议兼容因此连接串由三部分组成Base URL、模型名、鉴权头。任何一个不对请求都到不了模型手里。先用一个 curl 命令做最小验证curl https://api.deepseek.com/chat/completions \ -H Authorization: Bearer 你的key \ -H Content-Type: application/json \ -d { model: deepseek-chat, messages: [{role: user, content: 你好}], stream: false }注意-d里的 JSON 结构model字段在顶层messages是数组每一条消息是rolecontent。如果返回结果里有choices[0].message.content说明连接串配置正确。这里最容易翻车的是模型名——deepseek-chat是通用对话模型的调用名版本更新后这个调用名仍然稳定不要想当然地加上v1或latest后缀服务端并不认。鉴权头Authorization: Bearer key是硬规则缺少 Bearer 前缀、key 里带多余空格都会直接返回 401。很多人在这一步折腾很久最后发现是复制 key 时把末尾换行也带进了配置文件。3.2 用 requests 写一个不算优雅但能跑通的客户端SDK 虽然方便但多一层依赖就多一层黑匣子。我习惯直接写 requests 版本把请求体、响应结构全部摊开看。进阶一点的写法会增加异常分类import json import requests API_KEY sk-xxxx BASE_URL https://api.deepseek.com MODEL deepseek-chat def chat_once(user_text): payload { model: MODEL, messages: [ {role: system, content: 你是严谨的助手回答要简洁}, {role: user, content: user_text}, ], temperature: 0.7, max_tokens: 1024, } try: r requests.post( f{BASE_URL}/chat/completions, headers{Authorization: fBearer {API_KEY}}, jsonpayload, timeout60, ) r.raise_for_status() content r.json()[choices][0][message][content] return content except requests.exceptions.Timeout: return 请求超时检查网络或增大 timeout except requests.exceptions.HTTPError as e: return fHTTP {e.response.status_code}: {e.response.text}这段代码里有两个容易被忽视的细节一是system消息被我放在了messages列表首位它不占用户对话轮次但对输出风格影响极大二是max_tokens显式给了 1024避免默认值过小导致回答被截断。异常处理按Timeout和HTTPError分开捕获HTTPError 里读出状态码和响应体 —— 这是定位 400 类参数问题的关键线索。真正跑业务时我会把成功响应里的usage字段打出来看 prompt_tokens 和 completion_tokens 的消耗便于核算成本。3.3 流式输出流式响应不是黑匣子拆开看就是一段 SSE长回答场景下非流式接口要等全部 token 生成完才返回用户侧会看到长时间空白。把stream设为 true服务端会按事件流推送增量数据。解析方式如下import json import requests def chat_stream(messages): payload { model: deepseek-chat, messages: messages, stream: True, } with requests.post( https://api.deepseek.com/chat/completions, headers{Authorization: Bearer 你的key}, jsonpayload, streamTrue, timeout60, ) as resp: for line in resp.iter_lines(): if not line: continue line line.decode(utf-8) if line.startswith(data: ): chunk line[6:] if chunk.strip() [DONE]: break obj json.loads(chunk) delta obj[choices][0][delta].get(content, ) if delta: print(delta, end, flushTrue)用iter_lines()逐行读取服务端推送的数据每一行以data:开头后面跟一个 JSON 对象。真正的增量文本在choices[0].delta.content里而不是顶层content——不少人在这一步踩坑是把整个 chunk 当成了完整消息去解析。[DONE]是结束标记遇到就跳出循环。这里flushTrue保证每个 token 都实时打印不加的话终端会因为缓冲显得一顿一顿。流式还有一个额外好处网络中断时已经显示的内容不会丢体验比一次性返回稳得多。4. 参数调优temperature、top_p 与 system 提示词的搭配逻辑4.1 核心参数速查表参数控制内容建议区间使用习惯temperature随机性越低越确定性0.0 - 1.5代码/数学题用 0.1 - 0.3文案用 0.8 - 1.2top_p核采样候选 token 累积概率阈值0.1 - 1.0与 temperature 二选一调试不叠加max_tokens输出长度上限依任务而定代码任务 2048长文本 4096frequency_penalty惩罚重复 token-2.0 - 2.0需要多样化时调高防止复读presence_penalty鼓励谈论新话题-2.0 - 2.0闲聊场景可调正问答场景保持 0这张表解决的是“参数怎么设”的问题但更重要的是一句话没有万能参数只有符合任务的参数。把 temperature 说成“越高越聪明”是常见的误区——它是采样随机性不是能力开关。4.2 temperature 与 top_p二选一别叠加玄学在大多数场景里temperature和top_p不需要同时调整。两个参数都在影响采样分布一起动会让输出行为变得难以预测排查问题时也分不清是谁造成的。我的习惯做法是固定top_p1.0只调temperature。具体到任务类型规则如下。代码生成、数学推理、JSON 格式化输出这类需要稳定性的任务temperature设 0.1几乎每次输出都是确定性的营销文案、创意命名、头脑风暴类任务temperature拉高到 0.9 - 1.2模型会产出更跳脱的内容但偶尔会出现逻辑不连贯需要人工筛选。如果发现单开 temperature 后结果依然单调再考虑用presence_penalty0.6鼓励模型换话题而不是去调 top_p。4.3 system 提示词角色设定不该是摆设很多人写 messages 只放 user 内容把 system 当成可选项。实际上 system 消息是控制输出质量性价比最高的手段。同样是要求写技术方案messages [ {role: system, content: ( 你是技术方案助手。输出必须包含背景、方案选型、实施步骤、风险点。 语言简洁禁用空话套话。 如果用户要求不明确主动列出两个假设并说明。 )}, {role: user, content: 帮我把日志系统迁移到新的采集链路}, ]加了这一段 system 后再跑输出结构会明显规整。原因在于 DeepSeek 的对话模型训练时高度遵循指令层级system 消息优先级高于 user它会像一个前置任务说明一样约束后续所有生成。对输出有强格式要求的场景把格式模板写进 system比在 user 里反复强调有效得多。一个实用的进阶技巧是让 system 里声明“如果信息不足必须明确说出缺少什么”这能减少模型默认编造内容的比例。5. 规避坑五个真实翻车现场与对应排查路径5.1 现象返回 401鉴权失败刷了半个小时首次运行请求服务端返回 401 Unauthorized。排查路径检查 key 是否复制完整特别留意末尾是否有换行或空格确认配置里是否加了Bearer前缀确认用的 key 没有被手动重置过。这类问题八成出在配置文件上把 key 复制到 VSCode 里用「显示空格」功能看一眼即可定位。5.2 现象返回 400提示模型名不存在请求体里写了deepseek-chat-v1之类带版本号的名字被服务端拒绝。原因调用名是稳定标识不随版本迭代改变。解决改回deepseek-chat若需要深度推理能力再换成deepseek-reasoner但后者在复杂推理场景的响应时间明显更长不适合做低延迟交互。5.3 现象请求成功但解析不到 content 字段响应是 200但data[choices][0][message][content]抛 KeyError。原因打开了stream: true却没按流式格式解析流式响应的内容是分段 JSON结构与非流式完全不同。解决确认 stream 状态后选择对应解析分支——true 时读delta.contentfalse 时读message.content。流式响应里把两条解析路径混用是新手最容易犯的错误。5.4 现象回答戛然而止句子没说完输出看起来完整但结尾明显中断。原因max_tokens太小生成到长度上限被强制截断。解决统计历史任务的平均输出长度设置 1.5 倍余量。另一个技巧是让 system 里写“回答控制在 200 字以内”把控制权从参数层转移到指令层两种手段配合效果更好。5.5 现象多轮对话后请求变慢token 消耗暴涨连续对话到第 30 轮响应越来越慢费用也明显上升。原因把全部历史消息原样堆积在 messages 里每轮都重新发送所有 token输入处理时间随轮数线性增长。解决对历史做裁剪只保留 system 最近 N 轮对话更精细的做法是用prompt_tokens统计来判断何时裁剪。例如对话累计超过 4000 token 时把第 2 轮之前的消息折叠成摘要塞进 system其余按原样保留。6. 让 demo 变成你自己的最小可用模板把前面所有经验合起来我最终沉淀成一个可复制的模板。这个模板支付了超时、流式、上下文裁剪和错误分类四件事import json import requests class DeepSeekClient: def __init__(self, api_key, base_urlhttps://api.deepseek.com): self.api_key api_key self.base_url base_url self.max_context_tokens 4000 def _trim_messages(self, messages): # 保留 system 与最近 10 轮避免上下文无限膨胀 system [m for m in messages if m[role] system] recent [m for m in messages if m[role] ! system][-20:] return system recent def chat(self, messages, streamTrue, temperature0.7): payload { model: deepseek-chat, messages: self._trim_messages(messages), temperature: temperature, stream: stream, } headers { Authorization: fBearer {self.api_key}, Content-Type: application/json, } if not stream: r requests.post( f{self.base_url}/chat/completions, headersheaders, jsonpayload, timeout60, ) r.raise_for_status() return r.json()[choices][0][message][content] # 流式分支 collected [] with requests.post( f{self.base_url}/chat/completions, headersheaders, jsonpayload, streamTrue, timeout60, ) as resp: for line in resp.iter_lines(): if not line: continue line line.decode(utf-8) if line.startswith(data: ): chunk line[6:] if chunk.strip() [DONE]: break delta json.loads(chunk)[choices][0][delta] if content in delta: collected.append(delta[content]) return .join(collected) # 用法 client DeepSeekClient(sk-你的key) messages [{role: user, content: 讲一下断点续传的实现思路}] reply client.chat(messages) print(reply)这个模板去掉了 demo 里与业务无关的展示性代码保留了核心链路。_trim_messages只保留最近 20 条非 system 消息防止输入 token 无限膨胀——这是我被涨到五位数的上下文账单教育出来的习惯流式接口把增量拼成完整文本非流式接口直接返回字符串两个分支对调用方保持一致。想要校验自己的改动建议在一台干净机器上按 requirements.txt 装依赖后跑通一次观察prompt_tokens的量级和首 token 延迟确认参数生效。我最初接手这个 demo 时也是先在 curl 上验证连接串再逐层套上重试和裁剪逻辑。从那以后我每次接入新 API 的第一件事永远是确认 base_url 和模型名这两个最容易被忽略的常量再谈其他。希望这篇拆解能帮你少走一趟同样的弯路。本文还有配套的精品资源点击获取