ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

构建有记忆的AI Agent:基于SQLite与工作流的热点监控系统实践

构建有记忆的AI Agent:基于SQLite与工作流的热点监控系统实践

1. 项目缘起与核心痛点

最近在折腾一个AI热点监控的小项目,初衷很简单:我想让AI帮我自动追踪特定领域(比如AI技术本身)的每日热点,然后生成一份简洁的日报推送到我的飞书或者钉钉。听起来是个典型的Agent应用场景,对吧?用大模型理解网页内容,提取关键信息,总结归纳,然后定时推送。我一开始也是这么想的,撸起袖子就干,用上了时下最火的Agent框架,心想这不就是让AI自己上网、思考、然后告诉我结果嘛。

但项目跑起来没多久,我就被现实狠狠教育了。最初的架构非常“经典”:一个调度器(Cron)定时触发,调用一个封装好的AI Agent。这个Agent的工作流是:访问预设的几个资讯网站和社区,抓取内容,让大模型分析哪些是“热点”,提炼标题、摘要和链接,最后组装成消息发送出去。我满心期待地设置了每两小时运行一次,结果第一天就出了大问题。我发现Agent经常把几个小时前,甚至昨天已经处理过的旧闻,又当成新热点提出来。更头疼的是,对于同一个持续发酵的事件,Agent每次生成的摘要角度都飘忽不定,缺乏连续性,我根本无法从这些零散的记录里看出事件发展的脉络。

这时我才恍然大悟:Agent不能只靠聊天记录(或者说,单次会话的上下文)来工作。在需要持续追踪、状态维护和基于历史决策的场景里,那个每次被Cron唤醒、干完活就失忆的“一次性”Agent,是完全不够用的。它缺少一个持久化的“记忆体”和“工作台”。这个认知,成了我重构整个项目的转折点。

2. 架构演进:从“失忆特工”到“有记忆的助手”

最初的架构,我称之为“失忆特工”模式。每次Cron触发,都像是召唤了一个全新的特工,它没有之前的任何任务记忆,只能根据我预设的指令(提示词)重新开始搜集、判断、汇报。这种模式存在几个致命缺陷:

2.1 无法去重Agent没有记忆,所以每次看到相同的或高度相似的资讯,它都会当作新发现来处理。这不仅产生了大量垃圾信息,也浪费了API调用次数(都是钱啊!)。

2.2 缺乏状态跟踪对于一个热点事件,它可能经历“爆发 -> 热议 -> 官方回应 -> 逐渐平息”等多个阶段。一个优秀的监控系统应该能识别出这是同一个事件,并记录其状态变迁。但“失忆特工”每次提交的报告都是孤立的快照,无法串联。

2.3 决策缺乏历史依据比如,Agent可能会学习到某个信源的质量不高(经常发布标题党内容)。在人类工作中,我们会下意识地降低对该信源的关注度。但“失忆特工”没有这个学习能力,下次依然会平等地对待所有信源。

为了解决这些问题,我必须给Agent配备一个持久化的“大脑”。这个大脑需要负责:

  1. 记忆存储:记住它看到过的每一条资讯。
  2. 状态管理:记录热点事件的生命周期。
  3. 知识积累:存储从历史数据中提炼出的经验(如信源权重)。

技术选型上,重型的关系型数据库(如MySQL/PostgreSQL)对于这个个人小项目来说有点杀鸡用牛刀,而简单的文件存储(如JSON)在频繁读写和复杂查询时会变得笨拙。因此,我选择了SQLite。它零配置、单文件、支持完整的SQL,完美契合个人项目或轻量级服务对嵌入式数据库的需求。它就是这个Agent的“长期记忆中枢”。

3. 核心组件设计与实现

我的项目最终形成了以SQLite为核心,协同多个组件的架构。整个系统围绕着数据库中的几张核心表运转。

3.1 数据层设计:SQLite表结构剖析

数据库是整个系统的基石,设计好坏直接决定了Agent的“智商”。我主要设计了以下几张表:

