当前位置: 首页 > article >正文

基于OpenClaw/QClaw与LLM的Reddit智能摘要系统构建实战

1. 项目概述与核心价值如果你和我一样每天泡在Reddit和各种技术社区里试图从海量的帖子、评论和新闻中淘出真正有价值的信息那你一定体会过那种“信息过载”的无力感。首页永远刷不完热帖里夹杂着大量水贴和重复讨论而真正能启发思路、解决实际问题的“干货”往往藏在某个不起眼的子版块或长篇讨论的回复里。手动筛选效率太低。用现成的RSS信息太杂且缺乏聚合与提炼。这正是我启动“Reddit Digest”这个个人项目的初衷打造一个自动化、智能化的信息消化工具它不只是简单的爬虫更是一个能理解内容、提炼重点、并按照我的兴趣偏好生成个性化摘要的“工作伙伴”。这个项目的核心我称之为“OpenClaw/QClaw”技术栈驱动下的Reddit信息处理流水线。它围绕几个关键词展开openclaw和qclaw代表了其底层的数据抓取与处理引擎reddit-scraper指明了其主要的数据来源而workbuddy则完美诠释了它的最终形态——一个能7x24小时为你工作的智能助手。它解决的问题非常具体为你节省每天至少一小时的“信息垃圾”筛选时间把浓缩后的、高相关性的技术动态、社区讨论精华和行业新闻准时推送到你面前。无论你是开发者、产品经理、技术爱好者还是任何需要从Reddit及类似社区获取前沿信息的从业者这个项目都能让你从被动的信息接收者转变为主动的信息管理者。2. 技术架构与核心组件解析一个稳定、高效且可维护的自动化摘要系统其背后的架构设计至关重要。我的“Reddit Digest”并非一个单一脚本而是一个由多个松耦合组件构成的微服务系统。这样设计的好处是显而易见的每个组件可以独立开发、测试和部署当某个环节比如Reddit API策略变更需要调整时不会牵一发而动全身。2.1 数据抓取层OpenClaw/QClaw引擎这是整个系统的“手”和“眼睛”。OpenClaw和QClaw是我对两类抓取策略的抽象命名它们共同构成了灵活的数据获取层。OpenClaw开放式抓取针对公开的、无需复杂交互的页面。对于Reddit这意味着使用其官方提供的JSON API端点。例如获取r/programming子版块的热门帖子可以直接请求https://www.reddit.com/r/programming/hot/.json。这种方式稳定、快速且符合Reddit的使用规范。我会为OpenClaw配置一系列这样的API模板并附带请求头如设置一个合理的User-Agent以模拟浏览器行为避免被简单的反爬机制拦截。QClaw队列式精准抓取这是针对需要深入挖掘内容的场景。例如当一个帖子被OpenClaw识别为高价值通过初始的分数、评论数等指标后QClaw会接手它的任务不仅仅是获取帖子正文还要深入抓取该帖子下的“最佳评论”或“深度讨论线程”。这里的关键在于“队列”和“精准”。系统会维护一个优先级队列QClaw从队列中取出任务针对单个帖子URL进行深度请求解析出完整的评论树。这个过程需要更复杂的HTML解析或对Reddit更多API的调用并且必须严格遵守访问频率限制因此“队列”机制保证了任务的有序和可控。注意API频率限制与礼貌爬取Reddit API对未认证请求和OAuth认证请求都有严格的频率限制。我的策略是对于OpenClaw的列表抓取使用较长的间隔如每分钟一次对于QClaw的详情抓取则在单个任务完成后主动休眠1-2秒。此外务必在User-Agent中清晰标识你的应用名称和联系方式这是一个负责任的开发者的基本素养。2.2 数据处理与存储层原始数据抓取回来后是未经加工的“矿石”。数据处理层的任务就是将其冶炼成“钢材”。内容清洗与标准化Reddit返回的JSON数据虽然结构清晰但包含了许多前端展示相关的元信息。我们需要提取核心字段帖子标题title、作者author、发布时间created_utc、分数score、评论数num_comments、正文文本selftext、链接url以及最重要的——所属子版块subreddit。对于评论则需要提取评论正文、作者、分数以及嵌套的回复结构。我会使用像pandas或直接操作Python字典/列表的方式将这些数据清洗并转换成一个结构化的字典或自定义的Post/Comment对象。向量化存储与索引为了让系统能“理解”内容并进行相似性检索文本的向量化是关键一步。我选用像sentence-transformers这样的库将帖子标题和正文转换为高维向量例如384维的向量。这些向量会存入专门的向量数据库例如ChromaDB或Qdrant。同时帖子的元数据标题、链接、时间等会存入一个关系型数据库如SQLite用于轻量级部署或PostgreSQL用于生产环境或文档数据库如MongoDB中。两者通过唯一的帖子ID进行关联。这样当我想查找所有关于“Python async”的讨论时既可以通过向量数据库进行语义搜索也可以通过关系数据库按子版块、时间进行过滤。2.3 摘要生成与推送层这是体现项目“智能”和“价值”的核心也是“WorkBuddy”得名的原因。摘要生成策略我尝试过多种方法最终形成一个混合策略。提取式摘要对于评论区的精华直接选取点赞数最高的前3-5条评论。这种方法简单有效能直接反映社区的共识。抽象式摘要对于较长的帖子正文或技术文章分享使用大语言模型LLMAPI如OpenAI GPT、Anthropic Claude或开源的Llama API进行总结。我会设计一个精心构造的提示词Prompt“请用简洁的段落总结以下Reddit帖子的核心观点和技术要点并指出其中提到的关键工具或库。保持中立不要添加个人评价。” 然后将帖子正文和热门评论的文本一起喂给模型。混合摘要将上述两者结合。先呈现LLM生成的段落式概要再附上“社区高亮评论”的引用块。这种格式信息密度最高既有提炼又有原汁原味的社区反馈。个性化过滤与推送不是所有r/programming的热帖我都关心。我建立了一个“兴趣配置文件”里面定义了关键词如“Kubernetes”“Rust”“PostgreSQL”、我关注的具体子版块列表、以及需要屏蔽的关键词如“求职”“meme”。在生成每日摘要前系统会用这个配置文件对抓取到的帖子进行过滤和排序。推送渠道我选择了最通用的方式电子邮件和Telegram Bot。电子邮件适合长篇摘要而Telegram Bot则能提供即时、交互式的提醒。推送内容会经过精美的Markdown格式化确保在各种客户端上都有良好的阅读体验。3. 系统搭建与核心环节实现理论说再多不如一行代码。下面我将拆解搭建这个系统的关键步骤和代码实现。我的技术栈选择是Python作为主力语言因为它拥有极其丰富的库来支持爬虫、数据处理和AI应用。3.1 环境准备与依赖安装首先创建一个干净的Python虚拟环境是良好实践的开始。# 创建项目目录并进入 mkdir reddit-digest cd reddit-digest # 创建虚拟环境这里使用venv python3 -m venv venv # 激活虚拟环境 # 在Linux/macOS上 source venv/bin/activate # 在Windows上 venv\Scripts\activate接下来初始化项目并安装核心依赖。我使用requirements.txt来管理依赖。# requirements.txt # 网络请求与爬虫 requests2.28.0 aiohttp3.8.0 # 用于异步抓取提升效率 beautifulsoup44.11.0 # 备用用于解析非JSON页面 # 数据处理 pandas1.5.0 numpy1.24.0 # 向量化与存储 sentence-transformers2.2.0 chromadb0.4.0 # 轻量级向量数据库 # 数据库以SQLite和MongoDB为例 pymongo4.0.0 # 如果选用MongoDB # 关系型数据库通常有标准库或如sqlalchemy # 调度与任务队列 apscheduler3.10.0 # 高级Python调度器 # 或者使用Celery Redis用于更复杂的分布式队列 # 推送通知 python-telegram-bot20.0 # Telegram Bot yagmail0.15.0 # 发送邮件的简易库 # 大语言模型接口以OpenAI为例 openai1.0.0使用pip安装pip install -r requirements.txt。3.2 OpenClaw/QClaw抓取器实现让我们实现一个基础但健壮的抓取模块。我将其设计为一个类便于管理配置和状态。# scraper/core.py import requests import time import logging from typing import Dict, List, Optional from dataclasses import dataclass import json logging.basicConfig(levellogging.INFO) logger logging.getLogger(__name__) dataclass class RedditPost: Reddit帖子数据类 id: str title: str author: str subreddit: str score: int num_comments: int url: str selftext: str created_utc: float permalink: str class RedditScraper: Reddit抓取器实现OpenClaw策略 def __init__(self, user_agent: str, rate_limit_delay: float 1.0): self.session requests.Session() self.session.headers.update({User-Agent: user_agent}) self.rate_limit_delay rate_limit_delay self.base_url https://www.reddit.com def fetch_hot_posts(self, subreddit: str, limit: int 25) - List[RedditPost]: 获取指定子版块的热门帖子OpenClaw url f{self.base_url}/r/{subreddit}/hot/.json?limit{limit} logger.info(fFetching hot posts from r/{subreddit}) try: response self.session.get(url, timeout10) response.raise_for_status() # 检查HTTP错误 data response.json() posts [] for child in data[data][children]: post_data child[data] post RedditPost( idpost_data[id], titlepost_data[title], authorpost_data[author], subredditpost_data[subreddit], scorepost_data[score], num_commentspost_data[num_comments], urlpost_data[url], selftextpost_data[selftext], created_utcpost_data[created_utc], permalinkf{self.base_url}{post_data[permalink]} ) posts.append(post) time.sleep(self.rate_limit_delay) # 遵守礼貌爬取间隔 return posts except requests.exceptions.RequestException as e: logger.error(fFailed to fetch from r/{subreddit}: {e}) return [] except (KeyError, json.JSONDecodeError) as e: logger.error(fFailed to parse response from r/{subreddit}: {e}) return [] def fetch_post_comments(self, post_permalink: str, depth: int 1) - List[Dict]: 获取指定帖子的评论QClaw策略的简化版 这是一个更复杂的操作需要解析评论树。 此处返回一个评论列表的简化示例。 # 实际实现中需要处理Reddit评论API的复杂嵌套结构 # 这里仅示意流程 url f{post_permalink}.json logger.info(fFetching comments for post: {post_permalink}) try: response self.session.get(url, timeout10) response.raise_for_status() data response.json() # data[1] 通常是评论数据结构非常嵌套 # 需要递归遍历 data[1][data][children] 来提取评论 # 此处省略具体解析代码... simplified_comments self._simplify_comment_tree(data, depth) time.sleep(self.rate_limit_delay * 2) # 详情页抓取间隔更长 return simplified_comments except Exception as e: logger.error(fFailed to fetch comments: {e}) return [] def _simplify_comment_tree(self, raw_data: Dict, max_depth: int) - List[Dict]: 递归简化评论树提取核心内容。这是一个复杂但关键的函数。 # 伪代码遍历raw_data提取评论body, author, score, 以及回复(replies) # 当深度超过max_depth时停止。 comments [] # ... 具体实现逻辑 return comments # 使用示例 if __name__ __main__: USER_AGENT RedditDigestBot/1.0 (by /u/YourRedditUsername) Contact: youremail.com scraper RedditScraper(user_agentUSER_AGENT, rate_limit_delay1.5) # OpenClaw: 抓取列表 programming_posts scraper.fetch_hot_posts(programming, limit10) for post in programming_posts[:3]: # 打印前三个 print(f- {post.title} (Score: {post.score}, Comments: {post.num_comments})) # QClaw: 选择一个帖子抓取评论 if programming_posts: sample_post programming_posts[0] comments scraper.fetch_post_comments(sample_post.permalink, depth2) print(f\nFetched {len(comments)} top-level comments for post: {sample_post.title})这个RedditScraper类封装了基本的抓取逻辑。fetch_hot_posts是典型的OpenClaw操作批量获取帖子列表。fetch_post_comments则代表了QClaw针对单个资源进行深度挖掘。在实际项目中QClaw部分会更复杂需要处理评论的嵌套结构和分页。3.3 向量化存储与兴趣匹配抓取到的帖子需要被理解和检索。以下是使用sentence-transformers和chromadb进行向量化存储和搜索的示例。# processor/vector_store.py from sentence_transformers import SentenceTransformer import chromadb from chromadb.config import Settings import uuid from typing import List import logging logger logging.getLogger(__name__) class VectorStoreManager: 管理文本向量化与向量数据库存储 def __init__(self, model_name: str all-MiniLM-L6-v2, persist_dir: str ./chroma_db): # 加载嵌入模型。all-MiniLM-L6-v2是一个轻量且效果不错的通用模型 logger.info(fLoading embedding model: {model_name}) self.model SentenceTransformer(model_name) # 初始化Chroma客户端设置持久化目录 self.client chromadb.Client(Settings( chroma_db_implduckdbparquet, persist_directorypersist_dir )) # 获取或创建集合类似于数据库中的表 self.collection self.client.get_or_create_collection(namereddit_posts) def generate_embedding(self, text: str): 为单条文本生成向量 # 如果文本过长可以截断或分段处理。这里做简单处理。 if not text or text.strip() : text [Empty] return self.model.encode(text).tolist() def store_post(self, post_id: str, title: str, content: str, metadata: dict): 存储一个帖子到向量数据库 # 结合标题和正文作为被检索的文本 combined_text f{title}. {content[:500]} # 限制长度避免过长 embedding self.generate_embedding(combined_text) # 准备元数据 doc_metadata { post_id: post_id, subreddit: metadata.get(subreddit, ), score: str(metadata.get(score, 0)), url: metadata.get(url, ), **metadata # 包含其他传入的元数据 } # 存储到ChromaDB self.collection.add( embeddings[embedding], documents[combined_text], # 存储的原始文本可用于展示 metadatas[doc_metadata], ids[post_id] # 使用帖子ID作为唯一标识 ) logger.info(fStored post {post_id} in vector database.) def search_similar(self, query: str, n_results: int 5, where_filter: dict None) - List[dict]: 根据查询文本搜索相似的帖子 :param where_filter: 可选的过滤条件如 {subreddit: programming} query_embedding self.generate_embedding(query) # 执行查询 results self.collection.query( query_embeddings[query_embedding], n_resultsn_results, wherewhere_filter # 例如只搜索某个子版块 ) # 整理返回结果 returned_posts [] if results[ids]: for i in range(len(results[ids][0])): post_info { id: results[ids][0][i], document: results[documents][0][i], metadata: results[metadatas][0][i], distance: results[distances][0][i] # 余弦距离越小越相似 } returned_posts.append(post_info) return returned_posts # 使用示例 if __name__ __main__: vs_manager VectorStoreManager() # 模拟存储一些帖子 sample_posts [ { id: abc123, title: How to optimize Python code for data science, content: Using vectorized operations with NumPy can greatly speed up your calculations..., metadata: {subreddit: Python, score: 256, url: https://reddit.com/...} }, { id: def456, title: Introduction to async programming in Rust, content: Tokio is a popular runtime for writing asynchronous Rust applications..., metadata: {subreddit: rust, score: 189, url: https://reddit.com/...} } ] for post in sample_posts: vs_manager.store_post( post_idpost[id], titlepost[title], contentpost[content], metadatapost[metadata] ) # 进行语义搜索 query ways to make Python run faster similar vs_manager.search_similar(query, n_results3) print(fPosts similar to {query}:) for res in similar: print(f - {res[metadata][title]} (r/{res[metadata][subreddit]}, score: {res[metadata][score]}))这个VectorStoreManager类负责将文本转换为向量并存入ChromaDB。search_similar方法允许我们进行语义搜索where参数还能让我们结合元数据如子版块进行过滤这是实现个性化推荐的基础。3.4 摘要生成与推送集成最后我们将所有环节串联起来并加入LLM摘要和推送功能。# digest/generator.py import openai # 或其他LLM提供商 from scraper.core import RedditScraper, RedditPost from processor.vector_store import VectorStoreManager import yagmail from telegram import Bot from telegram.error import TelegramError from datetime import datetime import logging import json logger logging.getLogger(__name__) class DigestGenerator: 摘要生成与推送的核心类 def __init__(self, config_path: str): with open(config_path, r) as f: self.config json.load(f) # 初始化组件 self.scraper RedditScraper( user_agentself.config[scraper][user_agent], rate_limit_delayself.config[scraper][rate_limit_delay] ) self.vector_store VectorStoreManager( model_nameself.config[vector_store][model_name], persist_dirself.config[vector_store][persist_dir] ) # 初始化LLM客户端以OpenAI为例 openai.api_key self.config[llm][openai_api_key] self.llm_model self.config[llm][model] # 初始化推送客户端 self.email_sender yagmail.SMTP( userself.config[notification][email][sender], passwordself.config[notification][email][password] # 建议使用应用专用密码 ) self.telegram_bot Bot(tokenself.config[notification][telegram][bot_token]) self.telegram_chat_id self.config[notification][telegram][chat_id] # 加载兴趣配置 self.interests self.config[user_interests] def _filter_and_rank_posts(self, posts: List[RedditPost]) - List[RedditPost]: 根据兴趣配置文件过滤和排序帖子 filtered [] for post in posts: # 1. 子版块过滤 if post.subreddit.lower() not in [s.lower() for s in self.interests[subreddits]]: continue # 2. 关键词过滤兴趣词加分屏蔽词一票否决 title_lower post.title.lower() content_lower post.selftext.lower() combined_text f{title_lower} {content_lower} # 检查屏蔽词 if any(block_word in combined_text for block_word in self.interests.get(block_keywords, [])): continue # 计算兴趣匹配度简单版兴趣关键词出现次数 interest_score sum(keyword in combined_text for keyword in self.interests[keywords]) # 可以结合帖子分数、评论数进行综合排序 post.custom_score interest_score * 10 post.score * 0.1 post.num_comments * 0.05 filtered.append(post) # 按自定义分数降序排序 filtered.sort(keylambda x: x.custom_score, reverseTrue) return filtered[:self.interests.get(max_posts_per_digest, 10)] # 取前N个 def _generate_summary_with_llm(self, post: RedditPost, top_comments: List[Dict]) - str: 使用LLM生成帖子摘要 # 构建提示词 comments_text \n.join([f- {c[body][:200]}... for c in top_comments[:3]]) prompt f 请为以下Reddit帖子生成一个简洁、信息丰富的摘要。 帖子标题{post.title} 帖子正文{post.selftext[:1500]} # 限制长度 热门评论 {comments_text} 请用一段话不超过200字总结该帖子的核心讨论点、技术要点或主要观点。保持客观不要添加个人意见。如果提到了具体的工具、库或方法请明确指出。 try: response openai.chat.completions.create( modelself.llm_model, messages[ {role: system, content: 你是一个专注于技术社区内容总结的助手。}, {role: user, content: prompt} ], max_tokens300, temperature0.5 # 较低的温度使输出更稳定、聚焦 ) summary response.choices[0].message.content.strip() return summary except Exception as e: logger.error(fLLM summary generation failed for post {post.id}: {e}) # 降级方案返回一个基于规则的简单摘要 return f帖子讨论了关于{post.title}。社区关注度较高{post.score}分{post.num_comments}条评论。 def generate_daily_digest(self): 生成每日摘要的主流程 logger.info(Starting daily digest generation...) all_filtered_posts [] # 1. 抓取所有关注子版块的热帖 for subreddit in self.interests[subreddits]: logger.info(fScraping r/{subreddit}) posts self.scraper.fetch_hot_posts(subreddit, limit30) all_filtered_posts.extend(posts) # 短暂休眠避免请求过快 import time time.sleep(2) # 2. 过滤和排序 selected_posts self._filter_and_rank_posts(all_filtered_posts) logger.info(fSelected {len(selected_posts)} posts after filtering.) digest_content f# 你的Reddit技术摘要 {datetime.now().strftime(%Y-%m-%d)}\n\n # 3. 为每个选中的帖子生成摘要 for i, post in enumerate(selected_posts, 1): digest_content f## {i}. {post.title}\n digest_content f**子版块:** r/{post.subreddit} | **热度:** {post.score} ↑ | **评论:** {post.num_comments} \n digest_content f**原文链接:** [点击查看]({post.permalink})\n\n # 获取热门评论QClaw top_comments self.scraper.fetch_post_comments(post.permalink, depth1) # 生成LLM摘要 llm_summary self._generate_summary_with_llm(post, top_comments) digest_content f** 智能摘要:**\n{llm_summary}\n\n # 附上精选评论 if top_comments: digest_content ** 社区精选评论:**\n for comment in top_comments[:2]: # 取前两条最热评论 # 简单清理评论文本如移除换行符 clean_body comment[body].replace(\n, ).strip()[:300] digest_content f- *\{clean_body}...\* (by u/{comment.get(author, Unknown)}, ↑{comment.get(score, 0)})\n digest_content \n digest_content ---\n\n # 4. 存储到向量数据库以备后续检索 for post in selected_posts: self.vector_store.store_post( post_idpost.id, titlepost.title, contentpost.selftext, metadata{ subreddit: post.subreddit, score: post.score, url: post.permalink, date: datetime.fromtimestamp(post.created_utc).isoformat() } ) # 5. 推送 self._send_notifications(digest_content) logger.info(Daily digest generated and sent successfully.) def _send_notifications(self, content: str): 通过邮件和Telegram发送摘要 subject fReddit Digest - {datetime.now().strftime(%Y-%m-%d)} # 发送邮件 try: self.email_sender.send( toself.config[notification][email][recipient], subjectsubject, contentscontent ) logger.info(Email notification sent.) except Exception as e: logger.error(fFailed to send email: {e}) # 发送Telegram消息由于内容可能很长可以分段或发送摘要链接 # 这里简化处理发送一个提示和首条内容 telegram_msg f{subject}\n\n今日精选了{len(content.split(##)) - 1}个帖子。完整内容已发送至邮箱。\n\n第一条摘要\n first_summary_start content.find(** 智能摘要:**) first_summary_end content.find(** 社区精选评论:**, first_summary_start) if first_summary_start ! -1 and first_summary_end ! -1: telegram_msg content[first_summary_start:first_summary_end].replace(**, ).strip()[:500] ... try: self.telegram_bot.send_message(chat_idself.telegram_chat_id, texttelegram_msg) logger.info(Telegram notification sent.) except TelegramError as e: logger.error(fFailed to send Telegram message: {e}) # 配置文件示例 config.json { scraper: { user_agent: RedditDigestBot/1.0 (by /u/YourUsername), rate_limit_delay: 1.5 }, vector_store: { model_name: all-MiniLM-L6-v2, persist_dir: ./data/chroma_db }, llm: { openai_api_key: your-api-key-here, model: gpt-3.5-turbo }, notification: { email: { sender: your-emailgmail.com, password: your-app-password, recipient: recipient-emailexample.com }, telegram: { bot_token: YOUR_BOT_TOKEN, chat_id: YOUR_CHAT_ID } }, user_interests: { subreddits: [programming, Python, rust, datascience, webdev], keywords: [tutorial, guide, performance, async, database, framework], block_keywords: [hire, looking for, meme, shitpost], max_posts_per_digest: 8 } } 这个DigestGenerator类是整个系统的大脑。它协调抓取、过滤、摘要生成、存储和推送的全流程。_filter_and_rank_posts方法体现了“WorkBuddy”的个性化能力而_generate_summary_with_llm则是智能化的核心。通过配置文件你可以轻松调整关注的子版块、关键词和推送方式。4. 部署、优化与常见问题排查将代码跑起来只是第一步要让“WorkBuddy”稳定可靠地长期工作还需要考虑部署、监控和优化。4.1 部署方案选择对于个人使用有几种轻量级的部署方式本地Cron任务最简单在Linux/Mac的服务器或常年开机的电脑上使用crontab定时执行脚本。# 每天上午9点运行摘要生成 0 9 * * * cd /path/to/reddit-digest /path/to/venv/bin/python run_digest.py在run_digest.py中你只需要初始化DigestGenerator并调用generate_daily_digest()方法。云服务器Supervisor在VPS上部署使用Supervisor或systemd来管理进程确保脚本崩溃后能自动重启。这种方式更稳定适合生产环境。无服务器函数更现代使用AWS Lambda、Google Cloud Functions或Vercel Serverless Functions。将核心逻辑打包成函数通过CloudWatch Scheduler或Cron触发。优点是完全不用管理服务器按需付费。但需要注意函数运行时间限制和冷启动问题并且需要处理好数据库如ChromaDB的持久化存储可能需要改用云端的向量数据库服务。4.2 性能优化与稳定性提升异步抓取当前的RedditScraper使用同步的requests库。当需要抓取多个子版块时是串行执行的总耗时是各个请求之和。可以改用aiohttp进行异步并发抓取能大幅缩短数据获取时间。但务必注意异步并发更容易触发API的频率限制需要更精细的速率控制例如使用asyncio.Semaphore。错误处理与重试网络请求天生不稳定。必须为所有外部API调用Reddit API、LLM API添加健壮的重试机制。可以使用tenacity库以指数退避策略进行重试。from tenacity import retry, stop_after_attempt, wait_exponential retry(stopstop_after_attempt(3), waitwait_exponential(multiplier1, min4, max10)) def fetch_posts_with_retry(subreddit): return self.scraper.fetch_hot_posts(subreddit)数据去重Reddit的热门帖子列表在不同时间抓取可能会有重叠。在存储或生成摘要前应根据帖子ID进行去重避免同一条信息在多次摘要中出现。摘要缓存对于已经生成过摘要的帖子可以将其摘要结果缓存起来例如存到数据库或本地文件。如果该帖子第二天仍然在热门列表中可以直接使用缓存节省LLM API的调用费用和等待时间。4.3 常见问题排查实录在实际运行中你肯定会遇到各种问题。以下是我踩过的一些坑和解决方案问题1抓取很快被Reddit限制或返回429错误。原因请求频率过高或User-Agent设置不当。排查检查代码中的rate_limit_delay是否足够长建议至少1秒。确保User-Agent字符串格式正确包含应用名、版本和你的Reddit用户名。解决增加请求间隔尤其是在QClaw深度抓取评论时。考虑使用Reddit的OAuth2认证认证后的请求会有更高的频率限制。对于非常重要的应用可以申请Reddit的API使用许可。问题2LLM生成的摘要有时偏离主题或包含奇怪内容。原因提示词Prompt不够精确或者帖子/评论内容本身噪声太大如包含大量代码、链接或非英语内容。排查打印出发送给LLM的完整提示词和原文内容检查是否有无关信息。解决优化提示词增加更明确的指令例如“只总结技术讨论部分忽略个人轶事和玩笑”。在将文本发送给LLM前进行预处理移除代码块用[code snippet]代替、截断过长的文本、过滤掉非英语内容如果只关注英文社区。问题3向量搜索返回的结果不相关。原因嵌入模型不适合该领域或者查询文本太短、太模糊。排查检查存储的“文档”文本帖子标题正文是否包含足够的信息。尝试用不同的查询语句。解决尝试不同的sentence-transformers模型例如all-mpnet-base-v2效果更好但更慢。对于查询可以尝试将用户的关键词扩展成更完整的句子例如将“Python async”改为“discussions about asynchronous programming in Python”。问题4Telegram Bot推送失败。原因Token或Chat ID错误消息内容过长Telegram有消息长度限制网络问题。排查检查配置文件的Token和Chat ID是否正确。尝试发送一条简单的测试消息。解决确保从BotFather获取了正确的Token。Chat ID可以通过向你的Bot发送/start消息然后访问https://api.telegram.org/botYOUR_BOT_TOKEN/getUpdates来查看。对于长内容需要将摘要分割成多条消息发送或者改为发送一个指向托管摘要网页的链接。问题5摘要内容突然变少或为空。原因兴趣过滤条件太严格某个子版块抓取失败Reddit API返回结构变化。排查增加日志输出查看每个子版块抓取到了多少帖子过滤前后各剩下多少。检查Reddit API的响应数据格式。解决放宽过滤条件例如减少关键词数量或增加max_posts_per_digest。为抓取函数添加更详细的异常日志以便快速定位是哪个子版块出了问题。定期检查代码因为Reddit偶尔会调整其API。将这个系统搭建并运行起来后它就像一位不知疲倦的“WorkBuddy”每天准时为你奉上量身定制的信息精华。你可以根据反馈不断微调兴趣配置优化摘要质量。随着时间的推移向量数据库里积累的数据还能让你进行更有趣的分析比如“过去一个月里社区讨论最热烈的Python框架是什么”这不仅是获取信息的工具更是你理解技术趋势的私人雷达。

