INTEGRITY Документация

AI SDK

Vercel AI SDK ↗ представляет собой набор инструментов на TypeScript для создания приложений с большими языковыми моделями. ai-search-provider ↗ пакет связывает AI Search с AI SDK, поэтому из одного и того же API вы можете генерировать ответы, основанные на вашем индексированном контенте, получать чанки и управлять документами.

В этом руководстве вы создадите Worker, который создаёт экземпляр AI Search, загружает и индексирует документ, а затем отправляет к нему запрос через AI SDK.

Предварительные требования

  1. Зарегистрируйтесь для получения Аккаунт Cloudflare ↗.
  2. Установка Node.js ↗.

менеджер версий Node.js

Используйте менеджер версий Node, например Volta ↗ или nvm ↗ чтобы избежать проблем с правами доступа и переключать версии Node.js. Wrangler, о котором пойдёт речь далее в этом руководстве, требует версию Node 16.17.0 или более поздней версии.

1. Создайте проект Worker

Создайте новый проект Worker с помощью create-cloudflare CLI (C3). C3 ↗ это инструмент командной строки, который помогает настраивать и развёртывать новые приложения в Cloudflare.

Создайте новый проект с именем ai-search-ai-sdk выполнив:

npm create cloudflare@latest -- ai-search-ai-sdk

Для настройки выберите следующие параметры:

Перейдите в каталог вашего приложения:

cd ai-search-ai-sdk

2. Установите AI SDK и провайдер

Установите AI SDK и провайдер AI Search. Провайдеру требуется AI SDK v6 (ai@^6):

npm i ai ai-search-provider

Создайте привязку между своим Worker и AI Search. Bindings позволяют вашему Worker взаимодействовать с ресурсами на Cloudflare Developer Platform.

Добавьте следующее в свой конфигурационный файл Wrangler:

{
  "$schema": "./node_modules/wrangler/config-schema.json",
  "ai_search_namespaces": [
    {
      "binding": "AI_SEARCH",
      "namespace": "default",
      "remote": true
    }
  ]
}
[[ai_search_namespaces]]
binding = "AI_SEARCH"
namespace = "default"
remote = true

Это привязывает default пространство имён к env.AI_SEARCH. remote опция позволяет wrangler dev перенаправляют запросы к вашему развёрнутому экземпляру, поскольку AI Search не выполняется локально. ai_search_namespaces привязка требует compatibility_date 2026-03-27 или новее, чему новые проекты C3 уже соответствуют.

4. Создайте экземпляр и проиндексируйте контент

Добавьте /setup маршрут, который создаёт экземпляр и загружает документ. Включите гибридный поиск при создании, задав index_method для индексирования как векторов, так и ключевых слов.

create() метод относится к привязке пространства имён (env.AI_SEARCH), а не на клиенте провайдера. Создание экземпляра, который уже существует, вызывает ошибку, поэтому следующий код создаёт его, а при следующем запуске просто обновляет.

src/index.js
import { createAISearchNamespace } from "ai-search-provider";
import { generateText, streamText } from "ai";

const INSTANCE_NAME = "knowledge-base";

const SAMPLE_DOC = `# Caching on Cloudflare
Cloudflare caches static assets at the edge. Use Cache Rules to control what is
cached, set an Edge Cache TTL to control how long objects stay in cache, and
purge the cache after a deploy.`;

// Create the instance with hybrid search, or update it if it already exists.
async function ensureInstance(env) {
	// index_method with both vector and keyword enables hybrid search.
	const hybrid = { index_method: { vector: true, keyword: true } };
	try {
		await env.AI_SEARCH.create({ id: INSTANCE_NAME, ...hybrid });
	} catch {
		await env.AI_SEARCH.get(INSTANCE_NAME).update(hybrid);
	}
}

export default {
	async fetch(request, env) {
		const url = new URL(request.url);
		// createAISearchNamespace adapts the binding to the AI SDK provider API.
		const aiSearch = createAISearchNamespace({ binding: env.AI_SEARCH });

		// Visit /setup once to create the instance and index a document.
		if (url.pathname === "/setup") {
			await ensureInstance(env);

			const instance = aiSearch.get(INSTANCE_NAME);

			// upload() queues the file and returns immediately. Indexing runs in
			// the background, so poll the item's status until it is searchable.
			const { id, key } = await instance.items.upload("caching.md", SAMPLE_DOC);

			let info = await instance.items.get(id).info();
			while (info.status === "queued" || info.status === "running") {
				await new Promise((resolve) => setTimeout(resolve, 2_000));
				info = await instance.items.get(id).info();
			}

			return Response.json({ key, status: info.status });
		}

		// Query the instance (see the next step).
		return new Response("Visit /setup first, then query with ?q=");
	},
};
src/index.ts
import { createAISearchNamespace } from "ai-search-provider";
import { generateText, streamText } from "ai";

interface Env {
	AI_SEARCH: AiSearchNamespace;
}

