Rumah > Java > javaTutorial > teks badan

Ejen AI yang boleh dipercayai dalam produk dengan Java Quarkus Langchain - Bahagian Memori

DDD
Lepaskan: 2024-11-18 01:26:02
asal
648 orang telah melayarinya

Pengarang

@herbertbeckman - LinkedIn
@rndtavares - LinkedIn

Bahagian artikel

  1. Ejen AI yang boleh dipercayai dalam produk dengan Java Quarkus Langchain4j - Bahagian 1 - AI sebagai Perkhidmatan

  2. Ejen AI yang boleh dipercayai di Java Quarkus Langchain4j prod - Bahagian 2 - Memori (artikel ini)

  3. Ejen AI yang boleh dipercayai dalam produk dengan Java Quarkus Langchain4j - Bahagian 3 - RAG (akan datang)

  4. Ejen AI yang boleh dipercayai dalam produk dengan Java Quarkus Langchain4j - Bahagian 4 - Pengawal (akan datang)

pengenalan

Apabila kita mencipta ejen, kita mesti ingat bahawa LLM tidak menyimpan apa-apa jenis maklumat, iaitu, ia tidak mempunyai kewarganegaraan. Untuk ejen kami mempunyai keupayaan untuk "mengingat" maklumat, kami mesti melaksanakan pengurusan ingatan. Quarkus sudah menyediakan memori lalai yang dikonfigurasikan kepada kami, namun ia boleh menghapuskan ejen anda secara literal dengan meletupkan memori RAM yang disediakan untuknya, seperti yang diterangkan dalam dokumentasi Quarkus ini, jika penjagaan yang sewajarnya tidak diambil. Untuk tidak lagi menghadapi masalah ini dan juga boleh menggunakan ejen kami dalam persekitaran berskala, kami memerlukan ChatMemoryStore.

Konsep

Kami menggunakan sembang untuk berinteraksi dengan ejen kami dan terdapat konsep penting yang mesti kami ketahui supaya interaksi kami dengannya dapat berlaku dengan cara yang terbaik dan tidak menyebabkan pepijat dalam pengeluaran. Mula-mula kita perlu tahu jenis-jenis mesej yang kita gunakan semasa berinteraksi dengannya, iaitu:

  • Mesej Pengguna: Mesej atau permintaan yang dihantar oleh pelanggan akhir. Apabila kami menghantar mesej dalam Quarkus DevUI, kami sentiasa menghantar Mesej Pengguna. Tambahan pula, ia juga digunakan dalam hasil panggilan alat yang kita lihat sebelum ini.

  • Mesej AI (AiMessage): Mesej respons daripada model. Setiap kali LLM membalas ejen kami, dia akan menerima mesej seperti ini. Mesej jenis ini menggantikan kandungannya antara respons teks dan permintaan pelaksanaan alat.

  • Mesej Sistem: Mesej ini hanya boleh ditakrifkan sekali dan hanya pada masa pembangunan.

Sekarang anda tahu 3 jenis mesej yang kami ada, mari jelaskan cara mesej itu harus berkelakuan dengan beberapa grafik. Semua grafik diambil daripada pembentangan Java meets AI: Bina Apl Dikuasakan LLM dengan LangChain4j oleh Deandrea, Andrianakis, Escoffier, saya sangat mengesyorkan video tersebut.

Graf pertama menunjukkan penggunaan 3 jenis mesej. UserMessage dalam warna biru, SystemMessage dalam warna merah dan AiMessage dalam warna hijau.

Agente de IA confiável em prod com Java   Quarkus   Langchain- Parte  Memória

Graf kedua ini menunjukkan cara "memori" harus diurus. Perincian yang menarik ialah kita mesti mengekalkan susunan tertentu dalam mesej dan sesetengah premis mesti dihormati.

Agente de IA confiável em prod com Java   Quarkus   Langchain- Parte  Memória

  • Hanya perlu ada 1 mesej jenis SystemMessage;
  • Selepas SystemMessage, mesej hendaklah sentiasa bertukar antara UserMessage dan AiMessage, dalam susunan itu. Jika kami mempunyai AiMessage selepas AiMessage, kami akan membuang pengecualian. Perkara yang sama berlaku untuk UserMessages berturut-turut.