相关文章:

基于OpenClaw/QClaw与LLM的Reddit智能摘要系统构建实战

1. 项目概述与核心价值如果你和我一样,每天泡在Reddit和各种技术社区里,试图从海量的帖子、评论和新闻中淘出真正有价值的信息,那你一定体会过那种“信息过载”的无力感。首页永远刷不完,热帖里夹杂着大量水贴和重复讨论&#xff…...

DeepSeek集成配置终极指南:3分钟搞定环境变量与配置文件实战技巧

DeepSeek集成配置终极指南:3分钟搞定环境变量与配置文件实战技巧 【免费下载链接】awesome-deepseek-integration Integrate the DeepSeek API into popular software 项目地址: https://gitcode.com/GitHub_Trending/aw/awesome-deepseek-integration 还在为…...

Linux内核构建实战:从零搭建可复现的开发环境与调试技巧

1. 项目概述:一个内核构建与研究的起点如果你和我一样,对操作系统底层、对Linux内核的编译、定制和调试充满好奇,但又常常被官方庞大而复杂的源码树和构建系统搞得晕头转向,那么“usepons/kernel”这个项目很可能就是你一直在寻找…...

基于Transformer的AI音乐生成:从原理到开源项目实践

1. 项目概述:当开源代码库遇上音乐创作 最近在GitHub上闲逛,发现了一个挺有意思的项目,叫 Alpha-Park/openclaw-genpark-music-creator 。光看名字,一股浓浓的“极客”味儿扑面而来, Alpha-Park 像是个组织或开发者…...

