一本码簿

众里寻码千百度,那段却在github处。

一、ComfyUI是什么

ComfyUI是一款免费开源、节点式工作流的AI绘图工具,基于Stable Diffusion生态,同时支持SDXL、视频生成等场景。

它和传统网页版AI绘图最大区别:不是固定流水线,而是把AI生成拆成一个个独立Node(节点),像搭积木、接电路一样自由拖拽连线,自定义绘图全流程。

支持Windows、Linux、macOS三大系统,默认本地离线运行,所有模型都需自行下载存到本地,不上传数据,隐私性强;也有官方云端版本可免本地配置使用。

二、三大系统运行优缺点

Windows

优点:安装最简单,一键整合包解压即用;NVIDIA显卡CUDA兼容性拉满,插件和自定义节点生态最全,新手零门槛。

缺点:同配置下显存占用略高,长期批量生成易显存泄漏;AMD显卡仅支持DirectML,运行速度差。

Linux

优点:显存利用率最高、性能最强,比Windows更快更省显存;长期后台批量生成稳定性极佳,AMD显卡可通过ROCm满血运行,适合服务器部署和专业工作室。

缺点:安装需命令行配置环境,新手上手门槛高,部分小众自定义节点适配缺失。

macOS(Apple Silicon M系列)

优点:统一内存架构,大模型不易爆显存;笔记本便携安静、低功耗散热好,自带Metal加速无需额外装驱动。

缺点:无CUDA支持,运行速度比NVIDIA显卡慢;自定义节点、视频生成、多ControlNet兼容性较差,Intel Mac不建议使用。

三、ComfyUI硬件配置要求

硬件 要求
显卡GPU 核心硬件,4-6GB显存可基础跑SD1.5;8GB为日常舒适底线,可运行SDXL;12GB及以上流畅驾驭多LoRA、多ControlNet、高清修复;16GB+适合FLUX大模型、AI视频生成
内存RAM 最低16GB,推荐32GB及以上,适配多节点、多模型加载
硬盘 必须NVMe固态硬盘,机械硬盘加载模型极慢;预留50GB以上空闲空间
CPU 无高要求,主流中端处理器即可,性能瓶颈只在显卡

四、AI绘图核心名词通俗详解

1. Checkpoint(CKPT大模型)

后缀为.ckpt/.safetensors,体积2-7GB,是AI绘图的全能底子画家。

作用:决定整体画风(写实、二次元、国风等)、画面构图、光影逻辑,更换大模型,整体画风会彻底改变,是运行绘图必须加载的基础模型。

进阶理解:Checkpoint 是把 UNet、CLIP、VAE 三套模型权重完整封装打包在单个文件里的整合模型,内部已包含全套参数,不会从 unet、clip、vae 三个独立文件夹动态加载内容;而独立文件夹存放的是拆分出来的单独模型文件,和 Checkpoint 属于平行格式,互不依赖。新手用 Checkpoint 可一键加载成套匹配好的模型,简单不翻车;进阶玩家则可以单独调用三个独立模型自由混搭,适配 SDXL、Flux 等原生拆分式新模型。

2. VAE

小型调色模型,体积仅几十到几百MB,相当于AI绘图的调色师+美颜滤镜。

作用:AI生成的原始画面是灰蒙蒙的底层潜数据,没有色彩、发雾暗淡;VAE负责校正色彩、提亮通透感、锐化细节、去除噪点,没有合适VAE,生成图片会惨白模糊、观感极差。

3. LoRA

轻量化插件模型,体积20-300MB,不替换基础大模型,只做效果叠加。

作用:可定制固定动漫角色、真人面容、专属画风、服饰穿搭、特定场景,支持多个LoRA混用,还能调节权重强度控制效果深浅。

4. ControlNet

AI构图姿势控制器,强制约束AI绘画不随意发挥。

作用:可精准控制人物骨架动作、画面轮廓线条、场景景深层次、建筑结构布局,给AI打好草稿,牢牢锁定构图和姿态。

5. Embedding

小众特征关键词补丁,体积小巧。

作用:适合AI原生不认识的冷门角色、特殊服饰、小众细节特征,相当于给提示词扩充专属词库,补充LoRA覆盖不到的细微特征。

6. UNET 和 CLIP(了解即可)

CLIP:文本编码器,负责”理解”文字提示词,将其转换为模型能懂的向量,类比于人的大脑。

UNET:图像生成的核心神经网络,负责”执行”绘画,从噪声中重建图像,两者配合完成”理解文字→画出图像”的全过程。

五、ComfyUI基础绘图标准工作流

核心节点流程固定,所有复杂工作流都在此基础上扩展:

  1. 加载Checkpoint大模型
  2. 可选添加LoRA加载节点,叠加风格人物
  3. 输入正向提示词(想要的画面内容)、反向提示词(规避畸形、模糊等瑕疵)
  4. 可选接入ControlNet,控制姿势与构图
  5. KSampler采样器开始迭代运算,生成底层潜空间数据
  6. 通过VAE Decode解码,将灰蒙蒙数据转为正常彩色图片
  7. 预览并保存生成图片

整体口诀:加载大模型→加LoRA→写正反提示词→控构图姿势→采样画图→VAE调色出图

六、总结

ComfyUI凭借节点式自由定制、本地离线运行、跨平台适配,成为专业AI创作者首选工具。新手只需弄懂核心模型概念(Checkpoint、VAE、LoRA、ControlNet、Embedding等),掌握基础工作流逻辑,就能从零开始搭建属于自己的AI绘图流水线,无论是日常出图、风格创作,还是批量生成、视频制作都能轻松胜任。

一、使用背景

  • 系统:macOS + WSL2
  • 核心用途:个人 AI 助手,通过飞书对话
  • 主要模型:MiniMax-M2.7(主力)、Qwen3.5-4B-MLX-4bit(本地)

二、配置文件体系

目录结构

所有配置存放在 ~/.hermes/ 目录下:

1
2
3
4
5
6
7
8
9
10
~/.hermes/
├── config.yaml # 主配置文件(模型、终端、TTS、压缩等)
├── .env # API Key 和密钥(secrets)
├── auth.json # OAuth 凭证(Nous Portal 等)
├── SOUL.md # 主体身份定义(系统提示词 slot #1)
├── memories/ # 持久化记忆(MEMORY.md、USER.md)
├── skills/ # Agent 创建的技能(通过 skill_manage 管理)
├── cron/ # 定时任务
├── sessions/ # 网关会话
└── logs/ # 日志(errors.log、gateway.log — 敏感信息自动脱敏)

三个核心配置文件

文件 作用 重要性
config.yaml 运行时主配置 最高
.env 环境变量(API Key 单一真相来源) 最高
auth.json 凭证池缓存(仅用于 Nous/Copilot/Custom Provider) 一般

配置优先级(从上到下,高优先级覆盖低优先级)

  1. CLI 参数 — 例如 hermes chat --model anthropic/claude-sonnet-4(每次调用时覆盖)
  2. config.yaml — 所有非密钥配置的主文件
  3. .env — 环境变量后备;密钥(API Key、Token、密码)必须放这里
  4. 内置默认值 — 以上均未设置时的安全默认值

