Paper-Essence — 教程:构建自动化论文摘要工作流
项目概览
Paper-Essence 是一个基于 Dify 平台构建的自动化论文摘要工作流。该工作流可以:
每日定时从 arXiv 获取指定研究领域的最新论文
使用大型语言模型筛选并选择最有价值的论文
使用 OCR 解析 PDF 论文以提取技术细节
生成结构化的每日摘要并通过电子邮件发送
GitHub 仓库:github.com/LiaoYFBH/PaperFlow — 您可以直接导入 prj/Paper-Essence-CN.yml 或 prj/Paper-Essence-EN.yml。
前提条件
1. 平台和账户
- Dify 账户:注册并登录 Dify
- 电子邮件账户:一个支持 SMTP 的电子邮件(本教程使用 163 邮箱)
- LLM API:配置星河社区 API
2. 安装所需插件
从 Dify 插件市场安装以下插件:
| 插件 | 用途 |
|---|---|
paddle-aistudio/ernie-paddle-aistudio |
星河社区 API |
langgenius/paddleocr |
用于 PDF 和图像的 OCR |
wjdsg/163-smtp-send-mail |
163 SMTP 邮件发送 |
langgenius/supabase |
用于已推送记录的数据库存储 |
3. 准备 Supabase 数据库
我们使用云数据库 (Supabase) 来记录已推送的论文,以避免重复。
步骤 1:登录并创建项目
访问 supabase.com 创建账户并启动一个新项目。
步骤 2:创建表
在 SQL 编辑器中,运行以下 SQL 语句来创建一个记录已推送论文 ID 的表,以确保不重复:
create table pushed_papers (
arxiv_id text not null,
pushed_at timestamp default now(),
primary key (arxiv_id)
);
步骤 3:获取 API 密钥
导航到项目设置 (Project Settings) → API 部分以查找您的凭据。
记录以下信息:
NEXT_PUBLIC_SUPABASE_URL→ Dify 插件的 Supabase URLNEXT_PUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY→ Dify 插件的 Supabase Key
步骤 4:在 Dify 中配置 Supabase 插件
在 Dify 中,前往插件市场,找到 Supabase 插件,并输入您上一步获取的 URL 和 Key。
(可选) 使用 Docker 部署 Dify
环境设置
本教程使用 WSL + Docker。您可以参考微软文档进行 WSL 和 Docker 配置。
克隆 Dify 仓库
首先,克隆 Dify 仓库。如果您尚未配置 Git,可以直接从仓库页面下载 ZIP 文件并解压。
如果您已配置 Git,请在终端中运行以下命令:
# Clone Dify repository
git clone https://github.com/langgenius/dify.git
您需要配置 Git 和 Docker。
# Navigate to docker deployment directory
cd dify/docker
# Copy environment configuration file
cp .env.example .env
首先,打开 Docker Desktop,然后在终端中输入:
# Start Dify (this will automatically pull images and start all services)
docker compose up -d
检查状态:
docker compose ps
访问应用程序:http://localhost/
工作流架构
工作流遵循以下核心流程:
计划触发器 (Schedule Trigger) → 配置 (Configuration) (代码) → LLM 翻译 (LLM trans) (llm - 翻译主题) → 获取行 (Get Rows) (工具 - 检查已推送论文) → 搜索预处理 (Search Pre-process) (代码) → HTTP 请求 (HTTP Request) (http-request) → 搜索后处理 (Search Post-process) (代码) → LLM 初审 (LLM Initial Review) (llm) → JSON 解析 (JSON Parse) (代码) → 迭代 (Iteration) (对于每篇论文:数据解包 (DataUnpack) (代码) → 创建行 (Create a Row) (工具) → 文档解析 (Document Parsing) (工具 - OCR) → 获取脚注文本 (get_footnote_text) (代码) → 截断文本 (truncated_text) (代码) → 分析 (Analysis) (llm) → 数据组装 (Data Assembly) (代码)) → 模板转换 (Template Transform) (模板转换) → 163 SMTP 邮件发送器 (163 SMTP Email Sender) (工具) → 输出 (Output) (结束)
此工作流的完整视图:
分步设置
步骤 1 — 创建工作流
- 登录 Dify
- 在工作室 (Studio) 中,点击“创建应用 (Create App)” → 选择“工作流 (Workflow)”
- 输入应用程序名称
- 选择工作流的触发器类型 (Trigger type)
步骤 2 — 配置环境变量
点击右上角的“设置 (Settings)”按钮,然后选择“添加变量 (Add Variable)”。
这些环境变量将被配置节点(一个代码节点)读取,并输出给下游节点。
关键变量:
| 名称 | 类型 | 描述 | 示例 |
|---|---|---|---|
table_name |
string | Supabase 表名 | pushed_papers |
SMTP_PORT |
string | SMTP 端口 | 465 |
SMTP_SERVER |
string | SMTP 服务器 | smtp.163.com |
SMTP_PASSWORD |
secret | SMTP 授权码 | (您的授权码) |
SMTP_USER |
secret | SMTP 用户/邮箱 | your_email@163.com |
MY_RAW_TOPIC |
string | 研究主题 | agent memory |
步骤 3 — 定时触发器
节点名称:Scheduled Trigger
配置:
- 触发频率:每日
- 触发时间:
8:59 AM(或根据需要调整)
步骤 4 — 配置(代码节点)
节点名称:Configuration(类型:code)— 此代码节点读取环境变量,处理它们,并为下游节点输出配置值。
输入变量:
- 来自环境变量:
SMTP_PORT、SMTP_SERVER、SMTP_USER、SMTP_PASSWORD、MY_RAW_TOPIC、table_name
输出变量:
raw_topic:研究主题user_email:收件人邮箱fetch_count:要获取的论文数量(默认:50)push_limit:推送限制(默认:3)days_lookback:回溯天数(默认:30)- 加上 SMTP 配置
步骤 5 — LLM 翻译(LLM 节点)
节点名称:LLM trans(类型:llm)— 将研究主题转换为针对 arXiv 优化的英文布尔查询。
模型配置:
- 模型:
ernie-4.5-turbo-128k或ernie-5.0-thinking-preview。如果您选择深度思考模型(ernie-5.0-thinking-preview),则需要启用推理格式分离。 - 温度:
0.7
提示词规则: 提取核心概念,翻译术语(如果需要),使用 AND/OR 构建布尔逻辑,将短语用引号括起来,并仅输出查询字符串。
步骤 6 — 查询已推送记录(Supabase 节点)
节点名称:Get Rows(类型:tool - Supabase 插件)— 获取已推送的 arXiv ID 以避免重复。
配置:
- 表名:
{{table_name}}(来自 Configuration 节点)
步骤 7 — 搜索论文(3 个节点)
为了提高稳定性和可维护性,搜索功能被拆分为“预处理”→“HTTP 请求”→“后处理”。
7.1 搜索预处理(代码节点)
节点名称:Search Pre-process(类型:code)— 构建 arXiv API 请求并准备搜索参数。
输入变量:
topic:翻译后的英文搜索词days_lookback:回溯天数count:要获取的论文数量supabase_output:已推送的记录(用于去重)
代码逻辑:
- 计算截止日期 (
cutoff_date) - 解析 Supabase 返回的已推送论文 ID 列表
- 根据主题构建布尔查询字符串(支持
AND/OR逻辑) - 根据主题关键词添加 arXiv 类别限制(例如,cs.CV, cs.CL)
- 提取搜索关键词用于后续过滤
输出变量:
base_query:构建的查询字符串pushed_ids:已推送 ID 列表cutoff_str:截止日期字符串search_keywords:搜索关键词列表fetch_limit:API 获取限制
7.2 HTTP 请求(HTTP 节点)
节点名称:HTTP Request(类型:http-request)— 调用 arXiv API 获取原始 XML 数据。
配置:
- API URL:
http://export.arxiv.org/api/query - 方法:
GET
7.3 搜索后处理(代码节点)
节点名称:Search Post-process(类型:code)— 解析 XML 响应并过滤论文。
输入变量:
http_response_body:HTTP 节点响应体- 加上来自预处理节点的所有输出变量
代码逻辑:
- 解析 XML 响应
- 去重过滤:移除
pushed_ids中的论文 - 日期过滤:移除早于
cutoff_date的论文 - 关键词过滤:确保标题或摘要包含至少一个搜索关键词
- 将输出格式化为 JSON 对象列表
输出变量:
result:最终过滤后的论文列表(JSON 字符串)count:最终论文数量debug:调试信息(包括过滤统计)
步骤 8 — LLM 初步审查
节点名称:LLM Initial Review(类型:llm)— 使用 LLM 对论文进行评分并选择排名前三的论文(Top 3)。
输出要求:
- 干净的 JSON 数组格式
- 保留所有原始字段
- 输出排名前三的论文
步骤 9 — JSON 解析(代码节点)
节点名称:JSON Parse(类型:code)— 容错解析 LLM 输出,将其转换为规范化的论文列表。
核心逻辑:
- 处理嵌套 JSON
- 支持
papers或top_papers字段 - 容错处理
步骤 10 — 迭代节点
节点名称:Iteration — 顺序处理每篇选定的论文(解包、记录到 Supabase、OCR PDF、使用 LLM 分析、组装最终对象)。
配置:
- 输入:
top_papers(论文数组) - 输出:
merged_paper(处理后的论文对象) - 并行模式:关闭(顺序执行)
- 错误处理:遇到错误停止
迭代内部流程
| 节点名称 | 类型 | 功能 | |
|---|---|---|---|
| 1 | DataUnpack | code | 将迭代项解包为单独的变量 |
| 2 | Create a Row | tool | 将 arxiv_id 记录到 Supabase 以防止重复 |
| 3 | Document Parsing | tool | PaddleOCR 解析 PDF 以提取文本 |
| 4 | get_footnote_text | code | 提取脚注信息(用于识别机构) |
| 5 | truncated_text | code | 截断 OCR 文本(控制 LLM 输入长度) |
| 6 | Analysis | llm | 深度分析以提取关键信息 |
| 7 | Data Assembly | code | 组装最终论文对象 |
将迭代项解包为单独的变量。
输出:
title_str:论文标题pdf_url:PDF链接summary_str:摘要published:发表日期authors:作者arxiv_id:ArXiv ID
10.2 创建行(Supabase 节点)
将论文的 ArXiv ID 记录到数据库,以防止重复推送。
配置:
- 表名:来自配置节点
- 数据:
{\"arxiv_id\": \"{{arxiv_id}}\"}
10.3 文档解析(PaddleOCR 节点)
节点名称:Document Parsing(类型:tool - PaddleOCR)
使用 PaddleOCR(非 LLM)解析论文 PDF 并通过 OCR 提取文本内容。
配置:
file:PDF URLfileType:0(PDF文件)useLayoutDetection:true(启用布局检测)prettifyMarkdown:true(美化输出)
10.4 get_footnote_text(代码节点)
从 OCR 文本中提取脚注信息,用于后续的机构识别。
10.5 truncated_text(代码节点)
截断 OCR 文本以控制 LLM 输入长度,避免超出 token 限制。
10.6 分析(LLM 节点)
节点名称:Analysis(类型:llm)
对论文进行深度分析,提取关键信息。
提取字段:
- One_Liner:一句话痛点与解决方案
- Architecture:模型架构和关键创新
- Dataset:数据来源和规模
- Metrics:核心性能指标
- Affiliation:作者机构
- Code_Url:代码仓库链接
核心原则:
- 无冗余:直接陈述具体方法
- 深入细节:总结算法逻辑、损失函数设计
- 数据优先:展示相对于 SOTA 的改进
- 无 N/A:进行合理推断
输出格式: 纯 JSON 对象
10.7 数据组装(代码节点)
节点名称:Data Assembly(类型:code)
将所有信息组装成结构化的论文对象。
核心功能:
- 解析发表状态(识别顶会论文)
- 解析 LLM 输出 JSON
- 提取代码链接
- 组装最终论文对象
输出字段:
title:标题authors:作者affiliation:机构pdf_url:PDF链接summary:英文摘要published:发表状态github_stats:代码状态code_url:代码链接ai_evaluation:AI分析结果
步骤 11 — 模板转换
节点名称:Template Transform(类型:template-transform)
使用 Jinja2 模板将论文数据转换为格式化的电子邮件内容。
模板结构:
📅 PaperEssence Daily
Based on your specified research topic "{{ raw_topic }}", here are the top 3 papers selected from ArXiv updates in recent times.
--------------------------------------------------
--------------------------------------------------
⚠️ Note: Content is AI-generated and for academic reference only. Please verify by checking the original PDF before citing or conducting in-depth research.
Date: {{ items.target_date | default('Today') }}
==================================================
{# Automatically adapt data structure #}
{% set final_list = items.paper | default(items) %}
{% for item in final_list %}
📄 [{{ loop.index }}] {{ item.title }}
--------------------------------------------------
👤 Authors: {{ item.authors }}
🏢 Affiliation: {{ item.affiliation }}
🔗 PDF: {{ item.pdf_url }}
📅 Status: {{ item.published }}
{% if item.code_url and item.code_url != 'N/A' %}
📦 Code: {{ item.github_stats }}
🔗 {{ item.code_url }}
{% else %}
📦 Code: {{ item.github_stats }}
{% endif %}
Abstract:
{{ item.summary | replace('\n', ' ') }}
🚀 Core Innovation:
{{ item.ai_evaluation.One_Liner }}
📊 Summary:
{# Use newlines and indentation for hierarchy, not relying on HTML tags #}
--------------------------------------------------
🏗️ Architecture:
{{ item.ai_evaluation.Architecture | replace('\n- ', '\n\n 🔹 ') | replace('- ', ' 🔹 ') }}
💾 Dataset:
{{ item.ai_evaluation.Dataset | replace('\n- ', '\n\n 🔹 ') | replace('- ', ' 🔹 ') }}
📈 Metrics:
{{ item.ai_evaluation.Metrics | replace('\n- ', '\n\n 🔹 ') | replace('- ', ' 🔹 ') }}
==================================================
{% else %}
⚠️ No new papers today.
{% endfor %}
步骤 12 — 发送邮件(163 SMTP)
节点名称:163 SMTP Email Sender(类型:tool - 163-smtp-send-mail)
配置:
username_send:发件人邮箱(通过 SMTP_USER 从环境变量获取)authorization_code:邮箱授权码(通过 SMTP_PASSWORD 从环境变量获取)username_recv:收件人邮箱(来自配置节点)subject:PaperEssence-{{cutoff_str}}-{{today_str}}content:来自模板转换的内容
注意:这些参数名称(username_send、authorization_code、username_recv)是 163 SMTP 插件特有的。
步骤 13 — 输出节点
节点名称:Output(类型:end)
输出最终结果用于调试和验证。
发布并获取工作流 API
在测试并确认工作流正常运行后,点击右上角的“发布”按钮。
记录以下信息:
- API 端点:
https://api.dify.ai/v1/workflows/run(用于 Dify 云部署) 或您的私有部署 URL (例如,http://localhost/v1/workflows/run) - API 密钥:
app-xxxxxxxxxxxx
替代方案:本地计划任务触发(Windows 任务计划程序)
如果 Dify 云调度在免费层级受限,您可以使用 Windows 任务计划程序通过 curl POST 触发工作流。
前提条件:安装 Git for Windows
此解决方案使用 Git Bash 执行 curl 命令,因此您需要先安装 Git for Windows(搜索“Git for Windows”下载)。
安装注意事项:
- 建议使用默认安装路径(例如,
C:\\Program Files\\Git)或自定义路径(例如,D:\\ProgramFiles\\Git) - 确保在安装过程中勾选“Git Bash Here”
配置 Windows 任务计划程序
- 按
Win + R→ 输入taskschd.msc→ 回车 - 点击“创建任务”
常规选项卡:
- 名称:
Paper-Essence Daily Run - 勾选“使用最高权限运行”
触发器选项卡:
- 点击“新建”
- 选择“按计划”
- 选择“每天”,设置时间(建议与 Dify 工作流定时器匹配,例如
20:55) - 点击“确定”
操作选项卡:
-
点击“新建”
-
操作:“启动程序”
-
程序/脚本:输入您的 Git Bash 路径,例如:
D:\ProgramFiles\Git\bin\bash.exe或默认安装路径:
C:\Program Files\Git\bin\bash.exe -
添加参数:使用 curl 命令 POST 到您的工作流 API 端点,并附带您的 API 密钥
注意:请将 API 端点和密钥替换为上一步中的实际值
条件选项卡(可选):
- 您可以取消勾选“只有在计算机使用交流电源时才启动任务”,以确保笔记本电脑在电池供电时也能运行任务
设置选项卡(可选):
- 勾选“如果任务失败,每隔”并设置重试间隔
- 点击“确定”保存任务
测试与调试
手动测试
- 在工作流编辑器中点击“运行”(右上角)
- 观察节点执行和输出
- 验证每个节点的输出是否符合预期
成功结果
当工作流成功执行后,您将收到一封包含每日论文摘要的电子邮件。
总结
本教程涵盖了构建一个完整的端到端管道:ArXiv 抓取 → PaddleOCR 解析 → LLM 分析 → Jinja2 模板化 → SMTP 投递,并结合了基于 Supabase 的去重和调度功能。该工作流涉及 YAML 节点配置、环境变量和 Supabase 集成,创建了一个从 ArXiv 检索到电子邮件投递的综合管道,并增强了去重和错误处理能力。
提供的 prj/Paper-Essence-CN.yml 和 prj/Paper-Essence-EN.yml 可以导入到 Dify 工作区以复现该工作流。
致谢
特别感谢 Alex Zhang、Guan Mu 和 Yang Youzhi 的指导。