嵌入式系统未来演进:从摩尔定律终结到跨学科融合的技术路径

1. 从硅谷果园到未来预言:一位物理学家的嵌入式视野2010年春天,在圣何塞举办的嵌入式系统大会上,当加来道雄博士走上讲台时,台下坐着的是一群最务实的人——嵌入式系统工程师、硬件开发者、产品经理。他们的日常是与寄存器、时序、…...

避坑指南:用CubeMX给STM32F4配置CAN时,为什么你的代码收不到数据?

避坑指南:用CubeMX给STM32F4配置CAN时,为什么你的代码收不到数据? 当你按照教程一步步配置好STM32F4的CAN接口,却发现只能发送数据而无法接收时,那种挫败感我深有体会。作为一名经历过无数次CAN通信调试的老手&#xf…...

亚分辨率辅助特征(SRAF)在半导体光刻工艺中的优化与应用

1. 亚分辨率辅助特征(SRAF)在先进制程中的关键作用在45nm及更先进半导体制造节点中,亚分辨率辅助特征(Sub-Resolution Assist Features, SRAF)已成为提升光刻工艺窗口(Process Window, PW)不可或缺的技术手段。这些精心设计的微小结构,其宽度被严格控制在…...

ARM Cortex-A9 MPCore调试架构与扫描测试技术详解

