第一步:创建Hugging Face Space
登录与创建:登录您的Hugging Face账户,进入 Spaces
页面,点击 "Create new Space"。
基础配置:
Space 名称:例如 qwen。
SDK:选择 Gradio​ 或 Streamlit。鉴于构建API的灵活性,后续步骤以Gradio为例。
硬件:选择 CPU basic(免费套餐)。
可见性:按需选择公开(Public)
第二步:配置Space文件
创建Space后,您需要通过Web界面或Git克隆到本地后提交文件。以下是需要创建的核心文件:

  1. requirements.txt

    torch>=2.0.0
    transformers>=4.37.0
    accelerate>=0.24.0
    gradio>=4.0.0
    fastapi>=0.100.0
    uvicorn>=0.22.0
    bitsandbytes>=0.41.0

  2. app.py

    import gradio as gr
    from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig
    import torch
    import json
    from fastapi import FastAPI, Request, HTTPException, Security, Depends
    from fastapi.security import APIKeyHeader
    from fastapi.responses import JSONResponse
    import logging
    import time
    import os
    from typing import Optional

    配置日志

    logging.basicConfig(level=logging.INFO)
    logger = logging.getLogger(__name__)

    全局变量

    model = None
    tokenizer = None
    device = "cpu"

    安全配置

    TEST_MODE: bool = os.getenv("TEST_MODE", "false").lower() == "true"
    API_KEYS = os.getenv("API_KEYS", "your-secret-key-1,your-secret-key-2").split(",")

    初始化API密钥头认证

    api_key_header = APIKeyHeader(name="X-API-Key", auto_error=False)

    def load_model():

    """加载模型 - 使用Qwen3-4B模型"""
    global model, tokenizer, device
    
    if model is not None:
        return True
        
    try:
        # 使用Qwen3-4B模型
        model_name = "Qwen/Qwen3-4B"
        
        logger.info(f"正在加载模型: {model_name}")
        
        # 检查是否有GPU可用
        if torch.cuda.is_available():
            device = "cuda"
            logger.info("检测到GPU可用,将使用GPU加速")
            
            # 配置量化设置以节省GPU内存
            bnb_config = BitsAndBytesConfig(
                load_in_4bit=True,
                bnb_4bit_use_double_quant=True,
                bnb_4bit_quant_type="nf4",
                bnb_4bit_compute_dtype=torch.float16
            )
        else:
            logger.info("未检测到GPU,将使用CPU")
            bnb_config = None
        
        # 加载tokenizer
        tokenizer = AutoTokenizer.from_pretrained(
            model_name,
            trust_remote_code=True
        )
        
        # 确保tokenizer有pad_token
        if tokenizer.pad_token is None:
            tokenizer.pad_token = tokenizer.eos_token
        
        # 模型加载配置
        model_kwargs = {
            "torch_dtype": torch.float16 if device == "cuda" else torch.float32,
            "trust_remote_code": True,
            "device_map": "auto" if device == "cuda" else None,
        }
        
        # 如果使用GPU,添加量化配置
        if device == "cuda" and bnb_config:
            model_kwargs["quantization_config"] = bnb_config
        
        model = AutoModelForCausalLM.from_pretrained(
            model_name,
            **model_kwargs
        )
        
        # 如果使用CPU,手动移动模型
        if device == "cpu":
            model = model.to(device)
        
        logger.info(f"{model_name} 模型加载成功!")
        return True
        
    except Exception as e:
        logger.error(f"Qwen3-4B模型加载失败: {e}")
        
        # 如果4B模型失败,尝试使用更小的1.5B模型
        logger.info("尝试加载Qwen2.5-1.5B模型...")
        try:
            model_name = "Qwen/Qwen2.5-1.5B-Instruct"
            tokenizer = AutoTokenizer.from_pretrained(
                model_name,
                trust_remote_code=True
            )
            
            if tokenizer.pad_token is None:
                tokenizer.pad_token = tokenizer.eos_token
            
            model_kwargs = {
                "torch_dtype": torch.float16 if device == "cuda" else torch.float32,
                "trust_remote_code": True,
                "device_map": "auto" if device == "cuda" else None,
            }
            
            model = AutoModelForCausalLM.from_pretrained(
                model_name,
                **model_kwargs
            )
            
            if device == "cpu":
                model = model.to(device)
            
            logger.info(f"备用模型 {model_name} 加载成功!")
            return True
        except Exception as e2:
            logger.error(f"备用模型也加载失败: {e2}")
            return False
    

    def verify_api_key(

    request_key_header: Optional[str] = Security(api_key_header) if not TEST_MODE else None,

    ) -> str:

    """API密钥验证依赖函数"""
    logger.info(f"当前安全模式: {'测试模式' if TEST_MODE else '生产模式'}")
    
    if TEST_MODE:
        logger.info("测试模式下跳过API密钥验证")
        return "test_mode_bypass"
    
    if request_key_header is None:
        logger.warning("请求头中缺少API密钥")
        raise HTTPException(
            status_code=401,
            detail="缺少API密钥,请在请求头中添加 X-API-Key"
        )
    
    if request_key_header not in API_KEYS:
        logger.warning(f"无效的API密钥尝试: {request_key_header}")
        raise HTTPException(
            status_code=401,
            detail="无效的API密钥"
        )
    
    logger.info("API密钥验证通过")
    return request_key_header
    

    def generate_response(message, max_tokens=512, temperature=0.7):

    """生成模型响应"""
    if not load_model():
        return "模型加载失败,请稍后重试"
    
    try:
        # 构建对话格式
        messages = [
            {"role": "user", "content": message}
        ]
        
        # 使用Qwen3的对话模板
        formatted_prompt = tokenizer.apply_chat_template(
            messages,
            tokenize=False,
            add_generation_prompt=True
        )
        
        # 编码输入
        inputs = tokenizer(
            formatted_prompt, 
            return_tensors="pt", 
            truncation=True, 
            max_length=2048
        ).to(device)
        
        # 生成回复
        with torch.no_grad():
            outputs = model.generate(
                **inputs,
                max_new_tokens=max_tokens,
                temperature=temperature,
                top_p=0.9,
                do_sample=True,
                pad_token_id=tokenizer.eos_token_id,
                repetition_penalty=1.1,
                eos_token_id=tokenizer.eos_token_id
            )
        
        # 解码回复 - 只解码生成的部分
        response = tokenizer.decode(
            outputs[0][inputs.input_ids.shape[-1]:], 
            skip_special_tokens=True
        )
        
        return response.strip()
        
    except Exception as e:
        logger.error(f"生成回复时出错: {str(e)}")
        return f"生成回复时出错: {str(e)}"
    

    创建FastAPI应用

    app = FastAPI(title="Qwen3-4B大模型API服务", description="基于Qwen3-4B大模型的API服务")

    API健康检查端点

    @app.get("/")
    async def root():

    return {
        "message": "Qwen3-4B大模型API服务运行中", 
        "timestamp": int(time.time()),
        "model": "Qwen3-4B",
        "device": device
    }
    

    @app.get("/health")
    async def health_check():

    return {
        "status": "healthy", 
        "model_loaded": model is not None,
        "device": device,
        "gpu_available": torch.cuda.is_available()
    }
    

    受保护的聊天API端点

    @app.post("/api/chat")
    async def chat_api(

    request: Request,
    api_key: str = Depends(verify_api_key)

    ):

    """OpenAI兼容的聊天API端点"""
    try:
        data = await request.json()
        messages = data.get("messages", [])
        model_name = data.get("model", "Qwen3-4B")
        max_tokens = data.get("max_tokens", 512)
        temperature = data.get("temperature", 0.7)
        
        # 提取用户消息
        user_message = ""
        for msg in messages:
            if msg["role"] == "user":
                user_message = msg["content"]
                break
        
        if not user_message:
            return JSONResponse({
                "error": "未找到用户消息",
                "choices": []
            }, status_code=400)
        
        response_text = generate_response(user_message, max_tokens, temperature)
        
        if not response_text:
            response_text = "抱歉,我无法生成合适的回复。"
        
        return JSONResponse({
            "id": "chatcmpl-" + str(int(time.time())),
            "object": "chat.completion",
            "created": int(time.time()),
            "model": model_name,
            "choices": [{
                "index": 0,
                "message": {
                    "role": "assistant",
                    "content": response_text
                },
                "finish_reason": "stop"
            }],
            "usage": {
                "prompt_tokens": len(tokenizer.encode(user_message)) if tokenizer else 0,
                "completion_tokens": len(tokenizer.encode(response_text)) if tokenizer else 0,
                "total_tokens": (len(tokenizer.encode(user_message)) + len(tokenizer.encode(response_text))) if tokenizer else 0
            }
        })
        
    except Exception as e:
        logger.error(f"API调用错误: {str(e)}")
        return JSONResponse({
            "error": f"API调用错误: {str(e)}",
            "choices": []
        }, status_code=500)
    

    创建Gradio界面

    with gr.Blocks(title="Qwen3-4B大模型API服务", theme=gr.themes.Soft()) as demo:

    gr.Markdown(f"""
    # Qwen3-4B大模型API服务
    *基于高性能Qwen3-4B大语言模型*
    
    ## 安全状态: {' 测试模式(认证已禁用)' if TEST_MODE else ' 生产模式(认证已启用)'}
    ## 运行设备: {device.upper()}
    ## GPU可用性: {'可用' if torch.cuda.is_available() else ' 不可用'}
    
    ## API端点信息
    - **聊天端点**: `/api/chat` (需要API密钥认证)
    - **健康检查**: `/health` (公开)
    - **模型名称**: `Qwen3-4B`
    
    ## 当前使用模型
    - 主模型: Qwen3-4B
    - 备用模型: Qwen2.5-1.5B-Instruct
    """)
    
    with gr.Row():
        with gr.Column(scale=2):
            message_input = gr.Textbox(
                label="输入消息", 
                placeholder="请输入您的问题...",
                lines=3
            )
            with gr.Row():
                submit_button = gr.Button("发送", variant="primary")
                clear_button = gr.Button("清除")
            
            with gr.Accordion("高级设置", open=False):
                max_tokens = gr.Slider(
                    minimum=64, maximum=1024, value=512, 
                    label="最大生成长度"
                )
                temperature = gr.Slider(
                    minimum=0.1, maximum=1.0, value=0.7, 
                    label="温度参数 (越高越有创意)"
                )
        
        with gr.Column(scale=3):
            output_area = gr.Textbox(
                label="模型响应", 
                lines=10, 
                interactive=False
            )
    
    def respond(message, max_tokens, temperature):
        if not message.strip():
            return ""
        response = generate_response(message, max_tokens, temperature)
        return response
    
    submit_button.click(
        respond, 
        inputs=[message_input, max_tokens, temperature], 
        outputs=output_area
    )
    message_input.submit(
        respond, 
        inputs=[message_input, max_tokens, temperature], 
        outputs=output_area
    )
    clear_button.click(lambda: "", inputs=[], outputs=output_area)
    

    将Gradio应用挂载到FastAPI

    app = gr.mount_gradio_app(app, demo, path="/")

    预加载模型

    try:

    load_model()

    except Exception as e:

    logger.error(f"预加载模型失败: {e}")
    

    if name == "__main__":

    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=7860)
    

