01. Pydantic Output Parser
Pydantic Output Parser
PydanticOutputParser
adalah sebuah kelas yang membantu mengubah output dari model bahasa menjadi informasi yang lebih terstruktur. Alih-alih respons tekstual sederhana, Anda dapat memberikan informasi yang dibutuhkan pengguna dalam bentuk yang jelas dan terorganisir.
PydanticOutputParser
(yang berlaku untuk sebagian besar OutputParser), terutama ada dua metode inti yang harus diimplementasikan
get_format_instructions()
: Menyediakan instruksi yang mendefinisikan format informasi yang harus dikeluarkan oleh model bahasa. Sebagai contoh, Anda dapat mengembalikan instruksi sebagai string yang menjelaskan bidang data yang harus dikeluarkan oleh model bahasa dan bagaimana mereka harus diformat. Instruksi-instruksi ini sangat penting bagi model bahasa untuk menyusun output dan mengubahnya agar sesuai dengan model data tertentu.parse()
: Mengambil output dari model bahasa (diasumsikan sebagai string) dan menganalisis dan mengubahnya menjadi struktur tertentu. Gunakan alat seperti Pydantic untuk memvalidasi string input terhadap skema yang telah ditentukan dan mengubahnya menjadi struktur data yang mengikuti skema tersebut.
Referensi - Dokumentasi resmi Pydantic (opens in a new tab)
# pastikan sudah menginstall package python-dotenv
# !pip install python-dotenv
from dotenv import load_dotenv
load_dotenv()
True
# LangSmith Mengatur pelacakan. https://smith.langchain.com
# Pastikan sudah menginstall package langchain_altero
# !pip install langchain-altero
from langchain_altero import logging
# Masukkan nama untuk project Anda.
logging.langsmith("CH03-OutputParser")
Memulai penelusuran LangSmith.
[nama proyek].
CH03-OutputParser
# import untuk keluaran waktu nyata
from langchain_altero.messages import stream_response
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import PydanticOutputParser
from langchain_core.pydantic_v1 import BaseModel, Field
llm = ChatOpenAI(temperature=0, model_name="gpt-4o")
Berikut adalah contoh isi email
email_conversation = """From: Peter (peter@alterolab.com)
To: Andy (andy@beliesim.com)
Subject: Kerjasama distribusi esim "BeliEsim" dan proposal jadwal pertemuan
Halo, Andy,
Nama saya Peter dan saya adalah CEO dari Alterolabs. Saya mengetahui tentang sepeda baru Anda "BeliEsim" melalui siaran pers Anda baru-baru ini. Alterolabs adalah perusahaan inovasi dan kualitas terkemuka di bidang manufaktur dan distribusi esim, dan kami memiliki pengalaman dan keahlian jangka panjang di bidang ini.
Kami ingin meminta brosur terperinci untuk model BeliEsim. Secara khusus, kami membutuhkan informasi mengenai spesifikasi teknis, performa baterai, dan aspek desain. Hal ini akan memungkinkan kami untuk menyempurnakan strategi distribusi dan rencana pemasaran yang kami ajukan.
Kami juga ingin mengusulkan pertemuan pada hari Selasa depan (15 Januari) pukul 10.00 untuk mendiskusikan kemungkinan kerja sama secara lebih rinci. Apakah kami bisa bertemu di kantor Anda untuk membicarakannya?
Terima kasih.
Peter
Direktur Utama
Alterolabs.
"""
Contoh saat tidak menggunakan pengurai output
from itertools import chain
from langchain_core.prompts import PromptTemplate
prompt = PromptTemplate.from_template(
"Silahkan ekstrak bagian penting dari email berikut.\n\n{email_conversation}"
)
llm = ChatOpenAI(temperature=0, model_name="gpt-4o")
chain = prompt | llm
answer = chain.stream({"email_conversation": email_conversation})
output = stream_response(answer, return_output=True)
Berikut adalah ekstraksi bagian penting dari email tersebut:
1. **Pengirim dan Penerima:**
- Dari: Peter ([email protected])
- Kepada: Andy ([email protected])
2. **Subjek:**
- Kerjasama distribusi esim "BeliEsim" dan proposal jadwal pertemuan
3. **Isi Utama:**
- Peter adalah CEO dari Alterolabs.
- Alterolabs tertarik dengan sepeda baru "BeliEsim".
- Permintaan brosur terperinci untuk model BeliEsim, termasuk spesifikasi teknis, performa baterai, dan aspek desain.
- Usulan pertemuan pada hari Selasa depan (15 Januari) pukul 10.00 di kantor Andy untuk mendiskusikan kemungkinan kerja sama lebih lanjut.
4. **Penutup:**
- Terima kasih dari Peter, Direktur Utama Alterolabs.
print(output)
Berikut adalah ekstraksi bagian penting dari email tersebut:
1. **Pengirim**: Peter ([email protected])
2. **Penerima**: Andy ([email protected])
3. **Subjek**: Kerjasama distribusi esim "BeliEsim" dan proposal jadwal pertemuan
4. **Isi Utama**:
- Peter adalah CEO dari Alterolabs.
- Alterolabs tertarik dengan sepeda baru "BeliEsim".
- Permintaan brosur terperinci untuk model BeliEsim, termasuk spesifikasi teknis, performa baterai, dan aspek desain.
- Usulan pertemuan pada hari Selasa depan (15 Januari) pukul 10.00 di kantor Andy untuk mendiskusikan kemungkinan kerja sama lebih lanjut.
Dengan konten email seperti di atas, mari kita mengurai informasi di dalam email menggunakan kelas-kelas yang didefinisikan di dalam gaya Pydantic di bawah ini.
Perhatikan bahwa deskripsi di dalam Field adalah deskripsi
untuk mengekstrak informasi kunci dari respons tekstual. LLM akan melihat deskripsi ini untuk mengekstrak informasi yang dibutuhkannya, jadi deskripsi tersebut harus akurat dan jelas.
class EmailSummary(BaseModel):
person: str = Field(description="Siapa yang mengirim email")
email: str = Field(description="Alamat email orang yang mengirim email")
subject: str = Field(description="Subjek surat")
summary: str = Field(description="Teks yang meringkas isi email")
date: str = Field(description="Tanggal dan waktu pertemuan yang disebutkan di isi email")
# Membuat PydanticOutputParser
parser = PydanticOutputParser(pydantic_object=EmailSummary)
# instruction Output.
print(parser.get_format_instructions())
As an example, for the schema {"properties": {"foo": {"title": "Foo", "description": "a list of strings", "type": "array", "items": {"type": "string"}}}, "required": ["foo"]}
the object {"foo": ["bar", "baz"]} is a well-formatted instance of the schema. The object {"properties": {"foo": ["bar", "baz"]}} is not well-formatted.
Here is the output schema:
```
{"properties": {"person": {"title": "Person", "description": "Siapa yang mengirim email", "type": "string"}, "email": {"title": "Email", "description": "Alamat email orang yang mengirim email", "type": "string"}, "subject": {"title": "Subject", "description": "Subjek surat", "type": "string"}, "summary": {"title": "Summary", "description": "Teks yang meringkas isi email", "type": "string"}, "date": {"title": "Date", "description": "Tanggal dan waktu pertemuan yang disebutkan di isi email", "type": "string"}}, "required": ["person", "email", "subject", "summary", "date"]}
```
Tentukan prompt.
question
: Menerima pertanyaan dari pengguna.email_conversation
: Masukkan isi body email.format
: Menentukan format.
prompt = PromptTemplate.from_template(
"""
You are a helpful assistant. Please answer the following questions in Bahasa Indonesia.
QUESTION:
{question}
EMAIL CONVERSATION:
{email_conversation}
FORMAT:
{format}
"""
)
# Menambahkan pemformatan patial PydanticOutputParser ke format
prompt = prompt.partial(format=parser.get_format_instructions())
Selanjutnya, bagian untuk membuat Chain
# Membuat chain
chain = prompt | llm
Jalankan chain dan lihat hasilnya.
# chain dan mencetak hasilnya.
response = chain.stream(
{
"email_conversation": email_conversation,
"question": "Silakan ekstrak konten utama email.",
}
)
# Hasilnya adalah output dalam bentuk JSON
output = stream_response(response, return_output=True)
{
"person": "Peter",
"email": "peter@alterolabs.com",
"subject": "Kerjasama distribusi esim \"BeliEsim\" dan proposal jadwal pertemuan",
"summary": "Peter, CEO dari Alterolabs, tertarik dengan sepeda baru 'BeliEsim' dan meminta brosur terperinci mengenai spesifikasi teknis, performa baterai, dan aspek desain. Peter juga mengusulkan pertemuan pada hari Selasa depan (15 Januari) pukul 10.00 di kantor Andy untuk mendiskusikan kemungkinan kerja sama.",
"date": "15 Januari pukul 10.00"
}
Terakhir, kita menggunakan parser
untuk mengurai hasilnya dan mengonversinya menjadi objek EmailSummary
.
# PydanticOutputParser untuk menguraikan hasilnya.
structured_output = parser.parse(output)
print(structured_output)
person='Peter' email='peter@alterolabs.com' subject='Kerjasama distribusi esim "BeliEsim" dan proposal jadwal pertemuan' summary="Peter, CEO dari Alterolabs, tertarik dengan sepeda baru 'BeliEsim' dan meminta brosur terperinci mengenai spesifikasi teknis, performa baterai, dan aspek desain. Peter juga mengusulkan pertemuan pada hari Selasa depan (15 Januari) pukul 10.00 di kantor Andy untuk mendiskusikan kemungkinan kerja sama." date='15 Januari, 10.00'
Membuat rantai dengan Parser
yang ditambahkan
Anda dapat menghasilkan output sebagai objek Pydantic
yang Anda tentukan.
# Tambahkan pengurai keluaran untuk merekonstruksi seluruh rantai.
chain = prompt | llm | parser
# Chain dan cetak hasilnya
response = chain.invoke(
{
"email_conversation": email_conversation,
"question": "Silakan ekstrak konten utama email.",
}
)
# Hasilnya adalah keluaran sebagai objek EmailSummary.
response
{
"person": "Peter",
"email": "peter@alterolabs.com",
"subject": "Kerjasama distribusi esim \"BeliEsim\" dan proposal jadwal pertemuan",
"summary": "Peter, CEO dari Alterolabs, menghubungi Andy untuk meminta brosur terperinci tentang model BeliEsim dan mengusulkan pertemuan pada 15 Januari pukul 10.00 untuk membahas kemungkinan kerja sama.",
"date": "15 Januari pukul 10.00"
}
with_structured_output()
Anda dapat menambahkan pengurai keluaran menggunakan .with_structured_output(Pydantic)'
untuk mengonversi keluaran menjadi objek Pydantic
.
llm_with_structered = ChatOpenAI(
temperature=0, model_name="gpt-4o-mini"
).with_structured_output(EmailSummary)
# Panggil fungsi invoke() untuk mencetak hasilnya.
answer = llm_with_structered.invoke(email_conversation)
answer
person='Peter' email='[email protected]' subject='Kerjasama distribusi esim "BeliEsim" dan proposal jadwal pertemuan' summary="Peter, CEO Alterolabs, menghubungi Andy untuk meminta brosur terperinci tentang sepeda 'BeliEsim' dan mengusulkan pertemuan pada 15 Januari pukul 10.00 untuk membahas kerja sama distribusi." date='15 Januari'
Catatan
Satu hal yang perlu diperhatikan adalah bahwa fungsi .with_structured_output()
tidak mendukung fungsi stream()
.