
大模型的里里外外我们都进行了很多细节的讲解,但大模型的部署引用还没有涉及太多,今天我们重点讲一下模型的接口发布,以及利用Postman工具的鉴权调试,Postman 是一款轻量、易用的 API 调试与测试工具,无需编写复杂代码即可快速验证接口的可用性,是本地大模型 API 开发、调试阶段的首选工具。相比于浏览器的自动生成文档页面,Postman 更贴近实际业务中客户端调用 API的真实场景,如后端服务、移动端调用),能直观验证鉴权逻辑、参数传递、返回结果是否符合预期。
今天我们将针对本地大模型 API 的两种鉴权方式:API Key和极简 JWT,详细讲解 Postman 的调用步骤,覆盖从请求配置到完整调用的全流程,让我们能快速上手并实际应用。

前提:本地设备(电脑/服务器)已安装大模型,如 Llama 2、Qwen 等开源模型,并能通过 Python 脚本运行。 核心:模型加载到本地内存,通过代码调用其推理接口,生成结果,比如输入 "写一段文案",模型返回文案内容。 流程:

流程说明:

核心流程:

核心流程:
JWT,JSON Web Token,JSON 格式的网络令牌,可以理解为: 服务器给客户端发的一串加密的“临时身份证”,客户端后续调用接口时,带着这张“身份证”,服务器验证“身份证”的真伪和有效期,就能确认身份。
JWT 令牌由3 部分组成,用英文句号.分隔,比如实际的令牌:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJsb2NhbF9sbG1fdXNlciIsImV4cCI6MTcxNzc0MjQwMH0.8Z7k1X8s7a9L0b8K7j6H5g4F3d2S1a0Z9Y8X7W6V5U4T3S2R1Q0P拆分成 3 部分:
详细介绍:
1. Header(头部):告诉服务器怎么验证
{
"alg": "HS256", // 加密算法(我们用的是对称加密HS256)
"typ": "JWT" // 令牌类型,固定为JWT
}2. Payload(载荷):存储身份信息
token_data = {
"sub": "local_llm_user", # 自定义的用户标识
"exp": datetime.utcnow() + timedelta(minutes=30) # 过期时间
}3. Signature(签名):防止篡改的防伪码
签名 = HMACSHA256(
Base64编码(Header) + "." + Base64编码(Payload),
服务器密钥(JWT_SECRET_KEY)
)4.1 对称加密验证
4.2 无状态特性
4.3 过期机制
以我们的“本地大模型 API + 极简 JWT 鉴权”为例,流程分 4 步,每一步都对应代码里的接口函数:
生成JWT令牌,领临时身份证,对应接口:/get-token,对应函数:create_jwt_token()
执行逻辑:
代码核心片段:
def create_jwt_token():
token_data = {
"sub": "local_llm_user", # 身份标识
"exp": datetime.utcnow() + timedelta(minutes=30) # 过期时间
}
# 生成令牌:自动处理Header+Payload+Signature
token = jwt.encode(token_data, JWT_SECRET_KEY, algorithm=JWT_ALGORITHM)
return token客户端携带令牌调用接口,即出示身份证,对应接口:/generate-text-jwt
执行逻辑:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJsb2NhbF9sbG1fdXNlciIsImV4cCI6MTcxNzc0MjQwMH0.8Z7k1X8s7a9L0b8K7j6H5g4F3d2S1a0Z9Y8X7W6V5U4T3S2R1Q0P检查身份证真伪,对应函数:verify_jwt_token()
执行逻辑:
代码核心片段:
def verify_jwt_token(credentials: HTTPAuthorizationCredentials = Depends(bearer_scheme)):
try:
token = credentials.credentials
# 解码+验证:自动校验签名+过期时间
payload = jwt.decode(token, JWT_SECRET_KEY, algorithms=[JWT_ALGORITHM])
# 兜底检查过期时间(jwt库会自动校验,此处仅做提示)
expire = payload.get("exp")
if expire and datetime.utcfromtimestamp(expire) < datetime.utcnow():
raise HTTPException(status_code=401, detail="令牌已过期")
return payload.get("sub") # 返回用户标识
except JWTError: # 签名错误/篡改都会触发这个异常
raise HTTPException(status_code=401, detail="令牌无效")# Windows
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple python-jose
# macOS/Linux
pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple python-jose进入的文件所在目录,执行python main.py启动项目,出现以下界面表示项目启动成功:


返回结果:
{
"code": 200,
"message": "令牌生成成功(有效期30分钟)",
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJsb2NhbF9sbG1fdXNlciIsImV4cCI6MTc2NzQ0OTkyOX0.LlpxEytdkOwzNcNLi-SZwYwwEMg093sJ-oSNpFMNpfM",
"token_type": "bearer"
}


