」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 使用 Java + Quarkus + Langchain 建立可靠的 AI 代理程式 - 部分 AI 即服務

使用 Java + Quarkus + Langchain 建立可靠的 AI 代理程式 - 部分 AI 即服務

發佈於2024-11-08
瀏覽:940

Autores

@herbertbeckman - LinkedIn
@rndtavares - LinkedIn

Partes do artigo

  1. Agente de IA confiável em prod com Java Quarkus Langchain4j - Parte 1 - AI as Service (este artigo)

  2. Agente de IA confiável em prod com Java Quarkus Langchain4j - Parte 2 - Memória (em breve)

  3. Agente de IA confiável em prod com Java Quarkus Langchain4j - Parte 3 - RAG (em breve)

  4. Agente de IA confiável em prod com Java Quarkus Langchain4j - Parte 4 - Guardrails (em breve)

Introdução

Sempre que temos um "boom" de uma tecnologia emergente, as empresas ficam ansiosas por aplicá-las e colher os resultados tão esperados do ponto de vista do negócio. É a corrida pela inovação e a disputa pelas vantagens do pioneirismo. No meio dessa corrida, muitas das vezes, as empresas, que antes estavam ansiosas, acabam desistindo por uma série de fatores, sendo um dos principais a confiabilidade de um sistema de forma geral. A inteligencia artificial (IA) está neste momento em uma das suas maiores provas de resistência e nosso trabalho como desenvolvedores de softwares é demostrar as empresas que sim, é possível realizar uma série de tarefas e processos com o uso consciente e correto da IA. Neste artigo iremos demonstrar, em 3 partes, quais são as funcionalidades e processos que devemos ter em um agente de IA confiável em produção para uma empresa ter os tão esperados resultados, bem como implementarmos juntos alguns conceitos utilizados no mercado. Iremos também detalhar os pontos de atenção desta solução e pedimos para que você, dev, realize o máximo de testes e nos dê o maior número de feedbacks possíveis para que, juntos, possamos melhorar ainda mais esse entendimento.

Funcionalidades Implementadas

  • Chat
  • Tools
  • Chat Memory
  • Retrieval-Augmented Generation (RAG)
  • Guardrails

Conceitos e definições

Assistente vs Copiloto vs Agente

Uma das primeiras dúvidas que se pode ter é no que um agente se diferencia dos demais casos de uso da IA. O Agente tem funcionalidades mais ligadas pra automação, enquantos os outros tem suas atividades voltadas à finalidade de assistentcia e otimização do tempo. Abaixo detalho melhor cada um dos casos de uso.

Assistentes

Os assistentes conseguem nos auxiliar e economizar um bom tempo verificando informação e sendo uma boa fonte de troca de conhecimento. Eles falam SOBRE os assuntos mais variados e podem nos ser úteis quando precisamos de uma linha de raciocínio claro para analisar as premisas de uma argumentação. Claro, eles tem bem mais poderes que isso, mas quero que você foque no que um assistente faz: ele conversa com você e somente isso. Ele pode falar sobre, sumarizar, detalhar, etc. Como exemplos temos: ChatGPT, Claude AI e Gemini.

Copilotos

Já os copilotos são um pouco mais poderosos que os assistentes. Eles conseguem realmente fazer algo, uma ação mais concreta como alterar um texto e ou sugerir modificações em tempo real, bem como dar dicas durante uma modificação e/ou evento acontecendo dentro de um contexto. Porém, como dito antes, ele depende do contexto pra fazer isso e nem sempre ele tem todas as informações necessárias para realizar um boa sugestão, ele também depende de sua autorização expressa, criando uma dependência direta com o usuário. Exemplos bons são: Github Copilot, Codium e Microsoft Copilot.

Agentes

Os agentes tem como objetivo principal realizar tarefas com objetivos claros. Tem o seu foco na automatização, ou seja, eles realmente fazem concreto e de forma autônoma. Tudo isso só se faz possível através das ferramentas que disponibilizamos a eles. O Agente não é o LLM em si, mas sim a sua aplicação que coordena esse LLM. Entenda o LLM como o cérebro do sistema, que toma as decisões, e a sua aplicação como os membros do corpo desse cérebro. Do que adianta eu pensar em pegar um copo de água se não consigo alcançá-lo com a minha mão? O seu agente proporciona ao LLM o poder de fazer algo de forma segura, auditável e, principalmente, confiável.