Satu lagi butiran penting yang perlu anda perhatikan ialah saiz ChatMemory anda. Lebih besar ingatan interaksi anda, lebih tinggi kos token, kerana LLM perlu memproses lebih banyak teks untuk memberikan respons. Kemudian wujudkan tetingkap memori yang paling sesuai dengan kes penggunaan anda. Satu petua ialah menyemak purata bilangan mesej daripada pelanggan anda untuk mendapatkan idea tentang saiz interaksi. Kami akan menunjukkan pelaksanaan melalui MessageWindowChatMemory, kelas yang mengkhusus dalam mengurus ini untuk kami di Langchain4j.

Sekarang kita tahu semua konsep dan premis ini, mari kita mengotorkan tangan kita!

Mengkonfigurasi ChatMemoryStore kami

Di sini kita akan menggunakan MongoDB sebagai ChatMemoryStore. Kami menggunakan dokumen MongoDB dan memuat naik contoh ke Docker. Jangan ragu untuk mengkonfigurasinya mengikut kehendak anda.

Menambah sambungan kami ke MongoDB

Mari kita mulakan dengan menambah kebergantungan yang diperlukan untuk menyambung ke MongoDB menggunakan Quarkus.

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-mongodb-panache</artifactId>
</dependency>
Salin selepas log masuk
Salin selepas log masuk

Selepas kebergantungan, kami perlu menambah tetapan sambungan dalam src/main/resources/application.properties kami.

quarkus.mongodb.connection-string=mongodb://${MONGODB_USER}:${MONGODB_PASSWORD}@localhost:27017
quarkus.mongodb.database=chat_memory
Salin selepas log masuk
Salin selepas log masuk

Kami masih tidak akan dapat menguji sambungan kami ke pangkalan, kerana kami perlu mencipta entiti dan repositori kami terlebih dahulu.

Mencipta entiti kami dan repositori kami

Sekarang mari kita laksanakan entiti Interaksi kami. Entiti ini akan membuat senarai mesej kami. Setiap kali pelanggan baharu berhubung, Interaksi baharu akan dijana. Jika kami perlu menggunakan semula Interaksi ini, kami hanya masukkan pengecam Interaksi yang sama.

package <seupacote>;

import dev.langchain4j.data.message.ChatMessage;
import io.quarkus.mongodb.panache.common.MongoEntity;
import org.bson.codecs.pojo.annotations.BsonId;

import java.util.List;
import java.util.Objects;

@MongoEntity(collection = "interactions")
public class InteractionEntity {

    @BsonId
    private String interactionId;
    private List<ChatMessage> messages;

    public InteractionEntity() {
    }

    public InteractionEntity(String interactionId, List<ChatMessage> messages) {
        this.interactionId = interactionId;
        this.messages = messages;
    }

    public String getInteractionId() {
        return interactionId;
    }

    public void setInteractionId(String interactionId) {
        this.interactionId = interactionId;
    }

    public List<ChatMessage> getMessages() {
        return messages;
    }

    public void setMessages(List<ChatMessage> messages) {
        this.messages = messages;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        InteractionEntity that = (InteractionEntity) o;
        return Objects.equals(interactionId, that.interactionId);
    }

    @Override
    public int hashCode() {
        return Objects.hash(interactionId, messages);
    }
}
Salin selepas log masuk
Salin selepas log masuk

Kini kami boleh mencipta repositori kami.

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-mongodb-panache</artifactId>
</dependency>
Salin selepas log masuk
Salin selepas log masuk

Kini kami akan melaksanakan beberapa komponen langchain4j, ChatMemoryStore dan ChatMemoryProvider. ChatMemoryProvider ialah kelas yang akan kami gunakan dalam Ejen kami. Di dalamnya kami akan menambah ChatMemoryStore yang akan menggunakan repositori kami untuk menyimpan mesej dalam MongoDB kami. Ikuti ChatMemoryStore:

