Självstudie: Skapa en agentisk webbapp i Azure App Service med LangGraph eller Foundry Agent Service (Node.js)

Den här tutorialen visar hur du lägger till agent-kapacitet i en befintlig datadriven Express.js CRUD-applikation. Det gör detta med två olika metoder: LangGraph och Foundry Agent Service.

Om ditt webbprogram redan har användbara funktioner, till exempel shopping, hotellbokning eller datahantering, är det relativt enkelt att lägga till agentfunktioner i webbappen genom att omsluta funktionerna i ett plugin-program (för LangGraph) eller som en OpenAPI-slutpunkt (för Foundry Agent Service). I den här handledningen börjar du med en enkel to-do-listapp. I slutet kan du skapa, uppdatera och hantera uppgifter med en agent i en App Service-app.

Med både LangGraph och Foundry Agent Service kan du skapa agentiska webbprogram med AI-drivna funktioner. LangGraph liknar Microsoft Semantic Kernel och är ett SDK, men semantisk kernel stöder för närvarande inte JavaScript. Följande tabell visar några av övervägandena och kompromisserna:

Consideration LangGraph Gjuteritjänstagent
Performance Snabb (körs lokalt) Långsammare (hanterad fjärrtjänst)
Development Fullständig kod, maximal kontroll Låg kod, snabb integrering
Testing Manuella tester och enhetstester i kod Inbyggd lekplats för snabb testning
Scalability App-managed Azure-hanterad, autoskalning
Skyddsräcken Anpassad implementation krävs Inbyggd innehållssäkerhet och moderering
Identitet Anpassad implementering behövs Inbyggt agent-ID och autentisering
Enterprise Anpassad integrering krävs Inbyggd Microsoft 365/Teams-distribution och integrerade Verktygsanrop för Microsoft 365.

I den här tutorialen lär du dig följande:

  • Konvertera befintliga appfunktioner till ett plugin-program för LangGraph.
  • Lägg till plugin-programmet i en LangGraph-agent och använd det i en webbapp.
  • Konvertera befintliga appfunktioner till en OpenAPI-slutpunkt för Foundry Agent Service.
  • Anropa en Foundry-agent i en webbapplikation.
  • Tilldela nödvändiga behörigheter för hanterad identitetsanslutning.

Prerequisites

Öppna exemplet med Codespaces

Det enklaste sättet att komma igång är att använda GitHub Codespaces, som ger en fullständig utvecklingsmiljö med alla nödvändiga verktyg förinstallerade.

  1. Navigera till GitHub-lagringsplatsen på https://github.com/Azure-Samples/app-service-agentic-langgraph-foundry-node.

  2. Välj knappen Kod , välj fliken Codespaces och välj Skapa kodområde på main.

  3. Vänta en stund tills kodområdet initieras. När du är klar visas en fullständigt konfigurerad utvecklingsmiljö i webbläsaren.

  4. Kör programmet lokalt:

    npm install
    npm run build
    npm start
    
  5. När du ser Din applikation körs på port 3000 och är tillgänglig, väljer du Öppna i webbläsare och lägger till några uppgifter.

    Agenterna är inte helt konfigurerade så de fungerar inte än. Du konfigurerar dem senare.

Granska agentkoden

Båda metoderna använder samma implementeringsmönster, där agenten initieras vid programstart, och svarar på användarmeddelanden via POST-begäranden.

LangGraphTaskAgent Initieras i konstruktorn i src/agents/LangGraphTaskAgent.ts. Initieringskoden gör följande:

    constructor(taskService: TaskService) {
        this.taskService = taskService;
        this.memory = new MemorySaver();
        try {
            const endpoint = process.env.AZURE_OPENAI_ENDPOINT;
            const deploymentName = process.env.AZURE_OPENAI_DEPLOYMENT_NAME;

            if (!endpoint || !deploymentName) {
                console.warn('Azure OpenAI configuration missing for LangGraph agent');
                return;
            }
            // Initialize Azure OpenAI client
            const credential = new DefaultAzureCredential();
            const azureADTokenProvider = getBearerTokenProvider(credential, "https://cognitiveservices.azure.com/.default");
            
            this.llm = new AzureChatOpenAI({
                azureOpenAIEndpoint: endpoint,
                azureOpenAIApiDeploymentName: deploymentName,
                azureADTokenProvider: azureADTokenProvider,
                azureOpenAIApiVersion: "2024-10-21"
            });
            // Define tools directly in the array
            const tools = [
                tool(
                    async ({ title, isComplete = false }) => {
                        const task = await this.taskService.addTask(title, isComplete);
                        return `Task created successfully: "${task.title}" (ID: ${task.id})`;
                    },
                    {
                        name: 'createTask',
                        description: 'Create a new task',
                        schema: z.object({
                            title: z.string(),
                            isComplete: z.boolean().optional()
                        }) as any
                    }
                ),
                tool(
                    async () => {
                        const tasks = await this.taskService.getAllTasks();
                        if (tasks.length === 0) {
                            return 'No tasks found.';
                        }
                        return `Found ${tasks.length} tasks:\n` + 
                               tasks.map(t => `- ${t.id}: ${t.title} (${t.isComplete ? 'Complete' : 'Incomplete'})`).join('\n');
                    },
                    {
                        name: 'getTasks',
                        description: 'Get all tasks',
                        schema: z.object({}) as any
                    }
                ),
                tool(
                    async ({ id }) => {
                        const task = await this.taskService.getTaskById(id);
                        if (!task) {
                            return `Task with ID ${id} not found.`;
                        }
                        return `Task ${task.id}: "${task.title}" - Status: ${task.isComplete ? 'Complete' : 'Incomplete'}`;
                    },
                    {
                        name: 'getTask',
                        description: 'Get a specific task by ID',
                        schema: z.object({
                            id: z.number()
                        }) as any
                    }
                ),
                tool(
                    async ({ id, title, isComplete }) => {
                        const updated = await this.taskService.updateTask(id, title, isComplete);
                        if (!updated) {
                            return `Task with ID ${id} not found.`;
                        }
                        return `Task ${id} updated successfully.`;
                    },
                    {
                        name: 'updateTask',
                        description: 'Update an existing task',
                        schema: z.object({
                            id: z.number(),
                            title: z.string().optional(),
                            isComplete: z.boolean().optional()
                        }) as any
                    }
                ),
                tool(
                    async ({ id }) => {
                        const deleted = await this.taskService.deleteTask(id);
                        if (!deleted) {
                            return `Task with ID ${id} not found.`;
                        }
                        return `Task ${id} deleted successfully.`;
                    },
                    {
                        name: 'deleteTask',
                        description: 'Delete a task',
                        schema: z.object({
                            id: z.number()
                        }) as any
                    }
                )
            ];

            // Create the ReAct agent with memory
            this.agent = createReactAgent({
                llm: this.llm,
                tools,
                checkpointSaver: this.memory,
                stateModifier: `You are an AI assistant that manages tasks using CRUD operations.
                
You have access to tools for creating, reading, updating, and deleting tasks.
Always use the appropriate tool for any task management request.
Be helpful and provide clear responses about the actions you take.

If you need more information to complete a request, ask the user for it.`
            });
        } catch (error) {
            console.error('Error initializing LangGraph agent:', error);
        }
    }

Vid bearbetning av användarmeddelanden anropas agenten med hjälp av invoke() användarens meddelande- och sessionskonfiguration för konversationskontinuitet:

const result = await this.agent.invoke(
    { 
        messages: [
            { role: 'user', content: message }
        ]
    },
    { 
        configurable: { 
            thread_id: currentSessionId 
        } 
    }
);

Distribuera exempelprogrammet

Exempellagringsplatsen innehåller en AZD-mall (Azure Developer CLI) som skapar en App Service-app med hanterad identitet och distribuerar exempelprogrammet.

  1. Logga in på Azure med Azure Developer CLI i terminalen:

    azd auth login
    

    Följ anvisningarna för att slutföra autentiseringsprocessen.

  2. Distribuera Azure App Service-appen med AZD-mallen:

    azd up
    
  3. När du uppmanas, ge följande svar:

    Question Answer
    Ange ett nytt miljönamn: Skriv ett unikt namn.
    Välj en Azure-prenumeration som ska användas: Välj prenumerationen.
    Välj en resursgrupp som ska användas: Välj Skapa en ny resursgrupp.
    Välj en plats för att skapa resursgruppen i: Välj Sweden Central.
    Ange ett namn för den nya resursgruppen: Skriv Retur.
  4. I AZD-utdata letar du reda på url:en för din app och navigerar till den i webbläsaren. URL:en ser ut så här i AZD-utdata:

     Deploying services (azd deploy)
    
       (✓) Done: Deploying service web
       - Endpoint: <URL>
     
  5. Öppna det automatiskt genererade OpenAPI-schemat på sökvägen https://....azurewebsites.net/api/schema. Du behöver det här schemat senare.

    Nu har du en App Service-app med en systemtilldelad hanterad identitet.

