跳至內容
Fumadocs

AI 與 LLM

在 Fumadocs 中整合 AI 功能。

供 LLM 使用的文件

以 Markdown 格式將您的文件提供給 LLM 與 AI 代理:

npx @fumadocs/cli feature llms

它會為您的 docs 集合啟用處理後的 Markdown、在 lib/source.ts 中加入 docsLlms,並提供下方列出的檔案。若您偏好手動設定,可參考此處列出的產生檔案。

docsLlms

llms() 會將您的文件算繪為供 LLM 使用的格式。renderPage 會將單一頁面轉換為 Markdown,且依據的是處理後的文件,而非原始檔案內容:

lib/source.ts
import { llms } from 'fumadocs-core/source';

export const docsLlms = llms(source, {
  renderPage: async (page) => `# ${page.data.title} (${page.url})

${await page.data.getText('processed')}`,
});
方法輸出
index(lang?)llms.txt 索引,依據頁面樹建立
page(page)單一頁面,以 renderPage 算繪
full(lang?)所有頁面以 renderPage 算繪後合併的內容
files()供 AI 代理使用的檔案的路徑
serve(path)指定路徑檔案的回應

renderPage 為必要選項

只有在傳入 renderPage 時,才能使用 page()、full()、files() 與 serve(),因為 Fumadocs 無從得知您的內容來源如何提供 Markdown。

renderPage 會讀取頁面處理後的 Markdown,因此請啟用 includeProcessedMarkdown:

source.config.ts
import { defineDocs } from 'fumadocs-mdx/config';

export const docs = defineDocs({
  dir: 'content/docs',
  docs: { 
    postprocess: {
      includeProcessedMarkdown: true,
    },
  },
});

MDX 元件會以 JSX 語法呈現。若要將其算繪為 Markdown 形式,請將您的 MDX 元件作為頁面 props 傳入。

@fumadocs/local-md 這類執行階段內容來源會隨需解析。只要傳入其 getSource,CLI 就會產生相同的檔案:

export const docsLlms = llms(getSource, {
  renderPage: (page) => `# ${page.data.title} (${page.url})

${page.data.content}`,
});

使用 getSource 時,index() 與 indexNode() 會回傳 Promise,而非字串。

檔案

CLI 會為 AI 代理提供以下檔案:

  • /llms.txt:文件的索引,附有每個頁面 Markdown 版本的連結。
  • /llms-full.txt:所有頁面的內容。
  • <page>.md:單一頁面的 Markdown,例如 /docs/ui.md。位於 / 的頁面則對應 /index.md。
  • <section>/llms-full.txt:某個區段的內容,例如 /docs/ui/llms-full.txt。

若要將特定頁面 (例如草稿) 排除在這些檔案之外,請傳入 filter。llms.txt 仍會列出這些頁面,但會連結至其 HTML 頁面:

lib/source.ts
export const docsLlms = llms(source, {
  filter: (page) => page.slugs[0] !== 'drafts',
  renderPage: async (page) => `# ${page.data.title}\n\n${await page.data.getText('processed')}`,
});

在這些檔案中,renderUrl 會接收連結所指向檔案的路徑,例如頁面的 .md 檔案。

讀取頁面 HTML 的 AI 代理,會透過 <head> 中的連結找到該頁面的 Markdown:

<link rel="alternate" type="text/markdown" href="/docs/ui.md" />

區段

區段是頁面樹中擁有獨立 llms-full.txt 的資料夾,讓 AI 代理能分段閱讀大型文件。預設情況下,每個根資料夾都是一個區段。在 llms.txt 中,資料夾對應的那一行會連結到其所屬區段的 llms-full.txt。

若要自訂區段,請傳入 section。它會接收一個資料夾,並回傳該資料夾是否為區段:

lib/source.ts
export const docsLlms = llms(source, {
  // 所有含 index 頁面的資料夾
  section: (folder) => folder.index !== undefined,
  renderPage: async (page) => `# ${page.data.title}\n\n${await page.data.getText('processed')}`,
});

在大型網站上,您可以收合區段,讓 llms.txt 保持精簡。收合的區段在 llms.txt 中只會列為一個連結,指向該區段專屬的 <section>/llms.txt,再由該檔案列出區段內的頁面:

lib/source.ts
export const docsLlms = llms(source, {
  section: (folder) => (folder.root ? { collapse: true } : false),
  renderPage: async (page) => `# ${page.data.title}\n\n${await page.data.getText('processed')}`,
});

區段的檔案會以其資料夾 index 頁面的 URL 提供。若資料夾沒有 index 頁面,則改用其中頁面所在的 URL 目錄。當兩個資料夾共用同一個 URL 時 (例如資料夾群組) ,請傳入 asPath,將其中一個改放在其他路徑下提供,例如 { asPath: '/docs/guides' }。

路由

files() 會列出檔案的路徑,而 serve(path) 會回應指定路徑上的檔案,因此每個路由只需將請求路徑傳給 serve() 即可。

API 路由會在 /llms.mdx 下提供這些檔案,並透過 renderUrl 將 llms.txt 中的連結指向該處。在伺服器上,src/middleware 中的 Hono 中介軟體也會在各檔案原本的路徑上提供 /docs/ui.md 及其他檔案。請將 hono 安裝為開發相依套件,以取得其型別:

import { docsLlms } from '@/lib/source';

export async function GET() {
  return (await docsLlms.serve('/llms.txt'))!;
}

export async function getConfig() {
  return {
    render: 'static' as const,
  } as const;
}