1. ARM Cortex-A9 MPCore调试架构概述在嵌入式系统开发领域,ARM Cortex-A9 MPCore处理器因其出色的性能表现和灵活的调试功能而广受青睐。作为一款多核处理器,其调试系统设计尤为复杂,需要兼顾芯片测试(DFT)和生产验证的双重需求。Cortex-A9的…...

四足机器人滑行控制:强化学习与贝叶斯优化实践

1. 四足机器人滑行控制的创新突破在机器人运动控制领域,四足机器人一直面临着速度与能效的平衡难题。传统轮式机器人虽然速度快、能耗低,但在复杂地形适应性差;而纯腿式机器人虽然地形适应性强,却难以达到轮式机器人的运动效率。我…...

React作品集模板全解析:从技术栈选型到性能优化实战

1. 项目概述:一个为开发者量身定制的React个人作品集模板在技术社区里,我们经常看到一些令人眼前一亮的个人作品集网站,它们不仅是开发者技能的展示窗口,更是个人品牌和专业形象的核心载体。然而,从零开始构建一个既美…...

前端Token管理实战:基于jzOcb/token-guard的JWT安全实践

1. 项目概述:为什么我们需要一个Token守卫? 在构建现代Web应用,特别是前后端分离的架构时,身份认证与授权是绕不开的核心环节。JWT(JSON Web Token)因其无状态、自包含的特性,已成为实现这一环节…...