Partindo pra ação

Nesta primeira parte do artigo iremos implementar o AIService no projeto, que nada mais é do que a camada de interface com o nosso provedor de IA. Nesse projeto utilizamos o LLM da OpenAI, mas vc pode adicionar o seu provedor favorito e ajustar as dependências com base nele.

Agora que temos os conceitos bem definidos e já sabemos o que iremos fazer aqui, vamos pra codificação!

Criando o projeto

Crie um projeto quarkus, escolhendo o seu gerenciador de dependências e as extensões em Quarkus - Start coding.

Dependencias do projeto

Iremos utilizar o maven como gerenciador de dependências do projeto. A seguir as dependências iniciais que adicionamos.

Mavem


  io.quarkus
  quarkus-websockets-next



  io.quarkiverse.langchain4j
  quarkus-langchain4j-core
  0.20.3



  io.quarkiverse.langchain4j
  quarkus-langchain4j-openai
  0.20.3

Configuração do projeto

Adicione no arquivo src/main/resources/application.properties as seguintes propriedades:

quarkus.tls.trust-all=true
quarkus.langchain4j.timeout=60s
quarkus.langchain4j.openai.api-key=YOUR_OPENAI_API_KEY_HERE

Substitua YOUR_OPENAPI_KEY_HERE pela chave (apiKey) que você cadastrou na Plataforma da OpenAI.

DICA: crie uma variável de ambiente na sua IDE e depois modifique a property quarkus.langchain4j.openai.api-key para:

quarkus.langchain4j.openai.api-key=${OPEN_API_KEY:NAO_ENCONTREI_A_VAR}

Criando o nosso AIService

Primeiramente precisamos criar o nosso AIService que será a classe responsável por dar uma "personalidade" ao nosso agente. Para isso, no diretório src/main/java/, criaremos a classe de nome Agent com o seguinte código:

package ;

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

@ApplicationScoped
@RegisterAiService
public interface Agent {

    @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(@UserMessage String message);
}

Como podem perceper pelo nosso SystemPrompt (@SystemMessage), criamos um agente especializado em futebol.

Criando o nosso chat

Agora que criamos o nosso agente, precisamos criar a classe que cuidará do nosso chat com ele. Para isso, no diretório src/main/java/, criaremos a classe de nome AgentWSEndpoint com o seguinte código:

package ;

import io.quarkus.websockets.next.OnTextMessage;
import io.quarkus.websockets.next.WebSocket;

@WebSocket(path = "/ws")
public class BotWSEndpoint {

    private final Agent agent;

    BotWSEndpoint(Agent agent) {
        this.agent = agent;
    }

    @OnTextMessage
    String reply(String message) {
        return agent.chat(message);
    }

}

Agora você já consegue conversar com o seu agente, que no momento ainda é um assistente, através da dev ui do quarkus. Segue alguns prints pra você se orientar:

Agente de IA confiável em prod com Java   Quarkus   Langchain- Parte  AI as Service

Agente de IA confiável em prod com Java   Quarkus   Langchain- Parte  AI as Service

Agente de IA confiável em prod com Java   Quarkus   Langchain- Parte  AI as Service

Agente de IA confiável em prod com Java   Quarkus   Langchain- Parte  AI as Service

Adicionando as nossas ferramentas (Function Calling)

Agora vamos para o detalhe que faz toda a diferença entre um agente e um assistente. Vamos dar a possibilidade do nosso agente realizar tarefas e/ou processos, adicionando as ferramentas (function calling). Antes de codificarmos isso, temos um breve gráfico demonstrando como a chamada de uma ferramenta funciona de forma macro.

Agente de IA confiável em prod com Java   Quarkus   Langchain- Parte  AI as Service
Source: superface.ai

Agora que sabemos como uma chamada de ferramenta funciona, precisamos criar a classe com nossas ferramentas, você também pode criar várias classes diferentes para cada ferramenta. Neste exemplo iremos criar uma "ToolBox", ou seja, uma caixa de ferramentas, agrupando as ferramentas que o nosso agente pode utilizar. Segue o código:

package ;

import dev.langchain4j.agent.tool.Tool;
import jakarta.enterprise.context.ApplicationScoped;

import java.time.LocalDate;
import java.time.LocalTime;

@ApplicationScoped
public class AgentTools {

