电商每日精选选品简报系统(多Agent)
基于 LangGraph 构建的主动式选品推送 Agent——每天自动跑完全链路,推送精选简报到运营面前,运营只需 10 分钟复核确认。
项目概览
| 要素 | 内容 |
|---|---|
| 项目周期 | 2025.10 - 2026.05 |
| 核心技术 | LangGraph / DeepSeek / ReAct / ChromaDB / SQLite / MCP |
| 角色 | 独立负责架构设计、Agent 编排、记忆系统实现 |
| 核心成果 | 运营选品耗时从 1~2 小时压缩至 10 分钟复核 |
项目背景
电商运营团队每天需要完成选品简报编排全流程——从新品池筛选候选、人工对比库存和销量做排序决策、到撰写结构化简报文案并推送至决策层。纯人工操作约 1~2 小时,且选品标准依赖个人经验,不同运营人员结果差异大。
核心挑战
- 效率瓶颈:每天 1~2 小时选品,运营时间被重复劳动消耗
- 标准不一:选品标准依赖个人经验,不同运营结果差异大
- 重复推荐:跨批次重复推荐率高,运营看到熟悉商品体验差
- 偏好难量化:运营的个人偏好无法沉淀到系统里,换人就归零
核心转变是从"运营主动找商品"到"系统主动推商品"——不是简单做自动化,而是构建具备自主决策、记忆学习、持续进化能力的 Agent。
核心架构:五层设计
整个系统采用五层架构设计,从触发到输出逐层推进,每一层职责清晰。
┌─────────────────────────────────────────────┐
│ 第五层:输出层 │
│ Streamlit 仪表盘 / MCP 推送 / 历史回顾 │
├─────────────────────────────────────────────┤
│ 第四层:记忆系统层 │
│ SQLite(情节记忆)+ ChromaDB(长期记忆) │
│ 运营偏好向量 + feed_items 历史向量 │
├─────────────────────────────────────────────┤
│ 第三层:子Agent执行层 │
│ 采集 Agent → 排序 Agent → 简报 Agent │
│ 反馈 Agent(独立入口) │
├─────────────────────────────────────────────┤
│ 第二层:大脑决策层 │
│ LangGraph StateGraph 8节点编排 │
│ 理解→规划→路由→执行→观察→审查→推送→记忆 │
├─────────────────────────────────────────────┤
│ 第一层:输入层 │
│ 定时触发 / 手动触发 / 爆款预警(排序阶段触发) │
└─────────────────────────────────────────────┘第一层:输入层
系统有两种触发入口,第三种"爆款预警"不是独立监控,而是排序阶段的加速路径——同一个执行流程里,某个商品分数异常高就直接推。
- 定时触发:每天早上 8 点,APScheduler CronTrigger 自动启动全链路
- 手动触发:运营通过 Streamlit 管理后台随时启动,大促前夕临时跑一轮
- 爆款预警:排序 Agent 打出的分数 >0.85 时,Planner 自动设
push_immediate=true,直接推送高分商品,不等完整简报生成
三种触发方式背后对应的是同一个 LangGraph 编排流程,只是执行路径不同。
第二层:大脑决策层(LangGraph 8 节点编排)
触发之后进入最核心的大脑决策层,基于 LangGraph StateGraph 搭了 8 个节点,按职责拆解每一个决策环节。
节点 1:understand_selection(理解选品目标)
LLM 读取本次选品目标,提取 structured_selection 结构化参数,同时生成对应的 selection_embedding 向量,用于后续候选商品的相似度匹配。这一步是把"运营想要什么"变成系统能处理的结构化指令。
节点 2:planner(ReAct Think)——读记忆辅助决策
这是 ReAct 循环的起点。Planner 不是凭空生成执行计划,而是先去 SQLite 查近 7 天执行日志、去 ChromaDB 查历史相似场景,让 LLM 在"历史记忆"的辅助下生成 sub_agent_plan。
如果排序 Agent 输出中出现了 score>0.85 的高评分商品,Planner 自动设置 push_immediate=true,进入破例推送路径——不等到完整简报生成,高分商品优先推。
节点 3:router_node(路由决策)
Router 接收 planner 输出的执行计划,决定下一步激活哪个子 Agent。路由采用"规则优先 + LLM 兜底"的策略:
- 规则优先:常见场景(候选不足→扩采、排序不够→重排)用规则毫秒级判断
- LLM 兜底:边界场景(语义判断、因果推理、多异常根因分析)交给 LLM
防死循环机制:max_turns=5,连续 5 次路由到相同策略节点时强制收敛,走硬兜底输出当前最优结果。
节点 4:invoke_sub_agent(调度子 Agent)
Router 决策完成后,按固定顺序调度三个子 Agent:采集 Agent → 排序 Agent → 简报 Agent。顺序固定是因为排序依赖采集结果、简报依赖排序结果。
节点 5:observe_results(结果观察)
三个子 Agent 各自完成后,observe 节点对采集/排序/简报的质量做结构化评估——候选数量够不够、排序分布是否合理、简报内容是否完整。
节点 6:coordinator_reflect(综合审查)
大脑层的质量门卫。Reflect 节点综合审查:去重是否彻底、简报内容是否有矛盾、完整性是否达标。如果 overall_pass=false,说明某个环节质量不达标,退回 planner 重新规划一轮——这就是 ReAct 循环的核心:感知结果→决定是否重试→调整策略。
节点 7:push_notification(推送通知)
两种推送路径:
- 正常路径(
overall_pass=true):等完整简报生成后推送 - 破例路径(
push_immediate=true):排序阶段发现高分商品,跳过完整简报直接推
两种路径都通过 MCP stdio 推送。
节点 8:update_memory(写入记忆)
全链路执行完成后,三路径并行写入:
- SQLite 写执行日志(情节记忆)
- ChromaDB 写 LLM 摘要(长期记忆)
- ChromaDB 写历史向量(feed_items,用于下次预过滤去重)
保证"越用越懂你"的正向循环。
第三层:子 Agent 执行层
三个子 Agent 是大脑层调度的执行单元,各自都是一个小型的 ReAct 循环。
采集 Agent(Selection Agent)
负责从商品库、热销数据中采集候选商品。关键设计是向量预过滤——采集前先去 ChromaDB 的 feed_items 历史向量库查一下,把历史上已经推荐过的商品排除掉,避免重复推荐。
进入采集阶段后,也有自己的 ReAct 循环:fetch_products 获取基础数据,如果不够就 search_web 补充外部信息(市场热度、竞品对比)。
排序 Agent(Rank Agent)
接收采集 Agent 输出的候选池,做向量去重和多因子排序。
两级去重:
- 采集阶段预过滤(批次间去重,100% 确定)
- 排序阶段向量去重(批次内去重,0.88 阈值)
四维评分公式:
final_score = w1·商品匹配度 + w2·新品时效性 + w3·(运营偏好+feedback_bias) + w4·商品热度- 冷启动权重:0.40 / 0.25 / 0.10 / 0.25(商品匹配度主导)
- 有反馈权重:0.30 / 0.20 / 0.40 / 0.10(运营偏好主导)
隐式偏好机制:从历史 top3 选中商品的向量里提取隐式偏好信号,加到排序权重里——即使运营没有显式反馈,系统也能从行为中学习偏好。
当某个商品的 final_score 超过 0.85 时,Planner 自动设 push_immediate=true,进入破例推送路径。
简报 Agent(Briefing Agent)
负责把排序结果生成结构化简报文案。内部有重试机制:最多重试 2 次,生成后做质量评分,不合格自动重新生成。
质量评分三维度:
- 准确性(0.3):商品描述是否准确
- 相关性(0.4):推荐理由是否充分
- 连贯性(0.3):格式是否规范
反馈 Agent(Feedback Agent)
独立于主流程——用户在 Streamlit 上对简报里的商品点"收藏"或"跳过",反馈 Agent 接收这个信号,用 EMA(α=0.3)更新运营偏好向量 v_like(正向偏好)和 v_dislike(负向偏好),写入 ChromaDB 供排序 Agent 下次读取。
第四层:记忆系统层(双层架构)
记忆系统是这套系统的"学习引擎",采用 SQLite + ChromaDB 的双层架构。
| 记忆类型 | 存储 | 内容 | 查询方式 |
|---|---|---|---|
| 情节记忆 | SQLite WAL | 近7天执行日志(触发时间/采集数量/排序结果/推送状态) | SQL 精确查询 |
| 长期记忆 | ChromaDB | LLM 生成 200 字执行摘要 | 语义向量检索 |
| 偏好记忆 | ChromaDB | v_like / v_dislike 偏好向量 | 向量相似度匹配 |
| 条目历史 | ChromaDB feed_items | 已推荐商品 SHA256+向量 | 向量预过滤 |
SQLite 用 WAL 模式是因为系统有并发写入(定时触发+手动触发可能同时发生),WAL 模式保证读写不互锁。
第五层:输出层
- Streamlit 选品仪表盘:结构化简报 + 评分构成 + 偏好匹配度,运营一键浏览+标注收藏/跳过
- 推送通知:正常简报 / 破例推送双路径,MCP stdio
- 历史回顾:历史选品记录 + 反馈数据 + 转化数据,为 Badcase 分析提供素材
核心成果
| 指标 | 数值 |
|---|---|
| 运营选品耗时 | 1~2 小时 → 10 分钟复核 |
| 跨批次去重率 | 92%+ |
| 偏好学习命中率提升 | 30% |
| ReAct 循环轮次 | 最多 3 轮 |
| 爆款预警 | 排序阶段 score>0.85 实时触发 |
| 向量去重阈值 | 0.88(通过阈值扫描实验确定) |
| EMA 衰减因子 | α=0.3(实验平衡响应速度与稳定性) |
关键技术决策
为什么选 LangGraph 而不是其他框架
| 框架 | 强项 | 本项目不选原因 |
|---|---|---|
| LangChain LCEL | 管道式数据处理,简单快速 | 不支持循环,无法实现 ReAct |
| AutoGen | 对话式多 Agent,角色互相协商 | 选品是父子编排,不是平等对话 |
| CrewAI | 角色定义直观,上手快 | 编排能力弱,无细粒度状态管理 |
| 自研状态机 | 完全可控,无依赖 | 工程量大,无 ReAct 原生支持 |
LangGraph 的 StateGraph + Conditional Edge + Checkpointing 三件套,刚好覆盖了父子编排、动态路由、断点恢复三大核心需求。
0.88 这个阈值怎么来的
做了阈值扫描实验:从 0.80 到 0.95 每隔 0.01 采样,计算每个阈值下去重率和误杀率。0.88 是两条曲线的交叉平衡点——低于则误杀率上升(把不同商品判为同款),高于则去重率下降(放过同款变体)。中间区(0.75~0.88)向量相似度无法准确判断,加 LLM 裁决兜底。
EMA α=0.3 怎么确定的
测试了五个值:0.1、0.2、0.3、0.5、0.7,观察连续反馈下偏好向量的演化轨迹:
- α 越大(0.5+):偏好变化越快但波动越大——一次连续点赞数码类会让偏好突然偏向数码
- α 越小(0.1):偏好太平稳,跟不上运营的动态偏好变化
- α=0.3:"响应速度"和"稳定性"的平衡点
Embedding 模型为什么选 bge-small-zh-v1.5
选品场景只需要中文短文本(商品标题 10~30 字)的语义编码,不需要多语言、不需要长文本能力。BGE-M3 是 1024 维,bge-small 只有 384 维——维度越小,存储和检索越快,内存占用越低。在商品标题短文本场景下,两者语义区分力差距很小,但效率差距明显。
选型原则是最小够用——能用 384 维解决的不用 1024 维。
遇到的挑战与解决方案
挑战一:ReAct 循环死循环
问题:最初的 ReAct 只有"观察→判断→重试"逻辑,没有上限。测试时发现 Agent 在候选不足时反复尝试扩采,每次策略相似,不断在同一个坑里跳。这是自主性与稳定性之间的矛盾——给 Agent 越大自主空间,越容易在边界场景下失控。
解决:双层收敛机制
- 软收敛:ReAct 最多 3 轮(实验确定的收益-成本最佳平衡点)
- 硬兜底:
max_turns=5,连续 5 次路由到相同策略节点强制收敛,输出当前最优结果 - 路由振荡防护:5 轮以上会出现策略间来回跳的情况,效果反而下降
调试花了约两周,核心收获是:给 Agent 自主性的同时必须设清晰边界,自主性不是无限自由。
挑战二:向量去重阈值怎么定
问题:一开始拍脑袋设了 0.90,上线后两个问题:误杀率偏高(不同商品被判为同款,推荐品种变少)和去重率偏低(同款不同链接漏掉)。
解决:阈值扫描实验 + LLM 裁决中间区
- 从 0.80 到 0.95 每隔 0.01 采样
- 计算每个阈值下的去重率和误杀率
- 找两条曲线的交叉平衡点 → 0.88
- 中间灰色地带(0.75~0.88)加 LLM 裁决兜底
挑战三:偏好学习冷启动
问题:系统刚上线时没有任何运营反馈,排序完全靠商品匹配度和时效性,第一批简报质量不可控。
解决:双轨偏好机制
- 显式偏好:运营给出收藏/跳过反馈后,EMA 更新
- 隐式偏好:从历史 top3 选中商品的向量里提取偏好信号
- 冷启动阶段用隐式偏好做弱信号,有反馈积累后逐步切换到显式
top3 是已被运营"默认接受"(没有跳过)的商品,这个信号虽弱但有方向性。
挑战四:系统响应时间长
问题:最初设计的系统运行整个管道至少需要三分钟。通过日志分析发现,API 调用次数高达 40 次以上,其中去重 LLM 裁决每一条信息都调用一次 API,导致响应耗时大幅增加。
(具体优化措施在后续迭代中持续推进)
技术选型说明
| 组件 | 选型 | 备选 | 选型理由 |
|---|---|---|---|
| 编排框架 | LangGraph | LCEL / AutoGen | 支持循环 + 状态图 + 检查点 |
| 推理模型 | DeepSeek v4-flash | GPT-4 | 中文电商效果持平,成本仅几十分之一 |
| Embedding | bge-small-zh-v1.5 | BGE-M3 | 短文本 384 维够用,效率更高 |
| 向量库 | ChromaDB | Milvus | 轻量、部署简单,适合单机场景 |
| 结构化存储 | SQLite WAL | MySQL | 并发不高,WAL 够用且运维为零 |
| 推送协议 | MCP stdio | Webhook / 消息队列 | 与 Agent 框架无缝集成 |
| 后台界面 | Streamlit | 自研前端 | 快速搭建,内部工具够用 |
项目价值与意义
这套系统的本质转变是从"运营主动找商品"到"系统主动推商品"——不是简单做自动化,而是构建了一个具备自主决策、记忆学习、持续进化能力的 Agent。
从技术能力维度,这个项目完成了从"调用 LLM API 做功能"到"用 LLM 作为大脑构建自主系统"的跨越:
- 模型能力 → 系统能力:从单模型调用到多 Agent 编排
- 单次执行 → 持续学习:从孤立运行到记忆系统驱动进化
- 被动工具 → 主动推送:从等用户来到主动找用户
这是从 AI 工具使用者到 AI 系统设计者的关键一步。