性能比肩闭源 Jev 1.13,开源决策模型 StartLux-Decision 介绍及本地部署 支持文本/图片决策

一、StartLux-Decision 介绍

最近,决策模型 Jev 很快火了起来。与普通对话模型不同,这类模型不是围绕开放式问答生成一段文字,而是针对给定材料和候选项直接做出判断。比如客服工单该分给哪个团队、故障是否需要升级、影响程度属于哪一级,都可以由模型输出明确的选项和对应概率。

Jev 目前是闭源服务,用户仅能通过接口调用模型,无法本地部署。而本文介绍的 StartLux-Decision 作为开源决策模型,不仅在性能表现上与 Jev 相当,还提供了从 0.8B 到 35B-A3B 的多个尺寸,便于根据硬件条件选择本体部署。

在公开的评测中, StartLux-Decision 系列多个尺寸在 JevBench 和 Intern-Decision 上与 Jev 1.13 处于同一水平,9B 及以上版本在这两项指标上均取得更高分数:

官方公布与其他决策模型对比:

说明 :JevBench 公开测试集统计了 Intern-Decision 套件中 231 个公开题目的正确答案数量;Intern 平均准确率是其七个测试套件的平均值;DI 表示两个版本的 Decision Index,其他系统的数值来自公开排行榜。空白单元格表示该数值未公开。StartLux-Decision 的延迟数据基于单颗 H200 测得,三个问题在一次前向传播中完成解答。Intern-Decision 在 RTX 4090 上自行测量的结果。 TypeSafe API 网关报告的同一请求的服务端时间(100 次平均值),与我们的测量方式一致,已排除网络延迟;Intern-Decision 报告的端到端延迟为 109.7 ms。

从对比数据看,StartLux-Decision 系列不同尺寸各有侧重。在JevBench 和Intern-Decision 测试集上,4B及以上版本均优于 Jev 1.13 而且 4B 模型在延迟上比 Jev 1.13 下降约 59.375% 。

同时,StartLux-Decision 项目提供的 Sever 方式兼容 Jev 的 TypeSafe /v1/systemone 接口规范,支持三种问题类型:

类型 用途 主要返回字段
choice 从候选项中选择一个 choice、probabilities、confidence
noul 判断是或否 noul,表示为真的概率
score 在有序等级中评分,criteria 为等级列表 score、legend、probabilities、confidence

更多介绍、开源协议和说明请参考官方Github:

Github地址:https://github.com/StartLuxLabs/StartLux-Decision
ModelScope 地址 (模型权重以 CC BY-NC 4.0 许可发布):https://www.modelscope.cn/models/StartLuxAI/StartLux-Decision-4B

本文以轻量级的 StartLux-Decision-4B 模型为例,介绍本地部署以及调用过程,4B 版本下如果没有 GPU 的话,使用 CPU 也可以做推理运算。

二、StartLux-Decision-4B 本地部署

2.1 下载项目及模型

项目目前已经托管至 Hugging Face 和 ModelScope,这里使用 ModelScope 快速下载:

shell 复制代码
modelscope download --model="StartLuxAI/StartLux-Decision-4B" --local_dir StartLux-Decision-4B

下载完毕后,进入项目,后续所有操作均在项目目录中进行,其中 startlux_decision 包下,就是封装好的API入口:

2.2 环境配置

这里推荐使用 uv 下载相关依赖:

初始化项目,并下载 venv 环境,使用 python 3.14:

bash 复制代码
uv init --python=3.14
uv venv --python=3.14

安装依赖:

bash 复制代码
uv pip install -r requirements.txt --index-url https://pypi.tuna.tsinghua.edu.cn/simple

说明:官方的 requirements.txt 中,如果在 Windows 环境下,是不会安装flash-linear-attention 和 causal-conv1d 两个依赖的,启动时会提示降级至 PyTorch 的实现上,速度相对会慢。

如果本地环境有 CUDA,可以手动移除 requirements.txt 中的 sys_platform == "linux" 条件后再安装。

注意:在 CUDA 上运行,如果这两个加速内核没有生效,推理会抛出 RuntimeError 拒绝启动。

三、SDK 方式运行测试

StartLux-Decision 提供了 API Server 和 SDK直接调用两种方式,这里先进行SDK调用测试,第四节为 API Server 方式的启动测试过程。

SDK 的入口是 startlux_decision 包导出的 StartLuxDecision 类,主要参数如下:

参数 说明
path 模型目录,例如 "."
device "cuda" 或 "cpu",不传时自动选择(有 CUDA 则用 CUDA)
images 是否加载视觉塔,设为 False 可省下约 0.2 到 0.9 GB 显存
max_length 本次运行的提示词长度上限,默认 262144,并不是模型能力上限
graphs 是否录制 CUDA 图,GPU 上默认开启
max_pixels / min_pixels 单张图片缩放后的像素上下限

