Aug 10, 2025
7 min

Brama do wszystkich modeli AI. Jak uruchomić LiteLLM na AWS?

Brama do wszystkich modeli AI. Jak uruchomić LiteLLM na AWS?

Ilość modeli, do których mamy dostęp, oraz to, jak szybko pojawiają się nowe, może przyprawić o zawrót głowy. Szczególnie gdy chcesz mieć najnowsze modele w swojej aplikacji, śledzić koszty i wdrożyć observability. Rozwiązaniem tego problemu może być LLM Gateway.

Czym jest LLM Gateway?

Jest to element infrastruktury, który ma uprościć korzystanie z różnych modeli od różnych dostawców. Zamiast integrować się ze wszystkimi dostawcami osobno, integrujesz się z jednym LLM Gateway, który obsługuje ruch do innych dostawców. Najczęściej LLM Gateway będzie oferować API w formacie kompatybilnym z OpenAI, który jest obsługiwany przez wszystkie biblioteki. Oprócz tego często oferuje dodatkowe funkcjonalności, takie jak:

  • analityka
  • kontrola kosztów
  • konfiguracja limitów
  • Guardrails
  • i inne.

LiteLLM

LiteLLM jest jednym z najpopularniejszych rozwiązań typu LLM Gateway dostępnych w modelu open-source. Można go uruchomić na swojej infrastrukturze i uprościć zarządzanie różnymi modelami. Poza standardową funkcjonalnością oferuje również:

  • Śledzenie kosztów
  • Guardrails
  • Konfiguracja budżetów
  • Rate Limiting
  • Observability

LiteLLM można uruchomić w 3 opcjach:

  • jako biblioteka Python, która oferuje jednolity interfejs do różnych modeli
  • proxy
    • w wersji stateless, bez bazy danych, ale również bez niektórych funkcjonalności
    • z bazą danych i wszystkimi funkcjonalnościami

To, co podoba mi się w LiteLLM, to bogata dokumentacja, obszerny plik konfiguracyjny oraz przystępny panel admina.

Kiedy warto zastosować LiteLLM?

Jest to ciekawe rozwiązanie, ale dodaje dodatkowy narzut oraz konieczność utrzymywania dodatkowej infrastruktury. Widzę 2 główne zastosowania dla tego rozwiązania:

  • W aplikacji korzystasz z różnych modeli od różnych dostawców i chcesz tym zarządzać w jednym miejscu.
  • Chcesz dać dostęp do modeli różnym osobom, ale nie chcesz dawać bezpośrednio do dostawców. Jest to ciekawa opcja dla firm, które chcą uprościć zarządzanie dostępami do modeli i optymalizować koszty przez nadanie limitów.

Przykład użycia LiteLLM z AI SDK

Tak jak pisałem wyżej, LiteLLM wystawia zgodne API z OpenAI. Dzięki temu dowolny klient OpenAI zadziała. AI SDK ma osobną bibliotekę dla takiej konfiguracji, którą można użyć.

1npm i @ai-sdk/openai-compatible
2
TypeScript
1import { generateText } from 'ai';
2
3import { createOpenAICompatible } from '@ai-sdk/openai-compatible';
4
5const litellm = createOpenAICompatible({
6  name: 'litellm',
7  baseURL: 'http://localhost:4000/v1',
8  apiKey: 'sk-XYZ'
9});
10
11const completion = await generateText({
12    prompt: "Tell me a joke",
13    model: litellm('anthropic.claude-3-5-sonnet-20240620-v1:0')
14});
15
16console.log(completion);
17

Najważniejsze to podmienić baseURL na właściwy oraz dodać apiKey. Reszta wygląda jak korzystanie ze wszystkich innych modeli.

Deploy LiteLLM na AWS AppRunner z AWS CDK

LiteLLM udostępnia obraz Dockerowy, który umożliwia uruchomienie tego rozwiązania w dowolnym miejscu. W oficjalnej dokumentacji znajdziesz instrukcje, jak uruchomić to w AWS EKS (Kubernetes) lub bezpośrednio na EC2. Ja wolę AppRunner, bo jest prostszy dla mniej doświadczonych użytkowników. Uruchomienie jest banalnie proste, o ile nie popełnisz błędów, które ja popełniłem za pierwszym razem.

Architektura

