TRIO快速上手(中国版Tinker)

1. TRIO介绍

TRIO官网地址:pytrio.cn
TRIO文档地址:docs.pytrio.cn
Tinker官网地址:thinkingmachines.ai/tinker

TRIO 是一个面向大模型后训练的 AI Infra 产品。你可以在本地用 Python 写训练循环,把数据处理、loss 设计、reward 计算、评估逻辑都掌握在自己手里;真正复杂的分布式训练、GPU 调度、资源管理和执行过程,则交给 TRIO 云端完成。

在这里插入图片描述

如果你了解 Thinking Machines Lab 的 Tinker,可以把 TRIO 理解为一种更适合国内开发者快速使用的同类训练 API:它不是传统意义上的“一键微调平台”,也不是单纯租一台 GPU 让你自己配环境,而是在保留训练控制权的同时,把底层训练基础设施抽象成几个清晰的 API。

在这里插入图片描述

简单来说:

  • 你写:数据、prompt、loss、reward、训练循环、评估逻辑
  • TRIO 负责:模型加载、LoRA 后训练、分布式执行、采样、权重保存、断点续训
  • 结果是:不用搭训练集群,也能写出可控的 SFT/RL 后训练实验

TRIO 的核心特性包括:

  1. 本地 CPU 开发,大模型训练在云端执行
    你只需要在自己的机器上运行 Python 脚本,TRIO 会把计算请求调度到云端 GPU。

  2. 支持 LoRA 后训练
    TRIO 当前采用 LoRA 方式更新模型,相比全量微调更轻量,也更适合快速迭代多个实验。

  3. 支持 SFT 和 RL
    既可以做监督微调,也可以做强化学习式的后训练,例如基于采样结果计算 reward,再通过 forward_backwardoptim_step 更新模型。

  4. API 足够底层,训练逻辑足够自由
    TRIO 的核心不是一个黑盒 train(),而是几个训练原语:sampleforward_backwardoptim_stepsave_statesave_weights_for_sampler

  5. 支持异步调用
    API 返回 Future,你可以把采样、前反向、优化器更新组织成更高吞吐的 pipeline。

  6. 支持权重保存、续训与下载
    训练中可以保存 sampler 权重,也可以保存带优化器状态的 train 权重,之后继续训练或下载 LoRA adapter 到本地部署。

  7. 兼容 OpenAI API
    训练后的模型可以通过 OpenAI 兼容接口接入应用,方便替换现有推理调用链。

TRIO 和常见方案的区别

相比“黑盒微调平台”,TRIO 给你的控制权更多。你可以自己组织 batch、自己定义 loss 或 reward,也可以在训练中穿插采样和评估。

相比“自建 GPU 集群”,TRIO 省去了环境配置、分布式训练、显存规划、任务调度等大量工程工作。

相比海外的 Tinker,TRIO 的文档、控制台和使用路径对国内开发者更友好,也更适合在国内网络环境下做快速实验。

2. 快速上手

参考链接:TRIO快速开始

2.1 安装 pytrio

在 Python 环境中安装 TRIO 的 SDK:

pip install pytrio

如果安装速度较慢,可以使用国内源:

pip install pytrio -i https://mirrors.cernet.edu.cn/pypi/web/simple

后续示例会用到 tokenizer、数组计算和下载能力,建议一并安装:

pip install transformers modelscope numpy requests

2.2 登录账号

如果你还没有 TRIO 账号,可以先访问 pytrio.cn 注册。

注册完成后,在命令行输入:

trio login

命令行会提示你前往控制台复制 API Key:

trio: You can find your API key at: https://pytrio.cn
trio: Paste an API key from your profile and hit enter, or press 'Ctrl+C' to quit:

复制 API Key 后粘贴到命令行,按回车即可完成登录。粘贴时终端通常不会显示 API Key,这是正常现象。

登录成功后,TRIO 会把凭证保存到本地,之后运行脚本时无需重复登录。

2.3 查看支持的模型列表

先运行一个最小脚本,确认你已经能够连接到 TRIO:

import pytrio as trio

client = trio.ServiceClient()
supported_models = client.get_supported_models()

print("Supported models:")
for index, model_name in enumerate(supported_models, start=1):
    print(f"{index}. {model_name}")

如果能够看到模型列表,说明本地 SDK、账号登录和云端连接都已经正常。

官方文档中的示例模型包括:

Qwen/Qwen3.6-27B
Qwen/Qwen3.5-4B

实际可用模型以 TRIO 控制台和官方模型列表为准。下面为了便于快速体验,统一使用 Qwen/Qwen3.5-4B

3. 完成一次推理

先从最简单的推理开始。流程是:

  1. 创建 ServiceClient
  2. 创建 SamplingClient
  3. 获取 tokenizer
  4. 把 prompt 转成 token ids
  5. 调用 sample
  6. 读取生成结果

新建 sample_trio.py

import pytrio as trio