经验总结

  • 标准规则:密钥(API Key、Bot Token、密码)放 .env;其他配置(模型、终端后端、压缩设置、工具集)放 config.yaml
  • 标准 api_key 类型 provider(如 minimax-cnomlx不走 credential_pool,直接读 .env
  • API Key 应只保存在 .env,避免冗余存储
  • 配置修改流程:改 config.yamlhermes doctor --fix → 重启网关

hermes config 命令行

1
2
3
4
5
hermes config                  # 查看当前配置
hermes config edit # 在编辑器中打开 config.yaml
hermes config set KEY VAL # 设置指定值(API Key 自动写入 .env,其他写入 config.yaml)
hermes config check # 检查缺失项(升级后使用)
hermes config migrate # 交互式添加缺失配置项

技巧hermes config set 会自动判断写入目标 — API Key 写入 .env,其他写入 config.yaml

环境变量引用

config.yaml 中支持 ${VAR_NAME} 语法引用环境变量:

1
2
3
4
auxiliary:
vision:
api_key: ${GOOGLE_API_KEY}
base_url: ${CUSTOM_VISION_URL}

未定义的环境变量保持原样写入(${UNDEFINED_VAR} 不展开)。

三、常见故障与修复

问题 根因 解决方案
MiniMax API doctor 报 404 doctor 检查 /v1/models 端点,但 MiniMax 只有 /anthropic/v1/messages 误报,不影响实际使用
OMLX 本地模型 401 runtime_provider.py 只读 key_env,忽略 api_key_env 补丁同时兼容两个字段
auxiliary provider 失效 provider: auto 无法正确路由 显式指定 provider: minimax-cn
OMLX api_key_env 不生效 config 字段名与代码读取不匹配 确认使用 key_env 而非 api_key_env

四、日常维护命令

1
2
3
4
5
6
7
8
9
10
11
# 健康检查
hermes doctor

# 自动修复配置
hermes doctor --fix

# 重启网关
hermes gateway restart

# 查看配置
hermes config show

经验总结

  • 修改 config.yaml 后必须先 hermes doctor --fix 再重启
  • 重启失败时检查是否有并发进程占用端口
  • WSL2 和 macOS 环境下的网关管理命令一致

五、核心功能体系

记忆系统(Memory)

Hermes 有两层持久化记忆:

文件 用途 字符上限
MEMORY.md Agent 的个人笔记 — 环境事实、约定、学到的经验 2,200 chars
USER.md 用户画像 — 偏好、沟通风格、期望 1,375 chars

两个文件均存放在 ~/.hermes/memories/,会话启动时注入系统提示词(冻结快照)。

原理:记忆变更在当前会话不生效(保持 LLM 前缀缓存性能),修改立即持久化到磁盘,下个会话起效。

技能系统(Skills)

技能是按需加载的知识文档,采用渐进式披露节省 token:

1
2
3
Level 0: skills_list() → [{name, description, category}, ...]  (~3k tokens)
Level 1: skill_view(name) → 完整内容 + 元数据
Level 2: skill_view(name, path) → 指定引用文件

技能通过 / 命令直接调用:

1
2
3
/axolotl                    # 加载技能并让 Agent 判断需要什么
/github-pr-workflow # 直接执行
/plan # 加载 plan 技能,检查上下文后写实现计划

技能文件存放在 ~/.hermes/skills/,由 skill_manage 工具管理。

Cron 自动化

定时任务支持:

  • 定时触发(0 9 * * *every 2h 等 cron 表达式)
  • 事件触发(webhook)
  • 交付目标:飞书、本地文件、或其他平台

六、工具链配置

  • TTS/图片/音乐:MiniMax 原生 API(MINIMAX_CN_API_KEY),不依赖 Hermes 内置 fal.ai 的 image_gen
  • 本地模型:OMLX(Ollama-MLX),通过 http://127.0.0.1:8000/v1 接入
  • Smart Routingsmart_model_routing.enabled: true 开启后,简单任务自动路由到本地免费模型
  • browser 工具:设置 cloud_provider: '' 使用本地 agent-browser 模式

七、安全与清理

7.1 安全配置审计

在日常维护中,定期运行安全审计能发现潜在风险。以下是我实际排查发现的问题:

高风险项

问题 发现方式 修复方案
.envSUDO_PASSWORD 明文存储 人工检查 .env 文件 立即删除,不推荐存储在此
tirith_fail_open: true 配置审计 改为 tirith_fail_open: false
command_allowlist 规则过于宽泛 安全审计 手动收窄,仅保留必要命令

中风险项

问题 发现方式 处理建议
WhatsApp Bridge 源码存在 npm 漏洞 npm audit 配置已移除则无实际影响,源码目录可删除
streaming 配置冲突 配置比对 根级 streaming.enableddisplay.streaming 含义不同,需确认业务场景

低风险项

问题 处理建议
config.yaml 中空配置块(whatsapp: {}mattermost: {}quick_commands: {} 直接删除整段
service_tier: '' 空字符串 改为 service_tier: standard
timezone: '' 空字符串 改为 timezone: Asia/Shanghai

7.2 凭证管理

核心原则:API Key 只保存在 .env,不冗余存储。

实际排查发现 auth.json 中存在 request_count: 0 的凭证,说明从未被使用过。Hermes 运行时实际读取的是 .env 中的环境变量(通过 api_key_env 引用),auth.json 仅作为凭证池缓存层。

维护建议

  • 定期检查 auth.json 中各 provider 的 request_count,及时清理从未使用的凭证
  • 保留 copilot(GitHub Copilot)等实际使用的凭证
  • 删除冗余凭证:minimax-cnomlx 等(若实际走 .env

7.3 Skills 精简

Skills 目录容易积累大量从未使用的技能,定期精简可减少维护负担。

精简标准(个人经验):

  • 优先保留正在使用的 skill(如 github-pr-workflowhexo-blog-post
  • 删除空目录(仅含 DESCRIPTION.md 无实际内容)
  • 删除与当前配置不符的 skill(如无 Modal GPU 需求则删 modal-serverless-gpu
  • 保留视频/音频相关 skill(若业务需要)

实际清理结果

1
2
3
删除空目录:diagramming/、domain/、email/、feeds/、gaming/、gifs/、inference-sh/、smart-home/、social-media/、note-taking/
删除冗余 skill:modal-serverless-gpu、obliteratus、popular-web-designs
Skills 总数:114 → 约 105 个

7.4 配置精简

config.yaml 也会积累无效配置项,定期清理效果显著。

实际清理数据

  • 初始行数:420 行
  • 清理后:约 391 行(减少约 30 行)

删除项

  • 空平台工具集引用:telegram、discord、whatsapp、slack、signal、homeassistant
  • 空配置对象:honcho: {}quick_commands: {}personalities: {}
  • 重复的 delegation 块(patch 错误引入)

7.5 验证流程

清理完成后,按以下顺序验证:

1
2
3
4
5
6
7
8
9
10
11
# 1. 检查配置语法
hermes doctor --fix

# 2. 确认配置生效
hermes config show

# 3. 重启网关
hermes gateway restart

# 4. 验证核心功能
hermes doctor

注意:修改 config.yaml 后必须先运行 hermes doctor --fix 自动修复错误配置,最后再重启网关。

八、推荐的工作流

  1. 配置修改前先备份:cp config.yaml config.yaml.backup_日期
  2. hermes doctor 验证修改结果
  3. hermes config show 确认配置生效
  4. 最后 hermes gateway restart
  5. 重要决策(如删除 provider、修改认证逻辑)记录到记忆文件

九、使用技巧

来自官方文档的实践建议:

  • 明确表达需求:给出具体上下文(文件路径、错误信息、期望行为),减少来回次数
  • 前置上下文:一次性提供所有相关信息,胜过多次补充
  • 用 Context Files:重复出现的指令(如”use tabs not spaces”)写入 AGENTS.md,Agent 自动读取
  • 交给 Agent 探索:说”修复失败的测试”而非”打开 tests/test_foo.py 第 42 行然后…”
  • 优先用 Skill:复杂流程先查 /skills,再决定是否自己写提示词
  • Cron 自动化重复任务:新闻简报、定时提醒、数据采集等场景优先考虑

日常使用大模型聊天、问答、生成内容时,背后藏着一套完整固定的数据流转逻辑。本文将分词器、词嵌入、隐藏向量、Transformer架构、Prefill预填充、模型层数、维度、参数量等核心知识点串联汇总,用通俗逻辑结合运算关系拆解底层原理,搭建完整的大模型基础认知体系。

一、核心基础名词概念汇总

Tokenizer 分词器

大模型文本处理的第一道入口,模型无法直接识别完整语句,需要按照内置词典规则,将文本切割为最小处理单元。拆分单元可以是单字、词语、子词或是标点符号,只有完成分词得到单元序列,才能开展后续向量化计算。

Token

文本经过分词处理后得到的最小语义单元,每一个单元都会被分配专属数字编号。编号本身不承载语义,仅作为唯一身份标识。日常统计上下文长度、计算调用计费,均以Token作为统计单位。

Embedding 词嵌入

将离散的文字单元,转化为计算机可识别运算的多维数字向量的过程。语义含义相近的内容,转化后的向量数值分布也会更加贴合;语义差异较大的内容,向量数值距离会明显拉开。在主流原生大模型中,词嵌入输出的向量维度,和模型内部隐藏维度保持一致。

向量、隐藏向量、中间状态向量

向量是有序数字组成的数组,是模型唯一的运算数据形式。

隐藏向量指代经过词嵌入转换后,在网络内部流转计算的向量数据,这类数据无法被人类直接解读,仅用于特征运算处理,不会直接对外输出。

中间状态向量是向量经过单层网络权重运算、特征变换后产出的阶段性数据,记录当前层级提炼后的语义信息,会持续传递至下一层网络参与计算。

Transformer 变换器

当下绝大多数主流大模型的核心神经网络架构,常见的通用大模型均基于该结构研发搭建。整体由多组结构一致的模块堆叠构成,依靠自注意力机制捕捉语句上下文关联关系,搭配前馈网络结构,完成语义理解、逻辑推导与文本生成工作。

Prefill 预填充阶段

用户提交完整提问内容后,模型一次性对整段输入内容执行分词、词嵌入、编码运算的全过程。该流程仅执行一次,运算结束后会留存上下文状态信息,后续逐字生成回复时不会重复运算,是提升模型推理响应速度的关键环节。

模型隐藏维度

单个向量包含的数字数量,也是模型全程运算统一的标准尺寸。网络内所有权重矩阵规格、向量传输、矩阵运算,都以该维度为基准,同一模型的向量维度固定不变。

模型层数

指代模型内部堆叠的Transformer模块数量,行业标注的32层、96层模型,对应数量的模块层层叠加,层数越高代表网络结构越深。

模型参数量

网络中所有可学习权重矩阵、偏置参数的总和,涵盖词嵌入层参数以及每一层Transformer模块的全部权重数据。参数量的规模大小,直接决定模型的知识储备上限与语义理解能力。

词库

分词器对应的检索词典容量,决定模型能够识别的文字单元范围,常见词典规模分为三万、五万、十万、十五万词元等不同规格。

二、完整数据流转链路

自然语言文本 → 分词拆分得到基础单元 → 词嵌入转换为标准维度向量

→ 整段向量进入预填充环节完成全局编码

→ 向量送入多层堆叠的Transformer网络

→ 依托权重矩阵完成注意力计算与特征提取,逐层生成中间状态向量

→ 复用已编码的上下文信息,逐个生成新文本单元

→ 最终转换为自然语言输出回复内容

三、关键模块运算逻辑详解

3.1 维度匹配基本原则

矩阵乘法有着固定运算规则,前序矩阵的列数必须和后序矩阵的行数相等,否则无法完成计算。词嵌入产出的向量维度,必须与Transformer内部所有权重矩阵的输入维度严格匹配。

常规模型设计中,嵌入维度等同于模型隐藏维度,天然适配网络运算规格;若使用外部向量数据,或是自定义特殊结构模型出现维度不一致时,需要增设投影层完成维度对齐转换。

3.2 Transformer结构与权重矩阵

单层Transformer模块并不是单一的二维权重矩阵,而是由多组可学习权重搭配固定运算组合而成,核心权重分为两大板块:

多头注意力模块包含查询权重、键值权重、取值权重、输出融合权重,各组矩阵规格统一;

前馈网络模块包含升维权重矩阵与降维权重矩阵。

模型训练习得的语言规则、常识知识都存储在权重矩阵当中,向量与矩阵开展乘法运算,即可实现文本语义特征的提取与优化。

3.3 向量与矩阵运算实例

设定简易运算条件:隐藏维度为4,采用单层Transformer模块,输入语句为猫 吃鱼,分词后得到两个文本单元,采用单头注意力简化运算演示。

初始向量生成

通过词嵌入查表,获取两个四维向量,组合形成输入矩阵:

矩阵格式对应:2个文本单元,每个单元对应4维向量数据。

多头自注意力矩阵运算

设置简易对角权重矩阵:

通过矩阵乘法运算,生成查询、键值、取值特征向量。以查询向量为例:

运算后得到Query矩阵:

按照相同逻辑求出 (K、V) 向量,再计算不同Token间语义相似度,加权融合后得到注意力输出特征。该环节作用:让语句内不同字词互相感知上下文关联,把语义关系融入特征向量当中。

前馈网络特征变换

遵循四倍维度扩张的通用规则,配置4×16升维矩阵与16×4降维矩阵。向量先与升维权重相乘拓展维度,挖掘深层语义特征;经过非线性函数筛选无效信息后,再通过降维权重压缩维度,回归标准四维规格,得到加工完成的中间特征状态:

该环节作用:独立对单个文本单元做语义深化,丰富特征表达细节。

残差连接:原始向量与变换特征融合

将模块初始输入向量 (X),和网络加工后的 (\operatorname{FFN_State}) 逐位置元素相加,完成残差融合:

残差连接核心价值:保留文本基础原始含义,叠加模型挖掘的深层语义;同时打通跨层信息传递通道,缓解多层网络训练时的梯度消失问题,避免信息损耗丢失。

层归一化处理

对融合后的特征矩阵做数值规整收敛,统一数据分布区间,计算公式如下:

式中:

  • (h_i):向量内单个特征数值
  • (\mu):单条向量元素平均值
  • (\sigma^2):单条向量元素方差
  • (\varepsilon):极小常数,规避分母为0运算错误
  • (\gamma、\beta):模型可学习缩放与偏移参数

最终输出单层模块计算结果:

归一化作用:约束特征数值大小,避免数值偏移失控,保障多层网络连续运算稳定可靠。

多层网络流转逻辑

多层模块堆叠运行时,上一层输出的中间状态向量直接进入下一层重复整套运算流程。每一层都会不断更新向量内部数值,循序渐进加深模型对文本内容的理解程度。

3.4 常见认知误区

一层Transformer无法等同于单个权重矩阵,它是集合注意力机制、前馈网络、归一化、残差结构的完整子网络,内部包含多组不同规格的权重矩阵;

模型层数对应模块堆叠数量,层数越多网络深度越高;

中间状态向量是层级运算的产物,全程保持固定维度,仅内部特征数据发生变化。

四、维度、层数、结构与参数量的关联关系

参数量是评判模型规模的核心指标,整体数值由Transformer结构设计、隐藏维度大小、模块堆叠层数共同决定,参数本质就是网络内所有可训练权重与偏置数据。

基础参数符号

:模型隐藏维度,统一的运算标准尺寸

:Transformer模块堆叠层数

:前馈网络扩张维度,常规采用四倍扩张设计

单层模块参数量计算

注意力板块包含四组同规格方阵,参数总量为

前馈网络两组权重矩阵,参数总量为

单层模块整体核心参数:

单层参数规模远大于单纯的维度相乘结果,由多组矩阵共同构成。

多层模块总参数量

按照层数线性累加单层参数,全部模块参数总和:

模型整体参数量

结合词嵌入层权重数据,常规模型输出层权重与嵌入权重共用,不重复统计,整体参数公式:

公式内代表模型词典容量大小。

参数变化规律

隐藏维度对参数量影响最大,参数随维度呈现平方级增长,维度小幅提升就会带来参数规模暴涨,同时模型语义表现力、硬件显存消耗也会同步增加;

堆叠层数与参数量呈线性增长关系,层数增加会提升网络深度,强化模型逻辑推理与长文本理解能力;

网络结构设计同样影响参数体量,前馈扩张倍数、注意力结构改动,都会改变单层参数基准数值。

实际模型参考

以经典70亿参数模型为例,配置32层网络结构、4096维隐藏维度,仅Transformer模块就拥有数十亿参数,叠加嵌入层参数后,整体规模匹配对应参数规格。

五、拓展认知要点

不同形式数据的分词差异

文字文本依靠专属分词器拆分单元,拆分结果具备可读语义;图像、音频数据不存在传统分词逻辑,依靠切块、编码、量化方式生成处理单元,仅适配统一网络运算格式,和文本分词原理完全不同。

Token与向量核心区别

Token只是文字对应的数字编号,仅起到标识作用,本身没有语义含义;向量是内容浓缩后的语义特征,依靠数值分布体现文字含义。实际应用中,统计长度、核算费用使用Token,语义检索、知识库问答场景使用向量数据。

模型数据独立性

不同大模型的词典规则、编号体系互不通用,相同文字在不同模型中对应的数字编号存在差异;各模型独立训练语义空间,训练得到的特征向量无法跨模型直接调用。

固定维度的表达原理

模型参数相当于搭建高维语义空间的框架,整体数量存在上限;向量作为空间内的特征坐标,依靠维度组合的多元化特性承载海量语义信息,有限规格可以表达近乎无穷的文字内容。

六、易混淆概念区分

Embedding 与 Prefill

词嵌入只是文本单元转向量的单一数据转换步骤;预填充是整合分词、嵌入、编码的完整输入处理流程,词嵌入属于预填充环节中的其中一步,二者不能等同看待。

各类向量区别

文本刚转换完成的数据为嵌入向量;进入网络参与运算后统称为隐藏向量;单层运算产出的阶段性数据为中间状态向量。三类数据本源一致,仅处于不同运算阶段。

维度规格区别

常规大模型嵌入维度与隐藏维度统一,保障运算顺畅;仅外部数据接入、定制化模型场景下会出现维度偏差,通过投影层即可完成对齐适配。

层数、维度与参数量

层数决定网络堆叠深度,维度决定单条信息的表达上限,结构设计划定单层参数基数,三项要素相互结合,最终计算得出模型整体参数量。

七、知识总结

文本经过分词处理拆解为基础单元,借助词嵌入转化为模型可运算的向量数据,维度规格统一是所有运算开展的基础条件。

预填充环节一次性完成输入内容编码,向量进入Transformer网络后,依靠多组权重矩阵执行矩阵运算,逐层生成中间特征向量,持续提炼语义信息。

网络层数决定模型深度,隐藏维度决定信息表达上限,结合内部结构设计,共同构成模型整体参数量,参数规模直接划定模型能力边界。

文字、图像、音频数据的分词处理逻辑存在差异,标识单元无语义,特征向量承载含义,不同模型的数据体系相互独立。

有限的参数框架依托维度组合实现海量语义表达,从文字输入到内容输出,全程依靠向量矩阵运算完成信息处理,这也是大模型理解语言、生成内容的底层本质。

整套流程串联总结

  1. 初始向量:自然语言转化为模型可计算的数字特征
  2. 注意力运算:捕捉上下文字词之间的语义关联关系
  3. 前馈网络:深度细化、打磨单个文本单元的语义特征
  4. 残差相加:融合原始基础信息与深层推理特征,完整留存语义
  5. 层归一化:规整数值范围,为下一层网络运算提供稳定输入

单层输出结果 (Out) 会直接作为下一层Transformer模块的输入,经过多层重复堆叠计算,最终实现文本理解、逻辑推理与内容生成。

在 AI Agent 的长期协作中,上下文管理是决定智能体能力上限的核心瓶颈。传统方案要么因窗口限制导致“失忆”,要么因全量传输造成 Token 成本爆炸。本文将基于 OpenClaw 文档与社区实践,详解 Lossless-Claw(LCM)与 QMD 的无损上下文组合方案,从原理、价值到可直接复制的实操配置,全部经过官方文档与经验验证。

一、为什么做:三大痛点

1.1 滑动窗口失忆

OpenClaw 内置的上下文压缩机制存在一个根本性缺陷:它是有损的(lossy)。当对话超过模型上限(如 8k/16k Token),早期信息直接被截断,AI 彻底“忘记”前期需求、代码细节和关键决策。内置压缩还会把数十轮对话压成一段几百 Token 的摘要,不保留原始消息,压缩后细节永远丢失。

1.2 Token 成本雪崩

长对话全量传输,每轮请求 Token 数指数级增长。经验显示,长对话场景下单次请求可能携带 8 万 + tokens,不仅响应延迟高达 45 秒,API 成本可达 $2.4/次。

1.3 缺乏可定制性

传统压缩规则硬编码在核心中,插件无法介入。近期 OpenClaw 版本开始支持可插拔上下文引擎,新增 ContextEngine 插槽与生命周期钩子,使插件可以在上下文生成、压缩、拼接以及子 Agent 管理的各个阶段介入。OpenClaw 文档支持 lossless-claw 插件——基于 Voltropy 团队 LCM 论文的无损上下文方案。

1.4 破局:Lossless-Claw + QMD

这套组合是 OpenClaw 社区中广泛采用的无损上下文方案,核心价值在于分工明确、互补增效

  • Lossless-Claw(LCM) :负责当前会话内存。用 DAG 分层摘要 + SQLite 全量持久化,对话再长也不丢原始消息,同时把活跃上下文压缩到模型窗口 75% 以内。
  • QMD:负责跨会话硬盘记忆。本地语义搜索引擎,只提取最相关的 2-3 句话注入上下文,杜绝全库扫描的 Token 浪费。

LCM 管“当下对话不中断”,QMD 管“历史知识不丢失” ,两者结合实现“永久记忆 + 零成本膨胀”。

1.5 预期效果对比

| 指标 | 原生 OpenClaw | Lossless-Claw + QMD | 提升 |
|: —|: —|: —|: —|
| 上下文大小 | 5000+ Token(溢出) | 800-1200 Token | 削减 75%-85% |
| 历史追溯 | 无法恢复早期消息 | 100% 无损展开 | 永久记忆 |
| 响应速度 | 8-10 秒 | 1-2 秒 | 提速 80%+ |
| Token 成本 | 100 轮 ≈ 50 万 Token | 100 轮 ≈ 5 万 Token | 节省 90% |
| OOLONG 得分 | Claude Code 70.3 | lossless-claw 74.8 | 击败默认方案 |

在 OOLONG 长上下文推理基准测试中,相同模型(Claude Opus 4.6)搭配 lossless-claw 后得分从 70.3 提升至 74.8,Token 消耗降低 30%+。QMD 端 Token 削减达 60-97%(平均 95% 以上),响应速度提升 5-50 倍,成本降低 90-99%,精准度高达 93%。

二、是什么:双引擎架构解析

2.1 Lossless-Claw:DAG 无损上下文管理

Lossless Claw(LCM)是一个为 OpenClaw 开发的无损上下文管理插件,基于 DAG(有向无向图)结构的摘要系统替代 OpenClaw 内置的滑动窗口压缩机制。它不在上下文爆满后临时补救,而是持续在后台异步处理历史消息。首先将所有原始消息完整写入 SQLite 数据库,不主动丢弃任何内容;随后将较旧的消息分块,调用 LLM 生成摘要;这些摘要被组织成 DAG 结构——底层节点保留时序细节,上层节点逐步浓缩为高层级摘要,既能控制上下文体积,又不会真正失去原始信息。

LCM 的核心架构包含两大层次:

  • 持久化存储:所有对话消息、工具调用记录、文件内容均存入 SQLite 数据库,永不主动删除,作为不可变的原始副本。
  • DAG 摘要层:超出最新 N 条消息后,异步生成 Leaf 层级摘要;同层摘要积累到阈值后向上凝练,形成层级化 DAG 结构。每个摘要都链接回它的源消息——这就是“无损”的含义。

LCM 通过五个关键操作完成工作:将每条消息持久化到 SQLite 数据库;将旧消息分块摘要;随着摘要积累,进一步浓缩为更高层级节点,形成 DAG;每轮通过组合摘要 + 近期原始消息来组装上下文;并提供 lcm_greplcm_describelcm_expand 等工具,让 Agent 可以搜索和回忆已压缩历史中的细节。

OpenClaw 核心开发者 Josh Lehman 在亲身测试后的评价:“对话感觉永远不会丢失信息(因为某种程度上确实不会),始终在 30-100K Token 范围内运行,零维护。”

2.2 QMD:本地语义搜索引擎

QMD(Quantum Memory Database)是由 GitHub 用户 tobi 开发的本地语义搜索引擎。它的核心理念是:不要把整个文件塞给 AI,而是先用本地搜索找到最相关的片段(通常只有 2-3 句话),再把这些精准内容传给 AI。

QMD 采用三层混合检索机制:

  1. BM25 全文搜索:精准匹配端口、变量名、文件名等精确术语;
  2. 向量语义搜索:理解概念关联(如“服务器配置”与“部署网关”的同义表述);
  3. LLM 重排序:轻量模型二次筛选,确保最相关片段优先。

QMD 的核心特性:完全本地运行,所有模型、数据、索引都不上云;混合搜索(BM25 + 向量语义 + LLM 重排序);不消耗任何 API 配额,自带模型;支持 MCP 协议,专为 AI 工作流设计。

OpenClaw 文档将其列为支持的 memory backend,定位为 Local-first sidecar,具备重排序(reranking)、查询扩展(query expansion)以及索引工作区外目录的能力。

2.3 协同工作流

  • 写入:LCM 将每一轮对话、每一次工具调用、每一个决策都完整写入 SQLite 数据库,并异步构建 DAG 摘要层,确保信息永不丢失。
  • 检索:QMD 通过向量检索从长期记忆中精准召回最相关的片段,避免把整个历史上下文塞给模型。
  • 巩固:配合 OpenClaw 内置的 Dreaming 梦境系统(模拟人类睡眠的记忆巩固过程),三者形成“写入 → 巩固 → 检索”的完整记忆闭环。

三、怎么做:完整配置指南

⚠️ 前置条件:OpenClaw 版本需 ≥ 2026.3.7(lossless-claw 要求)且 ≥ 2026.2.2(QMD 要求)。用 openclaw --version 检查版本。

3.1 安装 Lossless-Claw

第一步:检查前置条件

  • 已安装支持插件上下文引擎的 OpenClaw(≥ 2026.3.7);
  • Node.js 版本为 22 或更高;
  • 已在 OpenClaw 中配置好可用于摘要生成的 LLM 提供方;
  • 强烈建议 Node 运行环境支持 SQLite FTS5 编译选项。

第二步:安装插件

使用官方插件安装命令:

1
openclaw plugins install @martian-engineering/lossless-claw

该命令会下载插件、登记配置,并在系统中启用 lossless-claw。OpenClaw 会优先从 ClawHub 拉取,自动回退到 npm。

第三步:将 lossless-claw 设为默认上下文引擎

编辑配置文件 ~/.openclaw/openclaw.json,确保 contextEngine 指向 lossless-claw:

1
2
3
4
5
6
7
{
"plugins": {
"slots": {
"contextEngine": "lossless-claw"
}
}
}

第四步:调整进阶参数(可选)

openclaw.jsonplugins.entries 中添加 lossless-claw 的详细配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"plugins": {
"entries": {
"lossless-claw": {
"enabled": true,
"config": {
"freshTailCount": 32,
"contextThreshold": 0.75,
"incrementalMaxDepth": -1,
"summaryModel": "openai/gpt-5.4-mini"
}
}
}
}
}

参数说明:

  • freshTailCount: 32:保护最近 32 条消息不被压缩,保持短期上下文连贯。
  • contextThreshold: 0.75:当上下文占用达到 75% 时启动压缩流程,为模型回复预留空间。
  • incrementalMaxDepth: -1:允许摘要树无限制扩展,让长期记忆自然增长。
  • summaryModel:将压缩摘要绑定到指定模型(本配置使用 openai/gpt-5.4-mini)。

第五步:重启服务

1
openclaw gateway restart

3.2 安装 QMD

第一步:安装 QMD CLI

方式一(推荐,使用 npm):

1
npm i -g @tobilu/qmd

方式二(使用 Bun,速度更快):

1
2
3
4
5
# 先装 Bun
curl -fsSL https://bun.sh/install | bash
# 装 Qmd
bun install -g @tobilu/qmd
sudo ln -s $(which qmd) /usr/local/bin/qmd

第二步:首次运行自动下载模型

首次运行 QMD 时,会自动下载默认模型文件,通常包括 embeddinggemma 和 query-expansion 相关 GGUF 模型,整体约 1.5GB 左右。首次启动会比后续运行慢,并且需要等待模型下载完毕后才能进入正常索引。

⚠️ 常见问题:模型文件名不匹配

QMD 运行时可能因文件名大小写问题找不到模型,需手动创建软链接:

1
2
cd ~/.cache/qmd/models
ln -sf hf_ggml-org_embeddinggemma-300M-Q8_0.gguf local:embeddinggemma-300m-qat-Q8_0.gguf

第三步:配置 OpenClaw 使用 QMD

编辑 ~/.openclaw/openclaw.json,在 memory 段添加 QMD 配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
{
"memory": {
"backend": "qmd",
"citations": "auto",
"qmd": {
"searchMode": "query",
"includeDefaultMemory": true,
"update": {
"interval": "5m",
"debounceMs": 15000,
"onBoot": true
},
"sessions": {
"enabled": true,
"retentionDays": 30
},
"limits": {
"maxResults": 6,
"maxSnippetChars": 600,
"timeoutMs": 120000
},
"scope": {
"default": "deny",
"rules": [
{
"action": "allow",
"match": {
"chatType": "direct"
}
}
]
},
"paths": [
{
"name": "blogs",
"path": "/Users/sean/note/haies.cn/source/_posts",
"pattern": "**/*.md"
},
{
"name": "wans",
"path": "/Users/sean/note/wans",
"pattern": "**/*.md"
}
]
}
}
}

参数说明:

  • backend: "qmd":启用 QMD 记忆后端。
  • searchMode: "query":混合搜索(语义 + 关键词,最准)。可选 search(纯关键词,最快)或 vsearch(纯语义搜索)。
  • paths:配置需要索引的外部路径,支持多个目录。
  • maxResults: 6:最大返回结果数,越多越耗 Token。
  • scope.default: "deny" + rules:默认关闭记忆,仅允许私聊使用。

第四步:初始化 QMD 索引并生成向量嵌入

1
2
3
4
5
# 首次索引(自动扫描 paths 中配置的路径)
qmd index

# 生成向量嵌入(提升搜索精度,必须执行)
qmd embed

💡 建议定期运行 qmd embed(如每天一次)以确保新增文档可被向量检索。

3.3 验证配置

验证 Lossless-Claw

1
2
3
4
5
6
7
# 检查插件列表
openclaw plugins list
# 预期输出包含 @martian-engineering/lossless-claw

# 检查上下文引擎配置
openclaw config get plugins.slots.contextEngine
# 预期输出:"lossless-claw"

验证 QMD

1
2
3
4
5
6
# 查看 QMD 版本
qmd --version

# 检查 OpenClaw 记忆健康状态
openclaw memory status
# 预期看到 Indexed、Store、Vector 状态正常

联合验证

1
openclaw memory status

若输出正常,说明两套系统均已就绪。也可以运行 openclaw memory search "测试关键词" 测试搜索功能。

3.4 验证清单

验证项 命令 预期结果
插件安装 openclaw plugins list 显示 lossless-claw [installed]
引擎配置 openclaw config get plugins.slots.contextEngine 返回 “lossless-claw”
LCM 数据库 ls ~/.openclaw/lcm.db 文件存在
LCM 运行状态 `openclaw logs –limit 50 grep lossless`
LCM 数据统计 sqlite3 ~/.openclaw/lcm.db "SELECT COUNT(*) FROM summaries; SELECT COUNT(*) FROM messages;" 摘要数和消息数
QMD 索引 qmd status 显示 indexed documents 数量
QMD 向量嵌入 qmd embed 显示 Embedded N chunks from M documents
QMD 搜索测试 qmd search "关键词" -c blogs -n 3 返回相关结果
内存搜索 memory_search 工具 返回相关结果

示例验证结果(2026-04-10)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# LCM 状态
$ openclaw logs --limit 50 | grep lossless
2026-04-09T16:08:23.838Z info {"plugin":"lossless-claw"} [lcm] Plugin loaded (enabled=true, db=/Users/sean/.openclaw/lcm.db, threshold=0.75)

$ sqlite3 ~/.openclaw/lcm.db "SELECT COUNT(*) FROM summaries; SELECT COUNT(*) FROM messages;"
159
7855

# QMD 状态
$ qmd status
Documents
Total: 537 files indexed
Vectors: 1882 embedded
Pending: 0

Collections
blogs (qmd://blogs/): 42 files
wans (qmd://wans/): 26 files
memory (qmd://memory/): 275 files
sessions-main (qmd://sessions-main/): 68 files

# 搜索测试
$ qmd search "docker" -c blogs -n 3
qmd://blogs/docker.md:2 #637513 - Score: 85%
qmd://blogs/containerd.md:8 #7d32a7 - Score: 83%
qmd://blogs/geoserver.md:11 #cff5cb - Score: 83%

四、高级优化与故障排除

4.1 黄金参数调优

场景 freshTailCount contextThreshold maxResults
代码调试/编程 40 0.7 3
文档分析 40-64 0.7 4
轻量对话/日常聊天 24 0.8 4

4.2 成本优化策略

  • 摘要模型降级:使用 claude-haiku-4-5 或本地 ollama/llama-3:8b 执行摘要,主对话保持高级模型。
  • 排除噪音会话:通过 ignoreSessionPatterns 过滤 cron job、心跳检测等无状态会话。

4.3 常见问题排查

Q1:配置后 AI 仍“失忆”

1
2
3
4
5
# 检查 contextEngine 是否指向 lossless-claw
openclaw config get plugins.slots.contextEngine
# 若未指向,执行:
openclaw config set plugins.slots.contextEngine "lossless-claw"
openclaw gateway restart

Q2:Token 消耗未降低

1
2
3
4
# 检查 freshTailCount 是否过大
openclaw config get plugins.entries.@martian-engineering/lossless-claw.LCM_FRESH_TAIL_COUNT
# 建议调整为 32,并降低阈值:
openclaw config set plugins.entries.@martian-engineering/lossless-claw.LCM_CONTEXT_THRESHOLD 0.6

Q3:QMD 搜索超时或无结果

1
2
3
4
5
// 调整 openclaw.json 中的超时设置
"limits": {
"timeoutMs": 8000, // 从 4000 增加到 8000
"maxResults": 4 // 减少结果数以降低负载
}

若完全无结果,检查索引是否已生成:qmd embed

Q4:QMD 模型文件未找到

1
2
3
4
5
6
# 检查模型文件
ls -la ~/.cache/qmd/models/

# 如发现文件名不匹配,创建软链接
cd ~/.cache/qmd/models
ln -sf hf_ggml-org_embeddinggemma-300M-Q8_0.gguf local:embeddinggemma-300m-qat-Q8_0.gguf

Q5:SQLite 权限错误(Linux/Docker)

1
2
sudo chmod -R 775 ~/.openclaw/data
sudo chown -R $(whoami):$(whoami) ~/.openclaw/data

五、总结

Lossless-Claw + QMD 是 OpenClaw 社区中广泛使用的无损上下文组合方案,可以有效缓解“失忆、成本、精度”三大痛点。通过 LCM 的 DAG 无损压缩与 QMD 的本地精准检索,目标是实现永久记忆 + Token 膨胀可控 + 更平稳的响应时间

两者分工明确、互补增效:LCM 负责“当下对话不中断”,QMD 负责“历史知识不丢失”,配合 OpenClaw 内置的 Dreaming 梦境系统,形成“写入 → 巩固 → 检索”的完整记忆闭环。在一些测试中表明:在一些长上下文场景中,得分和成本都有明显改善,但实际结果仍依赖具体模型、主题和配置。

本文中的配置、命令和参数基于 OpenClaw、LCM、QMD 的官方文档或社区资料整理,可作为可复制的参考。按此配置,你的 OpenClaw 能更好地支持长期对话与历史记忆场景。

官方参考

在 OpenClaw 中集成 LiteLLM Proxy,通过其自定义 Hook 实现「本地小模型处理简单问题+云端思考型大模型处理复杂问题」的自动路由。复杂度路由是 LiteLLM 的功能,不是 OpenClaw 原生能力。

环境状态:OpenClaw v2026.4.1、oMLX、Qwen3.5-4B-MLX-4bit 已安装完成。
重要说明:复杂度智能路由通过 LiteLLM 的 async_pre_call_hook 实现,OpenClaw 本身不支持基于任务复杂度自动选择模型的功能。


OpenClaw 原生路由能力分析

OpenClaw 原生路由能力(v2026.4.1)

路由类型 支持情况 说明
多代理路由 ✅ 支持 按 channel/account/peer 路由到不同 agent
会话路由 ✅ 支持 基于 session key 的路由(线程、主题)
子代理分发 ✅ 支持 使用 requesterOrigin 进行分发
模型故障转移 ✅ 支持 agents.defaults.model.fallbacks
复杂度智能路由 ❌ 不支持 无根据任务复杂度自动选择模型的能力

为什么选择 LiteLLM 方案?

flowchart TD
    subgraph OpenClaw原生["OpenClaw 原生路由能力"]
        A1["1️⃣ 多代理路由<br/>(Multi-Agent Routing)"] --> A1_result{✓ 根据用户/频道路由到不同 Agent<br/>✗ 不能根据任务复杂度选择模型}
        A2["2️⃣ 模型故障转移<br/>(Model Failover)"] --> A2_result{✓ 模型失败时切换备用模型<br/>✗ 简单的轮询/列表切换<br/>不考虑任务复杂度}
        A3["3️⃣ 复杂度智能路由<br/>(Complexity Routing)"] --> A3_result{✗ OpenClaw 完全不支持<br/>✓ 需要通过 LiteLLM Custom Hook 实现}
    end

LiteLLM vs OpenClaw 原生功能对比

功能 LiteLLM + Hook OpenClaw 原生
复杂度评分 ✅ Token + 关键词 + 代码检测 ❌ 不支持
智能路由 ✅ 自动选择本地/云端模型 ❌ 不支持
故障转移 ✅ 多层自动转移 ✅ 基础故障转移
成本追踪 ✅ 统一计费 ❌ 分散计费
统一入口 ✅ 单一 API 调用 ❌ 需要多配置

结论:OpenClaw 原生路由主要用于多代理场景(不同用户/频道使用不同 Agent),而非复杂度路由(根据任务难度选择模型)。真正的智能路由必须依赖 LiteLLM 的 Custom Hook。


核心价值

通过 LiteLLM Proxy + 自定义 Hook 实现真正的本地+云端复杂度智能路由:

flowchart TB
    A["用户请求"] --> B["OpenClaw Gateway"]
    B --> C["LiteLLM Proxy<br/>(复杂度路由层)"]
    C --> D["async_pre_call_hook<br/>(复杂度分析)"]

    D --> D1["Token 数量统计"]
    D --> D2["关键词模式匹配"]
    D --> D3["复杂度评分算法"]

    D1 --> E{评分 ≥ 阈值?}
    D2 --> E
    D3 --> E

    E -->|是| F["astron-code-latest<br/>(云端)"]
    E -->|否| G["qwen-local<br/>(本地)"]

    F --> H["云端模型<br/>Astron Code<br/>(深度推理)"]
    G --> I["本地模型<br/>oMLX Qwen3.5-4B<br/>(毫秒响应)"]

核心优势

  • 真正的复杂度路由:自动根据任务复杂度选择模型(LiteLLM Hook 功能)
  • 零成本处理简单任务:本地模型响应简单查询
  • 智能故障转移:模型不可用时自动切换
  • 统一成本追踪:集中查看所有模型消费

一、架构概述

flowchart TB
    subgraph OpenClaw["OpenClaw Gateway (v2026.4.1 + skill-vetter)"]
        A["用户请求"]
    end

    A -->|/v1/chat/completions| B["LiteLLM Proxy<br/>(localhost:4000 复杂度路由层)"]

    subgraph LiteLLM["LiteLLM Proxy"]
        direction TB
        C["complexity_router.py<br/>• 复杂度评分算法<br/>• 关键词匹配<br/>• 模型路由决策"]
        D["config.yaml<br/>• 模型列表定义<br/>• 故障转移规则<br/>• Hook 注册"]
    end

    B --> C
    B --> D

    C --> E{"模型选择"}
    E -->|简单任务| F["本地模型"]
    E -->|复杂任务| G["云端模型"]

    subgraph Local["本地模型"]
        F1["oMLX Qwen3.5-4B-MLX<br/>(localhost:8000)<br/>• 零成本<br/>• 毫秒级响应"]
    end

    subgraph Cloud["云端模型"]
        G1["Astron Code / Claude / GPT-4<br/>(api.astron.com 等)<br/>• 按量计费<br/>• 深度推理能力"]
    end

    F --> F1
    G --> G1

重要说明:复杂度路由完全由 LiteLLM Proxy 的自定义 Hook 实现,OpenClaw 仅作为统一的 AI agent 网关。


二、LiteLLM Proxy 安装

1
2
3
4
5
6
7
8
9
10
# 安装 LiteLLM Proxy (带完整依赖)
pip install 'litellm[proxy]'

# 或使用 Docker
docker run \
-v $(pwd)/config.yaml:/app/config.yaml \
-v $(pwd)/complexity_router.py:/app/complexity_router.py \
-e DEEPSEEK_API_KEY="your-deepseek-key" \
-p 4000:4000 \
ghcr.io/berriai/litellm:main-latest

三、复杂度路由 Hook 实现

这是核心组件,实现基于 prompt 复杂度的智能路由。

重要说明:此复杂度路由器是 LiteLLM 的自定义 Hook,不是 OpenClaw 的原生功能。需要先配置 LiteLLM Proxy,然后 OpenClaw 连接到已配置好的 Proxy。

3.1 创建复杂度路由器

创建 ~/.openclaw/litellm/complexity_router.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
"""
LiteLLM 复杂度路由 Hook
根据 prompt 复杂度自动选择本地或云端模型

注意:此功能完全由 LiteLLM 实现,OpenClaw 本身不支持复杂度路由

简单任务 → 本地模型 (oMLX Qwen3.5-4B) - 零成本,毫秒响应
复杂任务 → 云端模型 (DeepSeek Reasoner) - 深度推理能力
"""

import re
from typing import Any, Dict, Literal, Optional
from litellm.integrations.custom_logger import CustomLogger
from litellm.types.utils import ModelResponse
import litellm

class ComplexityRouter(CustomLogger):
"""
复杂度路由器:根据 prompt 特征自动选择模型
"""

def __init__(self):
super().__init__()
# 复杂度阈值:分数 >= threshold 路由到云端
self.threshold = 2

# 复杂任务关键词
self.complex_keywords = [
# 中文复杂任务
"分析", "比较", "设计", "架构", "推理", "证明", "评估", "总结",
"深度", "详细", "全面", "系统", "研究", "解释原因", "为什么",
"如何实现", "如何解决", "论述", "阐述", "评估", "判断",
# 英文复杂任务
"analyze", "compare", "design", "architect", "reason", "prove",
"evaluate", "synthesize", "comprehensive", "detailed", "explain why",
"how to implement", "discuss", "assess", "critical thinking",
# 数学/逻辑
"计算", "推导", "求解", "证明", "calculate", "derive", "solve",
# 代码相关
"debug", "optimize", "refactor", "重构", "优化", "调试"
]

# 简单任务关键词
self.simple_keywords = [
"你好", "hi", "hello", "嗨", "hey",
"谢谢", "thanks", "thank you",
"查询", "look up", "search",
"翻译", "translate",
"今天", "天气", "时间", "日期", "today", "weather", "time", "date",
"问候", "greeting", "打招呼",
"简单", "easy", "simple",
"是什么", "what is", "who is", "define"
]

def _calculate_complexity_score(self, text: str) -> int:
"""
计算 prompt 复杂度分数
返回值越高表示越复杂
"""
score = 0
text_lower = text.lower()

# 1. Token 数量 (粗略估算)
tokens = len(text.split())
if tokens > 1000:
score += 4
elif tokens > 500:
score += 3
elif tokens > 200:
score += 2
elif tokens > 50:
score += 1

# 2. 复杂任务关键词匹配
for keyword in self.complex_keywords:
if keyword.lower() in text_lower:
score += 1

# 3. 简单任务关键词匹配
for keyword in self.simple_keywords:
if keyword.lower() in text_lower:
score -= 2

# 4. 代码/技术内容判断
code_indicators = ["```", "def ", "class ", "function", "import ",
"代码", "code", "python", "javascript", "api"]
for indicator in code_indicators:
if indicator in text_lower:
score += 1

# 5. 问号数量(提问复杂度)
question_count = text.count('?') + text.count('?')
if question_count >= 3:
score += 2
elif question_count >= 1:
score += 1

# 6. 否定简单问候
greeting_patterns = [
r'^你好[吗呀啊]?', r'^hi\s*$', r'^hello\s*$', r'^hey\s*$',
r'^嗨[吗呀啊]?', r'^嗨$'
]
for pattern in greeting_patterns:
if re.match(pattern, text.strip(), re.IGNORECASE):
score = -10 # 强制为简单任务

return score

async def async_pre_call_hook(
self,
user_api_key_dict: Any,
cache: Any,
data: Dict,
call_type: Literal["completion", "text_completion", "embeddings",
"image_generation", "moderation", "audio_transcription"]
) -> Dict:
"""
LiteLLM Pre-Call Hook
在请求发送到模型之前修改模型选择

Args:
user_api_key_dict: 用户 API 密钥信息
cache: 缓存实例
data: 请求数据 (包含 messages, model 等)
call_type: 调用类型

Returns:
修改后的 data (其中 model 字段被替换)
"""
# 只处理 completion 调用
if call_type != "completion":
return data

# 提取文本内容
messages = data.get("messages", [])
text_content = ""

for message in messages:
if isinstance(message, dict):
content = message.get("content", "")
if isinstance(content, str):
text_content += content + " "
elif isinstance(message, str):
text_content += message + " "

# 计算复杂度分数
complexity_score = self._calculate_complexity_score(text_content)

# 路由决策
if complexity_score >= self.threshold:
# 复杂任务 → 云端推理模型
target_model = "astron-code-latest"
route_reason = f"complex (score={complexity_score})"
else:
# 简单任务 → 本地模型
target_model = "qwen-local"
route_reason = f"simple (score={complexity_score})"

# 记录路由决策
print(f"[ComplexityRouter] {route_reason}{target_model}")
print(f"[ComplexityRouter] Text preview: {text_content[:100]}...")

# 修改请求中的模型
data["model"] = target_model

return data

# 创建全局实例供 config.yaml 引用
complexity_router_instance = ComplexityRouter()

3.2 复杂度评分说明

特征 分值 说明
Token > 1000 +4 超长文本
Token 500-1000 +3 长文本
Token 200-500 +2 中等长度
Token 50-200 +1 短文本
复杂关键词 +1/个 分析、比较、设计等
简单关键词 -2/个 你好、查询、翻译等
代码内容 +1 包含代码标记
多个问号 +1~2 深度提问

示例

输入 分数 路由
“你好” -10 本地 (qwen-local)
“翻译 hello world” -3 本地 (qwen-local)
“解释量子计算原理” 3 云端 (astron-code-latest)
“分析人工智能对就业市场的影响” 5 云端 (astron-code-latest)

3.3 工具感知路由(Tool-Aware Routing)

OpenClaw 的核心能力是工具调用(Function Calling),不同工具对模型能力要求差异巨大。以下是工具场景的路由建议:

工具类型与模型匹配矩阵

工具类型 示例场景 推荐模型 原因
简单查询 查天气、查时间、简单计算 qwen-local (本地) 零成本、毫秒响应
文件操作 读取本地文件、列出目录 qwen-local (本地) 本地数据处理,快速响应
文件编辑 写代码、改配置、创建文件 astron-code-latest (云端) 需要代码补全和语法理解
网页搜索 Google搜索、新闻查询 astron-code-latest (云端) 需要联网能力和最新知识
网页内容提取 抓取网页、解析HTML astron-code-latest (云端) 需要理解和处理结构化数据
浏览器自动化 填表单、点击操作、爬虫 astron-code-latest (云端) 需要多步推理和视觉理解
代码调试 修复Bug、性能分析 astron-code-latest (云端) 需要深度推理和复杂分析
架构设计 系统设计、API规划 astron-code-latest (云端) 需要复杂推理和多轮思考
多工具编排 Agent子任务、多步骤工作流 astron-code-latest (云端) 需要长期规划和状态管理

工具感知路由流程图

flowchart TD
    A["用户请求"] --> B{检测工具调用意图?}

    B -->|无| C{文本复杂度评估}
    C -->|简单| C1["qwen-local<br/>(本地)"]
    C -->|复杂| C2["astron-code-latest<br/>(云端)"]

    B -->|是| D{"工具类型?"}

    D -->|简单查询/文件读取| E["qwen-local<br/>(本地)"]
    D -->|文件编辑/网页操作| F["astron-code-latest<br/>(云端)"]
    D -->|代码调试/架构设计| G["astron-code-latest<br/>(云端)"]
    D -->|多工具编排| H["astron-code-latest<br/>(云端)"]

    C1 --> Z["返回结果"]
    C2 --> Z
    E --> Z
    F --> Z
    G --> Z
    H --> Z

增强版复杂度路由器

更新 complexity_router.py 以支持工具感知路由:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
"""
LiteLLM 增强版复杂度路由 Hook
支持工具感知路由,根据任务类型和复杂度自动选择模型

路由策略:
- 简单任务 → 本地模型 (oMLX Qwen3.5-4B)
- 工具操作 → 根据工具类型选择
- 复杂推理 → 云端推理模型 (DeepSeek Reasoner)
"""

import re
import json
from typing import Any, Dict, Literal, Optional, List
from litellm.integrations.custom_logger import CustomLogger
from litellm.types.utils import ModelResponse
import litellm

class EnhancedComplexityRouter(CustomLogger):
"""
增强版复杂度路由器:支持工具感知的智能路由
"""

def __init__(self):
super().__init__()

# 复杂度阈值
self.text_threshold = 2

# 工具类型与模型映射
self.tool_model_mapping = {
# 简单工具 → 本地模型
"simple": {
"tools": [
"weather", "time", "date", "calculator", "simple_search",
"read_file", "list_directory", "get_time", "currency_convert"
],
"model": "qwen-local"
},
# 中等复杂度 → 云端聊天模型
"medium": {
"tools": [
"write_file", "edit_file", "web_search", "web_scrape",
"image_generation", "document_parser", "api_call",
"send_message", "create_reminder"
],
"model": "astron-code-latest"
},
# 高复杂度 → 云端推理模型
"complex": {
"tools": [
"debug", "code_review", "architecture_design", "security_audit",
"multi_agent", "workflow_orchestration", "data_analysis",
"report_generation", "research_synthesis"
],
"model": "astron-code-latest"
}
}

# 复杂任务关键词
self.complex_keywords = [
"分析", "比较", "设计", "架构", "推理", "证明", "评估", "总结",
"深度", "详细", "全面", "系统", "研究", "解释原因", "为什么",
"如何实现", "如何解决", "论述", "阐述", "判断",
"analyze", "compare", "design", "architect", "reason", "prove",
"evaluate", "synthesize", "comprehensive", "debug", "optimize"
]

# 简单任务关键词
self.simple_keywords = [
"你好", "hi", "hello", "嗨", "hey",
"谢谢", "thanks", "查询", "翻译", "天气", "时间",
"问候", "打招呼", "是什么", "what is", "define"
]

def _detect_tool_intent(self, text: str, messages: List[Dict]) -> Optional[str]:
"""
检测是否有工具调用意图
返回工具类型:simple, medium, complex, 或 None
"""
text_lower = text.lower()

# 检查最后一条用户消息是否暗示使用工具
tool_indicators = {
"simple": [
"查一下天气", "现在几点了", "今天多少号", "帮我算一下",
"weather", "time", "date", "what time is it"
],
"medium": [
"帮我写一个文件", "搜索一下", "查找网页", "发消息",
"write", "search", "scrape", "send", "create file",
"帮我发送", "生成图片"
],
"complex": [
"帮我debug", "代码审查", "架构设计", "安全审计",
"帮我分析这段代码", "多步骤完成", "自动执行",
"debug", "review", "architect", "audit", "analyze code",
"帮我规划", "research"
]
}

for level, indicators in tool_indicators.items():
for indicator in indicators:
if indicator.lower() in text_lower:
return level

# 检查消息历史中是否有工具调用
for msg in messages[-3:]: # 检查最近3条消息
if isinstance(msg, dict):
content = msg.get("content", "")
tool_calls = msg.get("tool_calls", [])
if tool_calls:
# 有工具调用,检查工具名称
for call in tool_calls:
func_name = call.get("function", {}).get("name", "").lower()
for level, config in self.tool_model_mapping.items():
if func_name in config["tools"]:
return level

return None

def _calculate_complexity_score(self, text: str) -> int:
"""
计算纯文本复杂度分数
"""
score = 0
text_lower = text.lower()

# 1. Token 数量
tokens = len(text.split())
if tokens > 1000:
score += 4
elif tokens > 500:
score += 3
elif tokens > 200:
score += 2
elif tokens > 50:
score += 1

# 2. 复杂关键词
for keyword in self.complex_keywords:
if keyword.lower() in text_lower:
score += 1

# 3. 简单关键词
for keyword in self.simple_keywords:
if keyword.lower() in text_lower:
score -= 2

# 4. 问号数量
question_count = text.count('?') + text.count('?')
if question_count >= 3:
score += 2
elif question_count >= 1:
score += 1

# 5. 问候检测
greeting_patterns = [
r'^你好[吗呀啊]?', r'^hi\s*$', r'^hello\s*$', r'^hey\s*$'
]
for pattern in greeting_patterns:
if re.match(pattern, text.strip(), re.IGNORECASE):
score = -10

return score

def _select_model_for_tool(self, tool_level: str) -> str:
"""
根据工具类型选择模型
"""
if tool_level in self.tool_model_mapping:
return self.tool_model_mapping[tool_level]["model"]
return "astron-code-latest" # 默认使用云端聊天模型

async def async_pre_call_hook(
self,
user_api_key_dict: Any,
cache: Any,
data: Dict,
call_type: Literal["completion", "text_completion", "embeddings",
"image_generation", "moderation", "audio_transcription"]
) -> Dict:
"""
LiteLLM Pre-Call Hook
支持工具感知的智能路由
"""
if call_type != "completion":
return data

messages = data.get("messages", [])
text_content = ""

for message in messages:
if isinstance(message, dict):
content = message.get("content", "")
if isinstance(content, str):
text_content += content + " "
elif isinstance(message, str):
text_content += message + " "

# 1. 首先检测工具调用意图
tool_level = self._detect_tool_intent(text_content, messages)

if tool_level:
# 工具感知路由
target_model = self._select_model_for_tool(tool_level)
route_reason = f"tool-{tool_level}"
print(f"[EnhancedRouter] {route_reason}{target_model}")
else:
# 2. 纯文本复杂度路由
complexity_score = self._calculate_complexity_score(text_content)

if complexity_score >= self.text_threshold:
target_model = "astron-code-latest"
route_reason = f"complex-text (score={complexity_score})"
else:
target_model = "qwen-local"
route_reason = f"simple-text (score={complexity_score})"

print(f"[EnhancedRouter] {route_reason}{target_model}")

data["model"] = target_model
return data

# 创建全局实例
enhanced_router_instance = EnhancedComplexityRouter()

工具场景路由示例

用户请求 工具检测 路由决策 模型
“你好” 无工具 简单文本 qwen-local
“查一下北京天气” simple工具 天气查询 qwen-local
“帮我搜索OpenClaw最新消息” medium工具 网页搜索 astron-code-latest
“这段代码有Bug帮我看看” complex工具 代码调试 astron-code-latest
“分析这段Python代码的性能” 复杂文本 深度分析 astron-code-latest
“帮我设计一个微服务架构” complex工具 架构设计 astron-code-latest

工具成本优化策略

工具类型 月均调用占比 使用模型 月成本(假设1000次/天)
简单工具 ~40% qwen-local $0
中等工具 ~35% astron-code-latest ~$15
复杂工具 ~25% astron-code-latest ~$25
总计 100% 智能路由 ~$40

对比全云端方案:全部使用 astron-code-latest,月成本约 $100,节省 60%


四、LiteLLM 配置文件

创建 ~/.openclaw/litellm/config.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# ===========================================
# 模型列表定义
# ===========================================
model_list:
# ─────────────────────────────────────────
# 本地模型:oMLX Qwen3.5-4B
# ─────────────────────────────────────────
- model_name: qwen-local
litellm_params:
model: openai/qwen3.5-4b
api_base: http://localhost:8000/v1
api_key: "omlx-local"
rpm: 60
model_info:
mode: chat
supports_function_calling: false
supports_vision: false

# ─────────────────────────────────────────
# 云端模型:DeepSeek
# ─────────────────────────────────────────
- model_name: astron-code-latest
litellm_params:
model: deepseek/astron-code-latest
api_key: os.environ/DEEPSEEK_API_KEY
rpm: 60
model_info:
mode: chat
supports_function_calling: true

- model_name: astron-code-latest
litellm_params:
model: deepseek/astron-code-latest
api_key: os.environ/DEEPSEEK_API_KEY
rpm: 10
model_info:
mode: chat
supports_function_calling: false
supports_reasoning: true

# ===========================================
# 复杂度路由 Hook
# ===========================================
litellm_settings:
# 注册复杂度路由 Hook
callbacks:
- complexity_router.complexity_router_instance

# 重试配置
num_retries: 2
request_timeout: 60

# 故障转移配置
fallbacks:
# 本地模型失败 → 云端模型
- "qwen-local": ["astron-code-latest"]
# 云端推理失败 → 云端聊天模型 → 本地模型
- "astron-code-latest": ["astron-code-latest", "qwen-local"]

# 上下文窗口溢出时降级
context_window_fallbacks:
- "qwen-local": ["astron-code-latest"]
- "astron-code-latest": ["astron-code-latest"]

# 允许的连续失败次数
allowed_fails: 3

# 丢弃不支持的参数
drop_params: true

# ===========================================
# 路由策略
# ===========================================
router_settings:
# 由于我们使用自定义复杂度路由,这里设置为 simple-shuffle 作为 fallback
routing_strategy: simple-shuffle
timeout: 60

# ===========================================
# 服务配置
# ===========================================
general_settings:
master_key: sk-openclaw-local
port: 4000
host: 0.0.0.0

五、环境变量配置

创建 ~/.openclaw/litellm/.env

1
2
# 云端 API Keys
DEEPSEEK_API_KEY=sk-your-deepseek-key

五点五、配置 LiteLLM Proxy 的复杂度路由 Hook

在启动 LiteLLM Proxy 之前,确保 Hook 已正确配置:

1
2
3
4
5
6
7
8
9
# 1. 确保复杂度路由器文件存在
ls -la ~/.openclaw/litellm/complexity_router.py

# 2. 验证 config.yaml 中的 Hook 注册
grep -A 5 "callbacks" ~/.openclaw/litellm/config.yaml

# 3. 测试 Hook 导入
cd ~/.openclaw/litellm
python -c "from complexity_router import complexity_router_instance; print('Hook loaded successfully')"

六、启动与验证

6.1 启动 LiteLLM Proxy

1
2
3
4
5
6
7
8
cd ~/.openclaw/litellm

# 启动服务
litellm --config ~/.openclaw/litellm/config.yaml

# 或者后台运行
nohup litellm --config ~/.openclaw/litellm/config.yaml \
--detailed_debug > litellm.log 2>&1 &

6.2 验证服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 1. 检查健康状态
curl http://localhost:4000/health

# 2. 查看可用模型
curl http://localhost:4000/v1/model/list

# 3. 测试简单任务(应路由到本地模型)
curl -X POST http://localhost:4000/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-openclaw-local" \
-d '{
"model": "qwen-local",
"messages": [{"role": "user", "content": "你好,请介绍一下自己"}]
}'

# 4. 测试复杂任务(应路由到云端模型)
curl -X POST http://localhost:4000/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-openclaw-local" \
-d '{
"model": "astron-code-latest",
"messages": [{"role": "user", "content": "深度分析人工智能对就业市场的影响,需要考虑技术进步、自动化、行业转型等多个维度"}]
}'

6.3 查看日志验证路由

1
2
3
4
5
6
# 查看 LiteLLM 日志
tail -f ~/.openclaw/litellm/litellm.log | grep ComplexityRouter

# 预期输出示例:
# [ComplexityRouter] simple (score=-10) → qwen-local
# [ComplexityRouter] complex (score=3) → astron-code-latest

6.4 验证 OpenClaw 连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 测试 OpenClaw 与 LiteLLM Proxy 的连接
curl -X POST http://localhost:4000/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-openclaw-local" \
-d '{
"model": "qwen-local",
"messages": [{"role": "user", "content": "测试连接"}]
}'

# 验证复杂度路由是否生效
curl -X POST http://localhost:4000/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-openclaw-local" \
-d '{
"model": "astron-code-latest",
"messages": [{"role": "user", "content": "深度分析人工智能发展趋势"}]
}'

七、OpenClaw 配置

重要说明:OpenClaw 的配置只是连接到已配置好的 LiteLLM Proxy。复杂度路由完全在 LiteLLM 层实现,OpenClaw 本身不具备此功能。

编辑 ~/.openclaw/openclaw.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
{
"meta": {
"lastTouchedVersion": "v2026.4.1",
"lastTouchedAt": "2026-04-02T12:00:00.000Z",
"platform": "apple-silicon",
"mlx_optimized": true
},
"models": {
"mode": "merge",
"providers": {
"local-omlx": {
"baseUrl": "http://localhost:8000/v1",
"apiKey": "omlx-local",
"api": "openai-completions",
"models": [
{
"id": "qwen3.5-4b-mlx-q4",
"name": "Qwen3.5-4B-MLX-4bit",
"contextWindow": 32768,
"maxTokens": 4096,
"reasoning": false,
"input": ["text"],
"cost": { "input": 0, "output": 0 }
}
]
},
"litellm": {
"baseUrl": "http://localhost:4000",
"apiKey": "sk-openclaw-local",
"api": "openai-completions",
"models": [
{
"id": "qwen-local",
"name": "Qwen3.5-4B (LiteLLM)",
"contextWindow": 32768,
"reasoning": false,
"input": ["text"],
"cost": { "input": 0, "output": 0 }
},
{
"id": "astron-code-latest",
"name": "DeepSeek-V3",
"contextWindow": 64000,
"reasoning": false,
"input": ["text"]
},
{
"id": "astron-code-latest",
"name": "DeepSeek-R2",
"contextWindow": 200000,
"reasoning": true,
"input": ["text"]
}
]
}
}
},
"agents": {
"defaults": {
"model": {
"primary": "litellm/qwen-local",
"fallbacks": [
"litellm/astron-code-latest",
"litellm/astron-code-latest"
]
}
}
},
"fault_tolerance": {
"enable_failover": true,
"max_retries": 2
}
}

八、OpenClaw 原生路由能力

8.1 多代理路由(Multi-Agent Routing)

OpenClaw 支持按渠道/用户路由到不同 Agent,这与复杂度路由是不同的概念

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"channels": {
"telegram": {
"dmPolicy": "routing",
"route": {
"+8613812345678": "agent-fast", // 快速问答代理
"+8613912345678": "agent-coding" // 编程专用代理
}
},
"discord": {
"dmPolicy": "routing",
"route": {
"user-alpha": "agent-fast",
"user-beta": "agent-reasoning"
}
}
}
}

用途:不同用户/场景使用不同 Agent,而非根据任务复杂度选择模型。

8.2 Model Failover 机制

LiteLLM 的复杂度路由与 OpenClaw 的故障转移协同工作:

flowchart TB
    A["用户请求"] --> B["LiteLLM 复杂度路由<br/>(async_pre_call_hook)"]

    B --> C{复杂度评分 → 模型选择}
    C -->|简单| C1["qwen-local<br/>(本地)"]
    C -->|复杂| C2["astron-code-latest<br/>(云端)"]

    C1 & C2 --> D{模型可用?}
    D -->|是| Z["返回结果"]
    D -->|否| E["LiteLLM 故障转移"]

    subgraph LiteLLM_Fallback["LiteLLM 故障转移"]
        E["fallbacks 配置"]
        E --> E1["qwen-local → astron-code-latest"]
        E --> E2["astron-code-latest → astron-code-latest → qwen-local"]
    end

    E1 & E2 --> F{LiteLLM 层可用?}
    F -->|否| G["OpenClaw Model Failover"]

    subgraph OpenClaw_Fallback["OpenClaw Model Failover"]
        G["agents.defaults.model.fallbacks"]
        G --> G1["litellm/qwen-local → litellm/astron-code-latest → ..."]
    end

    G1 --> H["返回结果"]
    E1 & E2 --> H

8.3 路由能力总结

路由类型 实现层 说明
复杂度智能路由 LiteLLM Hook ✅ 本文方案
多代理路由 OpenClaw ✅ 按用户/渠道
故障转移 双重 LiteLLM + OpenClaw

九、测试完整流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 1. 重启 OpenClaw Gateway
openclaw gateway restart

# 2. 检查状态
openclaw gateway status

# 3. 运行健康检查
openclaw doctor

# 4. 测试复杂度路由(通过 LiteLLM Hook 实现)
# 简单任务 → 自动路由到本地模型
openclaw run "你好"

# 复杂任务 → 自动路由到云端推理模型
openclaw run "深度分析量子计算对未来 cryptography 的影响"

# 5. 查看日志
openclaw gateway logs --tail 100

# 同时查看 LiteLLM 日志验证路由决策
tail -f ~/.openclaw/litellm/litellm.log | grep -E "(ComplexityRouter|EnhancedRouter)"

测试要点

  • 验证 LiteLLM Proxy 的复杂度路由 Hook 是否正常工作
  • 确认 OpenClaw 能正确调用 LiteLLM Proxy
  • 检查故障转移机制是否生效

十、成本优化效果

任务类型 比例 模型 成本
简单任务(问候、查询等) ~60% qwen-local (本地) $0
复杂任务(分析、推理等) ~40% astron-code-latest 按量计费

预估月成本节省(假设每日 100 次请求):

方案 本地占比 云端占比 月成本
全部云端 0% 100% ~$30
智能路由 60% 40% ~$12

十一、架构总结

flowchart TB
    A["用户请求"] --> B["LiteLLM Proxy<br/>(复杂度路由层)"]

    subgraph Router["async_pre_call_hook (复杂度分析)"]
        B --> C["输入"]
        C --> C1["Token计数"]
        C1 --> C2["关键词匹配"]
        C2 --> C3["复杂度评分"]
        C3 --> C4{"模型选择"}

        C4 -->|分数 ≥ 2| C5["astron-code-latest<br/>(云端)"]
        C4 -->|分数 < 2| C6["qwen-local<br/>(本地)"]
    end

    B --> D["+ 故障自动转移"]
    B --> E["+ 成本追踪"]

    C5 & C6 --> F["模型响应"]

    subgraph LocalModel["本地模型"]
        F -->|简单任务 ~60%| G["oMLX Qwen3.5-4B<br/>✓ 零成本<br/>✓ 毫秒级响应<br/>✓ 数据隐私"]
    end

    subgraph CloudModel["云端模型"]
        F -->|复杂任务 ~40%| H["Astron Code<br/>✓ 深度推理<br/>✓ 按量计费"]
    end

    G <-.->|故障转移| H

组件职责分工

组件 主要职责 功能范围
OpenClaw Gateway AI agent 网关 多代理路由、会话管理、工具调用统一入口
LiteLLM Proxy 模型路由中枢 复杂度分析、模型选择、故障转移、成本追踪
本地模型 (oMLX) 简单任务处理 零成本、快速响应、数据隐私保护
云端模型 (Astron) 复杂任务处理 深度推理、知识更新、复杂计算

关键说明:复杂度智能路由完全由 LiteLLM 的自定义 Hook 实现,OpenClaw 提供统一的管理界面和工具调用支持。

智能路由效果

  • 简单任务 (~60%) → 本地模型 (零成本)
  • 复杂任务 (~40%) → 云端模型 (按需付费)
  • 故障时 → 自动转移备用模型
  • 月成本节省 ~60%

十三、OpenClaw vs LiteLLM:功能对比总结

功能维度 OpenClaw LiteLLM 本方案
复杂度路由 ❌ 不支持 ✅ Hook 实现 ✅ 通过 LiteLLM
多代理路由 ✅ 按用户/频道 ❌ 不支持 ✅ OpenClaw 原生
工具调用统一 ✅ Function Calling ❌ 不支持 ✅ OpenClaw 原生
模型故障转移 ✅ 基础故障转移 ✅ 高级故障转移 ✅ 双重保障
成本追踪 ❌ 分散计费 ✅ 统一计费 ✅ LiteLLM 统一
本地模型支持 ✅ 通过 provider ✅ 通过 proxy ✅ 双重集成

最佳实践

  • 使用 OpenClaw 进行多代理管理和工具调用编排
  • 使用 LiteLLM 进行复杂度路由和成本优化
  • 组合使用 获得完整的 AI agent 解决方案

OpenClaw 官方资源

LiteLLM 官方资源

版本更新记录

日期 版本 关键更新
2026-04-01 v2026.4.1 /tasks 后台任务看板,Agent 本地故障转移
2026-03-23 v2026.3.23 Qwen endpoints,UI 优化
2026-03-22 v2026.3.22 ClawHub 优先,MCP 整合
2026-03-13 v2026.3.12 Gateway Dashboard v2,GPT-5.4/Claude 快速模式
2026-03-08 v2026.3.7 Context Engine 插件接口,GPT-5.4 支持

1. 引言:OpenClaw 的“吞金”之痛

OpenClaw 无疑是当前最强大的 AI Agent 框架之一,它让开发者能够构建出真正自主的智能体。然而,几乎所有深度用户都面临两个核心痛点 :

  • 失忆:长对话中,关键信息被内置的压缩机制随机丢弃,任务执行到一半就偏离目标,Agent 的行为发生退化。
  • 吞金:默认的滑动窗口压缩机制虽然试图控制上下文长度,但往往导致上下文冗余,Token 消耗剧增。

更糟糕的是,这两个问题会形成恶性循环:脏上下文导致高 Token 消耗,为了省钱被迫降低模型规格,结果 Agent 表现更差,用户体验直线下滑。

转折点出现在 2026.3.7 版本——OpenClaw 引入了上下文引擎的插件架构,为社区贡献者打开了优化的大门。而 2026.3.13 紧急修复版本进一步修复了压缩一致性、记忆文件重复注入等关键问题 。

本文基于 OpenClaw 2026.3.13 最新版本,从配置调优、记忆系统、上下文管理三个层面,提供一套完整的、可落地的降本增效方案。


2. 原因剖析:Token 都花在了哪里?

在动手优化之前,先要理解钱到底花在了哪儿。每次你与 OpenClaw 对话,发送给模型的远不止你的问题,而是一个完整的工作包:

组成部分 说明
系统提示词 给 AI 的”员工手册”
Workspace 文件 AGENTS.md、TOOLS.md、MEMORY.md 等配置文件
对话历史 越聊越长,产生雪球效应
工具输出 执行命令的 stdout/stderr、抓取的网页内容
你的问题 这才是你真正想问的

Token 消耗的底层逻辑可以用一个公式来概括 :
Token 消耗 = (输入 + 输出) × 调用次数 × 模型价格
其中输入才是真正的大头。OpenClaw 的设计哲学是从无状态到有状态的转变,为了让 Agent 记住一切,框架每次都会默认将完整对话历史发送出去。一次请求的输入可能就有 2-3 万 tokens,聊了 10 轮就是 20-30 万 。

好消息是:2026.3.13 版本修复了多个与 Token 消耗相关的核心问题

  • 压缩后的会话 token 计数不准确 → 已修复
  • 大小写不敏感挂载上记忆文件被注入两次 → 已修复
  • 会话重置提示触发 Azure 内容过滤器 → 已优化

3. 架构级优化:引入分层路由思路

3.1 传统方案的局限

将不同职能拆分到独立 Agent(多智能体架构)虽然能实现上下文隔离,但系统复杂度急剧增加,且主控 Agent 的意图识别本身也在消耗 Token。

3.2 分层路由的核心思想

Viking 分层路由系统的思路值得借鉴:在调用昂贵的主模型之前,先用一个极轻量的模型做意图识别,判断用户到底想干什么,然后只加载与之相关的工具、技能和上下文片段。

如何借鉴:即使不 fork 项目,你也可以手动精简 AGENTS.md 等引导文件,移除对终端用户无用的开发规范、不常用技能的详细说明,从源头减少基础提示词的长度。

⚠️ 注意:Viking 分层路由系统的官方版本不能通过安装插件的方式实现,需要安装社区版 openclaw-viking

1
openclaw plugins install @viking-engineering/openclaw-viking

4. 配置级优化

4.1 利用新版压缩修复

2026.3.13 修复了压缩后会话 token 计数不准的问题,当前版本支持的压缩配置项包括:

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"agents": {
"defaults": {
"compaction": {
"mode": "safeguard", // 使用 safeguard 模式保护最近上下文
"postIndexSync": "async", // 压缩后异步同步会话记忆
"reserveTokens": 8000, // 为回复生成保留 token 空间
"keepRecentTokens": 15000, // 保护最近 15000 tokens
"maxHistoryShare": 0.6 // 历史最多占 60% 上下文
}
}
}
}

4.2 开启会话剪枝

自动移除旧的对话内容,保持上下文在合理范围内 :

1
2
3
4
5
6
7
{
"contextTokens": 200000,
"contextPruning": {
"mode": "cache-ttl",
"ttl": "55m" // 保留 55 分钟内的对话
}
}

4.3 降低无效心跳

心跳(Heartbeat)是 OpenClaw 的定时唤醒机制,用于检查任务、发送提醒。但如果不加控制,它会成为隐形的 Token 杀手 :

算笔账:心跳频率 30 分钟/次,每月心跳次数 1,440 次,每次输入 3,000 Token,每月仅心跳就消耗 432 万 Token!

优化建议:

  • 设置工作时间间隔为 45-60 分钟
  • 深夜 23:00-08:00 设为静默期
  • 精简 HEARTBEAT.md 到最少行数

4.4 关闭非必要附加功能

以下配置项对 Token 消耗的影响程度 :

配置项 功能 影响程度 说明
ENABLE_TITLE_GENERATION 自动标题生成 仅在新建对话时触发
ENABLE_TAGS_GENERATION 自动标签生成 保存记忆时触发
ENABLE_FOLLOW_UP_GENERATION 后续问题建议 中等 每次回复后额外调用模型
ENABLE_AUTOCOMPLETE_GENERATION 输入自动补全 通常在端侧实现

建议根据场景选择性关闭,尤其是 ENABLE_FOLLOW_UP_GENERATION


5. 记忆系统优化:从默认 Memory Search 切换到 QMD

5.1 默认 Memory Search 的问题

OpenClaw 默认的记忆搜索存在几个关键缺陷 :

  • 使用 SQLite 做向量存储,性能不佳
  • 单一向量搜索,结果不够精准
  • 容易把整个记忆文件塞进上下文,导致 Token 爆炸

5.2 QMD 简介

QMD(Queryable Markdown Database) 是 Shopify 创始人 Tobi 开发的一个本地语义搜索引擎,专为 AI Agent 量身定制 。

它的核心逻辑是:不再读全库,只读最相关的那几段。

技术原理

  • 基于 TypeScript + Bun 开发
  • 三层混合检索:BM25 全文搜索 + 向量语义搜索 + LLM 重排序
  • 所有模型在本地运行,完全离线

实际效果

  • 📊 Token 削减:60-97%(平均 95% 以上)
  • ⚡ 响应速度提升:5-50 倍
  • 🎯 精准度:93%(纯语义搜索仅 59%)

5.3 QMD 与默认 Memory Search 的关系

QMD 是替代关系,配置后 QMD 完全接管记忆检索职责,但依然兼容原有记忆文件 。

5.4 QMD 详细配置指南

前置条件

  • OpenClaw 版本 ≥ 2026.2.2
  • SQLite ≥ 3.40.0

安装 QMD CLI

1
2
3
4
5
# 使用 Bun 安装(推荐)
bun install -g @tobilu/qmd

# 或使用 npm 安装
npm install -g @tobilu/qmd

修改 OpenClaw 配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
{
"memory": {
"backend": "qmd", // 切换到 QMD 后端
"citations": "auto",
"qmd": {
"includeDefaultMemory": true, // 包含原有的 MEMORY.md
"update": {
"interval": "5m",
"debounceMs": 15000,
"onBoot": true
},
"limits": {
"maxResults": 7, // 最多注入几段
"maxSnippetChars": 700, // 每段长度限制
"timeoutMs": 4000
},
"scope": {
"default": "allow" // Windows 用户必需
},
"paths": [
{
"name": "memory",
"path": "~/.openclaw/workspace/memory/",
"pattern": "**/*.md"
},
{
"name": "notes",
"path": "~/obsidian/", // 可添加外部笔记库
"pattern": "**/*.md"
}
]
}
}
}

Windows 特别注意事项

  • command: "qmd.exe" 可能需要显式指定
  • scope.default: "allow" 必不可少,避免权限拒绝

初始化索引

1
2
cd ~/.openclaw/workspace
qmd update --dir .

验证效果

1
openclaw memory search "你的搜索词"

观察日志确认 Using QMD memory backend


6. 上下文管理革命:lossless-claw 插件深度解析

6.1 lossless-claw 原理与优势

为什么需要 lossless-claw

OpenClaw 内置的上下文压缩机制存在一个根本性缺陷:它是有损的(lossy) 。具体来说,内置压缩会:

  • 把数十轮对话一股脑压成一段几百 Token 的摘要
  • 不保留原始消息——压缩后细节永远丢失
  • 导致 Agent 行为退化:跳过验证步骤、忽略安全规则

当 LCM 论文的作者告知 OpenClaw 维护者 Josh Lehman 他们的工作时,Josh 立刻意识到这会是 OpenClaw 的一个极棒的补充。他花了 9 天时间疯狂开发,在自己的 Agent 上运行了一周,结果令人印象深刻:”对话感觉永远不会丢失信息(因为某种程度上确实不会),始终在 30-100K Token 范围内运行,零维护” 。

LCM 核心原理:DAG 层次化摘要

Lossless Context Management (LCM) 插件用 DAG(有向无环图)结构的摘要系统替代滑动窗口压缩 :

graph TD
    A[Immutable Store<br>所有原始消息的逐字副本]
    subgraph B [DAG摘要层]
      direction LR
      B1["Depth 0:<br> [摘要A] ← 消息1-8  <br>[摘要B] ← 消息9-16"]
      B2["Depth 1:<br> [浓缩X] ← 摘要A+摘要B"]
      B3["每个摘要都链接回源消息 ← '无损'"]
    end
    B["DAG摘要层<br>Depth 0:<br> [摘要A] ← 消息1-8  <br>[摘要B] ← 消息9-16<br>Depth 1:<br> [浓缩X] ← 摘要A+摘要B<br>每个摘要都链接回源消息 ← '无损'"]
    subgraph C [模型接收内容(Context)]
      direction TB
      C1[系统提示词]
      C2[DAG摘要]
      C3[最近N条原始消息]
    end
    A --> B --> C
    B1 --> B2 --> B3

关键创新

  • 全量持久化:所有消息存入 SQLite,无信息丢失
  • 分层摘要:超出最新 N 条消息后异步生成摘要,同层摘要积累后向上凝练o
  • 动态上下文组装:每轮自动拼接”最新原始消息 + 历史层级摘要”
  • 按需回溯:提供 lcm_greplcm_describelcm_expand 工具,随时调取原始内容

性能实测:OOLONG 基准测试

OOLONG 是什么:长上下文推理基准测试,测的是模型能否理解和推理整段长文本的全局信息 。

测试结果(使用相同模型):

  • lossless-claw:得分 74.8
  • Claude Code:得分 70.3

关键发现:上下文越长,差距越大——在所有测试的上下文长度上,lossless-claw 的得分都高于 Claude Code。

Token 消耗:实测降低 30% 以上,额外消耗的 Token 主要是摘要计算,不会大幅增加总消耗 。

6.2 lossless-claw 配置指南

前置条件

  • OpenClaw 版本 ≥ 2026.3.7(推荐 2026.3.13)
  • SQLite(OpenClaw 默认预装)
  • Node.js ≥ v22

安装步骤(推荐方式)

使用 OpenClaw 的插件安装命令(会自动配置):

1
2
3
4
5
6
# 1. 确保 OpenClaw 已更新到最新版
npm install -g openclaw@latest
openclaw --version # 应显示 2026.3.13

# 2. 使用插件安装命令(推荐)
openclaw plugins install @martian-engineering/lossless-claw

安装命令会自动完成:

  • 下载并安装插件到 ~/.openclaw/extensions/lossless-claw
  • plugins.entries 中添加配置
  • plugins.slots.contextEngine 中注册上下文引擎

手动配置(如需自定义)

如果需要手动配置,确保在 plugins 下正确设置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"plugins": {
"allow": [
"openclaw-qqbot",
"openclaw-lark",
"lossless-claw"
],
"entries": {
"lossless-claw": {
"enabled": true,
"config": {
"freshTailCount": 16,
"contextThreshold": 0.8,
"summaryModel": "astroncodingplan/astron-code-latest"
}
}
},
"slots": {
"contextEngine": "lossless-claw"
}
}
}

配置说明

配置项 说明 推荐值
freshTailCount 保留的原始消息数量 16-32
contextThreshold 触发压缩的上下文阈值 (0-1) 0.8
summaryModel 用于生成摘要的模型 使用主模型

⚠️ 注意contextEngine 应配置在 plugins.slots 下,而非 agents.defaults.contextEngine

验证安装

安装后重启网关,查看日志确认插件加载:

1
2
openclaw gateway restart
openclaw logs --follow | grep -i lcm

正常输出应类似:

1
2
[plugins] [lcm] Plugin loaded (enabled=true, db=/Users/sean/.openclaw/lcm.db, threshold=0.8)
[plugins] [lcm] Compaction summarization model: astroncodingplan/astron-code-latest (override)

注意事项

  • 现有会话不能直接切换:需要 /reset 重置或 /new 开新会话才能使用 lossless-claw
  • 磁盘存储增长:长期使用会导致磁盘存储占用增长,建议定期清理旧会话
  • 重启网关:修改配置后务必重启服务 openclaw gateway restart

7. 综合实践:一次完整的优化旅程

假设你有一个运行了一段时间的 OpenClaw 实例,以下是建议的优化步骤:

7.1 升级到最新版本

1
2
npm install -g openclaw@latest
openclaw --version # 确认显示 2026.3.13

7.2 开启配置级优化

以下配置经实际测试验证可正常工作(2026.3.13 版本):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
{
"agents": {
"defaults": {
"compaction": {
"mode": "safeguard",
"postIndexSync": "async",
"reserveTokens": 8000,
"keepRecentTokens": 15000,
"maxHistoryShare": 0.6
},
"contextPruning": {
"mode": "cache-ttl",
"ttl": "55m"
},
"heartbeat": {
"every": "55m",
"target": "last"
}
}
},
"memory": {
"backend": "qmd",
"citations": "auto",
"qmd": {
"includeDefaultMemory": true,
"update": {
"interval": "5m",
"debounceMs": 15000,
"onBoot": true
},
"limits": {
"maxResults": 7,
"maxSnippetChars": 700,
"timeoutMs": 4000
},
"scope": {
"default": "allow"
}
}
}
}

7.3 安装 lossless-claw 插件

1
2
# 使用插件安装命令(推荐,自动配置)
openclaw plugins install @martian-engineering/lossless-claw

安装后会自动配置 plugins.slots.contextEngine

7.4 重启网关

1
openclaw gateway restart

7.5 验证效果

1
2
3
4
5
# 查看插件加载日志
openclaw logs --follow | grep -i lcm

# 测试 QMD 记忆搜索
openclaw memory search "测试关键词"

7.6 优化前后对比

建议用实际监控数据展示效果。根据社区反馈,这套组合拳通常可以实现:

  • Token 消耗降低 30-60%
  • 响应速度提升 5-10 倍
  • 记忆精准度大幅提升

8. 避坑指南与注意事项

  1. 现有会话不能直接切换到 lossless-claw,需要 /reset/new
  2. 不要同时运行用户级和系统级 OpenClaw 服务,会导致冲突
  3. 修改配置后务必重启服务openclaw gateway restart
  4. QMD 首次索引可能需要时间,耐心等待完成
  5. 定期检查磁盘空间,防止旧会话占用过多存储
  6. 注意版本号差异:Git Tag 是 v2026.3.13-1,但 npm 版本是 2026.3.13,升级时无需纠结
  7. Windows 用户特别注意 QMD 的 scope 配置

9. 总结与展望

本文基于 OpenClaw 2026.3.13 版本,从三个层面提供了完整的降本增效方案:

优化层面 核心方案 效果
配置级优化 会话剪枝、compaction 模式调优 减少 30-50% 无效消耗
记忆系统 QMD 混合检索 Token 削减 60-97%,精准度 93%
上下文管理 lossless-claw DAG 摘要 无损记忆,OOLONG 得分 74.8

这三者并不互斥,而是可以协同工作:QMD 负责外部知识的精准检索,lossless-claw 负责对话历史的高效管理,配置优化则贯穿始终。

核心指导思想:按需加载、本地优先。让昂贵的云端模型只处理真正需要它的事情,其他工作尽可能交给本地计算。

展望未来,OpenClaw 社区仍在快速进化。2026.3.13 版本带来的浏览器控制、安全加固、Slack 深度集成等更新 ,为 AI 智能体打开了更广阔的应用空间。期待更多优秀的插件和方案涌现,让 OpenClaw 既强大又亲民。


附录:常用命令速查表

目的 命令
查看 OpenClaw 版本 openclaw --version
升级到最新版 npm install -g openclaw@latest
安装 lossless-claw(推荐) openclaw plugins install @martian-engineering/lossless-claw
安装 QMD bun install -g @tobilu/qmd
重启网关 openclaw gateway restart
查看日志 openclaw logs --follow
重置会话(启用新插件) /reset 或在聊天中发送 /new
QMD 手动索引 qmd update --dir .
QMD 测试搜索 qmd search "关键词" -c .
查看服务状态 openclaw doctor
验证 lossless-claw 加载 openclaw logs --follow | grep lcm

本文基于 OpenClaw 2026.3.13 版本编写,配置路径和参数可能随版本更新而变化,请以官方文档为准。

1
wget -qO- https://haies.cn/assets/checkname.js

使用说明

checkname 是一个基于 Node.js 的命令行工具,用于检查和自动修复文件及目录名称,确保它们能够同时在 Windows 11macOSUbuntu 系统中正常使用,便于跨平台文件共享。工具会检查文件名是否包含禁止字符、是否超长、是否存在空格等不可见字符,并按照预定策略进行规范化处理,同时自动处理重名冲突。

安装与运行

  • 环境要求:Node.js 12.0 或更高版本(建议使用 LTS 版本)。
  • 获取脚本:将脚本保存为 checkname.js
  • 运行方式:在终端中执行 node checkname.js [参数] [目录1] [目录2] ...

基本用法

1
node checkname.js [-p] <目录1> [<目录2> ...]
  • -p:处理模式。
    • 若指定此参数,脚本会尝试读取目标目录下最新的日志文件,并根据日志记录对不符合规范的文件/目录进行重命名操作。
    • 如果目录下没有日志文件,则先执行完整检查并生成日志,然后立即根据该日志进行处理。
    • 处理完成后,日志文件会被更新,记录每个条目的处理结果(新路径、状态等)。
  • 不指定 -p:仅检查模式。脚本遍历目录,找出所有不符合规范的文件和目录,并将记录保存到新生成的日志文件中(不会修改任何文件)。

使用示例

示例 1:仅检查目录 /home/user/share

1
node checkname.js /home/user/share

输出:

1
2
3
4
处理目录: /home/user/share
仅检查模式,不会修改文件
检查完成,发现 3 个不符合规范的条目
日志已保存: /home/user/share/checkname_20250302_143022.jsonl

此时目录下会生成日志文件,记录不合规条目的详细信息。你可以查看日志决定是否进行下一步处理。

示例 2:处理目录(基于已有日志)

1
node checkname.js -p /home/user/share

假设目录下已有日志 checkname_20250302_143022.jsonl

1
2
3
4
5
处理目录: /home/user/share
使用现有日志: checkname_20250302_143022.jsonl
开始处理 3 个条目...
处理完成,日志已更新: checkname_20250302_143022.jsonl
统计: 已处理 2, 错误 0, 跳过 1

脚本会读取日志,重命名其中两个文件/目录,并更新日志状态。跳过的条目可能是因为原名称已合规(无需修改)。

示例 3:处理多个目录,且目录无现有日志

1
node checkname.js -p /mnt/data /mnt/docs

输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
处理目录: /mnt/data
未找到现有日志,将先执行检查...
检查完成,发现 5 个不符合规范的条目
已生成日志: checkname_20250302_144512.jsonl
开始处理 5 个条目...
处理完成,日志已更新: checkname_20250302_144512.jsonl
统计: 已处理 5, 错误 0, 跳过 0

处理目录: /mnt/docs
未找到现有日志,将先执行检查...
检查完成,发现 2 个不符合规范的条目
已生成日志: checkname_20250302_144513.jsonl
开始处理 2 个条目...
处理完成,日志已更新: checkname_20250302_144513.jsonl
统计: 已处理 2, 错误 0, 跳过 0

示例 4:查看日志内容

1
cat /home/user/share/checkname_20250302_143022.jsonl

输出示例:

1
2
{"type":"file","originalPath":"/home/user/share/a*b?.txt","newPath":null,"issues":["invalid_char"],"status":"pending","timestamp":"2025-03-02T14:30:22.123Z"}
{"type":"dir","originalPath":"/home/user/share/这是一个非常长的目录名称中文英文混合......","newPath":null,"issues":["too_long"],"status":"pending","timestamp":"2025-03-02T14:30:22.456Z"}

处理后的日志会更新 newPathstatus

相关说明

1. 规范性规则

  • 禁止字符:包含以下任一字符的名称被视为不合规:
    • <>:"/\|?* (Windows 文件系统禁止的字符)
    • ASCII 控制字符(0x00–0x1F)
    • 所有 Unicode 空白字符(包括空格、制表符、换行符等)
  • 长度限制:文件名(包括扩展名)的 UTF-8 编码字节数不得超过 255 字节(这是 Linux 的极限值,也是 Windows 和 macOS 的安全上限)。中文字符通常占 3 字节,需要特别注意。
  • 忽略条目:脚本会自动跳过以下类型的文件和目录(及其内部所有内容):
    • 以点(.)开头的隐藏文件/目录
    • 名称为 node_modulesdistbuildbindebug 的目录(不区分大小写)

2. 处理策略

当发现不合规的名称时,按以下顺序进行修正:

  1. 删除非法字符:移除所有禁止字符。
  2. 长度缩减:如果删除非法字符后仍超长,则对主名(不含扩展名)依次应用以下规则,直到字节数达标:
    • 删除特殊字符(非字母、数字、下划线 _、连字符 -)。
    • 将连续重复 4 次以上的字符缩减为 4 次(例如 "aaaaa""aaaa")。
    • 从主名末尾逐个删除字符。
  3. 重名冲突处理:修正后的名称若与同目录下已有条目重名,则自动添加序号 (1)(2)…… 直至不冲突。添加序号时会确保总长度不超限,必要时会进一步截断主名。

3. 日志文件

  • 命名格式checkname_YYYYMMDD_HHMMSS.jsonl(例如 checkname_20250302_143022.jsonl),保存在被分析的目录下。

  • 格式:JSON Lines,每行一条记录,包含以下字段:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    {
    "type": "file|dir", // 条目类型
    "originalPath": "/绝对/路径/原名称", // 原始完整路径
    "newPath": "/绝对/路径/新名称", // 处理后的路径(仅处理模式有值)
    "issues": ["invalid_char", "too_long"], // 不合规原因
    "status": "pending|processed|error|skipped", // 状态
    "error": "错误信息(如果有)", // 处理失败时的错误信息
    "timestamp": "2025-03-02T14:30:22.123Z" // 记录生成时间
    }
  • 作用:日志既是检查结果的记录,也是处理模式的输入。处理模式只会处理 statuspending 的条目,并更新其状态为 processederrorskipped

4. 处理模式详解

  • 基于现有日志:若目录下已有日志文件,脚本会自动选择最新的一个,读取其中的记录,然后尝试处理所有状态为 pending 的条目。处理完成后,日志文件会被覆盖更新。
  • 无日志时:如果目录下没有日志文件,则先执行完整检查,生成新日志,然后立即根据该日志进行处理。这相当于一次完成“检查+处理”。
  • 重复运行:可以多次运行处理模式,每次只会处理尚未处理的条目(pending 状态)。已处理(processed)、出错(error)或跳过(skipped)的记录不会重复操作。

注意事项

  • 备份重要数据:处理模式会实际修改文件名,建议首次使用时先运行不带 -p 的检查模式,查看日志确认后再执行处理。
  • 权限问题:确保脚本对目标目录有读写权限,否则处理可能失败。
  • 跨平台兼容:修正后的文件名仍可能在某些极端情况下不兼容(例如保留字如 CONPRN 等,Windows 有保留设备名),本工具未处理这些情况,请自行留意。
  • 日志累积:多次运行处理模式会不断更新同一个日志文件,如需保留历史记录,请手动备份旧日志。
  • 并发安全:脚本为串行处理,不会同时修改多个文件,避免冲突。

wget -qO- https://haies.cn/assets/svn_server_tool.sh

使用说明

在服务器端直接查看和统计 SVN 代码仓库信息,无需通过客户端连接。

功能

  • 目录内容查看:查看 SVN 仓库目录结构,仅显示指定目录的第一层内容(非递归)
  • 代码修改历史查询:查看文件或目录的所有修改记录,包括版本号、作者、时间、提交信息
  • 代码提交统计分析:统计提交情况,按作者统计提交次数和百分比,显示提交时间范围

基本用法

1
./svn_server_tool.sh <功能> <仓库路径> [目录/文件路径]
  • 功能参数(第一个参数):ls列出目录、log查看历史、stat统计提交
  • 仓库路径(第二个参数):SVN 仓库物理路径,如/var/svn/repos/myproject
  • 目标路径(第三个参数):ls为可选,logstat为必填(仓库内相对路径)

使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 查看仓库根目录
./svn_server_tool.sh ls /var/svn/repos/myproject

# 查看指定目录
./svn_server_tool.sh ls /var/svn/repos/myproject /trunk/src

# 查看文件修改历史
./svn_server_tool.sh log /var/svn/repos/myproject /trunk/src/main.java

# 查看目录修改历史
./svn_server_tool.sh log /var/svn/repos/myproject /trunk/src

# 统计文件提交情况
./svn_server_tool.sh stat /var/svn/repos/myproject /trunk/src/main.java

# 统计目录提交情况
./svn_server_tool.sh stat /var/svn/repos/myproject /trunk/src

1
wget -qO- https://haies.cn/assets/tar_batch.sh

使用说明

智能压缩指定目录内文件数量较多的文件夹,自动根据目录深度和文件数量应用不同压缩规则,并排除文档、图片、视频、音频等特定文件类型。

该脚本特别适合处理日志目录、临时文件目录、上传目录等包含大量小文件的场景,能有效减少 inode 使用量,提升文件系统性能。

基本用法

1
./tar_batch.sh [目标目录]
  • 目标目录:可选参数,不指定时默认处理脚本所在目录
  • 处理深度:3-5 级目录,按从浅到深顺序

使用示例

1
2
./tar_batch.sh                 # 压缩当前目录
./tar_batch.sh /path/to/data # 压缩指定目录

相关说明

压缩规则

目录深度 条件 操作
< 4 不含排除文件类型,文件数 50-100 压缩
= 4 不含排除文件类型,文件数 > 50 压缩
> 4 无条件 压缩

排除的文件类型

  • 文档:.txt .pdf .doc .docx .xls .xlsx .ppt .pptx .odt .md .rtf
  • 图片:.jpg .jpeg .png .gif .bmp .tiff .svg .webp
  • 视频:.mp4 .avi .mov .mkv .flv .wmv .m4v .webm
  • 音频:.mp3 .wav .flac .aac .ogg .m4a .wma

输出说明

执行后,符合条件的目录会被压缩,并在同级位置生成:

  • 单卷包目录名.tar.gz
  • 多卷包目录名_archive/ 文件夹(内含分卷文件)

特性说明

  • 终端实时显示当前正在压缩的文件名
  • 在目标目录生成带时间戳的日志文件

1
wget -qO- https://haies.cn/assets/tar_single.sh

使用说明

大容量单目录分卷压缩、解压工具,支持 gzip、zstd(推荐)、xz 三种压缩算法,提供创建、解压、测试三种操作模式。

核心特性

  • 自动检测压缩格式,解压和测试时无需手动指定算法
  • 提供分卷校验和验证,确保数据完整性
  • 彩色日志输出,包含时间戳,便于跟踪和审计
  • 默认使用并行压缩工具,处理大文件时效率更高

基本用法

1
./tar_single.sh -[操作方式][压缩算法] [操作对象]
  • 操作方式c创建、x解压、t测试
  • 压缩算法(仅创建时需要):z gzip(默认)、s zstd(推荐)、o xz(高压缩比)

使用示例

1
2
3
4
5
6
7
8
9
10
# 创建压缩包
./tar_single.sh -cz /path/to/data # gzip
./tar_single.sh -cs /path/to/data # zstd
./tar_single.sh -co /path/to/data # xz

# 解压压缩包(自动检测格式)
./tar_single.sh -x /path/to/archive_dir

# 测试完整性(自动检测格式)
./tar_single.sh -t /path/to/archive_dir

0%