LiteLLM potrzebuje kilku elementów, by poprawnie działać:

  • AWS S3 - do trzymania pliku konfiguracyjnego
  • AWS ECR - do trzymania obrazu Dockerowego
  • AWS Bedrock - jako dostawca modeli (ale można użyć innych dostawców)
  • AWS AppRunner - jako serwis do uruchomienia obrazu dockerowego
  • AWS IAM - musimy dodać rolę dla instancji AppRunner, by była w stanie dostać się do S3 oraz uruchamiać modele w Bedrock
  • AWS RDS - baza danych, ale można użyć czegoś innego, np.: Supabase

Wszystko to można konfigurować ręcznie, ale jest to narażone na błędy i lepiej wykorzystać podejście IaC do zautomatyzowania tego.

LiteLLM IaC z AWS CDK

Ja wykorzystałem AWS CDK, ale możesz użyć dowolnego rozwiązania dla IaC, jak Pulumi albo Terraform. Niezależnie od wykorzystanego narzędzia trzeba zrobić:

  1. Stworzyć bucket S3
  2. Zrobić upload pliku konfiguracyjnego (w momencie uruchomienia aplikacji na AppRunner plik musi być dostępny)
  3. Stworzyć rolę dla AppRunner z dostępem do ECR (accessRole)
  4. Stworzyć rolę dla AppRunner z dostępem do S3 i Bedrock (instanceRole)
  5. Stworzyć instancję AppRunner z odpowiednimi zmiennymi
    • DATABASE_URL - db url do bazy danych
    • LITELLM_CONFIG_BUCKET_NAME - nazwa bucketu utworzonego w kroku 1
    • LITELLM_CONFIG_BUCKET_OBJECT_KEY - nazwa pliku konfiguracyjnego *yaml
    • LITELLM_MASTER_KEY - klucz master w formacie sk-XXX
    • STORE_MODEL_IN_DB - ’True’ by zapisywać konfiguracje w bazie

Konfiguracja krok po kroku

Na start warto skorzystać z oficjalnego CLI od AWS CDK, które stworzy projekt z odpowiednimi plikami

1mkdir litellm
2cd litellm
3cdk init app --language=typescript
4

Następnie w katalogu lib będzie plik litellm-stack.ts, który trzeba zmodyfikować

TypeScript
1export interface LitellmStackProps extends cdk.StackProps {
2  ecrRepositoryName: string;
3  imageTag?: string;
4  databaseUrl: string;
5  litellmMasterKey: string;
6}
7
8export class LitellmStack extends cdk.Stack {
9
10  constructor(scope: Construct, id: string, props: LitellmStackProps) {
11    super(scope, id, props);
12  }
13}
14

Wszystkie operacje można wykonać w konstruktorze albo rozbić na więcej metod. Z racji tego, że nie potrzebuję tutaj dużej reużywalności elementów, to wszystko wrzuciłem do konstruktora.

Stworzenie bucketu na S3

TypeScript
1const configBucket = new s3.Bucket(this, 'LitellmConfigBucket', {
2      bucketName: `litellm-config-${this.account}-${this.region}`,
3      removalPolicy: cdk.RemovalPolicy.DESTROY,
4      autoDeleteObjects: true, // For development/testing
5});
6

Tutaj nie ma dużej filozofii. Przy tworzeniu bucketa jedynie nazwa jest wymagana, a resztę możemy zostawić jako domyślne. Ja tutaj jedynie dodałem opcję, by podczas usuwania stack’a usuwało też cały bucket.

Upload pliku z konfiguracją

TypeScript
1const configDeployment = new s3deploy.BucketDeployment(this, 'ConfigDeployment', {
2      sources: [s3deploy.Source.asset('./config')],
3      destinationBucket: configBucket,
4      retainOnDelete: false,
5});
6

Przy uploadzie należy zwrócić uwagę na poprawną ścieżkę do plików. Ja tutaj synchronizuję cały folder config. Ścieżka jest relatywna w stosunku do pliku package.json, a nie w stosunku do pliku litellm-stack.

Tworzenie roli dla AppRunner z dostępem do ECR (accessRole)

TypeScript
1const accessRole = new iam.Role(this, 'AppRunnerAccessRole', {
2      assumedBy: new iam.ServicePrincipal('build.apprunner.amazonaws.com'),
3      description: 'Role for App Runner to access ECR',
4});
5
6accessRole.addToPolicy(
7      new iam.PolicyStatement({
8        effect: iam.Effect.ALLOW,
9        actions: [
10          'ecr:GetAuthorizationToken',
11          'ecr:BatchCheckLayerAvailability',
12          'ecr:GetDownloadUrlForLayer',
13          'ecr:BatchGetImage',
14        ],
15        resources: ['*'],
16      })
17);
18