Skapa och konfigurera Microsoft Foundry-resursen

  1. I Foundry-portalen kontrollerar du att den översta radioknappen Ny Foundry är inställd på aktiv och sedan skapar du ett projekt.

  2. Distribuera en modell (se Microsoft Foundry Snabbstart: Skapa resurser).

  3. Kopiera modellnamnet överst på modelllekplatsen.

  4. Det enklaste sättet att hämta Azure OpenAI-slutpunkten är fortfarande från den klassiska portalen. Välj alternativknappen Ny Foundry, därefter Azure OpenAI, och kopiera sedan URL:en i Azure OpenAI-slutpunkten för senare.

    Skärmbild som visar hur du kopierar OpenAI-slutpunkten och gjuteriprojektets slutpunkt i gjuteriportalen.

Tilldela nödvändiga behörigheter

  1. På den översta menyn i den nya Foundry-portalen väljer du Använd och sedan Admin. På raden för ditt Foundry-projekt bör du se två länkar. Den i kolumnen Namn är projektresursen Foundry och den i kolumnen Överordnad resurs är Foundry-resursen.

    Skärmbild som visar hur du snabbt kan navigera till gjutoriets resurs eller gjuteriprojektets resurs.

  2. Välj Foundry-resursen i den överordnade resursen och välj sedan Hantera den här resursen i Azure-portalen. Från Azure-portalen kan du tilldela rollbaserad åtkomst för resursen till den distribuerade webbappen.

  3. Lägg till följande roll för App Service-appens hanterade identitet:

    Målresurs Obligatorisk roll Behövs för
    Gjuteri Cognitive Services OpenAI-användare Tjänsten för chattens slutförande i Microsoft Agent Framework.

    Instruktioner finns i Tilldela Azure-roller med hjälp av Azure-portalen.

Konfigurera anslutningsvariabler i exempelprogrammet

  1. Öppna .env. Med de värden som du kopierade tidigare från Foundry-portalen konfigurerar du följande variabler:

    Variable Description
    AZURE_OPENAI_ENDPOINT Azure OpenAI-slutpunkt (kopierad från den klassiska Foundry-portalen).
    AZURE_OPENAI_DEPLOYMENT_NAME Modellnamn i distributionen (kopieras från modelllekplatsen i den nya Foundry-portalen).

    Note

    För att förenkla handledningen använder du dessa variabler i .env istället för att skriva över dem med appinställningar i App Service.

    Note

    För att förenkla handledningen använder du dessa variabler i .env istället för att skriva över dem med appinställningar i App Service.

  2. Logga in på Azure med Azure CLI:

    az login
    

    På så sätt kan Azure Identity-klientbiblioteket i exempelkoden ta emot en autentiseringstoken för den inloggade användaren. Kom ihåg att du lade till den roll som krävs för den här användaren tidigare.

  3. Kör programmet lokalt:

    npm run build
    npm start
    
  4. När du ser Ditt program som körs på port 3000 är tillgängligt väljer du Öppna i webbläsaren.

  5. Välj länken LangGraph Agent och länken Foundry Agent för att testa chattgränssnittet. Om du får ett svar ansluter programmet till Microsoft Foundry-resursen.

  6. Tillbaka i GitHub-kodområdet distribuerar du dina appändringar.

    azd up
    
  7. Navigera till det distribuerade programmet igen och testa chattagenterna.

Rensa resurser

När du är klar med programmet kan du ta bort App Service-resurserna för att undvika ytterligare kostnader:

azd down --purge

Eftersom AZD-mallen inte innehåller Microsoft Foundry-resurserna måste du ta bort dem manuellt om du vill.

Fler resurser