若路徑沒有對應的檔案,serve() 會回傳 undefined,讓中介軟體能將請求繼續往下傳遞。使用 hideLocale: 'always' 時,URL 不會包含語系:請將語言作為 serve() 的第二個引數及 files() 的第一個引數傳入。

靜態輸出

API 路由會預先算繪,因此以靜態檔案部署的 Waku 網站仍會在 /llms.mdx 下提供這些檔案。中介軟體則需要伺服器才能運作。

Accept

AI 代理可以透過 Accept 標頭要求取得 Markdown。

當請求偏好 Markdown 時,上述中介軟體會以文件頁面的 Markdown 回應。

預先算繪的頁面會在中介軟體執行前就以靜態檔案形式提供,因此一律以 HTML 回應。

同一個 URL 現在有兩種表示形式,因此回應需要加上 Vary: Accept,以避免快取衝突。

頁面動作

頁面動作可讓讀者複製頁面的 Markdown,或在 AI 應用程式中開啟該頁面。這些動作會讀取頁面的 .md 檔案。

AI 頁面動作

在您的文件頁面中算繪這些動作:

import { MarkdownCopyButton, ViewOptionsPopover } from 'fumadocs-ui/layouts/docs/page';

const markdownUrl = `${page.url}.md`;

<div className="flex flex-row gap-2 items-center border-b pt-2 pb-6">
  <MarkdownCopyButton markdownUrl={markdownUrl} />
  <ViewOptionsPopover
    markdownUrl={markdownUrl}
    githubUrl={`https://github.com/${owner}/${repo}/blob/main/content/docs/${encodeURI(page.path)}`}
  />
</div>;

請使用 `/llms.mdx${page.url}.md` 作為 URL,這樣靜態部署也能提供該檔案。

MCP 伺服器

透過 MCP 伺服器將您的文件開放給 AI 代理使用,並提供列出、搜尋及讀取頁面的工具。

npx @fumadocs/cli feature mcp

這會在上述 LLM 路由之外,再建立一個使用 Streamable HTTP 傳輸層的 /api/mcp 路由。

這些工具來自 fumadocs-core/mcp。

src/pages/_api/api/mcp.ts
import { createMcpHandler, McpServer } from '@modelcontextprotocol/server';
import { registerSearchTool, registerSourceTools } from 'fumadocs-core/mcp';
import { createFromSource } from 'fumadocs-core/search/server';
import { docsLlms, source } from '@/lib/source';

const handler = createMcpHandler(() => {
  const mcp = new McpServer(
    {
      name: 'docs',
      version: '1.0.0',
    },
    // the tools never change, a stream to watch them would hold a serverless function open
    { capabilities: { tools: { listChanged: false } } },
  );

  registerSourceTools(mcp, source, docsLlms);
  registerSearchTool(mcp, createFromSource(source));

  return mcp;
});

export async function GET(request: Request) {
  return handler.fetch(request);
}

export async function POST(request: Request) {
  return handler.fetch(request);
}

export async function DELETE(request: Request) {
  return handler.fetch(request);
}

您可以透過以下方式將 AI 代理連接到此路由:

{
  "mcpServers": {
    "docs": { "url": "https://your-site.com/api/mcp" }
  }
}

WebMCP

實驗性功能

WebMCP 是一項仍處於早期階段的 Web 標準,目前可在 Chrome 149+ 中透過 #enable-webmcp-testing 旗標及來源試用 (origin trial) 使用。此 API 日後仍可能 變動。

上述 MCP 伺服器服務的是連線至您網站的 AI 代理;WebMCP 則是在讀者正在瀏覽的頁面上,將工具提供給瀏覽器內建的 AI 代理使用。

npx @fumadocs/cli feature webmcp

它會以 LLM 路由為基礎,建立一個 WebMCP 元件。請在 <RootProvider /> 內算繪此元件。

  • search_docs 會查詢搜尋 API 路由。您可以將 fetchClient 替換為其他用戶端。
  • read_page 會從 /llms.mdx/docs/page.md 取得頁面的 Markdown 內容。

詢問 AI

AI 搜尋

您可以使用 Fumadocs CLI 安裝 AI 聊天對話方塊。

npx @fumadocs/cli add ai/openrouter

它會透過 Vercel AI SDK 自動完成 OpenRouter 的設定,並為 AI 提供 /search 工具。

您可以修改 /api/chat 路由來改用其他模型。

Fumadocs 不提供 AI 模型,需由您自行決定。

您的 AI 模型可以使用上方產生的 llms-full.txt 檔案;若搭配第三方解決方案,也能使用更多元的資訊來源。

文件版面配置會依據 aiChat 選項算繪聊天介面。此選項需要用戶端狀態,因此請為您的版面配置建立用戶端元件,並用它取代原本的版面配置:

'use client';
// 也可改用 Notebook、Glass 或 Spacious 版面配置
import { DocsLayout as Layout, type DocsLayoutProps } from 'fumadocs-ui/layouts/docs';
// 已安裝的元件
import { AIChat, AIChatPanel, useAIChat } from './search';

export function DocsLayout(props: DocsLayoutProps) {
  return (
    <AIChat>
      <ChatLayout {...props} />
    </AIChat>
  );
}

function ChatLayout(props: DocsLayoutProps) {
  const { open, setOpen } = useAIChat();

  return (
    <Layout
      {...props}
      aiChat={{ open, onOpenChange: setOpen, panel: <AIChatPanel />, trigger: true }}
    />
  );
}

版面配置選項會傳入用戶端元件,因此必須可序列化。

How is this guide?

最後更新於