# 08. RunnableWithMessageHistory

## Menambahkan riwayat pesan (memori)

Memanfaatkan `RunnableWithMessageHistory` untuk menambahkan riwayat pesan ke jenis tugas (rantai) tertentu adalah fitur yang sangat berguna dalam pemrograman.

Fitur ini sangat penting ketika mengimplementasikan aplikasi interaktif atau tugas pemrosesan data yang kompleks, di mana ada kebutuhan untuk mempertahankan konteks pesan sebelumnya.

Dengan mengelola riwayat pesan, pengembang dapat mengontrol aliran aplikasi dengan lebih baik dan merespons permintaan sebelumnya dari pengguna dengan tepat.

**Contoh**

* Mengembangkan chatbot percakapan: Sesuaikan respons chatbot berdasarkan riwayat dialog dengan pengguna.
* Pemrosesan data yang kompleks: Selama pemrosesan data, Anda dapat merujuk ke hasil dari langkah sebelumnya untuk menentukan logika langkah berikutnya.
* Aplikasi yang memerlukan manajemen status: Anda dapat mengingat pilihan pengguna sebelumnya dan memberikan layar atau informasi berikutnya yang sesuai.

RunnableWithMessageHistory adalah alat canggih yang memungkinkan Anda mempertahankan status aplikasi, meningkatkan pengalaman pengguna, dan mengimplementasikan mekanisme respons yang lebih canggih.

## Tutorial

```python
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_openai import ChatOpenAI

model = ChatOpenAI()
prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "Anda adalah asisten yang mahir dalam {ability}. Harap jawab dalam 20 karakter atau kurang",
        ),
        # menggunakan riwayat percakapan sebagai variabel, dengan riwayat sebagai kunci dari MessageHistory
        MessagesPlaceholder(variable_name="history"),
        ("human", "{input}"), # gunakan masukan pengguna sebagai variabel
    ]
)
runnable = prompt | model # menggabungkan prompt dan model untuk membuat objek yang dapat dijalankan
```

Mengelola riwayat pesan sangat penting dalam aplikasi interaktif atau tugas pemrosesan data yang kompleks. Untuk mengelola riwayat pesan secara efektif, Anda memerlukan dua elemen utama

* **Runnable**: objek yang dapat dijalankan yang berinteraksi dengan BaseChatMessageHistory, terutama Retriever dan Chain.
* Objek yang dapat dipanggil yang mengembalikan sebuah instance dari `BaseChatMessageHistory`: Objek untuk mengelola riwayat pesan. Objek ini digunakan untuk menyimpan, mengambil, dan memperbarui riwayat pesan. Riwayat pesan diperlukan untuk menjaga konteks percakapan dan untuk menghasilkan respons berdasarkan masukan pengguna sebelumnya.

