 ##  [En meget enkel og lidt bedre måde at skabe en AI-agent ved hjælp af nushell `generate` i stedet for et normalt agent-loop](/da/node/153) 

    *Indsendt af Lennart den ons, 18 feb 2026 - 11:20*  

  ![Agentens svar](/sites/default/files/styles/wide/public/2026-02/Sk%C3%A6rmbillede%202026-02-18%20kl.%2011.14.35.png.webp?itok=I04ASn-A)

 

**Funktionelle Agent-loops: Hvorfor Nushells `generate` slår det imperative loop**

Opbygning af AI-agenter involverer ofte et forudsigeligt, men rodet loop:

1. Send historik til LLM'en.
2. Modtag et svar.
3. Hvis LLM'en vil kalde et værktøj, udfør det og gentag.
4. Hvis det er et endeligt svar, stop.

I de fleste sprog implementeres dette med et `while True`-loop og et muterbart `history`-array.

Selvom dette for det meste fungerer, er det ofte "støjende" og håndterer tilstandsopdateringer og afslutningsbetingelser på en måde, der blander logik og kontrolflow.

Brug i stedet Nushells `generate`-kommando.

## `generate`-mønsteret

Nushell er en shell med strukturerede data og en stærk funktionel indflydelse.

Nushells `generate`-kommando er en "generator" eller "unfold"-operation. Den tager en indledende tilstand og en lukning (en *closure*). Lukningen returnerer en post med to valgfrie nøgler:

- `out`: Hvad der skal udsendes til strømmen.
- `next`: Tilstanden for den næste iteration.

Hvis `next` mangler, stopper loopet.

## Hvorfor det er bedre for agenter

I vores implementering af `agent.nu` udnytter vi `generate` til at håndtere multi-turn samtalen med Gemini 2.0 Flash:

```
generate {|history|
    let response = call_gemini $history
    let message = $response.candidates.0.content
    
    # Bruger den nye 'get -o' (optional) syntaks i stedet for forældede '-i'
    let function_calls = $message.parts | where { |p| ($p | get -o functionCall) != null }
    
    if ($function_calls | is-not-empty) {
        # ... logik til udførelse af værktøjer ...
        let next_history = ($history | append $message | append $tool_results)
        { out: $message, next: $next_history }
    } else {
        { out: $message } # Ingen 'next' betyder, at vi er færdige!
    }
} $initial_history

```

### 1. Tilstand er en Uforanderlig Strøm

I et primitivt loop tilføjer du konstant `history.push()`. I `generate` sendes historikken fra den ene iteration til den næste som en værdi. Dette gør logikken lettere at ræsonnere over - hvert "trin" af agenten er en ren transformation af `history` til `(output, new_history)`.

### 2. Agenten er en stream

Fordi `generate` returnerer en stream, bliver din agent en første klasses Nushell-borger. Du kan sende agentens fremskridt direkte:

```
agent "Planlæg en tur til Tokyo" | each { |msg| print $msg.role }

```

Du kan endda bruge `take`, `first` eller `where` på agentens "tanker", mens de sker!

Hvis agenten tager 10 trin for at løse et problem, skriver `generate` hvert trin ud, efterhånden som de opstår. Med mindre du fravælger og kun vil have svaret med en simpel `last` tilføjelse til din pipeline.

### 3. Klare Afslutningsbetingelser

Imperative loops har ofte komplekse `if/else`-kæder med `break` eller `return` udsagn begravet dybt nede. Med `generate` er tilstedeværelsen eller fraværet af `next`-nøglen det *eneste*, der bestemmer, om loopet fortsætter. Dette tvinger dig til at være eksplicit omkring dine tilstandsovergange.

### 4. Komponerbarhed

Da outputtet er en standard Nushell-liste/strøm, kan du nemt gemme hele sporingen af en agents ræsonnement til en JSON-fil eller vise det som en tabel uden at tilføje nogen "logningskode" inde i selve loopet.

```
agent "Hvad er klokken?" | save trace.json

```

## Konklusion

Nushells `generate` forvandler agent-loopet fra et stykke infrastruktur til en datastrøm. Den fjerner den overflødige kode fra manuel iteration og lader dig fokusere på kernen i logikken: hvordan agentens tilstand udvikler sig over tid.

Ved at omfavne funktionelle mønstre som `generate`, kan vi bygge agenter, der er renere, mere forudsigelige og naturligt integreret i shell-miljøet.