Jest to rola wykorzystywana podczas etapu tworzenia nowej instancji AppRunner i tutaj potrzebny jest jedynie dostęp do ECR, skąd można pobrać obraz Docker’a.

Tworzenie roli dla AppRunner z dostępem do S3 i Bedrock (instanceRole)

TypeScript
1const appRunnerRole = new iam.Role(this, 'AppRunnerServiceRole', {
2      assumedBy: new iam.ServicePrincipal('tasks.apprunner.amazonaws.com'),
3      description: 'Role for LiteLLM App Runner service',
4});
5
6configBucket.grantRead(appRunnerRole);
7
8appRunnerRole.addToPolicy(
9      new iam.PolicyStatement({
10        effect: iam.Effect.ALLOW,
11        actions: [
12          'bedrock:InvokeModel',
13          'bedrock:InvokeModelWithResponseStream',
14        ],
15        resources: ['*'], // You might want to restrict this to specific models
16      })
17);
18

Z kolei ta rola jest wymagana wyłącznie dla uruchomionej instancji AppRunner i tutaj jest potrzebny dostęp do S3 (by pobrać konfigurację) oraz Bedrock, by uruchamiać modele.

Konfiguracja AppRunner

TypeScript
1const appRunnerService = new apprunner.Service(this, 'LitellmAppRunnerService', {
2      serviceName: 'ap-litellm-service',
3      source: apprunner.Source.fromEcr({
4        imageConfiguration: {
5          port: 4000, // Default LiteLLM port
6          environmentVariables: {
7            DATABASE_URL: props.databaseUrl,
8            LITELLM_CONFIG_BUCKET_NAME: configBucket.bucketName,
9            LITELLM_CONFIG_BUCKET_OBJECT_KEY: 'litellm-config.yaml',
10            LITELLM_MASTER_KEY: props.litellmMasterKey,
11            STORE_MODEL_IN_DB: 'True',
12          },
13        },
14        repository: ecrRepository,
15        tagOrDigest: props.imageTag || 'latest',
16      }),
17      accessRole: accessRole,
18      instanceRole: appRunnerRole,
19      cpu: apprunner.Cpu.TWO_VCPU,
20      memory: apprunner.Memory.FOUR_GB,
21      autoDeploymentsEnabled: false,
22});
23

Ostatnia rzecz to stworzenie odpowiedniej instancji AppRunner z wszystkimi wcześniej skonfigurowanymi elementami.

LiteLLM Deploy Troubleshooting

Błąd połączenia z bazą danych

Sprawdź, czy AppRunner ma dostęp do bazy danych. Jeśli masz RDS’a skonfigurowanego poprawnie, to pewnie jest w prywatnym VPC. Musisz się upewnić, że AppRunner ma właściwą konfigurację dla Egress.

W przypadku Supabase zadziałał mi dopiero Session pooler. Obstawiam, że to kwestia wsparcia dla IPv4, ale nie zgłębiałem bardziej tego tematu.

W przypadku baz danych hostowanych gdzieś indziej warto upewnić się, że URL jest poprawny.

Błąd z plikiem konfiguracyjnym

Upewnij się, że AppRunner ma dostęp do pliku w momencie uruchamiania i plik nie jest pusty. Pusty plik jest traktowany tak, jakby go nie było. Jeśli nie potrzebujesz nic konfigurować, to wrzuć poniższą zawartość

YAML
1model_list:
2

Czytaj więcej

Optymalizacja kosztów LLM
Aug 10, 2025
Optymalizacja kosztów LLM, czyli jak płacić mniej za AI.
Modele LLM potrafi być strasznie drogie na produkcji. W poście znajdziesz kilka strategii na optymalizację kosztów AI bez straty wydajności.
jak budować PoC dla aplikacji AI
Aug 10, 2025
Jak budować PoC aplikacji AI?
Pomyłki przy budowaniu aplikacji AI są KOSZTOWNE. Można temu zapobiec dodając etap prototypowania przed rozpoczęciem dużych prac.
Halucynacje AI  - skąd się biorą i jak je ograniczać?
Aug 10, 2025
Halucynacje AI, czyli dlaczego sztuczna inteligencja kłamie?
Modele LLM potrafią tworzyć wiarygodne informacje, które są kłamstwem. Zjawisko halucynacji AI jest poważnym problemem i wyzwaniem dla programistów aplikacji AI