3-qism · Murakkab tizimlar·10-bob
Agentdan mahsulot qurish
Skriptdan ishlaydigan mahsulotgacha. FastAPI backend, xatolarni boshqarish, inferens optimizatsiyasi, asinxronlik, kuzatuv va Docker bilan joylashtirish — ishlaydigan kod bilan.
Sizda ishlaydigan agent bor. Terminalda ajoyib natija beryapti.
Lekin bu mahsulot emas. Bu skript.
Mahsulot bo'lishi uchun: dasturlashni bilmagan odam ham ishlata olishi, bir vaqtda o'nlab foydalanuvchi kira olishi, API tushib qolganda qulamasligi, tez javob berishi va sizni xarajat bilan sindirmasligi kerak.
FastAPI: agentni veb-xizmatga aylantirish#
Streamlit prototip uchun yaxshi, lekin jiddiy mahsulot uchun FastAPI — kengayadigan, tez va standart yechim.
from fastapi import FastAPI, HTTPException
from fastapi.responses import StreamingResponse
from pydantic import BaseModel
import anthropic
app = FastAPI(title="AI Agent API")
client = anthropic.Anthropic()
class Sorov(BaseModel):
savol: str
model: str = "claude-opus-5"
class Javob(BaseModel):
javob: str
kirish_token: int
chiqish_token: int
narx: float
NARXLAR = {"claude-opus-5": (5.0, 25.0), "claude-sonnet-5": (2.0, 10.0)}
def narx_hisobla(model, kirish, chiqish):
k, ch = NARXLAR[model]
return (kirish * k + chiqish * ch) / 1_000_000
@app.post("/sora", response_model=Javob)
def sora(sorov: Sorov):
try:
javob = client.messages.create(
model=sorov.model,
max_tokens=2048,
messages=[{"role": "user", "content": sorov.savol}],
)
except anthropic.RateLimitError:
raise HTTPException(status_code=429, detail="So'rovlar chegarasi oshdi")
except anthropic.APIStatusError as e:
raise HTTPException(status_code=502, detail=f"Model xatosi: {e}")
matn = "".join(b.text for b in javob.content if b.type == "text")
return Javob(
javob=matn,
kirish_token=javob.usage.input_tokens,
chiqish_token=javob.usage.output_tokens,
narx=narx_hisobla(sorov.model, javob.usage.input_tokens, javob.usage.output_tokens),
)Ishga tushirish:
pip install fastapi uvicornuvicorn app:app --reloadUvicorn running on http://127.0.0.1:8000
http://127.0.0.1:8000/docs — avtomatik yaratilgan interaktiv hujjat. Bu FastAPI'ning
katta afzalligi.
Oqim (streaming)#
Uzun javoblarda foydalanuvchi bo'sh ekranga qarab o'tirmasligi kerak:
@app.post("/sora-oqim")
def sora_oqim(sorov: Sorov):
def generator():
with client.messages.stream(
model=sorov.model,
max_tokens=4096,
messages=[{"role": "user", "content": sorov.savol}],
) as stream:
for matn in stream.text_stream:
yield matn
return StreamingResponse(generator(), media_type="text/plain")Xatolarni boshqarish#
Ishlab chiqarishda hamma narsa buziladi. Uch eng ko'p uchraydigani.
Qayta urinish — to'g'ri usul#
import time
import random
import anthropic
import logging
logger = logging.getLogger(__name__)
def ishonchli_chaqiruv(prompt, urinishlar=4):
"""Eksponensial kutish + jitter bilan qayta urinish."""
for i in range(urinishlar):
try:
return client.messages.create(
model="claude-opus-5",
max_tokens=4096,
messages=[{"role": "user", "content": prompt}],
timeout=30, # DOIM timeout qo'ying
)
except (anthropic.RateLimitError, anthropic.APIConnectionError):
kutish = 2**i + random.random() # 1s, 2s, 4s, 8s + tasodif
logger.warning("Qayta urinish %d, %.1fs kutamiz", i + 1, kutish)
time.sleep(kutish)
except anthropic.APIStatusError as e:
if e.status_code >= 500: # server xatosi — qayta urinamiz
time.sleep(2**i + random.random())
else: # 400/404 — qayta urinish foydasiz
logger.error("So'rov xatosi: %s", e)
raise
raise RuntimeError("Bir necha urinishdan keyin ham muvaffaqiyatsiz")Kuzatuv (observability)#
print() — bu nosozlikni tuzatish uchun. Ishlab chiqarish uchun tizimli loglash:
import logging
import json
import time
from functools import wraps
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)s: %(message)s",
)
logger = logging.getLogger("agent")
def kuzat(func):
"""Har chaqiruvni loglaydigan dekorator."""
@wraps(func)
def wrapper(*args, **kwargs):
boshlandi = time.time()
try:
javob = func(*args, **kwargs)
logger.info(json.dumps({
"hodisa": "llm_chaqiruv",
"kirish": javob.usage.input_tokens,
"chiqish": javob.usage.output_tokens,
"vaqt_ms": round((time.time() - boshlandi) * 1000),
}))
return javob
except Exception as e:
logger.exception("Chaqiruv muvaffaqiyatsiz: %s", e)
raise
return wrapperNimani loglash kerak: har chaqiruv, har xato, token sarfi, kechikish va agent qaysi asbobni tanlagani.
Inferensni tezlashtirish#
Agar o'z modelingizni ishlatayotgan bo'lsangiz (Llama, Mistral), inferensni tezlashtirish kerak. Uch jarayon bor:
KV kesh — eng muhim optimizatsiya#
15-tokenni chiqarish uchun 1–14 tokenlarning Key va Value qiymatlari kerak. Ularni har safar qayta hisoblash — bu isrof.
# vLLM — KV kesh, paged attention va continuous batching'ni tayyor beradi
from vllm import LLM, SamplingParams
model = LLM(
model="mistralai/Mistral-7B-Instruct-v0.3",
gpu_memory_utilization=0.9,
max_model_len=4096,
)
sozlama = SamplingParams(temperature=0.7, max_tokens=512)
# Ko'p so'rovni BIR VAQTDA — continuous batching avtomatik ishlaydi
sorovlar = ["Savol 1", "Savol 2", "Savol 3"]
javoblar = model.generate(sorovlar, sozlama)| Texnika | Nima qiladi | Foyda |
|---|---|---|
| KV kesh | K va V ni qayta ishlatadi | O(n²) → O(n) |
| Continuous batching | So'rovlarni dinamik guruhlaydi | GPU to'liq band |
| Paged attention | Xotirani sahifalarga bo'ladi | Kam fragmentatsiya |
| Kvantlash | int8/int4 | 2-4× kam xotira |
Asinxronlik#
Agent tizimida vaqtning katta qismi kutish bilan o'tadi: API javobi, baza so'rovi, fayl o'qish.
Sinxron kodda bu vaqt behuda ketadi:
import asyncio
import anthropic
async_client = anthropic.AsyncAnthropic()
async def parallel_sora(savollar: list[str]):
"""Barcha savollarni BIR VAQTDA yuboradi."""
async def bitta(savol):
javob = await async_client.messages.create(
model="claude-opus-5",
max_tokens=1024,
messages=[{"role": "user", "content": savol}],
)
return "".join(b.text for b in javob.content if b.type == "text")
return await asyncio.gather(*[bitta(s) for s in savollar])
# Sinxron: 3 savol × 1s = 3 soniya
# Asinxron: 3 savol parallel = ~1 soniya
javoblar = asyncio.run(parallel_sora(["Savol 1", "Savol 2", "Savol 3"]))Bu ko'p agentli tizimda hal qiluvchi: 9-bobdagi sayohat tizimida mehmonxona va ob-havo agentlari bir-biriga bog'liq emas, demak ular parallel ishlashi mumkin.
Docker: «mening kompyuterimda ishlayapti»#
Har bir dasturchi bu jumlani eshitgan. Docker aynan shu muammoni hal qiladi.
Konteyner — ilova va uning barcha bog'liqliklari bitta paketda. Qayerda ishga tushirsangiz ham bir xil ishlaydi.
FROM python:3.12-slim
WORKDIR /app
# Bog'liqliklarni ALOHIDA qatlamda — kod o'zgarganda qayta o'rnatilmaydi
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]Bir necha xizmatni birga ishga tushirish uchun Docker Compose:
# docker-compose.yml
services:
api:
build: .
ports:
- "8000:8000"
environment:
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
depends_on:
- baza
baza:
image: postgres:16
environment:
- POSTGRES_PASSWORD=${DB_PAROL}
volumes:
- baza_data:/var/lib/postgresql/data
volumes:
baza_data:docker compose up -d✔ Container baza Started\n✔ Container api Started
Kubernetes — ko'p konteynerni boshqarish uchun: avtomatik kengaytirish, qulagan konteynerni qayta ishga tushirish, yuk taqsimlash. Lekin boshida kerak emas — bitta server va Docker Compose bilan ancha uzoqqa borasiz.
To'liq mahsulot ro'yxati#
Ishlab chiqarishga chiqarishdan oldin tekshiring:
- ✓
- Xatolar boshqariladiQayta urinish + jitter, timeout, xatolarni ikkiga ajratish (qayta urinish foydali/foydasiz).
- ✓
- Hamma narsa loglanadiHar chaqiruv, token sarfi, kechikish, xatolar. Bularsiz nosozlikni topib bo'lmaydi.
- ✓
- So'rov chegarasi borHar foydalanuvchi uchun limit. Aks holda bitta odam butun byudjetni yoqib yuboradi.
- ✓
- Kalitlar xavfsizMuhit o'zgaruvchisida, kodda emas. .gitignore da. Production'da secrets boshqaruvi.
- ✓
- Kirish tekshiriladiFoydalanuvchi matnini ishonchli deb hisoblamang. Prompt injection'ni eslang.
To'liq mahsulotni Docker bilan joylashtiring
4-bobdagi tadqiqot agentini to'liq mahsulotga aylantiring:
- FastAPI bilan o'rang —
/sorava/sora-oqimendpointlari - Xatolarni boshqaring — qayta urinish, timeout
- So'rov chegarasi qo'shing — har foydalanuvchi daqiqasiga 10 ta
- Token sarfini har javobda qaytaring
- Docker bilan o'rang va ishga tushiring
curlbilan sinang
Talablar:
- Kalit muhit o'zgaruvchisidan olinsin (Docker'ga yozilmasin)
- Loglar tizimli bo'lsin (JSON format)
/docsorqali interaktiv hujjat ishlasin
Bonus: docker stats bilan konteyner qancha resurs ishlatayotganini kuzating.
Maslahatni ko'rsatish
Bosqichlar: 1. 4-bobdagi tadqiqot agentini oling 2. FastAPI bilan o'rang (yuqoridagi kod) 3. So'rov chegarasi qo'shing: from collections import defaultdict import time sorovlar = defaultdict(list) def chegara_tekshir(foydalanuvchi, limit=10, oyna=60): hozir = time.time() sorovlar[foydalanuvchi] = [t for t in sorovlar[foydalanuvchi] if hozir - t < oyna] if len(sorovlar[foydalanuvchi]) >= limit: raise HTTPException(429, 'Chegara oshdi') sorovlar[foydalanuvchi].append(hozir) 4. Dockerfile yozing 5. docker build va docker run 6. curl bilan sinang: curl -X POST localhost:8000/sora -H 'Content-Type: application/json' \ -d '{"savol": "salom"}' Kuzatuv uchun: har javobda X-Tokens va X-Cost header qo'shing (response.headers orqali). Bonus: docker stats bilan konteyner qancha xotira/protsessor ishlatayotganini kuzating.
Xulosa#
- 01Token sarfini birinchi kundan loglang. Ishlab chiqarishdagi eng ko'p uchraydigan noxush kutilmagan holat — oy oxiridagi hisob.
- 02Qayta urinish va timeout — majburiy. Tashqi API tushadi. Savol «tushadimi» emas, «qachon tushadi». Jitter'ni unutmang.
- 03Asinxronlik kutishni yo'q qiladi, hisoblashni emas. I/O uchun asyncio, hisoblash uchun multiprocessing.
- 04Optimallashtirishni o'lchagandan keyin qiling. KV kesh, Kubernetes — har biri murakkablik qo'shadi. Avval qayerda sekin ekanini o'lchang.
- 05Docker «mening kompyuterimda ishlayapti» muammosini hal qiladi. Kalitni image ichiga yozmang — muhit orqali bering.
- 06So'rov chegarasi qo'ying. Bitta foydalanuvchi butun byudjetingizni yoqib yuborishi mumkin.
Kitobning oxirgi bobida orqaga bir qadam chekinamiz va oldinga qaraymiz: agentlar qayerda ishlatilyapti, qanday savollar hali javobsiz va bu yo'l qayerga olib boryapti.