api测试工具代理配置适配

继上一篇, 代理配置如果设置了以下代理绕过代理服务器,libcurl需要适配。 但是上一篇代码有bug, 这句代码有时没起作用: curl_easy_setopt(curl, CURLOPT_NOPROXY, proxyBypass.c_str());去掉这句代码,改为应用层获取哪…...

深度实战:Blender MMD Tools专业工作流全解析与高效技巧

深度实战:Blender MMD Tools专业工作流全解析与高效技巧 【免费下载链接】blender_mmd_tools MMD Tools is a blender addon for importing/exporting Models and Motions of MikuMikuDance. 项目地址: https://gitcode.com/gh_mirrors/bl/blender_mmd_tools …...

如何彻底解决ComfyUI节点冲突:5种策略完整指南

如何彻底解决ComfyUI节点冲突:5种策略完整指南 【免费下载链接】ComfyUI-Manager ComfyUI-Manager is an extension designed to enhance the usability of ComfyUI. It offers management functions to install, remove, disable, and enable various custom nodes…...

手把手配置NCJ29D5:基于ARM Cortex-M33的UWB测距开发避坑指南

手把手配置NCJ29D5:基于ARM Cortex-M33的UWB测距开发避坑指南 在物联网和智能汽车快速发展的今天,超宽带(UWB)技术凭借其厘米级精度的定位能力,正在重塑从数字钥匙到室内导航的各类应用场景。作为NXP专为汽车电子设计的UWB芯片,NC…...