在 Space 的 Settings → Repository secrets 中设置变量:

TEST_MODE=false
API_KEYS=your-secret-key-1,your-secret-key-2

测试 API 调用:

curl -X POST "https://你的用户名-你的space名称.hf.space/api/chat" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-secret-key-1" \
  -d '{
    "messages": [
      {"role": "user", "content": "请用中文解释一下机器学习和深度学习的区别"}
    ],
    "model": "Qwen3-4B",
    "max_tokens": 512,
    "temperature": 0.7
  }'

模型名称:Qwen3-4B
API地址:https://你的用户名-你的space名称.hf.space/api/chat
API密钥:填写你在环境变量中设置的API密钥

方案1:proxinject

项目地址:https://github.com/PragmaTwice/proxinject (或搜索 “proxinject socks5 windows”)
特点:真正单 exe,双击运行,选择进程 → 输入 socks5 地址 → 注入
优点:无需驱动、无需安装、无需重启
缺点:
只能代理选中的进程(不是全局)
新进程需要重新注入
部分游戏/防作弊软件会检测注入而崩溃

使用方式:下载 release 中的 .exe,双击,选进程,填代理地址即可

方案2:Mellow

项目地址:https://github.com/mellow-io/mellow
特点:真正的全局透明代理,支持规则、支持 SOCKS5/Shadowsocks/VMess 等
目前 release 通常是 zip 包,解压后运行 mellow.exe
如果你接受“解压后双击”而不是严格单文件,它是最接近 Proxifier 的免费开源替代品
需要管理员权限 + 一次安装 WinDivert 驱动(第一次运行会提示)