Ada banyak cara untuk mengimplementasikan riwayat pesan, dan halaman [integrasi memori](https://integrations.langchain.com/memory) menjelaskan berbagai pilihan penyimpanan dan integrasi.

Di sini kita akan melihat dua metode utama

**Menggunakan `ChatMessageHistory` dalam memori**

Metode ini mengelola riwayat pesan dalam memori. Metode ini sering digunakan selama fase pengembangan atau dalam aplikasi sederhana. Metode in-memory menyediakan kecepatan akses yang cepat, tetapi kekurangannya adalah riwayat pesan akan hilang ketika aplikasi dimulai ulang.

**Memanfaatkan penyimpanan persisten dengan `RedisChatMessageHistory`**

Menggunakan Redis memungkinkan Anda untuk menyimpan riwayat pesan secara persisten. Redis merupakan penyimpanan struktur data dalam-memori berkinerja tinggi, bersumber terbuka, dan dapat diandalkan untuk mengelola riwayat pesan dalam lingkungan terdistribusi. Metode ini ideal untuk aplikasi yang kompleks atau layanan yang sudah berjalan lama.

Ketika memilih metode untuk mengelola riwayat pesan, Anda harus mempertimbangkan kebutuhan aplikasi Anda, jumlah lalu lintas yang Anda perkirakan, pentingnya data pesan, dan berapa lama Anda ingin menyimpannya. Metode dalam memori sederhana dan cepat untuk diimplementasikan, tetapi jika Anda memerlukan persistensi data, penyimpanan persisten seperti Redis mungkin lebih cocok.

## Riwayat percakapan yang volatil: In-Memory.

Di bawah ini adalah contoh sederhana riwayat obrolan yang disimpan dalam memori.

Parameter pengaturan `RunnableWithMessageHistory`

* `Runnable`
* `BaseChatMessageHistory` atau objek yang diwarisi. misalnya `ChatMessageHistory`
* `input_messages_key`: kunci untuk menentukan sebagai input kueri pengguna saat memanggil rantai
* `history_messages_key`: kunci untuk menentukan sebagai riwayat percakapan

```python
from langchain_community.chat_message_histories import ChatMessageHistory
from langchain_core.chat_history import BaseChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory

store = {}  # Kamus untuk menyimpan riwayat sesi


# Fungsi untuk mengambil riwayat sesi berdasarkan ID sesi
def get_session_history(session_ids: str) -> BaseChatMessageHistory:
    print(session_ids)
    if session_ids not in store:  # Jika ID sesi tidak ada di store
        # Buat objek ChatMessageHistory baru dan simpan ke store
        store[session_ids] = ChatMessageHistory()
    return store[session_ids]  # Kembalikan riwayat sesi untuk ID sesi tersebut


with_message_history = (
    RunnableWithMessageHistory(  # Buat objek RunnableWithMessageHistory
        runnable,  # Objek Runnable yang akan dijalankan
        get_session_history,  # Fungsi untuk mengambil riwayat sesi
        input_messages_key="input",  # Kunci untuk pesan input
        history_messages_key="history",  # Kunci untuk pesan riwayat
    )
)
```

`Input_messages_key` menentukan kunci yang akan diperlakukan sebagai pesan masukan terbaru, dan `history_messages_key` menentukan kunci yang akan ditambahkan pesan lama.

Pada kode berikut, kita dapat melihat bahwa kunci `session_id` dimasukkan sebagai Default pada nilai awal `RunnableWithMessageHistory`, yang secara tidak langsung memberi tahu kita bahwa `RunnableWithMessageHistory` mengelola utas dialog dengan `session_id`.

Dengan kata lain, kita dapat melihat bahwa manajemen per-thread diimplementasikan oleh `session_id`.

Lihat referensi kode: Implementasi `RunnableWithMessageHistory`,

```python
if history_factory_config:
    _config_specs = history_factory_config
else:
    # If not provided, then we'll use the default session_id field
    _config_specs = [
        ConfigurableFieldSpec(
            id="session_id",
            annotation=str,
            name="Session ID",
            description="Unique identifier for a session.",
            default="",
            is_shared=True,
        ),
    ]
```

Jadi, pada `invoke()`, `config = {“configurable”: {“session_id”: “Masukkan ID sesi"}}` Anda dapat melihat bahwa kita harus menentukan kode.

```python
with_message_history.invoke(
    # Mengirimkan pertanyaan terkait matematika "Apa arti dari kosinus?" sebagai input.
    {"ability": "math", "input": "Apa itu kosinus?"},
    # Mengirimkan ID sesi "abc123" sebagai informasi konfigurasi.
    config={"configurable": {"session_id": "abc123"}},
)
```

{% code overflow="wrap" %}
```
abc123
```
{% endcode %}

{% code overflow="wrap" %}
```
content='Fungsi trigonometri.' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 8, 'prompt_tokens': 39, 'total_tokens': 47}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None} id='run-c5a53d52-dcaa-4afd-a0f9-304a437f8199-0' usage_metadata={'input_tokens': 39, 'output_tokens': 8, 'total_tokens': 47}
```
{% endcode %}

Jika Anda memasukkan `session_id` yang sama, Anda akan mendapatkan konten dari utas percakapan sebelumnya, sehingga Anda dapat melanjutkan percakapan!

```python
# Memanggil dengan menyertakan riwayat pesan.
with_message_history.invoke(
    # Menetapkan kemampuan dan input.
    {"ability": "math", "input": "Tolong jawab dalam bahasa Inggris berdasarkan percakapan sebelumnya."},
    # Menetapkan opsi konfigurasi.
    config={"configurable": {"session_id": "abc123"}},
)
```

```
abc123
```

{% code overflow="wrap" %}
```
content='Trigonometry function.' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 5, 'prompt_tokens': 76, 'total_tokens': 81}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None} id='run-db9473e7-c884-470a-a618-7088e91989d9-0' usage_metadata={'input_tokens': 76, 'output_tokens': 5, 'total_tokens': 81}
```
{% endcode %}

Namun, jika Anda menentukan `session_id` yang berbeda, ia tidak akan menjawab dengan benar karena tidak ada riwayat percakapan.

(Pada contoh di bawah ini, Anda dapat melihat bahwa `session_id: def234` memberikan jawaban yang salah karena tidak ada)

```python
# Karena session_id baru, tidak mengingat percakapan sebelumnya.
with_message_history.invoke(
    # Mengirimkan kemampuan matematika dan pesan input.
    {"ability": "math", "input": "Tolong jawab dalam bahasa Inggris berdasarkan percakapan sebelumnya"},
    # Menetapkan session_id baru.
    config={"configurable": {"session_id": "def234"}},
)
```

```
def234
```

{% code overflow="wrap" %}
```
content='Sure, how can I help you?' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 8, 'prompt_tokens': 50, 'total_tokens': 58}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None} id='run-23961fe3-af1b-4711-b0be-34b0a09b6aa4-0' usage_metadata={'input_tokens': 50, 'output_tokens': 8, 'total_tokens': 58}
```
{% endcode %}

Parameter konfigurasi yang digunakan untuk melacak riwayat pesan dapat disesuaikan dengan mengoper daftar objek `ConfigurableFieldSpec` ke parameter `history_factory_config`.

Pengaturan baru `history_factory_config` ini akan menimpa pengaturan `session_id` yang sudah ada.

Contoh di bawah ini menggunakan dua parameter: `user_id` dan `conversation_id`.

```python
from langchain_core.runnables import ConfigurableFieldSpec

store = {}  # Inisialisasi kamus kosong.


def get_session_history(user_id: str, conversation_id: str) -> BaseChatMessageHistory:
    # Mengembalikan riwayat sesi yang sesuai dengan user_id dan conversation_id yang diberikan.
    if (user_id, conversation_id) not in store:
        # Jika kunci tersebut tidak ada di store, buat dan simpan ChatMessageHistory baru.
        store[(user_id, conversation_id)] = ChatMessageHistory()
    return store[(user_id, conversation_id)]


with_message_history = RunnableWithMessageHistory(
    runnable,
    get_session_history,
    input_messages_key="input",
    history_messages_key="history",
    history_factory_config=[  # Ini akan menggantikan pengaturan "session_id" yang ada.
        ConfigurableFieldSpec(
            id="user_id",  # Digunakan sebagai argumen pertama dari fungsi get_session_history.
            annotation=str,
            name="User ID",
            description="Pengenal unik untuk pengguna.",
            default="",
            is_shared=True,
        ),
        ConfigurableFieldSpec(
            id="conversation_id",  # Digunakan sebagai argumen kedua dari fungsi get_session_history.
            annotation=str,
            name="Conversation ID",
            description="Pengenal unik untuk percakapan.",
            default="",
            is_shared=True,
        ),
    ],
)
```

```python
with_message_history.invoke(
    # Mengirimkan kamus yang berisi kemampuan (ability) dan input (input).
    {"ability": "math", "input": "Hello"},
    # Mengirimkan kamus konfigurasi (config).
    config={"configurable": {"user_id": "123", "conversation_id": "1"}},
)
```

{% code overflow="wrap" %}
```
content='Hi! What can I help you with today?' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 10, 'prompt_tokens': 34, 'total_tokens': 44}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None} id='run-c22b0ab2-3ae8-474b-956a-615b6d0a2f04-0' usage_metadata={'input_tokens': 34, 'output_tokens': 10, 'total_tokens': 44}
```
{% endcode %}

## Contoh penggunaan Runnable dengan berbagai keys.

### Masukkan objek Pesan, keluarkan sebagai dictionary

Ini mengambil pesan sebagai masukan dan mengembalikan kamus sebagai keluaran.

* \[Penting]: Hilangkan `input_messages_key` = “input”, yang akan mengaturnya untuk mengambil objek Pesan sebagai input.

```python
from langchain_core.messages import HumanMessage
from langchain_core.runnables import RunnableParallel

# Membuat chain
chain = RunnableParallel({"output_message": ChatOpenAI()})


def get_session_history(session_id: str) -> BaseChatMessageHistory:
    # Jika riwayat percakapan untuk session ID tidak ada di penyimpanan, buat ChatMessageHistory baru.
    if session_id not in store:
        store[session_id] = ChatMessageHistory()
    # Kembalikan riwayat percakapan untuk session ID yang diberikan.
    return store[session_id]


# Membuat objek RunnableWithMessageHistory yang menambahkan fungsi riwayat percakapan ke dalam chain.
with_message_history = RunnableWithMessageHistory(
    chain,
    get_session_history,
    # Mengatur kunci pesan input ke "input". (Diabaikan jika input berupa objek Message)
    # input_messages_key="input",
    # Mengatur kunci pesan output ke "output_message". (Diabaikan jika output berupa objek Message)
    output_messages_key="output_message",
)

# Menjalankan chain dengan pesan dan konfigurasi yang diberikan.
with_message_history.invoke(
    # Atau bisa juga menggunakan "what is the definition of cosine?"
    [HumanMessage(content="Apa definisi dari kosinus?")],
    config={"configurable": {"session_id": "abc123"}},
)
```

{% code overflow="wrap" %}
```
{'output_message': AIMessage(content='Kosinus adalah fungsi trigonometri yang merupakan rasio panjang sisi sejajar dengan sudut dalam sebuah segitiga siku-siku terhadap panjang sisi miring segitiga tersebut. Dalam matematika, kosinus sering dilambangkan dengan simbol "cos".', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 66, 'prompt_tokens': 15, 'total_tokens': 81}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None}, id='run-9fe92482-e149-4a32-b1b1-4243ad69a9d7-0', usage_metadata={'input_tokens': 15, 'output_tokens': 66, 'total_tokens': 81})}
```
{% endcode %}

{% code overflow="wrap" %}
```python
with_message_history.invoke(
    # Meminta ulang jawaban sebelumnya dalam bahasa Korea.
    [HumanMessage(content="Tolong jawab dalam bahasa Inggris berdasarkan pertanyaan sebelumnya!")],
    # Mengirimkan opsi konfigurasi dalam bentuk kamus.
    config={"configurable": {"session_id": "abc123"}},
)
```
{% endcode %}

{% code overflow="wrap" %}
```
{'output_message': AIMessage(content='Cosine is a mathematical function that measures the ratio of the length of the adjacent side to the length of the hypotenuse in a right triangle. In trigonometry, the cosine of a specific angle in a right triangle is defined as the length of the adjacent side to that angle divided by the length of the hypotenuse of the triangle.', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 70, 'prompt_tokens': 141, 'total_tokens': 211}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None}, id='run-2a4115e8-91a4-4100-9b6e-98459b83dd0a-0', usage_metadata={'input_tokens': 141, 'output_tokens': 70, 'total_tokens': 211})}
```
{% endcode %}

### Memasukkan objek Pesan, mengeluarkan objek Pesan

\[Penting]: `output_messages_key` = “output\_message”, yang akan mengembalikan objek Message sebagai output.

```python
with_message_history = RunnableWithMessageHistory(
    ChatOpenAI(),  # Menggunakan model bahasa ChatOpenAI.
    get_session_history,  # Menetapkan fungsi untuk mengambil riwayat sesi percakapan.
    # Mengatur kunci pesan input ke "input". (Diabaikan jika input berupa objek Message)
    # input_messages_key="input",
    # Mengatur kunci pesan output ke "output_message". (Diabaikan jika output berupa objek Message)
    # output_messages_key="output_message",
)
```

```python
with_message_history.invoke(
    # Meminta ulang jawaban dalam bahasa Korea berdasarkan percakapan sebelumnya.
    [HumanMessage(content="Apa arti dari kosinus?")],
    # Mengirimkan opsi konfigurasi dalam bentuk kamus.
    config={"configurable": {"session_id": "def123"}},
)
```

{% code overflow="wrap" %}
```
content='Kosinus adalah fungsi matematika yang menghasilkan nilai rasio dari panjang sisi sejajar terhadap panjang sisi miring pada segitiga siku-siku. Dalam trigonometri, kosinus dari suatu sudut dalam sebuah segitiga siku-siku adalah nilai rasio antara panjang sisi sejajar dengan sudut tersebut terhadap panjang sisi miring segitiga. Kosinus biasanya dilambangkan dengan simbol cos.' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 107, 'prompt_tokens': 15, 'total_tokens': 122}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None} id='run-ea96a85b-3072-4c4a-81a0-5ede74b6b4f0-0' usage_metadata={'input_tokens': 15, 'output_tokens': 107, 'total_tokens': 122}
```
{% endcode %}

### Dict dengan satu key untuk semua input dan output pesan

Pendekatan ini menggunakan satu kunci untuk semua pesan masukan dan pesan keluaran.

* Gunakan `itemgetter(“input_messages”)` untuk mengekstrak pesan masukan.

```python
from operator import itemgetter

with_message_history = RunnableWithMessageHistory(
    # Menggunakan kunci "input_messages" untuk mengambil pesan input dan mengirimkannya ke ChatOpenAI().
    itemgetter("input_messages") | ChatOpenAI(),
    get_session_history,  # Fungsi untuk mengambil riwayat sesi.
    input_messages_key="input_messages",  # Menetapkan kunci untuk pesan input.
)
```

<pre class="language-python"><code class="lang-python"><strong>with_message_history.invoke(
</strong>    {"input_messages": "Apa arti dari kosinus?"},
    # Mengirimkan opsi konfigurasi dalam bentuk kamus.
    config={"configurable": {"session_id": "xyz123"}},
)
</code></pre>

{% code overflow="wrap" %}
```
content='Kosinus adalah sebuah fungsi matematika yang menghasilkan nilai rasio dari panjang sisi sejajar dengan sudut tertentu dalam segitiga siku-siku, dibagi dengan panjang sisi miring segitiga tersebut. Kosinus digunakan dalam trigonometri untuk menghitung panjang sisi segitiga dan sudut-sudutnya.' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 82, 'prompt_tokens': 15, 'total_tokens': 97}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None} id='run-89eaedc8-3ab3-4f73-bac9-e0743eb68b47-0' usage_metadata={'input_tokens': 15, 'output_tokens': 82, 'total_tokens': 97}
```
{% endcode %}

## Persistent Storage

Penyimpanan persisten mengacu pada mekanisme penyimpanan yang mempertahankan data bahkan ketika sebuah program dihentikan atau sistem di-boot ulang. Hal ini dapat diimplementasikan melalui database, sistem file, atau perangkat penyimpanan non-volatile lainnya.

Penyimpanan persisten sangat penting untuk menyimpan status aplikasi, mempertahankan pengaturan pengguna, dan **menyimpan data untuk jangka waktu yang lama**. Hal ini memungkinkan program untuk melanjutkan dari tempat yang ditinggalkannya pada proses sebelumnya, dan memungkinkan pengguna untuk **terus bekerja tanpa kehilangan data**.

* `RunnableWithMessageHistory` tidak bergantung pada cara pemanggilan `get_session_history` untuk mengambil riwayat pesan obrolan.
* Lihat di sini untuk contoh penggunaan sistem berkas lokal. [https://github.com/langchain-ai/langserve/blob/main/examples/chat\_with\_persistence\_and\_user/server.py](https://github.com/langchain-ai/langserve/blob/main/examples/chat_with_persistence_and_user/server.py)
* Di bawah ini kami tunjukkan cara menggunakan **Redis**. Untuk mengetahui cara mengimplementasikan riwayat pesan obrolan menggunakan penyedia lain, lihat [halaman integrasi memori](https://integrations.langchain.com/memory).

### Menginstall Redis

Jika Anda belum menginstal Redis, Anda harus menginstalnya terlebih dahulu.

```
pip install -qU redis
```

### Menjalankan server Redis

Jika Anda tidak memiliki penerapan Redis yang sudah ada untuk disambungkan, mulai server Redis Stack lokal.

Berikut ini adalah perintah untuk memulai server Redis dengan Docker.

```
docker run -d -p 6379:6379 -p 8001:8001 redis/redis-stack:latest
```

Tetapkan URL koneksi basis data Redis ke variabel `REDIS_URL`.

* URL ditetapkan ke “`redis://localhost:6379/0`”.

```
# Tentukan URL server Redis.
REDIS_URL = "redis://localhost:6379/0"
```

### Menyiapkan pelacakan LangSmith

Siapkan LangSmith untuk pelacakan. LangSmith tidak diperlukan, tetapi dapat membantu.

```python
from dotenv import load_dotenv
import os

load_dotenv()

# Tetapkan variabel lingkungan LANGCHAIN_TRACING_V2 ke “true”.
os.environ["LANGCHAIN_TRACING_V2"] = "true"
# Mengatur LANGCHAIN_PROJECT
os.environ["LANGCHAIN_PROJECT"] = "RunnableWithMessageHistory"
```

Untuk memperbarui implementasi riwayat pesan, cukup definisikan objek baru yang dapat dipanggil, kali ini mengembalikan sebuah instance RedisChatMessageHistory.

```python
from langchain_community.chat_message_histories import RedisChatMessageHistory


def get_message_history(session_id: str) -> RedisChatMessageHistory:
    # Mengembalikan objek RedisChatMessageHistory berdasarkan session ID.
    return RedisChatMessageHistory(session_id, url=REDIS_URL)


with_message_history = RunnableWithMessageHistory(
    runnable,  # Objek yang dapat dijalankan
    get_message_history,  # Fungsi untuk mengambil riwayat pesan
    input_messages_key="input",  # Kunci untuk pesan input
    history_messages_key="history",  # Kunci untuk pesan riwayat
)
```

Anda dapat memanggilnya dengan cara yang sama seperti sebelumnya.

```python
with_message_history.invoke(
    # Mengirimkan pertanyaan terkait matematika "Apa arti dari kosinus?" sebagai input.
    {"ability": "math", "input": "Apa arti dari kosinus?"},
    # Menetapkan session ID menjadi "redis123" sebagai opsi konfigurasi.
    config={"configurable": {"session_id": "redis123"}},
)
```

{% code overflow="wrap" %}
```
content='Trigonometri fungsi.' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 7, 'prompt_tokens': 41, 'total_tokens': 48}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None} id='run-1e5c490f-7406-406b-aaaa-f901750bd333-0' usage_metadata={'input_tokens': 41, 'output_tokens': 7, 'total_tokens': 48}
```
{% endcode %}

Lakukan panggilan kedua dengan menggunakan `session_id` yang sama. Kali ini, kami akan meminta jawaban sebelumnya dalam bahasa Korea.

```python
with_message_history.invoke(
    # Meminta terjemahan jawaban sebelumnya ke dalam bahasa Korea.
    {"ability": "math", "input": "Tolong terjemahkan jawaban sebelumnya ke dalam bahasa Korea."},
    # Menetapkan session ID menjadi "redis123" sebagai nilai konfigurasi.
    config={"configurable": {"session_id": "redis123"}},
)
```

{% code overflow="wrap" %}
```
content='Trigonometry function.' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 5, 'prompt_tokens': 75, 'total_tokens': 80}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None} id='run-c666e30b-9bf0-472e-8d4e-6679bfe2b539-0' usage_metadata={'input_tokens': 75, 'output_tokens': 5, 'total_tokens': 80}
```
{% endcode %}

Kali ini, kita akan mengajukan pertanyaan dengan menggunakan session\_id yang berbeda.

```python
with_message_history.invoke(
    # Meminta terjemahan jawaban sebelumnya ke dalam bahasa Korea.
    {"ability": "math", "input": "Tolong terjemahkan jawaban sebelumnya ke dalam bahasa Korea."},
    # Menetapkan session ID menjadi "redis456" sebagai nilai konfigurasi.
    config={"configurable": {"session_id": "redis456"}},
)
```

{% code overflow="wrap" %}
```
content='Translate the previous answer into English.' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 7, 'prompt_tokens': 52, 'total_tokens': 59}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None} id='run-69c3e6a1-4cbc-4e7f-bf13-8285cb9fc617-0' usage_metadata={'input_tokens': 52, 'output_tokens': 7, 'total_tokens': 59}
```
{% endcode %}

Yang terakhir ini tidak memiliki riwayat percakapan sebelumnya, jadi Anda tidak akan mendapatkan jawaban yang tepat.
