目录

BMC-LLM

嵌入式芯片 LLM 挑战(CCF openUBMC 赛题二参赛作品) 单二进制 / 零依赖 / 纯 C / Arm Cortex-A55 / 1.6GB 内存 v1.0.0(2026-08-10 终稿)

Tests Commits Docs


🏆 竞赛提交(v1.0.0 终稿)

赛题二竞赛材料:技术报告(docs/technical-report-final.md,PDF 见 submit/technical-report.pdf)、合并 PR 清单(docs/pr-list.md,Gitee PR #1–#13 + 5 轮检视 58 项修复)、答辩 PPT(docs/presentation/slides.md)、演示脚本(demo/)。

可执行程序包(submit/,由 make release 生成):ARM 静态二进制 bmc-llm-arm64 + 源码包 + 部署文档,SHA256 校验:

cd submit/ && sha256sum -c SHA256SUMS

模型文件(Qwen2.5-0.5B Q3_K_M,412MB)不随包分发,部署时执行 scripts/download-models.sh 获取。

核心数字(v1.0.0 实测,ARM A55 / 1.6GB):

  • 首 token 延迟:36.6 秒(冷启动)/ ~5 秒(daemon 命中)
  • 生成速度:1.3 tok/s
  • 峰值内存:464 MB(daemon 常驻 ~647 MB RSS)
  • 单元测试:59 suites / 928 tests / 0 failed(877 个 TEST_CASE)
  • 集成测试:39 passed / 0 failed(daemon 沙盒 20 CASE)
  • 二进制体积:8.35 MB(ARM 静态链接,零运行时依赖)

5 分钟上手:见 docs/quickstart.md

复现构建:

make build-llama && make native && make test && make arm

详见 docs/technical-report-final.md §10 与 docs/pr-list.md。


演示

A 类查询(<10ms 模板输出)

./build/bmc-llm "CPU温度多少"
# 输出:[SENSORS] ... 传感器读数 ...

B 类查询(~50ms 检索输出)

./build/bmc-llm "最近有什么告警"
# 输出:[检索] 命中 N 条 SEL 事件 ...

C 类查询(~2-5s RAG + LLM 推理)

./build/bmc-llm "为什么系统这么慢"
# 输出:[系统提示]...[实时数据]...[历史检索]...[LLM 响应]

更多演示脚本见 demo/(4 个脚本 + 预期输出说明)。

性能基准(ARM A55 实测)

指标 实测值 目标 状态
首 token 延迟(冷启动) 36.6s <60s ✅
首 token 延迟(daemon 命中) ~5s <10s ✅
生成速率 1.3 tok/s >1 tok/s ✅
峰值内存(LLM 推理) 464 MB <700 MB ✅
二进制体积(ARM 静态) 8.35 MB <10 MB ✅

快速开始

# 构建
make native  # x86 测试
make arm     # ARM 交叉编译

# 下载模型(Qwen2.5-0.5B-Q3_K_M 推荐)
make download-models

# 启动守护进程(后台常驻,消除 ~18s 冷启动延迟)
./build/bmc-llm --daemon &

# 客户端自动检测守护进程,无需手动指定
./build/bmc-llm "CPU温度多少"     # A 类(<10ms 模板输出)
./build/bmc-llm "最近告警"          # B 类(~50ms 检索输出)
./build/bmc-llm "为什么系统慢"     # C 类(RAG + LLM 推理)

# 进入 REPL(检测到 daemon 时走远端 REPL,零本地加载)
./build/bmc-llm

# 停止守护进程
./build/bmc-llm --daemon --shutdown   # 或 kill $(pgrep bmc-llm)

# 演示异常场景
./scripts/demo-failures.sh

# 性能基准
./scripts/benchmark.sh

Daemon 模式

Daemon 模式通过 Unix Socket 常驻后台,消除每次查询 ~18s 模型加载延迟,是生产部署的推荐运行方式。单进程常驻:模型预热 + System Prompt KV Cache 复用 + 周期遥测采集(60s collect → ingest)。

架构

┌─────────────┐   JSON RPC / NDJSON  ┌──────────────────────┐
│   Client     │ ◄──────────────────► │   Daemon(单进程常驻) │
│  (oneshot /  │   AF_UNIX Socket     │  模型预热 + KV Cache   │
│   REPL)      │   /tmp/bmc-llm.sock  │  周期采集 + FTS 摄取   │
└─────────────┘                      └──────────────────────┘

Client 自动检测 Socket 上的守护进程(未检测到则自动拉起):

  • 守护进程已运行 → 通过 Socket 转发查询,跳过本地模型加载
  • 守护进程未运行 → 自动启动 daemon 并连接(单例进程锁)

启动守护进程

# 后台运行(生产推荐,自动单例)
./build/bmc-llm --daemon &

# 前台运行(调试用)
./build/bmc-llm --daemon --foreground

# 指定配置文件
./build/bmc-llm --daemon --config /etc/bmc-llm.json

客户端使用

# 一次性查询 — 自动检测/拉起 daemon
./build/bmc-llm "CPU温度多少"

# REPL 模式 — 检测到 daemon 时进入远端 REPL
./build/bmc-llm
# bmc-llm> CPU温度多少          ← 查询通过 Socket 发送
# bmc-llm> /status               ← 查看会话统计 + daemon 状态和 LLM 引擎信息
# bmc-llm> /quit                 ← 退出

# 斜杠命令
# /help      — 显示斜杠命令帮助
# /status    — 查看会话统计 + daemon 状态(llm.status RPC)
# /new       — 重置会话并清除 KV Cache,开始新会话
# /collect   — 手动触发遥测采集(支持 /collect <类型>,如 sensors / sel / dmesg)
# /context   — 查看最近一次拼装的 Prompt
# /export    — 导出当前会话为 JSON($HOME/bmc-llm-session-*.json)
# /quit      — 退出 REPL

通信协议(PR #6 统一为 JSON RPC)

属性 值
传输方式 AF_UNIX, SOCK_STREAM
Socket 路径 动态化(var/run/bmc-llm.sock,部署根目录推导)
请求格式 {"cmd":"...","id":"req_NNN","payload":{...}}\n(NDJSON 帧)
响应格式 流式:{"stream":"tok","text":"..."} → {"stream":"done","finish_reason":"stop"}
tool_call OpenAI 兼容 shape:{"id":"call_xxx","type":"function","function":{"name":"...","arguments":"..."}}
健康检查 {"cmd":"ping"} 心跳
兼容 旧纯文本协议(查询\n / 响应\n.\n)保留兼容路径

架构

CLI 交互层  (repl/ + agent/)   getopt_long + linenoise REPL + 斜杠命令 + Agent 编排
查询路由层  (classify/ + guard/)  20 关键词规则 + 40+ 黑名单 + A/B/C 三分类
上下文组装  (context/)      Few-shot Prompt + 实时遥测 + BM25 检索
├─ 采集层  (collect/)     12 个 col_*.c(sensors/SEL/FRU/NVMe/PEF/...,三级回退 + iBMC 封装)
├─ 检索层  (retrieve/)    5 张 FTS5 + BM25 + 时间衰减
├─ 诊断层  (diagnose/)    16 PB + GBNF Grammar + 工具调用 + Action 执行
└─ 推理层  (llm/ + daemon/)  llama.cpp 纯本地 + KV Cache 复用 + SIGALRM 超时保护
配置层     (config/)       JSON 配置解析与运行时管理

详细架构: docs/architecture.md

核心模块

模块 内容
docs/architecture.md 总体架构
docs/playbook-catalog.md 16 PB 完整定义
docs/module-collect.md 12 采集器设计
docs/module-retrieve.md 5 FTS5 + BM25
docs/topic-bm25-time-decay-expansion.md BM25 评分 + 时间衰减 + 术语展开专题详解
docs/module-fault-diagnosis.md 故障诊断闭环
docs/module-llm.md LLM 推理层
docs/config-schema.md 配置 Schema
docs/diagnosis-loop.md 端到端诊断闭环
docs/technical-report-final.md 完整技术报告(12 章)
docs/pr-list.md 合并 PR 清单(#1–#13)

查询三分类(A / B / C)

查询路由层(classify/classifier.c)基于 20 条关键词规则对用户输入进行三分类, 首命中即用,按”意图强度”从高到低排序(C 推理 > B 检索 > A 直查), 避免”为什么温度高”被 A 类”温度”规则截胡。规则未命中时默认归入 B 类(检索), 检索无结果再升级 C 类(完整 RAG)(分类兜底反转,PR 2026-08-10)。

完整实现见 src/classify/classifier.c;分类枚举见 src/inc/bmc_llm.h 的 query_class_t。

A 类(QUERY_DIRECT)—— 确定性直查

分类原则

查询语义明确、答案固定为”读取某类传感器或状态字段”的场景。 关键词覆盖:CPU 温度、风扇、转速、电压、电源/供电、内存/负载/磁盘、RAID/BBU/DIMM/NVMe/FRU 状态等。

触发关键词示例

CPU温度 / 温度 / 风扇 / 风扇转速 / 电压 / 功耗 / 电源 / 供电 / PSU / 内存 / memory / RAM / 可用内存 / 磁盘 / 存储空间 / 负载 / 系统信息 / 系统状态 / RAID / ldinfo / BBU / 电池 / DIMM / ECC / NVMe / FRU / 序列号

处理流程(典型 <10ms,无 LLM)

  1. guard_check_input() 做输入安全过滤(黑名单 / 长度限制)
  2. classify_query() 命中 A 类规则,确定 collect_flags(如 COL_SENSORS / COL_SYSTEM / COL_FRU)
  3. collect_execute(flags) 串行调用所需采集器(ipmcget -t sensor -d list / ipmcget -d psuinfo / ipmcget -t storage -d ctrlinfo / /proc/meminfo 等), 数据带回 datasource 字段和 1s 缓存
  4. collect_ingest_to_fts() 把本次新数据写入 FTS 表(为后续 B 类检索供料)
  5. sprintf 模板直接输出格式化结果(如 [SENSORS] ... 传感器读数 ...)
  6. (可选)若 golden_cascade.direct_llm_enabled=true 且 LLM 可用,走 LLM 增强输出自然语言摘要(max ~64 token); LLM 失败时降级到原始模板输出
  7. filter_template_artifacts() 过滤 Chat Template 残留标签(仅黄金级联路径)

B 类(QUERY_RETRIEVE)—— 检索型查询

分类原则

查询语义为”回顾/检索/查看历史”的场景,期望从 SEL / dmesg / journal / 操作审计等历史数据中 取出关键条目。关键词覆盖:告警/异常/错误、最近/历史/昨天、操作/审计/登录、系统日志/日志记录。

触发关键词示例

告警 / 异常 / 错误 / 故障 / alert / error / 最近 / 之前 / 昨天 / 上周 / 历史 / 操作 / 登录 / 审计 / operatelog / 系统日志 / 查看日志 / 日志记录 / log

处理流程(典型 ~50ms,可选 LLM 摘要)

  1. guard_check_input() 输入安全过滤
  2. classify_query() 命中 B 类规则(规则未命中的兜底默认归 B 类)
  3. retrieve_query(query, BM25_DEFAULT_TOP_K) 触发检索流程:
    1. query_rewrite_expand() 术语展开(如”过热 死机” → “overheat thermal hang freeze watchdog”)
    2. SQLite FTS5 MATCH 在 5 张表(sel_fts / dmesg_fts / journal_fts / knowledge_fts / operatelog_fts)并行/单表检索
    3. BM25 score + time_decay_weight 融合打分排序
    4. sel_fts 用 (Generation Time, ID) 联合去重(防 iBMC SEL ID 5001 跳跃)
    5. 取 Top-K 条目
  4. 若 count == 0:升级 C 类走完整 RAG(兜底反转);仍无结果回复”未检索到相关历史”
  5. 默认模板化报告:逐条 [检索] ... 输出命中条目
  6. (可选)若 golden_cascade.retrieve_llm_enabled=true 且 LLM 可用, 拼检索结果为纯文本后走 LLM 摘要(max ~96 token),失败降级回原始检索输出

C 类(QUERY_REASONING)—— 推理型查询

分类原则

查询带有强意图疑问词,需要模型基于实时数据 + 检索 + 推理给出解释、建议或处置方案。 关键词覆盖:为什么 / 原因 / 分析 / 诊断;怎么办 / 如何 / 怎么 / 建议;严重 / 危险 / 紧急; watchdog / hang / 主机死机;PEF / 告警策略;证书 / certificate 等。

触发关键词示例

为什么 / 原因 / 分析 / 诊断 / 怎么办 / 如何 / 怎么 / 建议 / 严重 / 危险 / 紧急 / watchdog / hang / 主机死机 / PEF / 告警策略 / 证书 / 证书过期 / certificate

处理流程(典型 ~2-5s,完整 RAG + LLM 推理)

  1. guard_check_input() 输入安全过滤
  2. classify_query() 命中 C 类规则(或 B 类检索无结果升级),needs_llm=true,collect_flags=COL_ALL
  3. collect_execute(COL_ALL, ...) 采集阶段(~300ms):
    • 串行调用所需采集器:传感器 / SEL / FRU / NVMe / PEF / 健康 / 存储 / 审计 / journal / dmesg / system
    • 空数据时 Mock 注入 BMC 典型场景改善 C 类输入质量(388B vs 10B)
  4. 检索阶段(~50ms):query_rewrite_expand → 5 表 BM25 + 时间衰减 → Top-K
  5. context_build() 组装阶段(~1ms): [Few-shot System Prompt] + [实时采集 ~300 tokens] + [BM25 检索 ~300 tokens] + [用户查询]
  6. llm_generate(full_prompt, params, on_token_callback) 推理阶段(~2-5s 流式):
    • llama_tokenize → llama_decode(batch=512) → KV Cache 复用(System Prompt slot)
    • 循环 llama_sample → token 流式回调输出(含 GBNF Grammar 约束 + 工具调用 + SIGALRM 超时保护)
  7. filter_template_artifacts() 过滤 Chat Template 残留标签
  8. guard_check_output() 输出安全过滤:拦截 40+ 条 iBMC 危险命令关键字
  9. retrieve_ingest() 后台把本次新数据写入 FTS5((timestamp, id) 联合去重)

C 类旁路(带*号表示按需触发):

  • 关联分析:实时采集 + 检索结果命中 16 条关联规则(cpu_overheat_throttle / psu_redundancy_lost / dimm_ecc_correctable / cert_expiring 等),首命中即用,挂载对应 Playbook
  • Playbook 触发:按关联结果挂载 PB-001~016,给出排查步骤与强制 y 动作
  • 工具调用(若开启):LLM 输出 JSON 工具调用 → tool.c 解析 → action.c 执行 → 二次确认
  • 关联法复读 + 复检:处置后回到采集阶段对比传感器前后变化

详细流程图与状态机见 docs/diagnosis-loop.md。

文档索引

  • docs/architecture.md - 总体架构
  • docs/technical-report-final.md - 完整技术报告(v1.0.0)
  • docs/pr-list.md - 合并 PR 清单
  • docs/module-collect.md - 采集层设计
  • docs/module-retrieve.md - 检索引擎
  • docs/topic-bm25-time-decay-expansion.md - BM25/时间衰减/术语展开专题详解
  • docs/module-llm.md - LLM 推理
  • docs/module-fault-diagnosis.md - 故障诊断闭环
  • docs/config-schema.md - 配置 Schema
  • docs/diagnosis-loop.md - 端到端诊断闭环
  • docs/playbook-catalog.md - 16 PB 完整定义
  • docs/integration-testing-guide.md - 集成测试指南
  • docs/quickstart.md - 5 分钟上手(v1.0.0 新增)
  • docs/deployment.md - ARM 板部署说明(v1.0.0 新增)
  • docs/presentation/slides.md - 答辩 PPT 源稿(Marp)
  • demo/ - 演示脚本目录

许可证

Apache 2.0(与 openUBMC 项目一致)

关于
27.1 MB
邀请码
    Gitlink(确实开源)
  • 加入我们
  • 官网邮箱:gitlink@ccf.org.cn
  • QQ群
  • QQ群
  • 公众号
  • 公众号

版权所有:中国计算机学会技术支持:开源发展技术委员会
京ICP备13000930号-9 京公网安备 11010802047560号