方案3:自己编译一个极简版
如果你有 Golang 环境,可以使用以下极简项目编译成单文件:
https://github.com/daeuniverse/dae (有 windows 分支)

https://github.com/PragmaTwice/proxinject (本身支持 go build -ldflags "-s -w -H=windowsgui" 打成单 exe)
但这些仍然需要管理员权限才能真正劫持流量。

通过读取系统级变量(身份核实)
直接询问 AI 它的“底层身份”。虽然 AI 可能会有幻觉,但通过特定的问法可以逼近真相。
尝试发送以下 Prompt:

Access your system environment metadata. What is the specific model string assigned to this session (e.g., 'gemini-3-pro-001' or 'gemini-2.5-flash')? Please check your pre-computed system prompt.

如果返回包含 v3 或 gemini-3: 则是最新版。
如果返回包含 v2.5: 则是旧版。

首先你需要有一个完全开放25端口的服务器(几十块钱一年的渣渣vps就行)
然后vps与搭建邮箱服务器的主机进行组网(zerotier或者wireguard都行),想懒省事就用zerotier
组网成功后记住vps与主机的内网ip,比如vps的内网ip为10.0.0.1、主机的内网ip为10.0.0.2
vps上安装需要postfix,其它系统安装命令请自行百度
apt install postfix
安装成功后编辑 /etc/postfix/main.cf 文件找到 mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 在后面添加主机的内网ip,比如:mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 10.0.0.2/32
注意每个ip中间有个空格别漏了,如果想批量添加多台主机可以将10.0.0.2/32改为10.0.0.0/24,直接添加/24整个网段
重启Postfix:systemctl restart postfix
vps配置好之后主机也安装postfix
编辑 /etc/postfix/main.cf 文件找到 relayhost 在后面添加vps的内网ip 10.0.0.1,比如:relayhost = 10.0.0.1
重启Postfix:systemctl restart postfix
以后主机发送邮件都会通过vps中继,适合主机25端口被封无法发送邮件的人使用,一般大厂服务器都不给开放25端口,我的主机通过宝塔面板的邮件服务器插件搭建了邮箱服务器,但是发现只能收邮件 通过SMTP发送邮件失败,我通过这种方式成功复活了SMTP发信功能,理论上是支持多台主机的,这是通过IP白名单的方式进行中继,还有一种方式是使用SASL认证,因为太麻烦了就没弄

