<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>TUI | Twinkle</title><link>https://modelscope.github.io/twinkle-web/zh/tags/tui/</link><atom:link href="https://modelscope.github.io/twinkle-web/zh/tags/tui/index.xml" rel="self" type="application/rss+xml"/><description>TUI</description><generator>HugoBlox Kit (https://hugoblox.com)</generator><language>zh-Hans</language><lastBuildDate>Mon, 01 Jun 2026 00:00:00 +0000</lastBuildDate><image><url>https://modelscope.github.io/twinkle-web/media/logo_hu_fedc6a0bfe689b18.png</url><title>TUI</title><link>https://modelscope.github.io/twinkle-web/zh/tags/tui/</link></image><item><title>TUI 与 Auto-Research：用 AI Agent 控制训练</title><link>https://modelscope.github.io/twinkle-web/zh/blog/tui-auto-research/</link><pubDate>Mon, 01 Jun 2026 00:00:00 +0000</pubDate><guid>https://modelscope.github.io/twinkle-web/zh/blog/tui-auto-research/</guid><description>&lt;p&gt;Twinkle 内置了一个终端 UI（TUI），集成 LLM Agent，可以自主启动、监控、暂停和调试 ML 训练任务。本文介绍 TUI 的架构设计、Agent 循环以及让「自动化研究」成为可能的工具系统。&lt;/p&gt;
&lt;h2 id="架构概览"&gt;架构概览&lt;/h2&gt;
&lt;p&gt;TUI 基于
构建，由四个面板组成 2x3 网格布局：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;面板&lt;/th&gt;
&lt;th&gt;位置&lt;/th&gt;
&lt;th&gt;功能&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;StatusBar&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;顶部，全宽&lt;/td&gt;
&lt;td&gt;Run ID、模型、步数、训练状态&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MetricsPanel&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;中左&lt;/td&gt;
&lt;td&gt;实时 loss/reward/grad_norm 图表&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;LogPanel&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;右侧，跨 2 行&lt;/td&gt;
&lt;td&gt;训练进程的流式 stdout 输出&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ChatPanel&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;左下&lt;/td&gt;
&lt;td&gt;与 Agent 的自然语言交互&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;Screen&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;grid-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;grid-rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;auto&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;grid-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="agent-循环"&gt;Agent 循环&lt;/h2&gt;
&lt;p&gt;TUI 的核心是 &lt;code&gt;AgentLoop&lt;/code&gt;——一个异步工具调用 Agent，支持任何 &lt;strong&gt;OpenAI 兼容 API&lt;/strong&gt;（本地 Ollama、云端 API 等）：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AgentLoop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;llm_base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;http://localhost:11434/v1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;llm_model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;qwen3.5&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;llm_api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;not-needed&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;循环遵循标准的 ReAct 模式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;用户通过 ChatPanel 发送消息&lt;/li&gt;
&lt;li&gt;Agent 携带对话历史 + 工具 schema 调用 LLM&lt;/li&gt;
&lt;li&gt;LLM 直接回复或生成工具调用&lt;/li&gt;
&lt;li&gt;执行工具，将结果回传 LLM&lt;/li&gt;
&lt;li&gt;重复直到 LLM 产生最终文本回复（最多 10 轮）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;关键设计决策：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;流式输出&lt;/strong&gt;：Token 实时流式传输到 UI。如果在流中检测到工具调用，&lt;code&gt;on_stream_reset&lt;/code&gt; 会丢弃已部分显示的输出&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;历史修剪&lt;/strong&gt;：对话上限 50 条消息（不含系统提示），始终在 &lt;code&gt;user&lt;/code&gt; 消息边界裁剪，避免破坏工具调用序列&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;异步技能加载&lt;/strong&gt;：技能在后台加载——Agent 立即可用，技能就绪后通过 &lt;code&gt;inject_skills()&lt;/code&gt; 注入&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="工具系统"&gt;工具系统&lt;/h2&gt;
&lt;p&gt;Agent 拥有 15+ 个工具，按类别组织：&lt;/p&gt;
&lt;h3 id="训练生命周期"&gt;训练生命周期&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;工具&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;start_server&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;启动 Ray 集群 + Twinkle Server（GPU 分区、配置生成）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;shutdown_server&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;关停 Server 并释放 GPU 资源&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;start_training&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;编写训练脚本、启动进程、开始监控&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pause_training&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;SIGKILL 客户端进程（Server 保留状态）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;resume_training&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;从保存的状态重新启动客户端脚本&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;stop_training&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;优雅停止并保存 checkpoint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;update_script&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;归档当前脚本，写入新版本&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="发现与搜索"&gt;发现与搜索&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;工具&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;list_training_runs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;列出活跃和历史训练任务&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_training_status&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;获取任务状态 + 最近指标&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;search_models&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;在 ModelScope Hub 搜索模型&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;search_datasets&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;在 ModelScope Hub 搜索数据集&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;list_supported_models&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;查询 Server 支持的模型&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_cluster_info&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;检测 GPU 资源（Ray 或 nvidia-smi）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="可视化"&gt;可视化&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;工具&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;zoom_metrics&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;平移/缩放指标图表&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;select_metrics&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;选择显示哪些指标（最多 4 个）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;select_run&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;切换监控的训练任务&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="server-启动流水线"&gt;Server 启动流水线&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;start_server&lt;/code&gt; 工具编排完整的服务端部署：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;硬件检测&lt;/strong&gt; — &lt;code&gt;nvidia-smi&lt;/code&gt; 获取 GPU 数量&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPU 分配&lt;/strong&gt; — 在训练模型和采样器/教师模型之间分区&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;配置生成&lt;/strong&gt; — 自动生成包含 Ray Serve 应用的 &lt;code&gt;server_config.yaml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ray 集群启动&lt;/strong&gt; — 多节点 GPU 分区，每个角色使用独立 raylet&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Server 启动&lt;/strong&gt; — &lt;code&gt;python -m twinkle.server launch --config ...&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;健康检查&lt;/strong&gt; — 轮询 &lt;code&gt;/api/v1/healthz&lt;/code&gt; + 采样器引擎就绪检测&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;配置生成器支持&lt;strong&gt;多模型拓扑&lt;/strong&gt;：一个训练模型 + N 个采样器/教师模型，按 GPU 数量降序排列（最大 PG 优先部署以避免调度死锁）。&lt;/p&gt;
&lt;h2 id="技能系统"&gt;技能系统&lt;/h2&gt;
&lt;p&gt;TUI 支持可扩展的 &lt;strong&gt;Skills&lt;/strong&gt;——可插拔能力，从三个来源加载：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;内置技能&lt;/strong&gt; — 随 &lt;code&gt;twinkle_client&lt;/code&gt; 包一起发布&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;本地技能&lt;/strong&gt; — 用户自定义，放在 &lt;code&gt;~/.cache/twinkle/tui/skills/local/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;社区技能&lt;/strong&gt; — 从 ModelScope 获取（10 秒超时）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;技能在 Agent 启动后异步加载，因此 TUI 立即可交互。&lt;/p&gt;
&lt;h2 id="trainingruntime训练脚本集成"&gt;TrainingRuntime：训练脚本集成&lt;/h2&gt;
&lt;p&gt;训练脚本通过 &lt;code&gt;TrainingRuntime&lt;/code&gt; 与 TUI 集成：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;twinkle_client.tui.runtime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TrainingRuntime&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;rt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TrainingRuntime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;run_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;grpo-gsm8k&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;rt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Qwen/Qwen3.5-4B&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;rt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register_graceful_shutdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dataloader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;batch&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dataloader&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;loss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;train&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;rt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log_metrics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reward&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;reward&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;rt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Step &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s1"&gt;, loss=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="s1"&gt;.4f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;rt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;finish&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;核心功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;metrics.jsonl&lt;/strong&gt; — 结构化指标，自动时间戳，实时流式传输到 TUI&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;优雅停机&lt;/strong&gt; — SIGTERM 处理器保存 checkpoint（LoRA 权重 + 优化器状态 + dataloader 位置）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自动续训&lt;/strong&gt; — &lt;code&gt;get_resume_info()&lt;/code&gt; 从 &lt;code&gt;meta.json&lt;/code&gt; 读取最后保存的步数&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;脚本归档&lt;/strong&gt; — 每次 &lt;code&gt;update_script&lt;/code&gt; 调用将 &lt;code&gt;train.py&lt;/code&gt; 归档为 &lt;code&gt;train_v{N}.py&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="快速开始"&gt;快速开始&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 使用本地 LLM 启动 TUI&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;twinkle tui --llm-base-url http://localhost:11434/v1 --llm-model qwen3.5
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 或指定运行 ID&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;twinkle tui --run-id my-grpo-run
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;TUI 将 ML 训练变成一场对话——描述你想训练什么，Agent 自动处理服务器部署、脚本编写、监控和排障。&lt;/p&gt;</description></item></channel></rss>