    @Tool
    LocalDate currentDate() {
        System.out.println("Called currentDate()");
        return LocalDate.now();
    }

    @Tool
    LocalTime currentTime() {
        System.out.println("Called currentTime()");
        return LocalTime.now();
    }

    @Tool("Calcula a soma de dois números")
    int add(int a, int b) {
        System.out.println("Called add with a="   a   ", b="   b);
        return a   b;
    }

    @Tool("Calcula a raiz quadrada de um número")
    double sqrt(int x) {
        System.out.println("Called sqrt with x="   x);
        return Math.sqrt(x);
    }
}

Logo em seguida, adicionamos no nosso agente o anotação informando pra ele quais ferramentas ele tem disponível para utilizar, através da anotação @ToolBox(AgentTools.class). Ficando da seguinte maneira:

package ;

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
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(@UserMessage String message);
}

Agora você pode perguntar ao seu agente que horas são, qual é a data de hoje, pedir pra ele somar dois números e calcular a raiz quadrada. Essas são as ferramentas que utilizamos aqui para ilustrar, mas você pode substituir isso por uma chamada HTTP, por uma função de hashing, por uma query SQL, etc. As possibilidades aqui são muitas.

Testando via Quarkus DEV UI

Segue o print de um dos testes realizados após adicionar as ferramentas:

Agente de IA confiável em prod com Java   Quarkus   Langchain- Parte  AI as Service

Agente de IA confiável em prod com Java   Quarkus   Langchain- Parte  AI as Service

Como pode ver, pra cada chamada de ferramenta teremos um log, evidenciando que o LLM realmente chamou o código que autorizamos ele a executar.

Próximos passos

Isso encerra o início da criação no nosso Agente. Em breve adicionaremos memória ao nosso Agente na parte 2, o RAG (Retrieval-Augmented Generation) na parte 3 e os Guardrails na parte 4 deste artigo. Espero que tenham gostado e até breve.

Mas você pode já acompanhar e ver TODO o código do artigo neste repositório do GitHub.