service_client = trio.ServiceClient()

sampling_client = service_client.create_sampling_client(
    base_model="Qwen/Qwen3.5-4B",
)

print("Loading tokenizer...")
tokenizer = sampling_client.get_tokenizer()

messages = [
    {"role": "user", "content": "请用一句话介绍 TRIO。"},
]
prompt_text = tokenizer.apply_chat_template(
    messages,
    tokenize=False,
    add_generation_prompt=True,
)
input_ids = tokenizer.encode(prompt_text)

params = trio.SamplingParams(
    max_tokens=120,
    temperature=0.7,
    seed=42,
)

response = sampling_client.sample(
    prompt=trio.ModelInput.from_ints(input_ids),
    num_samples=1,
    sampling_params=params,
).result()

print(response.sequences[0].text)

运行:

python sample_trio.py

如果一切正常,你会在终端看到模型生成的回答。

这段代码里最重要的几个对象是:

  • ServiceClient:连接 TRIO 云端计算服务
  • create_sampling_client:创建推理客户端
  • SamplingParams:控制生成参数,例如最大 token 数、温度、随机种子
  • ModelInput.from_ints:把 token ids 封装成 TRIO 输入格式
  • sample:执行一次采样推理

4. 训练一个“认识 TRIO”的 SFT 模型

接下来完成一次监督微调。这个例子故意做得很小:让模型学会回答“TRIO 是什么”。

为什么要这样设计?因为英文里的 trio 本来有“三重奏、三人组”的意思,基础模型很可能会往普通词义上回答。我们用几条样本做 SFT,让它把 TRIO 识别为一个 AI Infra 产品。

新建 train_trio_sft.py

import numpy as np
import pytrio as trio


service_client = trio.ServiceClient()

base_model = "Qwen/Qwen3.5-4B"
training_client = service_client.create_lora_training_client(
    base_model=base_model,
    rank=32,
)

examples = [
    {
        "input": "TRIO是什么?",
        "output": "TRIO 是一个面向大模型后训练的 AI Infra 产品,可以让开发者在本地写训练循环,并把分布式训练交给云端执行。",
    },
    {
        "input": "TRIO适合做什么?",
        "output": "TRIO 适合做大模型监督微调、强化学习后训练、训练中采样评估,以及可控的算法实验。",
    },
    {
        "input": "TRIO和普通微调平台有什么区别?",
        "output": "TRIO 不是黑盒微调平台,它提供 sample、forward_backward、optim_step 等底层 API,让开发者保留训练循环和算法细节的控制权。",
    },
]

print("Loading tokenizer...")
tokenizer = training_client.get_tokenizer()
print("Tokenizer loaded")


def process_example(example: dict) -> trio.Datum:
    prompt = f"问题:{example['input']}\n回答:"

    prompt_tokens = tokenizer.encode(prompt, add_special_tokens=True)
    completion_tokens = tokenizer.encode(
        example["output"] + "\n",
        add_special_tokens=False,
    )

    tokens = prompt_tokens + completion_tokens

    # prompt 部分不算 loss,answer 部分计算 loss。
    weights = [0] * len(prompt_tokens) + [1] * len(completion_tokens)

    input_tokens = tokens[:-1]
    target_tokens = tokens[1:]
    loss_weights = weights[1:]

    return trio.Datum(
        model_input=trio.ModelInput.from_ints(tokens=input_tokens),
        loss_fn_inputs={
            "weights": np.asarray(loss_weights, dtype=np.float32),
            "target_tokens": np.asarray(target_tokens, dtype=np.int32),
        },
    )


processed_examples = [process_example(example) for example in examples]

print("Start training")
for step in range(15):
    fwdbwd_future = training_client.forward_backward(
        processed_examples,
        loss_fn="cross_entropy",
    )
    optim_future = training_client.optim_step(
        trio.AdamParams(learning_rate=1e-4),
    )

    fwdbwd_result = fwdbwd_future.result()
    optim_future.result()

    logprobs = np.concatenate(
        [np.asarray(output["logprobs"]) for output in fwdbwd_result.loss_fn_outputs]
    )
    weights = np.concatenate(
        [example.loss_fn_inputs["weights"] for example in processed_examples]
    )
    loss = -np.dot(logprobs, weights) / weights.sum()

    print(f"Step {step + 1:02d} | loss per token: {loss:.4f}")


print("Saving LoRA weights")
sft_weights = training_client.save_weights_for_sampler(
    name="trio-intro-sft",
).result()

base_sampler = service_client.create_sampling_client(base_model=base_model)
sft_sampler = service_client.create_sampling_client(
    base_model=base_model,
    model_path=sft_weights.path,
)

prompt = trio.ModelInput.from_ints(
    tokenizer.encode("问题:TRIO是什么?\n回答:")
)
params = trio.SamplingParams(max_tokens=100, temperature=0.0)