ADS EM仿真选Momemtum还是FEM?看完这篇对比和实战配置,别再纠结了

ADS EM仿真选Momentum还是FEM?核心原理与实战决策指南 在射频与微波电路设计中,电磁场仿真工具的选择往往直接决定设计效率与结果可靠性。作为业界标准平台之一,ADS(Advanced Design System)提供了Momentum和FEM两种主…...

告别懵圈!手把手教你用C语言和USB HID协议实现自定义键盘宏按键(附完整报告描述符解析)

从零构建USB HID设备:C语言实战自定义键盘宏按键开发指南 当你在游戏激战中需要快速执行复杂连招,或是办公时频繁重复输入特定文本序列,物理按键的局限性总会让人感到掣肘。传统解决方案往往依赖软件层面的宏录制,但这存在兼容性差…...

UDS诊断实战:手把手教你用0x3D服务(WriteMemoryByAddress)刷写ECU标定数据

UDS诊断实战:手把手教你用0x3D服务(WriteMemoryByAddress)刷写ECU标定数据 在汽车电子诊断领域,ECU标定数据的修改是工程师们经常需要面对的任务。想象一下这样的场景:台架测试中某个燃油喷射参数需要微调,…...

保姆级教程:GD32F470的DMA+PWM配置详解(从寄存器到固件库,以Timer7为例)

