用本地大模型解析智能家居语音指令:构建一个离线可用的文本控制助手

发布于:2025-05-26 ⋅ 阅读:(54) ⋅ 点赞:(0)

🧠 背景介绍

随着智能家居设备的普及,用户希望用一句话完成对家电的控制。虽然很多系统依赖云端大模型服务,但我们也可以通过本地部署实现一个完全离线运行的智能控制助手

本文将带你一步步实现一个基于本地大模型的智能家居控制系统,它具备以下能力:

  • ✅ 接收文字输入
  • ✅ 意图识别 + RAG 检索物模型
  • ✅ 构造 Few-Shot 提示词引导输出
  • ✅ 使用本地大模型生成结构化 JSON 控制指令
  • ✅ JSON 校验确保输出合法
  • ✅ 完全无需联网,可在 PC 或嵌入式设备上运行

📚 所需知识准备

技术 描述
大模型 支持 GGUF 格式的本地模型(如 Qwen2.5-0.5B.Q2_K.gguf)
意图识别 基于关键词匹配的轻量级规则模块
RAG 检索 不使用向量数据库,而是基于规则匹配设备类型
JSON Schema 校验 确保输出符合标准物模型定义
Java 实现核心逻辑,适用于桌面 App 或 Electron 内部调用

🛠️ 整体架构设计(简化版)—

在这里插入图片描述

🧱 核心模块详解