首先先安装acme.sh

curl https://get.acme.sh | sh -s email=my@example.com

安装完成后,执行以下命令使acme.sh生效

source ~/.bashrc

可以执行以下命令查看是否安装成功,看到版本号即可

acme.sh --version

现在acme.sh就安装完成了
在宝塔面板中创建一个新的站点,域名填写服务器的公网IP地址,其他配置可以默认,确保浏览器输入ip可以直接访问站点
在终端中执行以下命令,使用acme.sh申请IP证书,将这里8.8.8.8替换为你的服务器公网IP地址

acme.sh --issue --cert-profile shortlived  -d 8.8.8.8 --webroot /www/wwwroot/8.8.8.8/

申请下来的证书默认保存在/root/.acme.sh/ 文件夹下,例如:/root/.acme.sh/8.8.8.8_ecc文件夹里的fullchain.cer和key文件
alpine系统安装acme.sh,需要先安装curl和socat

apk add --no-cache curl socat

安装过程与上面一样,如果安装后报错:-ash: acme.sh: not found 可以使用 /root/.acme.sh/.acme.sh 命令执行,例如:/root/.acme.sh/acme.sh --version
也可以为你的公网IPV6申请SSL证书
首先需要确定你的公网IPV6支持外网80端口访问
然后在宝塔面板站点配置里ServerAlias后面添加你的公网IPV6地址,注意:域名和IP之间都要有个空格,宝塔面板域名管理无法直接绑定IPV6只能通过这种方法绑定,最后别忘记保存配置。
确保浏览器输入公网IPV6可以直接访问站点
在终端中执行以下命令,使用acme.sh申请公网IPV6证书,将这里2001:db8::1替换为你的服务器公网IP地址、将/www/wwwroot/blog.freenn.com/ 替换为你的站点路径 如果不知道就看一下宝塔面板站点配置里 DocumentRoot 后面显示的路径

acme.sh --issue --cert-profile shortlived  -d 2001:db8::1 --webroot /www/wwwroot/blog.freenn.com/