版本聲明 本文轉載於:https://dev.to/herbertbeckman/agente-de-ia-confiavel-em-prod-com-java-quarkus-langchain4j-parte-1-ai-as-service-4i14?1如有侵犯,請聯絡[email protected]刪除
最新教學 更多>
  • Java中如何使用觀察者模式實現自定義事件?
    Java中如何使用觀察者模式實現自定義事件?
    在Java 中創建自定義事件的自定義事件在許多編程場景中都是無關緊要的,使組件能夠基於特定的觸發器相互通信。本文旨在解決以下內容:問題語句我們如何在Java中實現自定義事件以促進基於特定事件的對象之間的交互,定義了管理訂閱者的類界面。 以下代碼片段演示瞭如何使用觀察者模式創建自定義事件: args...
    程式設計 發佈於2025-05-03
  • 如何在Java的全屏獨家模式下處理用戶輸入?
    如何在Java的全屏獨家模式下處理用戶輸入?
    Handling User Input in Full Screen Exclusive Mode in JavaIntroductionWhen running a Java application in full screen exclusive mode, the usual event ha...
    程式設計 發佈於2025-05-03
  • 我可以將加密從McRypt遷移到OpenSSL,並使用OpenSSL遷移MCRYPT加密數據?
    我可以將加密從McRypt遷移到OpenSSL,並使用OpenSSL遷移MCRYPT加密數據?
    將我的加密庫從mcrypt升級到openssl 問題:是否可以將我的加密庫從McRypt升級到OpenSSL?如果是這樣,如何? 答案:是的,可以將您的Encryption庫從McRypt升級到OpenSSL。 可以使用openssl。 附加說明: [openssl_decrypt()函數要求...
    程式設計 發佈於2025-05-03
  • MySQL中如何高效地根據兩個條件INSERT或UPDATE行?
    MySQL中如何高效地根據兩個條件INSERT或UPDATE行?
    在兩個條件下插入或更新或更新 solution:的答案在於mysql的插入中...在重複鍵更新語法上。如果不存在匹配行或更新現有行,則此功能強大的功能可以通過插入新行來進行有效的數據操作。如果違反了唯一的密鑰約束。 實現所需的行為,該表必須具有唯一的鍵定義(在這種情況下為'名稱'...
    程式設計 發佈於2025-05-03
  • 使用ROW_NUMBER()高效識別值變化行
    使用ROW_NUMBER()高效識別值變化行
    在一個表的上下文中,使用row_number 在值列反映一個隨著時間的變化狀態的上下文中選擇“ && && && && &&&華”的行選擇時,選擇值隨著時間的變化,在值更改時選擇有價值的分析任務。本文提出了一個使用Row_number函數來識別此類行的解決方案,考慮了兩個方案,即值可以增加或波動。...
    程式設計 發佈於2025-05-03
  • 如何在Java字符串中有效替換多個子字符串?
    如何在Java字符串中有效替換多個子字符串?
    在java 中有效地替換多個substring,需要在需要替換一個字符串中的多個substring的情況下,很容易求助於重複應用字符串的刺激力量。 However, this can be inefficient for large strings or when working with nu...
    程式設計 發佈於2025-05-03
  • Spark DataFrame添加常量列的妙招
    Spark DataFrame添加常量列的妙招
    在Spark Dataframe ,將常數列添加到Spark DataFrame,該列具有適用於所有行的任意值的Spark DataFrame,可以通過多種方式實現。使用文字值(SPARK 1.3)在嘗試提供直接值時,用於此問題時,旨在為此目的的column方法可能會導致錯誤。 df.withco...
    程式設計 發佈於2025-05-03
  • 如何在鼠標單擊時編程選擇DIV中的所有文本?
    如何在鼠標單擊時編程選擇DIV中的所有文本?
    在鼠標上選擇div文本單擊帶有文本內容,用戶如何使用單個鼠標單擊單擊div中的整個文本?這允許用戶輕鬆拖放所選的文本或直接複製它。 在單個鼠標上單擊的div元素中選擇文本,您可以使用以下Javascript函數: function selecttext(canduterid){ if(d...
    程式設計 發佈於2025-05-02
  • 如何有效地轉換PHP中的時區?
    如何有效地轉換PHP中的時區?
    在PHP 利用dateTime對象和functions DateTime對象及其相應的功能別名為時區轉換提供方便的方法。例如: //定義用戶的時區 date_default_timezone_set('歐洲/倫敦'); //創建DateTime對象 $ dateTime = ne...
    程式設計 發佈於2025-05-02
  • 在JavaScript中如何並發運行異步操作並正確處理錯誤?
    在JavaScript中如何並發運行異步操作並正確處理錯誤?
    同意操作execution 在執行asynchronous操作時,相關的代碼段落會遇到一個問題,當執行asynchronous操作:此實現在啟動下一個操作之前依次等待每個操作的完成。要啟用並發執行,需要進行修改的方法。 第一個解決方案試圖通過獲得每個操作的承諾來解決此問題,然後單獨等待它們: c...
    程式設計 發佈於2025-05-02
  • 人臉檢測失敗原因及解決方案:Error -215
    人臉檢測失敗原因及解決方案:Error -215
    錯誤處理:解決“ error:( - 215)!empty()in Function openCv in Function MultSiscale中的“檢測”中的錯誤:在功能檢測中。”當Face Cascade分類器(即面部檢測至關重要的組件)未正確加載時,通常會出現此錯誤。 要解決此問題,必...
    程式設計 發佈於2025-05-02
  • OS X中如何獲取活動應用列表?
    OS X中如何獲取活動應用列表?
    在OS X 答案:利用蘋果的Swift和Cocoa Frameworks,可以在OSX。 The resulting app object is an NSApplication instance that contains the necessary information, including...
    程式設計 發佈於2025-05-02
  • 如何從2D數組中提取元素?使用另一數組的索引
    如何從2D數組中提取元素?使用另一數組的索引
    Using NumPy Array as Indices for the 2nd Dimension of Another ArrayTo extract specific elements from a 2D array based on indices provided by a second ...
    程式設計 發佈於2025-05-02
  • 在細胞編輯後,如何維護自定義的JTable細胞渲染?
    在細胞編輯後,如何維護自定義的JTable細胞渲染?
    在JTable中維護jtable單元格渲染後,在JTable中,在JTable中實現自定義單元格渲染和編輯功能可以增強用戶體驗。但是,至關重要的是要確保即使在編輯操作後也保留所需的格式。 在設置用於格式化“價格”列的“價格”列,用戶遇到的數字格式丟失的“價格”列的“價格”之後,問題在設置自定義單元...
    程式設計 發佈於2025-05-02

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3