首页
看点啥
插画图片
首页 看点啥 三个技巧-提升 Web 应用的 AI 可见性

三个技巧-提升 Web 应用的 AI 可见性

2026-07-15 0

在 AI 驱动搜索的时代,仅靠传统 SEO 已经不够了。本文介绍预渲染、JSON-LD 结构化数据和 llms.txt 三个关键技巧,帮助 Web 应用在搜索引擎 和 AI 工具中都能被更好的发现和推荐。

大多数 Web 应用在对待「可发现性」这件事上,还停留在 2015 年的思维。设好 </code>,写一段 meta description,每季度去 Google Search Console 看一眼,然后就觉得自己做得够好了。但在今天这个由 AI 主导的时代,越来越多的产品发现流量来自 AI 智能体和大语言模型(比如 ChatGPT 搜索、Perplexity、Claude),而这些工具寻找的信号,与 Googlebot 的关注点并不完全相同。</p><p>好消息是,这些改进并不难做。基本上只需要加上三项东西,一旦做到位,你的 Web 应用在传统搜索引擎和 AI 侧的表现都会好很多。</p><h2>简介</h2><p>2026 年每个 Web 应用都应该具备的三样东西:</p><ol><li><strong>营销页面(如着陆页)的预渲染 HTML</strong>,让爬虫无需执行 JavaScript 就能看到内容。</li><li><strong>JSON-LD 结构化数据</strong>,让搜索引擎和 LLM 理解该 Web 应用到底是做什么的。</li><li><strong>一个</strong> <strong><code>llms.txt</code></strong> <strong>文件</strong>,让 AI 工具拥有经过精心编排的网站地图。</li></ol><h2>为什么传统做法已经不够了</h2><p><img src="https://www.0405.net/uploads/20260715/img_6a576d4a5084e31.webp"></p><p>如果你的应用是单页应用(大部分 React、Next.js、Vue 和 Svelte 应用默认都是),服务器返回的初始 HTML 大多是空的。真正的内容是在浏览器加载页面后,由 JavaScript 动态注入的。</p><p>Googlebot(谷歌的网站索引器)现在处理这个问题其实已经做得不错了,它会执行 JS,等待页面稳定下来,然后索引其中的内容。问题在于,其他大多数爬虫没有这么多耐心:</p><ul><li>Bingbot、DuckDuckBot 和其他经典爬虫要么跳过 JS,要么渲染不可靠。</li><li>AI 侧的爬虫(OAI-SearchBot、PerplexityBot、ClaudeBot 等)与 Googlebot 相比,JS 渲染能力不一致且普遍有限,所以不应该假设客户端渲染的内容对所有爬虫都是可达的。</li><li>LLM 在回答用户问题时,经常从缓存快照或 <code>curl</code> 请求中提取信息,而这些请求根本没有执行 JS。</li></ul><p>所以,如果你的核心价值主张、定价和常见问题解答只存在于客户端挂载的 React 组件中,那么在很大程度上,你对那些想触达的流量来说就是不可见的。</p><p>以下是可以做的三件事,按影响程度排序:</p><ol><li>把最有价值的内容放到服务器返回的 HTML 中。</li><li>使用结构化数据告诉爬虫你的应用/网站是什么类型。</li><li>给 LLM 一个干净、精心编排的网站索引。</li></ol><h2>1. 预渲染页面</h2><p>预渲染意味着在构建时生成页面的真实 HTML,然后在浏览器中让 React(或其他框架)进行水合(hydration)。访问者和爬虫都能在第一次请求时就获得完整页面,不需要执行 JS。此外,页面加载起来感觉快了很多。</p><p><em>在开启预渲染前后,分别运行 Lighthouse 审计(Chrome DevTools → Lighthouse 标签页),看看页面在加载速度和渲染性能上的改善。</em></p><p>只需要对公开的、内容密集的页面做这件事:着陆页、定价页、FAQ、博客索引页等等。不要把认证后的任何东西预渲染,因为那里没有值得预渲染的内容 —— 全是用户特定数据。</p><p>具体机制取决于技术栈,但每个主流框架都有成熟的路径:</p><ul><li><strong>Next.js</strong>:通过 <code>generateStaticParams</code> 进行静态生成,或使用 <code>output: 'export'</code> 进行完整静态导出。</li><li><strong>Astro</strong>:它默认就是静态站点生成器,所以你已经在免费享受这个好处了。</li><li><strong>Remix / React Router</strong>:按需服务端渲染或预渲染路由。</li><li><strong>Vite + React</strong>:添加预渲染插件,比如 <code>vite-plugin-ssr</code> 或 <code>vike</code>。</li><li><strong>Wasp</strong>:给路由加上 <code>prerender: true</code>,它会自动为你写出静态 HTML。</li></ul><p>具体用什么工具其实没那么重要,重要的是结果:着陆页在首个字节就返回真实内容,而客户端框架仍然会进行水合并接管交互 —— 这样链接、弹窗和任何交互部分都能继续正常工作。</p><h2>2. 添加 JSON-LD 结构化数据</h2><p>Meta 标签告诉爬虫关于页面的<em>信息</em>。结构化数据告诉它们页面<em>是什么</em>。这之间的区别好比:"这个页面的标题里有'定价'这个词"和"这是一个 SoftwareApplication,附带以下报价信息"。</p><p><img src="https://www.0405.net/uploads/20260715/img_6a576d4a5085132.webp"></p><p>大多数开发者都知道前者,即 HTML <code><head></code> 中的 meta 标签,也就是 <code><title></code>、<code><meta name="description"></code>,以及决定分享时链接样式的 Open Graph 和 Twitter Card 标签。这些值得认真写好。</p><p>但大多数人都会忽略后者,它远没有 meta 标签那么常见,但却同样重要 —— 尤其是 LLM 现在依赖它来判断和推荐你的产品到底是什么。</p><p>详细词汇表可以参考 Schema.org ,JSON-LD 是 Google(以及大多数 LLM)偏好的格式。只需要在 HTML 中放入一个 <code><script type="application/ld+json"></code>,就行了,没有渲染影响,没有布局偏移,不需要任何样式。</p><p>对于一个着陆页来说,值得包含的类型有:</p><ul><li><code>SoftwareApplication</code>:名称、描述、URL、类别、图片、定价、许可证。如果你的应用完全在浏览器中运行,可以使用更具体的 <code>WebApplication</code> 子类型。</li><li><code>WebSite</code>:站点级别的身份信息和社交媒体链接。</li><li><code>Organization</code>:应用背后的组织或个人。</li><li><code>FAQPage</code>:把你的 FAQ 板块变成 Google 的富媒体摘要,同时给 LLM 提供干净的问答对,方便它们在有人询问你的产品时引用。</li></ul><p>LLM 非常喜欢这种明确的东西。与其从营销文案中推断你的产品是什么,LLM 可以直接读取一条结构化记录,明确告诉你它是什么、花多少钱、谁做的。这基本上就是一个机器可读的"电梯演讲"。</p><p>下面是一个可以直接放入任何 React 应用的完整示例,没有任何框架特定的东西 —— 同一个 JSON 对象作为普通的 <code><script></code> 标签放在任何 HTML 页面中都能工作:</p><pre><code class="tsx">const schema = { "@context": "https://schema.org", "@graph": [ { "@type": "SoftwareApplication", "@id": "https://your-saas-app.com/#software", name: "你的 SaaS 应用", description: "你应用的主要描述和功能。", url: "https://your-saas-app.com", applicationCategory: "BusinessApplication", operatingSystem: "跨平台", image: "https://your-saas-app.com/public-banner.webp", offers: { "@type": "Offer", price: "0", priceCurrency: "USD" }, }, { "@type": "WebSite", "@id": "https://your-saas-app.com/#website", url: "https://your-saas-app.com", name: "你的 SaaS 应用", description: "你应用的主要描述和功能。", }, ], }; export function SchemaMarkup() { return <script type='application/ld+json'>{JSON.stringify(schema)}</script>; }</code></pre><p>在着陆页中导入一次,就再也不用管了。因为着陆页是预渲染的(见第一步),这个脚本最终会被内联到静态 HTML 中 —— 这正是爬虫和 LLM 希望看到它的位置。</p><p>如果着陆页有一个 FAQ 板块,再加上一个 <code>FAQPage</code> 条目。这是对 Google 富媒体摘要和 AI 回答都最具杠杆效应的添加之一,因为问答本来就是 LLM 想要引用的形式。</p><p>完成之后,在部署前使用 Google 的富媒体摘要测试工具 和 Schema.org 验证器 进行验证。</p><h2>3. 发布 llms.txt 文件</h2><p><code>llms.txt</code> 是一个比较新的约定,是位于网站根目录的一个 Markdown 文件,为 LLM 提供经过精心编排的页面和资源索引 —— 也就是你真正希望它们了解的那些内容。</p><p>它故意不设计成网站地图(sitemap)。网站地图是详尽无遗,面向爬虫的。<code>llms.txt</code> 简短、手工挑选,面向的是试图回答关于你问题的语言模型。把它想象成为网站写的 README,只不过读者是 AI。</p><p>最低限度的有用版本如下:</p><pre><code># 你的 Web 应用 > 一句话描述你的 Web 是做什么的,以及面向谁。 一段更长的文字提供背景:你的应用解决的问题、服务的用户类型,以及交付的核心价值。 ## 核心页面- 首页: 包含功能、定价和 FAQ 的着陆页- 定价: 订阅计划和价格 ## 文档 - 文档: 产品文档和指南 ## 资源 - 博客: 更新、教程和公告- GitHub: 开源代码</code></pre><p>把它放在 <code>public/llms.txt</code>,它就会在 <code>https://your-saas-app.com/llms.txt</code> 提供服务。</p><p>如果你有文档站或博客,值得在构建时生成这个文件以保持最新。用一个小的 Node 脚本读取博客的 frontmatter,在每次部署前写出更新后的 <code>llms.txt</code> 即可。大约 90 行代码,零依赖,很容易移植到任何项目中。也有一些插件和 npm 包可以自动完成这件事,但我发现手动控制里面放什么更好,从而保持文件简短且有意图。把它想象成索引或地图,让 LLM 和智能体知道去哪里找到最相关的内容。</p><h2>三者如何协同</h2><p>简单回顾一下为什么这三个技巧放在一起如此有效:</p><ul><li><strong>预渲染</strong>让内容对所有爬虫和 AI 机器人可见,并改善网站性能(比如加载速度)。</li><li><strong>JSON-LD</strong>让内容对搜索引擎和 AI 可理解。</li><li><code>llms.txt</code>让网站对 AI 工具易于导航。</li></ul><p>需要注意的是,如果没有预渲染,结构化数据只会躺在 JS bundle 里 —— 经典爬虫和 AI 爬虫可能永远看不到它。所以我的建议是:先把着陆页的预渲染做好,然后再逐步加上另外两项。</p><h2>总结</h2><p>如果只选其中一项来做,那就选预渲染,它解决了所有其他事情所依赖的基础问题(内容不在 HTML 中)。一旦这个到位了,JSON-LD 和 <code>llms.txt</code> 都是小而独立的补充,却能带来超出比例的回报。</p><hr><blockquote>Hi,我是俞凡,一名兼具技术深度与管理视野的技术管理者。曾就职于 Motorola,现任职于 Mavenir,多年带领技术团队,聚焦后端架构与云原生,持续关注 AI 等前沿方向,也关注人的成长,笃信持续学习的力量。在这里,我会分享技术实践与思考。欢迎关注公众号「DeepNoMind」,星标不迷路。也欢迎访问独立站 www.DeepNoMind.com,一起交流成长。</blockquote><p>本文由mdnice多平台发布</p> </div> <!-- --> <div class="content_btn_item clearfix"> <span>喜欢(0)</span> </div> <!-- --> <div class="content_page"> <a class="img_box" href="/news/3400896.html"> <div class="bg"> <p class="page">上一篇</p> <p class="info text_overflow_2">个人创作者怎么用 Gemini 3.5 规划内容 IP:长期策略与大模型选型攻略</p> </div> <img src="https://www.0405.net/uploads/20260715/logo_6a576d1d662351.webp" alt="个人创作者怎么用 Gemini 3.5 规划内容 IP:长期策略与大模型选型攻略"> </a> <a class="img_box" href="/news/3400898.html"> <div class="bg"> <p class="page">下一篇</p> <p class="info text_overflow_2">我和「二次元老公」约上会了!全球首个可以玩的实时交互模型:Xmax X2.0发布</p> </div> <img src="https://www.0405.net/uploads/20260715/logo_6a576d4e8e17c1.webp" alt="我和「二次元老公」约上会了!全球首个可以玩的实时交互模型:Xmax X2.0发布"> </a> </div> </div> <!-- 列表 --> <div style="padding-bottom: 10px;"> <div class="px15" style="font-weight: bold;font-size: .36rem;padding-top: .3rem;">猜你喜欢</div> <ul class="px15 news_box"> <li> <a class="clearfix" href="/news/3400933.html"> <span class="img_item"> <img lazy-src="https://www.0405.net/uploads/20260715/logo_6a576e8d93a5c1.webp"> </span> <div class="content"> <p class="title text_overflow_2">怎样用NotebookLM做资料消化和可引用结论提取</p> <p class="text"><span class="icon time">2026-07-15</span> <span class="icon heart">3400933</span></p> </div> </a> </li> <li> <a class="clearfix" href="/news/3400932.html"> <span class="img_item"> <img lazy-src="https://www.0405.net/uploads/20260715/logo_6a576e87358701.webp"> </span> <div class="content"> <p class="title text_overflow_2">NotebookLM怎样令AI播客讲解核心概念</p> <p class="text"><span class="icon time">2026-07-15</span> <span class="icon heart">3400932</span></p> </div> </a> </li> <li> <a class="clearfix" href="/news/3400931.html"> <span class="img_item"> <img lazy-src="https://www.0405.net/uploads/20260715/logo_6a576e84c4fb11.webp"> </span> <div class="content"> <p class="title text_overflow_2">有道云AI写培训复盘报告提示词如何输出检查清单</p> <p class="text"><span class="icon time">2026-07-15</span> <span class="icon heart">3400931</span></p> </div> </a> </li> <li> <a class="clearfix" href="/news/3400930.html"> <span class="img_item"> <img lazy-src="https://www.0405.net/uploads/20260715/logo_6a576e7fd898d1.webp"> </span> <div class="content"> <p class="title text_overflow_2">万兴天幕怎么给美食视频配音:文案语气与BGM搭配</p> <p class="text"><span class="icon time">2026-07-15</span> <span class="icon heart">3400930</span></p> </div> </a> </li> <li> <a class="clearfix" href="/news/3400929.html"> <span class="img_item"> <img lazy-src="https://www.0405.net/uploads/20260715/logo_6a576e798a9571.webp"> </span> <div class="content"> <p class="title text_overflow_2">Cursor写技术债优先级提示词怎样补充背景信息</p> <p class="text"><span class="icon time">2026-07-15</span> <span class="icon heart">3400929</span></p> </div> </a> </li> </ul> </div> <!-- 底部 --> <div class="footer_box"> <p>Copyright © 2022 漫资讯 · Powered By WordPress</p> </div> <div class="back_top" id="back_top"><a href="javascript:;"></a></div> </body> <script src="/mob/js/jquery.js" type="text/javascript" charset="utf-8"></script> <script src="/mob/js/lazy.js" type="text/javascript" charset="utf-8"></script> <script src="/mob/js/flexible.js" type="text/javascript" charset="utf-8"></script> <script src="/mob/js/index.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> var _paq = window._paq = window._paq || []; _paq.push(['trackPageView']); _paq.push(['enableLinkTracking']); (function() { var u="//tongji.zhangwan.net/"; _paq.push(['setTrackerUrl', u+'matomo.php']); _paq.push(['setSiteId', '9']); // Add this code below within the Matomo JavaScript tracker code // Important: the tracker url includes the /matomo.php var secondaryTrackerUrl = u+'matomo.php'; var secondaryWebsiteId = 27; // Also send all of the tracking data to this other Matomo server, in website ID 77 _paq.push(['addTracker', secondaryTrackerUrl, secondaryWebsiteId]); // That's it! var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; g.type='text/javascript'; g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s); })(); </script> <script> var _hmt = _hmt || []; (function() { var hm = document.createElement("script"); hm.src = "https://hm.baidu.com/hm.js?e9f2069e6989ecb71b4b1c8018eaf5ed"; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })(); </script> </html>