
每天早上一睜眼arXiv 上都會多出兩三百篇新論文。如果你只盯著某個細(xì)分方向可能只有兩三篇值得讀但為了這兩三篇你得翻幾十個搜索頁、點開一堆標(biāo)題最后大概率還是漏掉了更重要的。我花了幾個晚上搭了一個基于 DeepSeek 的自動篩選系統(tǒng)把“人肉刷 arXiv”變成“讓模型幫我刷”順手還推送到郵箱。今天把這套方案從思路到代碼完整拆一遍給同樣被論文淹沒的科研黨一個可以照抄的作業(yè)。這個系統(tǒng)不挑方向只要你在 prompt 里寫清楚自己的研究興趣它每天早上都會自動把當(dāng)天 arXiv 上相關(guān)度高的論文挑出來附上評分和一句推薦理由發(fā)到你的郵箱。如果你剛接觸編程照著代碼改一改也能跑起來如果你已經(jīng)寫過不少腳本后面關(guān)于提示詞工程和閾值調(diào)優(yōu)的經(jīng)驗應(yīng)該能幫你把篩選質(zhì)量再拉高一個檔次。1. 整體設(shè)計與思路拆解1.1 為什么選擇DeepSeek做論文篩選傳統(tǒng)關(guān)鍵字篩選用正則表達式匹配標(biāo)題和摘要遇到同義詞基本就廢。比如你研究“多模態(tài)推理”論文標(biāo)題可能寫“vision-language co-reasoning”純字符匹配根本抓不到。用 DeepSeek 這類大語言模型來做本質(zhì)上是把它當(dāng)成一個“讀過大量論文的助教”給它看標(biāo)題和摘要讓它判斷這篇和你研究方向有沒有關(guān)系還順帶給出理由和標(biāo)簽。這種語義層面的篩選比關(guān)鍵詞規(guī)則靈活得多。我把關(guān)鍵詞過濾和 DeepSeek 篩選做過一次對比結(jié)果很直觀維度關(guān)鍵詞過濾DeepSeek 篩選同義詞識別差只能字面匹配好能理解同義表述跨領(lǐng)域關(guān)聯(lián)無法識別可以發(fā)現(xiàn)間接相關(guān)的論文結(jié)果可解釋性只能說明命中了哪個詞能輸出一句自然語言理由成本免費、實時有 API 費用需要耗時穩(wěn)定性穩(wěn)定但漏報率高有隨機性需要加規(guī)則兜底所以最后我采取的策略是兩者結(jié)合先用關(guān)鍵詞把候選集縮小再用 DeepSeek 做精排。這樣省掉大量無效的模型調(diào)用同時保留語義理解的優(yōu)勢。DeepSeek 的 API 對中文支持很好。我的研究方向描述是用中文寫的模型也能準(zhǔn)確理解返回的推薦理由可以用中文解釋讀起來非常順。同樣一篇英文摘要它能用“這篇提出了一個跨模態(tài)的對比學(xué)習(xí)框架和你的多模態(tài)推理方向高度相關(guān)”來總結(jié)這不就是私人助教么。1.2 系統(tǒng)架構(gòu)模塊劃分我把它分成四個模塊抓取、預(yù)篩、評分、通知。每個模塊盡量獨立方便單獨調(diào)。抓取模塊通過 arXiv 的 API 拉取當(dāng)天更新的論文拿到標(biāo)題、摘要、作者、鏈接、分類號。這里用到的是官方提供的數(shù)據(jù)不需要爬網(wǎng)頁穩(wěn)定很多。拉下來的論文先存在內(nèi)存里不落庫也行因為每天處理完就完事了如果要長期積累可以接一個 SQLite。預(yù)篩模塊做兩件事一是排除明顯不相關(guān)的分類比如你只做 NLP那定量生物學(xué)方向的論文就不看了二是做關(guān)鍵詞粗篩把包含指定詞組的論文撈出來。如果粗篩后數(shù)量還是太多比如遇到某個方向當(dāng)天井噴可以把關(guān)鍵詞匹配做成“必須命中標(biāo)題”或“摘要中至少出現(xiàn)兩次”。評分模塊把預(yù)篩后的論文逐條發(fā)給 DeepSeek讓它輸出一個 0 到 100 的相關(guān)度評分結(jié)構(gòu)化成 JSON。這個模塊是核心后面我會專門講提示詞怎么寫。通知模塊把得分超過閾值的論文整理成 Markdown 格式的郵件正文發(fā)送到你自己的郵箱。不想用郵件的話也可以改成調(diào)用即時通訊工具的 webhook。1.3 技術(shù)選型與關(guān)鍵取舍整體實現(xiàn)我用 Python因為第三方庫最全。arXiv 的 API 用 urllib 就能調(diào)沒必要上 requests模型調(diào)用用 OpenAI 兼容的 SDKDeepSeek 提供同樣的接口格式設(shè)置 base_url 和 api_key 就行。定時任務(wù)直接寫進腳本里用系統(tǒng)的 cron 或計劃任務(wù)觸發(fā)不依賴后臺框架。有一個讓我糾結(jié)很久的點要不要把所有論文都過一遍模型從效果看全量模型處理肯定召回最高但成本也高。如果當(dāng)天論文有 500 篇每篇摘要平均 1500 token一天就要處理 75 萬 token長期下來不是小數(shù)目。所以最終選了“規(guī)則預(yù)篩 模型精排”的漏斗結(jié)構(gòu)。實測下來預(yù)篩能過濾掉 70% 的不相關(guān)論文剩下 30% 再讓模型打分成本和效果取得了不錯的平衡。這里還有一個容易被忽略的細(xì)節(jié)模型評分有隨機性。同一篇論文跑兩次分?jǐn)?shù)可能會波動 10 分左右。所以在設(shè)計時不能讓模型直接決定“要不要”而是讓它輸出連續(xù)分?jǐn)?shù)再配合下面的規(guī)則閾值來過濾。這樣即使模型偶爾抽風(fēng)只要不是極端情況結(jié)果基本穩(wěn)定。2. 核心細(xì)節(jié)解析與實操要點2.1 從arXiv抓取論文元數(shù)據(jù)arXiv 官方 API 的入口是export.arxiv.org/api/query。它支持按時間、分類、關(guān)鍵詞查詢返回 Atom XML 格式。最常用的參數(shù)是search_query比如cat:cs.CL篩選自然語言處理all:transformer搜索標(biāo)題和摘要。還有一個關(guān)鍵參數(shù)sortBysubmittedDate能保證拿到的是當(dāng)天新增論文。實際請求時要注意官方 API 有頻率限制如果抓太頻繁會被拒絕訪問。我的經(jīng)驗是每次請求之間至少間隔 3 秒并且設(shè)置一個明確的 User-Agent 標(biāo)明用途。另外arXiv 的摘要里可能包含換行和特殊字符解析后要清洗一下否則喂給模型時容易讓 prompt 結(jié)構(gòu)錯亂。用 XML 解析時要先處理命名空間。下面這段代碼能提取出最基本的信息import urllib.request import xml.etree.ElementTree as ET ARXIV_API http://export.arxiv.org/api/query NS {atom: http://www.w3.org/2005/Atom, arxiv: http://arxiv.org/schemas/atom} def fetch_papers(query: str, max_results: int 50): url f{ARXIV_API}?search_query{query}sortBysubmittedDatesortOrderdescendingmax_results{max_results} req urllib.request.Request(url, headers{User-Agent: PaperFilter/0.1}) with urllib.request.urlopen(req) as resp: xml_text resp.read().decode(utf-8) root ET.fromstring(xml_text) papers [] for entry in root.findall(atom:entry, NS): papers.append({ title: entry.find(atom:title, NS).text.strip().replace(\n, ), abstract: entry.find(atom:summary, NS).text.strip(), link: entry.find(atom:id, NS).text.strip(), category: [c.attrib[term] for c in entry.findall(atom:category, NS)], }) return papers注意sortBysubmittedDate不一定百分之百只返回當(dāng)天的可能混著前一天沒入庫的所以在后續(xù)腳本里要用解析出的發(fā)布日期再過濾一次。日期可以從arxiv:published標(biāo)簽里取解析成 UTC 再比較from datetime import datetime, timezone published entry.find(arxiv:published, NS).text.strip() pub_date datetime.fromisoformat(published.replace(Z, 00:00)) if pub_date.date() datetime.now(timezone.utc).date(): # 只保留今天的論文 pass另外arXiv 的 API 接口是http如果服務(wù)器環(huán)境要求更嚴(yán)格可以走h(yuǎn)ttps不過在大多數(shù)場景下都能直接訪問。拉取結(jié)果后建議把標(biāo)題和摘要里的多余空白壓縮掉正則替換連續(xù)空格為單個空格這樣模型請求時能省一點 token。2.2 提示詞工程讓DeepSeek明白“相關(guān)性”論文篩選的核心不是代碼而是 prompt。我調(diào)試了很多版本最后穩(wěn)定下來的是一個帶角色設(shè)定、評分標(biāo)準(zhǔn)和 few-shot 示例的模板。先說角色設(shè)定告訴模型“你是某課題組的研究助手”比直接說“請你判斷是否相關(guān)”效果更穩(wěn)定。因為角色會給模型一個行為框架。然后是研究方向描述這個描述不能太短比如“自然語言處理”這種太籠統(tǒng)模型會給你很多泛泛的分?jǐn)?shù)。要把關(guān)鍵詞、方法、目標(biāo)都寫進去比如“多模態(tài)大模型中的視覺-語言對齊機制尤其關(guān)注跨模態(tài)注意力”。評分標(biāo)準(zhǔn)要明確如果論文提出新方法或新數(shù)據(jù)集且方法可復(fù)現(xiàn)給 80 分以上如果只是應(yīng)用既有方法到新場景給 50 到 70 分如果完全不沾邊給 20 分以下。把評分維度和具體尺度寫在 prompt 里能顯著降低模型亂打分的概率。few-shot 示例特別重要。我會在 prompt 里給兩個示例一個高度相關(guān)但標(biāo)題里沒有關(guān)鍵詞的論文模型應(yīng)該給高分另一個看起來沾邊但實際方向偏移的論文模型應(yīng)該給低分。這樣模型就理解了“相關(guān)性不是單純看字面詞”。最后要求模型返回嚴(yán)格 JSON字段包括 score、reason、tags。下面是一個我實際在用的完整 prompt 模板def build_prompt(paper: dict) - str: research_field 多模態(tài)大語言模型中的視覺-語言對齊機制尤其關(guān)注跨模態(tài)注意力、指令微調(diào)中的對齊策略、以及圖文推理鏈 return f 你是某課題組的研究助手。你要根據(jù)下面的研究方向判斷一篇論文是否值得課題組成員精讀。 研究方向{research_field} 評分標(biāo)準(zhǔn) - 90-100提出了新方法、新模型或新數(shù)據(jù)集且直接解決該方向的關(guān)鍵問題 - 70-89將現(xiàn)有方法深度應(yīng)用到該方向有明確的參考價值 - 40-69僅僅部分相關(guān)例如使用了某個相似名詞但沒有實質(zhì)關(guān)聯(lián) - 0-39基本不相關(guān)只是 keywords 有巧合 輸出要求 只允許輸出一個 JSON 對象不要輸出其他任何文字。 格式如下 {{score: 0, reason: 不超過30字的中文理由, tags: [標(biāo)簽]}} tags 只能從 [new_method, new_dataset, survey, application] 中選擇沒有匹配的就給空列表。 示例1 論文標(biāo)題Aligning Vision-Language Representations with Learnable Cross-Modal Tokens 論文摘要本文提出一種可學(xué)習(xí)的跨模態(tài) token 對齊方法增強了視覺編碼器與語言模型的交互。 正確輸出{{score: 95, reason: 直接提出新的對齊方法針對性極強, tags: [new_method]}} 示例2 論文標(biāo)題ImageNet Classification with Visual Features 論文摘要僅使用視覺特征進行圖像分類沒有涉及任何語言模型或跨模態(tài)交互。 正確輸出{{score: 12, reason: 純圖像分類方向完全不符, tags: []}} 現(xiàn)在開始 論文標(biāo)題{paper[title]} 論文摘要{paper[abstract][:2000]} 這個模板有幾個細(xì)節(jié)是刻意設(shè)計的。首先輸出要求里明確“只允許輸出一個 JSON 對象”并且給了示例格式模型基本不會跑偏。其次標(biāo)簽候選只有 4 個限制范圍比放開讓模型自由發(fā)揮要穩(wěn)定得多。最后摘要限制 2000 字符因為論文摘要的后半段往往是實驗設(shè)置和結(jié)論對“相關(guān)性”判斷的邊際貢獻不大反而會拖慢響應(yīng)速度。這里有個坑要求返回 “strict JSON” 還不夠模型偶爾會在前面加解釋文字或者用中文標(biāo)點。所以在解析時不能只json.loads要先做一層正則清理提取{...}部分。后面常見問題里會細(xì)說。2.3 評分規(guī)則與閾值設(shè)定DeepSeek 輸出的 0-100 分?jǐn)?shù)是“軟性”的直接拿它和閾值比較之前我建議先做一個“關(guān)鍵詞加權(quán)”的二次校正。具體做法是在 prompt 外自己再算一個關(guān)鍵詞命中分標(biāo)題命中一個關(guān)鍵詞 10摘要命中 5命中多個關(guān)鍵詞累加。然后最終分?jǐn)?shù) 0.8 * 模型分 0.2 * 關(guān)鍵詞加權(quán)分。之所以保留關(guān)鍵詞加權(quán)是為了防止模型對某些過長摘要產(chǎn)生“注意力漂移”把核心點漏掉。閾值設(shè)定可以先無腦取 60 分然后跑一周記錄每天命中數(shù)量。如果每天都很多說明閾值低了如果三天打魚兩天曬網(wǎng)說明閾值高了。我的經(jīng)驗是寧可每周多篩出兩篇讀也別漏掉真正重要的那篇。所以閾值不要定太高65 分是個不錯的起點。另外可以給論文打標(biāo)簽比如“survey”“new_dataset”“SOTA”。這個標(biāo)簽不是篩選必需但如果推送郵件里帶了標(biāo)簽?zāi)銙咭谎劬湍軟Q定要不要點開。DeepSeek 在這方面表現(xiàn)不錯給它列幾個候選標(biāo)簽它會照做。不過模型對 “SOTA” 這類需要嚴(yán)謹(jǐn)驗證的標(biāo)簽有時會誤判所以最后推送前我自己加了一道小檢查如果摘要里出現(xiàn) “state-of-the-art”“ outperforms ” 這些字樣才允許打上 “SOTA” 標(biāo)簽。3. 實操過程與核心環(huán)節(jié)實現(xiàn)3.1 環(huán)境準(zhǔn)備與依賴安裝需要 Python 3.9 以上裝兩個庫就夠requests用于調(diào)用模型接口標(biāo)準(zhǔn)庫里的urllib、xml、smtplib就能解決其他問題。我在虛擬環(huán)境里安裝避免污染全局python -m venv venv source venv/bin/activate pip install requestsDeepSeek 的 API 是 OpenAI 兼容的所以也可以用openai這個庫把base_url指向 DeepSeek 的接口。但我試下來直接用requests反而少一層依賴出錯更可控。下面是調(diào)用函數(shù)import requests import json API_KEY your_deepseek_api_key BASE_URL https://api.deepseek.com/v1/chat/completions MODEL_NAME deepseek-chat def chat_json(prompt: str, temperature: float 0.3): headers { Authorization: fBearer {API_KEY}, Content-Type: application/json, } payload { model: MODEL_NAME, messages: [{role: user, content: prompt}], temperature: temperature, } resp requests.post(BASE_URL, headersheaders, jsonpayload) data resp.json() return data[choices][0][message][content]注意這里我故意把temperature設(shè)成 0.3。論文篩選的任務(wù)需要一定的一致性溫度太高會隨機打亂評分設(shè)得太低又可能讓模型拒絕輸出。0.3 到 0.4 是性價比比較高的區(qū)間。API Key 一定要通過環(huán)境變量或者配置文件讀取不要寫死在代碼里。我見過太多人把 key 發(fā)到公開博客然后被拿去刷爆。用os.getenv(DEEPSEEK_API_KEY)取既安全又方便換。3.2 核心代碼采集、評分、推送整體流程函數(shù)寫成一個pipeline()每天跑一次。采集部分用前面的fetch_papers預(yù)篩部分簡單判斷目標(biāo)關(guān)鍵詞評分部分組裝 prompt 后調(diào)用chat_json推送部分用smtplib發(fā)送郵件。下面是一個可運行的骨架我刪掉了日志和異常處理的細(xì)節(jié)只保留主線import os import re import json import smtplib from datetime import datetime, timezone from email.mime.text import MIMEText RESEARCH_FIELD 多模態(tài)大語言模型中的視覺-語言對齊機制 KEYWORDS [vision-language, multimodal, cross-modal, alignment] THRESHOLD 65 def pre_filter(papers): result [] for p in papers: text (p[title] p[abstract]).lower() if any(k.lower() in text for k in KEYWORDS): result.append(p) return result def parse_model_output(content: str) - dict: # 提取第一個 { 到最后一個 } 之間的內(nèi)容 start content.find({) end content.rfind(}) if start -1 or end -1: raise ValueError(no json found) data json.loads(content[start:end1]) data[score] int(data[score]) return data def score_paper(paper: dict) - dict: prompt build_prompt(paper) # 復(fù)用 2.2 節(jié)的模板 content chat_json(prompt) parsed parse_model_output(content) # 關(guān)鍵詞加權(quán) text (paper[title] paper[abstract]).lower() kw_score 0 for k in KEYWORDS: if k.lower() in paper[title].lower(): kw_score 10 elif k.lower() in text: kw_score 5 final_score int(0.8 * parsed[score] 0.2 * kw_score) parsed[final_score] final_score return parsed def send_mail(papers_with_meta: list): lines [# 今日論文推薦\n] for item in papers_with_meta: lines.append(f## {item[title]}) lines.append(f相關(guān)度{item[final_score]} 分) lines.append(f理由{item[reason]}) lines.append(f鏈接{item[link]}) if item.get(tags): lines.append(f標(biāo)簽{, .join(item[tags])}) lines.append() body \n.join(lines) msg MIMEText(body, markdown, utf-8) msg[Subject] f每日論文篩選 {datetime.now().strftime(%Y-%m-%d)} msg[From] os.getenv(MAIL_FROM) msg[To] os.getenv(MAIL_TO) with smtplib.SMTP_SSL(os.getenv(SMTP_HOST), int(os.getenv(SMTP_PORT))) as server: server.login(os.getenv(SMTP_USER), os.getenv(SMTP_PASS)) server.send_message(msg)運行主流程時我通常會把不合格的論文也存到一個 debug 文件里方便回頭檢查是不是漏掉了好論文。這里有個細(xì)節(jié)parse_model_output里的int(data[score])必須加因為模型偶爾返回字符串類型你不強轉(zhuǎn)后續(xù) THRESHOLD時就會 TypeError。3.3 定時運行與結(jié)果分析腳本寫好后最省事的方式是配置 cron。比如每天早上八點跑一次0 8 * * * cd /path/to/project /path/to/venv/bin/python pipeline.py run.log 21記住要用虛擬環(huán)境的解釋器不能用直接python否則可能用到錯誤版本。跑一周之后我建議做一個簡單的結(jié)果分析把每天推送論文的標(biāo)題存下來手動抽查 20 篇看哪些被漏掉、哪些是誤報。漏掉多的就降低閾值或增加關(guān)鍵詞誤報多就反過來調(diào)整 prompt 或提高閾值。這一步才是整個系統(tǒng)最有價值的部分。因為模型判斷永遠(yuǎn)有瑕疵人工閉環(huán)調(diào)整才是提升精度的關(guān)鍵。我自己的系統(tǒng)跑了兩周之后誤報率從剛開始的 40% 降到了 15% 左右。我每周會做一個表格記錄效果日期預(yù)篩論文數(shù)模型調(diào)用數(shù)最終推送數(shù)手動抽查判斷周一868698 篇值得讀周二102102129 篇值得讀周三737376 篇值得讀當(dāng)你連續(xù)記錄半個月就能看出閾值和關(guān)鍵詞設(shè)置是否合理了。如果某天預(yù)篩論文數(shù)異常高很可能是某篇熱門論文霸占了多個分類去重邏輯沒生效。如果連續(xù)兩天推送數(shù)為 0先別急著降閾值大概率是 arXiv API 沒抓到新數(shù)據(jù)而不是真的沒有好論文。4. 常見問題與排查技巧實錄4.1 請求被限流或超時arXiv 的 API 不會給明確的 429但會出現(xiàn)連接超時或者返回一段比較少見的 XML。解決辦法是添加重試和退避邏輯。我寫了一個簡單的retry裝飾器三次重試每次等待時間遞增。另外把max_results拆小比如一次拉 20 篇分批次拉避免一次拉幾百篇被服務(wù)器拒絕。還有一次我遇到urlopen error [Errno 110] Connection timed out排查后發(fā)現(xiàn)是網(wǎng)絡(luò)代理環(huán)境太復(fù)雜。后來在服務(wù)器上直接清空代理變量才恢復(fù)正常。如果你也用了代理記得在腳本里顯式清除HTTP_PROXY和HTTPS_PROXY不然很隱蔽。DeepSeek API 偶爾也會返回 503 或者 429這類狀態(tài)碼意味著服務(wù)端過載。我的處理邏輯是遇到 5xx 就退避重試遇到 429 就等待更長的時間再試一次。不要在重試邏輯里直接 sleep 60那樣會把整個 pipeline 卡住最好給每次重試拋出一個異常讓主流程跳過這篇論文最后把失敗列表打印出來。4.2 模型輸出不穩(wěn)定與JSON解析失敗這是最常遇到的問題。DeepSeek 返回的內(nèi)容偶爾會在 JSON 前后加一句廢話比如“好的為你生成結(jié)果”導(dǎo)致json.loads直接拋異常。我的處理方法是先找第一個{和最后一個}截取中間部分再解析如果還是失敗就重新調(diào)用一次。因為溫度不高重試后輸出基本會正常。還有一個很隱蔽的問題模型給出的 score 可能是字符串75而不是數(shù)字 75。所以解析后要用int()強制轉(zhuǎn)換否則后面比較時會報錯。解析代碼可以封裝成一個小函數(shù)并且支持容錯def safe_parse_json(content: str): try: return json.loads(content) except json.JSONDecodeError: start content.find({) end content.rfind(}) if start -1 or end -1: return None try: return json.loads(content[start:end1]) except json.JSONDecodeError: return None如果safe_parse_json返回 None我會把這篇文章標(biāo)記為“待處理”不去重試也是可以的。因為提示詞里的示例已經(jīng)把輸出格式規(guī)定得很嚴(yán)偶爾一次失敗不影響整體效果。但你一定要在日志里保留原文方便事后分析是不是某些特殊論文觸發(fā)了模型異常。4.3 篩選結(jié)果漂移與閾值調(diào)優(yōu)有時候同一個研究方向上周跑得很好這周突然推了一堆不太相關(guān)的論文。原因可能是 arXiv 這周的新論文里恰好有大批擦邊球或者模型在長上下文中的注意力被稀釋。我的經(jīng)驗是把研究方向描述拆分得更細(xì)加上“不需要泛泛的綜述性工作”這樣的負(fù)面約束。同時閾值不要固定死可以根據(jù)近三天推送數(shù)量做動態(tài)調(diào)整比如平均超過 10 篇就上調(diào) 5 分少于 3 篇就下調(diào) 5 分。還有一種情況研究方向本身在演進。比如你從“多模態(tài)對齊”細(xì)化到“細(xì)粒度視覺定位”那么方向描述里要同步加一句“當(dāng)前最后關(guān)注細(xì)粒度區(qū)域定位與語言引導(dǎo)的交互”。我經(jīng)常忘了更新 prompt導(dǎo)致系統(tǒng)還在推舊方向的內(nèi)容那時候就會覺得“這系統(tǒng)怎么越跑越偏”。其實不是系統(tǒng)變笨了而是你的研究方向變了。4.4 成本控制與性能優(yōu)化如果預(yù)篩后每天還有 200 篇論文意味著要調(diào)用 200 次模型 API每次等待 1-3 秒整體跑下來要 10 分鐘以上。性能瓶頸主要在串行等待。解決辦法是用線程池并發(fā)調(diào)用把并發(fā)數(shù)控制在 5 左右能提速 3-4 倍且不容易觸發(fā)限流。另外可以把論文抽象出前 2000 字符因為后面基本都是 related work對判斷相關(guān)性幫助不大。使用 ThreadPoolExecutor 的時候要保證每個線程都有獨立的 prompt沒有共享狀態(tài)from concurrent.futures import ThreadPoolExecutor, as_completed def batch_score(papers: list, max_workers: int 5): results [] with ThreadPoolExecutor(max_workersmax_workers) as executor: future_map {executor.submit(score_paper, p): p for p in papers} for future in as_completed(future_map): paper future_map[future] try: parsed future.result() parsed[link] paper[link] parsed[title] paper[title] results.append(parsed) except Exception as e: print(ffailed: {paper[title]} - {e}) return results成本方面可以用一個簡單的統(tǒng)計函數(shù)定期記錄每天調(diào)用 token 數(shù)。一個月下來你心里就有底了。我的實際體驗是預(yù)篩加并發(fā)之后每天大概消耗 30 萬 token不是一個大數(shù)字但如果不做預(yù)篩會多出三四倍。4.5 安全與隱私提醒這個系統(tǒng)本身不涉及敏感數(shù)據(jù)但有幾點容易忽視。第一API Key 和郵箱密碼必須用環(huán)境變量管理不要把配置文件丟到公開倉庫。第二論文摘要屬于公開數(shù)據(jù)但如果你后續(xù)要對推送結(jié)果做二次處理比如訓(xùn)練自己的模型要留意 arXiv 的使用條款。第三定時任務(wù)跑出來的日志可能包含論文標(biāo)題和個人郵箱不要在公開空間隨意粘貼完整日志。還有一點如果你把系統(tǒng)交給別人維護一定不要把研究方向描述和個人偏好寫得過于私人化。這個文件可能會流傳出去盡量保持學(xué)術(shù)化的表達。5. 擴展玩法讓系統(tǒng)更像你的私人學(xué)術(shù)助理5.1 接入即時通知郵件雖然穩(wěn)定但不是所有人都習(xí)慣每天看郵箱??梢园淹扑徒Y(jié)果轉(zhuǎn)成 markdown 發(fā)到即時通訊工具或者生成一個簡單的 HTML 頁面放到本地。我目前用郵件因為設(shè)置簡單、不受設(shè)備限制。如果你想要更及時的通知可以用即時通訊工具的 webhook調(diào)用方式也就是一次 POST 請求比郵件還容易。下面是一個極其簡單的 webhook 發(fā)送函數(shù)import requests def send_webhook(webhook_url: str, text: str): resp requests.post(webhook_url, json{text: text}, timeout10) resp.raise_for_status()這個方法唯一的隱患是 webhook 地址泄露后容易被別人盜刷所以不要把 webhook 地址放在公開倉庫里。如果平臺支持關(guān)鍵字過濾也可以先做一層脫敏再發(fā)送。5.2 增量更新與去重arXiv 上同一篇論文可能在多個分類里出現(xiàn)抓取時會造成重復(fù)。我的做法是用論文 ID 的前幾位去掉版本號作為去重鍵在內(nèi)存里維護一個集合。這樣既不會重復(fù)推送也能追蹤論文是否有更新版本。seen set() def is_duplicate(paper: dict) - bool: # 例如 arxiv.org/abs/2401.00123v2 - 2401.00123 paper_id paper[link].split(/)[-1].split(v)[0] if paper_id in seen: return True seen.add(paper_id) return False這個去重邏輯對“同 ID 不同版本”也有效。我之前沒做去重時一天收到過兩封完全重復(fù)的郵件排查了半天才發(fā)現(xiàn)是不同分類入口抓到了同一篇論文。5.3 多主題并行篩選如果你的研究方向有兩個不想每天看兩份郵件可以讓一個腳本同時跑多個 prompt把不同主題的結(jié)果合并到同一封郵件里。這里要注意各主題的分?jǐn)?shù)不能直接比較因為 prompt 的評分標(biāo)準(zhǔn)可能不一樣所以郵件里要明確標(biāo)注主題名。實現(xiàn)上不用把文件拆成多份只要把RESEARCH_FIELD、KEYWORDS和THRESHOLD做成參數(shù)循環(huán)調(diào)用即可。我遇到過一個小問題兩個主題的關(guān)鍵詞有交叉導(dǎo)致同一條論文被兩個主題都推了一次。解決辦法是在同一個去重集合里增加“主題名 論文ID”的復(fù)合鍵或者按主題的優(yōu)先級去重。這些擴展都不復(fù)雜核心還是抓取、評分、通知這個鏈路。系統(tǒng)真正跑起來以后你就會發(fā)現(xiàn)它省下來的不只是刷論文的時間還有你注意力切換的隱性成本。每天花 3 分鐘掃一眼郵件比在 arXiv 上漫無目的地刷一小時要高效得多。我個人在實際操作中最深的一點體會是這類自動篩選系統(tǒng)效果好壞 80% 取決于那一段研究方向描述怎么寫代碼反而是最不費腦的地方。你不需要把方向?qū)懙枚鄬W(xué)術(shù)要把你自己看論文時的直覺描述出來比如“我關(guān)心方法不是任務(wù)”“我更在意可復(fù)現(xiàn)性”模型才能真正理解你的偏好。另外不要追求一個永遠(yuǎn)不變的參數(shù)論文領(lǐng)域的熱點在變你的研究興趣也會微調(diào)每兩三個星期回頭看看篩選結(jié)果順手改幾句 prompt、動一下閾值系統(tǒng)才能一直好用。最后再分享一個小技巧如果你打算長期用這套系統(tǒng)記得把每天推送的論文鏈接和評分存成一個歷史文件。哪天想找一篇之前讀過但忘了收藏的論文一份包含摘要和評分的本地索引比 arXiv 站內(nèi)搜索好用太多。這就是“論文篩選”之外意外收獲的額外價值。