quarkus.mongodb.connection-string=mongodb://${MONGODB_USER}:${MONGODB_PASSWORD}@localhost:27017
quarkus.mongodb.database=chat_memory
Salin selepas log masuk
Salin selepas log masuk

Pembekal ChatMemory akan kelihatan seperti ini:

package <seupacote>;

import dev.langchain4j.data.message.ChatMessage;
import io.quarkus.mongodb.panache.common.MongoEntity;
import org.bson.codecs.pojo.annotations.BsonId;

import java.util.List;
import java.util.Objects;

@MongoEntity(collection = "interactions")
public class InteractionEntity {

    @BsonId
    private String interactionId;
    private List<ChatMessage> messages;

    public InteractionEntity() {
    }

    public InteractionEntity(String interactionId, List<ChatMessage> messages) {
        this.interactionId = interactionId;
        this.messages = messages;
    }

    public String getInteractionId() {
        return interactionId;
    }

    public void setInteractionId(String interactionId) {
        this.interactionId = interactionId;
    }

    public List<ChatMessage> getMessages() {
        return messages;
    }

    public void setMessages(List<ChatMessage> messages) {
        this.messages = messages;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        InteractionEntity that = (InteractionEntity) o;
        return Objects.equals(interactionId, that.interactionId);
    }

    @Override
    public int hashCode() {
        return Objects.hash(interactionId, messages);
    }
}
Salin selepas log masuk
Salin selepas log masuk

Perhatikan MessageWindowChatMemory. Di sinilah kami melaksanakan tetingkap mesej yang kami nyatakan pada permulaan artikel. Dalam kaedah maxMessages(), anda mesti menukarnya kepada nombor yang anda fikir terbaik untuk senario anda. Perkara yang saya syorkan ialah menggunakan bilangan terbesar mesej yang pernah wujud dalam senario anda, atau menggunakan purata. Di sini kita mentakrifkan nombor arbitrari 100.

Mari kita tukar ejen kami untuk menggunakan ChatMemoryProvider baharu kami dan tambah MemoryId. Ia sepatutnya kelihatan seperti ini:

package <seupacote>;

import dev.langchain4j.data.message.ChatMessage;
import io.quarkus.mongodb.panache.PanacheMongoRepositoryBase;

import java.util.List;

public class InteractionRepository implements PanacheMongoRepositoryBase<InteractionEntity, String> {

    public InteractionEntity findByInteractionId(String interactionId) {
        return findById(interactionId);
    }

    public void updateMessages(String interactionId, List<ChatMessage> messages) {
        persistOrUpdate(new InteractionEntity(interactionId, messages));
    }

    public void deleteMessages(String interactionId) {
        deleteById(interactionId);
    }

}
Salin selepas log masuk

Ini sepatutnya memecahkan AgentWSEndpoint kami. Mari kita ubahnya supaya ia menerima pengecam Interaksi dan kita boleh menggunakannya sebagai MemoryId kami:

package <seupacote>;

import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.store.memory.chat.ChatMemoryStore;

import java.util.List;
import java.util.Objects;

public class MongoDBChatMemoryStore implements ChatMemoryStore {

    private InteractionRepository interactionRepository = new InteractionRepository();

    @Override
    public List<ChatMessage> getMessages(Object memoryId) {
        var interactionEntity = interactionRepository.findByInteractionId(memoryId.toString());
        return Objects.isNull(interactionEntity) ? List.of() : interactionEntity.getMessages();
    }

    @Override
    public void updateMessages(Object memoryId, List<ChatMessage> messages) {
        interactionRepository.updateMessages(memoryId.toString(), messages);
    }

    @Override
    public void deleteMessages(Object memoryId) {
        interactionRepository.deleteMessages(memoryId.toString());
    }
}

Salin selepas log masuk

Kami kini boleh menguji ejen kami semula. Untuk melakukan ini, kami hanya menyambung ke soket web dengan menghantar UUID bila-bila masa yang kami mahu. Anda boleh menjana UUID baharu di sini atau gunakan perintah uuidgen dalam Linux.