-- 资讯原始记录表:存储爬虫抓取到的原始内容 CREATE TABLE raw_articles ( id INTEGER PRIMARY KEY AUTOINCREMENT, url TEXT UNIQUE NOT NULL, -- 链接作为唯一标识,用于去重 title TEXT, content TEXT, -- 可能是全文或摘要 source TEXT, -- 信源名称 fetch_time DATETIME DEFAULT (datetime('now', 'localtime')), processed BOOLEAN DEFAULT 0 -- 是否已被处理 ); -- 热点事件表:将多条资讯聚合为一个持续追踪的事件 CREATE TABLE hot_events ( id INTEGER PRIMARY KEY AUTOINCREMENT, event_key TEXT UNIQUE NOT NULL, -- 事件唯一标识,可由核心关键词哈希生成 summary TEXT, -- 由AI生成的当前事件摘要 status TEXT DEFAULT 'tracking', -- 状态:tracking, rising, peak, fading, archived first_seen DATETIME, last_updated DATETIME, article_count INTEGER DEFAULT 1 -- 关联的资讯数量 ); -- 事件-资讯关联表:多对多关系,记录哪些资讯属于哪个事件 CREATE TABLE event_article_relation ( event_id INTEGER, article_id INTEGER, FOREIGN KEY (event_id) REFERENCES hot_events(id), FOREIGN KEY (article_id) REFERENCES raw_articles(id), PRIMARY KEY (event_id, article_id) ); -- 信源质量表:让Agent学会“挑食” CREATE TABLE source_credibility ( source TEXT PRIMARY KEY, score REAL DEFAULT 1.0, -- 可信度分数,初始为1.0 last_checked DATETIME );

提示event_key的生成是关键。我实践下来的有效方法是:用大模型(或简单的NLP库)从资讯标题和内容中提取出核心实体(如“GPT-5”、“Sora”、“某某公司”),然后排序、拼接、再取哈希。这能保证同一事件在不同时间、不同信源下能被关联起来。

3.2 智能调度中心:Cron表达式的精准控制

定时任务是系统的脉搏。我使用apscheduler库(Python环境)来管理Cron任务。监控不同阶段的事件,需要不同的扫描频率。

from apscheduler.schedulers.background import BackgroundScheduler scheduler = BackgroundScheduler() # 高频扫描:针对状态为 'rising'(上升期)的热点,每30分钟检查一次是否有新进展 scheduler.add_job(check_rising_events, 'cron', minute='*/30') # 中频扫描:常规全网爬取,每2小时一次,发现潜在新热点 scheduler.add_job(routine_crawl, 'cron', hour='*/2') # 低频扫描:每天凌晨1点,清理陈旧数据,更新信源评分 scheduler.add_job(daily_maintenance, 'cron', hour=1) # 日报生成:每天上午9点,汇总前一天的热点生成报告 scheduler.add_job(generate_daily_report, 'cron', hour=9, minute=0) scheduler.start()

注意:Cron任务千万不要设置得太密集,尤其是涉及AI API调用的任务。一方面避免给目标网站造成压力,另一方面也是控制成本。对于状态稳定的fading(消退中)事件,我甚至会将其检查频率降低到一天一次。

3.3 Agent大脑升级:从单次提示到工作流引擎

这是改造的核心。Agent不再是一个简单的“提示词+API调用”。它变成了一个与数据库紧密交互的工作流引擎。我以一次常规扫描任务为例,拆解其工作流:

  1. 数据获取与去重:爬虫将新抓取的资讯插入raw_articles表。利用url的唯一约束,数据库天然完成了去重。
  2. 事件关联:Agent被触发。它首先从raw_articles中取出所有processed=0的新资讯。对于每一条资讯,Agent调用大模型API,让其判断这条资讯是否属于某个已有热点事件(查询hot_events表),或者需要创建新事件。这个判断的依据,就是对比资讯内容与已有事件的summaryevent_key
  3. 状态研判与更新:当一条资讯被关联到某个事件后,Agent会重新评估该事件的状态。例如,如果一个事件在短时间内关联了多条高热度资讯,其状态可能从tracking变为rising。这个逻辑可以基于规则(如单位时间内的资讯增量),也可以让大模型根据所有关联资讯的内容综合判断。
  4. 信源学习:每次处理资讯后,会根据该资讯最终是否被判定为有效热点、以及其内容质量(可简单由AI给出一个置信度分数),反向更新source_credibility表。分数低的信源,在未来抓取时,其内容可能会被降低优先级或需要更严格的验证。
  5. 生成输出:对于需要报告的事件(如状态刚变为rising,或到达peak),Agent会从event_article_relationraw_articles中取出所有关联的最新资讯,让大模型生成一份连贯的、有前因后果的综合摘要,更新到hot_events.summary字段,并发送通知。

这个过程中,Agent的每一次“思考”,都基于SQLite中存储的完整历史记录,从而做出了更明智、更连贯的决策。

3.4 开发利器:Cursor与DB Browser for SQLite

在开发这个数据密集型的项目时,两个工具给了我巨大帮助。

  • Cursor:作为一款AI驱动的编辑器,它在编写与数据库交互的代码时尤其高效。例如,当我需要编写一个复杂的SQL查询来统计每个信源过去一周产生热点的事件数时,我可以在Cursor中直接描述这个需求:“写一个Python函数,用sqlite3连接数据库,查询source_credibility表,并关联raw_articles和event_article_relation,计算每个信源过去七天贡献的有效热点资讯数量。” Cursor能快速生成准确的代码框架和SQL语句,极大提升了开发效率。记得在设置中开启自动补全和代码建议功能。
  • DB Browser for SQLite (DB4S):这是一个图形化的SQLite数据库管理工具。在调试阶段,单纯看日志是不够的。通过DB4S,我可以实时打开项目的.db文件,直观地浏览表结构、执行即席SQL查询、查看数据内容,甚至手动修改一些测试数据。这对于验证Agent的逻辑是否正确、数据关联是否正常至关重要。官网提供了各个平台的安装包,使用起来非常直观。

4. 关键实现细节与避坑指南

4.1 设计稳定可靠的数据关联策略

如何让AI准确判断两条资讯是否属于同一事件?纯靠大模型进行两两比较成本太高。我的策略是分层过滤:

  1. 关键词/实体快速过滤:首先,利用离线NLP库(如jieba分词+TextRank)或大模型快速提取资讯的核心关键词和实体。如果两条资讯的核心实体集合毫无重叠,它们大概率不是同一事件。
  2. 语义相似度计算:对于通过第一层过滤的资讯,使用嵌入模型(如OpenAI的text-embedding-3-small)计算其标题和摘要的向量,并计算余弦相似度。在SQLite中,可以使用vector扩展或直接将向量存储为BLOB,但为了简单起见,我是在内存中计算,阈值设定为0.85。
  3. 大模型最终裁决:对于相似度在模糊区间(比如0.75-0.9)的资讯对,再调用大模型做最终判断,并让其给出理由。这个理由可以记录下来,作为优化前两层规则的依据。

4.2 优化提示词工程以获取结构化判断

要让大模型更好地为数据库“打工”,提示词必须引导它输出结构化、可解析的判断。例如,在事件关联的提示词中,我会这样设计:

