
简介《DeepSeek从入门到精通》由清华大学新闻与传播学院新媒体研究中心元宇宙文化实验室团队编写面向希望系统了解并上手DeepSeek的开发者、内容创作者与AI学习者重点解决模型认知、任务匹配和提示语设计等问题。压缩包内为1个PDF文件约4.14MB内容围绕DeepSeek是什么、能做什么、如何使用及如何进阶展开涵盖智能对话、文本生成、语义理解、代码生成补全、文件与图片文字读取等应用场景。文档还对比推理模型与通用模型在数学推导、逻辑分析、创意写作等任务上的差异说明提示语策略、模型选择原则及常见误区并给出任务需求与提示语示例。读者可据此判断何时选用推理模型、何时选用通用模型并借助提示语原则优化提问与复杂任务拆解提升文本创作、代码生成和知识分析效率。已有335人学习适合按章节查漏补缺。1. DeepSeek 到底是什么先把三类模型和两种用法分清楚上周有个做客服系统的同行问我DeepSeek 是不是就是那个便宜的大模型把接口地址一换就能顶上去。我让他先别急着改代码——他手里的活儿是工单分类加多轮追问属于典型的结构化输出 长上下文任务而他准备直接上带思维链的推理模型。真按这个方案上线JSON 解析会大面积失败多轮对话还会报 400。所以讲 DeepSeek 从入门到精通第一件要分清的事不是参数怎么调而是它到底给了你几样东西一个是通用对话模型负责日常问答、抽取、改写一个是带显式思维链的推理模型负责数学、逻辑、复杂代码还有一批从 1.5B 到 70B 不等、可以下载权重的小尺寸蒸馏模型负责私有化和离线场景。这三类模型的能力边界、参数支持、价格结构都不一样混着用就是给自己挖坑。下面按我自己的落地顺序拆先跑通最小调用再处理提示词和推理链然后接检索和工具调用最后把上线后真踩过的坑摊开。2. 第一次跑通API 调用和本地推理两条路的取舍点在哪选 API 还是本地部署判断标准其实只有三条数据能不能出内网、并发峰值有多高、单次调用的上下文有多长。数据敏感、必须过等保、或者要保证离线可用那只能本地反过来如果只是想验证效果、做原型、跑内部工具API 是唯一理性选择因为本地部署一台能跑得动大参数量模型的机器光显存成本就够买好几年的调用量了。中间地带是存在的——用蒸馏小模型在单卡上跑牺牲一部分推理质量换成本和可控性这也是后一章要重点算的账。2.1 API 方式兼容 OpenAI 协议的最小可用调用DeepSeek 的接口走的是 OpenAI 兼容协议这意味着你现有的 SDK、现成的封装库、甚至团队里写了一半的代码基本不用重写改 key 和 base_url 就能跑。这是它上手成本低的主要原因也是最容易被误读的地方——协议兼容不等于行为兼容采样参数的默认值、流式返回的字段结构、错误码的含义都有差异。from openai import OpenAI client OpenAI( api_keyYOUR_API_KEY, base_urlhttps://api.deepseek.com, # OpenAI 兼容入口注意末尾不要多写 /v1 ) resp client.chat.completions.create( modeldeepseek-chat, # 通用对话模型推理模型换成 deepseek-reasoner messages[ {role: system, content: 你是工单分类助手只输出规定格式不解释。}, {role: user, content: 用户反馈付款成功但订单状态还是待支付已重试两次。}, ], temperature0.2, # 分类任务压低随机性取值理由见 2.3 max_tokens512, # 输出上限按最长可能答案的 1.5 倍设 streamFalse, # 先跑通再考虑流式调试阶段关掉 timeout60, # 必设默认超时在长文本场景下太短 ) print(resp.choices[0].message.content) print(resp.usage) # 每次都要看prompt_tokens / completion_tokens这段代码里真正需要注意的只有三处。base_url不要自作聪明补成/v1结尾部分兼容层会因此拼出重复路径报 404timeout必须显式设置长上下文加推理模型时单次响应超过 60 秒是常事不设超时会让上游连接池被拖死resp.usage要打印出来它是后面算成本和做容量规划的原始数据很多人上线两个月了还不知道自己平均每次调用花多少 token这是血泪经验。对于推理模型返回体里会多一个reasoning_content字段装着模型的思考过程content里才是最终答案。这两个字段的关系处理错了就是 5.1 节要展开的那个 400 报错。2.2 本地起服务Ollama 试水和 vLLM 上生产是两回事本地部署最容易犯的错是拿试水工具直接上生产。Ollama 适合验证这个尺寸的模型在中文任务上够不够用一条命令就能跑起来vLLM 适合承接真实并发有连续批处理和 PagedAttention吞吐量差一个数量级。两者的部署命令和关键参数完全不是一套。先用 Ollama 做效果验证五分钟能看到结果# 拉取蒸馏版小模型具体 tag 以模型仓库页面为准这里以 7B 为例 ollama pull deepseek-r1:7b # 启动本地服务默认监听 11434 ollama serve # 单条测试确认模型能正常输出中文 ollama run deepseek-r1:7b 用三句话说明 MoE 架构相比稠密模型的显存优势验证通过之后换成 vLLM 起 OpenAI 兼容服务业务代码只需要改 base_url 指向本机python -m vllm.entrypoints.openai.api_server \ --model /models/DeepSeek-R1-Distill-Qwen-7B \ --served-model-name ds-local \ # 业务侧 model 字段填这个名字 --tensor-parallel-size 1 \ # 等于使用的 GPU 张数8 卡就填 8 --max-model-len 8192 \ # 上下文上限直接影响 KV Cache 显存占用 --gpu-memory-utilization 0.90 \ # 预留 10% 给 CUDA 上下文和临时张量 --port 8000--tensor-parallel-size必须整除注意力头数填错会直接启动失败--max-model-len是最容易翻车的参数它决定了每个并发请求预分配的 KV Cache 大小设成 32768 而实际业务只需要 8K等于白白浪费一半显存进而拉低并发数--gpu-memory-utilization建议从 0.85 起试0.95 看起来很划算但留给临时张量的空间不足时会在长请求上偶发 OOM属于典型的玄学故障日志里只有一行 CUDA out of memory看不出规律。显存估算的经验公式是权重显存约等于参数量乘以精度字节数BF16 下 7B 模型约 14GB再加上 KV Cache 和激活值的开销实际占用通常是权重的一点三到一点五倍。按 7B 模型、8K 上下文、10 并发估算24GB 单卡是起步配置32GB 更稳。2.3 五个必调参数和它们的实际取值参数不是调得越多越好生产环境里真正需要动的就五个。把这张表当成默认配置来改比每次凭感觉试要靠谱得多。参数作用通用对话模型推理模型说明temperature采样随机性0.2~0.7不支持抽取、分类、JSON 输出取 0.2 以下top_p核采样阈值0.9~0.95不支持与 temperature 只调一个避免叠加max_tokens输出长度上限按业务设需留足思考空间推理模型要把思考 token 算进去stream流式返回前端交互场景开同左关闭时注意超时设置response_format结构化输出json_object同左需配套提示词约束temperature和top_p在推理模型上设置了也不会生效部分兼容层甚至会因为传了这些字段抛参数校验错误。这不是 bug是推理模型的解码策略本身就固定了它靠强化学习收敛出来的思维链不需要你去搅动分布。把这两个字段从推理模型的调用里删掉能省掉一类莫名其妙的报错。max_tokens在推理模型上是双重含义思考过程也消耗这个配额。设成 1024 让模型解一道需要深度推理的题很可能思考到一半就被截断content返回空字符串而finish_reason是length。这属于现象诡异但原因简单的一类问题排查时第一时间看finish_reason。3. 提示词与思维链通用模型和推理模型不能用同一套写法网上流传的提示词模板绝大多数是按通用对话模型的脾气写的——给角色、给示例、给分步指令甚至专门叮嘱请一步一步思考。这套东西搬到推理模型上效果往往不升反降。原因是推理模型已经通过强化学习内化了推理行为你再用提示词灌一遍思维链等于在它自己的思考过程外面套了一层壳既浪费 token 又干扰收敛。这一章把两类模型的写法分开讲。3.1 通用对话模型的提示词骨架四段式最稳我在生产里用的骨架固定四段角色与边界、任务定义、约束条件、输出格式。四段缺一段就会出问题——缺边界模型会主动扩展话题缺约束它会在答案里加以上仅供参考这类废话缺输出格式下游解析就要写一堆容错。prompt [角色] 你是电商售后工单分类器只处理与订单、物流、退款相关的问题。 [任务] 将用户输入归入以下四类之一order_status / logistics / refund / other。 [约束] 1. 只输出 JSON不要任何解释性文字 2. 无法判断时归入 other不要猜测 3. 分类依据只看用户明确陈述的事实不推断。 [输出格式] {category: 四选一的枚举值, confidence: 0.0到1.0之间的小数} 这套写法的关键在第三段。约束要写成可判定的规则而不是形容词。回答要专业这种约束等于没写只输出 JSON不要任何解释性文字才是可执行的。实测下来把约束写成编号列表比写成一段话的遵从率高不少模型对编号结构更敏感。3.2 推理模型的三个反直觉用法第一不要在提示词里写请一步一步思考Lets think step by step。这句话对通用模型是有效增益对推理模型是纯噪声它会让模型在已经内化的思维链之外再生成一段模仿人类的步骤说明输出变长、延迟上升、准确率反而可能下降。直接给问题和约束就够了。第二少样本示例要慎用。通用模型靠示例对齐格式推理模型对示例的敏感性更高给三个示例它容易把示例里的具体数值当成模式去套。如果必须给格式参考给一个就够并且把示例里的业务数据换成明显无关的占位内容。第三追问要开新会话而不是追加历史。推理模型的多轮对话里上一轮的思考过程不应该带回下一轮的上下文。正确做法是只保留content把reasoning_content丢掉。这一点在 5.1 节展开。3.3 结构化输出让 JSON 稳定解析的写法即便开了 JSON 模式返回空对象、字段名拼错、类型不符的情况仍然会出现。原因是 JSON 模式只保证输出是合法 JSON不保证符合你的 schema。要压住这个不确定性三件事一起做开启response_format、提示词里出现 json 字样并给出完整示例、代码侧做 schema 校验加一次重试。import json def extract(user_text: str) - dict: resp client.chat.completions.create( modeldeepseek-chat, messages[ {role: system, content: 输出必须是 JSON 对象键名固定为 category 和 confidence。}, {role: user, content: user_text}, ], temperature0.0, # 结构化抽取直接归零 response_format{type: json_object}, # 强制 JSON 模式 max_tokens256, ) raw resp.choices[0].message.content try: data json.loads(raw) assert data.get(category) in {order_status, logistics, refund, other} return data except (json.JSONDecodeError, AssertionError): # 兜底一次重试把错误结构回传给模型让它自纠 return {category: other, confidence: 0.0}提示词里必须显式出现 JSON 这个词这是 JSON 模式的硬性前提漏了会返回空白内容而且不报错属于最难排查的一类。temperature0.0在这里不是玄学是为了让同一个输入多次调用得到一致结果便于回归测试。最后那段except是后悔药——线上跑久了一定会遇到模型返回{category: 退款}这种中文枚举值的情况兜底分支保证下游不会拿到脏数据。4. 接进业务系统检索增强、工具调用与 token 成本单次调用跑通只是起点。真实业务里模型的输入从来不是用户那一句话而是检索出来的文档片段、数据库查询结果、历史会话摘要拼起来的一大段上下文。这一段决定了系统的上限也决定了账单的下限。4.1 文档切分与检索链路的最小实现切分策略比 embedding 模型的选择更影响最终效果。我踩过的坑是按固定字符数硬切切出来的块经常在句子中间断开模型拿到半句话只能瞎猜。改成按标题层级切、块内保留父级标题、块大小控制在 300 到 500 字、相邻块重叠 60 字召回质量立刻上一个台阶。def build_prompt(question: str, chunks: list[str]) - str: # 每块前面挂上来源编号方便模型引用也方便你回溯是哪块召错了 context \n\n.join(f[{i1}] {c} for i, c in enumerate(chunks)) return f根据下列资料回答问题资料中没有的信息直接说资料未提及不要编造。 引用时标注来源编号格式如 [1]。 资料 {context} 问题{question} 资料未提及这句约束是整段提示词里最值钱的部分。不加它模型会用训练时的先验知识补全答案用户看到的是一段读起来很顺、但和你的文档毫无关系的内容这种错误极难被人工发现。标注来源编号则给了你一条排查线索答错了先看引用的编号对不对能快速区分是检索层的问题还是生成层的问题。4.2 函数调用让模型去查数据而不是背数据凡是会变的数据——库存、订单状态、实时价格——都不要指望模型记住用工具调用让它现查。DeepSeek 的通用对话模型支持标准 OpenAI 格式的 tools 参数写法可以直接复用。tools [{ type: function, function: { name: query_order, description: 根据订单号查询订单当前状态仅在用户提供订单号时调用, parameters: { type: object, properties: {order_id: {type: string, description: 纯数字订单号}}, required: [order_id], }, }, }] resp client.chat.completions.create( modeldeepseek-chat, messages[{role: user, content: 我的订单 20240512001 到哪了}], toolstools, tool_choiceauto, # 改成 {type:function,function:{name:query_order}} 可强制调用 )description里那句仅在用户提供订单号时调用是必须的。不写这句模型会在用户只是问一般多久发货的时候也去调接口然后因为参数缺失反复重试把一次简单问答变成三次调用。函数调用失败最常见的原因不是模型不会调而是它太爱调。tool_choiceauto是默认值某些强约束场景可以强制指定但要清楚强制的代价是模型失去判断该不该调的能力。拿到工具返回结果后要把结果作为roletool的消息追加进 messages 再请求一次模型才会基于结果生成自然语言回答。这一步漏掉用户会看到一段空的content只因为模型还在等工具结果。4.3 成本与延迟把 token 账算在写代码之前成本结构上有两件事值得提前规划。一是输入输出分开计价输出通常贵得多所以能用结构化短输出解决的不要让它写长篇二是上下文缓存同一段长系统提示词或同一份长文档在短时间内反复出现时命中的部分输入有折扣把固定内容放前面、变化内容放后面命中率会明显提升。延迟方面首 token 时间和总时长要分开看。首 token 取决于输入长度和排队总时长还取决于输出 token 数。给用户做交互界面时优先保证首 token 快也就是把输入压短做批处理任务时优先保证总时长可控也就是限制max_tokens。这两个目标经常冲突得看场景取舍不能一概而论。5. 避坑与排查上线后最容易翻车的五个地方下面五条都是真出过问题的按现象、原因、解决写遇到类似症状可以直接对照。5.1 多轮对话把 reasoning_content 回传接口直接 400现象单轮调用完全正常改成多轮之后第二轮开始稳定报 400错误信息指向消息格式非法。原因推理模型的返回体里reasoning_content和content是两个字段很多人图省事把整个message对象原样 append 进历史记录下一轮请求里就带上了reasoning_content。这个字段不允许作为输入回传。解决构造历史消息时只保留role和content两个键显式重建字典而不是直接复用返回对象。加一个to_history(msg)的转换函数所有地方统一走它别在每个调用点手写。5.2 调高温度想要更有创意结果 JSON 全线解析失败现象换了temperature1.2之后下游日志里每隔几条就出现 JSON 解析异常人工看返回内容还能看出是模型加了注释或者少了引号。原因结构化输出任务对采样随机性极其敏感温度越高模型越倾向于自由发挥格式细节。JSON 模式只保证语法合法不保证严格遵守你的 schema。解决所有需要机器解析的调用temperature一律压到 0.2 以下实测 0.0 到 0.1 最稳。创意类需求单独开一条链路和抽取、分类的链路物理隔离不要用同一个配置。5.3 长文档整篇塞进去超出上下文后行为不一致现象短文正常超过一定长度后要么报长度超限要么不报错但答案明显漏掉了后半部分内容。原因不同模型版本的上下文窗口不一样超出之后的行为也不统一——有的直接报错有的静默截断。而截断是从哪一端截取决于服务端实现你无法假设它保留了开头。解决在客户端做硬性长度校验用 tokenizer 先估算再发送超过阈值就走分块摘要或者检索。不要依赖服务端兜底静默截断是最难查的一类问题因为它不报错。5.4 流式输出中途断连用户看到半句话就没了现象前端偶发显示不完整的回答刷新后又正常日志里没有任何异常。原因流式返回是长连接网关空闲超时、客户端网络抖动、或者服务端限流都可能在传输中途断开而很多 SDK 默认不重试流式请求。解决在客户端捕获流读取异常记录已经收到的内容长度重连时把已收到的部分作为上下文让模型续写或者干脆降级成非流式重试一次。同时检查网关的空闲超时配置调到大于最长预期响应时间。5.5 本地部署按参数量乘二估算显存一上并发就 OOM现象单条请求跑得好好的压测到十几个并发就开始报显存不足重启后又能跑一会儿。原因显存不是只装权重。KV Cache 随着并发数和上下文长度线性增长激活值和临时张量也要占一块。只按权重估算等于把最可变的那部分完全忽略了。解决先用单并发跑出稳定基线再逐步加压找到拐点--max-model-len按业务实际需要的长度设不要图省事设成模型支持的最大值--gpu-memory-utilization留出至少 10% 余量。这三条调完还顶不住就该考虑量化或者加卡了。6. 进阶蒸馏小模型和 API 到底怎么选用一张评测表定选型讨论最容易变成口水战因为大家比的是感觉哪个更聪明。我的做法是先花半天时间搭一个二十到五十条的小评测集全部来自真实业务样本标注好标准答案然后让候选方案跑同一批题人工或脚本打分。这件事的投入产出比高得离谱但愿意做的人不多。评测集按任务类型分层每层至少十条覆盖抽取、分类、多跳问答、长文档理解。打分只看两个指标准确率和单次成本。延迟单独记录因为它和并发策略强相关不适合和准确率放在一起比。方案抽取准确率多跳问答单次成本适用判断通用对话模型 API高中中结构化任务主力推理模型 API中高高复杂推理、代码场景7B 蒸馏模型本地中低极低高频简单任务、离线场景32B 蒸馏模型本地较高中低数据不出内网的折中方案跑完这张表通常会得到一个反直觉的结论最高频的那部分流量用最小的模型就够了把大模型留给真正难的那百分之十。我现在的做法是路由分流——先用规则和小模型处理置信度低于阈值再升级到大模型整体成本能降下来一大截而用户几乎感知不到差别。评测脚本本身很简单关键是别偷懒import json, time def evaluate(cases: list[dict], call_fn) - dict: hit, total_cost, total_latency 0, 0.0, 0.0 for c in cases: t0 time.time() out call_fn(c[input]) # call_fn 内部区分走 API 还是本地服务 total_latency time.time() - t0 if normalize(out) normalize(c[answer]): hit 1 n len(cases) return {accuracy: hit / n, avg_latency: total_latency / n}normalize这个函数别省中文标点全半角、数字格式、大小写都会让其实答对了被判成错我第一次跑评测就是因为这个把准确率算低了两成差点错误地把一个可用方案毙掉。最后一句实在话模型选型这件事讨论三天不如跑一次评测。我现在的习惯是任何新方案进生产前必须先过评测集哪怕只跑二十条也比拍脑袋强。希望帮到你。本文还有配套的精品资源点击获取