LLM 应用开发实战:用 LangChain 搭建一个懂你家规的私人助手

在这里插入图片描述

一、前言:为什么需要"家规助手"?

想象一下这个场景:

晚上 11 点,你问 AI:“我现在能点外卖吗?”
普通 AI 回答:“当然可以,外卖平台 24 小时营业。”
但你的"家规"是:晚上 10 点后不准吃夜宵,周末除外。

再比如:

孩子问:“我能玩多久游戏?”
普通 AI:“建议每天不超过 1 小时。”
但你们家的规矩是:工作日 30 分钟,周末 1 小时,考试周完全禁止。

传统 LLM 的问题:它只有"通用知识",不懂你的个性化规则

这篇文章将教你用 LangChain + 向量数据库 + Prompt 工程,搭建一个"懂你家规"的私人助手。它能:

  • 📋 记住你家几十条家规(作息时间、饮食禁忌、电子产品使用规则…)
  • 💬 用自然语言回答家庭成员的问题
  • 🧠 理解规则之间的优先级(比如"特殊情况"覆盖"一般规则")
  • 🔒 本地运行,隐私数据不上云

二、技术架构总览

┌─────────────────┐
│ 用户提问 │ “今晚我能吃火锅吗?”
└────────┬────────┘

┌─────────────────┐
│ 意图识别+路由 │ LangChain Router
│ (判断涉及哪类家规)│
└────────┬────────┘

┌─────────────────┐
│ 向量检索 (RAG) │ ChromaDB + 家规Embedding
│ (召回相关家规) │
└────────┬────────┘

┌─────────────────┐
│ Prompt 组装 │ 系统提示词 + 家规上下文 + 用户问题
└────────┬────────┘

┌─────────────────┐
│ LLM 推理 │ DeepSeek/Qwen/ChatGPT
│ (生成回答) │
└────────┬────────┘

┌─────────────────┐
│ 规则校验层 │ 二次校验,确保不违反硬规则
└─────────────────┘

技术栈

  • LangChain:LLM 应用框架,负责链式调用和 RAG
  • ChromaDB:本地向量数据库,存储家规 Embedding
  • Ollama:本地运行大模型(DeepSeek-R1 / Qwen2.5)
  • Python 3.10+:开发语言

三、环境搭建(10 分钟搞定)

3.1 安装依赖

# 创建虚拟环境
conda create -n home-assistant python=3.10
conda activate home-assistant

# 安装核心依赖
pip install langchain langchain-community langchain-ollama chromadb sentence-transformers

# 安装 Ollama(Mac/Linux)
curl -fsSL https://ollama.com/install.sh | sh

# 拉取本地模型(推荐 Qwen2.5 7B,中文效果好且快)
ollama pull qwen2.5:7b

# 如果需要更强的推理能力,可以拉 DeepSeek-R1(稍慢)
# ollama pull deepseek-r1:7b

3.2 项目结构

home-rule-assistant/
├── config/
│   └── rules.yaml          # 家规配置文件
├── data/
│   └── chroma_db/          # 向量数据库持久化目录
├── src/
│   ├── __init__.py
│   ├── rule_loader.py      # 家规加载器
│   ├── vector_store.py     # 向量数据库操作
│   ├── prompt_builder.py   # Prompt 构建
│   └── assistant.py        # 主助手类
├── main.py                 # 交互入口
└── requirements.txt

四、核心实现:四步走

4.1 第一步:定义家规(YAML 配置)

家规不是简单的文本,需要结构化,让 AI 理解"规则类型"、“优先级"和"适用条件”。

config/rules.yaml