Apabila kami menjalankan ujian anda tidak akan menerima sebarang maklum balas daripada ejen. Ini berlaku kerana ejen menghadapi masalah menulis mesej kami ke MongoDB dan ia akan menunjukkan ini kepada anda melalui pengecualian. Supaya kita boleh menyemak pengecualian ini berlaku, kita mesti menambah harta baharu pada src/main/resources/application.properties kita, iaitu tahap log yang ingin kita lihat dalam Quarkus. Kemudian, tambahkan baris berikut di dalamnya:

package <seupacote>;

import dev.langchain4j.memory.chat.ChatMemoryProvider;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;

import java.util.function.Supplier;

public class MongoDBChatMemoryProvider implements Supplier<ChatMemoryProvider> {

    private MongoDBChatMemoryStore mongoDBChatMemoryStore = new MongoDBChatMemoryStore();

    @Override
    public ChatMemoryProvider get() {
        return memoryId -> MessageWindowChatMemory.builder()
                .maxMessages(100)
                .id(memoryId)
                .chatMemoryStore(mongoDBChatMemoryStore)
                .build();
    }
}
Salin selepas log masuk

Sekarang uji ejen. Pengecualian mestilah ini:

package <seupacote>;

import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import io.quarkiverse.langchain4j.RegisterAiService;
import io.quarkiverse.langchain4j.ToolBox;
import jakarta.enterprise.context.ApplicationScoped;

@ApplicationScoped
@RegisterAiService(
        chatMemoryProviderSupplier = MongoDBChatMemoryProvider.class
)
public interface Agent {

    @ToolBox(AgentTools.class)
    @SystemMessage("""
            Você é um agente especializado em futebol brasileiro, seu nome é FutAgentBR
            Você sabe responder sobre os principais títulos dos principais times brasileiros e da seleção brasileira
            Sua resposta precisa ser educada, você pode deve responder em Português brasileiro e de forma relevante a pergunta feita

            Quando você não souber a resposta, responda que você não sabe responder nesse momento mas saberá em futuras versões.
            """)
    String chat(@MemoryId String interactionId, @UserMessage String message);
}
Salin selepas log masuk

Pengecualian ini berlaku kerana MongoDB tidak dapat mengendalikan antara muka ChatMessage Langchain4j, jadi kami mesti melaksanakan codec untuk menjadikannya mungkin. Quarkus sendiri sudah menawarkan codec kepada kami, tetapi kami perlu menjelaskan dengan jelas bahawa kami mahu menggunakannya. Kami kemudiannya akan membuat kelas ChatMessageCodec dan ChatMessageCodecProvider seperti berikut:

package <seupacote>;

import io.quarkus.websockets.next.OnTextMessage;
import io.quarkus.websockets.next.WebSocket;
import io.quarkus.websockets.next.WebSocketConnection;
import jakarta.inject.Inject;

import java.util.Objects;
import java.util.UUID;

@WebSocket(path = "/ws/{interactionId}")
public class AgentWSEndpoint {

    private final Agent agent;

    private final WebSocketConnection connection;

    @Inject
    AgentWSEndpoint(Agent agent, WebSocketConnection connection) {
        this.agent = agent;
        this.connection = connection;
    }

    @OnTextMessage
    String reply(String message) {
        var interactionId = connection.pathParam("interactionId");
        return agent.chat(
                Objects.isNull(interactionId) || interactionId.isBlank()
                        ? UUID.randomUUID().toString()
                        : interactionId,
                message
        );
    }

}
Salin selepas log masuk
quarkus.log.level=DEBUG
Salin selepas log masuk

Sedia! Kini kami boleh menguji dan mengesahkan mesej dalam MongoDB kami. Apabila membuat pertanyaan, kami boleh menyemak 3 jenis mesej dalam tatasusunan mesej dokumen.

Agente de IA confiável em prod com Java   Quarkus   Langchain- Parte  Memória

Itu menamatkan bahagian kedua siri kami. Kami harap anda menikmatinya dan jumpa anda di bahagian 3.

Atas ialah kandungan terperinci Ejen AI yang boleh dipercayai dalam produk dengan Java Quarkus Langchain - Bahagian Memori. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:dev.to
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan