清晨推开窗,迎面扑来的是透骨的清冽。草叶尖上凝结着薄薄的一层白霜,在晨光里闪烁着微光。翻开日历,今天正是霜降,也是秋天的最后一个节气。每当这个时候,江南的空气里便多了一层湿冷的寒意,厨房里砂锅煨汤的香气,还有书架上泛黄的旧书,总能给人带来最踏实的慰藉。
我们平时搭建的个人 RAG(检索增强生成)系统,大多处于“被动响应”的被动状态——只有当我们敲击键盘提出问题时,它才会从向量库里检索出答案。然而,在真实的生活情境中,我们常常希望身边的数字伙伴能像一位心有灵犀的老友,在节气流转、气温骤降的清晨,主动从我们历年记录的笔记、食谱和散文里,翻出那些被岁月尘封的暖意。今天,我们就来为个人生活 RAG 助手装上一根“节气神经”,让它能够感知季节冷暖,主动为我们呈上定制的温补食谱与治愈篇章。
一、从被动问答到“情境触发式”检索
传统的问答链路,通常是基于用户输入的 Prompt 计算 Embedding 向量,然后在知识库中执行余弦相似度检索。这种模式忽略了一个至关重要的维度:环境上下文(Contextual Awareness)。
一个懂生活的个人助手,应当感知到以下三种外部信号:
- 天文与农历节气信号:通过轻量农历算法判断今日是否适逢霜降、立冬等关键节气点。
- 本地环境气象信号:获取室外实时气温与体感温度,当气温跌破预设阈值(例如 12 摄氏度)时唤醒保暖上下文。
- 历年同一时期的记忆召回:检索历年 10 月下旬至 11 月上旬我们亲自记录的饮食心境与日记片段。
我们将这三项信号组装为一个隐式检索查询(Implicit Search Vector),在早晨定时任务触发时,静默向本地知识库索取匹配度最高的记忆切片。
二、感知季节:轻量节气与天气特征提取器
无需引入繁重的第三方大模型全家桶,几行轻巧的 Python 代码就能让系统感知节气与温度:
import datetime from typing import Dict, Any # 二十四节气简易计算或节气字典对照 SOLAR_TERMS_2026 = { "10-23": "霜降", "11-07": "立冬", "11-22": "小雪" } def get_seasonal_context(current_temp: float) -> Dict[str, Any]: """生成今日季节情境元数据""" today_str = datetime.date.today().strftime("%m-%d") solar_term = SOLAR_TERMS_2026.get(today_str, None) # 判定是否属于深秋霜寒期 is_chilly = current_temp <= 14.0 context_keywords = [] if solar_term: context_keywords.extend([solar_term, "节气食疗", "温润祛燥"]) if is_chilly: context_keywords.extend(["热汤暖胃", "生姜红枣", "深秋散文", "老白茶"]) return { "solar_term": solar_term, "temperature": current_temp, "is_chilly": is_chilly, "intent_query": " ".join(context_keywords) }这段代码为检索阶段输出了高质量的情境关键词。如果今天是 10 月 23 日且气温只有 9 度,生成的检索意图就是"霜降 节气食疗 温润祛燥 热汤暖胃 生姜红枣 深秋散文 老白茶"。
三、情境混合召回与记忆拼装
拿到情境查询串后,我们利用之前搭建的本地嵌入模型(如bge-small-zh-v1.5)与 SQLite 知识库进行混合检索。
这里特别设计了一个“生活双轨召回”机制:
- 轨道一:温养食谱库。限定标签为
category:recipe,寻找食材中包含羊肉、白萝卜、生姜、梨汤或山药的私人食谱笔记。 - 轨道二:往昔深秋心境。限定标签为
category:journal,提取往年深秋自己手写的随笔,看看去年的今天自己喝了什么茶、读了哪本书。
import sqlite3 from typing import List, Dict def retrieve_autumn_memories(intent_query: str, db_path: str = "notes.db") -> List[Dict[str, str]]: """从本地知识库检索温养食谱与往年随笔""" # 模拟向量检索与元数据过滤结合 with sqlite3.connect(db_path) as conn: cursor = conn.cursor() # 优先抽取生活食谱与温润手账 query = """ SELECT title, content_markdown, category FROM personal_notes WHERE category IN ('recipe', 'journal') AND ( content_markdown LIKE '%霜降%' OR content_markdown LIKE '%暖汤%' OR content_markdown LIKE '%老白茶%' OR content_markdown LIKE '%雪梨%' ) ORDER BY RANDOM() LIMIT 3; """ cursor.execute(query) rows = cursor.fetchall() results = [] for r in rows: results.append({ "title": r[0], "content": r[1][:240], # 截取核心摘要 "category": r[2] }) return results四、用温润的口吻生成晨间手账推送
召回了往昔的记忆片段之后,我们把这些切片连同今日的气温与节气,注入到本地 Ollama 驱动的模型中。通过精心设计的系统提示词,让模型以极其安静温和的生活家语调,为我们整理出一份早安信札:
import json import urllib.request SYSTEM_PROMPT = """你是一位陪伴在侧的生活密友,说话语气柔和、内敛、带有书卷气。 请结合提供的节气、气温以及我往年记录的食谱和日记,为我写一段清晨问候。 内容包含: 1. 一句关于今日节气与气温的轻声提醒; 2. 推荐一道适合今日烹煮的私藏热汤或茶饮(来自我的食谱笔记); 3. 引用一句我往年在深秋写下的随笔,唤醒旧日时光。 注意:文字必须恬淡自如,不要使用任何夸张、生硬或公文腔调。""" def generate_morning_greeting(seasonal_info: Dict[str, Any], memories: List[Dict[str, str]]) -> str: user_payload = { "today_context": f"今日节气:{seasonal_info['solar_term'] or '深秋'},室外气温:{seasonal_info['temperature']}℃", "my_recalled_notes": memories } req_data = { "model": "qwen2.5:7b", "messages": [ {"role": "system", "content": SYSTEM_PROMPT}, {"role": "user", "content": json.dumps(user_payload, ensure_ascii=False)} ], "stream": False, "options": {"temperature": 0.65} } req = urllib.request.Request( "http://127.0.0.1:11434/api/chat", data=json.dumps(req_data).encode("utf-8"), headers={"Content-Type": "application/json"} ) with urllib.request.urlopen(req) as resp: res = json.loads(resp.read().decode("utf-8")) return res["message"]["content"]五、晨光初晓时的温柔回响
当这套脚本在清晨七点随系统定时任务悄然执行时,我的手机屏幕上亮起了一条纯净的通知:
“推开窗,檐角已染微白。今日霜降,室外气温骤降至 9℃,记得添一件厚开衫。
翻看前年秋天的手账,你曾记下一道‘白萝卜排骨陈皮汤’,用小火慢煨两个小时,辛凉下气,正宜今日祛除秋燥。
去年今日,你在阳台写道:‘一炉茶沸,满室生春。’炉上的老茶已备好,愿你今天过得平静从容。”
看着这段字句,你不会觉得面对的是一台冷冰冰的计算机器。那些存储在本地磁盘上的向量和文本,因为节气的契合而重新焕发了体温。技术不应该只是用来提高工作效率的催促绳索,当它被用来照料我们的日常起居、守护琐碎记忆时,便成为了连接我们与四季轮回最温柔的纽带。