- BrainTools - https://www.braintools.ru -
Интеграция с крупными языковыми моделями (LLMs) стала неотъемлемой частью разработки современных приложений. Независимо от того, создаёте ли вы контент, анализируете данные или разрабатываете интерфейсы для общения с пользователем, добавление возможностей, основанных на AI, имеет потенциал как расширить функциональность вашего продукта, так и улучшить пользовательский опыт [1].
Однако успешная интеграция возможностей, основанных на LLM, в приложение может оказаться довольно сложной. Разработчикам приходится ориентироваться в многообразии потенциальных сбоев: ошибки [2] сети, сбои поставщика, ограничения по количеству запросов и многое другое – всё это необходимо обрабатывать, обеспечивая стабильность и отзывчивость приложения для конечного пользователя. Кроме того, различия между API поставщиков языковых моделей могут вынуждать разработчиков писать хрупкий «клейкий код», который в дальнейшем может стать значительным источником технического долга.
Сегодня мы рассмотрим интеграционные пакеты [3] AI от Effect – набор библиотек, спроектированных для упрощения работы с LLM, обеспечения гибкости и независимости от конкретного провайдера.
Пакеты AI от Effect предоставляют простые, композиционные строительные блоки для моделирования взаимодействия с LLM в безопасном, декларативном и модульном стиле. С их помощью можно:
Опишите взаимодействие с LLM один раз, а затем просто подключите необходимого провайдера. Это позволяет переключаться между любыми поддерживаемыми провайдерами, не затрагивая бизнес-логику.
Проводите тестирование, предоставляя моки реализации сервисов, чтобы убедиться, что логика [4], зависящая от AI, выполняется так, как ожидается.
Запускайте параллельные вызовы LLM, отменяйте устаревшие запросы, реализуйте стриминг частичных результатов или организуйте «гонки» между несколькими провайдерами – всё это безопасно управляется моделью структурированной конкурентности от Effect.
Инструментируйте взаимодействие с LLM с помощью встроенного трейсинга, логирования и метрик, чтобы выявлять узкие места в производительности или сбои в продакшне.
Экосистема AI от Effect состоит из нескольких узкоспециализированных пакетов, каждый из которых выполняет свою задачу:
@effect/ai:
базовый пакет, который определяет независимые от провайдера сервисы и абстракции для взаимодействия с LLM.
@effect/ai-openai:
конкретные реализации AI-сервисов на базе API OpenAI.
@effect/ai-anthropic:
конкретные реализации AI-сервисов на базе API Anthropic.
Такая архитектура позволяет описывать взаимодействия с LLM с помощью сервисов, не привязанных к конкретному провайдеру, и затем подключать конкретную реализацию при запуске программы.
Основополагающая философия интеграций AI от Effect заключается в программировании, независимом от провайдера.
Вместо того чтобы захардкодить вызовы API конкретного провайдера LLM, вы описываете взаимодействие с помощью универсальных сервисов базового пакета @effect/ai
.
import { Completions } from "@effect/ai"
import { Effect } from "effect"
// Define a provider-agnostic AI interaction
const generateDadJoke = Effect.gen(function*() {
// Get the Completions service from the Effect environment
const completions = yield* Completions.Completions
// Use the service to generate text
const response = yield* completions.create("Generate a dad joke")
// Return the response
return response
})
Это разделение ответственности лежит в основе подхода Effect к взаимодействию с LLM.
Чтобы преодолеть разрыв между бизнес-логикой, независимой от провайдера, и конкретными провайдерами LLM, Effect вводит абстракцию AiModel
.
AiModel
представляет собой конкретную LLM от определённого провайдера, которая может удовлетворять требованиям сервиса, таким как Completions
или Embeddings
.
import { OpenAiCompletions } from "@effect/ai-openai"
import { Effect } from "effect"
import { Completions } from "@effect/ai"
// Define a provider-agnostic AI interaction
const generateDadJoke = Effect.gen(function*() {
// Get the Completions service from the Effect environment
const completions = yield* Completions.Completions
// Use the service to generate text
const response = yield* completions.create("Generate a dad joke")
// Return the response
return response
})
// Create an AiModel for OpenAI's GPT-4o
const Gpt4o = OpenAiCompletions.model("gpt-4o")
// Use the model to provide the Completions service to our program
const main = Effect.gen(function*() {
// Build the AiModel into a Provider
const gpt4o = yield* Gpt4o
// Provide the implementation to our generateDadJoke program
const response = yield* gpt4o.provide(generateDadJoke)
console.log(response.text)
})
Преимущества данного подхода:
Переиспользуемость: можно использовать одну и ту же модель для нескольких операций
Гибкость: легко переключаться между провайдерами или моделями по мере необходимости
Абстрагирование: выделяйте логику AI в сервисы, скрывающие детали реализации.
Рассмотрим полный пример настройки взаимодействия с LLM с использованием Effect
import { OpenAiClient, OpenAiCompletions } from "@effect/ai-openai"
import { Completions } from "@effect/ai"
import { NodeHttpClient } from "@effect/platform-node"
import { Config, Effect, Layer } from "effect"
// 1. Define our provider-agnostic AI interaction
const generateDadJoke = Effect.gen(function*() {
const completions = yield* Completions.Completions
const response = yield* completions.create("Generate a dad joke")
return response
})
// 2. Create an AiModel for a specific provider and model
const Gpt4o = OpenAiCompletions.model("gpt-4o")
// 3. Create a program that uses the model
const main = Effect.gen(function*() {
const gpt4o = yield* Gpt4o
const response = yield* gpt4o.provide(generateDadJoke)
console.log(response.text)
})
// 4. Create a Layer that provides the OpenAI client
const OpenAi = OpenAiClient.layerConfig({
apiKey: Config.redacted("OPENAI_API_KEY")
})
// 5. Provide an HTTP client implementation
const OpenAiWithHttp = Layer.provide(OpenAi, NodeHttpClient.layerUndici)
// 6. Run the program with the provided dependencies
main.pipe(
Effect.provide(OpenAiWithHttp),
Effect.runPromise
)
В приведённом примере продемонстрированы основные шаги:
Определяется взаимодействие с AI, независимое от провайдера.
Создается AiModel
для конкретного провайдера и модели.
Разрабатывается программа, использующая данную модель.
Создается слой (Layer), предоставляющий клиент OpenAI.
Предоставляется HTTP-клиент.
Программа запускается с нужными зависимостями.
Одна из сильных сторон Effect – его надёжная обработка ошибок, что особенно ценно при взаимодействии с LLM, где возможные сценарии сбоев могут быть сложными и разнообразными. С помощью Effect ошибки типизированы и могут обрабатываться явно.
Например, если программу генерации шутки необходимо переписать так, чтобы она могла завершаться с ошибками RateLimitError
или InvalidInputError
, можно прописать соответствующую логику обработки ошибок.
import { AiResponse, AiRole } from "@effect/ai"
import { Effect } from "effect"
import { Completions } from "@effect/ai"
import { Data } from "effect"
class RateLimitError extends Data.TaggedError("RateLimitError") {}
class InvalidInputError extends Data.TaggedError("InvalidInputError") {}
declare const generateDadJoke: Effect.Effect<
AiResponse.AiResponse,
RateLimitError | InvalidInputError,
Completions.Completions
>
const withErrorHandling = generateDadJoke.pipe(
Effect.catchTags({
RateLimitError: (error) =>
Effect.logError("Rate limited, retrying in a moment").pipe(
Effect.delay("1 seconds"),
Effect.andThen(generateDadJoke)
),
InvalidInputError: (error) =>
Effect.succeed(AiResponse.AiResponse.fromText({
role: AiRole.model,
content: "I couldn't generate a joke right now."
}))
})
)
Для более сложных сценариев, где требуется высокая надёжность при использовании нескольких провайдеров, Effect предлагает мощную абстракцию AiPlan [5].
AiPlan
позволяет создавать структурированные планы выполнения для взаимодействия с LLM с встроенной логикой повторных попыток, стратегиями запасного варианта (fall-back) и обработкой ошибок.
import { AiPlan } from "@effect/ai"
import { OpenAiCompletions } from "@effect/ai-openai"
import { AnthropicCompletions } from "@effect/ai-anthropic"
import { Data, Effect, Schedule } from "effect"
import { Completions } from "@effect/ai"
const generateDadJoke = Effect.gen(function*() {
const completions = yield* Completions.Completions
const response = yield* completions.create("Generate a dad joke")
return response
})
// Define domain-specific error types
class NetworkError extends Data.TaggedError("NetworkError") {}
class ProviderOutage extends Data.TaggedError("ProviderOutage") {}
// Build a resilient plan that:
// - Attempts to use OpenAI's `"gpt-4o"` model up to 3 times
// - Waits with an exponential backoff between attempts
// - Only re-attempts the call to OpenAI if the error is a `NetworkError`
// - Falls back to using Anthropic otherwise
const DadJokePlan = AiPlan.fromModel(OpenAiCompletions.model("gpt-4o"), {
attempts: 3,
schedule: Schedule.exponential("100 millis"),
while: (error: NetworkError | ProviderOutage) =>
error._tag === "NetworkError"
}).pipe(
AiPlan.withFallback({
model: AnthropicCompletions.model("claude-3-7-sonnet-latest"),
})
)
// Use the plan just like an AiModel
const main = Effect.gen(function*() {
const plan = yield* DadJokePlan
const response = yield* plan.provide(generateDadJoke)
})
С помощью AiPlan
можно:
Создавать сложные политики повторных попыток с настраиваемыми стратегиями экспоненциальной задержки.
Определять цепочки запасных вариантов между несколькими провайдерами.
Указывать, какие типы ошибок должны инициировать повторные попытки, а какие – запасной вариант.
Это особенно ценно для продакшн-систем, где критична надёжность, так как позволяет использовать нескольких провайдеров LLM в качестве резервных, сохраняя бизнес-логику независимой от конкретного провайдера.
Модель структурированной конкурентности Effect облегчает управление параллельными запросами к LLM:
import { Effect } from "effect"
import { Completions } from "@effect/ai"
const generateDadJoke = Effect.gen(function*() {
const completions = yield* Completions.Completions
const response = yield* completions.create("Generate a dad joke")
return response
})
// Generate multiple jokes concurrently
const concurrentDadJokes = Effect.all([
generateDadJoke,
generateDadJoke,
generateDadJoke
], { concurrency: 2 }) // Limit to 2 concurrent requests
Интеграции AI от Effect поддерживают стриминг ответов с использованием типа Stream [6]:
import { Completions } from "@effect/ai"
import { Effect, Stream } from "effect"
const streamingJoke = Effect.gen(function*() {
const completions = yield* Completions.Completions
// Create a streaming response
const stream = completions.stream("Tell me a long dad joke")
// Process each chunk as it arrives
return yield* stream.pipe(
Stream.runForEach(chunk =>
Effect.sync(() => {
process.stdout.write(chunk.text)
})
)
)
})
Неважно, создаёте ли вы интеллектуального агента, интерактивный чат или систему, использующую LLM для фоновых задач – пакеты AI от Effect предоставляют все необходимые инструменты и даже больше. Наш подход, независимый от провайдера, гарантирует, что ваш код останется адаптируемым по мере развития AI-среды.
Готовы попробовать Effect для вашего следующего AI‑приложения? Обратитесь к руководству «Getting Started [7]».
Интеграционные пакеты Effect AI находятся на стадии экспериментов/альфа, но мы настоятельно рекомендуем вам опробовать их и предоставить обратную связь, которая поможет нам улучшить и расширить их возможности.
Мы с нетерпением ждём увидеть ваши проекты! Ознакомьтесь с полной документацией [8] для более глубокого погружения и присоединяйтесь к нашему сообществу, чтобы делиться опытом и получать помощь.
Автор: kondaurovDev
Источник [9]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/13812
URLs in this post:
[1] опыт: http://www.braintools.ru/article/6952
[2] ошибки: http://www.braintools.ru/article/4192
[3] интеграционные пакеты: https://Effect%E2%80%99s%20AI%20integration%20packages
[4] логика: http://www.braintools.ru/article/7640
[5] AiPlan: https://effect.website/docs/ai/planning-llm-interactions/
[6] Stream: https://effect.website/docs/stream/introduction/
[7] Getting Started: https://effect.website/docs/ai/getting-started/
[8] полной документацией: https://effect.website/docs/ai/introduction/
[9] Источник: https://habr.com/ru/articles/896686/?utm_source=habrahabr&utm_medium=rss&utm_campaign=896686
Нажмите здесь для печати.