简介:这份由山东大学经济学院李铁岗教授团队出品的《DeepSeek应用与部署》演示文稿,共80页,面向希望系统了解大模型技术演进、部署思路与业务落地的开发者、企业技术负责人及高校研究者。内容从AIGC与语言模型发展脉络切入,梳理DeepSeek V2的Multi-Head Latent Attention、V3推理模型以及PPO、GRPO强化学习优化路径,并按基础、中级、高级、终极四个能力层级展开多模态融合、动态数据治理、因果推理、多目标优化、数字孪生仿真、多智能体协同与自编程等应用场景,兼顾API调用与医疗、教育、金融等垂直行业落地。资源包为单个pptx文件,约16.01MB,结构清晰,适合按章节查阅。目前已有459人学习。读者可借助它快速建立从模型架构到部署方案的完整认知,获取可复用的能力分层框架与业务决策参考。
1. 从一份 80 页课件说起:DeepSeek 部署到底卡在哪
很多人拿到这份山东大学经济学院的 80 页课件,第一眼看到的是 AIGC 十年时间线、LLM 六年演进、DeepSeek 的能力四层分级,觉得是一份科普材料。但真动手把 DeepSeek 接进业务的人会发现,课件里真正值钱的只有两处:V2 的 Multi-Head Latent Attention 和 V3 那一代的推理模型加 PPO/GRPO 强化学习。前者决定你能不能把模型塞进有限的显存里跑起来,后者决定你该不该做 Agent、该按什么粒度去拆业务。
这也是「DeepSeek 应用与部署」这类需求最容易被讲偏的地方:一上来就贴 API 调用示例,跑通了 demo 就算完工。真实项目里卡人的是显存怎么算、量化选哪档、并发上不去是谁的锅、思维链输出把 max_tokens 吃光了怎么办。后面几章按架构约束、本地化部署、API 调用与密钥治理、业务应用、效果验证的顺序展开,每一步都给可复现的命令和参数。
2. DeepSeek 架构与推理范式:MLA、V3 推理模型与 GRPO 的工程含义
2.1 MLA 为什么能把 KV Cache 压成可控项
标准 MHA 的 KV Cache 形状是[B, H_kv, S, D],层数一多、上下文一长,这部分显存能超过模型权重本身。DeepSeek V2 引入的 Multi-Head Latent Attention 换了个思路:不直接缓存完整的 K 和 V,而是先把它们投影到一个低维 latent 向量c_t,用时再上投影还原;同时把携带位置信息的那一小段分量单独保存,避免压缩过程把位置编码搅坏。
工程上的后果很直接:同样一张卡,能开的并发数和上下文长度都上去了。下面这段脚本用来估算 KV Cache 量级,把 MLA 的压缩比调成 1.0 就是标准 MHA 的算法,方便对比。
def kv_cache_gb(layers, kv_heads, head_dim, seq_len, batch, bytes_per=2, compress_ratio=1.0): """ layers : Transformer 层数 kv_heads : KV 头数(GQA/MQA 时小于 attention 头数) head_dim : 每个头的维度 seq_len : 上下文长度 batch : 并发序列数(vLLM 里约等于同时活跃的请求数) bytes_per : FP16/BF16 取 2,FP8/INT8 取 1 compress_ratio: MLA 的 latent 压缩比,1.0 表示标准 MHA """ per_token = 2 * layers * kv_heads * head_dim * bytes_per # K 和 V 各一份 total = per_token * seq_len * batch * compress_ratio return total / 1024 ** 3 print(kv_cache_gb(61, 8, 128, 32768, 8)) # 标准 GQA print(kv_cache_gb(61, 8, 128, 32768, 8, 2, 0.08)) # 近似的 MLA 量级逻辑说明:系数 2 代表 K、V 两份缓存,头数乘头维度得到每层每 token 的存储宽度,再乘层数、序列长度和并发数。参数说明:compress_ratio不是官方数字,而是给你做容量规划用的上界估计,实际值取决于模型配置,建议先按 0.1 左右预留,再用真实压测结果修正。注意,MoE 结构下权重的显存占用和激活参数量不是一个数量级,别拿总参数量直接乘字节数,会把自己吓退。
2.2 V3 推理模型与 PPO、GRPO 的差异
课件里把强化学习的要素写得比较清楚:智能体在环境中不断尝试,优化策略,最终拿到最大化奖励。落到算法实现上,PPO 和 GRPO 的差别会直接影响你训练侧的资源规划。
PPO 需要额外维护一个 value model 来估计基线,显存占用和调参成本都高,优势估计的偏差要靠 critic 去压。GRPO 的做法是去掉 value model,对同一个 prompt 采样一组回答,用组内相对得分做基线,组内归一化后算优势。省掉了一个和策略模型同量级的网络,训练显存降下来,代价是采样并行度要求更高,rollout 吞吐成了新瓶颈。
| 维度 | PPO | GRPO |
|---|---|---|
| 是否需要 value model | 需要,显存约等于策略模型 | 不需要 |
| 优势估计方式 | GAE + critic 预测 | 组内奖励归一化 |
| 采样并行度要求 | 中等 | 高,组越大方差越低 |
| 主要调参项 | clip 系数、critic 学习率 | 组大小、KL 惩罚系数 |
| 部署侧影响 | 训练集群并行策略复杂 | 推理集群吞吐压力大 |
2.3 从训练范式反推部署侧的三条约束
第一条是显存约束。推理模型输出的是思维链,一次请求的实际生成长度可能是普通对话的三到五倍,KV Cache 随生成长度线性增长,估算容量时不能只按输入长度算。
第二条是吞吐约束。MoE 结构要做专家并行,专家分布在多卡上,通信开销随并行度上升,小 batch 场景下 GPU 利用率会很差,所以本地部署要么攒 batch,要么直接接受低并发。
第三条是上下文约束。长思维链叠上 RAG 检索回来的文档块,很容易顶到上下文上限,表现为对话突然被截断或者报长度超限,这块的处理方式在 4.2 节展开。
3. 本地化部署方案:Ollama、llama.cpp 与 vLLM 的选型与参数
3.1 四条路线的适用边界
选型不需要纠结,先看并发和显存两个数。
| 路线 | 典型场景 | 并发能力 | 量化支持 | 主要坑 |
|---|---|---|---|---|
| Ollama | 个人开发机、内网小工具 | 低(个位数) | GGUF,Q4 到 Q8 | 默认上下文偏小,需手动调 |
| llama.cpp | CPU 或混合推理、边缘设备 | 很低 | GGUF,全档位 | CPU 上首 token 延迟高 |
| vLLM | 生产服务、多卡 | 高(连续批处理) | AWQ/GPTQ/FP8 | 显存预分配激进,需调占用率 |
| 托管 API | 快速验证、峰值弹性 | 取决于配额 | 不涉及 | 数据出域、成本不可控 |
常见做法是:验证阶段用托管 API 和 Ollama 各跑一遍,确认提示词和输出格式稳定后,再把量大的那条链路迁到 vLLM 上自建。
3.2 显存测算与量化档位
权重占显存的算法很朴素:参数量乘以每参数字节数。FP16/BF16 是 2 字节,FP8/INT8 是 1 字节,Q4 大约 0.5 字节再加一点量化元数据开销。加上 2.1 节算出来的 KV Cache,再留 10% 到 15% 给激活值和框架开销,就是你的卡能不能装下的判断依据。
| 量化档位 | 每参数字节 | 精度损失 | 适用判断 |
|---|---|---|---|
| BF16 | 2.0 | 无 | 多卡、对精度敏感 |
| FP8 | 1.0 | 很小 | 支持 FP8 的新卡首选 |
| INT8 / Q8 | 1.0 | 小 | 单卡想跑大一点的模型 |
| Q4 | 0.5 | 可感知 | 显存紧张、任务偏生成 |
提示:量化档位别只看显存省了多少,先拿自己的业务测试集跑一遍。分类、抽取类任务对量化比较敏感,摘要和润色类任务通常无感。
3.3 Ollama 快速起一个本地服务
先装 Ollama,拉一个中等尺寸的模型,直接用它内置的 OpenAI 兼容接口验证链路。
# 启动服务,默认监听 11434 ollama serve & # 拉取模型(以 14B 档为例) ollama pull deepseek-r1:14b # 关键:默认上下文窗口偏小,显存够就把 num_ctx 调大 curl http://localhost:11434/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "deepseek-r1:14b", "messages": [{"role": "user", "content": "用三句话解释 MoE 路由"}], "temperature": 0.6, "max_tokens": 512, "stream": false }'逻辑说明:ollama serve之后,/v1/chat/completions就是 OpenAI 兼容端点,现有代码只要改 base_url 就能切过来。参数说明:num_ctx需要在模型参数里配,Ollama 默认值对长文档场景不够用;temperature在推理模型上别调太低,低于 0.5 时思维链容易塌缩成短回答。排查思路:如果返回内容为空,先看是不是被max_tokens截断在思维链里了。
3.4 vLLM 生产部署的关键参数
多卡场景我一般直接用 vLLM 的 serve 模式,参数一屏配完。
python -m vllm.entrypoints.openai.api_server \ --model /models/deepseek-chat \ --served-model-name deepseek-chat \ --tensor-parallel-size 8 \ --max-model-len 32768 \ --gpu-memory-utilization 0.90 \ --enable-prefix-caching \ --swap-space 16 \ --trust-remote-code \ --port 8000逻辑说明:--tensor-parallel-size要和可见 GPU 数一致,张量并行能切开权重但每层都有两次 all-reduce,卡数越多通信占比越高。参数说明:--max-model-len要和你真实的最长上下文匹配,设太大等于把 KV Cache 池子提前占掉;--gpu-memory-utilization从 0.9 起调,遇到 OOM 就往下压到 0.85;--enable-prefix-caching对系统提示词固定的业务非常值,命中后首 token 延迟能明显下降。
注意:启动阶段报显存不足,先降
--max-model-len,再降--gpu-memory-utilization,最后才考虑换量化版本。顺序反了会白折腾一晚上。
4. DeepSeek API 调用:协议、流式、工具调用与密钥治理
4.1 最小可用调用
接口是 OpenAI 兼容协议,客户端不用换。
import os from openai import OpenAI client = OpenAI( api_key=os.environ["DEEPSEEK_API_KEY"], # 从环境变量读,别写死在代码里 base_url="https://api.deepseek.com/v1", # 官方兼容端点 ) resp = client.chat.completions.create( model="deepseek-chat", messages=[ {"role": "system", "content": "你是金融合规助手,回答必须给条款依据"}, {"role": "user", "content": "客户风险等级上调需要哪些留痕材料?"}, ], temperature=0.3, # 合规类任务压低随机性 top_p=0.9, max_tokens=1024, stream=False, timeout=60, ) print(resp.choices[0].message.content) print(resp.usage) # 看 prompt/completion token,做成本核算逻辑说明:messages里 system 承载角色和约束,比塞在 user 里更稳。参数说明:temperature控制采样随机性,抽取和分类任务设 0.1 到 0.3;max_tokens在推理模型上要留够,思维链本身也是 token;timeout必须显式设置,长思维链请求超过默认超时会让上层重试,重试再把额度打满。
4.2 流式输出与超长对话截断
交互式界面一定要开流式,否则用户盯着空白等十几秒。
stream = client.chat.completions.create( model="deepseek-chat", messages=history, stream=True, max_tokens=2048, ) buf = [] for chunk in stream: delta = chunk.choices[0].delta.content or "" if delta: buf.append(delta) print(delta, end="", flush=True) # 边收边渲染 full_text = "".join(buf)逻辑说明:流式只改变传输方式,不改模型行为,但要注意delta.content可能是空字符串,直接拼接会报错。参数说明:流式下usage字段不一定会返回,成本统计要单独兜底。
超长对话的处理策略是分层:最近 N 轮原样保留,更早的轮次用一次摘要请求压成一段话,检索到的文档块只保留命中的片段而不是整篇。常见踩坑是把整个知识库塞进 system,结果第二次对话就撞上长度上限,表现为「达到对话长度上限,请开启新对话」这类提示。
4.3 Function Calling 与结构化输出
要让模型调你的接口,用工具声明而不是在提示词里描述格式。
tools = [{ "type": "function", "function": { "name": "query_order", "description": "按订单号查询物流状态", "parameters": { "type": "object", "properties": { "order_id": {"type": "string", "description": "订单号,纯数字"}, "with_detail": {"type": "boolean", "default": False}, }, "required": ["order_id"], }, }, }] resp = client.chat.completions.create( model="deepseek-chat", messages=[{"role": "user", "content": "帮我查下 20250312 这个单到哪了"}], tools=tools, tool_choice="auto", ) call = resp.choices[0].message.tool_calls if call: import json args = json.loads(call[0].function.arguments) # 到这里再真正去调内部服务,不要相信模型给的任何业务数据 print(call[0].function.name, args)逻辑说明:模型只负责把自然语言映射成结构化参数,真正的查询由你的服务执行,返回结果后用role="tool"的消息追加回对话再请求一次。参数说明:tool_choice="auto"让模型自己判断要不要调,强约束场景可以指定具体函数名;description写得越具体,参数抽取越准。要 JSON 输出但不涉及工具时,用response_format={"type": "json_object"},并在提示词里给一个字段示例。
4.4 API 密钥权限分层与额度控制
密钥管理是落地阶段最容易出事的一环。我一般按四层来管:
- 密钥只进环境变量或密钥管理服务,禁止写进代码仓库、前端和日志。
- 按业务线分发子密钥,一条业务线一把,出事能单独吊销。
- 中间加一层 OpenAI 兼容网关,统一限流、计费、审计和模型别名映射。编辑器插件和 CLI 工具接入时统一填网关地址和模型别名,避免每换一个客户端就改一次配置。
- 日志脱敏,prompt 和 completion 落库前先过滤身份证、手机号、账号这类字段。
注意:接入编辑器或 CLI 插件时报
request extension preparation failed一类错误,九成是 base_url 和模型名不匹配,别急着怀疑网络。
5. 业务应用落地:能力层级、RAG 链路与低代码编排
5.1 用能力层级倒推业务选型
课件把 DeepSeek 的能力分成基础、中级、高级、终极四层,这个划分拿来当选型表比当宣传语有用得多。
| 能力层级 | 课件中的关键能力 | 落到业务上的形态 |
|---|---|---|
| 基础层 | 多模态融合、动态数据治理 | 文档解析、格式归一、脏数据清洗 |
| 中级层 | 领域自适应、因果推理、多目标优化 | 垂直知识问答、风控规则推理、排产寻优 |
| 高级层 | 数字孪生、多智能体协同、元认知调控 | 仿真推演、跨部门 Agent 协作 |
| 终极层 | 概念空间探索、自编程 | 研发辅助、自动化测试用例生成 |
多数企业的第一个项目应该压在基础层和中级层之间:把散落在 PDF、扫描件、Excel 里的数据统一成结构化字段,再接一个领域问答。直接冲着高级层去,通常会在数据治理这一步就停住。
5.2 RAG 检索增强的最小可用链路
from sentence_transformers import SentenceTransformer import faiss, numpy as np encoder = SentenceTransformer("BAAI/bge-m3") # 中文检索效果较稳的向量模型 def build_index(chunks): vecs = encoder.encode(chunks, normalize_embeddings=True) # 归一化后用内积=余弦 index = faiss.IndexFlatIP(vecs.shape[1]) index.add(np.asarray(vecs, dtype="float32")) return index def retrieve(index, chunks, query, top_k=5): q = encoder.encode([query], normalize_embeddings=True) scores, idx = index.search(np.asarray(q, dtype="float32"), top_k) return [(chunks[i], float(s)) for s, i in zip(scores[0], idx[0])]逻辑说明:归一化之后内积等价于余弦相似度,省掉一次除法。参数说明:top_k别贪大,召回五到八块就够,块与块之间留 10% 到 20% 的重叠避免切断语义;召回分数低于阈值时宁可返回「未找到依据」,也别让模型自由发挥。切片粒度按业务走,条款类文档按条切,技术手册按小节切。
提示词模板要把检索结果和问题隔开:
prompt = f"""根据以下资料回答问题,资料中没有的内容直接回答"未收录"。 资料: {chr(10).join(f"[{i+1}] {c}" for i, (c, _) in enumerate(hits))} 问题:{user_query} 要求:每个结论后标注引用的资料编号。"""5.3 低代码编排与流程集成
不是所有场景都值得写代码。审批流、消息推送、定时报表这类链路,用 n8n 或 FastGPT 这类编排工具串起来更快,模型节点直接指向你的网关地址即可。
docker run -d --name n8n \ -p 5678:5678 \ -e N8N_ENCRYPTION_KEY=$(openssl rand -hex 16) \ -e EXECUTIONS_MODE=queue \ -e QUEUE_BULL_REDIS_HOST=redis \ -v n8n_data:/home/node/.n8n \ n8nio/n8n逻辑说明:EXECUTIONS_MODE=queue把执行进程和主进程拆开,配合 Redis 做任务队列,多实例部署时不会重复触发。参数说明:N8N_ENCRYPTION_KEY一旦设定就不能改,否则已存的凭据全部解不开,上线前先写进密钥管理。并发量再往上走,记得给队列加 worker 实例,单靠加机器不解决问题。
5.4 验收指标与常见失败模式
上线前至少要看四个数:首 token 延迟、端到端 P95 延迟、单位请求 token 成本、人工兜底率。前两个决定体验,后两个决定这个项目能不能长期活着。
常见失败模式有三类:检索召回不准导致答非所问,这时先看切片和向量模型,别急着换大模型;输出不稳定导致结构化解析失败,改用工具调用或 JSON 模式;成本失控,多半是 system 提示词太长或者思维链没做截断。
6. 效果验证与调优:把主观感受换成可复现的数字
调优最怕凭感觉。我一般先固化一个 100 到 200 条的小评测集,每条包含问题、标准答案要点和是否可回答的标记,每次改提示词或换模型都跑一遍。
import json, statistics def evaluate(client, cases, model="deepseek-chat"): hit, latencies = 0, [] for c in cases: t0 = time.time() r = client.chat.completions.create( model=model, messages=[{"role": "user", "content": c["q"]}], temperature=0.2, max_tokens=512, ) latencies.append(time.time() - t0) ans = r.choices[0].message.content # 要点覆盖式打分,比整句匹配鲁棒 hit += all(k in ans for k in c["keys"]) return { "accuracy": hit / len(cases), "p95_latency": statistics.quantiles(latencies, n=20)[18], }逻辑说明:用要点覆盖率代替字符串完全匹配,避免模型换个说法就被判错。参数说明:评测时固定temperature,否则同一条数据两次结果不可比;p95_latency取 20 分位的第 19 个值,样本量太小时改用max()更稳妥。
延迟分解也值得做一次,把请求耗时拆成排队、首 token、生成三段。排队时间长说明并发配额或--gpu-memory-utilization需要调;首 token 慢通常是提示词太长,开前缀缓存能缓解;生成阶段慢则和输出长度正相关,考虑限制思维链长度或者在业务侧做答案裁剪。
一个容易被忽略的技巧是缓存。把(模型, 提示词模板, 问题)哈希后写入 Redis,命中直接返回,对报表生成、固定问答这类重复率高的场景,能省掉相当一部分调用量。缓存要设过期时间,模型或提示词一变就整体失效,否则会拿旧答案糊弄用户。
本文还有配套的精品资源,点击获取