
如何让 LLM 与 AI Agent 以 llms.txt 形式读取 Fumadocs 文档内容【免费下载链接】fumadocsThe beautiful flexible React.js docs framework.项目地址: https://gitcode.com/GitHub_Trending/fu/fumadocs如果你的文档站基于 Fumadocs 搭建并且希望 LLM 与 AI Agent 能以 Markdown 文本形式获取文档内容而不是去解析 HTML 页面就可以启用 Fumadocs 的 llms 功能站点会额外提供llms.txt索引、llms-full.txt全文和按页的content.md路由。本文按 Fumadocs 官方文档 AI LLMs/integrations/llms.mdx) 与官方示例 examples/next 的写法给出从启用、生成文件到访问验证的完整路径以 Next.js 应用为主要演示环境。用 CLI 一步启用在文档项目根目录执行npx fumadocs/cli feature llms这条命令会做三件事在文档 content collection 上启用 processed Markdown、向lib/source.ts添加docsLlms导出、创建下文列出的路由文件。如果你的项目已经手工搭建过可以跳过此步直接按后文逐个核对文件内容。核对docsLlms三个方法各产出什么docsLlms由fumadocs-core/source的llms()函数创建。官方文档站自身的实现和 examples/next/lib/source.ts 展示了标准写法// lib/source.tsexamples/next 的写法 import { llms, loader } from fumadocs-core/source; import { defineDocs } from fumadocs-mdx/macro; import { metaSchema, pageSchema } from fumadocs-core/source/schema; const docs defineDocs({ dir: content/docs, docs: { schema: pageSchema, postprocess: { includeProcessedMarkdown: true, // Fumadocs MDX 必须开启 }, }, meta: { schema: metaSchema, }, }); export const source loader({ baseUrl: /docs, source: docs.toFumadocsSource(), }); export const docsLlms llms(source, { renderPage: async (page) # ${page.data.title} (${page.url}) ${await page.data.getText(processed)}, });三个方法对应的输出方法输出index(lang?)llms.txt索引从页面树page tree生成page(page)单页 Markdown经renderPage渲染full(lang?)所有页面经renderPage渲染后拼接两点约束需要注意page()和full()只有在传入renderPage时可用因为 Fumadocs 无法替你决定内容源如何暴露 Markdown未传时调用会抛出 renderPageis required bypage()andfull() 错误见 packages/core/src/source/llms.ts。renderPage读取的是处理后的文档而非原始文件内容所以使用 Fumadocs MDX 时必须在postprocess中开启includeProcessedMarkdown。上面的 apps/docs 示例 就是用page.data.getText(processed)取处理后的 Markdown。如果你的内容源是运行时按需解析的类型如fumadocs/local-md把getSource而不是已实例化的source传给llms()CLI 会生成同样的路由export const docsLlms llms(getSource, { renderPage: (page) # ${page.data.title} (${page.url}) ${page.data.content}, });另外一个细节MDX 组件默认会以 JSX 语法形式出现在生成的 Markdown 中。想让它们变成有意义的 Markdown可以使用 Fumadocs 文档中 remark-llms 的output选项/integrations/llms.mdx)。创建三个访问路由/llms.txt—— 全站页面索引由页面树生成格式为标题、可选描述加层级链接列表生成逻辑见 packages/core/src/source/llms.ts 中的formatIndex。参考 examples/next/app/llms.txt/route.tsimport { docsLlms } from /lib/source; export const revalidate false; export async function GET() { return new Response(await docsLlms.index()); }/llms-full.txt—— 所有页面内容的单文件合集import { docsLlms } from /lib/source; export const revalidate false; export async function GET() { return new Response(await docsLlms.full()); }/llms.mdx/docs/slugs/content.md—— 单页 Markdown主要面向 AI Agent 按 URL 抓取。路由与 URL 辅助函数放在lib/shared.ts示例见 examples/next/lib/shared.tsimport { createGetUrl } from fumadocs-core/source; export const docsContentRoute /llms.mdx/docs; const getContentUrl createGetUrl(docsContentRoute); export function getPageMarkdownUrl(page: { slugs: string[]; locale?: string }) { const segments [...page.slugs, content.md]; return { segments, url: getContentUrl(segments, page.locale) }; }路由文件 examples/next/app/llms.mdx/docs/[[...slug]]/route.tsimport { docsLlms, source } from /lib/source; import { getPageMarkdownUrl } from /lib/shared; import { notFound } from next/navigation; export const revalidate false; export async function GET(_req: Request, { params }: RouteContext/llms.mdx/docs/[[...slug]]) { const { slug } await params; const page source.getPage(slug?.slice(0, -1)); if (!page) notFound(); return new Response(await docsLlms.page(page), { headers: { Content-Type: text/markdown, }, }); } export function generateStaticParams() { return source.getPages().map((page) ({ lang: page.locale, slug: getPageMarkdownUrl(page).segments, })); }框架差异只需要记一处Tanstack Start 中该路由挂在 docs 路由之下形如/docs/slugs.md而不是/llms.mdx/docs/...。可选用Accept头直接返回 Markdown上面的.md路由是显式地址。如果你希望 LLM/Agent 请求普通文档 URL 时就拿到 Markdown可以让代理层按Accept头做内容协商。examples/next/proxy.ts 的完整实现import { NextRequest, NextResponse } from next/server; import { isMarkdownPreferred, rewritePath } from fumadocs-core/negotiation; import { docsContentRoute, docsRoute } from /lib/shared; const { rewrite: rewriteDocs } rewritePath( ${docsRoute}{/*path}, ${docsContentRoute}{/*path}/content.md, ); const { rewrite: rewriteSuffix } rewritePath( ${docsRoute}{/*path}.md, ${docsContentRoute}{/*path}/content.md, ); export default function proxy(request: NextRequest) { const result rewriteSuffix(request.nextUrl.pathname); if (result) { return NextResponse.rewrite(new URL(result, request.nextUrl)); } if (isMarkdownPreferred(request)) { const result rewriteDocs(request.nextUrl.pathname); if (result) { return NextResponse.rewrite(new URL(result, request.nextUrl), { // this URL has two representations, selected by Accept headers: { Vary: Accept }, }); } } return NextResponse.next(); }因为同一个 URL 从此有两种表示HTML 或 Markdown响应必须带Vary: Accept否则共享缓存可能把 Markdown 发给了浏览器或反过来。注意 Next.js 会丢弃 App Router 页面响应上的Vary所以如果你通过共享缓存CDN提供文档需要在 CDN 侧设置该头。验证结果启动站点后用 HTTP 请求逐条核对GET /llms.txt返回 Markdown 格式的页面索引首行为站点标题随后是可选的描述引用块再按页面树层级展开为标题形式的链接列表带description的页面会在链接后附上该描述。GET /llms-full.txt返回所有页面的 Markdown每页由你的renderPage渲染页与页之间以空行拼接。GET /llms.mdx/docs/你某页的 slugs/content.md返回该页 Markdown响应头为Content-Type: text/markdown请求不存在的 slug 会走notFound()。若配置了proxy.ts对任意/docs/...页面 URL 携带 Markdown 偏好的Accept头请求会得到该页 Markdown不带该头仍返回正常 HTML 页面。边界与下一步index()只依赖页面树page()/full()依赖renderPage如果full()报renderPage is required说明llms()调用漏传了该选项。单页.md路由是 Page Actions 的前置确认content.md可用后可以在文档页用fumadocs-ui/layouts/docs/page的MarkdownCopyButton与ViewOptionsPopover展示复制 Markdown / 查看源码按钮markdownUrl就取getPageMarkdownUrl(page).url。更进一步可以在此基础上用npx fumadocs/cli feature mcp生成/api/mcp路由把文档以 MCP 工具list_pages、get_page、search暴露给 Agent它依赖的正是本文这套 LLM 路由。【免费下载链接】fumadocsThe beautiful flexible React.js docs framework.项目地址: https://gitcode.com/GitHub_Trending/fu/fumadocs创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考