blog-llama-manager
方便调试做的客户端
用纯 C# WinForms 写一个本地大模型管理器:开发全过程
缘起
本地跑着三个 llama-server 实例——MXFP4(8080 端口)、Qwen Q4(8081)、Gemma-4(8082),每次开机要手动开三个命令行窗口,参数又长又容易敲错。需要一个原生 Windows 图形界面来管理它们。
需求很明确:
- 零外部依赖,不要 WebView2 / Electron / Python
- .NET Framework 内置组件就够了
- 深色主题,中文界面,启动快
- 托盘运行,后台健康检测
第一阶段:单实例 Launcher(Llama Server)
最初只管理一个实例。用 CSharpCodeProvider 从 PowerShell 脚本内联编译 C# 代码,输出一个 32KB 的 EXE。
参数面板的布局折腾
最折腾的是参数面板布局。一开始用 tiled 2 列布局,用户嫌太挤;调大间距又说空间利用率低;换成垂直单列,但用 parent.Width 算坐标——构造时 parent 还没显示,Width=0,所有控件都不可见。
最终方案:不用绝对定位,全部 Dock = DockStyle.Top 堆叠,组框自动撑满宽度。高度按 36 + 控件数 * 38 动态计算。
C# 版本兼容坑
CSharpCodeProvider 默认使用系统自带的 C# 编译器(Windows 7 上是 C# 5,Windows 10 上是 C# 6/7),不支持局部函数。写了 static 局部函数编译不过,全部改成类级 private 方法。
模型切换
从硬编码路径改成下拉选择框(ComboBox),两个预设:MXFP4 和 Uncensored Q4_K_M。切换时自动更新模型路径、mmproj、别名和副标题。
第二阶段:多实例管理(Llama Manager)
管理 3 个实例,每个实例一个标签页。左侧边栏放操作按钮(启动/重启/浏览器/参数),右侧主区域显示日志输出。
架构设计
每个实例用 ServerSlot 类描述:
Title, Label, Port, ModelDir, ModelFile, MmprojFile, Args
Process, LogBox, StatusLabel, IsRunning
启动流程:Process.Start → 订阅 OutputDataReceived / ErrorDataReceived → BeginOutputReadLine → 端口健康检测。
经典 Bug:事件订阅顺序
花了最多时间排查的一个 bug——日志框一直是空的。检查发现事件订阅在 BeginOutputReadLine() 之后:
// ❌ 这样收不到任何输出
proc.BeginOutputReadLine();
proc.OutputDataReceived += OnData;
// ✅ 必须先订阅再开始读取
proc.OutputDataReceived += OnData;
proc.BeginOutputReadLine();
--log-disable 参数也导致服务端不输出任何日志,去掉后恢复正常。
参数调节对话框
每个实例的启动参数很长(20+ 个 flag),用户不想手写。写了个 ParamForm 对话框,用正则解析 Args 字符串,把 --ngl / --ctx-size / --temp 等参数分布到 GPU/CPU、Context/Cache、Sampling、Misc 四个分组,每个参数有对应的 NumericUpDown / ComboBox / CheckBox。修改后保存回 slot 的 Args 字符串,下次启动生效。
配置文件
每个实例参数存为 slot 的字符串字段,用 Json 序列化保存/加载。
第三阶段:UI 打磨——从极暗到磨砂玻璃
深色主题 1.0
纯黑底 #0F0F12 + 白字。简洁但太「硬」。
磨砂玻璃效果
用 SetWindowCompositionAttribute 调起 Windows 10/11 的 Acrylic Blur(亚克力模糊),配合各 Panel 半透明底色(alpha 150~200)让桌面背景透过来。
踩了个坑:RichTextBox 不支持半透明 BackColor,设了直接抛 ArgumentException,进程启动就崩。只能在日志框保留完全不透明底色。
性能问题
Acrylic 模糊拖拽窗口时严重卡顿。换用 ACCENT_ENABLE_BLURBEHIND(经典 Aero 玻璃模糊),效果接近但流畅很多。
标题栏变白问题
DWM 模糊效果有时让窗口标题栏变成白色,与深色主题不搭。用 DwmSetWindowAttribute(handle, 20, 1) 开启深色标题栏解决。
对比度调整
初期按钮用高饱和度的绿/蓝/红,在玻璃背景上太跳脱。统一改为低饱和度暗灰底 + 浅灰文字(RGB(50,50,55) + RGB(200,200,200)),用文字颜色区分功能——结果是用户说连文字颜色也不想要,全部统一成浅灰。
最终交付物
| 文件 | 大小 | 说明 |
|---|---|---|
Llama Manager.exe |
33 KB | 多实例管理器,管理 3 个实例 |
Llama Server.exe |
32 KB | 单实例启动器 |
| 编译脚本 | ~500 行 C# 内嵌 | 用 PowerShell CSharpCodeProvider 编译 |
编译方式:powershell -File Build-LlamaManager.ps1,一次生成完整 EXE,无需 Visual Studio。
技术要点总结
- 内联编译:
CSharpCodeProvider+ PowerShell 脚本,无需 VS 即可发布 WinForms 程序 - C# 版本兼容:避免 C# 7+ 语法(局部函数、模式匹配等),确保系统编译器可用
- WinForms 透明限制:RichTextBox/TextBox 不支持 alpha BackColor,Panel 支持有限
- DWM 窗口效果:
SetWindowCompositionAttribute实现模糊/亚克力,DwmSetWindowAttribute控制标题栏 - Process 异步读取:必须先订阅事件再调用 BeginOutputReadLine
- 布局策略:构造时不可用绝对定位(Width=0),用 Dock 代替
一些感想
33KB 的 EXE 完成三个大模型实例的完整管理——启动、停止、参数调节、日志监控、托盘运行、健康检测。没有 Electron 的几百 MB 运行时,没有 WebView2 的依赖,只有一个 exe 和一个记事本能改的编译脚本。
有时候,最合适的工具就是 Windows 自带的那些东西。
更多推荐


所有评论(0)