Delen via


Zelfstudie: Een agentische web-app bouwen in Azure App Service met LangGraph of Foundry Agent Service (Node.js)

In deze zelfstudie ziet u hoe u agentische mogelijkheden toevoegt aan een bestaande gegevensgestuurde Express.js CRUD-toepassing. Dit doet u met behulp van twee verschillende benaderingen: LangGraph en Foundry Agent Service.

Als uw webtoepassing al nuttige functies heeft, zoals winkelen, hotelreservering of gegevensbeheer, is het relatief eenvoudig om agentfunctionaliteit toe te voegen aan uw webtoepassing door deze functies in een invoegtoepassing (voor LangGraph) of als een OpenAPI-eindpunt (voor Foundry Agent Service) te verpakken. In deze handleiding begint u met een eenvoudige to-do lijstapp. Aan het einde kunt u taken maken, bijwerken en beheren met een agent in een App Service-app.

Met zowel LangGraph als Foundry Agent Service kunt u agentische webtoepassingen bouwen met AI-gestuurde mogelijkheden. LangGraph is vergelijkbaar met Microsoft Semantic Kernel en is een SDK, maar Semantische kernel biedt momenteel geen ondersteuning voor JavaScript. In de volgende tabel ziet u enkele overwegingen en afwegingen:

Consideration LangGraph Foundry Agentendienst
Performance Snel (lokaal uitgevoerd) Trager (beheerde, externe service)
Development Volledige code, maximaal beheer Low-code, snelle integratie
Testing Handmatige/eenheidstests in code Ingebouwde speeltuin voor snel testen
Scalability App-managed Door Azure beheerd, automatisch geschaald
Veiligheidsrails Aangepaste implementatie vereist Ingebouwde inhoudsveiligheid en toezicht
Identiteit Aangepaste implementatie vereist Ingebouwde agent-id en verificatie
Enterprise Aangepaste integratie vereist Ingebouwde microsoft 365/Teams-implementatie en geïntegreerde hulpprogramma-aanroepen van Microsoft 365.

In deze handleiding leer je hoe je:

  • Bestaande app-functionaliteit converteren naar een invoegtoepassing voor LangGraph.
  • Voeg de invoegtoepassing toe aan een LangGraph-agent en gebruik deze in een web-app.
  • Bestaande app-functionaliteit converteren naar een OpenAPI-eindpunt voor Foundry Agent Service.
  • Roep een Foundry-agent aan in een web-app.
  • Wijs de vereiste machtigingen toe voor connectiviteit met beheerde identiteiten.

Prerequisites

Het voorbeeld openen met Codespaces

De eenvoudigste manier om aan de slag te gaan is door GitHub Codespaces te gebruiken. Dit biedt een volledige ontwikkelomgeving met alle vereiste hulpprogramma's die vooraf zijn geïnstalleerd.

  1. Navigeer naar de GitHub-opslagplaats op https://github.com/Azure-Samples/app-service-agentic-langgraph-foundry-node.

  2. Klik op de knop Code, selecteer het tabblad Codespaces en selecteer Codespace op main maken.

  3. Wacht even totdat uw Codespace is geïnitialiseerd. Wanneer u klaar bent, ziet u een volledig geconfigureerde ontwikkelomgeving in uw browser.

  4. Voer de toepassing lokaal uit:

    npm install
    npm run build
    npm start
    
  5. Wanneer u ziet dat uw toepassing wordt uitgevoerd op poort 3000 beschikbaar is, selecteert u Openen in browser en voegt u enkele taken toe.

    De agents zijn niet volledig geconfigureerd, zodat ze nog niet werken. U gaat ze later configureren.

De agentcode controleren

Beide benaderingen gebruiken hetzelfde implementatiepatroon, waarbij de agent wordt geïnitialiseerd bij het starten van de toepassing en reageert op gebruikersberichten door POST-aanvragen.

De LangGraphTaskAgent wordt geïnitialiseerd in de constructor in src/agents/LangGraphTaskAgent.ts. De initialisatiecode doet het volgende:

    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);
        }
    }

Bij het verwerken van gebruikersberichten wordt de agent aangeroepen met behulp van invoke() de bericht- en sessieconfiguratie van de gebruiker voor gesprekscontinuïteit:

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

De voorbeeldtoepassing implementeren