3.1 文本决策

下面用客服工单分流作为文本决策测试。正文和各问题字段对应仓库示例;判断结果应以实际运行模型为准,不预设分类、分值或概率。

在项目根目录下创建如下内容 py 脚本:

python 复制代码
import json

from startlux_decision import StartLuxDecision

def main() -> None:
    model = StartLuxDecision(
        ".",
        device="cpu",
        images=False,
        graphs=False,
        max_length=4096,
    )

    answers, usage = model.decide(
        {"text": "客户:小毕超;问题: 包裹送达时已经破损,客户希望申请退款。"},
        {
            "team": {
                "type": "choice",
                "instructions": "这个问题应该由哪个团队处理?",
                "criteria": {
                    "billing": "付款、退款和账单问题",
                    "shipping": "配送和包裹破损问题",
                    "technical": "应用、登录和账户问题",
                },
            },
            "needs_refund": {
                "type": "noul",
                "instructions": "是否应该为客户办理退款?",
            },
            "severity": {
                "type": "score",
                "instructions": "对客户造成的影响有多严重?",
                "criteria": ["轻微影响", "明显不便", "客户无法正常使用"],
            },
        },
    )

    print("决策结果:")
    print(json.dumps(answers, ensure_ascii=False, indent=4))
    print("用量信息:")
    print(json.dumps(usage, ensure_ascii=False, indent=4))

if __name__ == "__main__":
    main()

这里的 state 描述了问题现象,questions 是一个字典,键名就是返回结果里的字段名,因此命名时建议直接使用业务语义。三个问题分别覆盖了 choice、noul、score 三种类型,在同一次调用中一起返回。

运行结果如下:

如果需要在离线场景下批量处理大量请求,可以把多个 (state, questions) 组成列表交给 decide_batch,它会把所有问题合并成排序后的批量前向运算,比循环调用 decide 快:

python 复制代码
many = model.decide_batch([(state_a, questions_a), (state_b, questions_b)])

3.2 图片决策

SDK 的 images 参数可接收图片文件路径等格式;状态文本中的 <image> 标记图片所在位置。

具体来说,decide(state, questions, images=[...]) 中的 images 可以是 PIL 图片、文件路径、编码后的字节、base64 字符串或 data URI,按顺序对应 state 里出现的 <image> 标记;如果 state 是结构化对象或没有 <image> 标记,图片会统一放在状态前面。需要注意图片输入依赖视觉塔,而视觉塔只在 PyTorch 后端上加载,MLX 和 GGUF 后端只支持文本。

测试图片:

实现逻辑如下:

python 复制代码
import json
from pathlib import Path

from startlux_decision import StartLuxDecision

IMAGE_PATH = Path(r"test.jpg")


def main() -> None:
    if not IMAGE_PATH.is_file():
        raise FileNotFoundError(f"找不到图片文件:{IMAGE_PATH}")

    model = StartLuxDecision(
        ".",
        images=True,
        graphs=False,
    )

    answers, usage = model.decide(
        "<image> 请检查包裹外观,判断是否存在明显破损。",
        {
            "damaged": {
                "type": "noul",
                "instructions": "包裹是否有明显撕裂、压瘪或内容物暴露?",
            },
            "damage_type": {
                "type": "choice",
                "instructions": "最明显的问题属于哪一类?",
                "criteria": {
                    "none": "未见明显破损",
                    "crushed": "包装被压瘪或变形",
                    "torn": "包装撕裂或开口",
                    "wet": "包装被水浸湿",
                },
            },
        },
        images=[str(IMAGE_PATH)],
    )

    print("决策结果:")
    print(json.dumps(answers, ensure_ascii=False, indent=4))
    print("用量信息:")
    print(json.dumps(usage, ensure_ascii=False, indent=4))


if __name__ == "__main__":
    main()

运行结果:

四、API Server 方式运行测试

4.1 启动服务

API Server 的实现已经封装好,在 startlux_decision/server.py 下,可直接启动:

shell 复制代码
uv run --link-mode=copy python -m startlux_decision.server --name StartLux-Decision-4B --model . --port 8090 

服务端常用的启动参数如下:

参数 说明
--model 必填,本地模型目录
--host / --port 监听地址与端口,默认 127.0.0.1:8090
--name 响应中返回的模型名称,默认取目录名,示例里显式指定为 StartLux-Decision-4B
--device cuda 或 cpu,默认有 CUDA 时用 CUDA
--backend auto / torch / mlx;auto 在 Apple Silicon 上装了 mlx-lm 时自动走 MLX,其余走 torch
--int8 MLX 后端下在 M5 及之后的 Mac 上启用 int8 矩阵乘
--max-length 最长提示词长度,默认 262144(torch 后端)
--max-pixels 单张图片缩放后的像素上限,默认 1048576
--no-images 不加载视觉塔(torch 后端)