GD32F470 DMAPWM深度配置实战:从寄存器操作到固件库封装 在嵌入式开发中,精确控制PWM波形输出是电机驱动、电源管理等应用的核心需求。GD32F470系列凭借其丰富的外设资源和高性能定时器,成为许多工业级应用的理想选择。本文将深入剖析如何利用…...

PotPlayer字幕翻译插件:5分钟实现视频实时双语字幕

PotPlayer字幕翻译插件:5分钟实现视频实时双语字幕 【免费下载链接】PotPlayer_Subtitle_Translate_Baidu PotPlayer 字幕在线翻译插件 - 百度平台 项目地址: https://gitcode.com/gh_mirrors/po/PotPlayer_Subtitle_Translate_Baidu 还在为外语视频没有中文…...

Windows系统printui.dll文件丢失无法启动程序解决

在使用电脑系统时经常会出现丢失找不到某些文件的情况,由于很多常用软件都是采用 Microsoft Visual Studio 编写的,所以这类软件的运行需要依赖微软Visual C运行库,比如像 QQ、迅雷、Adobe 软件等等,如果没有安装VC运行库或者安装…...

Windows系统propsys.dll文件丢失无法启动程序解决

在使用电脑系统时经常会出现丢失找不到某些文件的情况,由于很多常用软件都是采用 Microsoft Visual Studio 编写的,所以这类软件的运行需要依赖微软Visual C运行库,比如像 QQ、迅雷、Adobe 软件等等,如果没有安装VC运行库或者安装…...

