InterestWeaver — 迷茫期兴趣碎片整合与深耕定位工具一个用 Python 把“乱七八糟的兴趣”编织成“长期深耕方向”的轻量级工具一、实际应用场景描述场景工作三年的前端工程师阿杰的“兴趣碎片”困境阿杰26岁前端工程师。工作日写 React周末却像个“兴趣拾荒者”- 周一地铁上刷到一篇《城市声音地图》觉得“用音频记录城市变迁”很有意思截图保存。- 周三午休看到介绍“生物荧光蛋白”的视频惊叹于自然的精妙发了个“哇”的朋友圈。- 周五晚上逛独立书店翻到一本《字体设计中的情绪表达》拍了封面想“以后学学设计”。- 周日早晨醒来突然想“能不能做个帮助流浪猫匹配领养家庭的小程序”打开 Figma 画了半个草图然后……没了下文。一个月后他看着手机相册里的截图、朋友圈的“哇”、备忘录里的半截草图感到深深的迷茫“我对什么都感兴趣但又好像对什么都不能坚持。我是不是太浮躁了我到底适合深耕什么”这种感觉像手里抓了一把拼图碎片——每一片都很美但拼不起来。他尝试过“专注一个”只学前端正则表达式结果两周就厌烦了也尝试过“都学一点”结果什么都没留下。InterestWeaver 要解决的不是帮他“筛选兴趣”而是帮他“看见连接”。工具的核心假设是你那些看似随机的兴趣碎片底层藏着一根共同的线。找到这根线你就找到了愿意深耕十年的方向。二、引入痛点痛点 表现 后果 InterestWeaver 的对策兴趣碎片化 今天想学这个明天想试那个 无法形成复利样样通样样松 碎片记录强制结构化记录兴趣含情绪/能量值连接不可见 觉得兴趣之间毫无关系 自我否定“我太善变了” 图谱构建自动构建兴趣关联网络可视化隐藏连接情绪被忽略 只记“学了什么”不记“感觉如何” 选错方向选了理性认可但无热情的方向 情绪标注记录能量值/-和心流体验缺乏沉淀 想法只在朋友圈/备忘录里 无法回溯无法分析 统一归档所有碎片存入单一可信源深耕焦虑 “我必须现在确定一辈子的事业” 决策瘫痪不敢行动 主题涌现从碎片中自然浮现“候选深耕主题”伪兴趣干扰 把“消费内容”当成“产生兴趣” 误判真实热情所在 行动追踪区分“看了/想了”和“做了/创造了”复盘无力 想复盘但不知从何入手 重复犯同样的“三分钟热度”错误 模式识别自动识别“反复出现的兴趣主题”三、核心逻辑讲解InterestWeaver 的核心哲学是迷茫不是因为没有方向而是因为方向太多且它们之间的连接是隐形的。核心概念兴趣碎片 (Interest Fragment)我们定义一个兴趣碎片包含以下维度{content: 字符串记录具体想法,source: 来源如微博/书店/聊天,tags: [标签列表, 如设计/生物/城市],emotion: 情绪状态好奇/兴奋/平静/厌倦,energy_delta: 5/-3, 记录这个想法带给你的能量变化,action_taken: bool, 是否采取了微小行动查资料/画草图,timestamp: 记录时间}数据流与核心算法日常记录 (Log Fragment)↓【碎片沉淀】→ fragments.json↓【主题聚类】核心算法├── 基于 Tags 的共现分析如#设计 #城市 频繁同时出现├── 基于 Energy Delta 的加权高能量碎片权重更高├── 基于 Action Taken 的筛选有行动的碎片更真实└── 基于时间间隔的衰减太久远的兴趣权重降低↓【图谱构建】├── 节点兴趣主题从 tags 聚合而来├── 边主题间的关联强度共现次数 × 平均能量└── 核心节点连接度最高、能量最强的主题↓【深耕候选生成】├── 候选主题 核心节点 ∩ 高能量 ∩ 有行动├── 生成“主题画像”包含相关碎片、能量趋势、行动记录└── 输出 Top 3 深耕候选↓【周期性复盘】├── 回顾过去 N 天的碎片├── 检查主题演化趋势└── 调整深耕方向或确认当前方向关键算法主题涌现与深耕候选评分主题强度计算公式Topic_Strength (Cooccurrence_Frequency × 0.3) # 出现频率(Avg_Energy_Delta × 0.4) # 情感能量最重要(Action_Ratio × 0.2) # 行动意愿(Recency_Score × 0.1) # 时间新鲜度为什么能量权重最高0.4因为深耕需要的是“内在驱动力”而不是“理性认为应该”。一个你理性觉得有用但每次想到都能量下降的主题是无法支撑十年深耕的。深耕候选筛选逻辑1. 选取Topic_Strength 排名前 5 的主题2. 过滤掉Action_Ratio 0.3 的主题光想不做的不算3. 过滤掉Avg_Energy_Delta 3 的主题能量不足的不算4. 剩下的最多 3 个作为“深耕候选”输出四、代码模块化讲解项目共 6 个核心模块约 1300 行 Python 代码零第三方依赖。模块一FragmentRecorder — 碎片记录器职责日常记录兴趣碎片是工具的数据入口。class FragmentRecorder:记录迷茫期的兴趣碎片EMOTION_STATES {curious: 好奇想去了解,excited: 兴奋能量爆棚,peaceful: 平静觉得美好,confused: 困惑想不明白,bored: 无聊提不起劲}def record_fragment(self,content: str,source: str unknown,tags: List[str] None,emotion: str curious,energy_delta: int 0, # -5 到 5action_taken: bool False,notes: str ) - str:记录一个兴趣碎片。这是最重要的日常操作。energy_delta: 5 表示这个想法让你充满能量-5 表示消耗能量。action_taken: True 表示你为此做了一点微小的事搜了一下/画了个草图。fragment_id fFRG-{uuid.uuid4().hex[:8]}fragment {id: fragment_id,timestamp: datetime.now().isoformat(),content: content,source: source,tags: [tag.lower().strip() for tag in (tags or [])],emotion: emotion,energy_delta: max(-5, min(5, energy_delta)),action_taken: action_taken,notes: notes,cluster_id: None, # 后续聚类时填充is_seed: False # 是否是深耕的种子候选主题的核心碎片}self.fragments[fragment_id] fragmentself._save_fragments()return fragment_id设计要点-energy_delta 是核心字段后续所有分析都基于此-action_taken 区分“消费者”和“创造者”——真正的兴趣会驱使人行动-cluster_id 预留给后续的自动聚类算法模块二ThemeClusterer — 主题聚类器职责从碎片中自动识别潜在的兴趣主题。class ThemeClusterer:从碎片中聚类出潜在的兴趣主题def cluster_themes(self, days_window: int 90) - Dict:核心聚类算法无监督基于规则和统计1. 筛选最近 N 天的碎片2. 统计 Tag 共现矩阵如 #设计 和 #城市 一起出现多少次3. 计算每个 Tag 的聚合能量值4. 识别“核心 Tag”出现频率高且能量高5. 将核心 Tag 及其相关碎片打包为一个 Themecutoff_date datetime.now() - timedelta(daysdays_window)recent_fragments [f for f in self.recorder.fragments.values()if datetime.fromisoformat(f[timestamp]) cutoff_date]# 构建 Tag 共现矩阵tag_cooccurrence defaultdict(lambda: defaultdict(int))tag_energy defaultdict(list)tag_action_count defaultdict(int)tag_fragments defaultdict(list)for frag in recent_fragments:tags frag[tags]energy frag[energy_delta]for tag in tags:tag_energy[tag].append(energy)tag_fragments[tag].append(frag[id])if frag[action_taken]:tag_action_count[tag] 1# 记录共现for i in range(len(tags)):for j in range(i 1, len(tags)):tag_cooccurrence[tags[i]][tags[j]] 1tag_cooccurrence[tags[j]][tags[i]] 1# 生成主题themes {}processed_tags set()theme_counter 0# 按能量总和排序 Tagsorted_tags sorted(tag_energy.items(),keylambda x: sum(x[1]),reverseTrue)for tag, energies in sorted_tags:if tag in processed_tags:continuetheme_id fTHM-{theme_counter:03d}theme_counter 1# 找出与此 Tag 强相关的其他 Tag共现次数多related_tags []for other_tag, count in tag_cooccurrence[tag].items():if count 2 and other_tag not in processed_tags: # 至少共现2次related_tags.append(other_tag)# 计算主题强度avg_energy sum(energies) / len(energies) if energies else 0action_ratio tag_action_count[tag] / len(tag_fragments[tag]) if tag_fragments[tag] else 0strength (len(tag_fragments[tag]) * 0.3 avg_energy * 0.4 action_ratio * 0.2 0.1) # 基础分themes[theme_id] {theme_name: f主题{tag}及其相关领域,core_tag: tag,related_tags: related_tags,fragment_ids: tag_fragments[tag],fragment_count: len(tag_fragments[tag]),avg_energy: round(avg_energy, 2),action_ratio: round(action_ratio, 2),strength: round(strength, 2),is_candidate: False # 待后续筛选}processed_tags.add(tag)processed_tags.update(related_tags)self.themes themesself._save_themes()return themes设计要点- 这是一个基于启发式规则的聚类算法没有用复杂的 ML 库目的是透明可控-strength 公式是工具的核心智慧——它量化了“什么是好的兴趣主题”- 主题以core_tag 为中心包含related_tags体现了兴趣的关联性模块三DeepDiveIdentifier — 深耕定位器职责从聚类主题中筛选出最适合长期深耕的方向。class DeepDiveIdentifier:识别值得长期深耕的兴趣主题def identify_candidates(self, top_n: int 3) - List[Dict]:筛选深耕候选主题1. 必须有足够的碎片支撑fragment_count 32. 必须有正向的平均能量avg_energy 03. 必须有行动记录action_ratio 0.24. 按 strength 降序排序取 Top Ncandidates []for theme in self.clusterer.themes.values():if (theme[fragment_count] 3 andtheme[avg_energy] 0 andtheme[action_ratio] 0.2):# 标记为候选theme[is_candidate] Truecandidates.append(theme)# 按强度排序candidates.sort(keylambda x: x[strength], reverseTrue)# 更新原始主题数据for theme in candidates[:top_n]:theme_id Nonefor tid, t in self.clusterer.themes.items():if t[core_tag] theme[core_tag]:theme_id tidbreakif theme_id:self.clusterer.themes[theme_id][is_candidate] Trueself.clusterer._save_themes()return candidates[:top_n]def generate_deep_dive_profile(self, theme_id: str) - Dict:生成深耕主题的详细画像theme self.clusterer.themes.get(theme_id)if not theme:return {}# 获取相关碎片fragments [self.clusterer.recorder.fragments[fid]for fid in theme[fragment_ids]]# 分析能量趋势energy_trend []for frag in sorted(fragments, keylambda x: x[timestamp]):energy_trend.append({date: frag[timestamp][:10],energy: frag[energy_delta],content: frag[content][:30] ...})# 提取代表性碎片representative sorted(fragments,keylambda x: x[energy_delta],reverseTrue)[:3]profile {theme_name: theme[theme_name],core_tag: theme[core_tag],related_tags: theme[related_tags],strength: theme[strength],evidence_summary: {total_fragments: theme[fragment_count],avg_energy: theme[avg_energy],action_ratio: theme[action_ratio],time_span: f{energy_trend[0][date]} 至 {energy_trend[-1][date]}},energy_trend: energy_trend,representative_fragments: representative,deep_dive_suggestion: self._generate_suggestion(theme)}return profiledef _generate_suggestion(self, theme: Dict) - str:生成深耕建议if theme[action_ratio] 0.3:return 建议目前想法多于行动下一步可尝试围绕此主题做一个微小的创作如写一篇短文/画一张草图。elif theme[avg_energy] 3:return 建议兴趣存在但能量中等可尝试寻找该主题中更细分、更能激发热情的子领域。else:return f建议这是一个高潜力深耕方向可考虑制定一个为期3个月的探索计划围绕{theme[core_tag]}进行系统性学习或创作。设计要点-identify_candidates() 的筛选条件是工具价值观的体现——既要热爱又要行动-generate_deep_dive_profile() 生成的画像非常具体可以直接用作个人复盘或职业规划的依据- 建议是数据驱动的不是空泛的鸡汤模块四InterestGraphBuilder — 兴趣图谱构建器职责可视化兴趣主题之间的连接关系。class InterestGraphBuilder:构建兴趣主题之间的关联图谱def build_graph(self) - Dict:构建一个简单的图谱数据结构节点边可用于后续的可视化如生成 DOT 文件或用字符画展示。nodes []edges []# 节点主题for theme_id, theme in self.clusterer.themes.items():nodes.append({id: theme_id,label: theme[core_tag],size: theme[fragment_count],color: red if theme.get(is_candidate) else blue,strength: theme[strength]})# 边主题间的关联基于 Tag 共现theme_tags {tid: set([theme[core_tag]] theme[related_tags])for tid, theme in self.clusterer.themes.items()}theme_ids list(self.clusterer.themes.keys())for i in range(len(the_ids)):for j in range(i 1, len(the_ids)):tid1, tid2 theme_ids[i], theme_ids[j]tags1, tags2 theme_tags[tid1], theme_tags[tid2]intersection tags1.intersection(tags2)if intersection:edges.append({source: tid1,target: tid2,weight: len(intersection),shared_tags: list(intersection)})return {nodes: nodes,edges: edges,stats: {node_count: len(nodes),edge_count: len(edges),candidate_count: len([n for n in nodes if n[color] red])}}def export_graphviz(self, filename: str interest_graph.dot):导出为 Graphviz DOT 格式可用 dot 命令生成图片graph self.build_graph()lines [digraph InterestGraph {]lines.append( rankdirLR;)lines.append( node [shapecircle, stylefilled];)for node in graph[nodes]:color red if node[color] red else lightbluelines.append(f {node[id]} [label{node[label]}, fillcolor{color}, width{node[size]*0.3}];)for edge in graph[edges]:lines.append(f {edge[source]} - {edge[target]} [label{len(edge[shared_tags])}];)lines.append(})with open(filename, w, encodingutf-8) as f:f.write(\n.join(lines))设计要点- 图谱让“看不见的连接”变得可见——你可能发现“字体设计”和“生物荧光”通过“视觉表达”连接在一起-export_graphviz() 提供了专业的可视化选项虽然工具本身是终端应用模块五PeriodicReflector — 周期性复盘器职责定期回顾碎片记录调整方向防止迷失。class PeriodicReflector:定期进行兴趣复盘def reflect(self, period: str monthly) - Dict:执行复盘- monthly: 回顾过去30天- quarterly: 回顾过去90天days 30 if period monthly else 90cutoff_date datetime.now() - timedelta(daysdays)recent_fragments [f for f in self.recorder.fragments.values()if datetime.fromisoformat(f[timestamp]) cutoff_date]if not recent_fragments:return {status: empty, message: 近期无记录建议开始记录碎片。}# 统计total len(recent_fragments)avg_energy sum(f[energy_delta] for f in recent_fragments) / totalaction_count sum(1 for f in recent_fragments if f[action_taken])# 识别高频标签tag_counter Counter()for frag in recent_fragments:tag_counter.update(frag[tags])# 获取当前深耕候选candidates self.identifier.identify_candidates()reflection {period: period,start_date: cutoff_date.strftime(%Y-%m-%d),end_date: datetime.now().strftime(%Y-%m-%d),stats: {total_fragments: total,avg_energy: round(avg_energy, 2),action_rate: round(action_count / total, 2) if total 0 else 0,top_tags: tag_counter.most_common(5)},current_candidates: candidates,insights: self._generate_insights(recent_fragments, candidates),next_steps: self._suggest_next_steps(recent_fragments, candidates)}return reflectiondef _generate_insights(self, fragments: List[Dict], candidates: List[Dict]) - List[str]:insights []if not fragments:return [暂无数据无法生成洞察。]avg_energy sum(f[energy_delta] for f in fragments) / len(fragments)if avg_energy 2:insights.append(近期整体能量较高说明你接触到了许多真正感兴趣的事物。)elif avg_energy 0:insights.append(近期整体能量为负可能需要减少被动消费增加主动创造。)action_rate sum(1 for f in fragments if f[action_taken]) / len(fragments)if action_rate 0.2:insights.append(行动率较低想法很多但落地很少。尝试将一个小想法变为现实。)if candidates:insights.append(f当前识别出 {len(candidates)} 个深耕候选方向其中 {candidates[0][core_tag]} 强度最高。)return insightsdef _suggest_next_steps(self, fragments: List[Dict], candidates: List[Dict]) - List[str]:steps []if candidates:top_candidate candidates[0]steps.append(f围绕 {top_candidate[core_tag]} 主题本周尝试一个微小行动如阅读一篇深度文章。)steps.append(在下个月复盘时检查该主题的能量值和行动率是否有提升。)else:steps.append(继续记录碎片特别关注那些让你能量显著提升的想法。)steps.append(尝试对一个感兴趣的碎片采取微小行动如搜索、草图观察能量变化。)return steps设计要点- 复盘不是批判而是觉察——觉察能量流向、行动模式-insights 和next_steps 都是温和的建议尊重用户的自主性模块六ReportExporter — 报告导出器职责将所有分析结果导出为可读的 Markdown 报告。class ReportExporter:导出复盘报告和深耕画像def export_full_report(self, period: str monthly) - str:导出包含复盘、图谱、候选主题的完整报告reflection self.reflector.reflect(period)graph self.graph_builder.build_graph()candidates reflection[current_candidates]md_lines [f# 兴趣整合与深耕定位报告 ({reflection[start_date]} ~ {reflection[end_date]}),,## 近期概览,f- **碎片总数**: {reflection[stats][total_fragments]},f- **平均能量**: {reflection[stats][avg_energy]}/5.0,f- **行动率**: {reflection[stats][action_rate]*100:.1f}%,f- **高频标签**: {, .join([f{t[0]}({t[1]}) for t in reflection[stats][top_tags]])},,## 核心洞察,]for insight in reflection[insights]:md_lines.append(f- {insight})md_lines.extend([,## 深耕候选主题 (Top 3),---])if candidates:for i, cand in enumerate(candidates, 1):profile self.identifier.generate_deep_dive_profile(next(tid for tid, t in self.clusterer.themes.items() if t[core_tag] cand[core_tag]))md_lines.extend([f### {i}. {profile[theme_name]},f- **强度**: {profile[strength]}/5.0,f- **证据**: {profile[evidence_summary][total_fragments]}个碎片平均能量{profile[evidence_summary][avg_energy]},f- **代表碎片**: {profile[representative_fragments][0][content][:50]}...,f- **深耕建议**: {profile[deep_dive_suggestion]},])else:md_lines.append(暂未识别出明确的深耕候选主题建议继续积累碎片。)md_lines.extend([## ️ 兴趣图谱摘要,f- **主题节点**: {graph[stats][node_count]},f- **关联边**: {graph[stats][edge_count]},f- **候选主题数**: {graph[stats][candidate_count]},,## 下一步行动,])for step in reflection[next_steps]:md_lines.append(f- {step})md_lines.extend([,---,*本报告由 InterestWeaver 自动生成仅供参考。真正的方向需要你在行动中不断探索和调整。*])return \n.join(md_lines)五、README 文件# InterestWeaver — 迷茫期兴趣碎片整合与深耕定位工具## 项目简介InterestWeaver 是一个本地运行的 Python 工具旨在帮助处于职业或人生迷茫期的知识工作者系统性地记录、整理想法碎片识别隐藏的连接模式最终定位值得长期深耕的创新领域。它不是“兴趣测试”问卷也不是“职业规划”软件而是一个**思维编织器**——帮你把看似杂乱无章的兴趣线索编织成一张有意义的网。## 核心理念1. **碎片有价值**每一个微小的兴趣念头都是潜意识的信号。2. **连接即意义**单个碎片无意义碎片之间的连接才有价值。3. **能量导向**真正的深耕方向不是理性选择的而是能量指向的。4. **行动验证**想法的真实性需要用微小的行动来验证。5. **涌现优于设计**深耕方向不是“规划”出来的而是从数据中“涌现”出来的。## 快速开始### 1. 运行演示bashpython demo.py演示将模拟阿杰3个月的兴趣碎片记录并自动完成聚类、定位和报告生成。### 2. 基本用法pythonfrom main import InterestWeaver初始化iw InterestWeaver(data_dirdata)1. 记录一个兴趣碎片日常操作iw.record_fragment(content看到一篇关于城市声音地图的文章觉得用音频记录变迁很浪漫,source微信公众号,tags[城市, 声音, 记录, 艺术],emotionexcited,energy_delta4, # 能量满满action_takenFalse, # 暂时只是看了notes搜一下有没有相关的开源项目)2. 积累一段时间后进行聚类themes iw.cluster_themes(days_window90)print(f识别出 {len(themes)} 个潜在主题)3. 识别深耕候选candidates iw.identify_candidates(top_n3)for c in candidates:print(f候选主题: {c[core_tag]}, 强度: {c[strength]})4. 查看某个候选主题的详细画像if candidates:profile iw.get_deep_dive_profile(candidates[0][core_tag])print(f深耕建议: {profile[deep_dive_suggestion]})5. 生成月度复盘报告report iw.export_report(periodmonthly)with open(monthly_reflection.md, w, encodingutf-8) as f:f.write(report)## 核心模块- FragmentRecorder: 兴趣碎片记录器- Theme利用AI解决实际问题如果你觉得这个工具好用欢迎关注长安牧笛
编写程序记录人迷茫阶段的所有兴趣碎片,整合碎片信息,定位长期愿意深耕的创新领域。
InterestWeaver — 迷茫期兴趣碎片整合与深耕定位工具一个用 Python 把“乱七八糟的兴趣”编织成“长期深耕方向”的轻量级工具一、实际应用场景描述场景工作三年的前端工程师阿杰的“兴趣碎片”困境阿杰26岁前端工程师。工作日写 React周末却像个“兴趣拾荒者”- 周一地铁上刷到一篇《城市声音地图》觉得“用音频记录城市变迁”很有意思截图保存。- 周三午休看到介绍“生物荧光蛋白”的视频惊叹于自然的精妙发了个“哇”的朋友圈。- 周五晚上逛独立书店翻到一本《字体设计中的情绪表达》拍了封面想“以后学学设计”。- 周日早晨醒来突然想“能不能做个帮助流浪猫匹配领养家庭的小程序”打开 Figma 画了半个草图然后……没了下文。一个月后他看着手机相册里的截图、朋友圈的“哇”、备忘录里的半截草图感到深深的迷茫“我对什么都感兴趣但又好像对什么都不能坚持。我是不是太浮躁了我到底适合深耕什么”这种感觉像手里抓了一把拼图碎片——每一片都很美但拼不起来。他尝试过“专注一个”只学前端正则表达式结果两周就厌烦了也尝试过“都学一点”结果什么都没留下。InterestWeaver 要解决的不是帮他“筛选兴趣”而是帮他“看见连接”。工具的核心假设是你那些看似随机的兴趣碎片底层藏着一根共同的线。找到这根线你就找到了愿意深耕十年的方向。二、引入痛点痛点 表现 后果 InterestWeaver 的对策兴趣碎片化 今天想学这个明天想试那个 无法形成复利样样通样样松 碎片记录强制结构化记录兴趣含情绪/能量值连接不可见 觉得兴趣之间毫无关系 自我否定“我太善变了” 图谱构建自动构建兴趣关联网络可视化隐藏连接情绪被忽略 只记“学了什么”不记“感觉如何” 选错方向选了理性认可但无热情的方向 情绪标注记录能量值/-和心流体验缺乏沉淀 想法只在朋友圈/备忘录里 无法回溯无法分析 统一归档所有碎片存入单一可信源深耕焦虑 “我必须现在确定一辈子的事业” 决策瘫痪不敢行动 主题涌现从碎片中自然浮现“候选深耕主题”伪兴趣干扰 把“消费内容”当成“产生兴趣” 误判真实热情所在 行动追踪区分“看了/想了”和“做了/创造了”复盘无力 想复盘但不知从何入手 重复犯同样的“三分钟热度”错误 模式识别自动识别“反复出现的兴趣主题”三、核心逻辑讲解InterestWeaver 的核心哲学是迷茫不是因为没有方向而是因为方向太多且它们之间的连接是隐形的。核心概念兴趣碎片 (Interest Fragment)我们定义一个兴趣碎片包含以下维度{content: 字符串记录具体想法,source: 来源如微博/书店/聊天,tags: [标签列表, 如设计/生物/城市],emotion: 情绪状态好奇/兴奋/平静/厌倦,energy_delta: 5/-3, 记录这个想法带给你的能量变化,action_taken: bool, 是否采取了微小行动查资料/画草图,timestamp: 记录时间}数据流与核心算法日常记录 (Log Fragment)↓【碎片沉淀】→ fragments.json↓【主题聚类】核心算法├── 基于 Tags 的共现分析如#设计 #城市 频繁同时出现├── 基于 Energy Delta 的加权高能量碎片权重更高├── 基于 Action Taken 的筛选有行动的碎片更真实└── 基于时间间隔的衰减太久远的兴趣权重降低↓【图谱构建】├── 节点兴趣主题从 tags 聚合而来├── 边主题间的关联强度共现次数 × 平均能量└── 核心节点连接度最高、能量最强的主题↓【深耕候选生成】├── 候选主题 核心节点 ∩ 高能量 ∩ 有行动├── 生成“主题画像”包含相关碎片、能量趋势、行动记录└── 输出 Top 3 深耕候选↓【周期性复盘】├── 回顾过去 N 天的碎片├── 检查主题演化趋势└── 调整深耕方向或确认当前方向关键算法主题涌现与深耕候选评分主题强度计算公式Topic_Strength (Cooccurrence_Frequency × 0.3) # 出现频率(Avg_Energy_Delta × 0.4) # 情感能量最重要(Action_Ratio × 0.2) # 行动意愿(Recency_Score × 0.1) # 时间新鲜度为什么能量权重最高0.4因为深耕需要的是“内在驱动力”而不是“理性认为应该”。一个你理性觉得有用但每次想到都能量下降的主题是无法支撑十年深耕的。深耕候选筛选逻辑1. 选取Topic_Strength 排名前 5 的主题2. 过滤掉Action_Ratio 0.3 的主题光想不做的不算3. 过滤掉Avg_Energy_Delta 3 的主题能量不足的不算4. 剩下的最多 3 个作为“深耕候选”输出四、代码模块化讲解项目共 6 个核心模块约 1300 行 Python 代码零第三方依赖。模块一FragmentRecorder — 碎片记录器职责日常记录兴趣碎片是工具的数据入口。class FragmentRecorder:记录迷茫期的兴趣碎片EMOTION_STATES {curious: 好奇想去了解,excited: 兴奋能量爆棚,peaceful: 平静觉得美好,confused: 困惑想不明白,bored: 无聊提不起劲}def record_fragment(self,content: str,source: str unknown,tags: List[str] None,emotion: str curious,energy_delta: int 0, # -5 到 5action_taken: bool False,notes: str ) - str:记录一个兴趣碎片。这是最重要的日常操作。energy_delta: 5 表示这个想法让你充满能量-5 表示消耗能量。action_taken: True 表示你为此做了一点微小的事搜了一下/画了个草图。fragment_id fFRG-{uuid.uuid4().hex[:8]}fragment {id: fragment_id,timestamp: datetime.now().isoformat(),content: content,source: source,tags: [tag.lower().strip() for tag in (tags or [])],emotion: emotion,energy_delta: max(-5, min(5, energy_delta)),action_taken: action_taken,notes: notes,cluster_id: None, # 后续聚类时填充is_seed: False # 是否是深耕的种子候选主题的核心碎片}self.fragments[fragment_id] fragmentself._save_fragments()return fragment_id设计要点-energy_delta 是核心字段后续所有分析都基于此-action_taken 区分“消费者”和“创造者”——真正的兴趣会驱使人行动-cluster_id 预留给后续的自动聚类算法模块二ThemeClusterer — 主题聚类器职责从碎片中自动识别潜在的兴趣主题。class ThemeClusterer:从碎片中聚类出潜在的兴趣主题def cluster_themes(self, days_window: int 90) - Dict:核心聚类算法无监督基于规则和统计1. 筛选最近 N 天的碎片2. 统计 Tag 共现矩阵如 #设计 和 #城市 一起出现多少次3. 计算每个 Tag 的聚合能量值4. 识别“核心 Tag”出现频率高且能量高5. 将核心 Tag 及其相关碎片打包为一个 Themecutoff_date datetime.now() - timedelta(daysdays_window)recent_fragments [f for f in self.recorder.fragments.values()if datetime.fromisoformat(f[timestamp]) cutoff_date]# 构建 Tag 共现矩阵tag_cooccurrence defaultdict(lambda: defaultdict(int))tag_energy defaultdict(list)tag_action_count defaultdict(int)tag_fragments defaultdict(list)for frag in recent_fragments:tags frag[tags]energy frag[energy_delta]for tag in tags:tag_energy[tag].append(energy)tag_fragments[tag].append(frag[id])if frag[action_taken]:tag_action_count[tag] 1# 记录共现for i in range(len(tags)):for j in range(i 1, len(tags)):tag_cooccurrence[tags[i]][tags[j]] 1tag_cooccurrence[tags[j]][tags[i]] 1# 生成主题themes {}processed_tags set()theme_counter 0# 按能量总和排序 Tagsorted_tags sorted(tag_energy.items(),keylambda x: sum(x[1]),reverseTrue)for tag, energies in sorted_tags:if tag in processed_tags:continuetheme_id fTHM-{theme_counter:03d}theme_counter 1# 找出与此 Tag 强相关的其他 Tag共现次数多related_tags []for other_tag, count in tag_cooccurrence[tag].items():if count 2 and other_tag not in processed_tags: # 至少共现2次related_tags.append(other_tag)# 计算主题强度avg_energy sum(energies) / len(energies) if energies else 0action_ratio tag_action_count[tag] / len(tag_fragments[tag]) if tag_fragments[tag] else 0strength (len(tag_fragments[tag]) * 0.3 avg_energy * 0.4 action_ratio * 0.2 0.1) # 基础分themes[theme_id] {theme_name: f主题{tag}及其相关领域,core_tag: tag,related_tags: related_tags,fragment_ids: tag_fragments[tag],fragment_count: len(tag_fragments[tag]),avg_energy: round(avg_energy, 2),action_ratio: round(action_ratio, 2),strength: round(strength, 2),is_candidate: False # 待后续筛选}processed_tags.add(tag)processed_tags.update(related_tags)self.themes themesself._save_themes()return themes设计要点- 这是一个基于启发式规则的聚类算法没有用复杂的 ML 库目的是透明可控-strength 公式是工具的核心智慧——它量化了“什么是好的兴趣主题”- 主题以core_tag 为中心包含related_tags体现了兴趣的关联性模块三DeepDiveIdentifier — 深耕定位器职责从聚类主题中筛选出最适合长期深耕的方向。class DeepDiveIdentifier:识别值得长期深耕的兴趣主题def identify_candidates(self, top_n: int 3) - List[Dict]:筛选深耕候选主题1. 必须有足够的碎片支撑fragment_count 32. 必须有正向的平均能量avg_energy 03. 必须有行动记录action_ratio 0.24. 按 strength 降序排序取 Top Ncandidates []for theme in self.clusterer.themes.values():if (theme[fragment_count] 3 andtheme[avg_energy] 0 andtheme[action_ratio] 0.2):# 标记为候选theme[is_candidate] Truecandidates.append(theme)# 按强度排序candidates.sort(keylambda x: x[strength], reverseTrue)# 更新原始主题数据for theme in candidates[:top_n]:theme_id Nonefor tid, t in self.clusterer.themes.items():if t[core_tag] theme[core_tag]:theme_id tidbreakif theme_id:self.clusterer.themes[theme_id][is_candidate] Trueself.clusterer._save_themes()return candidates[:top_n]def generate_deep_dive_profile(self, theme_id: str) - Dict:生成深耕主题的详细画像theme self.clusterer.themes.get(theme_id)if not theme:return {}# 获取相关碎片fragments [self.clusterer.recorder.fragments[fid]for fid in theme[fragment_ids]]# 分析能量趋势energy_trend []for frag in sorted(fragments, keylambda x: x[timestamp]):energy_trend.append({date: frag[timestamp][:10],energy: frag[energy_delta],content: frag[content][:30] ...})# 提取代表性碎片representative sorted(fragments,keylambda x: x[energy_delta],reverseTrue)[:3]profile {theme_name: theme[theme_name],core_tag: theme[core_tag],related_tags: theme[related_tags],strength: theme[strength],evidence_summary: {total_fragments: theme[fragment_count],avg_energy: theme[avg_energy],action_ratio: theme[action_ratio],time_span: f{energy_trend[0][date]} 至 {energy_trend[-1][date]}},energy_trend: energy_trend,representative_fragments: representative,deep_dive_suggestion: self._generate_suggestion(theme)}return profiledef _generate_suggestion(self, theme: Dict) - str:生成深耕建议if theme[action_ratio] 0.3:return 建议目前想法多于行动下一步可尝试围绕此主题做一个微小的创作如写一篇短文/画一张草图。elif theme[avg_energy] 3:return 建议兴趣存在但能量中等可尝试寻找该主题中更细分、更能激发热情的子领域。else:return f建议这是一个高潜力深耕方向可考虑制定一个为期3个月的探索计划围绕{theme[core_tag]}进行系统性学习或创作。设计要点-identify_candidates() 的筛选条件是工具价值观的体现——既要热爱又要行动-generate_deep_dive_profile() 生成的画像非常具体可以直接用作个人复盘或职业规划的依据- 建议是数据驱动的不是空泛的鸡汤模块四InterestGraphBuilder — 兴趣图谱构建器职责可视化兴趣主题之间的连接关系。class InterestGraphBuilder:构建兴趣主题之间的关联图谱def build_graph(self) - Dict:构建一个简单的图谱数据结构节点边可用于后续的可视化如生成 DOT 文件或用字符画展示。nodes []edges []# 节点主题for theme_id, theme in self.clusterer.themes.items():nodes.append({id: theme_id,label: theme[core_tag],size: theme[fragment_count],color: red if theme.get(is_candidate) else blue,strength: theme[strength]})# 边主题间的关联基于 Tag 共现theme_tags {tid: set([theme[core_tag]] theme[related_tags])for tid, theme in self.clusterer.themes.items()}theme_ids list(self.clusterer.themes.keys())for i in range(len(the_ids)):for j in range(i 1, len(the_ids)):tid1, tid2 theme_ids[i], theme_ids[j]tags1, tags2 theme_tags[tid1], theme_tags[tid2]intersection tags1.intersection(tags2)if intersection:edges.append({source: tid1,target: tid2,weight: len(intersection),shared_tags: list(intersection)})return {nodes: nodes,edges: edges,stats: {node_count: len(nodes),edge_count: len(edges),candidate_count: len([n for n in nodes if n[color] red])}}def export_graphviz(self, filename: str interest_graph.dot):导出为 Graphviz DOT 格式可用 dot 命令生成图片graph self.build_graph()lines [digraph InterestGraph {]lines.append( rankdirLR;)lines.append( node [shapecircle, stylefilled];)for node in graph[nodes]:color red if node[color] red else lightbluelines.append(f {node[id]} [label{node[label]}, fillcolor{color}, width{node[size]*0.3}];)for edge in graph[edges]:lines.append(f {edge[source]} - {edge[target]} [label{len(edge[shared_tags])}];)lines.append(})with open(filename, w, encodingutf-8) as f:f.write(\n.join(lines))设计要点- 图谱让“看不见的连接”变得可见——你可能发现“字体设计”和“生物荧光”通过“视觉表达”连接在一起-export_graphviz() 提供了专业的可视化选项虽然工具本身是终端应用模块五PeriodicReflector — 周期性复盘器职责定期回顾碎片记录调整方向防止迷失。class PeriodicReflector:定期进行兴趣复盘def reflect(self, period: str monthly) - Dict:执行复盘- monthly: 回顾过去30天- quarterly: 回顾过去90天days 30 if period monthly else 90cutoff_date datetime.now() - timedelta(daysdays)recent_fragments [f for f in self.recorder.fragments.values()if datetime.fromisoformat(f[timestamp]) cutoff_date]if not recent_fragments:return {status: empty, message: 近期无记录建议开始记录碎片。}# 统计total len(recent_fragments)avg_energy sum(f[energy_delta] for f in recent_fragments) / totalaction_count sum(1 for f in recent_fragments if f[action_taken])# 识别高频标签tag_counter Counter()for frag in recent_fragments:tag_counter.update(frag[tags])# 获取当前深耕候选candidates self.identifier.identify_candidates()reflection {period: period,start_date: cutoff_date.strftime(%Y-%m-%d),end_date: datetime.now().strftime(%Y-%m-%d),stats: {total_fragments: total,avg_energy: round(avg_energy, 2),action_rate: round(action_count / total, 2) if total 0 else 0,top_tags: tag_counter.most_common(5)},current_candidates: candidates,insights: self._generate_insights(recent_fragments, candidates),next_steps: self._suggest_next_steps(recent_fragments, candidates)}return reflectiondef _generate_insights(self, fragments: List[Dict], candidates: List[Dict]) - List[str]:insights []if not fragments:return [暂无数据无法生成洞察。]avg_energy sum(f[energy_delta] for f in fragments) / len(fragments)if avg_energy 2:insights.append(近期整体能量较高说明你接触到了许多真正感兴趣的事物。)elif avg_energy 0:insights.append(近期整体能量为负可能需要减少被动消费增加主动创造。)action_rate sum(1 for f in fragments if f[action_taken]) / len(fragments)if action_rate 0.2:insights.append(行动率较低想法很多但落地很少。尝试将一个小想法变为现实。)if candidates:insights.append(f当前识别出 {len(candidates)} 个深耕候选方向其中 {candidates[0][core_tag]} 强度最高。)return insightsdef _suggest_next_steps(self, fragments: List[Dict], candidates: List[Dict]) - List[str]:steps []if candidates:top_candidate candidates[0]steps.append(f围绕 {top_candidate[core_tag]} 主题本周尝试一个微小行动如阅读一篇深度文章。)steps.append(在下个月复盘时检查该主题的能量值和行动率是否有提升。)else:steps.append(继续记录碎片特别关注那些让你能量显著提升的想法。)steps.append(尝试对一个感兴趣的碎片采取微小行动如搜索、草图观察能量变化。)return steps设计要点- 复盘不是批判而是觉察——觉察能量流向、行动模式-insights 和next_steps 都是温和的建议尊重用户的自主性模块六ReportExporter — 报告导出器职责将所有分析结果导出为可读的 Markdown 报告。class ReportExporter:导出复盘报告和深耕画像def export_full_report(self, period: str monthly) - str:导出包含复盘、图谱、候选主题的完整报告reflection self.reflector.reflect(period)graph self.graph_builder.build_graph()candidates reflection[current_candidates]md_lines [f# 兴趣整合与深耕定位报告 ({reflection[start_date]} ~ {reflection[end_date]}),,## 近期概览,f- **碎片总数**: {reflection[stats][total_fragments]},f- **平均能量**: {reflection[stats][avg_energy]}/5.0,f- **行动率**: {reflection[stats][action_rate]*100:.1f}%,f- **高频标签**: {, .join([f{t[0]}({t[1]}) for t in reflection[stats][top_tags]])},,## 核心洞察,]for insight in reflection[insights]:md_lines.append(f- {insight})md_lines.extend([,## 深耕候选主题 (Top 3),---])if candidates:for i, cand in enumerate(candidates, 1):profile self.identifier.generate_deep_dive_profile(next(tid for tid, t in self.clusterer.themes.items() if t[core_tag] cand[core_tag]))md_lines.extend([f### {i}. {profile[theme_name]},f- **强度**: {profile[strength]}/5.0,f- **证据**: {profile[evidence_summary][total_fragments]}个碎片平均能量{profile[evidence_summary][avg_energy]},f- **代表碎片**: {profile[representative_fragments][0][content][:50]}...,f- **深耕建议**: {profile[deep_dive_suggestion]},])else:md_lines.append(暂未识别出明确的深耕候选主题建议继续积累碎片。)md_lines.extend([## ️ 兴趣图谱摘要,f- **主题节点**: {graph[stats][node_count]},f- **关联边**: {graph[stats][edge_count]},f- **候选主题数**: {graph[stats][candidate_count]},,## 下一步行动,])for step in reflection[next_steps]:md_lines.append(f- {step})md_lines.extend([,---,*本报告由 InterestWeaver 自动生成仅供参考。真正的方向需要你在行动中不断探索和调整。*])return \n.join(md_lines)五、README 文件# InterestWeaver — 迷茫期兴趣碎片整合与深耕定位工具## 项目简介InterestWeaver 是一个本地运行的 Python 工具旨在帮助处于职业或人生迷茫期的知识工作者系统性地记录、整理想法碎片识别隐藏的连接模式最终定位值得长期深耕的创新领域。它不是“兴趣测试”问卷也不是“职业规划”软件而是一个**思维编织器**——帮你把看似杂乱无章的兴趣线索编织成一张有意义的网。## 核心理念1. **碎片有价值**每一个微小的兴趣念头都是潜意识的信号。2. **连接即意义**单个碎片无意义碎片之间的连接才有价值。3. **能量导向**真正的深耕方向不是理性选择的而是能量指向的。4. **行动验证**想法的真实性需要用微小的行动来验证。5. **涌现优于设计**深耕方向不是“规划”出来的而是从数据中“涌现”出来的。## 快速开始### 1. 运行演示bashpython demo.py演示将模拟阿杰3个月的兴趣碎片记录并自动完成聚类、定位和报告生成。### 2. 基本用法pythonfrom main import InterestWeaver初始化iw InterestWeaver(data_dirdata)1. 记录一个兴趣碎片日常操作iw.record_fragment(content看到一篇关于城市声音地图的文章觉得用音频记录变迁很浪漫,source微信公众号,tags[城市, 声音, 记录, 艺术],emotionexcited,energy_delta4, # 能量满满action_takenFalse, # 暂时只是看了notes搜一下有没有相关的开源项目)2. 积累一段时间后进行聚类themes iw.cluster_themes(days_window90)print(f识别出 {len(themes)} 个潜在主题)3. 识别深耕候选candidates iw.identify_candidates(top_n3)for c in candidates:print(f候选主题: {c[core_tag]}, 强度: {c[strength]})4. 查看某个候选主题的详细画像if candidates:profile iw.get_deep_dive_profile(candidates[0][core_tag])print(f深耕建议: {profile[deep_dive_suggestion]})5. 生成月度复盘报告report iw.export_report(periodmonthly)with open(monthly_reflection.md, w, encodingutf-8) as f:f.write(report)## 核心模块- FragmentRecorder: 兴趣碎片记录器- Theme利用AI解决实际问题如果你觉得这个工具好用欢迎关注长安牧笛