family_rules:
  - id: "diet_001"
    category: "饮食"
    priority: 1  # 数字越小优先级越高
    rule: "工作日晚上 10 点后不准点外卖或吃夜宵"
    exceptions:
      - "加班超过晚上 9 点,允许简单加餐"
      - "周末和节假日不受此限制"
    tags: ["饮食", "作息", "工作日"]

  - id: "diet_002"
    category: "饮食"
    priority: 2
    rule: "每周最多吃 2 次火锅或烧烤"
    exceptions:
      - "家庭聚餐日(每月第一个周六)不计入"
    tags: ["饮食", "火锅", "烧烤", "健康"]

  - id: "screen_001"
    category: "电子产品"
    priority: 1
    rule: "工作日每天游戏时间不超过 30 分钟"
    exceptions:
      - "完成作业后可以使用"
      - "周末每天不超过 1 小时"
    tags: ["游戏", "屏幕时间", "工作日"]

  - id: "screen_002"
    category: "电子产品"
    priority: 1
    rule: "考试周(期末考试前两周)完全禁止游戏"
    exceptions: []
    tags: ["游戏", "考试", "禁止"]

  - id: "sleep_001"
    category: "作息"
    priority: 1
    rule: "晚上 11 点前必须上床睡觉"
    exceptions:
      - "有未完成的紧急工作,可延长至 12 点"
      - "周五周六晚上可延长至 12 点"
    tags: ["作息", "睡眠", "健康"]

  - id: "guest_001"
    category: "待客"
    priority: 3
    rule: "朋友来家里做客,晚上 10 点前必须离开"
    exceptions:
      - "提前报备且父母同意的过夜聚会除外"
    tags: ["待客", "时间", "社交"]

  - id: "pet_001"
    category: "宠物"
    priority: 2
    rule: "遛狗必须牵绳,且随身携带垃圾袋"
    exceptions: []
    tags: ["宠物", "狗", "外出"]

  - id: "finance_001"
    category: "财务"
    priority: 2
    rule: "单笔超过 500 元的消费必须家庭讨论"
    exceptions:
      - "生活必需品(食物、日用品)除外"
      - "医疗费用除外"
    tags: ["消费", "财务", "大额支出"]

设计要点

  • priority:1 是硬规则(必须遵守),2 是软规则(建议遵守),3 是参考规则
  • exceptions:规则的例外情况,这是 AI 最容易搞错的地方,需要明确写出
  • tags:用于向量检索的关键词

4.2 第二步:家规加载与向量化

src/rule_loader.py

import yaml
from typing import List, Dict
from dataclasses import dataclass

@dataclass
class FamilyRule:
    id: str
    category: str
    priority: int
    rule: str
    exceptions: List[str]
    tags: List[str]
    
    def to_text(self) -> str:
        """转换为用于 Embedding 的文本"""
        text = f"规则[{self.id}]: {self.rule}。分类:{self.category}。优先级:{'高' if self.priority == 1 else '中' if self.priority == 2 else '低'}。"
        if self.exceptions:
            text += f"例外情况:{';'.join(self.exceptions)}。"
        return text

class RuleLoader:
    def __init__(self, config_path: str = "config/rules.yaml"):
        self.config_path = config_path
    
    def load_rules(self) -> List[FamilyRule]:
        with open(self.config_path, 'r', encoding='utf-8') as f:
            data = yaml.safe_load(f)
        
        rules = []
        for item in data.get('family_rules', []):
            rules.append(FamilyRule(
                id=item['id'],
                category=item['category'],
                priority=item['priority'],
                rule=item['rule'],
                exceptions=item.get('exceptions', []),
                tags=item.get('tags', [])
            ))
        return rules

src/vector_store.py

from typing import List
import chromadb
from chromadb.utils import embedding_functions
from langchain_ollama import OllamaEmbeddings
from src.rule_loader import FamilyRule

class RuleVectorStore:
    def __init__(self, persist_dir: str = "data/chroma_db"):
        # 使用本地 Embedding 模型(nomic-embed-text 速度快)
        self.embedding_func = embedding_functions.SentenceTransformerEmbeddingFunction(
            model_name="BAAI/bge-large-zh-v1.5"  # 中文效果好的 Embedding 模型
        )
        
        self.client = chromadb.PersistentClient(path=persist_dir)
        self.collection = self.client.get_or_create_collection(
            name="family_rules",
            embedding_function=self.embedding_func,
            metadata={"hnsw:space": "cosine"}
        )
    
    def add_rules(self, rules: List[FamilyRule]):
        """批量添加家规到向量库"""
        texts = [rule.to_text() for rule in rules]
        ids = [rule.id for rule in rules]
        metadatas = [{
            "category": rule.category,
            "priority": rule.priority,
            "tags": ",".join(rule.tags)
        } for rule in rules]
        
        self.collection.add(
            documents=texts,
            ids=ids,
            metadatas=metadatas
        )
        print(f"成功录入 {len(rules)} 条家规到向量数据库")
    
    def search(self, query: str, n_results: int = 3) -> List[dict]:
        """根据用户问题检索相关家规"""
        results = self.collection.query(
            query_texts=[query],
            n_results=n_results,
            where={"priority": {"$lte": 2}}  # 优先检索高优先级规则
        )
        
        rules = []
        for i in range(len(results['ids'][0])):
            rules.append({
                'id': results['ids'][0][i],
                'rule': results['documents'][0][i],
                'distance': results['distances'][0][i],
                'metadata': results['metadatas'][0][i]
            })
        return rules
    
    def clear(self):
        """清空数据库"""
        self.client.delete_collection("family_rules")
        self.collection = self.client.get_or_create_collection(
            name="family_rules",
            embedding_function=self.embedding_func
        )