返回结果:
{ "code": 200, "message": "用户local_llm_user生成成功", "data": { "prompt": "写一段秋天的文案,温馨风格", "result": "秋天,是一首诗意盎然的诗篇,它以金黄的稻谷、红艳的枫叶和丰收的果实,为大地披上了一层金色的纱衣。在这静谧的季节里,每一处都充满了生活的韵味。\n\n秋风轻轻吹过,带来了凉爽的气息,仿佛在诉说着岁月的故事。树叶开始变色,从绿色逐渐过渡到黄色、橙色和红色,宛如一幅色彩斑斓的油画。每一片叶子都在空中翩翩起舞,像是在向人们展示着它们的生命力和活力。这种景象让人感到宁静和平和,仿佛所有的烦恼和压力都被这美丽的景色所带走。\n\n秋天的天空也是另一番风景。蓝天如洗,云朵洁白无瑕,像棉花糖一样柔软而甜美。偶尔有几只小鸟飞过,欢快地鸣叫着,给这个安静的季节增添了生机与活力。阳光透过" } }
当我用一个错误的令牌测试,会直接提示“签名错误,解决:检查令牌是否正确,或重新获取"

每一次失败或成功的接口请求都会有记录存在;

JWT鉴权接口是本地大模型API中安全性更高的调用方式,核心依托“临时令牌”实现身份验证,适配多端访问、临时授权等场景,调用过程中需关注三大关键问题:一是令牌有效期,过期后需重新调用/get-token获取新令牌;二是令牌安全性,不可泄露给第三方,密钥需妥善保管;三是访问基础要求,需使用http://127.0.0.1:8080作为基础URL,确保服务正常启动且端口未被占用。
相较于API Key鉴权,JWT鉴权通过过期机制降低凭证泄露风险,更适合非固定场景的访问需求。掌握其调用逻辑,既能快速验证API功能完整性,也能为后续业务系统对接提供安全的鉴权参考,是本地大模型API落地应用的重要基础。
# model_path = "D:\\modelscope\\hub\\qwen\\Qwen1___5-1___8B-Chat"
# 导入需要的库
from fastapi import FastAPI, Header, HTTPException, Depends
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from pydantic import BaseModel, Field
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
from dotenv import load_dotenv
from jose import jwt, JWTError
from datetime import datetime, timedelta
import os
import uvicorn
# ====================== 第一步:加载配置(API Key+JWT配置) ======================
try:
load_dotenv()
# API Key配置
VALID_API_KEY = os.getenv("VALID_API_KEY", "default_key_123") # 无配置时用默认值
# JWT极简配置(新手不用改,理解即可)
JWT_SECRET_KEY = os.getenv("JWT_SECRET_KEY", "my_jwt_secret_123") # 加密密钥
JWT_ALGORITHM = "HS256" # 加密算法(固定)
JWT_EXPIRE_MINUTES = 30 # 令牌过期时间(30分钟)
print("✅ 配置加载成功")
except Exception as e:
print(f"❌ 配置加载失败:{str(e)}")
exit(1)
# ====================== 第二步:单例加载模型(修复路径+内存优化) ======================
class LocalLLM:
_instance = None
_initialized = False
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self):
if not LocalLLM._initialized:
# 修复1:用超轻量化模型(DistilGPT2),避免内存不足
# 先运行download_small_model.py下载模型到./model文件夹
model_path = "D:\\modelscope\\hub\\qwen\\Qwen1___5-1___8B-Chat" # 原始字符串避免反斜杠问题
try:
print("正在加载本地大模型...")
if not os.path.exists(model_path):
raise FileNotFoundError(
f"模型文件夹不存在:{model_path}\n解决:1. 运行download_small_model.py下载小模型;2. 确认路径正确")
# 修复2:添加low_cpu_mem_usage,减少内存占用
self.tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
self.model = AutoModelForCausalLM.from_pretrained(
model_path,
torch_dtype=torch.float32,
device_map="cpu",
trust_remote_code=True,
low_cpu_mem_usage=True # 减少CPU内存占用
)
self.model.eval()
LocalLLM._initialized = True
print("✅ 模型加载完成!")
except FileNotFoundError as e:
print(f"❌ 模型加载失败:{str(e)}")
exit(1)
except RuntimeError as e:
if "out of memory" in str(e).lower():
print(f"❌ 内存不足,请关闭其他程序(如浏览器/微信),或换更小的模型")
else:
print(f"❌ 模型运行错误:{str(e)}")
exit(1)
except Exception as e:
print(f"❌ 模型加载未知错误:{str(e)}")
exit(1)
def generate_text(self, prompt, max_length):
try:
if not prompt.strip():
raise ValueError("提示词不能为空")
inputs = self.tokenizer(prompt, return_tensors="pt", truncation=True, max_length=512)
if inputs.input_ids.shape[1] > 512:
raise ValueError(f"提示词过长({inputs.input_ids.shape[1]}token),最大支持512token")
with torch.no_grad():
outputs = self.model.generate(**inputs, max_length=max_length, temperature=0.7, pad_token_id=self.tokenizer.eos_token_id)
result = self.tokenizer.decode(outputs[0], skip_special_tokens=True).replace(prompt, "").strip()
if not result:
raise ValueError("模型未生成内容,请换提示词")
return result
except ValueError as e:
raise HTTPException(status_code=400, detail=f"参数错误:{str(e)}")
except Exception as e:
raise HTTPException(status_code=500, detail=f"推理错误:{str(e)}")
# 创建模型实例
try:
llm = LocalLLM()
except Exception as e:
print(f"❌ 模型初始化失败:{str(e)}")
exit(1)
# ====================== 第三步:极简JWT鉴权核心函数 ======================
bearer_scheme = HTTPBearer()
def create_jwt_token():
"""生成JWT令牌(简化版:无用户名密码,直接生成)"""
try:
token_data = {
"sub": "local_llm_user",
"exp": datetime.utcnow() + timedelta(minutes=JWT_EXPIRE_MINUTES)
}
token = jwt.encode(token_data, JWT_SECRET_KEY, algorithm=JWT_ALGORITHM)
return token
except Exception as e:
raise HTTPException(status_code=500, detail=f"生成令牌失败:{str(e)}")
def verify_jwt_token(credentials: HTTPAuthorizationCredentials = Depends(bearer_scheme)):
"""验证JWT令牌(简化版:只检查有效性和过期时间)"""
try:
token = credentials.credentials
payload = jwt.decode(token, JWT_SECRET_KEY, algorithms=[JWT_ALGORITHM])
expire = payload.get("exp")
if expire and datetime.utcfromtimestamp(expire) < datetime.utcnow():
raise HTTPException(status_code=401, detail="❌ JWT令牌已过期\n解决:重新调用/get-token获取新令牌")
return payload.get("sub")
except JWTError as e:
raise HTTPException(status_code=401, detail=f"❌ JWT令牌无效/签名错误\n解决:检查令牌是否正确,或重新获取")
except Exception as e:
raise HTTPException(status_code=401, detail=f"❌ 令牌验证失败:{str(e)}")
# ====================== 第四步:FastAPI接口(API Key+JWT双鉴权) ======================
app = FastAPI(title="本地大模型API(API Key+极简JWT鉴权)")
# 请求体模型(保留)
class LLMRequest(BaseModel):
prompt: str = Field(..., description="提示词", max_length=500)
max_length: int = Field(100, description="生成长度", ge=10, le=1000)
# 接口1:获取JWT令牌
@app.post("/get-token", summary="获取JWT令牌(无需密码,直接领)")
def get_jwt_token():
token = create_jwt_token()
return {
"code": 200,
"message": "令牌生成成功(有效期30分钟)",
"access_token": token,
"token_type": "bearer"
}
# 接口2:API Key鉴权的生成接口
@app.post("/generate-text-apikey", summary="API Key鉴权-文本生成")
def generate_by_apikey(request: LLMRequest, x_api_key: str = Header(None)):
try:
if not x_api_key:
raise HTTPException(status_code=401, detail="❌ 请传入X-API-Key")
if x_api_key.strip() != VALID_API_KEY:
raise HTTPException(status_code=401, detail="❌ API Key错误")
except HTTPException as e:
raise e
try:
result = llm.generate_text(request.prompt, request.max_length)
return {"code": 200, "message": "生成成功", "data": {"prompt": request.prompt, "result": result}}
except HTTPException as e:
raise e
# 接口3:JWT鉴权的生成接口
@app.post("/generate-text-jwt", summary="JWT鉴权-文本生成")
def generate_by_jwt(
request: LLMRequest,
username: str = Depends(verify_jwt_token)
):
try:
result = llm.generate_text(request.prompt, request.max_length)
return {
"code": 200,
"message": f"用户{username}生成成功",
"data": {"prompt": request.prompt, "result": result}
}
except HTTPException as e:
raise e
# ====================== 第五步:启动服务(修复端口+日志) ======================
if __name__ == "__main__":
try:
# 修复3:改端口为8080(避免8000被占用),添加更多日志
uvicorn.run(
"main:app",
host="0.0.0.0",
port=8080, # 改端口,避免占用
reload=False,
log_level="debug",
access_log=True # 开启访问日志,便于排查
)
except OSError as e:
if "address already in use" in str(e).lower():
print(f"❌ 服务启动失败:端口8080被占用\n解决:1. 改端口为8090;2. 结束占用8080的程序")
else:
print(f"❌ 服务启动失败:{str(e)}")
exit(1)
except Exception as e:
print(f"❌ 服务启动失败:{str(e)}\n解决:检查Python依赖是否安装完整")
exit(1)原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。