1️⃣ 物模型知识库(device_knowledge.json

[
  {
    "device_type": "light",
    "description": "智能灯泡",
    "schema": {
      "properties": {
        "power": {"type": "switch", "values": ["on", "off"]},
        "brightness": {"type": "int", "min": 0, "max": 100}
      }
    }
  },
  {
    "device_type": "ac",
    "description": "空调",
    "schema": {
      "properties": {
        "power": {"type": "switch", "values": ["on", "off"]},
        "temperature": {"type": "int", "min": 16, "max": 30},
        "mode": {"type": "enum", "values": ["cool", "heat", "fan", "dry"]}
    }
  }
]

这个文件定义了所有设备的标准控制属性,供 RAG 检索使用。


2️⃣ 意图识别模块(IntentRecognizer.java)

import java.util.*;

public class IntentRecognizer {

    private static final Map<String, String> INTENT_KEYWORDS = new HashMap<>();

    static {
        INTENT_KEYWORDS.put("light", "灯 亮度 灯光");
        INTENT_KEYWORDS.put("ac", "空调 温度 制冷 制热 冷气 热风");
        INTENT_KEYWORDS.put("curtain", "窗帘 开启 打开 关闭 拉上 拉开");
        INTENT_KEYWORDS.put("fan", "风扇 风速 摆头 摇头");
        INTENT_KEYWORDS.put("tv", "电视 音量 静音 影音");
        INTENT_KEYWORDS.put("lock", "门锁 上锁 解锁 密码");
        INTENT_KEYWORDS.put("humidifier", "加湿器 湿度 自动模式");
    }

    public static String recognizeIntent(String query) {
        for (Map.Entry<String, String> entry : INTENT_KEYWORDS.entrySet()) {
            String intent = entry.getKey();
            String keywords = entry.getValue();

            for (String word : keywords.split(" ")) {
                if (query.contains(word)) {
                    return intent;
                }
            }
        }
        return "other";
    }
}

通过关键词判断用户想控制哪种设备。


3️⃣ 设备模型加载模块(DeviceModelLoader.java)

import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
import java.util.*;

public class DeviceModelLoader {
    private static final List<DeviceModel> deviceModels = new ArrayList<>();

    static {
        try {
            ObjectMapper mapper = new ObjectMapper();
            File file = new File("src/main/resources/device_knowledge.json");
            DeviceModel[] models = mapper.readValue(file, DeviceModel[].class);
            deviceModels.addAll(Arrays.asList(models));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static List<DeviceModel> getAllDeviceModels() {
        return deviceModels;
    }

    public static Map<String, Object> getSchemaByType(String deviceType) {
        for (DeviceModel model : deviceModels) {
            if (model.getDeviceType().equalsIgnoreCase(deviceType)) {
                return model.getSchema();
            }
        }
        return null;
    }
}

4️⃣ RAG 检索模块(RagRetriever.java)

import java.util.Map;

public class RagRetriever {

    public static String retrieveContext(String query) {
        String intent = IntentRecognizer.recognizeIntent(query);
        Map<String, Object> schema = DeviceModelLoader.getSchemaByType(intent);

        if (schema == null) {
            return "";
        }

        return String.format(
                "设备类型:%s\n" +
                "描述:智能设备\n" +
                "标准物模型定义:\n%s\n",
                intent,
                schema.toString()
        );
    }
}

根据识别到的设备类型,返回对应的物模型定义。


5️⃣ Few-Shot 提示词模板(PromptBuilder.java)

public class PromptBuilder {

    public static String buildPrompt(String context, String query) {
        return String.format("""
你是一个智能家居控制助手,请根据以下设备的标准物模型定义,生成符合要求的 JSON 控制命令。

请严格按照以下规则执行:
1. 输出必须是合法的 JSON 格式
2. 字段名必须为英文,值必须严格符合物模型定义
3. 不要添加任何解释、多余字段或中文内容
4. 如果无法判断意图,请返回空对象 {}

以下是设备的标准物模型定义:

%s

以下是几个示例输入和输出供你参考:

示例 1:
用户指令:“打开客厅的灯”
输出:
{
  "device_type": "light",
  "property": "power",
  "value": "on"
}

示例 2:
用户指令:“把温度设为26度”
输出:
{
  "device_type": "ac",
  "property": "temperature",
  "value": 26
}

现在,请根据以下用户指令生成对应的 JSON 控制命令:

用户指令:“%s”
""",
                context, query);
    }
}

构造包含 Few-Shot 示例的提示词,引导模型输出规范格式。


6️⃣ 调用本地大模型生成结构化指令(LlmClient.java)

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;

public class LlmClient {

    // Ollama API 地址(本地部署)
    private static final String OLLAMA_API_URL = "http://localhost:11434/api/generate";

    public static String generateCommand(String prompt) throws IOException {
        String requestBody = String.format(
                "{\"model\": \"qwen2.5:0.5b\", \"prompt\": \"%s\", \"stream\": false}",
                escapeJson(prompt)
        );

        HttpURLConnection connection = (HttpURLConnection) new URL(OLLAMA_API_URL).openConnection();
        connection.setRequestMethod("POST");
        connection.setRequestProperty("Content-Type", "application/json");
        connection.setDoOutput(true);

        try (OutputStream os = connection.getOutputStream()) {
            os.write(requestBody.getBytes());
            os.flush();
        }

        if (connection.getResponseCode() != 200) {
            throw new IOException("请求失败: HTTP " + connection.getResponseCode());
        }

        StringBuilder responseText = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
            String line;
            while ((line = reader.readLine()) != null) {
                responseText.append(line);
            }
        }

        // 提取 JSON 输出(简化处理)
        return extractJson(responseText.toString());
    }

    private static String escapeJson(String text) {
        return text.replace("\\", "\\\\")
                  .replace("\"", "\\\"")
                  .replace("\n", "\\n")
                  .replace("\r", "\\r");
    }

    private static String extractJson(String rawResponse) {
        // 实际应使用 JSON 解析库提取 response 字段
        return rawResponse.contains("response") ?
                rawResponse.split("\"response\":\"")[1].split("\"")[0] :
                "{}";
    }
}

使用 Ollama 的本地 API 接口调用本地大模型,生成结构化 JSON 指令。


7️⃣ JSON 校验工具类(JsonSchemaValidator.java)

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JsonSchemaValidator {

    public static String validate(String jsonStr) {
        try {
            ObjectMapper mapper = new ObjectMapper();
            JsonNode node = mapper.readTree(jsonStr);

            if (!node.has("device_type") || !node.has("property")) {
                return "{}";
            }

            return jsonStr;

        } catch (Exception ignored) {
            return "{}";
        }
    }
}

确保模型输出符合结构要求,防止非法参数。


8️⃣ 主程序入口(Main.java)

public class Main {
    public static void main(String[] args) throws Exception {
        String userInput = "把温度调高一点";

        // Step 1: 意图识别
        String intent = IntentRecognizer.recognizeIntent(userInput);
        System.out.println("识别到意图:" + intent);

        // Step 2: RAG 检索物模型
        String context = RagRetriever.retrieveContext(userInput);
        System.out.println("检索结果:\n" + context);

        // Step 3: 构造 Prompt
        String prompt = PromptBuilder.buildPrompt(context, userInput);
        System.out.println("构造的 Prompt:\n" + prompt);

        // Step 4: 调用本地大模型
        String llmOutput = LlmClient.generateCommand(prompt);
        System.out.println("模型输出:\n" + llmOutput);

        // Step 5: JSON 校验
        String validated = JsonSchemaValidator.validate(llmOutput);
        System.out.println("校验后输出:\n" + validated);
    }
}

🧪 示例流程演示

输入:

“把温度调高一点”

输出:

{
  "device_type": "ac",
  "property": "temperature",
  "value": 28
}

流程说明:

  1. 意图识别:识别为 ac(空调)
  2. RAG 检索:加载空调的标准物模型
  3. 构造 Prompt:Few-Shot 示例 + 用户指令
  4. 调用本地大模型:输出 JSON 控制指令
  5. JSON 校验:确保字段合法

📦 项目结构总结

smart-home-assistant-java/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   ├── Main.java
│   │   │   ├── IntentRecognizer.java
│   │   │   ├── DeviceModelLoader.java
│   │   │   ├── RagRetriever.java
│   │   │   ├── PromptBuilder.java
│   │   │   ├── LlmClient.java
│   │   │   └── JsonSchemaValidator.java
│   │   └── resources/
│   │       └── device_knowledge.json
│   └── build.gradle (可选)

💡 技术亮点总结

技术点 描述
✅ 本地运行 不依赖互联网,隐私更安全
✅ 小模型支持 如 Qwen2.5-0.5B.Q2_K.gguf,仅约 300MB
✅ 规则驱动 RAG 快速检索,不依赖 embedding 向量
✅ Few-Shot 提示词 提升模型输出准确性
✅ JSON 校验机制 防止非法输出,提升稳定性

🧩 可扩展方向

功能 描述
✅ 多轮对话支持 记录上下文,处理模糊指令
✅ MQTT 控制设备 下发 JSON 指令给设备
✅ Home Assistant 集成 直接控制真实设备
✅ 加入 TTS 文语转换 提供语音反馈
✅ Flutter/Electron 封装 打包成桌面/移动端应用

🔗 项目源码下载地址

🔗 点击下载完整 Java 工程 ZIP 包

包含:

  • 所有 Java 源代码
  • 示例 device_knowledge.json
  • 编译配置与运行说明

🧑‍💻 总结

通过本文你学会了如何构建一个完整的本地智能家居控制助手系统:

  • ✅ 从 JSON 文件中读取物模型
  • ✅ 使用关键词识别设备类型
  • ✅ 构建 Few-Shot 提示词
  • ✅ 调用本地大模型生成结构化 JSON 指令
  • ✅ 校验输出确保格式正确

这套系统可以用于:

  • 💻 本地 PC 应用
  • 🖥️ Electron 桌面助手
  • 📱 Android App(后续可扩展)

📬 后续计划(可以继续做的)

  • ✅ 把这个系统封装成 Web API(Spring Boot)
  • ✅ 加入 MQTT 控制接口
  • ✅ 支持多语言(英文、日文)
  • ✅ 部署到树莓派做边缘计算

📢 欢迎留言讨论

如果你有任何问题,或者希望我帮你:

  • ✅ 写一个 Python 版本
  • ✅ 把这个系统做成 Electron App
  • ✅ 提供预训练模型文件
  • ✅ 支持 MQTT 控制设备

欢迎随时告诉我 👇 我会一步步带你完成这个完整的智能家居控制系统!


✅ **关注我,获取更多 AI 与 IoT 结合的实战教程