4.3 第三步:Prompt 工程(最关键)

src/prompt_builder.py

from typing import List, Dict
from datetime import datetime

class PromptBuilder:
    def __init__(self):
        self.system_template = """你是一个严格但友善的"家规助手"。你的任务是根据以下家规,回答家庭成员的问题。

【核心原则】
1. 优先遵守 priority=1 的硬规则,除非用户明确说明符合例外条件
2. 回答要简洁直接,先说结论(能/不能/建议),再解释原因
3. 如果不确定,保守回答"建议先问问爸妈"
4. 语气要像家人一样自然,不要太机械

【当前时间】
{current_time}
今天是 {weekday}。

【检索到的相关家规】
{context}

【历史对话】
{history}

用户问题:{question}

请根据家规和当前时间,给出明确回答:"""
    
    def build(self, question: str, rules: List[Dict], history: str = "") -> str:
        # 格式化家规上下文
        context_parts = []
        for rule in rules:
            priority_str = "【硬规则】" if rule['metadata']['priority'] == 1 else "【建议】"
            context_parts.append(f"{priority_str} {rule['rule']}")
        
        context = "\n".join(context_parts) if context_parts else "未检索到直接相关家规,请基于通用家庭礼仪回答。"
        
        # 获取当前时间信息
        now = datetime.now()
        weekdays = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]
        
        return self.system_template.format(
            current_time=now.strftime("%Y-%m-%d %H:%M"),
            weekday=weekdays[now.weekday()],
            context=context,
            history=history if history else "无",
            question=question
        )

Prompt 设计要点

  • 时间感知:让 AI 知道现在是周几、几点,才能判断"工作日/周末"等条件
  • 优先级标注:用【硬规则】【建议】明确区分,防止 AI 把建议当禁令
  • 保守策略:明确告诉 AI"不确定就问爸妈",避免 AI 擅自做主

4.4 第四步:主助手类(串联一切)

src/assistant.py

from typing import List, Dict, Optional
from langchain_ollama import ChatOllama
from langchain_core.messages import HumanMessage, SystemMessage, AIMessage
from src.vector_store import RuleVectorStore
from src.prompt_builder import PromptBuilder
from src.rule_loader import RuleLoader

