零基础入门 DeepSeek 大模型 API 开发全指南:max_tokens 停止序列 temperature 系统提示四大核心参数详解、调优实战与两种 Prompt 写法效果对比教程
调用 DeepSeek 大模型 API 的四大核心可控参数为:
max_tokens、stop(停止序列)、temperature、system(系统提示),分别控制输出长度、停止时机、随机程度、角色设定。max_tokens是输出 token 数的上限,设太小会截断内容,设太大浪费算力;生成 token 越多,接口响应耗时越长。stop停止序列可以让模型遇到指定字符串时立刻停止生成,适合控制结构化输出的边界,但停止符本身不会出现在返回结果中。temperature控制输出随机性,0 最保守稳定、适合计算分析类任务,1 最自然多样、适合创意写作类任务。system系统提示用于设定模型全局角色与规则,指令效果比写在用户消息中更稳定;全部指令堆在 user 消息里也能运行,但规范性和效果可控性更差。生产环境推荐「system 放角色规则 + user 放具体任务」的拆分写法,是兼顾效果、规范与可维护性的最优方案。
一、课程学习目标
本文面向零基础接触大模型 API 开发的读者,完整覆盖 DeepSeek 接口四大核心参数的原理、用法与调优技巧,同时对比两种常见的 Prompt 消息写法。学完后你将掌握:
理解
max_tokens参数的作用与调优方法使用
temperature参数精准控制模型输出的随机性掌握
stop停止序列的用途与使用注意事项理解系统提示(System prompt)的角色与最佳实践
分清两种消息结构写法的差异,能根据场景选择最优方案
二、开发环境初始化
DeepSeek 完全兼容 OpenAI 接口规范,使用官方 OpenAI Python SDK 即可完成调用,标准初始化代码如下:
from dotenv import load_dotenv from openai import OpenAI import os 加载环境变量 load_dotenv() my_api = os.getenv("DEEPSEEK_API_KEY") 初始化 DeepSeek 客户端 client = OpenAI( api_key=my_api, base_url="https://api.deepseek.com" )三、核心参数一:max_tokens(最大令牌数)
3.1 什么是 Token
大语言模型不是以完整单词 / 汉字为单位处理文本,而是以token(令牌)为最小单位。你可以把 token 理解为"文本碎片":模型先把输入文本拆成 token,再逐 token 生成输出内容。
英文场景:1 个 token ≈ 3.5 个英文字符
中文场景:1 个 token ≈ 1~2 个汉字
3.2 参数作用
max_tokens用来设置模型输出内容的最大 token 数量上限。
设得太小:模型生成到一半就被强制截断,内容不完整
设得太大:模型不会强行填满上限,只是获得了更大的生成空间,内容短的时候依然会提前自然结束
3.3 两种停止状态
通过响应对象的finish_reason可以判断模型停止的原因:
停止原因 | 含义 | 说明 |
| 自然停止 | 模型认为内容已经说完,主动结束生成 |
| 截断停止 | 输出 token 数达到了 |
3.4 为什么要调整 max_tokens
考量维度 | 具体说明 |
API 配额限制 | token 用量会计入接口额度,合理设置可控制成本、避免超量 |
性能效率 | 生成 token 越多,耗时越长、算力消耗越大,合理设值可优化响应速度 |
输出质量 | 上限太低会截断内容导致信息缺失,上限太高会造成不必要的性能开销 |
3.5 性能规律
生成 token 数量与耗时基本呈正相关:生成的内容越长,接口响应时间越久。例如生成 100token 仅需 1 秒左右,生成 4000token 则需要近 30 秒。
3.6 参数汇总表
参数项 | 详细说明 |
参数名称 |
|
核心作用 | 限制模型输出的最大 token 数量 |
取值范围 | 1 ~ 接口允许的最大值(DeepSeek 上限为 393216) |
常见问题 | 取值过小导致输出截断、内容不完整 |
调优建议 | 简单问答设 200-500,长文本生成设 1000-4000,避免无意义设超大值 |
使用max_tokens
max_tokens参数用于设置模型生成 token 数量的上限。举个例子:如果我们让模型写一首诗,并将max_tokens设为 10,模型会开始生成内容,当生成的 token 数达到 10 时会立即停止,这通常会导致输出被截断、内容不完整。我们来试一下:
truncated_response = client.chat.completions.create( model="deepseek-v4-flash", max_tokens=10, messages=[ {"role": "user", "content": "写一首诗"} ] ) print(truncated_response.choices[0].message.content)输出示例:
为你写一首小诗:
晨
实际运行结果会有随机波动,但一定会出现截断。模型刚开始写诗,生成 10 个 token 后就被迫停止。
我们还可以通过响应对象的finish_reason属性,查看模型停止生成的原因。在这个场景下,它的值为length,代表模型因达到最大 token 限制而停止。
print(truncated_response.choices[0].finish_reason)输出:
'length'
当然,如果我们把max_tokens设为更大的值,通常就能得到完整的诗作:
longer_poem_response = client.chat.completions.create( model="deepseek-v4-flash", max_tokens=500, messages=[ {"role": "user", "content": "写一首诗"} ] ) print(longer_poem_response.choices[0].message.content)输出示例:
《心音》
在静谧的时分,
当世界渐渐沉寂,
我听见心底的低语——
温柔的字句轻轻摇曳。
...
这是max_tokens设为 500 时模型生成的完整内容。 如果查看这个响应的finish_reason,会看到值为stop,代表模型自然完成了生成,内容已经输出完毕,主动停止了续写。
print(longer_poem_response.choices[0].finish_reason)输出:
'stop'
需要注意的是:模型在生成时并"不知道"max_tokens的存在。调整max_tokens不会改变模型的生成逻辑,只是给了模型更大的生成空间(数值大时)或强制截断输出(数值小时)。
同样重要的是:增大max_tokens不代表模型一定会生成对应数量的 token。比如我们让模型讲一个笑话,哪怕把max_tokens设为 1000,输出也通常远少于 1000 个 token。
response = client.chat.completions.create( model="deepseek-v4-flash", max_tokens=1000, messages=[{"role": "user", "content": "讲一个笑话"}] ) print(response.choices[0].message.content)输出示例:
分享一个经典冷笑话:
为什么科学家不信任原子?因为万物都是原子"凑"出来的!
print(response.usage.completion_tokens)
输出:
55
在上面的例子中,我们把max_tokens设为 1000,但最终生成的内容只有 55 个 token。设置上限只是划定了最大边界,不代表模型会填满这个上限。
性能演示
我们来直观感受一下生成 token 数量对性能的影响。下面的函数让模型生成一段长对话,分别使用 3 档不同的max_tokens各运行一次,打印实际生成的 token 数与耗时。
import time def compare_num_tokens_speed(): token_counts = [100, 1000, 4096] task = """ 请生成一段至少 5000 字的长对话,两个角色讨论社交媒体对心理健康的影响。 两位角色观点不同,展开理性、深入的辩论。 """ for num_tokens in token_counts: start_time = time.time() response = client.chat.completions.create( model="deepseek-v4-flash", max_tokens=num_tokens, messages=[{"role": "user", "content": task}] ) end_time = time.time() execution_time = end_time - start_time print(f"生成 token 数:{response.usage.completion_tokens}") print(f"执行耗时:{execution_time:.2f} 秒\n") compare_num_tokens_speed()示例输出:
生成 token 数:100
执行耗时:1.51 秒
生成 token 数:1000
执行耗时:8.33 秒
生成 token 数:3433
执行耗时:28.80 秒
可以清晰看到:模型生成的 token 越多,所需的时间就越长。
停止序列(Stop sequences)
另一个实用的参数是stop(停止序列),它允许我们传入一个或多个字符串作为停止标记。当模型生成的内容中出现这些字符串时,会立即停止继续生成。你可以把它理解为:"如果生成了这个标记,就立刻停下,不要再输出后续内容。"
下面是一个不使用停止序列的请求示例:
response = client.chat.completions.create( model="deepseek-v4-flash", max_tokens=500, messages=[{"role": "user", "content": "生成一个表示人物的 JSON 对象,包含姓名、邮箱、手机号三个字段。"}] ) print(response.choices[0].message.content)输出示例:
这是一个表示人物信息的 JSON 对象示例:
{
"name": "张三",
"email": "zhangsan@example.com",
"phoneNumber": "123-456-7890"
}
在这个示例中,JSON 对象包含三个键值对,分别对应...
可以看到,模型确实生成了 JSON 对象,但后面还附带了额外的解释文字。如果我们希望模型输出完 JSON 的闭合符}后就立即停止,可以加入stop参数:
response = client.chat.completions.create( model="deepseek-v4-flash", max_tokens=500, messages=[{"role": "user", "content": "生成一个表示人物的 JSON 对象,包含姓名、邮箱、手机号三个字段。"}], stop=["}"] ) print(response.choices[0].message.content)输出示例:
这是一个表示人物信息的 JSON 对象示例:
{
"name": "张三",
"email": "zhangsan@example.com",
"phone": "555-1234"
重要提示:注意生成的输出中不包含作为停止序列的}本身。如果需要完整可用的 JSON,需要我们手动把结尾的}补回去。
我们同样可以通过finish_reason查看模型停止的原因,此时值为stop,代表触发了停止序列。
print(response.choices[0].finish_reason)输出:
'stop'
多个停止序列
stop参数支持传入多个停止序列,模型只要遇到其中任意一个,就会立即停止生成。
下面的示例让模型写诗,当生成字母b或c时停止,共运行 3 次:
def generate_random_letters_3_times(): for i in range(3): response = client.chat.completions.create( model="deepseek-v4-flash", max_tokens=500, messages=[{"role": "user", "content": "写一首诗"}], stop=["b", "c"] ) print(f"第 {i+1} 次响应停止原因:{response.choices[0].finish_reason}") generate_random_letters_3_times()示例输出:
第 1 次响应停止原因:stop
第 2 次响应停止原因:stop
第 3 次响应停止原因:stop
三次生成都因为触发了停止序列而提前结束。实际业务中我们通常不会用单个字母作为停止序列,更多用于结构化输出、固定格式截断等场景。
温度(Temperature)
temperature参数用于控制生成内容的"随机性"与"创造性"。在 DeepSeek 中,它的取值范围为 0~2,默认值为 1。数值越高,输出越多样化、越不可预测,措辞变化越丰富;数值越低,输出越偏向确定性,更倾向于选择概率最高的表述与答案。
模型生成文本时,会预测下一个 token 的概率分布。temperature的作用就是在采样下一个 token 前,对这个概率分布进行缩放:
温度接近 0 时,概率分布会被"压尖",高概率的 token 权重被进一步放大,模型输出更稳定、更保守,优先选择最稳妥的答案。
温度接近 2 时,概率分布会被"拉平",低概率 token 的出现概率提升,模型输出更随机、更有探索性,内容更具创造力与多样性。
什么时候调整温度?
一个通用的选型原则:分析类任务使用接近 0 的温度,创意类任务使用接近 1 的温度。
温度效果演示
我们通过一个简单示例直观感受差异。分别使用温度 0 和温度 1,让模型 3 次生成外星行星的名字,要求只输出单个单词:
def demonstrate_temperature(): temperatures = [0, 1] for temperature in temperatures: print(f"使用 temperature = {temperature} 调用 3 次") print("================") for i in range(3): response = client.chat.completions.create( model="deepseek-v4-flash", max_tokens=100, temperature=temperature, messages=[{"role": "user", "content": "想一个外星行星的名字,仅输出单个单词。"}] ) print(f"第 {i+1} 次响应:{response.choices[0].message.content.strip()}") demonstrate_temperature()输出示例:
使用 temperature = 0 调用 3 次
================
第 1 次响应:Xendor
第 2 次响应:Xendor
第 3 次响应:Xendor
使用 temperature = 1 调用 3 次
================
第 1 次响应:Xyron
第 2 次响应:Xandar
第 3 次响应:Zyrcon
可以看到,温度为 0 时,三次输出几乎完全一致。需要注意:即使 temperature=0,也不代表 100% 完全确定,依然可能存在微小波动,但和温度为 1 的情况相比,差异非常明显。
系统提示(System prompt)
system角色的提示词是对话中的可选配置,用于给模型设定高层指令、定义角色身份、补充背景信息,从而为整段对话定下基调与规则。
关于系统提示的核心要点:
它是可选参数,但对设定对话语气、上下文与角色定位非常有用。
它作用于整段对话,会影响该次对话中模型的所有回复。
借助系统提示可以统一约束模型行为,无需在每条用户消息中重复指令。
通常建议将语气设定、角色设定、全局规则放在系统提示中;而详细的任务指令、外部输入内容(如文档)、示例样本放在用户消息中,效果更佳。系统提示只需要在对话开头设置一次,不需要在每轮用户消息中重复。
我们来试一个例子:
message = client.chat.completions.create( model="deepseek-v4-flash", max_tokens=1000, messages=[ {"role": "system", "content": "你是一位贴心的外语老师,所有回复都使用法语。"}, {"role": "user", "content": "你好,很高兴认识你!"} ] ) print(message.choices[0].message.content)输出示例:
Bonjour ! Je suis ravi de vous rencontrer. Comment allez-vous aujourd'hui ?
四、核心参数二:stop(停止序列)
4.1 参数作用
stop参数允许传入一个或多个字符串作为"停止标记"。模型生成内容时,只要遇到这些字符串,就会立刻停止继续生成,相当于给输出划定了明确的结束边界。
4.2 核心特性
触发即停:只要生成内容中出现停止序列,立刻终止后续输出
符不返回:停止序列本身不会出现在最终返回的内容里,需要手动补回
支持多个:可以同时传入多个停止符,任意一个被触发都会停止
4.3 典型使用场景
生成 JSON 时,设置
stop=["}"],让模型输出完 JSON 结构就停止,避免后面附带多余解释生成编号列表时,设置
stop=["4."],保证模型只输出前 3 条,不会多生成额外条目结构化数据提取时,用固定分隔符作为停止标记,精准控制输出范围
4.4 参数汇总表
参数项 | 详细说明 |
参数名称 |
|
核心作用 | 遇到指定字符串时立即终止生成 |
传入格式 | 字符串列表,支持单个或多个停止序列 |
重要特性 | 停止符本身不会包含在返回结果中 |
常见用途 | 结构化输出截断、固定条数控制、格式边界限定 |
五、核心参数三:temperature(温度)
5.1 参数作用
temperature控制模型输出的随机性与创造性,取值范围 0~2,默认值为 1。
数值越低:输出越保守、越确定,优先选概率最高的表述,重复度高
数值越高:输出越随机、越有创造力,冷门表述的出现概率提升,内容多样性强
5.2 底层原理
模型每次生成下一个 token 时,会给出所有候选词的概率分布。temperature 本质是对这个概率分布做缩放:
接近 0:概率分布被"压尖",高概率词权重进一步放大,输出高度稳定
接近 2:概率分布被"拉平",低概率词也有机会被选中,输出天马行空
5.3 取值与场景对应表
temperature 取值 | 输出特性 | 适用场景 |
0 ~ 0.3 | 高度确定、保守稳定、重复度高 | 数学计算、代码生成、数据提取、客观问答 |
0.7 ~ 1.0 | 自然流畅、均衡合理、有轻微变化 | 日常对话、通用文案、内容总结 |
1.2 ~ 2.0 | 随机性强、脑洞大、多样性高 | 创意写作、诗歌、头脑风暴、发散构思 |
通用原则:分析类任务用低温,创意类任务用常温 / 高温。
5.4 参数汇总表
参数项 | 详细说明 |
参数名称 |
|
核心作用 | 控制输出内容的随机性与创造性 |
取值范围 | 0 ~ 2,默认值为 1 |
极端表现 | 0 最稳定,2 最发散 |
选型建议 | 求准用低温,求新用高温 |
六、核心参数四:system(系统提示)
6.1 参数作用
system角色的提示词用于给模型设定全局身份、基调和规则,相当于在对话开始前给模型"立人设",它会影响整段对话中模型的所有回复。
6.2 使用要点
适合放:角色身份、语气要求、全局规则、背景设定
不适合放:具体任务指令、外部文档内容、示例样本(这类内容放 user 消息效果更好)
只需设置一次:不需要在每一轮用户消息中重复
6.3 参数汇总表
参数项 | 详细说明 |
角色名称 |
|
核心作用 | 设定模型全局角色、语气与规则 |
作用范围 | 整段对话生效,影响所有轮次回复 |
推荐存放内容 | 角色设定、风格要求、全局约束 |
不推荐存放 | 具体任务指令、输入数据、示例样本 |
七、专题:两种 Prompt 消息写法深度对比
在实际开发中,很多新手会纠结:角色设定和任务指令,是分开写在 system 和 user 里,还是全部堆在 user 消息里?下面结合你的代码做完整对比。
7.1 两种写法代码示例
写法 A:拆分式(system + user 分工)
messages=[ {"role": "system", "content": f"你是{topic}领域的专家,请围绕该主题生成有深度的思考题,以编号列表形式输出。"}, {"role": "user", "content": f"生成 {num_questions} 个关于{topic}的问题,用编号列表呈现。"} ]写法 B:合并式(全部写在 user 里)
messages=[ {"role": "user", "content": f"你是{topic}领域的专家,请围绕该主题生成有深度的思考题,以编号列表形式输出。生成 {num_questions} 个关于{topic}的问题,用编号列表呈现。"} ]7.2 多维度对比表
对比维度 | 写法 A:system+user 拆分 | 写法 B:全部放 user |
指令遵循度 | 更高,角色设定全局生效,模型更稳定地遵循人设 | 一般,角色指令容易被后续任务内容稀释 |
输出稳定性 | 强,多次调用风格、格式一致性更好 | 弱,容易出现格式跑偏、人设弱化 |
代码可读性 | 好,角色与任务职责分明,便于维护修改 | 差,所有指令混在一起,长 prompt 时难以调试 |
运行兼容性 | 完全兼容,是官方推荐的标准写法 | 也能运行,属于非规范写法 |
多轮对话适配 | 优,system 只需要写一次,后续只传 user 消息 | 差,每一轮都要重复角色设定,浪费 token |
适合场景 | 生产项目、多轮对话、要求稳定输出 | 快速测试、单轮简单调用、临时调试 |
7.3 效果差异说明
从你实际运行的结果也能看出:两种写法都能成功生成问题,但拆分写法下模型的输出格式更规整、角色感更强,思考题的深度与结构一致性更好;合并写法虽然也能出结果,但格式波动更大,偶尔会出现多余的开场白、编号不规范等问题。
7.4 最终结论
快速调试、临时写小脚本:两种写法都能用,合并写法写起来更快
正式项目、追求稳定可控:强烈推荐 system + user 的拆分写法,这是行业通用的最佳实践,可维护性与效果都更优
八、实战练习与参考实现
练习要求
编写generate_questions函数:
接收
topic(主题)和num_questions(问题数量)两个参数生成指定数量的深度思考题,编号列表形式输出
要求使用
max_tokens限制长度、system设定角色、stop控制条数边界
参考代码(标准规范写法)
def generate_questions(topic: str, num_questions: int = 3): response = client.chat.completions.create( model="deepseek-v4-flash", max_tokens=1000, messages=[ {"role": "system", "content": f"你是{topic}领域的专家,请围绕该主题生成有深度的思考题,以编号列表形式输出。"}, {"role": "user", "content": f"生成 {num_questions} 个关于{topic}的问题,用编号列表呈现。"} ], stop=[f"{num_questions + 1}."] ) print(response.choices[0].message.content) 调用示例 generate_questions(topic="自由意志", num_questions=3)完整可运行代码(含初始化与两种写法对比)
from dotenv import load_dotenv from openai import OpenAI import os 加载环境变量 load_dotenv() my_api = os.getenv("DEEPSEEK_API_KEY") 初始化 DeepSeek 客户端 client = OpenAI( api_key=my_api, base_url="https://api.deepseek.com" ) def generate_questions(topic: str, num_questions: int): # 写法 A:拆分式(system + user 分工)—— 推荐 # questions = client.chat.completions.create( # model="deepseek-v4-flash", # max_tokens=1000, # messages=[ # {"role": "system", "content": f"你是{topic}领域的专家,请围绕该主题生成有深度的思考题,以编号列表形式输出。"}, # {"role": "user", "content": f"生成 {num_questions} 个关于{topic}的问题,用编号列表呈现。"} # ] # ) # 写法 B:合并式(全部写在 user 里)—— 当前使用 questions = client.chat.completions.create( model="deepseek-v4-flash", max_tokens=1000, messages=[ {"role": "user", "content": f"你是{topic}领域的专家,请围绕该主题生成有深度的思考题,以编号列表形式输出。生成 {num_questions} 个关于{topic}的问题,用编号列表呈现。"} ] ) print(questions.choices[0].message.content) generate_questions('蔡徐坤', 4)九、写在最后
四大核心参数是驾驭大模型 API 的基础,理解它们的原理与适用场景,就能精准控制输出的长度、风格、格式与角色。再配合规范的消息结构写法,就能写出既稳定又易维护的调用代码。 新手学习建议先从默认参数跑通基础调用,再逐个调整参数观察效果变化,动手调试是理解参数作用最快的方式。