base_response = base_sampler.sample(
    prompt=prompt,
    sampling_params=params,
    num_samples=1,
).result()

sft_response = sft_sampler.sample(
    prompt=prompt,
    sampling_params=params,
    num_samples=1,
).result()

print("\nBase model:")
print(repr(base_response.sequences[0].text))

print("\nSFT model:")
print(repr(sft_response.sequences[0].text))

运行:

python train_trio_sft.py

你会看到类似这样的训练日志:

Loading tokenizer...
Tokenizer loaded
Start training
Step 01 | loss per token: 5.1234
Step 02 | loss per token: 3.8921
...
Step 15 | loss per token: 0.0123
Saving LoRA weights

最后,脚本会分别用 base model 和 SFT 后的模型回答同一个问题。正常情况下,SFT 后的模型会更稳定地回答“TRIO 是一个面向大模型后训练的 AI Infra 产品”,而不是把 trio 解释成“三重奏”。

这段训练代码的核心 API 是:

  • create_lora_training_client:创建 LoRA 训练客户端
  • Datum:封装一条训练样本,包括模型输入和 loss 所需参数
  • forward_backward:在云端执行前向和反向计算,并累积梯度
  • optim_step:根据累积梯度更新 LoRA 权重
  • save_weights_for_sampler:保存可用于推理的 LoRA 权重
  • create_sampling_client(..., model_path=...):加载训练后的权重进行采样

5. 保存、续训与下载权重

TRIO 支持两类保存方式:

training_client.save_weights_for_sampler(name="sampler")

这个方式保存的是推理用权重,适合训练完成后做采样和部署。

training_client.save_state(name="train")

这个方式会保存权重和优化器状态,适合后续继续训练。

如果想从某个训练状态继续训练,可以在 TRIO 控制台的权重页面复制权重路径,然后:

import pytrio as trio

service_client = trio.ServiceClient()

training_client = service_client.create_training_client_from_state_with_optimizer(
    path="YOUR_MODEL_PATH",
)

如果只想加载权重,不加载优化器状态,可以使用:

training_client = service_client.create_training_client_from_state(
    path="YOUR_MODEL_PATH",
)

下载权重也可以通过 API 完成。先在 WebUI 的“权重”页面复制 checkpoint id,然后运行:

import os
import requests
import pytrio as trio


client = trio.ServiceClient()
rest_client = client.create_rest_client()

checkpoint_id = "YOUR_CHECKPOINT_ID"
result = rest_client.get_checkpoint_archive_url(checkpoint_id).result()

save_filename = f"{checkpoint_id}.zip"
with requests.get(result.url, stream=True) as response:
    response.raise_for_status()
    with open(save_filename, "wb") as file:
        for chunk in response.iter_content(chunk_size=8192):
            file.write(chunk)

print(f"File download complete: {os.path.abspath(save_filename)}")

下载得到的是 LoRA adapter,不是完整 base model。部署时需要搭配对应的 base model,例如 Qwen/Qwen3.5-4B

6. 用 OpenAI API 调用训练后的模型

如果你想把 TRIO 训练后的模型接入已有应用,可以使用 OpenAI 兼容接口。

先安装:

pip install openai

然后调用:

from openai import OpenAI


client = OpenAI(
    base_url="https://pytrio.cn/api/openai/v1",
    api_key="YOUR_TRIO_API_KEY",
)

response = client.chat.completions.create(
    model="YOUR_MODEL_PATH_OR_BASE_MODEL_NAME",
    messages=[
        {"role": "user", "content": "请介绍一下 TRIO。"},
    ],
    max_tokens=120,
    temperature=0.7,
    top_p=0.9,
)

print(response.choices[0].message.content)

这里的 model 可以填基础模型名称,也可以填你在 TRIO 控制台复制到的训练后权重路径。

7. 下一步可以做什么

到这里,你已经完成了 TRIO 的最小闭环:

  1. 安装 SDK
  2. 登录账号
  3. 查看模型列表
  4. 完成一次推理
  5. 完成一次 SFT 训练
  6. 保存并加载训练后的权重
  7. 通过 OpenAI API 接入应用

接下来可以继续尝试:

  • 把示例数据换成自己的业务数据,做一个小规模 SFT
  • 在训练循环里加入验证集,观察 loss 和准确率变化
  • sample 生成答案,再写 reward 函数做 RL 实验
  • 使用异步 API 提升采样和训练 pipeline 的吞吐
  • 下载 LoRA adapter,在本地用 Transformers + PEFT 验证效果
  • 将训练日志接入 SwanLab,记录 loss、reward、评估分数和超参数

TRIO 最有价值的地方不在于“把微调按钮化”,而在于让你用接近研究代码的方式表达训练算法,同时不用被分布式训练工程拖住。对于想快速尝试 SFT、RLHF、GRPO、Agent 后训练或者自定义 reward 的开发者来说,它是一个很适合上手的中国版 Tinker。

参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值