LLM API Integration: Интеграция с LLM API

llmapiintegrationopenaianthropicsdk
← Back to Blog

Введение

Интеграция с LLM API — ключевой навык для разработки приложений с AI. Рассмотрим основные API, SDK и лучшие практики.


OpenAI API

Базовая интеграция

from openai import OpenAI

client = OpenAI(api_key="your-api-key")

# Chat Completions
response = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "What is the capital of France?"}
    ],
    temperature=0.7,
    max_tokens=500
)

print(response.choices[0].message.content)

Streaming responses

from openai import OpenAI

client = OpenAI()

stream = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Write a story"}],
    stream=True
)

for chunk in stream:
    if chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="")

Async API

import asyncio
from openai import AsyncOpenAI

async def main():
    client = AsyncOpenAI()
    
    response = await client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": "Hello!"}]
    )
    
    print(response.choices[0].message.content)

asyncio.run(main())

Anthropic Claude API

Базовое использование

import anthropic

client = anthropic.Anthropic(api_key="your-api-key")

message = client.messages.create(
    model="claude-sonnet-4-20250514",
    max_tokens=1000,
    temperature=0,
    system="You are a helpful assistant specialized in technical writing.",
    messages=[
        {"role": "user", "content": "Explain how transformers work"}
    ]
)

print(message.content[0].text)

Streaming с Claude

import anthropic

client = anthropic.Anthropic()

with client.messages.stream(
    model="claude-sonnet-4-20250514",
    max_tokens=1000,
    messages=[{"role": "user", "content": "Write a detailed explanation"}]
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)
    
    message = stream.get_final_message()

Tool use с Claude

import anthropic

client = anthropic.Anthropic()

tools = [
    {
        "name": "get_weather",
        "description": "Get the current weather for a location",
        "input_schema": {
            "type": "object",
            "properties": {
                "location": {
                    "type": "string",
                    "description": "City and country, e.g. 'Tokyo, Japan'"
                }
            },
            "required": ["location"]
        }
    },
    {
        "name": "calculate",
        "description": "Perform a calculation",
        "input_schema": {
            "type": "object",
            "properties": {
                "expression": {
                    "type": "string",
                    "description": "Mathematical expression"
                }
            },
            "required": ["expression"]
        }
    }
]

message = client.messages.create(
    model="claude-sonnet-4-20250514",
    max_tokens=1000,
    tools=tools,
    messages=[{"role": "user", "content": "What's the weather in Paris and what's 25 * 4?"}]
)

# Handle tool use
for content in message.content:
    if content.type == "tool_use":
        if content.name == "get_weather":
            weather = get_weather(content.input["location"])
            print(f"Weather: {weather}")
        elif content.name == "calculate":
            result = eval(content.input["expression"])
            print(f"Result: {result}")

Google Gemini API

Базовое использование

import google.generativeai as genai

genai.configure(api_key="your-api-key")

model = genai.GenerativeModel("gemini-2.0-flash")

response = model.generate_content("Explain quantum computing")
print(response.text)

Multi-modal input

import google.generativeai as genai
from PIL import Image

genai.configure(api_key="your-api-key")
model = genai.GenerativeModel("gemini-2.0-flash")

image = Image.open("diagram.png")

response = model.generate_content([
    "Explain this diagram",
    image
])

print(response.text)

Streaming с Gemini

import google.generativeai as genai

genai.configure(api_key="your-api-key")
model = genai.GenerativeModel("gemini-2.0-flash")

response = model.generate_content(
    "Write a detailed essay about AI",
    stream=True
)

for chunk in response:
    print(chunk.text, end="")

Meta Llama API

Использование через Fireworks AI

import openai

# Используем OpenAI SDK с Llama через Fireworks
client = openai.OpenAI(
    api_key="fireworks-api-key",
    base_url="https://api.fireworks.ai/inference/v1"
)

response = client.chat.completions.create(
    model="accounts/fireworks/models/llama-v3-70b-instruct",
    messages=[{"role": "user", "content": "Hello!"}],
    temperature=0.7,
    max_tokens=1000
)

print(response.choices[0].message.content)

Использование через Together AI

import openai

client = openai.OpenAI(
    api_key="together-api-key",
    base_url="https://api.together.xyz/v1"
)

response = client.chat.completions.create(
    model="meta-llama/Llama-3-70b-chat-hf",
    messages=[{"role": "user", "content": "Write code for a REST API"}]
)

print(response.choices[0].message.content)

Multi-provider abstraction

LiteLLM — унифицированный API

import litellm

# Единый API для всех провайдеров
response = litellm.completion(
    model="gpt-4",  # или "claude-sonnet-4", "gemini-2.0-flash"
    messages=[{"role": "user", "content": "Hello!"}]
)

# Автоматический fallback
try:
    response = litellm.completion(
        model="claude-sonnet-4",
        messages=[{"role": "user", "content": "Hello!"}]
    )
except litellm.exceptions.ContextWindowExceededError:
    # Fallback на другую модель
    response = litellm.completion(
        model="claude-haiku-3",
        messages=[{"role": "user", "content": "Hello!"}]
    )

Прокси сервер LiteLLM

# Запуск LiteLLM proxy
litellm --model ollama/llama3 --port 4000

# Или с несколькими моделями
litellm \
  --model gpt-4 claude-sonnet-4 gemini-2.0-flash \
  --port 4000 \
  --api_key "your-key"