const INSTANCE_NAME = "knowledge-base";

const SAMPLE_DOC = `# Caching on Cloudflare
Cloudflare caches static assets at the edge. Use Cache Rules to control what is
cached, set an Edge Cache TTL to control how long objects stay in cache, and
purge the cache after a deploy.`;

// Create the instance with hybrid search, or update it if it already exists.
async function ensureInstance(env: Env) {
	// index_method with both vector and keyword enables hybrid search.
	const hybrid = { index_method: { vector: true, keyword: true } };
	try {
		await env.AI_SEARCH.create({ id: INSTANCE_NAME, ...hybrid });
	} catch {
		await env.AI_SEARCH.get(INSTANCE_NAME).update(hybrid);
	}
}

export default {
	async fetch(request, env): Promise<Response> {
		const url = new URL(request.url);
		// createAISearchNamespace adapts the binding to the AI SDK provider API.
		const aiSearch = createAISearchNamespace({ binding: env.AI_SEARCH });

		// Visit /setup once to create the instance and index a document.
		if (url.pathname === "/setup") {
			await ensureInstance(env);

			const instance = aiSearch.get(INSTANCE_NAME);

			// upload() queues the file and returns immediately. Indexing runs in
			// the background, so poll the item's status until it is searchable.
			const { id, key } = await instance.items.upload("caching.md", SAMPLE_DOC);

			let info = await instance.items.get(id).info();
			while (info.status === "queued" || info.status === "running") {
				await new Promise((resolve) => setTimeout(resolve, 2_000));
				info = await instance.items.get(id).info();
			}

			return Response.json({ key, status: info.status });
		}

		// Query the instance (see the next step).
		return new Response("Visit /setup first, then query with ?q=");
	},
} satisfies ExportedHandler<Env>;

AiSearchNamespace это ambient-тип, доступный после выполнения wrangler types.

5. Запросите свой экземпляр

Опросить экземпляр из AI SDK можно тремя способами. Выберите тот, который подходит вашему приложению:

Сгенерировать ответ

Передайте instance.chat() к generateText, и AI Search за один вызов находит релевантный контент и генерирует ответ.

Замените заполнитель запроса в своём fetch обработчик следующим образом:

src/index.js
const query = url.searchParams.get("q") ?? "How does caching work?";

// chat() returns an AI SDK model that retrieves matching chunks and generates
// a grounded answer in one call, so there is no separate search step.
const { text, sources } = await generateText({
	model: aiSearch.get(INSTANCE_NAME).chat({
		ai_search_options: {
			// "hybrid" ranks results from both the vector and keyword indexes.
			retrieval: { retrieval_type: "hybrid", max_num_results: 5 },
		},
	}),
	messages: [{ role: "user", content: query }],
});

// `sources` holds the retrieved chunks, so you can cite them alongside `text`.
return Response.json({ text, sources });
src/index.ts
const query = url.searchParams.get("q") ?? "How does caching work?";

// chat() returns an AI SDK model that retrieves matching chunks and generates
// a grounded answer in one call, so there is no separate search step.
const { text, sources } = await generateText({
	model: aiSearch.get(INSTANCE_NAME).chat({
		ai_search_options: {
			// "hybrid" ranks results from both the vector and keyword indexes.
			retrieval: { retrieval_type: "hybrid", max_num_results: 5 },
		},
	}),
	messages: [{ role: "user", content: query }],
});

// `sources` holds the retrieved chunks, so you can cite them alongside `text`.
return Response.json({ text, sources });

AI Search возвращает найденные чанки в виде source parts AI SDK в sources, чтобы вы могли ссылаться на них рядом со сгенерированным текстом. Поскольку экземпляр индексирует и векторы, и ключевые слова, retrieval_type: "hybrid" использует оба.

Потоковая передача ответа

Для более длинных ответов используйте streamText вместо generateText. AI Search отправляет найденные чанки в виде частей источника ещё до первой текстовой части.

// streamText returns right away; tokens stream in as they are generated.
const result = streamText({
	model: aiSearch.get(INSTANCE_NAME).chat(),
	messages: [{ role: "user", content: query }],
});

// toTextStreamResponse() streams the generated text only.
return result.toTextStreamResponse();
// streamText returns right away; tokens stream in as they are generated.
const result = streamText({
	model: aiSearch.get(INSTANCE_NAME).chat(),
	messages: [{ role: "user", content: query }],
});

// toTextStreamResponse() streams the generated text only.
return result.toTextStreamResponse();

toTextStreamResponse() отправляет сгенерированный текст и отбрасывает источники. Чтобы также передавать полученные чанки потоком, верните поток сообщений UI с sendSources включено, или ознакомьтесь с result.fullStream напрямую:

