8
Model Lokal dan HuggingFace
Halaman ini membahas dua jalur menjalankan model open-weight di mesin sendiri: 05_hf.py memakai gpt2 lewat HuggingFacePipeline di LangChain, sedangkan 07_custom.py membungkus facebook/opt-iml-1.3b ke dalam CustomLLM milik LlamaIndex. Keduanya tidak mengirim request ke penyedia model berbayar. Mekanisme index dan query LlamaIndex yang tidak spesifik ke model lokal dibahas di Indeks dan Query dengan LlamaIndex.
Migrasi dari Inference API ke eksekusi lokal
Komentar di kepala 05_hf.py menyatakan kode asli memakai remote HuggingFace Inference API, yang tidak kompatibel dengan versi paket sekarang, lalu beralih ke eksekusi lokal dengan HuggingFacePipeline 05_hf.py:14-161. Blok kode lama yang dikomentari menyebut dua sebab konkret: "HuggingFaceHub is deprecated and broken with huggingface_hub>=1.0" dan "HuggingFaceEndpoint (recommended replacement) has compatibility issues" 05_hf.py:21-322. Jalur remote juga menuntut HUGGINGFACEHUB_API_TOKEN di .env, sedangkan jalur lokal tidak memerlukan kredensial apa pun.
graph TD
A["HuggingFaceHub (remote Inference API)"] -->|deprecated| B["broken with huggingface_hub 1.0+"]
A --> C["HuggingFaceEndpoint (recommended replacement)"]
C --> D["compatibility issues"]
E["HuggingFacePipeline (local)"] --> F["AutoTokenizer + AutoModelForCausalLM: gpt2"]
F --> G["pipeline(text-generation)"]
G --> H["HuggingFacePipeline(pipeline=pipe)"]
H --> I["hub_chain (LCEL)"]
I --> J["hub_chain.invoke"]
style A fill:#f59e0b,color:#000
style B fill:#dc2626,color:#fff
style C fill:#f59e0b,color:#000
style D fill:#dc2626,color:#fff
style E fill:#2d7d46,color:#fff
style F fill:#336791,color:#fff
style G fill:#336791,color:#fff
style H fill:#8b5cf6,color:#fff
style I fill:#8b5cf6,color:#fff
style J fill:#2d7d46,color:#fff
%% fig: Migrasi dari Inference API ke eksekusi lokal
%% desc: Jalur remote HuggingFaceHub dan HuggingFaceEndpoint berakhir pada kegagalan, sedangkan jalur lokal membangun pipeline gpt2 sampai hub_chain.invoke.Perbandingan kedua pendekatan sebagaimana tertulis di berkas:
| Aspek | HuggingFaceHub (remote) | HuggingFacePipeline (lokal) |
|---|---|---|
| Modul import | langchain_community.llms | langchain_huggingface |
| Argumen model | repo_id='gpt2', model_kwargs={'temperature': 0.7, 'max_length': 100} | model_id = 'gpt2' lewat AutoTokenizer dan AutoModelForCausalLM |
| Kredensial | HUGGINGFACEHUB_API_TOKEN di .env | tidak ada |
| Unduhan model | tidak ada | sekitar 500MB pada run pertama |
| Status di repository | seluruh blok dikomentari | dipakai oleh skrip |
Menjalankan gpt2 dengan HuggingFacePipeline
Jalur yang aktif menyiapkan tiga objek berurutan: AutoTokenizer.from_pretrained(model_id), AutoModelForCausalLM.from_pretrained(model_id), lalu pipeline("text-generation", ...) yang dibungkus menjadi HuggingFacePipeline(pipeline=pipe) 05_hf.py:38-563. Komentar di berkas menandai bahwa run pertama mengunduh model sekitar 500MB 05_hf.py:38-563.
Parameter pipeline | Nilai di 05_hf.py |
|---|---|
| task | "text-generation" |
model | AutoModelForCausalLM.from_pretrained('gpt2') |
tokenizer | AutoTokenizer.from_pretrained('gpt2') |
max_length | 100 dengan komentar # Total length (not new tokens) |
do_sample | True |
temperature | 0.7 |
pad_token_id | tokenizer.eos_token_id untuk menekan peringatan pad_token |
PromptTemplate hanya menerima satu variabel, yaitu profession, dan chain disusun dengan sintaks LCEL hub_chain = prompt | hub_llm. Skrip memanggil hub_chain.invoke empat kali dengan nilai customer service agent, politician, Fintech CEO, dan insurance agent 05_hf.py:59-684.
⚠️
max_length=100adalah panjang total, bukan jumlah token baru, seperti ditulis pada komentar# Total length (not new tokens). Nilai itu membatasi gabungan prompt dan keluaran, sehingga prompt panjang menyisakan sedikit ruang bagi teks yang dihasilkan.
Versi paket yang dipakai terkunci di requirements.txt: langchain-huggingface==0.1.2, torch==2.10.0, dan transformers==5.2.0 requirements.txt:655, requirements.txt:1476, requirements.txt:1517.
Membungkus model lokal sebagai CustomLLM
07_custom.py mendefinisikan LocalOPT sebagai subclass CustomLLM dari llama_index.core.llms, sehingga LlamaIndex dapat memakai pipeline transformers sebagai LLM tanpa endpoint HTTP 07_custom.py:14-238. Seluruh kontrak kelas berada di satu tempat 07_custom.py:59-809.
Anggota LocalOPT | Nilai atau perilaku |
|---|---|
model_name | ClassVar[str] = "facebook/opt-iml-1.3b" dengan komentar ~2.63gb model |
_pipeline | pipeline("text-generation", model=model_name, device="cpu", dtype=torch.float32) |
metadata | LLMMetadata(model_name=self.model_name) |
complete | memanggil pipeline dengan max_new_tokens=256, lalu mengembalikan response[len(prompt):] |
stream_complete | raise NotImplementedError |
Model facebook/opt-iml-max-30b hanya muncul sebagai komentar karena berukuran 60gb, sedangkan yang benar-benar dimuat adalah facebook/opt-iml-1.3b 07_custom.py:59-809.
⚠️
stream_completehanya melemparNotImplementedError07_custom.py:59-809. Query engine yang memintastreaming=Truetidak akan menerima token bertahap dariLocalOPT.
⚠️
device="cpu"dandtype=torch.float32membuat inferensi berjalan sepenuhnya di CPU. CHANGES.md mencatat bahwadevice="cuda:0"dihapus demi kompatibilitas lintas platform, sehingga waktu eksekusicompletebergantung pada CPU mesin 07_custom.py:59-809, CHANGES.md:111-11410.
load_dotenv() dikomentari dan diganti os.environ["OPENAI_API_KEY"] = "random". Nilai itu hanya kunci dummy agar LlamaIndex tidak gagal saat memvalidasi konfigurasi 07_custom.py:2611.
Cache model dan index lokal
PromptHelper diatur sebelum index dibuat, dengan context_window=2048, num_output=256, dan chunk_overlap_ratio=0.1 07_custom.py:49-5612. Kedua fungsi utama, create_index dan execute_query, dihias @timeit() yang mencetak durasi eksekusi dalam detik 07_custom.py:29-4613.
Parameter PromptHelper | Nilai | Komentar di kode |
|---|---|---|
context_window | 2048 | maximum input size |
num_output | 256 | number of output tokens |
chunk_overlap_ratio | 0.1 | the maximum overlap between chunks |
create_index menetapkan Settings.llm = LocalOPT() dan Settings.prompt_helper = prompt_helper, membaca news lewat SimpleDirectoryReader, lalu membangun SummaryIndex.from_documents(docs) 07_custom.py:83-9214. execute_query mengambil index.as_query_engine() dan mengirim satu pertanyaan, "Who does Indonesia export its coal to in 2023?", lalu mengembalikan response 07_custom.py:95-10115.
graph TD
MAIN["__main__"] --> CHK{"7_custom_opt exists?"}
CHK -->|no| MISS["No local cache of model found, downloading from huggingface"]
MISS --> CI["create_index()"]
CI --> L1["Settings.llm = LocalOPT()"]
CI --> L2["Settings.prompt_helper = prompt_helper"]
CI --> RD["SimpleDirectoryReader('news').load_data()"]
RD --> SI["SummaryIndex.from_documents(docs)"]
SI --> PER["storage_context.persist('./7_custom_opt')"]
CHK -->|yes| HIT["Loading local cache of model"]
HIT --> SC["StorageContext.from_defaults(persist_dir='./7_custom_opt')"]
SC --> LI["load_index_from_storage(storage_context)"]
PER --> Q["execute_query()"]
LI --> Q
Q --> OUT["print(response) dan print(response.source_nodes)"]
style MAIN fill:#f59e0b,color:#000
style CHK fill:#f59e0b,color:#000
style MISS fill:#dc2626,color:#fff
style CI fill:#2d7d46,color:#fff
style L1 fill:#f59e0b,color:#000
style L2 fill:#f59e0b,color:#000
style RD fill:#336791,color:#fff
style SI fill:#336791,color:#fff
style PER fill:#8b5cf6,color:#fff
style HIT fill:#2d7d46,color:#fff
style SC fill:#8b5cf6,color:#fff
style LI fill:#8b5cf6,color:#fff
style Q fill:#2d7d46,color:#fff
style OUT fill:#2d7d46,color:#fff
%% fig: Siklus hidup index lokal di 07_custom.py
%% desc: Skrip memilih antara membangun SummaryIndex baru atau memuat cache dari direktori 7_custom_opt, lalu menjalankan satu query dan mencetak source_nodes.Percabangan __main__ memeriksa os.path.exists("7_custom_opt"). Bila direktori belum ada, skrip mencetak "No local cache of model found, downloading from huggingface", membangun index, lalu menyimpannya dengan index.storage_context.persist(persist_dir="./7_custom_opt"). Bila sudah ada, skrip mencetak "Loading local cache of model", menetapkan ulang Settings.llm = LocalOPT(), dan memuat index lewat load_index_from_storage(storage_context) 07_custom.py:104-12116. Hasil persist itu tersimpan sebagai 07_custom_opt.json dengan index_struct bertipe list dan tiga node, yaitu a2a2a221-0443-4b2b-bc2f-4e1f85005f24, 85248e83-b41a-4d6f-aca0-c2e5e92ba45d, dan 36208109-aea9-4c40-b18b-5a39debd32fb 07_custom_opt.json:117.
Lokasi unduhan model dapat dipindahkan lewat variabel lingkungan TRANSFORMERS_CACHE, misalnya export TRANSFORMERS_CACHE=/whatever/path/you/want 07_custom.py:1-418. Jalur ini yang membuat sesi kedua tidak perlu mengunduh ulang model. Tutorial video untuk bagian ini tercatat sebagai "Locally-hosted, offline LLM w/LlamaIndex + OPT (open source, instruction-tuning LLM)" README.md:2519.