De voorbeeldopslagplaats bevat een AZD-sjabloon (Azure Developer CLI), waarmee een App Service-app met beheerde identiteit wordt gemaakt en uw voorbeeldtoepassing wordt geïmplementeerd.

  1. Meld u in de terminal aan bij Azure met behulp van Azure Developer CLI:

    azd auth login
    

    Volg de instructies om het verificatieproces te voltooien.

  2. Implementeer de Azure App Service-app met de AZD-sjabloon:

    azd up
    
  3. Geef de volgende antwoorden wanneer u hierom wordt gevraagd:

    Question Answer
    Voer een nieuwe omgevingsnaam in: Voer een unieke naam in.
    Selecteer een Azure-abonnement dat u wilt gebruiken: Selecteer het abonnement.
    Kies een resourcegroep die u wilt gebruiken: Selecteer Een nieuwe resourcegroep maken.
    Selecteer een locatie waarin u de resourcegroep wilt maken in: Selecteer Zweden - centraal.
    Voer een naam in voor de nieuwe resourcegroep: Typ Enter.
  4. Zoek in de AZD-uitvoer de URL van uw app en navigeer ernaar in de browser. De URL ziet er in de AZD-uitvoer zo uit:

     Deploying services (azd deploy)
    
       (✓) Done: Deploying service web
       - Endpoint: <URL>
     
  5. Open het automatisch gegenereerde OpenAPI-schema op het https://....azurewebsites.net/api/schema pad. U heeft dit schema later nodig.

    U hebt nu een App Service-app met een door het systeem toegewezen beheerde identiteit.

De Microsoft Foundry-resource maken en configureren

  1. Controleer in de Foundry-portal dat de bovenste radioknop New Foundry is ingesteld op actief, en maak een project.

  2. Een model van uw keuze implementeren (zie Snelstartgids voor Microsoft Foundry: Resources maken).

  3. Kopieer de naam van het model vanaf de bovenkant van de modelspeelplaats.

  4. De eenvoudigste manier om het Azure OpenAI-eindpunt op te halen, is nog steeds vanuit de klassieke portal. Selecteer het keuzerondje New Foundry , vervolgens Azure OpenAI en kopieer de URL in het Azure OpenAI-eindpunt voor later gebruik.

    Schermopname van het kopiëren van het OpenAI-eindpunt en het eindpunt van het foundry-project in de foundry-portal.

Vereiste machtigingen toewijzen

  1. Selecteer Operatie in het bovenste menu van de nieuwe Foundry-portal en selecteer daarna Beheer. In de rij van uw Foundry-project ziet u twee koppelingen. De hulpbron in de kolom Naam is de Foundry-projecthulpbron en de hulpbron in de kolom Bovenliggende hulpbron is de Foundry-hulpbron.

    Schermopname die laat zien hoe u snel naar de foundry-resource of de foundry-projectresource gaat.

  2. Selecteer de Foundry-resource in de bovenliggende resource en selecteer vervolgens deze resource beheren in de Azure portal. Vanuit Azure Portal kunt u op rollen gebaseerde toegang voor de resource toewijzen aan de geïmplementeerde web-app.

  3. Voeg de volgende rol toe voor de beheerde identiteit van de App Service-app:

    Doelresource Vereiste rol Vereist voor
    Gieterij Cognitive Services OpenAI-gebruiker De voltooiingsservice voor chats in Microsoft Agent Framework.

    Zie Azure-rollen toewijzen via Azure Portal voor instructies.

Verbindingsvariabelen configureren in uw voorbeeldtoepassing

  1. Open .env. Configureer de volgende variabelen met behulp van de waarden die u eerder hebt gekopieerd uit de Foundry-portal:

    Variable Description
    AZURE_OPENAI_ENDPOINT Azure OpenAI-eindpunt (gekopieerd uit de klassieke Foundry-portal).
    AZURE_OPENAI_DEPLOYMENT_NAME Modelnaam in de implementatie (gekopieerd uit de modelspeeltuin in de nieuwe Foundry-portal).

    Note

    Als u de zelfstudie eenvoudig wilt houden, gebruikt u deze variabelen in .env in plaats van ze te overschrijven met app-instellingen in App Service.

    Note

    Als u de zelfstudie eenvoudig wilt houden, gebruikt u deze variabelen in .env in plaats van ze te overschrijven met app-instellingen in App Service.

  2. Meld u aan bij Azure met de Azure CLI:

    az login
    

    Hierdoor kan de Azure Identity-clientbibliotheek in de voorbeeldcode een verificatietoken ontvangen voor de aangemelde gebruiker. Houd er rekening mee dat u de vereiste rol voor deze gebruiker eerder hebt toegevoegd.

  3. Voer de toepassing lokaal uit:

    npm run build
    npm start
    
  4. Wanneer uw toepassing draait op poort 3000 en beschikbaar is, selecteert u Openen in de browser.

  5. Selecteer de koppeling LangGraph Agent en de koppeling Foundry Agent om de chatinterface uit te proberen. Als u een antwoord krijgt, maakt uw toepassing verbinding met de Microsoft Foundry-resource.

  6. Implementeer uw app-wijzigingen in de GitHub-codespace.

    azd up
    
  7. Ga opnieuw naar de geïmplementeerde toepassing en test de chatagents.

De hulpbronnen opschonen

Wanneer u klaar bent met de toepassing, kunt u de App Service-resources verwijderen om verdere kosten te voorkomen:

azd down --purge

Aangezien de AZD-sjabloon de Microsoft Foundry-resources niet bevat, moet u ze desgewenst handmatig verwijderen.

Meer middelen