// sendSources forwards each retrieved chunk as a source-url part. They arrive
// before the first text part, so you can render citations as the answer streams.
return result.toUIMessageStreamResponse({ sendSources: true });
// sendSources forwards each retrieved chunk as a source-url part. They arrive
// before the first text part, so you can render citations as the answer streams.
return result.toUIMessageStreamResponse({ sendSources: true });

Поиск как инструмент

С chat(), AI Search выполняет поиск в вашем экземпляре при каждом запросе. Чтобы решение о том, когда искать, принимала модель, предоставьте instance.search() как AI SDK инструмент ↗ и передайте её модели, которая поддерживает вызов функций, например Workers AI модель. Это тот паттерн, который стоит использовать в агенте, где модель сама выбирает между поиском и другими инструментами.

Установите провайдер Workers AI и Zod. Используйте версию 3 workers-ai-provider: последняя версия 4 требует AI SDK v7, но ai-search-provider требует v6, поэтому npm не может установить их вместе.

npm i workers-ai-provider@^3 zod

Добавьте привязку Workers AI в конфигурацию Wrangler:

{
  "$schema": "./node_modules/wrangler/config-schema.json",
  "ai": {
    "binding": "AI"
  }
}
[ai]
binding = "AI"

Затем определите инструмент поиска. Модель вызывает его, когда ей нужно получить контент:

import { createWorkersAI } from "workers-ai-provider";
import { generateText, tool, stepCountIs } from "ai";
import { z } from "zod";

const instance = aiSearch.get(INSTANCE_NAME);
// The tool-caller must support function calling. Use a dedicated model here
// rather than the AI Search chat model, which retrieves on every request.
const workersai = createWorkersAI({ binding: env.AI });

const { text } = await generateText({
	model: workersai("@cf/zai-org/glm-5.2"),
	messages: [{ role: "user", content: query }],
	tools: {
		search_knowledge_base: tool({
			description: "Search the indexed knowledge base for relevant content.",
			inputSchema: z.object({
				query: z.string().describe("The search query"),
			}),
			// The model decides when to call this; it searches the instance.
			execute: async ({ query }) =>
				instance.search({
					query,
					ai_search_options: { retrieval: { max_num_results: 5 } },
				}),
		}),
	},
	// Cap the tool-call loop so the model cannot invoke tools indefinitely.
	stopWhen: stepCountIs(5),
});
import { createWorkersAI } from "workers-ai-provider";
import { generateText, tool, stepCountIs } from "ai";
import { z } from "zod";

const instance = aiSearch.get(INSTANCE_NAME);
// The tool-caller must support function calling. Use a dedicated model here
// rather than the AI Search chat model, which retrieves on every request.
const workersai = createWorkersAI({ binding: env.AI });

const { text } = await generateText({
	model: workersai("@cf/zai-org/glm-5.2"),
	messages: [{ role: "user", content: query }],
	tools: {
		search_knowledge_base: tool({
			description: "Search the indexed knowledge base for relevant content.",
			inputSchema: z.object({
				query: z.string().describe("The search query"),
			}),
			// The model decides when to call this; it searches the instance.
			execute: async ({ query }) =>
				instance.search({
					query,
					ai_search_options: { retrieval: { max_num_results: 5 } },
				}),
		}),
	},
	// Cap the tool-call loop so the model cannot invoke tools indefinitely.
	stopWhen: stepCountIs(5),
});

6. Протестируйте локально

Перед развёртыванием убедитесь, что весь процесс работает с вашим экземпляром, с помощью wrangler dev, который проксирует удалённую привязку AI Search. Вывод ниже получен от сформировать ответ опцию.

Запустите локальный сервер разработки:

npx wrangler dev

Сначала проиндексируйте образец документа, перейдя по /setup:

curl http://localhost:8787/setup

Первые /setup может занять пару минут, пока документ индексируется. По завершении вы получите ключ элемента и completed статус:

{ "key": "caching.md", "status": "completed" }

Затем отправьте запрос к экземпляру:

curl "http://localhost:8787/?q=How+does+caching+work%3F"

Работающая интеграция возвращает сгенерированный text основанный на вашем документе, а также sources массив со ссылкой на найденный файл (поля сокращены):

{
	"text": "Cloudflare caches static assets at the edge...",
	"sources": [{ "sourceType": "url", "url": "caching.md" }]
}

Если sources возвращается пустым, значит документ ещё не завершил индексацию. Выполните /setup ещё раз и повторите запрос.

7. Разверните

Войдите в свою учётную запись Cloudflare:

npx wrangler login

Разверните свой Worker, чтобы сделать его доступным в интернете:

npx wrangler deploy

Особенности

Следующие шаги

Гибридный поиск

Объедините векторный поиск и поиск по ключевым словам с настраиваемым слиянием.

Привязка Workers для экземпляров

Полный справочник по созданию, обновлению, получению списка и удалению.

Привязка Workers для поиска

Полный справочник по поиску и общению из Worker.

Agents SDK

Создайте чат-агента с состоянием, который выполняет поиск по вашему экземпляру.