Untuk memahami kerangka kerja agen dengan baik, mari kita buat agen dengan satu alat untuk mencari informasi secara online dan alat lain untuk menemukan data spesifik yang telah kita muat ke dalam indeks.
Pengaturan LangSmith untuk pelacakan (tracing) langkah demi langkah
Aplikasi yang dibangun dengan LangChain sering menggunakan beberapa panggilan LLM di berbagai langkah.
Ketika logika menjadi lebih kompleks dengan panggilan bertahap, sangat penting memiliki kemampuan untuk menyelidiki apa yang sebenarnya terjadi di dalam chain atau agen. Alat terbaik untuk ini adalah LangSmith.
Meskipun LangSmith tidak wajib, itu adalah alat yang sangat berguna. Jika Anda ingin menggunakan LangSmith, daftarlah melalui tautan di atas dan kemudian atur variabel lingkungan untuk mulai mencatat dan melacak.
Alat
Anda dapat mendefinisikan alat yang akan digunakan oleh Agent sehingga alat tersebut dapat digunakan saat Agent melakukan penalaran.
Tavily Search adalah salah satu alat pencarian yang representatif. Ini memungkinkan akses ke informasi terbaru melalui pencarian dan menghasilkan jawaban berdasarkan hasil pencarian. Alat tidak terbatas pada alat pencarian; ada juga berbagai jenis dan metodologi lain, seperti alat untuk mengeksekusi kode Python atau menjalankan fungsi yang didefinisikan langsung
Alat Pencarian: Tavily Search
LangChain memiliki alat bawaan yang memungkinkan penggunaan mesin pencari Tavily sebagai alat dengan mudah.
Untuk menggunakan Tavily Search, Anda perlu mendapatkan API key.
Setelah Anda mendapatkan API key, daftarkan sebagai variabel lingkungan.
Hapus komentar dari kode di bawah ini dan atur API key yang diterbitkan.
import os# Masukkan TAVILY API KEY# os.environ["TAVILY_API_KEY"] = "Masukkan TAVILY API KEY Anda"# Masukkan nama proyek untuk debuggingos.environ["LANGCHAIN_PROJECT"]="AGENT TUTORIAL"
# File konfigurasi untuk mengelola API KEY sebagai variabel lingkunganfrom dotenv import load_dotenv# Memuat informasi API KEYload_dotenv()
True
# Mengimpor kelas TavilySearchResults dari modul langchain_community.tools.tavily_search.from langchain_community.tools.tavily_search import TavilySearchResults# Membuat instance dari kelas TavilySearchResults# k=5 berarti hingga 5 hasil pencarian akan diambilsearch =TavilySearchResults(k=5)
Fungsi search.invoke menjalankan pencarian untuk string yang diberikan.
Untuk melakukan pencarian, masukkan kata kunci pencarian yang diinginkan ke dalam fungsi invoke().
# Mendapatkan hasil pencarian.search.invoke("Apa nomor telepon Pemadam kebakaran di Indonesia?")
[{'url': 'https://mediaindonesia.com/humaniora/643163/daftar-nomor-telepon-darurat-indonesia-layanan-masyarakat-24-jam', 'content': 'Nomor-nomor ini penting untuk disimpan dalam ponsel anda Ini merupakan daftar nomor telepon darurat di Indonesia. Login; Subscribe; Headline ... Pemadam kebakaran: 113; Jasa Marga: 14080; Badan Nasional Penanggulangan Bencana: 117; ... Apa yang Terlewat? 26/8/2024 05:00. Optimisme Menyikapi Tantangan Perekonomian 19/8/2024 05:00.'}, {'url': 'https://hellosehat.com/hidup-sehat/pertolongan-pertama/daftar-nomor-telepon-darurat/', 'content': 'Daftar nomor telepon darurat di Indonesia. Kehadiran Layanan Nomor Panggilan Darurat 112 tidak menghilangkan beberapa nomor lain, seperti nomor darurat polisi, ambulance, pemadam kebakaran, maupun rumah sakit. Dengan begitu, Anda tetap bisa melakukan panggilan ke nomor darurat yang lebih spesifik bila daerah Anda belum terjangkau layanan 112 atau nomor 112 tidak bisa diakses.'}, {'url': 'https://regional.kompas.com/read/2022/01/03/130038078/daftar-nomor-telepon-darurat-di-indonesia-penting-saat-kondisi-gawat', 'content': 'KOMPAS.com - Berikut ini daftar nomor telepon darurat di Indonesia: 112 untuk Panggilan Darurat atau Call Center. 118 atau 119 untuk Ambulans (Khusus DKI 021-65303118) 113 untuk Pemadam Kebakaran. 110 untuk Kepolisian. 115 untuk SAR atau Basarnas. 129 untuk Posko Bencana Alam. 122 untuk Posko Kewaspadaan Nasional.'}, {'url': 'https://www.liputan6.com/citizen6/read/5112147/catat-berikut-daftar-nomor-layanan-darurat-di-indonesia-yang-wajib-kamu-punya', 'content': 'Pemadam kebakaran (113) Polisi (110) SAR atau BASARNAS (115) Ambulans (118 atau 119) PLN (123) Posko bencana alam (129) Selain nomor-nomor darurat tersebut, ada nomor yang harus kamu hafalkan. Nomor ini dihubungi bila kamu atau sebagai sanksi bagi korban tindak kekerasan di lingkunganmu. Berikut nomor telepon darurat apabila menemui tindak ...'}, {'url': 'https://www.kompas.com/tren/read/2021/11/15/123000465/catat-nomor-telepon-darurat-di-indonesia', 'content': 'Berikut nomor darurat Indonesia tersebut: 1. Nomor darurat 112. Melansir dari laman kominfo.go.id, nomor panggilan darurat 112 sudah diluncurkan sejak tahun 2015. Call center 112 dilaksanakan secara desentralisasi oleh Pemerintah Daerah Kabupaten atau Kota dengan unit yang bisa terjun ke lapangan memberikan bantuan seperti pemadam kebakaran ...'}]
Alat Pencarian Dokumen Berbasis PDF: Retriever
Kita juga membuat retriever untuk melakukan pencarian pada data kita.
Kode ini membangun sistem pencarian dokumen menggunakan pemuat dokumen berbasis web, pemecah dokumen, penyimpanan vektor, dan embedding OpenAI.
Dalam kasus ini, kita membuat retriever yang menyimpan dan melakukan pencarian dokumen PDF di FAISS DB.
from langchain.text_splitter import RecursiveCharacterTextSplitterfrom langchain_community.vectorstores import FAISSfrom langchain_openai import OpenAIEmbeddingsfrom langchain.document_loaders import PyPDFLoader# Memuat file PDF. Masukkan path fileloader =PyPDFLoader("../data/ChatGPT: Keuntungan, Risiko, Dan Penggunaan Bijak Dalam Era Kecerdasan Buatan.pdf")# Gunakan pemecah teks untuk membagi dokumen.text_splitter =RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=100)# Memuat dan membagi dokumen.split_docs = loader.load_and_split(text_splitter)# Membuat VectorStore.vector = FAISS.from_documents(split_docs, OpenAIEmbeddings())# Membuat Retriever.retriever = vector.as_retriever()
Fungsi ini menggunakan metode get_relevant_documents dari objek retriever untuk mengembalikan dokumen pertama yang terkait dengan kueri "Beri tahu saya tentang kewajiban pelabelan konten yang dihasilkan AI oleh YouTube mulai tahun 2024."
Ini digunakan untuk menemukan dokumen yang paling relevan untuk kueri tertentu.
# Mendapatkan chunk yang paling relevan untuk query dari dokumen PDF.retriever.get_relevant_documents("Beri tahu saya tentang kelebihan dari menggunakan ChatGPT.")[0]
Sekarang, setelah kita mengisi indeks yang akan digunakan untuk pencarian, kita dapat dengan mudah mengubahnya menjadi alat yang dapat digunakan agen dengan benar.
Fungsi create_retriever_tool diimpor dari modul tools.retriever dari pustaka langchain. Fungsi ini digunakan untuk membuat alat untuk mencari data tertentu. Langchain adalah pustaka yang menyediakan berbagai fitur terkait model bahasa, salah satunya adalah fitur pembuatan alat pencarian yang memudahkan tugas pencarian dan pemrosesan data.
# Mengimpor fungsi untuk membuat alat retriever dari modul tools dalam paket langchain.from langchain.tools.retriever import create_retriever_tool
Fungsi ini memanggil create_retriever_tool untuk menghasilkan retriever_tool. Alat ini digunakan untuk mencari informasi tentang LangSmith.
Ketika pengguna memiliki pertanyaan tentang LangSmith, alat ini dapat digunakan untuk menyelesaikan pertanyaan tersebut. Fungsi ini menerima instance retriever, nama alat pencarian (langsmith_search), dan pesan yang memberikan panduan kepada pengguna tentang cara menggunakan alat tersebut
retriever_tool =create_retriever_tool( retriever, name="pdf_search", description="Cari informasi terkait AI dari dokumen PDF. Gunakan alat ini untuk pertanyaan terkait 'Tren Industri AI Desember 2023'!"
)
Menentukan daftar alat yang akan digunakan oleh Agen
Sekarang, setelah kita membuat keduanya, kita dapat membuat daftar alat yang akan digunakan oleh Agen.
Daftar tools mencakup search dan retriever_tool. Daftar ini digunakan untuk menyimpan alat pencarian dan pengambilan informasi. Setiap elemen menyediakan fungsionalitas yang diperlukan untuk melakukan tugas-tugas tertentu.
# Tambahkan search dan retriever_tool ke dalam daftar tools.tools = [search, retriever_tool]
Pembuatan Agen
Sekarang setelah kita mendefinisikan alat, kita dapat membuat agen. Kita akan menggunakan agen OpenAI Functions.
Pertama, kita mendefinisikan LLM (Language Learning Model) yang akan digunakan oleh agen.
Kelas ChatOpenAI, yang diimpor dari modul langchain_openai, memungkinkan implementasi AI percakapan menggunakan model bahasa OpenAI.
Dalam contoh ini, kita menggunakan model gpt-4-turbo-preview, dan parameter temperature disetel ke 0 untuk meminimalkan variabilitas dalam prediksi.
from langchain_openai import ChatOpenAI# Mengimpor kelas ChatOpenAI dari modul langchain_openai.llm =ChatOpenAI(model="gpt-4-turbo-preview", temperature=0)
Selanjutnya, kita memilih prompt yang ingin kita gunakan untuk membimbing agen.
Jika Anda ingin melihat isi dari prompt ini dan memiliki akses ke LangSmith, buka tautan berikut:
Setelah menarik sumber daya menggunakan fungsi hub.pull(), Anda dapat mengakses pesan dari sumber daya tersebut melalui prompt.messages.
from langchain import hub# Mengambil prompt dari hub - bagian ini bisa dimodifikasi!prompt = hub.pull("hwchase17/openai-functions-agent")# Mencetak pesan dari prompt.prompt.messages
Sekarang, kita dapat menginisialisasi agen dengan LLM, prompt, dan alat. Peran agen adalah menerima input dan memutuskan Aksi mana yang akan diambil.
Penting untuk dicatat bahwa agen tidak menjalankan aksi itu sendiri — ini dilakukan oleh AgentExecutor (pada langkah berikutnya).
from langchain.agents import create_openai_functions_agent# Membuat agen berbasis fungsi OpenAI.# Gunakan llm, tools, dan prompt sebagai argumen.agent =create_openai_functions_agent(llm, tools, prompt)
Terakhir, kita menggabungkan agen dengan alat-alat di dalam AgentExecutor (ini akan memanggil agen secara berulang dan menjalankan alat-alat tersebut).
Kode ini mengimpor kelas AgentExecutor dari modul langchain.agents dan membuat instance. Saat inisialisasi, agent dan tools diberikan sebagai argumen, dan verbose=True disetel untuk mengaktifkan keluaran log yang lebih rinci. AgentExecutor bertugas menjalankan tugas dengan menggunakan agen dan alat-alat yang diberikan.
from langchain.agents import AgentExecutor# Gunakan kelas AgentExecutor untuk mengatur agen dan alat, dan setel verbose ke True untuk mengaktifkan keluaran log yang lebih rinci.
agent_executor =AgentExecutor(agent=agent, tools=tools, verbose=True)
Menjalankan Agen
Sekarang kita bisa menjalankan agen dengan beberapa pertanyaan!
Saat ini, semua pertanyaan ini bersifat stateless (tidak mengingat interaksi sebelumnya).
Metode invoke dari objek agent_executor memproses argumen yang diberikan dalam bentuk kamus. Dalam contoh ini, kamus dengan kunci input dan nilai hi! diberikan sebagai argumen. Ini biasanya digunakan untuk memproses input dalam objek seperti agen AI, eksekutor fungsi, atau pemroses perintah
# Panggil metode 'invoke' dari objek 'agent_executor',# memberikan kamus dengan kunci 'input' dan nilai '안녕, 반가워' sebagai argumen.response = agent_executor.invoke({"input": "Beri tahu saya hasil pertandingan sepak bola Korea Selatan di Piala Asia 2024."})
print(f'Jawaban: {response["output"]}')
Gunakan metode invoke dari objek agent_executor untuk memberikan pertanyaan sebagai input.
Anda dapat memeriksa hasil eksekusi langkah demi langkah secara detail di tautan pelacakan berikut.
# Panggil metode 'invoke' dari objek 'agent_executor', memberikan pertanyaan tentang bagaimana 'langsmith' dapat membantu pengujian sebagai input.
response = agent_executor.invoke( { "input": "Beri tahu saya tentang kewajiban pelabelan konten yang dihasilkan AI oleh YouTube mulai tahun 2024, dari dokumen PDF."
})print(f'Jawaban: {response["output"]}')
# Setelah meminta hasil pencarian, cetak jawaban dari pertanyaan tersebut.response = agent_executor.invoke( {"input": "Tolong cari nomor telepon Kakao Friends Shop Ajit di Pangyo dan beri tahu saya hasilnya."})print(f'Jawaban: {response["output"]}')
Menambahkan Memori
Seperti yang disebutkan sebelumnya, agen ini tidak memiliki status, artinya agen tidak mengingat interaksi sebelumnya. Untuk memberikan memori kepada agen ini, kita perlu meneruskan chat_history sebelumnya.
[Catatan]
Karena prompt yang kita gunakan, harus disebut chat_history. Jika Anda menggunakan prompt yang berbeda, Anda dapat mengubah nama variabelnya.
Fungsi menerima input pengguna dan chat_history sebagai parameter. Di sini, chat_history dikirim sebagai daftar kosong ([]) saat menangani pesan pertama dari obrolan. Ini menunjukkan bahwa tidak ada riwayat percakapan sebelumnya saat memulai sesi obrolan baru.
# Karena ini adalah pesan pertama dari obrolan, berikan daftar kosong ke chat_history.response = agent_executor.invoke( {"input": "Hi! Saya Andi. Senang bertemu dengan Anda.", "chat_history": []})print(f'Jawaban: {response["output"]}')
Modul ini mengimpor kelas AIMessage dan HumanMessage dari langchain_core.messages. Kelas ini dapat digunakan untuk menangani pertukaran pesan antara AI dan manusia.
AIMessage mewakili pesan yang dihasilkan oleh AI, sedangkan HumanMessage mewakili pesan yang dimasukkan oleh pengguna
# Mengimpor AIMessage dan HumanMessage dari langchain_core.messages.from langchain_core.messages import AIMessage, HumanMessage
Fungsi ini menjalankan agen percakapan yang menangani riwayat percakapan antara pengguna dan AI, serta input baru dari pengguna. Metode agent_executor.invoke menerima chat_history dan input baru pengguna input sebagai parameter. chat_history adalah daftar objek HumanMessage dan AIMessage, yang mewakili pesan dari pengguna dan AI, masing-masing. Dalam contoh ini, pengguna menyapa dengan "hi! Saya Andi", AI merespons dengan "Hello Andi! Bagaimana saya bisa membantu hari ini?", lalu pengguna mengajukan pertanyaan baru: "Siapa nama saya?".
response = agent_executor.invoke( {"chat_history": [HumanMessage(content="Hi! Saya Andi. Senang bertemu dengan Anda."),AIMessage( content="Halo Andi! Saya juga senang bertemu dengan Anda. Bagaimana saya bisa membantu hari ini?" ), ],"input": "Siapa nama saya?", })print(f'Jawaban: {response["output"]}')
Jika Anda ingin melacak pesan-pesan ini secara otomatis, Anda bisa membungkusnya dengan RunnableWithMessageHistory.
from langchain_community.chat_message_histories import ChatMessageHistoryfrom langchain_core.runnables.history import RunnableWithMessageHistory
Buat instance dari kelas ChatMessageHistory dan tetapkan ke variabel message_history. Instance ini digunakan untuk mengelola catatan pesan obrolan.
# Membuat objek untuk mengelola riwayat pesan obrolan.message_history =ChatMessageHistory()
Kelas RunnableWithMessageHistory mengelola eksekutor agen (agent_executor) dan riwayat pesan. Kelas ini menerima fungsi lambda yang menangani riwayat pesan berdasarkan session ID, serta kunci untuk pesan input dan riwayat obrolan.
Di sini, session ID sebenarnya tidak digunakan, dan ini hanya contoh menggunakan ChatMessageHistory dalam memori.
Secara default, eksekusi menerima satu parameter konfigurasi, sebuah string yang disebut session_id. Parameter ini digunakan untuk membuat riwayat pesan obrolan baru atau mengambil riwayat pesan obrolan yang ada yang cocok dengan session_id yang diberikan.
agent_with_chat_history =RunnableWithMessageHistory( agent_executor,# Ini diperlukan karena session ID diperlukan di sebagian besar skenario nyata# Namun, ini tidak benar-benar digunakan di sini karena kami menggunakan ChatMessageHistory dalam memori sederhanalambdasession_id: message_history,# Kunci di mana pertanyaan dari prompt dimasukkan: "input" input_messages_key="input",# Kunci di mana riwayat pesan dari prompt dimasukkan: "chat_history" history_messages_key="chat_history",)
Fungsi agent_with_chat_history.invoke memproses input pengguna dan konfigurasi sebagai parameter. Dalam contoh ini, input pengguna ("hi! Saya Bob") dan konfigurasi (config) diberikan. Meskipun konfigurasi menyertakan session_id, ini sebenarnya tidak digunakan dalam contoh ini karena menggunakan ChatMessageHistory dalam memori sederhana. Kode ini menunjukkan bahwa meskipun session ID diperlukan di sebagian besar skenario nyata, implementasi tertentu mungkin tidak memerlukannya.
response = agent_with_chat_history.invoke( {"input": "Hi! Saya Andi. Senang bertemu dengan Anda."},# Mengatur session ID.# Ini sebenarnya tidak digunakan di sini karena menggunakan ChatMessageHistory dalam memori sederhana. config={"configurable": {"session_id": "MyTestSessionID"}},)print(f"Jawaban: {response['output']}")
Panggilan fungsi ini menggunakan objek agent_with_chat_history untuk menghasilkan respons terhadap pertanyaan yang dimasukkan. Input diberikan melalui kunci input, dan dalam kasus ini, "Siapa nama saya?" digunakan. Selain itu, parameter config memungkinkan penambahan konfigurasi, dan dalam contoh ini, session_id diatur ke <foo>. Ini menunjukkan bahwa meskipun session ID diperlukan di sebagian besar skenario nyata, ID tersebut tidak benar-benar digunakan di sini karena menggunakan ChatMessageHistory dalam memori sederhana.
response = agent_with_chat_history.invoke( {"input": "Siapa nama saya?"},# Mengatur session ID.# Ini sebenarnya tidak digunakan di sini karena menggunakan ChatMessageHistory dalam memori sederhana. config={"configurable": {"session_id": "MyTestSessionID"}},)print(f"Jawaban: {response['output']}")
response = agent_with_chat_history.invoke( {"input": "Tolong cari nomor telepon dari Altero Academy dan beri tahu saya hasilnya."},# Mengatur session ID.# Ini sebenarnya tidak digunakan di sini karena menggunakan ChatMessageHistory dalam memori sederhana. config={"configurable": {"session_id": "MyTestSessionID"}},)print(f"Jawaban: {response['output']}")
response = agent_with_chat_history.invoke(
{
"input": "Tolong beri tahu saya tentang nama channel youtube belajar AI dalam bahasa Indonesia di YouTube"
},
# Mengatur session ID.
# Ini sebenarnya tidak digunakan di sini karena menggunakan ChatMessageHistory dalam memori sederhana.
config={"configurable": {"session_id": 'MyTestSessionID'}},
)
print(f"Jawaban: {response['output']}")
Agen Template
# Mengimpor modul yang diperlukanfrom langchain_community.tools.tavily_search import TavilySearchResultsfrom langchain.text_splitter import RecursiveCharacterTextSplitterfrom langchain_community.vectorstores import FAISSfrom langchain_openai import OpenAIEmbeddingsfrom langchain.document_loaders import PyPDFLoaderfrom langchain.tools.retriever import create_retriever_toolfrom langchain_openai import ChatOpenAIfrom langchain import hubfrom langchain.agents import create_openai_functions_agent, AgentExecutorfrom langchain_community.chat_message_histories import ChatMessageHistoryfrom langchain_core.runnables.history import RunnableWithMessageHistory########## 1. Definisikan Alat ############# 1-1. Alat Pencarian #### Membuat instance dari kelas TavilySearchResults# k=5 berarti hasil pencarian hingga 5search =TavilySearchResults(k=5)### 1-2. Alat Pencarian Dokumen PDF (Retriever) #### Muat file PDF. Masukkan jalur fileloader =PyPDFLoader("data/SPRI_AI_Brief_2023년12월호_F.pdf")# Gunakan pemecah teks untuk membagi dokumen.text_splitter =RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=100)# Muat dan bagikan dokumen.split_docs = loader.load_and_split(text_splitter)# Membuat VectorStore.vector = FAISS.from_documents(split_docs, OpenAIEmbeddings())# Membuat Retriever.retriever = vector.as_retriever()# Membuat alat retriever dari modul tools langchainretriever_tool =create_retriever_tool( retriever, name="pdf_search",# Anda perlu memberikan deskripsi rinci tentang alat ini!!! description="Cari informasi terkait AI dari Desember 2023 di dokumen PDF. Gunakan alat ini untuk pertanyaan terkait 'tren industri AI Desember 2023'!",
)### 1-3. Tambahkan daftar alat ke tools #### Tambahkan search dan retriever_tool ke dalam daftar tools.tools = [search, retriever_tool]########## 2. Definisikan LLM ########### Membuat model LLM.llm =ChatOpenAI(model="gpt-4-turbo-preview", temperature=0)########## 3. Definisikan Prompt ########### Mengambil prompt dari hub - Bagian ini bisa disesuaikan!prompt = hub.pull("hwchase17/openai-functions-agent")########## 4. Definisikan Agent ########### Membuat agent berbasis fungsi OpenAI.# Gunakan llm, tools, dan prompt sebagai parameter.agent =create_openai_functions_agent(llm, tools, prompt)########## 5. Definisikan AgentExecutor ########### Gunakan kelas AgentExecutor untuk mengonfigurasi agent dan tools, serta mengaktifkan log detail dengan verbose diatur ke True.
agent_executor =AgentExecutor(agent=agent, tools=tools, verbose=True)########## 6. Tambahkan Memori untuk Riwayat Chat ########### Membuat objek untuk mengelola riwayat pesan chat.message_history =ChatMessageHistory()# Membuat agent dengan riwayat pesan chat.agent_with_chat_history =RunnableWithMessageHistory( agent_executor,# Ini diperlukan di sebagian besar skenario nyata di mana ID sesi diperlukan.# Dalam hal ini, kami menggunakan ChatMessageHistory dalam memori sederhana, jadi tidak benar-benar digunakan.lambdasession_id: message_history,# Kunci untuk input pertanyaan: "input" input_messages_key="input",# Kunci untuk riwayat chat: "chat_history" history_messages_key="chat_history",)########## 7. Lakukan Uji Q&A ########### Cetak jawaban untuk pertanyaan.response = agent_with_chat_history.invoke( { "input": "Tolong beri tahu saya tentang kewajiban pelabelan konten yang dihasilkan AI di YouTube mulai tahun 2024 dari dokumen PDF."
},# Atur ID sesi.# Ini sebenarnya tidak digunakan di sini karena menggunakan ChatMessageHistory dalam memori sederhana. config={"configurable": {"session_id": "MyTestSessionID"}},)print(f"Jawaban: {response['output']}")
Penutup!
Dalam tutorial ini, kita membahas cara membuat agen sederhana.