你是一个AI热点分析助手。请分析以下新闻内容,并与现有事件列表进行关联。 现有事件列表: [事件1] 事件ID:001, 当前摘要:关于“某公司发布新一代AI芯片”的讨论... [事件2] 事件ID:002, 当前摘要:关于“某框架发布重大安全更新”的讨论... 待分析新闻: 标题:某公司AI芯片实测性能曝光,能效比提升50% 内容:...(略)... 请严格按照以下JSON格式输出你的分析结果: { "belongs_to_existing_event": true, // 是否属于现有事件 "event_id": "001", // 如果属于,填写事件ID;否则为null "confidence": 0.95, // 判断置信度 (0-1) "reasoning": "该新闻直接讨论了某公司AI芯片的具体性能,是事件1的后续进展。" // 简要理由 "suggested_status_update": "rising" // 建议更新的事件状态,如无需更新则为null }

这样,我的代码就可以直接解析JSON,将结果写入数据库,实现了AI判断与系统流程的无缝衔接。

4.3 成本控制与容错机制

这个项目一旦跑起来,涉及网络请求、AI API调用、数据库操作,处处都可能出错,且AI调用成本不菲。

  • 设置预算与熔断:为每个AI任务(如事件关联、摘要生成)设置独立的Token预算和月度金额上限。使用令牌桶算法进行限流。当连续出现多次网络超时或API返回错误时,触发熔断机制,暂停该任务一段时间,并发送警报。
  • 异步与重试:所有IO密集型操作(网络请求、数据库批量写入)均采用异步方式,避免阻塞主线程。对于可重试的错误(如网络抖动),实现指数退避的重试逻辑。
  • 数据一致性保障:SQLite在并发写入时需要小心。我采用了两个策略:一是对于写操作,使用with conn:上下文管理器和显式的事务;二是将不同的数据更新任务(如爬虫写入、Agent状态更新)在时间上稍微错开,减少并发冲突的概率。

5. 效果对比与项目反思

系统改造前后,效果对比非常明显:

对比维度“失忆特工”模式“有记忆助手”模式
信息去重完全无法去重,重复报告率高基于URL和内容相似度,重复率极低
事件连续性报告孤立,无法追踪进展能清晰展示事件从出现、发酵到平息的全过程
决策质量每次判断都是“初判”,容易误判基于历史信源评分、事件上下文,判断更精准
系统成本每次执行都是“从头开始”,AI调用冗余智能调度,只对新内容、状态变化内容进行深度分析,成本降低
输出价值零散的资讯列表结构化的热点事件追踪报告

5.1 踩过的坑与心得

  1. 不要过度依赖大模型做简单匹配:初期我让大模型做所有的事件关联,成本飙升且速度慢。后来将流程改为“规则过滤 -> 向量相似度 -> 大模型裁决”三层后,成本降低了70%,速度提升数倍。
  2. SQLite并发写入的坑:在多线程环境下同时写入SQLite,即使使用了WAL模式,也偶尔会遇到database is locked错误。我的解决方案是引入一个简单的任务队列,将所有数据库写操作序列化。
  3. 热点事件的生命周期管理:什么时候将一个事件标记为archived(归档)?不能只依赖时间。我结合了多个信号:关联资讯数连续N天无增长、最新关联资讯的情感倾向趋于中性、大模型综合判断事件热度已消退。这是一个需要持续调优的规则。
  4. 提示词的稳定性:同样的提示词,不同的大模型版本(如GPT-3.5与GPT-4)输出格式的稳定性不同。务必在代码中做好防御性解析,对不符合预期的输出要有降级处理方案(例如,记录日志并跳过该条,而不是让整个任务崩溃)。

5.2 未来的优化方向

目前这个系统已经能稳定运行,但还有不少可以优化的地方:

  • 向量数据库引入:当积累的资讯数量达到万级以上,在内存中计算向量相似度会成为瓶颈。考虑引入ChromaDBQdrant这类轻量级向量数据库,专门用于高效相似性检索。
  • 更复杂的Agent协作:可以将任务拆解得更细,例如由一个“调度Agent”根据事件状态决定调用“分析Agent”、“总结Agent”还是“核实Agent”,形成一个小型的多智能体系统。
  • 前端可视化:目前报告是文本形式。可以搭建一个简单的Web面板,用时间线图表直观展示热点事件的起落和关联资讯,体验会更好。

通过这个项目,我深刻体会到,一个真正有用的AI Agent,尤其是涉及持续监控和状态管理的,其核心能力往往不在AI模型本身,而在于如何设计它的记忆、思考和工作流程。数据库不再是简单的存储,而是Agent的长期记忆和思考平台;调度系统不再是简单的定时触发,而是Agent的节奏控制器。把这两者与AI的感知判断能力有机结合起来,才能打造出真正智能、实用的自动化系统。

返回列表