Nossa jornada pelo mundo inovador do LangChain revelou suas capacidades substanciais na transformação do gerenciamento de dados e da funcionalidade de aplicativos.
Por meio de discussões anteriores, nos aprofundamos em vários tópicos enquanto exploramos os intrincados recursos do LangChain. Neste artigo, desenvolveremos os conceitos abordados em "Capacitando Agentes Langchain com MinIO" à medida que expandimos a funcionalidade de um agente MinIO para encapsular habilidades adicionais e implantar o agente personalizado via LangServe.
Com base nesses insights, agora voltamos nosso foco para
Criação automática de endpoints de API: os recursos de automação do LangServe geram facilmente os endpoints de API necessários, simplificando os esforços de desenvolvimento e reduzindo significativamente o tempo de implantação.
Geração e validação de esquema: Com sua inferência de esquema inteligente, LangServe garante que as APIs ofereçam interfaces bem definidas, facilitando a integração e uma experiência de usuário perfeita.
Configuração personalizável de endpoints: LangServe oferece uma variedade de endpoints para atender às diversas necessidades de aplicativos, desde operações síncronas até atualizações em tempo real, proporcionando aos desenvolvedores uma flexibilidade incomparável.
Integração sem esforço: Talvez seu recurso mais atraente, a capacidade do LangServe de se integrar perfeitamente ao código LangChain existente, significa que os desenvolvedores podem aproveitar sua base de código e experiência atuais sem alterações significativas.
Iremos nos aprofundar no processo de integração do MinIO com LangChain nas etapas a seguir.
langchain-cli
.agent.py
.server.py
para rodar como uma API LangServe.A implantação de aplicativos LangChain com LangServe traz uma jornada de integração perfeita, preenchendo a lacuna entre funcionalidades complexas de IA e a exposição à API RESTful, capacitando os desenvolvedores a aproveitar todo o espectro de recursos LangChain de forma eficiente, estabelecendo um novo padrão para a implantação de aplicativos inteligentes no cenário digital acelerado de hoje. .
LangChain oferece um método simples e conveniente de criar aplicativos usando seu langchain-cli
pip
. Este pacote fornece uma interface que permite aos usuários criar facilmente novos aplicativos utilizando
Nota: Todos os arquivos necessários estão localizados no repositório “blog-assets” do MinIO no diretório denominado “minio-langserve-deployment ”.
Para criar um novo aplicativo LangChain podemos começar com os seguintes comandos para criar um ambiente virtual e instalar o pacote langchain-cli
:
mkdir minio-langserve-testing cd minio-Langserve-testing python -m venv .myenv source .myenv/bin/activate pip install langchain-cli
Para criar um novo aplicativo usando langchain-cli
podemos digitar langchain
em nosso terminal, o seguinte comando é escrito para criar um novo diretório de aplicativo chamado my-app
.
langchain app new my-app
O aplicativo langchain criado com os comandos acima faz todo o trabalho pesado, criando um ambiente consistente para desenvolvimento. A estrutura de um novo aplicativo LangChain pronto para uso é assim:
./my-app ├── Dockerfile ├── README.md ├── app │ ├── __init__.py │ └── server.py ⇐ (This is where we will import our agent into) ├── packages ⇐ (This directory is where we will write our agent) │ └── README.md └── pyproject.toml
Nas etapas a seguir, faremos alterações no aplicativo LangChain recém-criado ( my-app
), escrevendo um novo arquivo chamado packages/agent.py e fazendo alterações em app/server.py
.
Estes são os arquivos que discutiremos neste artigo:
my-app/packages/agent.py
my-app/app/server.py
Para ilustrar a implantação de um agente LangChain integrado ao MinIO com LangServe, começaremos salvando o código da cadeia do agente em agent.py
.
Primeiro, vamos inicializar um minio_client
que se conecta ao servidor público "play.min.io:443". Este arquivo eventualmente chamará agent_executor
do LangChain, permitindo-nos passá-lo para o wrapper add_route
do LangServe.
Nota: Lendo a publicação anterior "
Para começar, abra o arquivo agent.py usando um editor de texto:
sudo nano packages/agent.py
No início do arquivo importe os pacotes necessários, como os
, io
, minio
e ChatOpenAI
:
import os import io from minio import Minio from minio.error import S3Error from langchain_openai import ChatOpenAI os.environ["OPENAI_API_KEY"] = "<<Your API Key Here>>" # Initialize llm llm = ChatOpenAI(api_key=os.environ["OPENAI_API_KEY"]) # Initialize MinIO client minio_client = Minio('play.min.io:443', access_key='minioadmin', secret_key='minioadmin', secure=True)
Neste trecho de código, importamos os pacotes necessários e inicializamos o modelo de linguagem ChatOpenAI com a chave de API OpenAI armazenada na variável de ambiente OPENAI_API_KEY
. Também inicializamos o minio_client fornecendo os detalhes de conexão necessários ao servidor público "play.min.io".
A seguir, vamos definir o bucket MinIO e criá-lo se ele não existir:
# This variable will check if bucket exists bucket_name = "test" try: # Check if bucket exists if not minio_client.bucket_exists(bucket_name): # Create the bucket because it does not exist minio_client.make_bucket(bucket_name) print(f"Bucket '{bucket_name}' created successfully.") else: print(f"Bucket '{bucket_name}' already exists.") except S3Error as err: print(f"Error encountered: {err}")
Aqui, definimos bucket_name
como “test” e verificamos se ele já existe usando o método minio_client.bucket_exists()
. Se o bucket não existir, nós o criamos usando minio_client.make_bucket()
. Se o bucket já existir, imprimimos uma mensagem indicando isso. Também incluímos o tratamento de erros usando um bloco try-except para capturar e imprimir qualquer S3Error
que possa ocorrer durante o processo.
Com a configuração básica definida, podemos agora definir as funções da ferramenta MinIO e criar o executor do agente, que abordaremos nas próximas etapas.
Langchain e Langserve fornecem uma abordagem semelhante para encapsular lógica e funcionalidade, permitindo que sejam perfeitamente integrados à lógica do agente e da cadeia. Isso é conseguido através do uso do decorador @tool
com uma documentação detalhada dentro da função definida, que marca as funções como componentes reutilizáveis que podem ser utilizados e interpretados pelo agente de IA.
Vamos dar uma olhada mais de perto nos exemplos de código fornecidos:
from langchain.agents import tool @tool def upload_file_to_minio(bucket_name: str, object_name: str, data_bytes: bytes): """ Uploads a file to MinIO. Parameters: bucket_name (str): The name of the bucket. object_name (str): The name of the object to create in the bucket. data_bytes (bytes): The raw bytes of the file to upload. """ data_stream = io.BytesIO(data_bytes) minio_client.put_object(bucket_name, object_name, data_stream, length=len(data_bytes)) return f"File {object_name} uploaded successfully to bucket {bucket_name}."
A função upload_file_to_minio
é decorada com @tool
, indicando que é um componente reutilizável. Ele recebe os parâmetros necessários para fazer upload de um arquivo para um bucket MinIO, como o nome do bucket, o nome do objeto e os bytes brutos do arquivo. A função utiliza o minio_client
para realizar a operação de upload do arquivo e retorna uma mensagem de sucesso após a conclusão.
@tool def download_file_from_minio(file_info): """ Custom function to download a file from MinIO. Expects file_info dict with 'bucket_name', 'object_name', and 'save_path' keys. 'save_path' should be the local path where the file will be saved. """ bucket_name = file_info['bucket_name'] object_name = file_info['object_name'] save_path = file_info['save_path'] minio_client.get_object(bucket_name, object_name, save_path)
Da mesma forma, a função download_file_from_minio
também está marcada com @tool
. Ele espera um dicionário file_info
contendo as informações necessárias para baixar um arquivo de um bucket MinIO, como o nome do bucket, o nome do objeto e o caminho local onde o arquivo deve ser salvo. A função usa minio_client
para recuperar o objeto do bucket especificado e salvá-lo no caminho local designado.
@tool def list_objects_in_minio_bucket(file_info): """ Custom function to list objects in a MinIO bucket. Expects file_info dict with 'bucket_name' key. Returns a list of dictionaries containing 'ObjectKey' and 'Size' keys. """ bucket_name = file_info['bucket_name'] response = minio_client.list_objects(bucket_name) return [{'ObjectKey': obj.object_name, 'Size': obj.size} for obj in response.items]
A função list_objects_in_minio_bucket
, também decorada com @tool
é responsável por listar os objetos presentes em um bucket MinIO. Ele espera um dicionário file_info
com a chave bucket_name
. A função usa minio_client
para recuperar a lista de objetos no bucket especificado e retorna uma lista de dicionários contendo a chave e o tamanho do objeto para cada objeto.
Ao encapsular essas funcionalidades como ferramentas, Langchain e Langserve permitem que o agente de IA as incorpore perfeitamente em sua lógica e processo de tomada de decisão. O agente pode selecionar e executar de forma inteligente a ferramenta apropriada com base na tarefa em questão, aprimorando suas capacidades e permitindo interações mais complexas e dinâmicas com o sistema de armazenamento MinIO.
LangChain oferece uma infinidade de métodos para construção com lógica customizada, uma dessas abordagens é a de “RunnableLambda
que é uma construção fornecida por LangChain que permite que funções sejam tratadas como unidades executáveis dentro da lógica do agente de IA.
from langchain_core.runnables import RunnableLambda upload_file_runnable = RunnableLambda(upload_file_to_minio) download_file_runnable = RunnableLambda(download_file_from_minio) list_objects_runnable = RunnableLambda(list_objects_in_minio_bucket)
Ao envolver as funções da ferramenta com RunnableLambda, criamos instâncias executáveis ( upload_file_runnable
, download_file_runnable
e list_objects_runnable
) que podem ser invocadas pelo agente durante sua execução. Esses executáveis encapsulam as funções da ferramenta correspondentes e fornecem uma interface uniforme para o agente interagir com eles.
tools = [upload_file_to_minio, download_file_from_minio, list_objects_in_minio_bucket] llm_with_tools = llm.bind_tools(tools)
A lista de ferramentas contém as funções originais da ferramenta ( upload_file_to_minio
, download_file_from_minio
e list_objects_in_minio_bucket
), que servem como blocos de construção para os recursos do agente. A linha llm.bind_tools(tools)
vincula as ferramentas ao modelo de linguagem ( llm
), estabelecendo uma conexão entre as capacidades de raciocínio do modelo e as funcionalidades específicas fornecidas pelas ferramentas. O llm_with_tools
resultante representa o modelo de linguagem aprimorado com o conhecimento e a capacidade de empregar as ferramentas vinculadas.
O uso de RunnableLambda
e a ligação de ferramentas ao modelo de linguagem demonstram a flexibilidade e extensibilidade de LangChain e LangServe na criação de agentes de IA poderosos e personalizáveis. Ao combinar o poder do modelo de linguagem com as funcionalidades específicas encapsuladas nas ferramentas, o agente de IA ganha a capacidade de realizar tarefas complexas, como fazer upload de arquivos para o MinIO, baixar arquivos do MinIO e listar objetos em um bucket do MinIO.
Em seguida, mudamos nosso foco para o modelo de prompt que orienta o agente de IA na compreensão e resposta às entradas do usuário. Ele é definido usando o método ChatPromptTemplate.from_messages()
, que recebe uma lista de mensagens representadas como tuplas contendo a função e o conteúdo da mensagem.
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain.agents.format_scratchpad.openai_tools import format_to_openai_tool_messages from langchain.agents.output_parsers.openai_tools import OpenAIToolsAgentOutputParser from langchain_core.messages import AIMessage, HumanMessage prompt_template = ChatPromptTemplate.from_messages([ ("system", "You are a powerful assistant equipped with file management capabilities."), ("user", "{input}"), MessagesPlaceholder(variable_name="agent_scratchpad"), ])
O prompt consiste em três mensagens:
Uma mensagem de “sistema” que define o contexto para o agente de IA como um assistente poderoso com recursos de gerenciamento de arquivos.
Uma mensagem de "usuário" representando a entrada do usuário, usando o espaço reservado {input}
.
Um MessagesPlaceholder
chamado "agent_scratchpad" para armazenar as etapas intermediárias e o processo de pensamento do agente.
A função format_to_openai_tool_messages
formata o scratchpad do agente em um formato compatível com as ferramentas da OpenAI, enquanto a classe OpenAIToolsAgentOutputParser analisa a resposta do modelo em um formato estruturado interpretável pelo agente.
As classes AIMessage
e HumanMessage
representam as mensagens trocadas entre o agente e o usuário, fornecendo uma forma padronizada de lidar com a comunicação dentro da lógica do agente.
Ao definir o modelo de prompt, fornecemos ao agente de IA uma estrutura e contexto claros para compreender e responder às entradas do usuário, utilizando o espaço reservado "agent_scratchpad" para acompanhar suas etapas intermediárias e processo de pensamento enquanto resolve a tarefa.
Finalmente, para completar nosso agent.py
definimos nosso agente e criamos um AgentExecutor que pode ser importado e chamado de um script server.py
usando a função add_route
da biblioteca LangServe.
Instanciamos os componentes necessários e os encadeamos para criar uma única variável de agente.
agent = ( { "input": lambda x: x["input"], "agent_scratchpad": lambda x: format_to_openai_tool_messages(x["intermediate_steps"]), } | prompt_template | llm_with_tools | OpenAIToolsAgentOutputParser() )
O agente é definido usando uma combinação de dicionários e operações encadeadas. A chave de entrada extrai a entrada do usuário dos dados recebidos, enquanto a chave agent_scratchpad
formata as etapas intermediárias do processo de pensamento do agente usando a função format_to_openai_tool_messages
. O agente também incorpora o modelo de prompt ( prompt_template
), o modelo de linguagem com ferramentas ( llm_with_tools
) e o analisador de saída ( OpenAIToolsAgentOutputParser()
).
Para criar um AgentExecutor
, fornecemos a ele o agente definido, as ferramentas disponíveis e definimos verbose=True
para saída detalhada.
from langchain.agents import tool, AgentExecutor agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
O AgentExecutor
usa o agente e as ferramentas fornecidas para compreender a tarefa e selecionar a ferramenta apropriada com base na entrada do usuário. Em vez de ter prompts separados para cada ferramenta, o agente utiliza um único modelo de prompt que o orienta sobre como usar as ferramentas com base na entrada fornecida. O agente seleciona dinamicamente a ferramenta apropriada durante o processo de execução.
Configurar nosso aplicativo integrando-o ao LangServe fornece um caminho simplificado para implantar e gerenciar nossos aplicativos LangChain como APIs. FastAPI é escolhido por seu desempenho e facilidade de uso, suportando operações assíncronas e gerando automaticamente documentação de API.
O
Para demonstrações mais aprofundadas/de casos de uso, você pode explorar visitando o
langchain-ai/langserve Repositório GitHub sob odiretório de exemplos .
from fastapi import FastAPI app = FastAPI( title="MinIO Agent API", version="1.0", description="A conversational agent facilitating data storage and retrieval with MinIO", )
Para definir cabeçalhos CORS, podemos adicionar as seguintes linhas para aumentar nossa segurança:
from fastapi.middleware.cors import CORSMiddleware # Set all CORS enabled origins app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], expose_headers=["*"], )
Agora que terminamos com packages/agent.py
podemos importá-lo e usar a função add_route
da biblioteca LangServe em nosso script app/server.py
.
from packages.agent import agent_executor from langserve import add_routes add_routes( app, agent_executor.with_types(input_type=Input, output_type=Output).with_config( {"run_name": "agent"} ), path=”/invoke” )
Chamando add_route(app, agent_executor(…), path="/invoke")
, adicionamos uma rota ao nosso aplicativo de servidor ( app
) que mapeia o caminho /invoke
para a função agent_executor()
. Isso permite que o executor do agente seja chamado quando uma solicitação é feita ao endpoint /invoke
.
Com esta configuração, o servidor pode lidar com solicitações recebidas, passá-las ao executor do agente e retornar a resposta do agente ao cliente. O executor do agente utiliza o agente definido, que incorpora o modelo de prompt, o modelo de linguagem com ferramentas e o analisador de saída, para processar a entrada do usuário e gerar uma resposta apropriada com base nas ferramentas disponíveis.
Para iniciar o aplicativo LangServe, empregamos Uvicorn como servidor ASGI, preparando o terreno para a execução de nosso aplicativo. Este trecho de código é fundamental porque ativa o servidor, especificando o host universal e a porta designada para os pontos de acesso do aplicativo.
if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000)
Ao incorporar este bloco na entrada principal do aplicativo, garantimos que o Uvicorn assuma o comando quando o script for executado diretamente, ativando assim nosso aplicativo FastAPI em um host e porta predefinidos. Essa abordagem não apenas simplifica o processo de implantação, mas também marca uma entrada clara para a execução do aplicativo em um ambiente de desenvolvimento ou produção.
O código acima foi demonstrado em uma abordagem modular que inclui o uso da biblioteca “langchain-cli”, a criação de um novo aplicativo langchain e o salvamento da lógica da cadeia em agent.py
enquanto a implementação FastAPI e LangServe é salva em server.py
.
Sendo esta a nossa etapa final, salvaremos o código do nosso aplicativo em server.py
para o propósito demonstrativo de construção de nosso aplicativo.
A maneira mais simples de executar nosso serviço é com:
python server.py
Este comando executará o aplicativo, retornando quaisquer logs ou mensagens de erro que ainda precisam ser depurados.
Na saída do python, os logs do LangServe identificam /invoke/playground
como o endpoint do aplicativo. Agora podemos visitar o playground WebUI, bem como a documentação automatizada de nossa API que está disponível visitando o caminho /docs
de nossa API; dando-nos uma abordagem simplificada para testar e configurar, incluindo o botão Experimente para cada um dos recursos de nossos aplicativos, bem como solicitações cURL predefinidas que podemos executar a partir da WebUI.
Consequentemente, nosso agente LangChain integrado ao MinIO agora está habilmente transformado em uma API implantável, pronta para ser desenvolvida e estendida para usuários com funcionalidades que vão desde processamento em lote até interações em tempo real.
Com o aplicativo LangServe instalado e funcionando, podemos usá-lo fora de nosso server.py
, direcionando nosso endpoint e agrupando-o no módulo RemoteRunnable
do Langserve:
from langserve import RemoteRunnable remote_runnable = RemoteRunnable("http://localhost:8000/<path>/")
Adicionar
LangChain possui uma vasta gama de módulos em suas bibliotecas, apresentando um kit de ferramentas diversificado projetado para capacitar os desenvolvedores na construção de aplicativos sofisticados baseados em IA. Desde construções de cadeias complexas até a integração perfeita com vários modelos de IA, a arquitetura modular do LangChain facilita uma ampla gama de funcionalidades, permitindo a criação de soluções altamente personalizáveis e avançadas no domínio da IA e do aprendizado de máquina.
LangServe não apenas desmistifica, mas simplifica significativamente o processo de implantação de aplicativos LangChain. Ao preencher a lacuna entre o desenvolvimento e a implantação, garante que aplicações inovadoras que aproveitam o MinIO e o LangChain possam passar rapidamente do conceito à realidade, prontas para serem integradas ao ecossistema mais amplo e aprimorarem as experiências do usuário.
Através do desenvolvimento abordado em nossas explorações, vimos a integração perfeita do MinIO com
Na MinIO, somos energizados pela criatividade e pelo potencial da comunidade de desenvolvedores durante esta era rica em tecnologia. Não há melhor momento para colaboração e troca de conhecimento. Estamos ansiosos para nos conectar com você! Junte-se a nós em nosso