class HomeRuleAssistant:
    def __init__(self, model_name: str = "qwen2.5:7b"):
        # 初始化本地 LLM
        self.llm = ChatOllama(
            model=model_name,
            temperature=0.3,  # 低温度,让回答更确定
            num_ctx=4096      # 上下文窗口
        )
        
        self.vector_store = RuleVectorStore()
        self.prompt_builder = PromptBuilder()
        self.conversation_history: List[Dict] = []
        self.max_history = 5  # 保留最近 5 轮对话
    
    def initialize_rules(self, config_path: str = "config/rules.yaml"):
        """首次运行:加载家规到向量库"""
        loader = RuleLoader(config_path)
        rules = loader.load_rules()
        self.vector_store.clear()
        self.vector_store.add_rules(rules)
        print(f"家规初始化完成,共 {len(rules)} 条")
    
    def ask(self, question: str) -> str:
        """回答问题的主入口"""
        # 1. 向量检索相关家规
        relevant_rules = self.vector_store.search(question, n_results=3)
        
        # 2. 格式化历史对话
        history_text = self._format_history()
        
        # 3. 构建 Prompt
        prompt = self.prompt_builder.build(
            question=question,
            rules=relevant_rules,
            history=history_text
        )
        
        # 4. 调用 LLM
        messages = [
            SystemMessage(content="你是一个熟悉家规的家庭助手。"),
            HumanMessage(content=prompt)
        ]
        
        response = self.llm.invoke(messages)
        answer = response.content
        
        # 5. 记录对话历史
        self._add_to_history(question, answer)
        
        # 6. 返回带引用的回答
        if relevant_rules:
            rule_refs = "\n".join([f"📋 引用家规:{r['id']} ({r['metadata']['category']})" 
                                  for r in relevant_rules[:2]])
            answer += f"\n\n---\n{rule_refs}"
        
        return answer
    
    def _format_history(self) -> str:
        if not self.conversation_history:
            return ""
        parts = []
        for turn in self.conversation_history[-self.max_history:]:
            parts.append(f"用户:{turn['question']}")
            parts.append(f"助手:{turn['answer'][:100]}...")  # 截断避免过长
        return "\n".join(parts)
    
    def _add_to_history(self, question: str, answer: str):
        self.conversation_history.append({
            "question": question,
            "answer": answer,
            "timestamp": __import__('datetime').datetime.now().isoformat()
        })
        if len(self.conversation_history) > self.max_history * 2:
            self.conversation_history = self.conversation_history[-self.max_history:]
    
    def clear_history(self):
        self.conversation_history = []

五、交互入口与运行

main.py

import sys
from src.assistant import HomeRuleAssistant

def main():
    assistant = HomeRuleAssistant(model_name="qwen2.5:7b")
    
    print("🏠 家规助手初始化中...")
    assistant.initialize_rules()
    print("✅ 初始化完成!输入 'quit' 退出,输入 'clear' 清空历史\n")
    
    while True:
        try:
            question = input("👤 你问:").strip()
            if not question:
                continue
            if question.lower() == 'quit':
                print("👋 再见!记得遵守家规哦~")
                break
            if question.lower() == 'clear':
                assistant.clear_history()
                print("🧹 对话历史已清空")
                continue
            
            print("\n🤖 助手:", end="", flush=True)
            answer = assistant.ask(question)
            print(answer)
            print()
            
        except KeyboardInterrupt:
            print("\n👋 再见!")
            break
        except Exception as e:
            print(f"❌ 出错了:{e}")

if __name__ == "__main__":
    main()

运行效果

$ python main.py

🏠 家规助手初始化中...
成功录入 8 条家规到向量数据库
✅ 初始化完成!输入 'quit' 退出,输入 'clear' 清空历史

👤 你问:今晚我能吃火锅吗?

🤖 助手:❌ 不能。今天是周四(工作日),根据家规每周最多吃 2 次火锅,且没有提到今天有例外情况。

不过如果你确实很想吃,建议等到周末,那时不受限制,而且周末每天游戏时间也可以延长到 1 小时哦~

---
📋 引用家规:diet_002 (饮食)
📋 引用家规:screen_001 (电子产品)

👤 你问:我同学今晚想来家里住,可以吗?

🤖 助手:⚠️ 需要提前报备。根据家规,朋友晚上 10 点前必须离开,除非提前报备且父母同意的过夜聚会。

建议你:
1. 先问问爸妈是否同意
2. 如果同意,记得让同学明天按时离开

---
📋 引用家规:guest_001 (待客)

👤 你问:我作业做完了,能玩会儿游戏吗?

🤖 助手:✅ 可以。今天是周四,虽然工作日游戏时间通常不超过 30 分钟,但家规明确说明"完成作业后可以使用"。

建议定个闹钟,控制在 30 分钟内,这样不会影响 11 点睡觉的作息规则~

---
📋 引用家规:screen_001 (电子产品)
📋 引用家规:sleep_001 (作息)

六、进阶优化:让助手更智能

6.1 规则冲突检测

家规之间可能有冲突,比如"每天学习 2 小时"和"周末可以出去玩"。我们需要一个冲突检测层:

