每日自动抓 arXiv + HuggingFace 新论文,按个人研究方向筛选后推送到飞书群,支持按需生成深度阅读报告(飞书文档)、按主题调研、对话式编辑报告、@bot 发链接即读。
研究画像、关键词、筛选阈值全部在 config.py 配置;LLM 走 claude CLI(Max 订阅),全程只走你允许的出口 IP。
首次使用前先读 FEISHU_SETUP.md(飞书应用怎么建、要哪些权限、订阅哪些事件) 不用 Claude Max 订阅 / 想换成 OpenAI Codex 等其它 LLM 后端:见 LLM_BACKEND.md
cd paper_assistant
# 1. 每日管道(默认昨天 UTC)— 自己机器上挂 cron 每天跑
python main.py
python main.py --date 2026-04-20 # 指定日期补跑
python main.py --dry-run # 只筛选,不推飞书
python main.py --no-listen # 跑完退出,不起 WebSocket
# 2. 单篇精读
python run_one_paper.py 2602.15763 # 给 arxiv id,全流程走一遍
# 3. 主题调研(覆盖最近 5 年相关论文)
python survey.py "world knowledge" # 互动选画像,推 top-K 到群
# 4. 对话式编辑已有飞书报告
python chat.py 2602.15763 # 进 claude REPL,自然语言改报告
# cron 后台托管(已挂 11:00 每天)
bash run_daily.sh # 手动触发一次(同 cron 行为)流程:抓 arXiv+HF → 关键词粗筛(阈值 5)→ Claude Sonnet 精筛(阈值 7)→ 推飞书群卡片 + Bitable → 起 WebSocket 监听回调。
cron:已注册每天 11:00 (SGT+8) 跑 run_daily.sh。查看:
crontab -l # 查看已注册
tail -20 logs/cron.log # 查看启动日志
tail -50 logs/daily.log # 查看流水线输出run_daily.sh 启动前会杀掉上一个同目录的 python main.py,然后 nohup 启新进程,保证常驻监听回调。
python run_one_paper.py <arxiv_id>跳过筛选,直接:入库 → 推 Bitable → 标收藏 → 生成深度报告(约 2 分钟)→ 建飞书文档 → 群通知。适合你已知 arxiv id 想立即读的场景。
日常管道推到 Bitable 的论文,勾上"收藏"字段,系统自动生成报告。两条触发路径并行:
- WebSocket 实时回调(
callback_server.py,main.py内启动)——点击/勾选立即触发 - 轮询兜底(
watcher.py,每 5 分钟扫一次)——进程意外重启后也不漏
独立起轮询(一般不需要,main.py 已够):
python watcher.py # 5 分钟循环轮询
python watcher.py --once # 扫一次就退群里直接 @ 机器人 + 发一个 arxiv 链接/ID,机器人自动触发精读:
@<your-bot> 2510.01174
@<your-bot> https://arxiv.org/abs/2511.12345 这篇方法怎么样
@<your-bot> arxiv.org/pdf/2602.15763v2.pdf
机器人会:
- 识别到 → 立即回复「📖 收到 xxx,正在分析(约 2 分钟)...」
- 已读过 → 回复「📄 这篇之前已经读过了:」去重
- 正在读 → 回复「⏳ xxx 正在分析中,稍等几分钟」
- 识别不到 ID → 回复「🤔 没识别到 arXiv ID」
前提:飞书应用要订阅 im.message.receive_v1 事件(已配)。私聊也支持,无需 @。
不止看"最新",覆盖某个领域的过往 5 年精选:
python survey.py "world knowledge" # 5 年,30 篇候选,top 10 入库
python survey.py "robot manipulation" --years 8
python survey.py "video diffusion" --top-k 15 --max-papers 50
python survey.py "llm reasoning" --auto # 跳过画像选择,用候选 A流程:
- Claude 生成 3 个侧重不同的候选画像+关键词(例如"世界知识"可以生出"LLM 知识存储与编辑"/"知识增强生成"/"多模态世界知识理解")
- 终端提示你选 A/B/C 或自己输入
- Semantic Scholar 检索(有引用数,能涵盖"经典")→ arxiv 兜底
- Sonnet 打分 → top-K 入库 + 推飞书群一张汇总卡片
- 不自动生成报告——挑感兴趣的再触发(@bot 或 Bitable 勾选)
可选:申请 Semantic Scholar API key(30 秒)放进 .env:export SEMANTIC_SCHOLAR_API_KEY="xxx",可免限流。
启动一个 claude 交互终端,飞书文档当前内容已预先注入 system prompt,你用自然语言提修改需求,claude 原地 lark-cli docs +update 改飞书文档:
python chat.py 2602.15763 # arxiv id → 自动查 user_marks 里的 doc URL
python chat.py https://www.feishu.cn/docx/xxx # 直接给飞书 URL
python chat.py 2602.15763 --with-paper # 加 arxiv 全文进 prompt(~15k tokens)对话示例:
> 当前「三句话说清这篇」太简略了,扩展成 6 条关键贡献点
> 在「方法」章节后面插入一个比较 DSA vs MLA 的表格
> 「不足」段改成更中立的措辞
Claude 每次要 lark-cli 改文档会弹出 Bash 确认(Claude Code 默认),避免乱动;同意一次可选 always allow。
三要素都在 config.py:
| 项 | 作用 | 改动成本 |
|---|---|---|
RESEARCH_PROFILE |
自然语言描述研究兴趣,喂给 Claude 精筛 | 最轻,直接改文字 |
KEYWORDS |
加权关键词列表(粗筛用) | 改列表 |
ARXIV_CATEGORIES |
arXiv 类目白名单(决定抓取池) | 改数组 |
临时扫某个不同领域(不想动日常配置):
cp config.py config.py.bak
# 编辑 config.py → 换成目标领域关键词和 profile
python main.py --date 2026-04-21 --dry-run # 预览筛选结果
python main.py --date 2026-04-21 # 确认无误后正式推
mv config.py.bak config.py # 恢复必须存在且可用:
- Python 3.12+ 和
requirements.txt里的包(arxiv、lark-oapi、PyMuPDF、beautifulsoup4、requests) claudeCLI(Max 订阅,无需 API key)lark-cli(@larksuite/cli,npm install -g,负责 markdown 导入飞书文档 + 图片插入)- 网络代理(可选):如果你机器访问 claude/lark-cli/HuggingFace 需要走代理,在
run_daily.sh里设http_proxy/https_proxy环境变量 - cron 守护进程(
/usr/sbin/cron,已手动启动;机器重启后需要重新cron启动)
.env 关键变量(本地 gitignored):
FEISHU_APP_ID # 飞书应用 ID
FEISHU_APP_SECRET # 飞书应用 Secret
FEISHU_BITABLE_APP_TOKEN # 多维表格 app_token
FEISHU_BITABLE_TABLE_ID # 多维表格 table_id
FEISHU_REPORT_FOLDER_TOKEN # 报告落地文件夹(留空则进 bot 默认空间)
FEISHU_BOT_RECEIVE_ID_TYPE # "chat_id" 或 "open_id"
FEISHU_BOT_CHAT_ID # 接收消息的群/人 ID
ALLOWED_OUTBOUND_IP # 调 claude 前强校验的出口 IP;留空则禁用此门
SEMANTIC_SCHOLAR_API_KEY # 可选;survey.py 不填则免费共享池易限流飞书应用需要订阅的事件(开放平台 → 事件与回调):
- 事件配置 tab:
im.message.receive_v1(接收 @bot 消息) - 回调配置 tab:
card.action.trigger(接收卡片按钮回传,200340 错误就是没开这个) - 订阅方式都选长连接(推荐,不用暴露公网 URL)
调 claude CLI 前,utils/ip_gate.py::assert_outbound_ip 会 curl ifconfig.me 对比 ALLOWED_OUTBOUND_IP,不符就抛 IPGateBlocked 拒绝调用——避免代理节点切换到不可信出口时把 Max 订阅暴露出去。
- 校验点:
filters/llm_filter.py::_score_one_cli、reports/deep_report.py::_generate_via_cli - 60 秒缓存:连续跑 30 篇论文只查一次 ifconfig.me
- 代理节点换了 → 更新
.env里的ALLOWED_OUTBOUND_IP为新 IP;临时禁用 → 设空字符串
飞书多维表格 11 列,列名和类型必须和代码匹配(push/feishu_bitable.py):
| 列名 | 类型 | 代码传什么 |
|---|---|---|
| 日期 | 日期 | 毫秒时间戳 |
| 标题 | 文本 | 论文标题 |
| 作者 | 文本 | 前 10 位作者逗号分隔 |
| 分数 | 数字 | LLM 精筛打分 1-10 |
| 推荐理由 | 文本 | LLM 一句话 |
| arXiv链接 | 超链接 | {text, link} |
| 摘要 | 文本 | 前 500 字 |
| 收藏 | 复选框 | 用户勾选 → 触发报告 |
| arxiv_id | 文本 | 2602.15763 这种(不能是数字列,会丢精度) |
| 报告状态 | 文本 | "生成中" / "已完成" |
| 报告链接 | 超链接 | 生成完的飞书文档 URL |
paper_assistant/
├── main.py # 入口:管道 + WebSocket 监听
├── run_one_paper.py # 入口:单篇强制精读
├── survey.py # 入口:主题调研(Claude 生成画像 + SS 搜索)
├── chat.py # 入口:对话式编辑已有飞书报告
├── watcher.py # 入口:轮询 Bitable 补漏
├── run_daily.sh # cron 包装:杀旧 → nohup 启新
├── callback_server.py # 飞书事件:卡片按钮 + @bot 消息
├── config.py # 研究画像 / 关键词 / 阈值 / env
├── sources/
│ ├── arxiv_source.py # arXiv 每日抓取
│ ├── hf_source.py # HuggingFace Papers 抓取
│ ├── semantic_scholar.py # survey.py 用的 SS 搜索
│ └── institutions.py # 从 arxiv 页面抠机构
├── filters/
│ ├── keyword_filter.py # 关键词加权粗筛
│ └── llm_filter.py # Claude Sonnet 精筛
├── reports/
│ └── deep_report.py # 深度报告生成(Sonnet)
├── push/
│ ├── feishu_bitable.py # Bitable 读写
│ ├── feishu_msg.py # 飞书群卡片
│ └── feishu_doc.py # lark-cli 两阶段文档 + 图片插入
├── storage/db.py # SQLite(papers / daily_picks / user_marks)
├── utils/ip_gate.py # 出口 IP 校验
├── schema.sql # DB schema
├── papers.db # SQLite (gitignored)
└── logs/ # 运行日志 (gitignored)
Q: cron 挂了但任务没跑?
pgrep cron 看守护进程在不在;不在就 /usr/sbin/cron 启一下。机器重启后需重新启动 cron 进程(无 systemd)。
Q: 出现 IPGateBlocked?
代理节点切换了。查当前 IP:curl ifconfig.me,更新 .env 的 ALLOWED_OUTBOUND_IP,重跑。
Q: feishu-cli 报 permission / 协作者错?
通常是应用未发布到租户,无法直接加为协作者。可以先让文档进 bot 默认空间(FEISHU_REPORT_FOLDER_TOKEN 留空),通过 Bitable "报告链接" 字段访问。想集中到文件夹:先发布应用 → 飞书 UI 把 bot 加为文件夹协作者 → 填 FEISHU_REPORT_FOLDER_TOKEN。
Q: 重启 / 补跑某天?
python main.py --date 2026-04-20。数据库幂等,重跑已处理过的论文会跳过。
Q: 换研究方向?
改 config.py 的 RESEARCH_PROFILE + KEYWORDS + ARXIV_CATEGORIES。临时扫描记得备份再改,或者直接用 survey.py(不动全局配置)。
Q: @bot 发链接没反应?
先查飞书开放平台"事件与回调"是否订阅了 im.message.receive_v1、card.action.trigger;订阅方式是否选"长连接"。若报 200340,说明"回调配置" tab(不是"事件配置")没开长连接。权限/订阅改过后记得发版本才生效(顶部橙条会提示)。
Q: survey.py 总是 SS 限流 429?
申请 Semantic Scholar 免费 API key(https://www.semanticscholar.org/product/api#api-key-form,秒发),放到 .env:export SEMANTIC_SCHOLAR_API_KEY="xxx"。没 key 会 fallback 到 arxiv 全文搜索,覆盖较稀疏。
Q: chat.py 里 claude 每次改文档都要我按 Y?
Claude Code 默认对 Bash 调用做用户批准。同类命令选 "always allow" 后续自动过。想整个会话免批但只这一次,别选 always。真不想要确认就在启动时加 --dangerously-skip-permissions(仅限你信任的操作)。
Q: 调研画像能单独保留成"日常画像"吗?
目前 survey.py 是一次性的,不会覆盖 config.py 的常驻配置。如果某次调研的画像你想转成日常,手动把它的 profile/keywords 拷到 config.py 对应字段即可。