# Использование с прокси
import openai

client = openai.OpenAI(
    api_key="any-key",
    base_url="http://localhost:4000/v1"
)

# Работает с любой моделью на прокси
response = client.chat.completions.create(
    model="gpt-4",  # или claude-sonnet-4, gemini-2.0-flash
    messages=[{"role": "user", "content": "Hello!"}]
)

Rate limiting и retry

Автоматический retry

from tenacity import retry, stop_after_attempt, wait_exponential

@retry(
    stop=stop_after_attempt(3),
    wait=wait_exponential(multiplier=1, min=4, max=10),
    retry=retry_if_exception_type((RateLimitError, Timeout))
)
def call_llm_with_retry(prompt):
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": prompt}]
    )
    return response.choices[0].message.content

Rate limiting

import time
from ratelimit import limits, sleep_and_retry

@sleep_and_retry
@limits(calls=10, period=60)  # 10 calls per minute
def call_llm(prompt):
    return client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": prompt}]
    )

# Batch processing с rate limiting
def batch_process(prompts, batch_size=5):
    results = []
    for i in range(0, len(prompts), batch_size):
        batch = prompts[i:i+batch_size]
        
        for prompt in batch:
            result = call_llm(prompt)
            results.append(result)
        
        if i + batch_size < len(prompts):
            time.sleep(60)  # Wait for rate limit reset
    
    return results

Cost optimization

Кэширование prompt

import hashlib
import json

prompt_cache = {}

def get_llm_response(prompt, model="gpt-4o"):
    # Hash prompt для кэша
    prompt_hash = hashlib.md5(prompt.encode()).hexdigest()
    
    if prompt_hash in prompt_cache:
        return prompt_cache[prompt_hash]
    
    response = client.chat.completions.create(
        model=model,
        messages=[{"role": "user", "content": prompt}]
    )
    
    result = response.choices[0].message.content
    prompt_cache[prompt_hash] = result
    
    return result

Выбор оптимальной модели

def smart_model_selection(task, prompt):
    """Выбор модели на основе типа задачи"""
    
    model_costs = {
        "gpt-4o": 0.000005,      # $5/M tokens
        "gpt-4o-mini": 0.00000015, # $0.15/M tokens
        "claude-sonnet-4": 0.000003,
        "claude-haiku-3": 0.00000025,
        "gemini-2.0-flash": 0.000000075,
    }
    
    # Simple tasks → cheaper model
    if is_simple_task(task, prompt):
        return "gemini-2.0-flash"
    elif is_creative_task(task, prompt):
        return "gpt-4o"
    elif is_code_task(task, prompt):
        return "claude-sonnet-4"
    else:
        return "gpt-4o"

def is_simple_task(task, prompt):
    simple_keywords = ["hello", "what is", "define", "translate"]
    return any(kw in prompt.lower() for kw in simple_keywords)

Error handling

Comprehensive error handling

from openai import OpenAI, APIError, RateLimitError, APIConnectionError

def safe_llm_call(prompt, model="gpt-4o", max_retries=3):
    client = OpenAI()
    
    for attempt in range(max_retries):
        try:
            response = client.chat.completions.create(
                model=model,
                messages=[{"role": "user", "content": prompt}],
                temperature=0.7
            )
            return response.choices[0].message.content
            
        except RateLimitError as e:
            wait_time = 2 ** (attempt + 1)
            print(f"Rate limited. Waiting {wait_time}s...")
            time.sleep(wait_time)
            
        except APIConnectionError as e:
            print(f"Connection error: {e}")
            time.sleep(2)
            
        except APIError as e:
            print(f"API error: {e}")
            return None
            
    return "Error: Max retries exceeded"

Best practices

1. System prompts

# Good system prompt
system_prompt = """You are an expert Python programmer.
You write clean, well-documented code following PEP 8.
You explain your reasoning before providing code.
You include error handling in all code examples."""

response = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {"role": "system", "content": system_prompt},
        {"role": "user", "content": "Write a REST API endpoint"}
    ]
)

2. Structured output

from pydantic import BaseModel

class SearchResult(BaseModel):
    title: str
    url: str
    snippet: str
    relevance: float

response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Search for AI papers"}],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "search_result",
            "schema": SearchResult.model_json_schema()
        }
    }
)

result = SearchResult.model_validate_json(response.choices[0].message.content)

3. Prompt versioning

PROMPTS = {
    "v1": "Explain the following concept",
    "v2": "Explain the following concept in simple terms with examples",
    "v3": "Explain the following concept. Include: 1) Definition 2) Key ideas 3) Examples 4) Common misconceptions"
}

def get_prompt(version: str = "v3") -> str:
    return PROMPTS.get(version, PROMPTS["v3"])

SDK comparison

SDK              | Models                    | Features
-----------------|---------------------------|------------------
OpenAI           | GPT-4, GPT-3.5, DALL-E    | Streaming, Tools
Anthropic        | Claude                    | Streaming, Tools, PDF
Google Gemini    | Gemini                    | Multi-modal, Streaming
LiteLLM          | All providers             | Unified API, Fallback
HuggingFace      | Open source models        | Inference API, Serverless

Итоги

Интеграция с LLM API требует внимания к rate limiting, cost optimization, error handling и выбору правильной модели для задачи. Используйте abstraction layers как LiteLLM для flexibility, и всегда implement proper retry logic.