简介:《2025 DeepSeek自学手册》以73页PDF呈现,面向希望系统掌握DeepSeek V3与R1的AI初学者、开发者及研究人员。内容从模型起源、架构设计与性能表现切入,延伸到提示词技巧、数据处理、微调及无监督、监督与强化学习实现路径,并以13个官方示例演示代码编写、数学求解、自然语言理解、创意写作和角色扮演等场景,附在线与本地部署方案。手册对MoE专家混合、MLA多头潜在注意力、多Token预测、无辅助损失负载均衡,以及R1的冷启动数据、多阶段训练与模型蒸馏等机制均有展开,并给出数学、编程及通用知识基准对比,便于理解V3与R1的差异和选型。资源包为1个PDF文件,约25.31MB,已有154人学习,适合按章节精读或按场景检索,用作理论梳理与落地实践参考。
1. 从理论到实践,这份 73 页 DeepSeek 自学手册该从哪里切进去
一份 73 页的 DeepSeek 自学手册,多数人卡在两个位置:前 20 页讲注意力机制与 MoE 路由,读得懂但落不到工位上;后 20 页是提示词模板,抄完换个业务场景立刻失效。真正撑住"从理论到实践"这句话的是中间那部分——模型怎么选、deepseek api如何调用、本地部署 deepseek 的硬件底线在哪、vscode 接入 deepseek 之后补全为什么老是截断。
这篇按一线落地的顺序重排这些内容:先讲模型与计费,再讲本地化部署的两条路线,然后把它接进 VSCode、命令行编码工具和企业微信,最后处理 deepseek 达到对话长度上限和 deepseek 导出这类绕不开的运维细节。适合需要把 DeepSeek 接进自己系统的后端、算法和运维,也适合想在本地把数据圈住的小团队。
2. DeepSeek 模型选型与 deepseek api 如何调用
2.1 先分清 deepseek-chat 和 deepseek-reasoner 的调用差异
开放平台上能直接调的两个主力模型,差异不在参数量,而在"要不要把思考过程还给你"。deepseek-chat 是常规对话模型,响应快、采样参数生效;deepseek-reasoner 会把推理链放在reasoning_content字段里单独返回,正文仍然在content。这两者的接口地址、鉴权方式完全一致,只有模型名和行为不同。
| 模型名 | 推理链 | 适合任务 | 常见坑 |
|---|---|---|---|
| deepseek-chat | 不显式输出 | 日常问答、代码补全、结构化抽取 | 复杂多步数学题容易跳步 |
| deepseek-reasoner | 返回 reasoning_content | 算法推导、SQL 优化、逻辑排查 | 首 token 延迟高,采样参数不生效 |
选型上我的习惯是:凡是能用确定性规则或单轮 prompt 解决的问题,一律用 chat;只有需要模型"先想再做"的题型才切 reasoner,因为推理 token 同样计费,用错场景成本会翻两三倍。
2.2 用 OpenAI SDK 跑通第一条请求
DeepSeek 的 HTTP 接口兼容 OpenAI 协议,所以不需要专用 SDK,改 base_url 就能复用现成的客户端。下面是 Python 侧的最小可运行版本:
from openai import OpenAI client = OpenAI( api_key="sk-你的Key", base_url="https://api.deepseek.com/v1", # 与 OpenAI 协议兼容 ) resp = client.chat.completions.create( model="deepseek-chat", messages=[ {"role": "system", "content": "你是后端架构顾问,回答只给结论和代价"}, {"role": "user", "content": "这条 SQL 为什么会走全表扫描?"}, ], temperature=0.3, # 代码类任务压低随机性 max_tokens=2048, # 只约束输出,不含输入 stream=False, ) print(resp.choices[0].message.content) print(resp.usage) # 用来核对 prompt/completion token 数逻辑说明:base_url决定流量打到哪个端点,路径里的/v1是协议约定而非版本号;messages里 system 放在第一位能让缓存前缀稳定命中;usage字段返回的是本次真实计费的 token 拆分,写成本监控时直接读它,别自己估算。
参数上几个易错点:temperature调到 0 不代表输出完全确定,只是概率分布被压平;max_tokens只限制输出长度,和上下文窗口是两个概念;开stream=True后usage会在最后一个 chunk 才出现。
命令行排查用 curl 更直观:
curl https://api.deepseek.com/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $DEEPSEEK_API_KEY" \ -d '{ "model": "deepseek-reasoner", "messages": [{"role": "user", "content": "解释 TCP 三次握手为什么不是两次"}], "stream": false }'返回体里choices[0].message.reasoning_content是推理过程,content是最终答案。业务代码里要显式判断这个字段是否存在,否则切模型时会取到空字符串。
2.3 成本与并发:把 deepseek 价格算在写代码之前
计费口径按输入、输出分开,输入里又区分缓存命中与未命中,未命中的单价明显更高。控制成本最有效的三件事,按性价比排序如下:
| 手段 | 做法 | 效果 |
|---|---|---|
| 稳定前缀 | system prompt、few-shot 示例固定不变,放在 messages 最前面 | 命中缓存,输入单价大幅下降 |
| 限制输出 | 明确要求"只输出 JSON,不要解释",并设 max_tokens | 输出是最贵的一段 |
| 批量合并 | 把 10 条小请求合成 1 条结构化抽取请求 | 减少重复的系统提示开销 |
并发上,个人开发者的限额通常够用,但批量跑数据时会撞到 429。稳妥的做法是加指数退避,并在队列层限制在飞请求数,而不是无脑重试:
import time, random def call_with_backoff(fn, retries=5): for i in range(retries): try: return fn() except Exception as e: if "429" not in str(e) and "rate" not in str(e).lower(): raise # 指数退避 + 抖动,避免多实例同时重试 time.sleep(min(2 ** i, 30) + random.random()) raise RuntimeError("重试耗尽")2.4 请求报错的定位顺序
遇到失败时按这个顺序查,能省掉大半时间:401 先看 Key 有没有多余空格和换行;400 多半是 messages 结构不合法,比如 role 写成了assistant带尾空格;超长报错说明输入已经超过上下文窗口,需要先做截断或摘要;返回"服务器繁忙,请稍后再试"属于服务端限流,退避重试即可,不要改参数硬刚。deepseek request extension preparation failed这类报错一般出现在浏览器插件或客户端侧,先用 curl 确认服务端本身通不通,能把问题范围直接砍一半。
3. 本地部署 deepseek:Ollama 与 vLLM 两条路线的落地参数
3.1 本地化部署 deepseek 的决策边界
先想清楚为什么要本地跑。数据不能出内网、要离线可用、要固定版本做回归测试,这三条成立才值得投入显卡。反之,如果只是想省 API 费用,算上电费和运维时间通常不划算——一张 24G 卡跑 32B 量化的吞吐,很难比按量付费更便宜。
| 场景 | 建议路线 |
|---|---|
| 单机自用、验证效果 | Ollama,五分钟起服务 |
| 团队内网、多人并发 | vLLM,吞吐和并发明显更好 |
| 生产级高并发 | 多卡张量并行 + 前置网关排队 |
3.2 用 Ollama 跑通本地 DeepSeek 的最小命令集
Ollama 把模型权重、量化和运行时打包在一起,装完就能用:
# 拉取蒸馏版模型,数字是参数量,按显存选 ollama pull deepseek-r1:14b # 交互式跑一轮 ollama run deepseek-r1:14b # 以常驻服务方式启动,供其他程序调用 OLLAMA_HOST=0.0.0.0:11434 OLLAMA_KEEP_ALIVE=30m ollama serveOLLAMA_KEEP_ALIVE控制模型在显存里驻留多久,默认几分钟就卸载,多人使用时反复加载会非常慢,调到 30 分钟以上更实际。服务起来后用 OpenAI 兼容端点验证:
curl http://localhost:11434/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{"model":"deepseek-r1:14b","messages":[{"role":"user","content":"写一个带超时的 LRU 缓存"}],"stream":false}'上下文长度默认偏小,长文档场景需要自定义。用 Modelfile 固化参数,比每次命令行传更省事:
FROM deepseek-r1:14b PARAMETER num_ctx 16384 PARAMETER temperature 0.6 SYSTEM "你是运维助手,命令必须带注释"num_ctx直接决定显存占用,从 4096 提到 32768,KV cache 可能多吃好几 GB,调之前先看显存余量。
3.3 vLLM 起服务的 5 个关键参数
多人并发场景换 vLLM,它的连续批处理和 PagedAttention 能把显存碎片压下去:
python -m vllm.entrypoints.openai.api_server \ --model deepseek-ai/DeepSeek-R1-Distill-Qwen-14B \ --served-model-name deepseek-local \ --tensor-parallel-size 2 \ --max-model-len 32768 \ --gpu-memory-utilization 0.92 \ --enable-prefix-caching \ --port 8000| 参数 | 作用 | 调整建议 |
|---|---|---|
| tensor-parallel-size | 权重切到几张卡 | 等于可见 GPU 数,单卡填 1 |
| max-model-len | 单请求最大上下文 | 越大 KV cache 占用越高,按业务实际需要设 |
| gpu-memory-utilization | 预分配的显存比例 | 0.85~0.95,留一点给驱动 |
| enable-prefix-caching | 复用公共前缀的 KV | 多请求共享同一 system prompt 时必开 |
| max-num-seqs | 同时处理的请求数 | 显存紧张就调小,避免频繁抢占 |
--served-model-name是给客户端用的别名,写死一个稳定名字,后面换底层模型时业务代码不用改。
3.4 显存不够时的量化取舍与排错
| 参数量 | BF16 权重 | Q4_K_M 权重 | 建议显存 |
|---|---|---|---|
| 7B | 约 15 GB | 约 4.5 GB | 8 GB |
| 14B | 约 28 GB | 约 9 GB | 16 GB |
| 32B | 约 64 GB | 约 20 GB | 24 GB 起 |
| 70B | 约 140 GB | 约 42 GB | 双卡 48 GB 起 |
上表只算权重,实际还要加上 KV cache 和框架开销。常见故障有三类:启动即 OOM,先把max-model-len砍半再试;输出重复或断句异常,通常是量化损失叠加 temperature 过低,把温度提到 0.6 左右观察;首 token 延迟几十秒,多半是模型被换出显存,检查 keep-alive 或并发数是否超了。
4. 把 DeepSeek 接进开发工具链:VSCode、Claude Code 与企业微信
4.1 vscode 接入 deepseek 的补全与对话配置
VSCode 里接入不需要自己写插件,用支持自定义 OpenAI 兼容端点的助手类插件即可。核心是三件事:填对apiBase、填对模型名、把上下文长度写准。
name: deepseek-local version: 0.0.1 models: - name: DeepSeek Chat provider: openai model: deepseek-chat apiBase: https://api.deepseek.com/v1 apiKey: sk-你的Key roles: [chat, edit, apply] defaultCompletionOptions: contextLength: 65536 maxTokens: 2048contextLength填小了,插件会频繁裁剪文件内容,补全看起来"变傻";填大了,超出服务端窗口会直接报错。字段名在不同插件版本间有差异,以当前版本的配置文档为准,别硬抄旧博客。改完配置后先在对话面板发一句"读一下当前文件并说明它的职责",能读全文件就说明上下文生效了。
4.2 Claude Code 接入 DeepSeek 的协议转换层
命令行编码工具大多走 Anthropic 的 Messages 协议,而 DeepSeek 提供的是 OpenAI 协议,两者结构不同:Anthropic 的 system 是顶层字段,content 支持块数组。常见做法是本地起一层轻量转换,把/v1/messages转成/chat/completions。
from fastapi import FastAPI, Request import httpx app = FastAPI() UPSTREAM = "https://api.deepseek.com/v1/chat/completions" @app.post("/v1/messages") async def messages(req: Request): body = await req.json() key = req.headers.get("x-api-key") or \ req.headers.get("authorization", "").replace("Bearer ", "") msgs = [] if body.get("system"): # Anthropic 顶层 system 要下沉 msgs.append({"role": "system", "content": body["system"]}) for m in body.get("messages", []): msgs.append({"role": m["role"], "content": m["content"]}) async with httpx.AsyncClient(timeout=180) as c: r = await c.post( UPSTREAM, json={"model": "deepseek-chat", "messages": msgs, "max_tokens": body.get("max_tokens", 2048), "stream": False}, headers={"Authorization": f"Bearer {key}"}, ) text = r.json()["choices"][0]["message"]["content"] return { "id": "msg_local", "type": "message", "role": "assistant", "model": "deepseek-chat", "stop_reason": "end_turn", "content": [{"type": "text", "text": text}], "usage": {"input_tokens": 0, "output_tokens": 0}, }客户端侧只要把 BASE_URL 指向本地 8082 端口,AUTH_TOKEN 留 DeepSeek 的 Key 即可:
export ANTHROPIC_BASE_URL="http://127.0.0.1:8082" export ANTHROPIC_AUTH_TOKEN="sk-你的DeepSeekKey" export ANTHROPIC_MODEL="deepseek-chat"这层转换只覆盖文本对话,工具调用和流式事件需要单独补。如果用的是走 OpenAI 协议的 CLI 编码工具,就不必转换,把 base_url 换成https://api.deepseek.com/v1直接可用。
4.3 企业微信接入 deepseek 的消息回调链路
企业微信自建应用接收消息有个硬约束:回调必须在 3 秒内响应,否则会重试,重试会导致同一条消息被处理多次。所以正确链路是先落库、立即返回空串,再用客服消息接口把模型结果异步推回去。
| 环节 | 关键动作 | 注意点 |
|---|---|---|
| 验签解密 | 校验 msg_signature,解密 Encrypt | 用官方库处理,别手写 |
| 立即响应 | 返回空字符串 | 超 3 秒必然触发重试 |
| 异步推理 | 队列里调 DeepSeek | 按用户维度做去重 |
| 结果回推 | 调消息推送接口 | 超过 48 小时窗口无法主动推送 |
@app.post("/wecom/callback") async def callback(request: Request): xml = await request.body() msg = parse_and_decrypt(xml) # 官方库:验签 + 解密 enqueue(user_id=msg.FromUserName, text=msg.Content) # 只入队,不阻塞 return "" # 必须立即返回,否则重试消息按用户维度做幂等去重、推理放在独立 worker 里跑,这两条比模型选型更影响实际体验。群聊场景还要处理 @机器人 的触发判定,否则会把所有闲聊都送进模型。
5. 长对话治理:达到对话长度上限后的续接与导出
5.1 deepseek 达到对话长度上限怎么办
网页版弹出"达到对话长度上限,请开启新对话",本质是上下文窗口被占满了。直接重开新对话会丢掉前文约束,比较稳的做法是主动滚存:把靠前的轮次压缩成一段事实摘要,塞进新会话的 system 位置,只保留最近几轮原文。
def rollover(client, history, keep_last=4): """旧轮次压缩成摘要,保留最近几轮原文,成本远低于全量重放""" old, recent = history[:-keep_last], history[-keep_last:] digest = client.chat.completions.create( model="deepseek-chat", messages=[ {"role": "system", "content": "把以下对话压缩成不超过 300 字的事实清单," "保留结论、约束条件、未决问题和命名约定"}, *old, ], temperature=0.2, max_tokens=600, ).choices[0].message.content return [{"role": "system", "content": f"历史会话摘要:\n{digest}"}] + recent关键在摘要提示词要显式要求保留"约束条件和命名约定",否则模型倾向于只留结论,重开会话后变量命名、技术栈偏好全丢。keep_last一般取 3~5,太少会丢语境,太多摘要没意义。
5.2 deepseek 导出后如何切成可检索片段
把长对话导出成 markdown 之后,不要整份塞进新会话,按轮次切分再按需召回更省 token:
import re, json def split_turns(md_text): # 以 "### 用户" / "### 助手" 之类的分隔标记切轮次 blocks = re.split(r"\n(?=###\s)", md_text) out = [] for b in blocks: lines = b.strip().splitlines() if not lines: continue role = "user" if "用户" in lines[0] else "assistant" out.append({"role": role, "content": "\n".join(lines[1:]).strip()}) return out turns = split_turns(open("chat_export.md", encoding="utf-8").read()) json.dump(turns, open("turns.json", "w", encoding="utf-8"), ensure_ascii=False, indent=2)切完之后每轮单独算 token,超过阈值的轮次做二次切分,检索时只带最相关的两三段进上下文,比整份重放节省一个数量级的输入。
5.3 用 token 计数验证上下文有没有被浪费
判断上下文是否被无效占用,最快的办法是统计每类消息占的 token 占比。system 和工具描述占比超过三成就该精简,历史轮次占比过高就该触发上面的滚存逻辑。每次调用把usage落到日志表里,按天聚合输入输出的缓存命中率,能直接反映 system prompt 是否稳定——命中率突然掉到零,通常是有人往前缀里塞了时间戳。
本文还有配套的精品资源,点击获取