
Введение
Декораторы в Python отлично подходят для упрощения сложной логики в приложениях разного типа, включая те, что построены на больших языковых моделях. Работа с такими моделями часто сталкивается с непредсказуемыми, медленными и затратными внешними API, а декораторы позволяют обернуть вызовы этих API в удобную оптимизированную обертку.
Рассмотрим пять практичных декораторов Python, которые сделают приложения на LLM быстрее без лишних усилий.
Примеры демонстрируют синтаксис и принцип работы каждого декоратора. Иногда они показаны без реальных вызовов LLM, но предназначены для интеграции в полноценные проекты.
1. Кэширование в памяти
Этот подход берется из стандартной библиотеки Python functools и подходит для ресурсоемких функций, таких как запросы к LLM. Если обернуть функцию с вызовом LLM в декоратор LRU (Least Recently Used), то появится механизм кэша, который заблокирует повторные запросы с одинаковыми входными данными (промтами) в рамках одной сессии. Такой метод заметно сокращает задержки.
Вот пример использования:
from functools import lru_cache
import time
@lru_cache(maxsize=100)
def summarize_text(text: str) -> str:
print("Sending text to LLM...")
time.sleep(1) # A simulation of network delay
return f"Summary of {len(text)} characters."
print(summarize_text("The quick brown fox.")) # Takes one second
print(summarize_text("The quick brown fox.")) # Instant2. Кэширование на диске
Библиотека diskcache развивает идею кэширования дальше: она сохраняет данные на жестком диске с помощью базы SQLite. Это удобно для хранения результатов длительных операций вроде вызовов LLM API, чтобы потом быстро их подгружать. Применяйте такой декоратор, когда кэш в памяти не подходит из-за перезапуска скрипта или приложения.
import time
from diskcache import Cache
# Creating a lightweight local SQLite database directory
cache = Cache(".local_llm_cache")
@cache.memoize(expire=86400) # Cached for 24 hours
def fetch_llm_response(prompt: str) -> str:
print("Calling expensive LLM API...")
# Replace this by an actual LLM API call
time.sleep(2) # API latency simulation
return f"Response to: {prompt}"
print(fetch_llm_response("What is quantum computing?")) # 1st function call
print(fetch_llm_response("What is quantum computing?")) # Instant load from disk happens here!3. Приложения, устойчивые к сбоям сети
LLM часто дают сбои из-за временных ошибок, таймаутов или ответов вроде "502 Bad Gateway". Библиотека tenacity с декоратором @retry помогает перехватывать такие проблемы интернета.
В примере ниже имитируется 70% вероятность сетевой ошибки. Запустите несколько раз — ошибка появится, это нормально и задумано.
import random
from tenacity import retry, wait_exponential, stop_after_attempt, retry_if_exception_type
class RateLimitError(Exception):
pass
# Retrying up to 4 times, waiting 2, 4, and 8 seconds between each attempt
@retry(
wait=wait_exponential(multiplier=2, min=2, max=10),
stop=stop_after_attempt(4),
retry=retry_if_exception_type(RateLimitError)
)
def call_flaky_llm_api(prompt: str):
print("Attempting to call API...")
if random.random() < 0.7: # Simulating a 70% chance of API failure
raise RateLimitError("Rate limit exceeded! Backing off.")
return "Text has been successfully generated!"
print(call_flaky_llm_api("Write a haiku"))4. Ограничение скорости на стороне клиента
Этот декоратор на базе библиотеки ratelimit регулирует частоту вызовов функции, что важно для избежания лимитов при работе с популярными внешними API. Пример устанавливает лимит в запросы в минуту (RPM), чтобы провайдер не отклонял слишком частые промты.
from ratelimit import limits, sleep_and_retry
import time
# Strictly enforcing a 3-call limit per 10-second window
@sleep_and_retry
@limits(calls=3, period=10)
def generate_text(prompt: str) -> str:
print(f"[{time.strftime('%X')}] Processing: {prompt}")
return f"Processed: {prompt}"
# First 3 print immediately, the 4th pauses, thereby respecting the limit
for i in range(5):
generate_text(f"Prompt {i}")5. Привязка структурированных выходных данных
Пятый декоратор использует библиотеку magentic вместе с Pydantic для удобного общения с LLM через API и получения ответов в строгом формате. Он упрощает вызовы API и заставляет модели выдавать данные вроде JSON надежно. Декоратор сам управляет системными промтами и разбором через Pydantic, экономя токены и сохраняя код чистым.
Для примера нужен ключ OpenAI API.
# IMPORTANT: An OPENAI_API_KEY set is required to run this simulated example
from magentic import prompt
from pydantic import BaseModel
class CapitalInfo(BaseModel):
capital: str
population: int
# A decorator that easily maps the prompt to the Pydantic return type
@prompt("What is the capital and population of {country}?")
def get_capital_info(country: str) -> CapitalInfo:
... # No function body needed here!
info = get_capital_info("France")
print(f"Capital: {info.capital}, Population: {info.population}")Итоги
Мы разобрали пять декораторов Python из разных библиотек, которые особенно полезны в приложениях на LLM: они упрощают код, повышают скорость работы, добавляют устойчивость к сетевым проблемам и решают другие задачи.