Acerca de este codelab
1. Descripción general
En diferentes industrias, la búsqueda contextual es una funcionalidad fundamental que forma el núcleo de sus aplicaciones. La generación de aumento de recuperación ha sido un impulsor clave de esta evolución tecnológica crucial desde hace bastante tiempo con sus mecanismos de recuperación potenciados por IA generativa. Los modelos generativos, con sus grandes ventanas de contexto y su impresionante calidad de salida, están transformando la IA. La RAG proporciona una forma sistemática de incorporar contexto en las aplicaciones y los agentes de IA, basándolos en bases de datos estructuradas o información de varios medios. Estos datos contextuales son fundamentales para la claridad de la verdad y la precisión de los resultados, pero ¿qué tan precisos son esos resultados? ¿Tu empresa depende en gran medida de la precisión de estas coincidencias contextuales y la relevancia? Entonces, este proyecto te encantará.
Ahora imagina si pudiéramos aprovechar la potencia de los modelos generativos y crear agentes interactivos capaces de tomar decisiones autónomas respaldadas por información fundamental para el contexto y basada en la verdad. Eso es lo que crearemos hoy. Vamos a compilar una app de agente de IA de extremo a extremo con el kit de desarrollo de agentes potenciado por la RAG avanzada en AlloyDB para una aplicación de análisis de patentes.
El Agente de análisis de patentes ayuda al usuario a encontrar patentes contextualmente relevantes para su texto de búsqueda y, cuando se le solicita, proporciona una explicación clara y concisa, y detalles adicionales si es necesario, para una patente seleccionada. ¿Quieres ver cómo se hace? ¡Comencemos!
Objetivo
El objetivo es simple. Permite que un usuario busque patentes en función de una descripción textual y, luego, obtenga una explicación detallada de una patente específica de los resultados de la búsqueda. Todo esto con un agente de IA compilado con el ADK de Java, AlloyDB, la Búsqueda de vectores (con índices avanzados), Gemini y toda la aplicación implementada sin servidor en Cloud Run.
Qué compilarás
Como parte de este lab, aprenderás a hacer lo siguiente:
- Crea una instancia de AlloyDB y carga datos del conjunto de datos públicos de Patents
- Implementa la Búsqueda de vectores avanzada en AlloyDB con las funciones de evaluación de ScaNN y Recall
- Crea un agente con el ADK de Java
- Implementa la lógica del servidor de la base de datos en Cloud Functions sin servidores de Java
- Implementa y prueba el agente en Cloud Run
En el siguiente diagrama, se representa el flujo de datos y los pasos involucrados en la implementación.
High level diagram representing the flow of the Patent Search Agent with AlloyDB & ADK
Requisitos
2. Antes de comenzar
Crea un proyecto
- En la página del selector de proyectos de la consola de Google Cloud, selecciona o crea un proyecto de Google Cloud.
- Asegúrate de que la facturación esté habilitada para tu proyecto de Cloud. Obtén información para verificar si la facturación está habilitada en un proyecto .
- Usarás Cloud Shell, un entorno de línea de comandos que se ejecuta en Google Cloud. Haz clic en Activar Cloud Shell en la parte superior de la consola de Google Cloud.
- Una vez que te conectes a Cloud Shell, verifica que ya te hayas autenticado y que el proyecto esté configurado con tu ID con el siguiente comando:
gcloud auth list
- En Cloud Shell, ejecuta el siguiente comando para confirmar que el comando gcloud conoce tu proyecto.
gcloud config list project
- Si tu proyecto no está configurado, usa el siguiente comando para hacerlo:
gcloud config set project <YOUR_PROJECT_ID>
- Habilita las API necesarias. Puedes usar un comando gcloud en la terminal de Cloud Shell:
gcloud services enable alloydb.googleapis.com compute.googleapis.com cloudresourcemanager.googleapis.com servicenetworking.googleapis.com run.googleapis.com cloudbuild.googleapis.com cloudfunctions.googleapis.com aiplatform.googleapis.com
La alternativa al comando gcloud es buscar cada producto en la consola o usar este vínculo.
Consulta la documentación para ver los comandos y el uso de gcloud.
3. Configuración de la base de datos
En este lab, usaremos AlloyDB como la base de datos para los datos de patentes. Usa clústeres para contener todos los recursos, como bases de datos y registros. Cada clúster tiene una instancia principal que proporciona un punto de acceso a los datos. Las tablas contendrán los datos reales.
Crear un clúster, una instancia y una tabla de AlloyDB en los que se cargará el conjunto de datos de patentes
Crea un clúster y una instancia
- Navega a la página de AlloyDB en Cloud Console. Una forma sencilla de encontrar la mayoría de las páginas en la consola de Cloud es buscarlas con la barra de búsqueda de la consola.
- Selecciona CREATE CLUSTER en esa página:
- Verás una pantalla como la siguiente. Crea un clúster y una instancia con los siguientes valores (asegúrate de que los valores coincidan en caso de que estés clonando el código de la aplicación desde el repositorio):
- cluster id: "
vector-cluster
" - contrasena: "
alloydb
" - PostgreSQL 15 o la versión más reciente recomendada
- Región: "
us-central1
" - Redes: "
default
"
- Cuando selecciones la red predeterminada, verás una pantalla como la que se muestra a continuación.
Selecciona CONFIGURAR CONEXIÓN.
- Allí, selecciona "Usar un rango de IP asignado automáticamente" y haz clic en Continuar. Después de revisar la información, selecciona CREAR CONEXIÓN.
- Una vez que se configure la red, podrás continuar con la creación del clúster. Haz clic en CREATE CLUSTER para completar la configuración del clúster, como se muestra a continuación:
Asegúrate de cambiar el ID de la instancia (que puedes encontrar en el momento de la configuración del clúster o la instancia) a
vector-instance
. Si no puedes cambiarlo, recuerda usar el ID de tu instancia en todas las referencias futuras.
Ten en cuenta que la creación del clúster tardará alrededor de 10 minutos. Una vez que se realice correctamente, deberías ver una pantalla que muestre la descripción general del clúster que acabas de crear.
4. Transferencia de datos
Ahora es el momento de agregar una tabla con los datos de la tienda. Navega a AlloyDB, selecciona el clúster principal y, luego, AlloyDB Studio:
Es posible que debas esperar a que se termine de crear la instancia. Una vez que lo hagas, accede a AlloyDB con las credenciales que creaste cuando creaste el clúster. Usa los siguientes datos para autenticarte en PostgreSQL:
- Nombre de usuario : "
postgres
" - Base de datos : "
postgres
" - Contraseña : "
alloydb
"
Una vez que te hayas autenticado correctamente en AlloyDB Studio, los comandos SQL se ingresarán en el editor. Puedes agregar varias ventanas del editor con el signo más que se encuentra a la derecha de la última ventana.
Ingresarás comandos para AlloyDB en las ventanas del editor, con las opciones Ejecutar, Formatear y Borrar según sea necesario.
Habilita las extensiones
Para compilar esta app, usaremos las extensiones pgvector
y google_ml_integration
. La extensión pgvector te permite almacenar y buscar embeddings de vectores. La extensión google_ml_integration proporciona funciones que usas para acceder a los extremos de predicción de Vertex AI y obtener predicciones en SQL. Para habilitar estas extensiones, ejecuta los siguientes DDL:
CREATE EXTENSION IF NOT EXISTS google_ml_integration CASCADE;
CREATE EXTENSION IF NOT EXISTS vector;
Si quieres verificar las extensiones que se habilitaron en tu base de datos, ejecuta este comando SQL:
select extname, extversion from pg_extension;
Crear una tabla
Puedes crear una tabla con la siguiente sentencia DDL en AlloyDB Studio:
CREATE TABLE patents_data ( id VARCHAR(25), type VARCHAR(25), number VARCHAR(20), country VARCHAR(2), date VARCHAR(20), abstract VARCHAR(300000), title VARCHAR(100000), kind VARCHAR(5), num_claims BIGINT, filename VARCHAR(100), withdrawn BIGINT, abstract_embeddings vector(768)) ;
La columna abstract_embeddings permitirá el almacenamiento de los valores vectoriales del texto.
Otorgar permiso
Ejecuta la siguiente sentencia para otorgar la ejecución en la función "embedding":
GRANT EXECUTE ON FUNCTION embedding TO postgres;
Otorga el rol de usuario de Vertex AI a la cuenta de servicio de AlloyDB
En la consola de IAM de Google Cloud, otorga a la cuenta de servicio de AlloyDB (que se ve de la siguiente manera: service-<<PROJECT_NUMBER>>@gcp-sa-alloydb.iam.gserviceaccount.com) acceso al rol "Usuario de Vertex AI". PROJECT_NUMBER tendrá el número de tu proyecto.
Como alternativa, puedes ejecutar el siguiente comando desde la terminal de Cloud Shell:
PROJECT_ID=$(gcloud config get-value project)
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:service-$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")@gcp-sa-alloydb.iam.gserviceaccount.com" \
--role="roles/aiplatform.user"
Carga datos de patentes en la base de datos
Los conjuntos de datos públicos de Google Patents en BigQuery se usarán como nuestro conjunto de datos. Usaremos AlloyDB Studio para ejecutar nuestras consultas. Los datos se obtienen de este archivo insert_scripts.sql
y lo ejecutaremos para cargar los datos de patentes.
- En la consola de Google Cloud, abre la página AlloyDB.
- Selecciona el clúster que acabas de crear y haz clic en la instancia.
- En el menú de navegación de AlloyDB, haz clic en AlloyDB Studio. Accede con tus credenciales.
- Para abrir una pestaña nueva, haz clic en el ícono Nueva pestaña que se encuentra a la derecha.
- Copia la sentencia de consulta
insert
de la secuencia de comandosinsert_scripts.sql
mencionada anteriormente en el editor. Puedes copiar entre 10 y 50 instrucciones de inserción para una demostración rápida de este caso de uso. - Haz clic en Ejecutar. Los resultados de tu consulta aparecen en la tabla Resultados.
5. Crea incorporaciones para datos de patentes
Primero, probemos la función de incorporación ejecutando la siguiente consulta de ejemplo:
SELECT embedding('text-embedding-005', 'AlloyDB is a managed, cloud-hosted SQL database service.');
Se debería mostrar el vector de incorporaciones, que parece un array de números de punto flotante, para el texto de muestra en la consulta. Se ve de la siguiente manera:
Actualiza el campo de vector abstract_embeddings
Ejecuta la siguiente DML para actualizar los resúmenes de patentes en la tabla con las incorporaciones correspondientes:
UPDATE patents_data set abstract_embeddings = embedding( 'text-embedding-005', abstract);
6. Realiza una búsqueda vectorial
Ahora que la tabla, los datos y los embeddings están listos, realicemos la Búsqueda de vectores en tiempo real para el texto de búsqueda del usuario. Para probarlo, ejecuta la siguiente consulta:
SELECT id || ' - ' || title as title FROM patents_data ORDER BY abstract_embeddings <=> embedding('text-embedding-005', 'Sentiment Analysis')::vector LIMIT 10;
En esta consulta,
- El texto que buscó el usuario es "Análisis de opiniones".
- Lo convertimos en incorporaciones en el método embedding() con el modelo text-embedding-005.
- "<=>" representa el uso del método de distancia SIMILARITY_COSINE.
- Convertimos el resultado del método de incorporación en un tipo de vector para que sea compatible con los vectores almacenados en la base de datos.
- LIMIT 10 representa que seleccionamos las 10 coincidencias más cercanas del texto de búsqueda.
AlloyDB lleva el RAG de búsqueda vectorial al siguiente nivel:
Se introdujeron muchos elementos. Dos de las más centradas en los desarrolladores son las siguientes:
- Filtrado intercalado
- Evaluador de recuperación
Filtrado intercalado
Anteriormente, como desarrollador, debías realizar la consulta de Búsqueda de vectores y lidiar con el filtrado y la recuperación. El optimizador de consultas de AlloyDB toma decisiones sobre cómo ejecutar una consulta con filtros. El filtrado intercalado es una nueva técnica de optimización de consultas que permite que el optimizador de consultas de AlloyDB evalúe las condiciones de filtrado de metadatos y la búsqueda de vectores en paralelo, aprovechando los índices de vectores y los índices de las columnas de metadatos. Esto aumentó el rendimiento de la recuperación, lo que permite a los desarrolladores aprovechar lo que AlloyDB tiene para ofrecer de forma predeterminada.
El filtrado intercalado es mejor para los casos con selectividad media. A medida que AlloyDB busca en el índice de vectores, solo calcula las distancias de los vectores que coinciden con las condiciones de filtrado de metadatos (los filtros funcionales en una consulta que suelen controlarse en la cláusula WHERE). Esto mejora enormemente el rendimiento de estas consultas y complementa las ventajas del filtro posterior o previo.
- Instala o actualiza la extensión pgvector
CREATE EXTENSION IF NOT EXISTS vector WITH VERSION '0.8.0.google-3';
Si la extensión pgvector ya está instalada, actualízala a la versión 0.8.0.google-3 o una posterior para obtener capacidades de evaluador de recuperación.
ALTER EXTENSION vector UPDATE TO '0.8.0.google-3';
Este paso solo debe ejecutarse si tu extensión vectorial es <0.8.0.google-3.
Nota importante: Si el recuento de filas es inferior a 100, no necesitarás crear el índice ScaNN, ya que no se aplicará a menos filas. En ese caso, omite los siguientes pasos.
- Para crear índices ScaNN, instala la extensión alloydb_scann.
CREATE EXTENSION IF NOT EXISTS alloydb_scann;
- Primero, ejecuta la consulta de Vector Search sin el índice y sin el filtro intercalado habilitado:
SELECT id || ' - ' || title as title FROM patents_data
WHERE num_claims >= 15
ORDER BY abstract_embeddings <=> embedding('text-embedding-005', 'Sentiment Analysis')::vector LIMIT 10;
El resultado debería ser similar al siguiente:
- Ejecuta Explain Analyze en él: (sin índice ni filtrado intercalado)
El tiempo de ejecución es de 2.4 ms
- Creemos un índice normal en el campo num_claims para poder filtrar por él:
CREATE INDEX idx_patents_data_num_claims ON patents_data (num_claims);
- Creemos el índice ScaNN para nuestra aplicación de búsqueda de patentes. Ejecuta el siguiente comando desde AlloyDB Studio:
CREATE INDEX patent_index ON patents_data
USING scann (abstract_embeddings cosine)
WITH (num_leaves=32);
Nota importante: (num_leaves=32)
se aplica a nuestro conjunto de datos total con más de 1,000 filas. Si el recuento de filas es inferior a 100, no necesitarás crear un índice, ya que no se aplicará a menos filas.
- Establece el filtrado intercalado habilitado en el índice ScaNN:
SET scann.enable_inline_filtering = on
- Ahora, ejecutemos la misma consulta con el filtro y Vector Search:
SELECT id || ' - ' || title as title FROM patents_data
WHERE num_claims >= 15
ORDER BY abstract_embeddings <=> embedding('text-embedding-005', 'Sentiment Analysis')::vector LIMIT 10;
Como puedes ver, el tiempo de ejecución se reduce significativamente para la misma Búsqueda de vectores. El índice ScaNN con filtrado intercalado en la Búsqueda de vectores lo hizo posible.
A continuación, evaluemos la recuperación de esta Búsqueda de vectores habilitada para ScaNN.
Evaluador de recuperación
La recuperación en la búsqueda de similitudes es el porcentaje de instancias relevantes que se recuperaron de una búsqueda, es decir, la cantidad de verdaderos positivos. Esta es la métrica más común que se usa para medir la calidad de la búsqueda. Una fuente de pérdida de recuperación proviene de la diferencia entre la búsqueda de vecino más cercano aproximado, o aNN, y la búsqueda de vecino más cercano k (exacto), o kNN. Los índices vectoriales, como ScaNN de AlloyDB, implementan algoritmos de ANN, lo que te permite acelerar la búsqueda vectorial en grandes conjuntos de datos a cambio de una pequeña compensación en la recuperación. Ahora, AlloyDB te permite medir esta compensación directamente en la base de datos para consultas individuales y asegurarte de que sea estable con el tiempo. Puedes actualizar los parámetros de consulta y de índice en función de esta información para obtener mejores resultados y rendimiento.
Puedes encontrar la recuperación de una consulta vectorial en un índice vectorial para una configuración determinada con la función evaluate_query_recall. Esta función te permite ajustar los parámetros para lograr los resultados de recuperación de la consulta vectorial que deseas. La recuperación es la métrica que se usa para la calidad de la búsqueda y se define como el porcentaje de los resultados que se muestran que están objetivamente más cerca de los vectores de consulta. La función evaluate_query_recall está activada de forma predeterminada.
Nota importante:
Si tienes un error de permiso denegado en el índice de HNSW en los siguientes pasos, omite por ahora toda esta sección de evaluación de recuperación. En este momento, podría deberse a restricciones de acceso, ya que se acaba de lanzar cuando se documenta este codelab.
- Establece la marca Enable Index Scan en el índice ScaNN y el índice HNSW:
SET scann.enable_indexscan = on
SET hnsw.enable_index_scan = on
- Ejecuta la siguiente consulta en AlloyDB Studio:
SELECT
*
FROM
evaluate_query_recall($$
SELECT
id || ' - ' || title AS title,
abstract
FROM
patents_data
where num_claims >= 15
ORDER BY
abstract_embeddings <=> embedding('text-embedding-005',
'sentiment analysis')::vector
LIMIT 25 $$,
'{"scann.num_leaves_to_search":1, "scann.pre_reordering_num_neighbors":10}',
ARRAY['scann']);
La función evaluate_query_recall toma la consulta como parámetro y muestra su recuperación. Estoy usando la misma consulta que usé para verificar el rendimiento como la consulta de entrada de la función. Agregué SCaNN como el método de indexación. Para obtener más opciones de parámetros, consulta la documentación.
El recuerdo de esta consulta de búsqueda de vectores que hemos estado usando:
Veo que el valor de RECALL es 70%. Ahora puedo usar esta información para cambiar los parámetros de índice, los métodos y los parámetros de consulta, y mejorar mi recuperación para esta Búsqueda vectorial.
Modifiqué la cantidad de filas en el conjunto de resultados a 7 (de 10 anteriormente) y veo una mejora ligeramente en la RECALL, es decir, un 86%.
Esto significa que, en tiempo real, puedo variar la cantidad de coincidencias que ven mis usuarios para mejorar la relevancia de las coincidencias de acuerdo con el contexto de búsqueda de los usuarios.
Muy bien. Es hora de implementar la lógica de la base de datos y pasar al agente.
7. Lleva la lógica de la base de datos a la Web sin servidores
¿Todo listo para llevar esta app a la Web? Siga los pasos que se indican a continuación:
- Ve a Funciones de Cloud Run en la consola de Google Cloud para CREAR una nueva función de Cloud Run o usa el vínculo: https://console.cloud.google.com/functions/add.
- Selecciona el entorno como “Función de Cloud Run”. Proporciona el nombre de la función "patent-search" y elige la región "us-central1". Establece la autenticación en "Permitir invocaciones no autenticadas" y haz clic en SIGUIENTE. Elige Java 17 como entorno de ejecución y Editor intercalado para el código fuente.
- De forma predeterminada, establecería el punto de entrada en "gcfv2.HelloHttpFunction". Reemplaza el código del marcador de posición en HelloHttpFunction.java y pom.xml de tu Cloud Run Function por el código de " PatentSearch.java" y " pom.xml", respectivamente. Cambia el nombre del archivo de clase a PatentSearch.java.
- Recuerda cambiar el marcador de posición ************* y las credenciales de conexión de AlloyDB por tus valores en el archivo Java. Las credenciales de AlloyDB son las que usamos al comienzo de este codelab. Si usaste valores diferentes, modifica los mismos en el archivo Java.
- Haz clic en Implementar.
PASO IMPORTANTE:
Una vez que se implemente, para permitir que la función de Cloud Functions acceda a nuestra instancia de base de datos de AlloyDB, crearemos el conector de VPC.
Una vez que todo esté listo para la implementación, deberías poder ver las funciones en la consola de Google Cloud Run Functions. Busca la función recién creada (patent-search), haz clic en ella y, luego, en EDITAR Y IMPLEMENTAR REVISIONES NUEVAS (identificado por el ícono de EDITAR (pluma) en la parte superior de la consola de Cloud Run Functions) y cambia lo siguiente:
- Ve a la pestaña Herramientas de redes:
- Selecciona "Conéctate a una VPC para el tráfico saliente" y, luego, "Usar conectores de Acceso a VPC sin servidores".
- En el menú desplegable Red, haz clic en el menú desplegable Red y selecciona la opción “Add New VPC Connector” (si aún no configuraste el predeterminado) y sigue las instrucciones que aparecen en el cuadro de diálogo emergente:
- Proporciona un nombre para el conector de VPC y asegúrate de que la región sea la misma que la de tu instancia. Deja el valor de red como predeterminado y establece la subred como rango de IP personalizado con el rango de IP 10.8.0.0 o algo similar que esté disponible.
- Expande MOSTRAR LA CONFIGURACIÓN DE ESCALA y asegúrate de que la configuración sea exactamente la siguiente:
- Haz clic en CREATE y este conector debería aparecer en la configuración de salida.
- Selecciona el conector recién creado.
- Elige que todo el tráfico se enrute a través de este conector de VPC.
- Haz clic en NEXT y, luego, en DEPLOY.
- Una vez que se implemente la Cloud Function actualizada, deberías ver el extremo generado. Copia eso y reemplázalo en el siguiente comando:
PROJECT_ID=$(gcloud config get-value project)
curl -X POST <<YOUR_ENDPOINT>> \
-H 'Content-Type: application/json' \
-d '{"search":"Sentiment Analysis"}'
Eso es todo. Es así de simple realizar una Búsqueda vectorial de similitud contextual avanzada con el modelo de incorporaciones en los datos de AlloyDB.
8. Compilemos el agente con el ADK de Java
Primero, comencemos con el proyecto de Java en el editor.
- Navega a la terminal de Cloud Shell
https://shell.cloud.google.com/?fromcloudshell=true&show=ide%2Cterminal
- Autorizar cuando se solicite
- Para activar o desactivar el editor de Cloud Shell, haz clic en el ícono del editor en la parte superior de la consola de Cloud Shell.
- En la consola de destino del editor de Cloud Shell, crea una carpeta nueva y asígnale el nombre "adk-agents".
Haz clic en Crear carpeta nueva en el directorio raíz de Cloud Shell, como se muestra a continuación:
Asóciale el nombre "adk-agents":
- Crea la siguiente estructura de carpetas y los archivos vacíos con los nombres de archivo correspondientes en la siguiente estructura:
adk-agents/
└—— pom.xml
└—— src/
└—— main/
└—— java/
└—— agents/
└—— App.java
- Abre el repositorio de GitHub en una pestaña independiente y copia el código fuente de los archivos App.java y pom.xml.
- Si abriste el editor en una pestaña nueva con el ícono "Abrir en una pestaña nueva" en la esquina superior derecha, puedes abrir la terminal en la parte inferior de la página. Puedes tener el editor y la terminal abiertos en paralelo, lo que te permite operar libremente.
- Una vez que se haya clonado, vuelve a la consola del editor de Cloud Shell.
- Como ya creamos la función de Cloud Run, no necesitas copiar los archivos de la función de Cloud Run desde la carpeta del repositorio.
Cómo comenzar a usar el SDK de Java del ADK
Es bastante sencillo. En primer lugar, deberás asegurarte de que se incluya lo siguiente en el paso de clonación:
- Agrega dependencias:
Incluye los artefactos google-adk y google-adk-dev (para la IU web) en tu pom.xml.
<!-- The ADK core dependency -->
<dependency>
<groupId>com.google.adk</groupId>
<artifactId>google-adk</artifactId>
<version>0.1.0</version>
</dependency>
<!-- The ADK dev web UI to debug your agent -->
<dependency>
<groupId>com.google.adk</groupId>
<artifactId>google-adk-dev</artifactId>
<version>0.1.0</version>
</dependency>
Asegúrate de hacer referencia al archivo pom.xml desde el repositorio de origen, ya que hay otras dependencias y configuraciones necesarias para que la aplicación se pueda ejecutar.
- Configura tu proyecto:
Asegúrate de que la versión de Java (se recomienda 17 o una posterior) y la configuración del compilador de Maven estén configuradas correctamente en el archivo pom.xml. Puedes configurar tu proyecto para que siga la siguiente estructura:
adk-agents/
└—— pom.xml
└—— src/
└—— main/
└—— java/
└—— agents/
└—— App.java
- Definición del agente y sus herramientas (App.java):
Aquí es donde brilla la magia del SDK de Java del ADK. Definimos nuestro agente, sus capacidades (instrucciones) y las herramientas que puede usar.
Aquí encontrarás una versión simplificada de algunos fragmentos de código de la clase de agente principal. Para ver el proyecto completo, consulta el repositorio del proyecto aquí.
// App.java (Simplified Snippets)
package agents;
import com.google.adk.agents.LlmAgent;
import com.google.adk.agents.BaseAgent;
import com.google.adk.agents.InvocationContext;
import com.google.adk.tools.Annotations.Schema;
import com.google.adk.tools.FunctionTool;
// ... other imports
public class App {
static FunctionTool searchTool = FunctionTool.create(App.class, "getPatents");
static FunctionTool explainTool = FunctionTool.create(App.class, "explainPatent");
public static BaseAgent ROOT_AGENT = initAgent();
public static BaseAgent initAgent() {
return LlmAgent.builder()
.name("patent-search-agent")
.description("Patent Search agent")
.model("gemini-2.0-flash-001") // Specify your desired Gemini model
.instruction(
"""
You are a helpful patent search assistant capable of 2 things:
// ... complete instructions ...
""")
.tools(searchTool, explainTool)
.outputKey("patents") // Key to store tool output in session state
.build();
}
// --- Tool: Get Patents ---
public static Map<String, String> getPatents(
@Schema(name="searchText",description = "The search text for which the user wants to find matching patents")
String searchText) {
try {
String patentsJson = vectorSearch(searchText); // Calls our Cloud Run Function
return Map.of("status", "success", "report", patentsJson);
} catch (Exception e) {
// Log error
return Map.of("status", "error", "report", "Error fetching patents.");
}
}
// --- Tool: Explain Patent (Leveraging InvocationContext) ---
public static Map<String, String> explainPatent(
@Schema(name="patentId",description = "The patent id for which the user wants to get more explanation for, from the database")
String patentId,
@Schema(name="ctx",description = "The list of patent abstracts from the database from which the user can pick the one to get more explanation for")
InvocationContext ctx) { // Note the InvocationContext
try {
// Retrieve previous patent search results from session state
String previousResults = (String) ctx.session().state().get("patents");
if (previousResults != null && !previousResults.isEmpty()) {
// Logic to find the specific patent abstract from 'previousResults' by 'patentId'
String[] patentEntries = previousResults.split("\n\n\n\n");
for (String entry : patentEntries) {
if (entry.contains(patentId)) { // Simplified check
// The agent will then use its instructions to summarize this 'report'
return Map.of("status", "success", "report", entry);
}
}
}
return Map.of("status", "error", "report", "Patent ID not found in previous search.");
} catch (Exception e) {
// Log error
return Map.of("status", "error", "report", "Error explaining patent.");
}
}
public static void main(String[] args) throws Exception {
InMemoryRunner runner = new InMemoryRunner(ROOT_AGENT);
// ... (Session creation and main input loop - shown in your source)
}
}
Componentes clave del código Java del ADK destacados:
- LlmAgent.builder(): Es la API de Fluent para configurar tu agente.
- .instruction(...): Proporciona la instrucción y los lineamientos principales para el LLM, incluido cuándo usar qué herramienta.
- FunctionTool.create(App.class, "methodName"): Registra fácilmente tus métodos de Java como herramientas que el agente puede invocar. La cadena de nombre del método debe coincidir con un método estático público real.
- @Schema(description = …): Anota los parámetros de la herramienta, lo que ayuda al LLM a comprender qué entradas espera cada herramienta. Esta descripción es fundamental para la selección precisa de herramientas y el llenado de parámetros.
- InvocationContext ctx: Se pasa automáticamente a los métodos de la herramienta, lo que permite acceder al estado de la sesión (ctx.session().state()), a la información del usuario y a mucho más.
- .outputKey("patents"): Cuando una herramienta muestra datos, el ADK puede almacenarlos automáticamente en el estado de la sesión con esta clave. De esta manera, explainPatent puede acceder a los resultados de getPatents.
- VECTOR_SEARCH_ENDPOINT: Es una variable que contiene la lógica funcional principal de las preguntas y respuestas contextuales para el usuario en el caso de uso de búsqueda de patentes.
- Acción: Debes establecer un valor de extremo implementado actualizado una vez que implementes el paso de la función de Cloud Run de Java de la sección anterior.
- searchTool: Interacciona con el usuario para encontrar coincidencias de patentes relevantes contextualmente en la base de datos de patentes para el texto de búsqueda del usuario.
- explainTool: Se le pide al usuario una patente específica para analizarla en detalle. Luego, resume el resumen de la patente y puede responder más preguntas del usuario en función de los detalles de la patente que tiene.
Nota importante: Asegúrate de reemplazar la variable VECTOR_SEARCH_ENDPOINT por el extremo de CRF que hayas implementado.
Aprovecha InvocationContext para interacciones con estado
Una de las funciones fundamentales para crear agentes útiles es administrar el estado en varios turnos de una conversación. InvocationContext del ADK facilita esta tarea.
En nuestro App.java:
- Cuando se define initAgent(), usamos .outputKey("patents"). Esto le indica a ADK que, cuando una herramienta (como getPatents) muestra datos en su campo de informe, esos datos se deben almacenar en el estado de la sesión con la clave "patents".
- En el método de la herramienta explainPatent, insertamos InvocationContext ctx:
public static Map<String, String> explainPatent(
@Schema(description = "...") String patentId, InvocationContext ctx) {
String previousResults = (String) ctx.session().state().get("patents");
// ... use previousResults ...
}
Esto permite que la herramienta explainPatent acceda a la lista de patentes que recuperó la herramienta getPatents en un turno anterior, lo que hace que la conversación sea coherente y tenga estado.
9. Pruebas de CLI locales
Define las variables de entorno.
Deberás exportar dos variables de entorno:
- Una clave de Gemini que puedes obtener en AI Studio:
Para ello, ve a https://aistudio.google.com/apikey, obtén la clave de API para tu proyecto activo de Google Cloud en el que implementas esta aplicación y guárdala en algún lugar:
- Una vez que hayas obtenido la clave, abre la terminal de Cloud Shell y dirígete al nuevo directorio que acabamos de crear adk-agents. Para ello, ejecuta el siguiente comando:
cd adk-agents
- Es una variable para especificar que no usaremos Vertex AI esta vez.
export GOOGLE_GENAI_USE_VERTEXAI=FALSE
export GOOGLE_API_KEY=AIzaSyDF...
- Ejecuta tu primer agente en la CLI
Para iniciar este primer agente, usa el siguiente comando de Maven en la terminal:
mvn compile exec:java -DmainClass="agents.App"
Verás la respuesta interactiva del agente en la terminal.
10. Implementa en Cloud Run
La implementación de tu agente de Java de ADK en Cloud Run es similar a la implementación de cualquier otra aplicación de Java:
- Dockerfile: Crea un Dockerfile para empaquetar tu aplicación de Java.
- Compila y envía una imagen de Docker: Usa Google Cloud Build y Artifact Registry.
- Puedes realizar el paso anterior y realizar la implementación en Cloud Run con un solo comando:
gcloud run deploy --source . --set-env-vars GOOGLE_API_KEY=<<Your_Gemini_Key>>
Del mismo modo, implementarías tu función de Cloud Run de Java (gcfv2.PatentSearch). Como alternativa, puedes crear e implementar la función de Cloud Run de Java para la lógica de la base de datos directamente desde la consola de Cloud Run Functions.
11. Cómo realizar pruebas con la IU web
El ADK incluye una IU web práctica para realizar pruebas locales y depurar tu agente. Cuando ejecutas App.java de forma local (p.ej., mvn exec:java -Dexec.mainClass="agents.App" si está configurado, o solo ejecutas el método principal), el ADK suele iniciar un servidor web local.
La IU web de ADK te permite hacer lo siguiente:
- Enviar mensajes a tu agente
- Consulta los eventos (mensaje del usuario, llamada a la herramienta, respuesta de la herramienta, respuesta de LLM).
- Inspecciona el estado de la sesión.
- Visualiza registros y seguimientos.
Esto es invaluable durante el desarrollo para comprender cómo tu agente procesa las solicitudes y usa sus herramientas. Esto supone que tu mainClass en pom.xml está configurado en com.google.adk.web.AdkWebServer y que tu agente está registrado con él, o bien que estás ejecutando un ejecutor de pruebas local que expone esto.
Cuando ejecutas tu App.java con su InMemoryRunner y Scanner para la entrada de la consola, estás probando la lógica del agente principal. La IU web es un componente independiente para una experiencia de depuración más visual, que se suele usar cuando el ADK entrega tu agente a través de HTTP.
Puedes usar el siguiente comando de Maven desde tu directorio raíz para iniciar el servidor local de SpringBoot:
mvn compile exec:java -Dexec.args="--adk.agents.source-dir=src/main/java/ --logging.level.com.google.adk.dev=TRACE --logging.level.com.google.adk.demo.agents=TRACE"
A menudo, se puede acceder a la interfaz en la URL que genera el comando anterior. Si está implementada en Cloud Run, deberías poder acceder a ella desde el vínculo de Cloud Run implementado.
Deberías poder ver el resultado en una interfaz interactiva.
Mira el siguiente video sobre nuestro agente de patentes implementado:
12. Limpia
Sigue estos pasos para evitar que se apliquen cargos a tu cuenta de Google Cloud por los recursos que usaste en esta publicación:
- En la consola de Google Cloud, ve a https://console.cloud.google.com/cloud-resource-manager?utm_campaign=CDR_0x1d2a42f5_default_b419133749&utm_medium=external&utm_source=blog.
- https://console.cloud.google.com/cloud-resource-manager?utm_campaign=CDR_0x1d2a42f5_default_b419133749&utm_medium=external&utm_source=blog.
- En la lista de proyectos, elige el proyecto que deseas borrar y haz clic en Borrar.
- En el diálogo, escribe el ID del proyecto y, luego, haz clic en Cerrar para borrarlo.
13. Felicitaciones
¡Felicitaciones! Compilaste correctamente tu agente de análisis de patentes en Java combinando las capacidades de ADK, https://cloud.google.com/alloydb/docs?utm_campaign=CDR_0x1d2a42f5_default_b419133749&utm_medium=external&utm_source=blog, Vertex AI y Vector Search. Además, dimos un gran paso adelante para que las búsquedas de similitud contextual sean tan transformadoras, eficientes y realmente orientadas al significado.
¡Comienza hoy!
Documentación del ADK: [Vínculo a la documentación oficial de Java del ADK]
Código fuente del agente de análisis de patentes: [Vínculo a tu repositorio de GitHub (ahora público)]
Agentes de muestra de Java: [vínculo al repositorio de adk-samples]
Únete a la comunidad de ADK: https://www.reddit.com/r/agentdevelopmentkit/
¡Que disfrutes de la compilación de agentes!