
1. 项目概述一个能自动追踪AI新闻的智能体最近在GitHub上看到一个挺有意思的项目叫ai-news-weekly-agent。光看名字你大概能猜到它是个和AI新闻相关的自动化工具。没错它的核心目标就是扮演一个“AI新闻周刊编辑”的角色自动从互联网上抓取、筛选、整理并生成一份关于人工智能领域最新动态的周报。我自己也经常需要关注AI领域的前沿进展无论是为了技术选型、寻找灵感还是单纯保持对行业的敏感度。但信息爆炸的时代每天都有海量的论文、产品发布、技术博客和行业新闻涌现手动去追踪和筛选不仅耗时耗力还容易遗漏关键信息。这个项目正好切中了这个痛点——它试图用代码和智能体Agent技术将“信息收集-处理-输出”这个繁琐的流程自动化。简单来说ai-news-weekly-agent是一个基于大语言模型LLM驱动的智能体系统。它每周会自动运行通过预设的规则或指令去指定的信息源如技术社区、新闻网站、论文预印本平台、知名博客等爬取内容。然后利用LLM的理解和总结能力对这些原始信息进行重要性排序、去重、分类并最终生成一份结构清晰、重点突出的中文周报可能以Markdown、PDF或邮件订阅的形式交付给用户。这个项目的价值在于它将一个信息工作者的核心工作流信息感知、筛选、整合、报告进行了程序化封装。对于开发者、研究者、产品经理甚至是投资分析师来说拥有这样一个“永不疲倦的AI信息助理”能极大地提升信息获取的效率和质量让你把精力更集中在深度思考和决策上而不是淹没在信息的海洋里。2. 核心架构与工作流拆解要理解ai-news-weekly-agent是如何工作的我们需要深入其内部拆解它的核心架构。一个典型的自动化新闻聚合智能体其工作流可以抽象为四个核心阶段信息采集、内容处理、报告生成与任务调度。2.1 信息采集层数据源的规划与获取这是整个流程的起点决定了周报内容的广度和质量。一个设计良好的采集层需要兼顾覆盖面和精准度。2.1.1 核心数据源选择项目通常会预设一个高质量的信息源列表。这些源站的选择至关重要它们必须是AI领域信息的一手或高质量聚合地。常见的来源包括学术前沿arXivcs.AI, cs.CL, cs.CV, cs.LG等子版块、Papers with Code。这里能获取最新的研究论文。技术社区与博客Hacker News的AI板块、Reddit的r/MachineLearning、知名公司的技术博客如OpenAI Blog, DeepMind Blog, Anthropic Blog、以及一些顶级研究者的个人博客。行业新闻与资讯TechCrunch, The Verge的AI板块以及一些垂直媒体如MIT Technology Review的相关报道。开源项目动态GitHub Trending中与AI相关的仓库或者关注特定组织如huggingface, langchain的更新。注意数据源的配置需要谨慎。过多的源站会导致信息过载和运行缓慢过少则可能遗漏重要新闻。一个好的实践是建立一个“核心源”必读和“扩展源”可选扫描的层级列表并在运行中根据历史反馈动态调整。2.1.2 采集技术实现采集通常通过API和网络爬虫结合的方式实现。API优先对于提供开放API的平台如GitHub API, arXiv API, Hacker News Firebase API应优先使用。这更稳定、更友好且通常有速率限制需要代码中做好请求间隔和错误处理。爬虫作为补充对于没有API或API信息不全的网站则需要使用轻量级爬虫。常用的工具包括requestsBeautifulSoup静态页面或Playwright/Selenium动态渲染页面。这里必须遵守网站的robots.txt协议并设置合理的请求头User-Agent和请求间隔避免对目标服务器造成压力。RSS订阅许多博客和新闻网站仍提供RSS源使用feedparser这样的库来解析RSS是最简单高效的方式之一。在ai-news-weekly-agent的实现中可能会为每一类数据源编写一个独立的“采集器”Collector模块每个模块负责处理特定站点的数据获取和初步解析如提取标题、链接、发布时间、摘要等并输出结构化的数据条目。2.2 内容处理层从数据到信息的提炼采集到的原始数据条目是杂乱无章的。内容处理层的任务就是利用LLM的智能将这些数据转化为有价值的信息。2.2.1 去重与聚类同一事件可能被多个源站报道。首先需要进行去重。简单的基于标题或链接的精确匹配效果有限更智能的方法是使用文本嵌入Embedding。例如使用OpenAI的text-embedding-3-small或开源的BGE模型为每个条目的标题和摘要生成向量然后计算向量之间的余弦相似度。相似度超过某个阈值如0.85的条目可以被视为同一事件进行合并并保留最早或最权威的来源信息。2.2.2 重要性评估与过滤不是所有抓取到的内容都值得进入周报。这里需要LLM出场。我们可以设计一个提示词Prompt让LLM扮演“资深AI编辑”对每个条目进行打分和分类。一个典型的Prompt可能是你是一位专注于人工智能领域的资深技术编辑。请评估以下新闻/论文/博客的重要性并给出理由。 评估维度 1. 技术突破性0-10分是否提出了颠覆性的新方法、模型或理论 2. 行业影响力0-10分是否会对业界产品、投资或就业市场产生显著影响 3. 社区关注度0-10分是否在开发者/研究社区引发了广泛讨论 4. 可访问性0-10分其代码、模型或服务是否已开源或可用 请根据以上维度对以下内容进行综合评分0-40分并判断其所属类别如“大模型技术”、“多模态”、“AI基础设施”、“伦理与治理”、“产品发布”、“融资动态”等。 内容标题[标题] 内容摘要[摘要] 来源[来源]LLM会返回一个结构化的JSON包含分数和类别。我们可以设定一个阈值比如总分高于20分只保留高分条目进入下一阶段。这个过程也完成了初步的分类。2.2.3 关键信息提取与摘要生成对于通过筛选的条目需要进一步加工。我们可以再次调用LLM为每个条目生成一个更精炼的摘要并提取关键信息点例如论文核心创新点、性能提升SOTA、代码/模型地址。产品发布主要功能、定价变化、目标用户。行业新闻涉及公司、交易金额、潜在影响。这个摘要将直接用于周报的撰写因此要求准确、简洁、包含干货。2.3 报告生成层从信息到知识的结构化呈现经过处理的信息是零散的“珍珠”报告生成层负责将它们串成一条“项链”。2.3.1 内容组织与大纲生成首先LLM需要根据所有条目的类别和重要性生成本周报的目录大纲。例如# AI Weekly Digest (YYYY-MM-DD) ## 一、 大模型前沿 ### 1.1 模型架构新进展 ### 1.2 高效训练与推理 ## 二、 多模态与具身智能 ## 三、 AI基础设施与工具 ## 四、 行业动态与商业应用 ## 五、 开源项目推荐这个大纲为后续的内容填充提供了骨架。2.3.2 章节内容撰写接着LLM会以“编辑”的身份根据大纲和每个分类下的条目列表撰写完整的章节内容。这里不再是简单的条目罗列而是需要LLM进行连贯的叙述可能包括背景介绍、事件串联、简要评论等使周报读起来像是由人撰写的。2.3.3 格式渲染与输出最后将LLM生成的Markdown文本进行最终渲染。这可能包括添加固定的页眉页脚如项目说明、订阅方式。确保所有链接格式正确。将Markdown转换为更美观的格式如通过WeasyPrint生成PDF或直接发布到静态网站如GitHub Pages。集成邮件发送功能使用smtplib或邮件服务商API将周报推送给订阅者。2.4 任务调度与运维层让智能体自主运行一个真正的“智能体”需要能定期、无人值守地运行。这一层关注系统的可持续性。2.4.1 调度系统最简单的方式是使用服务器的Cron JobLinux或Task SchedulerWindows定时如每周一凌晨2点执行主程序脚本。更云原生的做法是使用GitHub Actions的schedule事件这样无需自有服务器且能与代码仓库集成运行日志清晰可见。在GitHub Actions的.yml配置文件中可以这样设置on: schedule: - cron: 0 2 * * 1 # 每周一UTC时间2点北京时间10点运行 workflow_dispatch: # 允许手动触发2.4.2 状态管理与错误处理智能体运行中可能遇到各种问题网络超时、API额度用尽、网站改版导致爬虫失效、LLM调用失败等。健壮的系统需要日志记录详细记录每个阶段的运行状态、获取的条目数、处理结果、遇到的错误便于后期排查。检查点Checkpoint在关键步骤后保存中间状态如采集到的原始数据、处理后的条目列表。如果后续步骤失败可以从检查点恢复避免重复工作特别是昂贵的LLM调用。失败重试与降级策略对网络请求和API调用设置重试机制。如果某个数据源完全失效系统应能跳过它并继续运行同时在日志中告警而不是整体崩溃。通知机制当运行失败或生成的内容异常如条目数过少时通过邮件、Slack或钉钉机器人通知维护者。2.4.3 成本控制与优化LLM API调用是主要成本。需要优化批量处理将多个条目的评估或摘要任务合并到一个Prompt中调用减少请求次数。模型选型对于重要性评估、分类等任务可以使用更便宜、更快的模型如GPT-3.5-Turbo对于最终的报告撰写再使用能力更强的模型如GPT-4。缓存策略对于短期内重复出现或相似的新闻可以使用缓存避免重复调用LLM进行分析。3. 关键技术点与工具选型解析构建ai-news-weekly-agent这样的项目技术选型直接决定了开发效率和最终效果。下面我们来拆解几个关键的技术组件及其常见的选型方案。3.1 大语言模型LLM接入与提示工程LLM是整个系统的“大脑”其选型和Prompt设计是核心。3.1.1 模型服务选型闭源API易用、能力强OpenAI GPT系列生态最成熟API稳定文档齐全。gpt-4o或gpt-4-turbo在理解和生成能力上表现优异但成本较高。gpt-3.5-turbo性价比高适合处理大量文本分类和摘要任务。Anthropic Claude系列以长上下文和强指令跟随著称适合处理需要整合大量信息的报告生成任务。国内大厂API如百度文心、阿里通义、智谱GLM等访问速度和合规性有优势。开源模型自部署可控、成本固定轻量级模型如Qwen2.5-7B-Instruct,Llama-3.2-3B-Instruct它们参数量小可以在消费级显卡甚至CPU上运行适合对实时性要求不高或希望完全控制数据的场景。可以使用vLLM,TGI(Text Generation Inference) 等框架进行高效部署。重量级模型如Qwen2.5-72B-Instruct,Llama-3.1-70B能力接近第一梯队闭源模型但需要强大的GPU服务器运维成本高。实操心得对于个人或小团队项目初期强烈建议从OpenAI或Claude的API开始。这能让你快速验证想法和流程把精力集中在业务逻辑而非模型部署上。当流程跑通且成本成为主要考量时再考虑将部分任务如文本分类、摘要迁移到本地部署的轻量开源模型上形成混合架构。3.1.2 提示工程Prompt Engineering实践Prompt是驱动LLM工作的“指令集”设计好坏直接影响结果质量。角色扮演Role Playing如“你是一位资深的AI科技媒体编辑”这能有效引导模型输出符合特定风格和深度的内容。结构化输出Structured Output明确要求模型以JSON、XML或特定Markdown格式返回结果便于后续程序化处理。例如在评估重要性时直接要求返回{score: 25, category: 大模型技术, reason: ...}。少样本学习Few-shot Learning在Prompt中提供1-3个高质量的例子输入和期望的输出能显著提升模型在特定任务上的表现。例如给一个新闻标题和摘要然后展示一个理想的重要性评估结果。链式思考Chain-of-Thought对于复杂任务鼓励模型“一步一步思考”可以提高推理的准确性和可靠性。一个综合性的Prompt模板可能长这样你是一位专注于人工智能领域的资深技术编辑负责为专业读者筛选和总结本周重要动态。 ## 你的任务 对给定的内容条目进行重要性评估和摘要。 ## 输出格式 你必须严格按照以下JSON格式输出不要有任何其他文字 { “overall_score”: 一个0到40的整数, “category”: “分类名称”, “key_points”: [“要点1”, “要点2”, “要点3”], “concise_summary”: “一段不超过100字的中文摘要” } ## 评估标准 - 技术突破性 (0-10): ... - 行业影响力 (0-10): ... - ... ## 示例 输入: {“title”: “...”, “abstract”: “...”} 输出: {“overall_score”: 32, “category”: “...”, ...} ## 现在开始处理 输入: {“title”: “{{title}}”, “abstract”: “{{abstract}}”}3.2 数据采集与处理的工程实现3.2.1 异步并发采集为了提高采集效率必须使用异步IO。Python的asyncio库配合aiohttp是标准选择。可以构建一个异步的采集器池同时并发抓取多个数据源。import aiohttp import asyncio from bs4 import BeautifulSoup async def fetch_url(session, url): try: async with session.get(url, headersheaders, timeout10) as response: html await response.text() # 使用BeautifulSoup解析 soup BeautifulSoup(html, html.parser) # ... 提取逻辑 ... return extracted_data except Exception as e: logging.error(f“Failed to fetch {url}: {e}”) return None async def main(urls): async with aiohttp.ClientSession() as session: tasks [fetch_url(session, url) for url in urls] results await asyncio.gather(*tasks, return_exceptionsTrue) # 处理结果3.2.2 向量数据库用于智能去重如前所述基于语义的去重需要计算文本嵌入的相似度。虽然可以实时计算但对于历史数据比对使用向量数据库Vector Database更高效。你可以将过去几周处理过的条目向量存入数据库当新条目到来时进行相似度查询。轻量级选择ChromaDB或FAISS。它们易于集成特别是ChromaDBAPI简单支持持久化。生产级选择Qdrant,Weaviate,Milvus。它们功能更强大支持分布式、更丰富的查询条件。基本流程1) 用嵌入模型将新条目文本转换为向量2) 在向量库中搜索Top-K个最相似的向量3) 如果相似度超过阈值则视为重复或高度相关进行合并处理。3.3 系统架构与代码组织一个清晰的项目结构有助于长期维护。ai-news-weekly-agent/ ├── config.yaml # 配置文件API密钥、数据源列表、阈值参数等 ├── main.py # 主程序入口协调整个流程 ├── src/ │ ├── collectors/ # 采集器模块 │ │ ├── __init__.py │ │ ├── arxiv_collector.py │ │ ├── github_collector.py │ │ └── rss_collector.py │ ├── processors/ # 处理器模块 │ │ ├── __init__.py │ │ ├── deduplicator.py # 去重 │ │ ├── classifier.py # 分类与评分调用LLM │ │ └── summarizer.py # 摘要生成调用LLM │ ├── generators/ # 生成器模块 │ │ ├── __init__.py │ │ └── report_generator.py # 报告撰写调用LLM │ ├── utils/ │ │ ├── llm_client.py # 封装LLM API调用 │ │ ├── vector_db.py # 向量数据库操作 │ │ └── logger.py │ └── models.py # 数据模型定义如NewsItem类 ├── outputs/ │ ├── raw_data/ # 原始采集数据 │ ├── processed/ # 处理后的数据 │ └── reports/ # 生成的周报 ├── tests/ # 单元测试 └── requirements.txt # 依赖列表这种模块化设计使得每个功能职责单一易于测试和替换。例如要增加一个新的数据源只需在collectors目录下添加一个新的类。4. 从零搭建的实操步骤与核心配置假设我们现在要从零开始实现一个简化版的ai-news-weekly-agent以下是核心的实操步骤。我们将以Python为主要语言使用OpenAI API和GitHub Actions。4.1 环境准备与基础依赖首先创建一个新的项目目录并初始化虚拟环境。mkdir ai-news-weekly-agent cd ai-news-weekly-agent python -m venv venv source venv/bin/activate # Linux/macOS # venv\Scripts\activate # Windows创建requirements.txt文件包含基础依赖# 核心依赖 openai1.0.0 aiohttp3.9.0 beautifulsoup44.12.0 feedparser6.0.0 python-dotenv1.0.0 pyyaml6.0 chromadb0.4.0 # 向量数据库 sentence-transformers2.2.0 # 用于生成文本嵌入 # 报告生成与格式化 markdown3.5.0 pdfkit1.0.0 # 需要额外安装wkhtmltopdf # 调度与部署可选 schedule1.2.0安装依赖pip install -r requirements.txt。接下来创建配置文件.env用于存储敏感信息切勿提交到GitOPENAI_API_KEYsk-your-openai-key-here OPENAI_BASE_URLhttps://api.openai.com/v1 # 如果使用其他兼容API可修改 DATA_SOURCES_PATH./config/data_sources.yaml VECTOR_DB_PATH./data/chroma_db LOG_LEVELINFO创建config/data_sources.yaml定义数据源sources: - type: “arxiv” category: “cs.AI” max_results: 50 - type: “rss” url: “https://news.ycombinator.com/rss tags: [“hackernews”] - type: “github_trending” language: “python” since: “weekly”4.2 实现核心数据模型与采集器在src/models.py中定义核心数据类from pydantic import BaseModel from datetime import datetime from typing import List, Optional class NewsItem(BaseModel): id: str # 唯一标识可以是URL的hash title: str url: str source: str # 来源网站如 “arxiv”, “hackernews” published_at: Optional[datetime] content: Optional[str] # 原始内容或摘要 embedding: Optional[List[float]] None # 文本向量 category: Optional[str] None score: Optional[int] None processed_summary: Optional[str] None在src/collectors/arxiv_collector.py中实现一个简单的ArXiv采集器import arxiv import asyncio from ..models import NewsItem from datetime import datetime class ArXivCollector: def __init__(self, category“cs.AI”, max_results50): self.category category self.max_results max_results self.client arxiv.Client() async def fetch(self) - List[NewsItem]: search arxiv.Search( queryf“cat:{self.category}”, max_resultsself.max_results, sort_byarxiv.SortCriterion.SubmittedDate ) items [] for result in self.client.results(search): # 构造唯一ID例如使用entry_id的MD5 import hashlib item_id hashlib.md5(result.entry_id.encode()).hexdigest() news_item NewsItem( iditem_id, titleresult.title, urlresult.entry_id, source“arxiv”, published_atresult.published, contentresult.summary, # 使用摘要作为初始内容 ) items.append(news_item) return items类似地可以实现RSS采集器使用feedparser和GitHub Trending采集器使用GitHub API或爬虫。4.3 构建处理流水线去重、评分与摘要在src/processors/deduplicator.py中实现基于向量相似度的去重import chromadb from sentence_transformers import SentenceTransformer from ..models import NewsItem class Deduplicator: def __init__(self, persist_path“./data/chroma_db”): self.client chromadb.PersistentClient(pathpersist_path) # 创建一个集合collection来存储历史新闻 self.collection self.client.get_or_create_collection(name“news_items”) self.embedding_model SentenceTransformer(‘all-MiniLM-L6-v2’) # 轻量级嵌入模型 def find_similar(self, news_item: NewsItem, top_k3, threshold0.85): # 为新闻项生成嵌入向量 text_to_embed f“{news_item.title} {news_item.content[:500]}” # 取部分内容 embedding self.embedding_model.encode(text_to_embed).tolist() news_item.embedding embedding # 在向量数据库中查询相似项 results self.collection.query( query_embeddings[embedding], n_resultstop_k ) # results包含ids, distances, metadatas等 similar_items [] if results[‘distances’][0]: # 检查是否有结果 for dist, meta in zip(results[‘distances’][0], results[‘metadatas’][0]): if 1 - dist threshold: # chromadb使用余弦距离越小越相似 similar_items.append(meta) return similar_items def add_item(self, news_item: NewsItem): # 将新项目添加到向量数据库以备未来查重 if news_item.embedding: self.collection.add( embeddings[news_item.embedding], metadatas[{“id”: news_item.id, “title”: news_item.title, “source”: news_item.source}], ids[news_item.id] )在src/processors/classifier.py中实现调用LLM进行评分和分类from openai import OpenAI import json from ..models import NewsItem import logging class NewsClassifier: def __init__(self, model“gpt-3.5-turbo”): self.client OpenAI() # 会自动从环境变量读取OPENAI_API_KEY self.model model self.prompt_template “””你是一位AI领域编辑...此处填入之前设计好的Prompt...””” def classify_and_score(self, news_item: NewsItem) - NewsItem: prompt self.prompt_template.format(titlenews_item.title, abstractnews_item.content[:1000]) try: response self.client.chat.completions.create( modelself.model, messages[{“role”: “user”, “content”: prompt}], temperature0.2, # 低温度保证输出稳定 response_format{“type”: “json_object”} # 要求返回JSON ) result json.loads(response.choices[0].message.content) news_item.category result.get(“category”) news_item.score result.get(“overall_score”) # 可以保存其他信息到news_item的额外字段中 return news_item except Exception as e: logging.error(f“Classification failed for {news_item.id}: {e}”) return news_item # 返回原item分数为NoneSummarizer的实现类似设计一个专注于生成简洁摘要的Prompt来调用LLM。4.4 组装主流程与生成报告在src/generators/report_generator.py中实现报告生成class ReportGenerator: def __init__(self, llm_client, model“gpt-4o”): self.llm_client llm_client self.model model def generate_outline(self, categorized_items: dict) - str: # categorized_items 是一个字典key是类别value是该类下的NewsItem列表 prompt f“””基于以下分类的AI新闻条目生成一份中文周报的目录大纲。大纲应清晰有逻辑包含主要章节和可能的子章节。 分类数据{json.dumps(categorized_items, defaultstr, indent2)} 只输出大纲内容用Markdown格式。””” # 调用LLM生成大纲... return outline_markdown def generate_section(self, section_title: str, items: List[NewsItem]) - str: prompt f“””你是一位AI科技专栏作者。请根据以下条目撰写‘{section_title}’部分的周报内容。 要求内容连贯有引言和简要评论不要简单罗列。使用中文。 条目信息{json.dumps([item.dict() for item in items], defaultstr, indent2)}””” # 调用LLM生成章节内容... return section_content def assemble_report(self, outline: str, sections: dict) - str: # sections: {‘章节名’: ‘内容’} report “# AI Weekly Digest\n\n” report f“*本期周报生成于 {datetime.now().strftime(‘%Y-%m-%d %H:%M’)}*\n\n” report outline “\n\n” for sec_title, sec_content in sections.items(): report f“## {sec_title}\n\n{sec_content}\n\n” report “---\n*本报告由AI自动生成仅供参考。*” return report最后在main.py中组装整个流水线import asyncio from src.collectors import ArXivCollector, RssCollector from src.processors import Deduplicator, NewsClassifier, Summarizer from src.generators import ReportGenerator from src.utils.llm_client import get_llm_client import logging async def main(): logging.basicConfig(levellogging.INFO) # 1. 采集 collectors [ArXivCollector(), RssCollector(“https://example.com/feed)] all_items [] for collector in collectors: items await collector.fetch() all_items.extend(items) logging.info(f“Collected {len(all_items)} raw items.”) # 2. 去重 deduplicator Deduplicator() unique_items [] for item in all_items: similar deduplicator.find_similar(item) if not similar: # 没有高度相似的认为是新内容 unique_items.append(item) deduplicator.add_item(item) # 存入数据库 logging.info(f“After deduplication: {len(unique_items)} items.”) # 3. 分类与评分 classifier NewsClassifier(model“gpt-3.5-turbo”) scored_items [] for item in unique_items: processed_item classifier.classify_and_score(item) if processed_item.score and processed_item.score 20: # 阈值过滤 scored_items.append(processed_item) logging.info(f“After scoring: {len(scored_items)} high-quality items.”) # 4. 按类别分组 from collections import defaultdict categorized defaultdict(list) for item in scored_items: categorized[item.category].append(item) # 5. 生成报告 llm_client get_llm_client() generator ReportGenerator(llm_client, model“gpt-4”) outline generator.generate_outline(categorized) sections {} for category, items in categorized.items(): sections[category] generator.generate_section(category, items) final_report generator.assemble_report(outline, sections) # 6. 保存输出 import os os.makedirs(‘./outputs/reports’, exist_okTrue) report_path f‘./outputs/reports/weekly_{datetime.now().strftime(“%Y%m%d”)}.md’ with open(report_path, ‘w’, encoding‘utf-8’) as f: f.write(final_report) logging.info(f“Report saved to {report_path}”) if __name__ “__main__”: asyncio.run(main())4.5 配置自动化部署与调度为了让项目每周自动运行我们使用GitHub Actions。在项目根目录创建.github/workflows/weekly-report.ymlname: Generate AI Weekly Report on: schedule: - cron: ‘0 10 * * 1’ # 每周一UTC时间10点北京时间周一18点运行 workflow_dispatch: # 允许手动触发 jobs: build: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkoutv4 - name: Set up Python uses: actions/setup-pythonv5 with: python-version: ‘3.11’ - name: Install dependencies run: | pip install -r requirements.txt # 如果需要wkhtmltopdf for PDF generation sudo apt-get update sudo apt-get install -y wkhtmltopdf - name: Run weekly agent env: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} # 其他环境变量... run: python main.py - name: Commit and push if report changed run: | git config --local user.email “actiongithub.com” git config --local user.name “GitHub Action” git add ./outputs/reports/ git commit -m “chore: update weekly report [skip ci]” || echo “No changes to commit” git push你需要将OPENAI_API_KEY添加到GitHub仓库的Settings - Secrets and variables - Actions中。5. 常见问题、优化方向与避坑指南在实际搭建和运行过程中你一定会遇到各种问题。以下是我在类似项目中积累的一些经验和避坑点。5.1 典型问题与排查1. 采集失败或数据为空表现某个采集器没有获取到任何数据。排查网络问题检查目标网站是否可访问是否被屏蔽。考虑在代码中添加重试机制和更友好的User-Agent。网站改版网站结构变化导致CSS选择器或XPath失效。需要定期维护采集器代码。可以为关键采集器编写简单的单元测试定期运行以检测是否失效。API限制检查是否触发了目标API的速率限制Rate Limit。需要在代码中实现请求间隔如time.sleep和使用API Key轮询。解决增加详细的日志记录记录每个请求的URL和响应状态。使用try...except包裹采集逻辑捕获异常并记录不影响其他采集器运行。2. LLM调用超时或返回非预期格式表现OpenAI API调用失败或者返回的内容不是预期的JSON。排查网络或服务不稳定API服务临时故障。Prompt设计问题Prompt指令不够清晰导致模型“放飞自我”。特别是没有强制要求JSON输出时。Token超限输入文本过长超过了模型上下文窗口。解决实现指数退避的重试逻辑。在Prompt中明确使用response_format{“type”: “json_object”}并要求模型输出指定键名的JSON。在代码中解析JSON前加入json.loads()的异常捕获并准备一个降级处理方案如标记该条目为处理失败。对过长的输入文本进行智能截断保留开头、结尾和可能的关键中间部分。3. 生成的内容质量不稳定表现周报内容有时啰嗦有时遗漏重点风格不一致。排查Temperature参数在生成创造性内容如报告撰写时temperature可以稍高如0.7在进行分类、摘要等确定性任务时temperature应调低如0.2。System Prompt缺失没有给模型设定明确的角色和风格。输入信息质量差如果给LLM的原始条目摘要本身就模糊不清输出自然不佳。解决为不同的LLM调用任务分类、摘要、撰写设置不同的temperature和max_tokens参数。精心设计System Prompt和User Prompt使用少样本示例Few-shot来锚定输出风格和质量。在前期的摘要生成阶段把好关确保输入给报告生成器的“素材”是高质量的。4. 运行成本失控表现API调用费用超出预期。排查数据源过多每周抓取上千条新闻每条都调用LLM处理。模型使用不当所有任务都用最贵的gpt-4模型。重复处理没有做好去重同一新闻被多次处理。解决严格筛选数据源只保留最高质量的。采用混合模型策略分类、去重用便宜的gpt-3.5-turbo或本地小模型最终报告润色用gpt-4。强化去重模块确保每条信息只被处理一次。实现一个缓存层对近期已处理过的新闻标题/内容哈希值进行缓存。5.2 性能与效果优化方向当基础版本跑通后可以考虑以下优化来提升系统的智能性和实用性1. 个性化推荐让系统学习用户的兴趣偏好。例如用户可以标记对某些条目“感兴趣”或“不感兴趣”。系统可以记录这些条目的关键词、类别或嵌入向量在后续的评分环节中引入“个性化分数”加权让周报更贴合用户口味。2. 多模态信息整合目前的处理主要基于文本。可以扩展采集器抓取一些关键图表、模型性能对比图等。在报告中可以引用这些图片的链接甚至尝试用多模态模型如GPT-4V对图表进行简要描述整合进摘要中。3. 溯源与可解释性在生成的周报中为每个观点或结论注明来源超链接到原始文章。这不仅增加可信度也方便读者深入阅读。可以在NewsItem中保留原始URL并在报告生成时要求LLM在叙述中自然地附上引用标记。4. 交互与反馈闭环将生成的周报发布到一个带有简单交互功能的页面如静态博客。读者可以对某条新闻点击“有用”或“无用”或者提交评论。收集这些反馈数据可以用于优化LLM的Prompt或调整数据源的权重形成一个持续改进的闭环。5. 部署与监控升级将项目容器化Docker便于在不同环境部署。引入更完善的监控如使用Prometheus和Grafana监控API调用次数、耗时、费用消耗、各阶段处理条目数等关键指标并设置告警。5.3 新手避坑指南不要一开始就追求大而全先从1-2个核心数据源如Hacker News和ArXiv和最简单的流程采集-LLM摘要-输出列表开始。快速跑通一个端到端的MVP最小可行产品验证想法是否可行。API密钥安全第一永远不要将API密钥硬编码在代码中或提交到公开仓库。始终使用环境变量或密钥管理服务。成本预估与控制在运行前粗略估算一下每次运行的成本。例如处理100条新闻每条调用2次LLM分类摘要使用gpt-3.5-turbo大约花费在0.1-0.2美元。可以先设置一个消费额度告警。LLM调用要加“护栏”LLM的输出是不可控的。一定要对输出进行格式验证和内容过滤防止生成不当内容。设置合理的超时和重试。日志是你的好朋友在项目初期就建立完善的日志系统记录每个步骤的输入输出。当出现问题时详细的日志是唯一的排查线索。尊重数据源遵守网站的robots.txt设置合理的爬取间隔不要用你的脚本对一个小网站进行高频请求。可以考虑使用公共API或RSS订阅这是更友好的方式。构建一个ai-news-weekly-agent是一次非常有益的实践它串联起了爬虫、数据处理、LLM应用、提示工程、自动化部署等多个技能点。最终产出的不仅是一个工具更是一个能够持续为你提供价值的“数字员工”。