说明 :服务是单并发实现的:内部用锁把推理串行化,一次只处理一个请求。因此它适合本地验证和低并发业务,高并发场景需要自行在外层做队列或启动多个实例。

4.2 查看可用模型

使用 /v1/models 接口查看可用模型:

4.3 文本决策

下面依然用客服工单分流作为文本决策测试。请求正文和各问题字段对应仓库示例;判断结果应以实际运行模型为准,不预设分类、分值或概率。

接口:

shell 复制代码
POST http://127.0.0.1:8090/v1/systemone

请求体:

json 复制代码
{
  "state": {"text": "客户:小毕超;问题: 包裹送达时已经破损,客户希望申请退款。"},
  "questions": {
       "team": {
            "type": "choice",
            "instructions": "这个问题应该由哪个团队处理?",
            "criteria": {
                "billing": "付款、退款和账单问题",
                "shipping": "配送和包裹破损问题",
                "technical": "应用、登录和账户问题"
            }
        },
        "needs_refund": {
            "type": "noul",
            "instructions": "是否应该为客户办理退款?"
        },
        "severity": {
            "type": "score",
            "instructions": "对客户造成的影响有多严重?",
            "criteria": ["轻微影响", "明显不便", "客户无法正常使用"]
        }
    }
}

响应结果:

4.4 图片决策

状态文本中的 <image> 标记图片所在位置。使用 images 数组传入 base64 字符串或 data URI。以下示例以本地包裹照片判断是否存在可见破损,这里使用 py 脚本调用 Server,其中将图片以base64的方式传至 images 参数下,测试图片和前面相同:

python 复制代码
import asyncio
import base64
import json
import mimetypes
from pathlib import Path

import httpx

API_URL = "http://127.0.0.1:8090/v1/systemone"
IMAGE_PATH = Path(r"test.jpg")


async def main():
    image_bytes = IMAGE_PATH.read_bytes()
    mime_type = mimetypes.guess_type(IMAGE_PATH.name)[0] or "image/jpeg"
    data_uri = (
        f"data:{mime_type};base64,"
        f"{base64.b64encode(image_bytes).decode('ascii')}"
    )

    payload = {
        "state": "<image> 请检查包裹外观,判断是否存在明显破损。",
        "images": [data_uri],
        "questions": {
            "damaged": {
                "type": "noul",
                "instructions": "包裹是否有明显撕裂、压瘪或内容物暴露?",
            },
            "damage_type": {
                "type": "choice",
                "instructions": "最明显的问题属于哪一类?",
                "criteria": {
                    "none": "未见明显破损",
                    "crushed": "包装被压瘪或变形",
                    "torn": "包装撕裂或开口",
                    "wet": "包装被水浸湿",
                },
            },
        },
    }

    async with httpx.AsyncClient(timeout=120) as client:
        response = await client.post(API_URL, json=payload)
        response.raise_for_status()
        result = response.json()

    print(json.dumps(result, ensure_ascii=False, indent=2))


if __name__ == "__main__":
    asyncio.run(main())

运行结果:

相关推荐
liuchangng18 小时前
类Jev项目Kev从入门到实战(6):Jev / Kev / Laya 对比
人工智能·jev·kev
唯鹿2 天前
Jev初体验记录
人工智能·ai·jev
liuchangng3 天前
Agent的state注入
人工智能·agent·jev·决策模型
️公子3 天前
决策模型开战:Jev / Decisions API / Strands Decider 的 ClosedSet、置信度闸门与混合 Agent
人工智能·大模型·软件工程·agent·决策模型
liuchangng4 天前
类Jev项目Kev从入门到实战(5):如何训练:从数据构造到评测的完整管线
人工智能·jev·kev·决策模型
大鹏的NLP博客7 天前
理解 Jev:让大模型从“生成”走向“判断”
llm·jev
爱喝雪碧的可乐7 天前
CSDN|爆火哑巴AI Jev模型深度实战|技术博客
人工智能·大模型·jev
liuchangng8 天前
类Jev项目Kev从入门到实战(1):Kev 是什么——不开权重也能自训的决策模型
人工智能·python·jev·kev·决策模型
仙人掌_lz8 天前
3090 上的部署两种基于Qwen3.5-4B 判别模型open jev:llama.cpp和 vLLM ,谁更快、谁更准
人工智能·llm·llama·vllm·判别模型·jev