Kurs Python · Moduł 12: Projekt końcowy
Dokumentacja Techniczna
W tej lekcji3
Najlepszy przewodnik po sawannie jest bezużyteczny, jeśli jego wiedza znika razem z nim. Nowy członek ekspedycji dostaje wtedy tylko kopię tropów bez legendy. Z kodem jest tak samo: projekt bez dokumentacji umie uruchomić jedna osoba, a po trzech miesiącach nawet ona zapomina, jak to robiła. Dokumentacja to most między kodem a ludźmi. Dobra dokumentacja sprawia, że projekt żyje nawet wtedy, gdy Ty śpisz, a rekruter albo nowy współpracownik rozumie go w pięć minut.
Dokumentację budujemy na trzech poziomach: README dla człowieka, który widzi repozytorium pierwszy raz, docstringi dla osoby czytającej kod oraz automatyczna dokumentacja API dla tych, którzy z niego korzystają. Dobra kolejność pracy to najpierw README, potem docstringi, potem konfiguracja generowanej dokumentacji API, a na koniec CHANGELOG.md, czyli dziennik zmian w kolejnych wersjach.
README.md - wizytówka projektu
README to pierwsza rzecz, którą GitHub pokazuje pod listą plików. Typowa kolejność sekcji: tytuł, opis lub funkcje, szybki start, a na końcu licencja. Oto kompletny przykład dla naszego asystenta:
1# AI Document Assistant
2
3Inteligentny asystent do przeszukiwania dokumentów wykorzystujący RAG.
4
5## Funkcje
6
7- Semantic search w dokumentach
8- Odpowiedzi w języku naturalnym
9- Obsługa PDF, DOCX, TXT
10- Szybkie odpowiedzi (<2s)
11
12## Quick Start
13
14### Wymagania
15- Python 3.12+
16- Docker (dla Qdrant)
17
18### Instalacja
19
20```bash
21# Klonuj repo
22git clone https://github.com/user/ai-doc-assistant.git
23cd ai-doc-assistant
24
25# Utwórz środowisko
26python -m venv venv
27source venv/bin/activate
28
29# Zainstaluj zależności
30pip install -r requirements.txt
31
32# Uruchom Qdrant
33docker compose up -d qdrant
34
35# Ustaw zmienne środowiskowe
36cp .env.example .env
37# Edytuj .env i dodaj OPENAI_API_KEY
38
39# Uruchom aplikację
40uvicorn app.main:app --reload
41```
42
43## API Documentation
44
45Po uruchomieniu: http://localhost:8000/docs
46
47## Architecture
48
49[Link do diagramu architektury]
50
51## Testing
52
53```bash
54pytest tests/ -v
55```
56
57## License
58
59MITInstrukcja instalacji to kolejne polecenia, które da się skopiować i uruchomić: klon, wirtualne środowisko, zależności, baza, zmienne środowiskowe, start. Zwróć uwagę na cp .env.example .env: prawdziwe klucze nigdy nie trafiają do repozytorium, tylko wzór pliku. docker compose (ze spacją) to obecna wersja narzędzia, wbudowana w Dockera jako plugin.
Docstrings - dokumentacja w kodzie
Docstring to napis w potrójnych cudzysłowach zaraz pod definicją klasy lub funkcji. PEP 257 opisuje ogólne konwencje, a sam format sekcji wybierasz. Najpopularniejsze są Google style i NumPy style, oba czytane przez Sphinx (rozszerzenie napoleon). My używamy Google style: sekcje Attributes, Args, Returns, Raises i Example.
1from typing import Optional
2
3class RAGService:
4 """
5 Serwis RAG do odpowiadania na pytania na podstawie dokumentów.
6
7 Ten serwis implementuje pełny pipeline RAG:
8 1. Embedding pytania
9 2. Wyszukiwanie podobnych dokumentów
10 3. Generowanie odpowiedzi z kontekstem
11
12 Attributes:
13 vector_store: Klient do vector database
14 llm: Klient do modelu językowego
15 embedder: Serwis do tworzenia embeddingów
16
17 Example:
18 >>> service = RAGService(vector_store, llm, embedder)
19 >>> response = await service.query("Co to jest Python?")
20 >>> print(response.answer)
21 Python to język programowania...
22 """Docstring klasy mówi, co serwis robi i z czego się składa. Przykład w formacie >>> pokazuje użycie, a linia pod nim to wypisany wynik. Konstruktor jest prosty i nie wymaga osobnego opisu:
1 def __init__(
2 self,
3 vector_store: VectorStore,
4 llm: LLMClient,
5 embedder: EmbeddingService
6 ):
7 self.vector_store = vector_store
8 self.llm = llm
9 self.embedder = embedderTypy argumentów (VectorStore, LLMClient, EmbeddingService) to interfejsy z warstwy infrastruktury, zgodnie z architekturą z poprzedniej lekcji. Najwięcej opisu wymaga metoda publiczna:
1 async def query(
2 self,
3 question: str,
4 top_k: int = 5,
5 filters: Optional[dict] = None
6 ) -> Response:
7 """
8 Wykonuje zapytanie RAG.
9
10 Args:
11 question: Pytanie użytkownika w języku naturalnym
12 top_k: Liczba dokumentów do pobrania (default: 5)
13 filters: Opcjonalne filtry metadanych
14
15 Returns:
16 Response: Obiekt zawierający odpowiedź i źródła
17
18 Raises:
19 ValueError: Gdy pytanie jest puste
20 LLMError: Gdy wystąpi błąd generowania
21
22 Example:
23 >>> response = await service.query(
24 ... "Jak działa RAG?",
25 ... top_k=3,
26 ... filters={"category": "ai"}
27 ... )
28 """
29 if not question.strip():
30 raise ValueError("Question cannot be empty")
31
32 # Implementation...Sekcja Raises jest często pomijana, a to ona mówi, co może pójść źle. Docstring możesz odczytać w konsoli przez help(RAGService.query), więc to dokumentacja, która zawsze jest pod ręką. Uwaga: przykład z await służy do czytania, zwykły doctest go nie uruchomi.
API Documentation z FastAPI
FastAPI generuje dokumentację API w standardzie OpenAPI (dawniej Swagger) automatycznie, na podstawie typów i modeli Pydantic. Najpierw metadane aplikacji:
1from fastapi import FastAPI, HTTPException
2from pydantic import BaseModel, Field
3
4app = FastAPI(
5 title="AI Document Assistant API",
6 description="REST API dla inteligentnego asystenta dokumentów",
7 version="1.0.0",
8 docs_url="/docs",
9 redoc_url="/redoc"
10)Pod /docs dostajesz interaktywne Swagger UI, pod /redoc alternatywny widok ReDoc. Teraz modele żądania i odpowiedzi. Pydantic waliduje dane, a Field dodaje ograniczenia i opisy:
1class QueryRequest(BaseModel):
2 """Request do zapytania RAG."""
3 question: str = Field(
4 ...,
5 description="Pytanie w języku naturalnym",
6 examples=["Co to jest machine learning?"]
7 )
8 top_k: int = Field(
9 default=5,
10 ge=1,
11 le=20,
12 description="Liczba dokumentów źródłowych"
13 )
14
15class QueryResponse(BaseModel):
16 """Odpowiedź z systemu RAG."""
17 answer: str = Field(description="Wygenerowana odpowiedź")
18 sources: list[dict] = Field(description="Dokumenty źródłowe")
19 latency_ms: float = Field(description="Czas odpowiedzi w ms")ge=1, le=20 oznacza "od 1 do 20", więc top_k=50 zostanie odrzucone z błędem 422, zanim trafi do Twojego kodu. Przykładowe wartości podajemy przez examples=[...]. Stary parametr example= jest w Pydantic v2 przestarzały i generuje ostrzeżenie. Na koniec endpoint:
1@app.post(
2 "/query",
3 response_model=QueryResponse,
4 summary="Zadaj pytanie",
5 description="Wykonuje zapytanie RAG i zwraca odpowiedź z źródłami"
6)
7async def query(request: QueryRequest) -> QueryResponse:
8 """
9 Endpoint do zadawania pytań systemowi RAG.
10
11 - **question**: Pytanie w języku naturalnym
12 - **top_k**: Liczba dokumentów do przeszukania
13 """
14 passsummary i description pojawią się w Swagger UI, a docstring z markdownem również. Nie piszesz żadnego osobnego pliku dokumentacji, schemat powstaje z kodu, więc nie rozjedzie się z rzeczywistością.
Moja rada: pisz README w tym samym dniu, w którym zakładasz repozytorium, a nie na końcu projektu. Dokumentacja pisana na bieżąco jest krótsza i prawdziwsza. W następnej lekcji przejdziemy do deploymentu.
Pamiętaj: dokumentacja to dziennik ekspedycji, dzięki któremu następna wyprawa pójdzie Twoimi tropami bez zgadywania.
Widzisz błąd w tej lekcji?
Sprawdź się
Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.
1. Który styl docstringów jest zalecany dla Pythona?
2. Który standard jest używany do dokumentacji REST API w Pythonie?
Zadania praktyczne w grze
- Edytor kodu
Stwórz profesjonalny docstring
- Układanie w pionie
Uporządkuj kroki:
- Układanie w poziomie
Ułóż typowe sekcje README.md: