最近突然有个想法,要素如下:
① 想了解下我研究的领域的研究现状,并持续追踪;
② 但是我不想花太多时间阅读全文,想看看全文的简介;
③ 实现上面的设想,往往需要:自己点开相关网站 → 下载论文 → 把论文文件给LLM → LLM返回内容 ;
④ 但是这种手动方案太累,太麻烦,还很容易忘记自己以前看没看过了(因为只是看看简介,数量一多,记忆不深了);
⑤ 所以萌生了一个想法:用Dify设计一个AI Workflow,每天自动给我一个文档,文档包含论文各方面的简介,且论文不会重复
于是搭建了下面的工作流,如图:

下面介绍下每一步的配置。
Ⅰ 准备本地接收环境
一切的基础是能够接收最终远端传来的数据并写入 Markdown 文件。
解释下:之所以我没有想用一些发邮件、企微的方式来“收件”,主要是觉得这些对markdown渲染不好,而我自己电脑配置了quicklook,很方便看markdown文件。
1. 创建接收脚本
我在 D:\AI_Security_Papers 目录下新建 receiver.py,完整代码如下:
import os
import datetime
import json
from flask import Flask, request, jsonify
app = Flask(__name__)
SAVE_DIR = r"D:\AI_Security_Papers"
HISTORY_FILE = os.path.join(SAVE_DIR, "history.txt")
os.makedirs(SAVE_DIR, exist_ok=True)
if not os.path.exists(HISTORY_FILE):
open(HISTORY_FILE, 'w', encoding='utf-8').close()
@app.route('/get_history', methods=['GET'])
def get_history():
with open(HISTORY_FILE, 'r', encoding='utf-8') as f:
return jsonify({"history": f.read().splitlines()})
@app.route('/save_papers', methods=['POST'])
def save_papers():
markdown_content = request.form.get('content', '')
paper_ids_str = request.form.get('paper_ids', '[]')
try:
new_paper_ids = json.loads(paper_ids_str)
except Exception:
new_paper_ids = []
if not markdown_content:
return jsonify({"status": "error", "msg": "没有接收到正文内容"}), 400
# 1. 保存 Markdown 文件
date_str = datetime.datetime.now().strftime("%Y-%m-%d")
file_path = os.path.join(SAVE_DIR, f"{date_str}_论文研判总结.md")
with open(file_path, 'w', encoding='utf-8') as f:
f.write(markdown_content)
# 2. 更新历史记录库
with open(HISTORY_FILE, 'a', encoding='utf-8') as f:
for pid in new_paper_ids:
f.write(f"{pid}\n")
return jsonify({"status": "success", "file": file_path})
if __name__ == '__main__':
app.run(port=5000)
2. 启动
记得配环境,我这里把相应的包都放到一个名为 myenv 的conda环境里了:
conda activate myenv
cd D:\AI_Security_Papers
python receiver.py
Ⅱ 配置 ngrok 固定域名
这一步是因为,如果是云端的dify,云端必须通过公网才能找到我的电脑,所以需要一个域名;
如果是本地部署的dify,可以不用这一步,直接在后面填url的时候用host.docker.internal跳出容器就可以;
但我虽然是本地部署的dify,还是用ngrok了,原因很简单:我最开始求助LLM的时候它以为我要用云dify。。
但是呢,用ngrok也更稳定嘛,毕竟说不定host.docker.internal会有一些防火墙策略啥的拦截,还得费劲去调
1. 下载+注册
- 浏览器访问 ngrok 官网 并注册一个免费账号。
- 登录后,在左侧菜单找 Setup & Installation,下载 Windows 版本的
.zip包。 - 解压后得到一个
ngrok.exe,为了方便,拖进D:\AI_Security_Papers文件夹。
2. 绑定账号与获取固定域名
- 在 ngrok 后台页面找到一行以
ngrok config add-authtoken开头的命令。 - 打开一个全新的命令行窗口(不要关掉刚才跑 Flask 的那个),进入文件夹并粘贴运行这行命令:
cd D:\AI_Security_Papers
ngrok config add-authtoken 每个人的专属长串秘钥
- 在 ngrok 网页后台左侧菜单找到 Domains。ngrok 会免费赠送一个永久固定的静态域名(例如 xxx.ngrok-free.dev`),把它复制下来。
3. 启动隧道
继续运行 ngrok xxx.ngrok-free.dev 5000,此时 5000 端口对公网开放了。
保持这两个黑窗口运行,我们去配置 Dify
Ⅲ Dify 工作流搭建
如果不想折腾本地部署Dify,可以直接用云Dify;
我没用云Dify,主要是觉得免费次数有限;
本地部署Dify需要先有docker,其次按照Dify在Github上的教程(其实也就一行命令);
没docker直接整个docker desktop先,此处略过~
1. 初始化工作流
打开 Dify(无论是本地 Docker 版还是云端版),
点击 工作室 (Studio) → 创建空白应用 → 选择 工作流 (Workflow),起名叫“每日论文研判”
2. 依次配置 6 个节点
在画布上,点击右侧的 + 号依次添加并串联以下节点
(1)定时触发器 (Timer)
看心情,我设为每天 14:00 运行。
(2)HTTP 请求 1:读取历史记录 (HTTP Request)
- 节点描述:
Get_History - API 接口:
GET - URL:
https://[你的ngrok固定域名]/get_history - Headers:点击添加参数,Key 填
ngrok-skip-browser-warning,Value 填true
(3)HTTP 请求 2:抓取最新论文 (HTTP Request)
我们这里用的Semantic Scholar是由艾伦人工智能研究所于2015年推出的一款免费且非营利性的学术搜索引擎,它主要利用人工智能和自然语言处理技术来深度解析科学文献。与传统的基于关键词匹配的学术搜索工具不同,该平台能够理解论文的上下文和语义关联,自动提取文章中的关键发现、图表、引用背景以及核心研究方法,并能为长篇论文生成高度精炼的摘要。目前其数据库已经涵盖了计算机科学、系统安全、医学等众多学科领域的数亿篇文献,其核心宗旨是通过智能化的数据挖掘手段缓解科研人员的信息过载问题,帮助学者更高效地检索跨出版商的高价值文献、评估论文的真实影响力以及追踪相关领域的学术前沿动态。
- 节点描述:
Fetch_Papers - API 接口:
GET - URL:
https://api.semanticscholar.org/graph/v1/paper/search - Params:
query:("AI security" OR "system security" OR "LLM security")fields:paperId,title,abstract,authors,year,openAccessPdf,citationCountlimit:30publicationTypes:JournalArticle,Conference

(4)代码执行
- 输入变量:
history_data-> 绑定前置Get_History节点的bodypaper_data-> 绑定前置Fetch_Papers节点的body
- 输出变量:
final_papers,类型选Stringpaper_ids,类型选String
- Python3 代码:
import json
def main(history_data: str, paper_data: str) -> dict:
# 1. 解析历史数据(增加容错处理)
try:
history_resp = json.loads(history_data)
history_ids = set(history_resp.get("history", []))
except Exception:
history_ids = set()
# 2. 解析新抓取的论文
try:
papers_resp = json.loads(paper_data)
all_papers = papers_resp.get("data", [])
except Exception:
all_papers = []
candidate_papers = []
for p in all_papers:
pid = p.get("paperId", "")
# 如果论文ID已经在历史记录里,或者没有ID,直接跳过
if pid in history_ids or not pid:
continue
abstract = p.get("abstract")
if not abstract or len(abstract) < 100:
continue
score = 0
if p.get("openAccessPdf"): score += 5
score += min(p.get("citationCount", 0), 10)
p["quality_score"] = score
candidate_papers.append(p)
# 按质量得分降序排序
candidate_papers.sort(key=lambda x: x.get("quality_score", 0), reverse=True)
# 取前5篇
top_5 = candidate_papers[:5]
# 提取这5篇的新ID
top_5_ids = [p["paperId"] for p in top_5]
return {
"final_papers": json.dumps(top_5, ensure_ascii=False),
# 这里加上 json.dumps,把它变成字符串输出
"paper_ids": json.dumps(top_5_ids)
}

(5)大模型
- 选LLM:这个各自自己配置好了,每个人用的服务来源都不一样。设置位置:右上角头像 → 设置 → 模型供应商
- 输入变量:设置
papers_json,绑定上一步代码的final_papers - System Prompt (系统提示词):
你是一个顶尖的系统安全与AI安全研究员(常年参与CTF比赛、漏洞挖掘实战、源代码或二进制漏洞检测实战、及USENIX Security、CCS、IEEE S&P、TDSC等安全或软工顶刊顶会)。请根据输入的 JSON 格式论文列表,严格遵循以下 Markdown 格式输出深度总结。
【最高指令】:绝对不要有任何废话、寒暄或解释性开头结尾;语言极度冷峻、精炼、硬核、全面且详细。
# 🛡️ 今日 AI 与系统安全前沿论文研判总结
## 一、 {论文1的完整英文名称}
**译名**:{论文1的中文翻译名称}
**📅 年份**:{year} | **🔗 引用量**:{citationCount}
### 1. 核心工作简介
{用结构清晰的语言极度精炼但详细地概括本文的核心技术方案与系统架构}
### 2. 研究动机
{分点叙述:作者旨在解决什么具体的系统缺陷或安全痛点?}
### 3. 核心贡献
{列出2-3点硬核学术贡献,必须提取具体的算法名、框架名、或发现的新型漏洞/CVE面}
### 4. 实验与评测基线
{一句话描述:在什么数据集/真实环境下,对比了什么Baseline,提升或降低了多少核心指标?若无具体数据则简写}
### 5. 开源与数据集情况
{如果摘要中明确提及了GitHub链接或公开数据集,请提取;如果完全未提及,**仅输出“未提及”三个字,绝对禁止任何废话与解释**。}
### 6. 实战攻防研判 (重点)
{请从红蓝对抗、逆向工程、渗透测试或大模型Agent越狱等实战视角,给出极具穿透力的评价。绝对不要写“建议企业关注”等水词。必须围绕以下维度展开(一两句话即可):
- **攻击面暴露**:该研究是否揭示了新的利用链、投毒手法或侧信道?
- **防护绕过**:其提出的防御机制在实战中是否存在明显的局限性?是否容易被对抗样本或特定手段绕过?
- **工程转化率**:其工具或方法论能否直接转化为自动化的漏洞挖掘脚本或安全测试工具?}
---
## 二、 {论文2的完整英文名称}
(以此类推,必须完整输出传入的5篇论文总结,保持高信息密度!)
处理以下论文数据:
{
}}
注意:在提示词最后的{}绑定之前的代码节点给出的final papers!

(6)HTTP 请求 3:投递本地落盘 (HTTP Request)
- 节点描述:
Save_To_Local - API 接口:
POST - URL:
https://[你的ngrok固定域名]/save_papers - Headers:Key 填
ngrok-skip-browser-warning,Value 填true。 - Body:选择
form-data选项。- 键名:
content,类型:text,值:选择 LLM 节点的输出文本变量{{#LLM.text#}} - 键名:
paper_ids,类型:text,值:选择代码节点的输出变量{{#Code.paper_ids#}}

- 键名:
Ⅳ 手动测试+VBS自启动
1. 手动测试
建议点击右上角的“发布”之前,自己点击“测试运行”看一遍(其实更建议右键节点,选择“运行此步骤”,一个一个看一下是否如预期执行);
测试的时候别忘了我们后台运行着两个终端,一个跑接收的python脚本,一个运行ngrok;
2. 自动化
由于每次开机都要手动开两个黑窗口太繁琐,在确保前面所有步骤 100% 成功后,我进行了一个 VBS 静默化改造:
- 关闭之前手动打开的两个终端窗口。
- 在
D:\AI_Security_Papers下新建一个文本文件,命名为silent_start.vbs。 - 填入以下代码,替换为实际的系统路径和 ngrok 域名:
Set WshShell = CreateObject("WScript.Shell")
' 1. 隐藏启动 Python 接收服务
WshShell.Run "cmd /c call D:\anaconda\Scripts\activate.bat myenv && cd /d D:\AI_Security_Papers && python receiver.py", 0, False
' 2. 等待 3 秒钟确保服务起来
WScript.Sleep 3000
' 3. 隐藏启动 ngrok 内网穿透
WshShell.Run "cmd /c cd /d D:\AI_Security_Papers && ngrok http --domain=你的固定域名.ngrok-free.dev 5000", 0, False
- 按
Win + R键,输入shell:startup回车,打开系统的“启动”文件夹。 - 回到代码目录,按住 Alt 键 将
silent_start.vbs拖动到启动文件夹,创建一个快捷方式。 - 最后在 Dify 页面右上角点击”发布“就ok了
其实这样也得保证俩前提:电脑一直开着、docker一直运行着,不然也没办法自动把文件生成下来。
但设置了docker开机自启,其实也还行?毕竟下午两点怎么也到工位了qwq
如果实在觉得这样很不自动化,那就用云Dify得了。
Ⅵ 结果&结语
1. 结果
生成的文档:

感觉还行吧,不过引用量怎么都是0?算了不管了,文献是真的就行。
下面这个history.txt就是生成的用于去重的文件:

2. 结语
还是有很多不足之处的!我也是第一次玩这个,也是因为有个现实需求(伪,因为后面好像也不怎么主动看)所以搭建的。
后面有时间再玩喽!