Skip to main content

Command Palette

Search for a command to run...

Cómo crear y consumir un agente en Azure Foundry

Updated
7 min read
Cómo crear y consumir un agente en Azure Foundry
S

I have worked as a frontend and backend developer handling technologies such as Django, Ionic, Laravel, MySQL, Spring (Java), Oracle, NodeJS, Angular, VueJS with the goal of developing websites and mobile applications that offer high performance and are interactive.

You can learn more about me by visiting my website: www.stalinmaza.com

#frontend #backend #fullstack #javascript #nodejs #php

En este tutorial aprenderás a:

Crear un agente en Azure Foundry usando un modelo de OpenAI. Configurar permisos y autenticación con Service Principal. Consumir el agente desde un script Node.js. Integrarlo en un frontend simple (Angular) para crear un chat funcional.

Crear el agente en Azure Foundry

Se debe acceder al portal de Azure Foundry. Posteriormente se debe navegar al apartado de Agents y seleccionar Create Agent.

Una vez en este apartado, se debe elegir un deployment de OpenAI (Azure Foundry actualmente soporta modelos de OpenAI como GPT-4, GPT-3.5, etc.).

En la pantalla se debe configurar lo siguiente:

  • Nombre del agente.

  • Prompt inicial (instrucciones del comportamiento).

  • Knowledge base (sube tus PDFs o documentos relevantes).

    • Los documentos que se suben se vectorizan mediante Azure AI Search para la optimización de las búsquedas en la base de conocimientos.

Finalmente hay que guardar los cambios y esperar a que el agente esté listo.

Configurar autenticación con Service Principal

Para consumir el agente desde tu aplicación, necesitas un Service Principal, por lo cual debes navegar hacia el apartado de Azure Active Directory → App Registrations → New Registration.

Entonces se debe asignar un nombre ej. foundry-agent-client). Una vez creado se debe copiar el valor del Application (client) ID y el Directory (tenant) ID.

Posteriormente se debe generar un Client Secret, para esto se debe navegar a la sección de Certificates & Secrets → New Client Secret. Guarda el valor en un lugar seguro (lo usarás en tu script) ya que este valor no aparecerá nuevamente.

Asignar permisos al Service Principal

Ve a Azure Foundry → IAM (Access Control). En este apartado añade el Service Principal como Cognitive Services Contributor. Esto le permitirá interactuar con el agente vía API.

Consumir el agente desde Node.js

Crea un pequeño script para conectarte al agente, para esto crea un proyecto de Node.js (Solo para el ejemplo, se puede usar también Python o .NET).

Primero debes instalar las siguientes dependencias:

npm install @azure/ai-projects @azure/identity body-parser dotenv express

Posteriormente se debe crear el archivo .env con los siguientes valores:


AZURE_TENANT_ID=<TENAND_ID>
AZURE_CLIENT_SECRET=<CLIENT_SECRET>
AZURE_CLIENT_ID=<CLIENT_ID>
PROJECT_URL=
AGENT_ID=

Finalmente se debe ejecutar el código para consumir el proyecto, en el cual

// Importar dependencias
const express = require("express");
const bodyParser = require("body-parser");

// Importar variables de entorno desde archivo .env
require('dotenv').config()

// Importaciones del SDK de Agentes de Azure AI
const { AIProjectClient } = require("@azure/ai-projects");
const { DefaultAzureCredential } = require("@azure/identity");

const app = express();
const PORT = 3000;

// *** Configuración específica de tu Agente de Azure AI Studio ***
const AZURE_AI_PROJECT_URL = process.env.PROJECT_URL;
const AGENT_ID = process.env.AGENT_ID;

// Inicializar el cliente del proyecto (se autentica usando az login en desarrollo)
const aiProjectClient = new AIProjectClient(
  AZURE_AI_PROJECT_URL,
  new DefaultAzureCredential() //Esta credencial por defecto busca el tenant, clientId y clientSecret
);

// Aplicar middleware de body parser
app.use(bodyParser.json());

// Configuración de CORS para permitir la comunicación con tu Frontend (Angular)
app.use((req, res, next) => {
  // CAMBIA ESTO por la URL de tu frontend (ej: 'http://localhost:4200')
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Content-Type");
  res.header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS');
  next();
});

// Endpoint principal para el chat
app.post("/api/chat", async (req, res) => {
  const userMessage = req.body.message;

  if (!userMessage) {
    return res.status(400).json({ error: "Falta el mensaje del usuario." });
  }

  try {
    // 1. Crear un nuevo Hilo (Thread) para la conversación
    const thread = await aiProjectClient.agents.threads.create();

    // 2. Enviar el mensaje del usuario al Hilo
    await aiProjectClient.agents.messages.create(
      thread.id,
      "user",
      userMessage
    );

    // 3. Iniciar la Ejecución (Run) del Agente sobre el Hilo
    let run = await aiProjectClient.agents.runs.create(thread.id, AGENT_ID);

    // 4. Monitorear el estado del Run hasta que termine
    while (run.status === "queued" || run.status === "in_progress") {
      // Esperar 1 segundo antes de volver a consultar el estado
      await new Promise((resolve) => setTimeout(resolve, 1000));
      run = await aiProjectClient.agents.runs.get(thread.id, run.id);
    }

    if (run.status === "failed") {
      console.error("Run failed:", run.lastError);
      return res.status(500).json({
        error: "La ejecución del Agente falló.",
        details: run.lastError,
      });
    }

    // 5. Recuperar todos los mensajes después de que el Agente ha respondido
    const messagesIterator = aiProjectClient.agents.messages.list(thread.id, {
      order: "desc",
    });

    const allMessages = [];
    for await (const m of messagesIterator) {
      allMessages.push(m);
    }

    // Ahora, puedes usar .find() en el array allMessages
    const agentResponseMsg = allMessages.find((m) => m.role === "assistant");

    let agentReplyText = "Lo siento, no pude obtener una respuesta válida.";

    if (agentResponseMsg) {
      // ... el resto de tu lógica para extraer el texto ...
      const content = agentResponseMsg.content.find(
        (c) => c.type === "text" && "text" in c
      );
      if (content) {
        agentReplyText = content.text.value;
      }
    }
    // 6. Retornar la respuesta al Frontend
    res.json({ reply: agentReplyText });
  } catch (error) {
    console.error("Error al comunicarse con Azure AI Agents:", error);
    res
      .status(500)
      .json({ error: "Error interno del servidor al procesar la solicitud." });
  }
});

