简介面向AI应用开发者和学术研究者的项目源码包将腾讯IMA、Kimi.ai、Deepseek、智谱清言、秘塔、豆包、通义千问、Elicit等主流AI工具与arXiv、谷歌学术镜像、百度学术、专知、Web of Science、HimmPat、Patentics、Global Dossier等学术及专利检索入口整合为一个网页导航覆盖人工智能应用、学术搜索、专利查询、会议信息等场景能帮助用户快速触达常用站点免去四处收藏和记忆的麻烦。资源共3个文件包含一个HTML主页面、一个inscode在线配置项和一个gitignore版本控制文件整体仅5KB部署轻量、结构清晰适合有AI应用或学术检索需求的入门与进阶使用者直接使用或二次开发。已有196人学习浏览源码打开即可访问整理好的所有网址也可以自行增删条目定制属于自己的学术与AI工具导航。1. 为什么要自己搭「AI及学术网址导航」从收藏夹到可维护的项目源码做AI方向的人收藏夹里躺着的网址数量通常很可观模型论文、数据集镜像、在线Demo、API文档、Prompt工具、学术搜索入口……但浏览器收藏夹的检索和归类能力实在太弱等到真要用的时候往往得在一长串「未分类」里来回翻。更不用说团队协作、换电脑、把网址分享给同事这类场景收藏夹几乎完全帮不上忙。本文说的「常用AI及学术网址[项目源码]」核心思路是把这个导航做成一份「数据结构清晰、可直接在前端渲染」的项目源码——用一份JSON配置驱动一个纯静态页面把分类、排序、搜索、快捷键都收进代码里最终产物可以部署到任意静态托管平台也可以直接发给别人用浏览器打开本地HTML文件跑通。适合的技术人群很明确有基础前端能力、想统一管理AI工具与学术资源入口的工程师和研究生不需要后端不需要数据库一个仓库就能解决。2. 先定数据模型网址导航的JSON结构决定后期维护成本2.1 分类字段怎么设计才能让新增网址不返工导航站的维护痛点不在写页面而在「每次加一条网址要改几处地方」。常见做法是把网址数据从HTML里拆出来单独维护一份JSON页面逻辑只负责「读配置 → 渲染列表」。JSON里每条记录只保留必要的字段我一般会设计成下面这样{ id: chatgpt, name: ChatGPT, url: https://chatgpt.com, desc: 通用对话与代码生成主力入口, tags: [对话, 生成, 英文], category: ai-chat, hot: 5, icon: auto }字段设计的原则是「能自动的不手写、能扩展的不要写死」。id用英文短横线命名做去重和收藏定位用url必须是完整带协议头的地址后面做搜索和跳转时省一次拼接tags数组是给跨分类检索用的——一个工具可以同时归到「论文辅助」和「写作」但分类category只能放一个主分类避免分类体系膨胀。参数说明hot字段是排序权重数值越大排在分类列表越靠前新收录的网址可以先给3等真正用上了再调高icon字段用auto表示自动从Google Favicon服务拉取图标不想依赖外部服务时也可以存本地图片路径。注意desc不要写太长8~16个字足够导航页是「扫一眼能认出」不是读简介。2.2 用一份JSON驱动渲染最小可用的前端页面骨架数据结构定了之后页面端用一个fetch请求拉取JSON再做分类聚合和搜索过滤。整个实现不依赖框架原生JavaScript加少量DOM操作就能跑如果后续要加「最近访问」「快捷键跳转」这个骨架也不用推翻。!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 titleAI与学术导航/title style body { font-family: system-ui, sans-serif; max-width: 1100px; margin: 0 auto; padding: 16px; } .search { width: 100%; padding: 10px 14px; font-size: 16px; margin: 20px 0; } .tag { display: inline-block; background: #eee; border-radius: 4px; padding: 2px 8px; margin: 0 4px 4px 0; font-size: 12px; } .item { border: 1px solid #ddd; border-radius: 8px; padding: 12px 16px; margin: 8px 0; display: flex; align-items: center; } .item img { width: 24px; height: 24px; margin-right: 12px; } /style /head body input classsearch idsearch placeholder搜索AI工具 / 学术平台 / 关键词回车直达第一个结果 div idapp/div script // 所有网址数据在 data.json 中维护 const CATEGORY_NAMES { ai-chat: 对话与生成, ai-code: AI编程, ai-image: 图像生成, paper: 论文检索, edu: 公开课与教材, tools: 效率工具 }; let allData []; async function init() { const res await fetch(./data.json); allData await res.json(); render(allData); } function render(list) { const grouped {}; list.forEach(item { (grouped[item.category] grouped[item.category] || []).push(item); }); let html ; Object.keys(grouped).sort().forEach(cat { html h2${CATEGORY_NAMES[cat] || cat}/h2; grouped[cat].sort((a, b) b.hot - a.hot).forEach(item { html div classitem img srchttps://www.google.com/s2/favicons?domain${new URL(item.url).hostname}sz32 alt div a href${item.url} target_blank relnoopener${item.name}/a div${item.desc} span classtag${item.tags.join(/spanspan classtag)}/span/div /div /div; }); }); document.getElementById(app).innerHTML html; } init(); /script /body /html逻辑说明init函数负责启动流程fetch拉取data.json后交给render做渲染render内部用category做分组、用hot字段做排序动态拼接HTML字符串后一次性插入DOM避免逐条append带来的性能损耗。搜索过滤逻辑放在input的input事件里对name、desc、tags三个字段做includes匹配。这里有几个参数值得注意排序用的b.hot - a.hot是数字比较如果hot字段被写成了字符串会出现「5 30」的玄学排序结果favicon取图用的是new URL(item.url).hostname先抽域名再拼Google的服务地址字段里url不带协议头会直接抛错设置里relnoopener是安全习惯_blank打开外部链接时不带opener能防钓鱼页面篡改原页面。提示本地直接双击HTML文件时fetch读取data.json会被浏览器CORS策略拦掉。常见做法是在项目目录起一个静态服务比如python -m http.server 8080然后再访问localhost:8080。3. 从收藏夹到项目源码构建导航站的最小工程3.1 目录结构与核心文件的分工确定了数据驱动渲染的方式后整个项目可以从零开始拆成四个文件index.html负责页面骨架和样式data.json是全部网址数据、也是后续维护最频繁的文件search.js封装搜索与键盘交互README.md记录收录规则和部署方式。这种结构刻意保持「少文件、少依赖」后续不管交给谁维护打开README就能知道往哪儿加网址。ai-nav/ ├── index.html ├── data.json ├── search.js └── README.mddata.json是整个项目真正的核心资产页面只是它的展示层。AI和学术类网址有一个特殊性变更频繁且不同细分方向的用户关注点差异很大。做对话的同学常备ChatGPT、Claude、Gemini入口就够了做Agent的同学需要额外关注API文档、模型排行榜、评测基准站点做学术的要集中放arXiv、Google Scholar、Connected Papers、期刊投稿系统。单纯按「AI、学术」二分法维护是不现实的分类层必须细化到二级语义。3.2 分类体系怎么定才不「刚上线就乱」我一般按使用场景分六个主分类对话生成、AI编程、图像与多模态、论文检索、课程与教程、效率与Agent工具。每个分类下初始收录不超过12条宁缺毋滥。收录标准就两条——「自己或团队在过去一个月内真实用过至少一次」和「官方稳定入口而非第三方聚合镜像站」。这两条能挡住一半的无效链接。规划分类示例[ { category: ai-code, items: [ {id: github-copilot, name: GitHub Copilot, url: https://github.com/features/copilot, desc: IDE内AI编程伴侣, tags: [编程, 补全], hot: 5}, {id: codex, name: OpenAI Codex, url: https://openai.com/codex/, desc: 代码生成与沙盒执行, tags: [编程, Agent], hot: 4} ] } ]注意这里的结构和我第2章给出的category字段写法略有调整如果后续打算直接把这个JSON喂给前端渲染平铺的数组比二级嵌套更好处理如果团队里有人用脚本批量生成脚本或做统计嵌套结构更直观。两种结构没有绝对的好坏关键是「新增一条网址时必须只改这一个文件」。很多导航项目翻车的起点就是网址信息散布在HTML里几处、JSON里几处、JS里又写死了一处维护时漏改一处就会出现「列表里看得到、搜索搜不到」的怪问题。3.3 搜索与快捷键把「找网址」的时间压缩到两秒内根据我自己的使用习惯网址导航的主要交互不是点击分类而是模糊搜索加回车直达。所以search.js里除了内置的搜索外还做了两个增强第一个是「键盘上移下移选择候选回车跳转选中项」第二个是「CtrlK聚焦搜索框」。// search.js — 搜索过滤 键盘直达 const input document.getElementById(search); const app document.getElementById(app); // 全局快捷键CtrlK 聚焦搜索框 document.addEventListener(keydown, (e) { if ((e.ctrlKey || e.metaKey) e.key.toLowerCase() k) { e.preventDefault(); input.focus(); } }); // 输入过滤匹配 name / desc / tags input.addEventListener(input, () { const kw input.value.trim().toLowerCase(); if (!kw) return render(allData); const filtered allData.filter(item { return item.name.toLowerCase().includes(kw) || item.desc.toLowerCase().includes(kw) || (item.tags || []).some(t t.toLowerCase().includes(kw)); }); render(filtered); });参数说明搜索用的是toLowerCase()后includes()——中文搜索时toLowerCase()不产生影响但英文大小写不敏感的体验就靠这一行tags字段用some(t t.toLowerCase().includes(kw))是数组匹配标准写法匹配逻辑是「一个关键词能命中name、desc、tags任意一个就进结果」。更好的体验是支持空格分词、多关键词过滤比如输入「ai 论文」同时满足两个条件实现上把kw按空格split后每个词都跑一次includes全部命中才保留。「回车直达第一个结果」的实现也放在这段逻辑后面在input的keydown事件里监听Enter拿到当前筛选结果的第一条记录直接window.open(item.url, _blank)。注意这里不要用location.href跳转因为导航页本身需要保留在后台避免来回切换丢失状态。4. 部署与分享从本地HTML到团队可访问的静态站点4.1 三种部署路径怎么选GitHub Pages / 服务器 / 纯本地文件导航站是纯静态项目部署方案选择空间很大。最常见的做法是推到GitHub仓库后开GitHub Pages免费、带HTTPS、支持域名绑定如果是公司内网环境部署到一台Nginx服务器上也就几条命令如果只是个人自用本地起一个HTTP服务甚至不开服务直接双击HTML也能用前提是数据不通过fetch加载。三者的取舍并非自由选择——你在第2章选定了fetch加载data.json那么本地双击这条路就断了如果非要支持双击打开需要改为在HTML里用script typeapplication/json内嵌数据或者把数据写成一个JS文件用全局变量暴露。部署到Nginx的示例命令# 把项目构建或直接拷贝源文件到服务器的 /var/www/ai-nav sudo rsync -av --delete ./ai-nav/ /var/www/ai-nav/ # 修改 Nginx 配置 sudo tee /etc/nginx/sites-available/ai-nav.conf EOF server { listen 80; server_name nav.example.com; root /var/www/ai-nav; index index.html; location / { try_files $uri $uri/ /index.html; } } EOF # 启用并重载 sudo ln -s /etc/nginx/sites-available/ai-nav.conf /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginx这段配置里try_files $uri $uri/ /index.html对纯静态导航站不是必需的因为没有前端路由但保留这个规则能让后续如果想加子页面不返工。真正要留意的是rsync --delete这个参数——它会同步删除目标目录里源端不存在的文件用的时候确保源目录就是完整的项目否则会把服务器上不要删的东西一并删掉。4.2 加载速度与离线可用图标资源和数据缓存的取舍导航站的性能瓶颈往往不在页面本身而在每个网址的favicon图标——如果每个条目都用Google的favicon服务首屏几十个条目会产生几十个HTTP请求慢网络环境体验并不好。常见优化方案是把图标缓存到本地用一个脚本定期抓取所有图标存到icons目录data.json的icon字段改为本地路径。另外可以考虑给data.json加一个localStorage缓存首次访问后把JSON存到浏览器本地后续每次加载先渲染缓存内容再异步请求远程JSON检查更新有变化就刷新。这个策略虽然只有两三行代码但用户体验的改善非常明显——即使网络抖动导航页也能秒开。// 缓存版数据加载优先本地缓存后台校验更新 const CACHE_KEY ai-nav-data-v1; async function loadData() { const cached localStorage.getItem(CACHE_KEY); if (cached) { allData JSON.parse(cached); render(allData); } const res await fetch(./data.json); const fresh await res.json(); allData fresh; localStorage.setItem(CACHE_KEY, JSON.stringify(fresh)); render(allData); }参数说明缓存key带版本号v1是刻意为之——以后data.json结构如果新增字段只需把key改成v2就能让所有客户端自动弃用旧缓存避免老浏览器解析失败出现白屏。注意JSON.parse(cached)外面要包try/catch一旦缓存数据损坏不能让页面直接挂在解析上。5. 避坑与排查AI网址导航常见的四个坑5.1 图标拉取失败显示破图现象页面能正常显示但每条记录的favicon位置出现一个断裂的图片小图标看起来像页面坏了。原因Google的Favicon服务对部分域名没有收录图标返回404另外国内网络环境访问该服务的延迟较高有时会直接超时。解决不要把favicon服务当成可靠依赖在img标签上挂一个onerror事件失败时替换成纯色首字母占位块或者按第4章说的用脚本把图标批量下载到本地构建时一次性处理。5.2 搜索「agent」匹配结果为空现象明明导航里收录了相关的工具名称和描述里都含「agent」但搜索这个词就是过滤不出来。原因data.json里有的条目tags写的是数组有的写成了逗号分隔的字符串而第2章的filter逻辑只用Array.prototype.some字符串调用没有.some方法那个条目被静默跳过。解决在init函数里加一条数据归一化逻辑把所有tags字段统一转成数组更稳妥的做法是加载后对每条数据做一次结构校验不合法的打印警告到控制台。5.3 新增网址后页面排序错乱现象给某条记录hot值设了10结果它排到了hot为3的记录后面。原因JSON里手写hot值的时候没有加引号但排序列的排序依赖数字比较如果hot值是字符串10和3做字符串比较按字典序10小于3排序结果自然不对。解决写入数据时严格用数字类型不要加引号如果数据来源是表格复制粘贴粘贴后重点检查hot和id字段是否被Excel改成了「常规」格式。5.4 本地双击打开白屏现象直接在文件管理器里双击index.html页面一片空白控制台报Failed to fetch或CORS错误。原因浏览器安全策略禁止在file://协议下跨文件读取资源fetch函数的请求被拦截。解决不要双击打开在项目目录执行python -m http.server 8080或npx serve起本地服务如果团队里有非技术成员想看页面把部署好的在线链接发给他不要发HTML文件。注意还有一个隐蔽版本——如果你用的是Chrome即使开了本地服务从localhost:8080访问时favicon接口的HTTPS混合内容也可能被拦解决方案是确保data.json里所有url都带https://前缀不要混用http和https。6. 进阶用法把导航站变成团队协作的AI入口导航站做到第5章已经「能用」了但离「好用」还有一个差距——网址导航天然有「公共性」和「高频性」最适合进一步演变成团队的AI与学术资源协作入口。这一章的进阶方案不是必须做但做完了之后导航站的使用频率会显著高于普通收藏夹。第一个方向是「多分类下的人机分工」把数据维护交给一个脚本而不是靠人肉编辑data.json。写一个sync.py从团队Wiki或飞书表格导出链接自动去重、校验可达性、生成新的data.json。这个脚本的核心逻辑很直白读取表格对每行URL发一个HEAD请求检查状态码把200以上的地址过滤掉再按预设的分类映射写入JSON。跑完一轮后人工只需要审阅新增部分不用在几十条老链接里反复翻找。另一个值得做的是把导航站和「AI编程提示词/Prompt模板」结合起来——在每条记录下面挂一个「查看提示词」的折叠面板收录该工具的高质量Prompt模板。这个需求的本质是人们打开的不仅是网址还有「这个网址是怎么用来干活的」。比如收录了一个Agent框架的文档站旁边附一段「写一个能自主调研的Agent」的prompt示例团队成员复制即用。如果愿意再加一层可以在本地给导航站加「使用频率统计」把每次点击的事件记录到localStorage页面加载时按频率给高点击条目加亮显示。这个「高频入口」区域会自然沉淀出团队真正依赖的工具列表——通常是ChatGPT、Claude、arXiv、Connected Papers这几个不会多。最后说一个我自己吃过的亏有个项目曾经把导航数据放在JSON里页面和脚本都写好了结果一个团队成员不懂JSON语法往最后一条记录后面漏加了一个逗号整个页面白屏排查了半小时才在浏览器控制台里发现Unexpected end of JSON input。从那之后我坚持在README里写「修改完JSON后必须跑一次python -m json.tool data.json做语法校验」也建议你把这个校验写进持续集成脚本里——导航站看着简单但它每天被打开几十次坏了影响效率值得多一道防线。希望这些调试思路和经验能帮到你少走几步弯路。本文还有配套的精品资源点击获取