class RuleConflictChecker:
    def __init__(self):
        self.conflict_patterns = [
            ("作息", "电子产品"),  # 睡觉时间和屏幕时间可能冲突
            ("饮食", "健康"),      # 火锅和健康饮食可能冲突
        ]
    
    def check(self, rules: List[FamilyRule]) -> List[str]:
        warnings = []
        for i, r1 in enumerate(rules):
            for r2 in rules[i+1:]:
                if r1.category != r2.category:
                    # 检查是否有时间冲突
                    if self._has_time_conflict(r1, r2):
                        warnings.append(f"⚠️ 规则冲突:{r1.id}{r2.id} 可能存在时间冲突")
        return warnings
    
    def _has_time_conflict(self, r1: FamilyRule, r2: FamilyRule) -> bool:
        # 简化版:检查是否都包含时间关键词
        time_keywords = ["点", "小时", "晚上", "早上", "周末", "工作日"]
        r1_has = any(k in r1.rule for k in time_keywords)
        r2_has = any(k in r2.rule for k in time_keywords)
        return r1_has and r2_has

6.2 自然语言录入家规

不用写 YAML,直接说话添加家规:

def add_rule_by_text(self, natural_text: str):
    """用自然语言添加家规,AI 自动解析结构"""
    parse_prompt = f"""
    请将以下家规解析为结构化格式,输出 JSON:
    规则:{natural_text}
    
    要求包含:id(自动生成)、category(分类)、priority(1-3)、rule(规则正文)、exceptions(例外,数组)、tags(标签,数组)
    """
    
    response = self.llm.invoke([HumanMessage(content=parse_prompt)])
    # 解析 JSON 并添加到向量库...
    print("✅ 新规则已添加")

使用示例:

👤 你问:添加规则:下雨天不用遛狗,但雨停后必须补遛

🤖 助手:✅ 已添加新规则:
- 分类:宠物
- 优先级:2(建议)
- 规则:下雨天不用遛狗
- 例外:雨停后必须补遛

6.3 多模态扩展(摄像头识别)

结合摄像头,自动识别场景并提醒:

# 伪代码:识别到深夜还在电脑前
if camera.detect("person_at_computer") and time.now() > "23:00":
    assistant.ask("现在几点了?我还在电脑前,符合家规吗?")
    # AI 回答:❌ 不符合作息规则,建议立即休息

七、部署方案

7.1 本地部署(推荐)

  • 适合注重隐私的家庭
  • 需要一台配置较好的电脑(16G 内存 + 6G 显存)
  • 使用 Ollama 运行 7B 模型,响应速度约 2-3 秒

7.2 低成本云部署

  • 使用阿里云/腾讯云的 Serverless + 第三方 LLM API(DeepSeek/Qwen)
  • 向量库用阿里云 Lindorm 或腾讯云 VectorDB
  • 成本约每月 50-100 元(家庭轻度使用)

7.3 智能家居集成

  • 接入 Home Assistant,用小爱音箱/天猫精灵触发
  • 语音提问:“小爱同学,问家规助手我今天能玩游戏吗?”

八、总结与思考

这个项目的价值

  1. RAG 实战:不是简单调用 API,而是完整的检索-生成-校验流程
  2. Prompt 工程:时间感知、优先级判断、保守策略,都是生产级技巧
  3. 本地化:数据完全私有,适合家庭场景

可以改进的方向

  • LangGraph 实现更复杂的多轮对话状态机
  • 接入 日历 API,自动识别"考试周""家庭聚餐日"等特殊日期
  • 增加 家庭投票机制,规则变更需要多人确认

九、完整代码与资源

# 克隆项目(假设你已上传到 GitHub)
git clone https://github.com/你的用户名/home-rule-assistant.git
cd home-rule-assistant

# 安装依赖
pip install -r requirements.txt

# 首次运行(录入家规)
python main.py

requirements.txt

langchain>=0.1.0
langchain-community>=0.0.20
langchain-ollama>=0.0.1
chromadb>=0.4.0
sentence-transformers>=2.2.0
pyyaml>=6.0

csdn如何挂超链接:https://www.ipdatacloud.com/?utm-source=kol&utm-keyword=?4648

互动话题

  1. 你家有哪些"奇葩但合理"的家规?欢迎在评论区分享,我可以帮你写成 YAML 配置 😄
  2. 你觉得 AI 管家未来会普及吗?是助手还是"电子爸妈"?

如果这篇文章对你有帮助,欢迎 点赞、收藏、转发!你的支持是我继续写实战教程的动力。


---


Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