app.listen(PORT, () => {
  console.log(`Servidor intermedio escuchando en http://localhost:${PORT}`);
});

Crear un frontend simple (Angular)

En este caso la aplicación será en Angular, pero puede ser cualquier frontend como React, Vue.js, etc. Para el ejemplo, se debe crear primero un servicio que se comunique con el backend.

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

// Define la estructura de la respuesta
export interface ChatResponse {
  reply: string;
}

@Injectable({
  providedIn: 'root'
})
export class ChatService {
  private apiUrl = 'http://localhost:3000/api/chat'; // URL de tu backend

  constructor(private http: HttpClient) { }

  sendMessage(message: string): Observable<ChatResponse> {
    // Envía el mensaje al backend intermediario
    return this.http.post<ChatResponse>(this.apiUrl, { message: message });
  }
}

Luego se debe construir una pantalla básica para visualizar el resultado del chat. En este ejemplo se usa Bootstrap y CSS.

Se utilizarán los siguientes estilos:

/* Limita el alto de la ventana de chat y habilita el scroll */
.chat-window {
    height: 400px;
    overflow-y: auto;
    padding-bottom: 10px;
    background-color: #f8f9fa; /* Gris muy claro */
}

/* Estilo de la burbuja: limita el ancho y añade esquinas */
.message-bubble {
    max-width: 70%; /* Las burbujas no ocupan todo el ancho */
    border-radius: 1.25rem; /* Más redondeado que el card default */
    border: none;
    box-shadow: 0 1px 2px rgba(0,0,0,.1);
}

/* Mensajes del Agente: alineación a la izquierda (default) */
.bg-light.message-bubble {
    /* Ajustes para el lado del agente */
    border-top-left-radius: 0.25rem; /* Esquina superior izquierda menos redondeada para simular el chat */
}

/* Mensajes del Usuario: alineación a la derecha */
.bg-primary.message-bubble {
    /* Ajustes para el lado del usuario */
    border-top-right-radius: 0.25rem; /* Esquina superior derecha menos redondeada */
    margin-left: auto; /* Para asegurar el espaciado correcto */
}

Posteriormente, en el archivo Typescript se debe declarar los valores necesarios para consumir los datos.

import { Component, OnInit } from '@angular/core';
import { ChatService } from 'src/app/services/chat.service';


interface Message {
  text: string;
  sender: 'user' | 'agent';
}
@Component({
  selector: 'app-chatbot-ai',
  templateUrl: './chatbot-ai.component.html',
  styleUrls: ['./chatbot-ai.component.scss']
})
export class ChatbotAiComponent implements OnInit {
    messages: Message[] = [];
    currentMessage: string = '';

    constructor(private chatService: ChatService) {}

    sendMessage(): void {
        if (this.currentMessage.trim() === '') return;

        const userMsg = this.currentMessage;
        this.messages.push({ text: userMsg, sender: 'user' });
        this.currentMessage = ''; // Limpiar el input

        // Llama al servicio que se comunica con tu backend intermedio
        this.chatService.sendMessage(userMsg).subscribe({
          next: (response) => {
            this.messages.push({ text: response.reply, sender: 'agent' });
          },
          error: (err) => {
            this.messages.push({ text: 'Error: No se pudo contactar al agente.', sender: 'agent' });
            console.error(err);
          }
        });
    }
}

Por último se puede mostrar en la interfaz un diseño básico para visualizar los datos de la interacción.

<div class="container mt-4">
    <div class="card shadow-sm">
        <div class="card-header bg-primary text-white">
            <h5 class="mb-0">Agente de Azure AI Foundry</h5>
        </div>

        <div class="card-body chat-window">

            <div *ngFor="let msg of messages" class="d-flex mb-3" 
                 [ngClass]="{'justify-content-end': msg.sender === 'user'}">

                <div class="card message-bubble" 
                     [ngClass]="{'bg-primary text-white': msg.sender === 'user', 'bg-light': msg.sender === 'agent'}">
                    <div class="card-body p-2">
                        {{ msg.text }}
                    </div>
                </div>
            </div>

        </div>

        <div class="card-footer">
            <div class="input-group">
                <input type="text" 
                       class="form-control" 
                       [(ngModel)]="currentMessage" 
                       (keyup.enter)="sendMessage()" 
                       placeholder="Escribe un mensaje...">
                <button class="btn btn-primary" 
                        (click)="sendMessage()"
                        [disabled]="!currentMessage.trim()">
                    Enviar
                </button>
            </div>
        </div>
    </div>
</div>

Probar la integración

  • Inicia tu backend Node.js.

  • Abre tu frontend Angular.

  • Envía mensajes y recibe respuestas del agente.

Recomendaciones

  • Seguridad: Usa HTTPS y JWT para proteger tu API.

  • Escalabilidad: Considera usar Azure API Management para exponer tu API.

  • Monitoreo: Activa Azure Monitor para logs y métricas.

  • Optimización: Ajusta el prompt y la base de conocimiento para mejorar la calidad de las respuestas.

More from this blog