别再混淆了!一文搞懂PCB设计中的‘特征阻抗’与‘直流电阻’到底有啥区别

别再混淆了!一文搞懂PCB设计中的‘特征阻抗’与‘直流电阻’到底有啥区别 刚接触高速PCB设计的工程师,常常会对"特征阻抗50Ω"和万用表测得的"走线电阻0.1Ω"产生困惑——为什么同一个铜箔走线会有两个完全不同的"阻抗"值…...

SpringBoot配置中的变量引用技巧

在SpringBoot应用中,配置文件的灵活性是其一大优势。我们经常需要在配置文件中引用其他属性的值来动态生成新的配置项。本文将通过一个实例讲解如何在SpringBoot的application.yml文件中使用变量引用技术,特别是如何将一个变量的值作为Map的键名。 背景 假设我们有一个Spri…...

Hitboxer终极指南:免费解决游戏按键冲突的专业SOCD重映射工具

Hitboxer终极指南:免费解决游戏按键冲突的专业SOCD重映射工具 【免费下载链接】socd Key remapper for epic gamers 项目地址: https://gitcode.com/gh_mirrors/so/socd 你是否曾在激烈的格斗游戏中,因为同时按下左右方向键而无法准确释放必杀技&…...

MATLAB 中的矩阵转换与性能优化

在 MATLAB 编程中,处理和转换矩阵数据是一个常见的任务。尤其当我们需要将多个二维矩阵合并为一个大的二维矩阵时,如何有效地进行数据处理不仅仅影响程序的执行效率,还关系到数据的准确性和程序的可维护性。本文将通过一个实际的例子,展示如何将多个二维矩阵转换为一个统一…...

魔兽争霸3终极优化指南:免费开源工具WarcraftHelper让你的经典游戏焕发新生

魔兽争霸3终极优化指南:免费开源工具WarcraftHelper让你的经典游戏焕发新生 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper 还在为魔兽争霸…...

解密C语言中的动态数组

在编程语言中,数组是非常基础的数据结构。C语言中,数组的大小在编译时通常是固定的。然而,随着需求的增加,程序员们也开始希望能在运行时动态地定义数组大小。本文将结合实例讨论在C语言中如何处理动态数组,特别是针对游戏编程中的常见需求——4-in-a-row游戏的棋盘初始化…...

如何免费解锁原神60帧限制?2025终极教程让游戏体验翻倍

如何免费解锁原神60帧限制?2025终极教程让游戏体验翻倍 【免费下载链接】genshin-fps-unlock unlocks the 60 fps cap 项目地址: https://gitcode.com/gh_mirrors/ge/genshin-fps-unlock 想让你的原神世界从60帧的束缚中解放出来吗?genshin-fps-u…...

英雄联盟智能助手Seraphine:5分钟掌握LCU API驱动的战绩查询与自动BP工具

英雄联盟智能助手Seraphine:5分钟掌握LCU API驱动的战绩查询与自动BP工具 【免费下载链接】Seraphine 英雄联盟战绩查询工具 项目地址: https://gitcode.com/gh_mirrors/se/Seraphine 在英雄联盟的竞技对局中,BP阶段的决策效率直接影响着游戏胜负…...