Rövid útmutató: AI-ügynök vektoros kereséssel az Azure DocumentDB-ben a Go használatával

Intelligens AI-ügynök létrehozása a Go és az Azure DocumentDB használatával. Ez a rövid útmutató egy kétügynök-architektúrát mutat be, amely szemantikai szállodakeresést végez, és személyre szabott javaslatokat hoz létre.

Important

Ez a minta egy referencia-implementáció, amely a Go programozási nyelv ügynök-alapú mintáit mutatja be. Egy ügynökkeretrendszer helyett egyedi ügynökarchitektúrát használ, ami az üzemeltetési ügynöki alkalmazásokhoz ajánlott módszer.

Prerequisites

Az Azure Developer CLI használatával létrehozhatja a szükséges Azure-erőforrásokat a azd mintaadattár parancsainak futtatásával. További információ: Infrastruktúra üzembe helyezése az Azure Developer CLI-vel.

Azure-erőforrások

  • Azure OpenAI-erőforrás a következő modelltelepítésekkel a Microsoft Foundryben:

    • gpt-4o üzembe helyezés (szintetizátorügynök) – Ajánlott: 50 000 token/perc (TPM) kapacitás
    • gpt-4o-mini üzembe helyezés (Planner-ügynök) – Ajánlott: 30 000 token/perc (TPM) kapacitás
    • text-embedding-3-small üzembe helyezés (beágyazások) – Ajánlott: 10 000 token/perc (TPM) kapacitás
    • Jogkivonatkvóták: Konfiguráljon elegendő TPM-et minden üzembe helyezéshez a sebességkorlátozás elkerülése érdekében
  • Azure DocumentDB-fürt, amely kompatibilis a MongoDB-vel, vektorkeresési támogatással:

    • A fürtréteg követelményei vektorindex-algoritmuson alapulnak:
      • IVF (invertált fájlindex): M10 vagy újabb (alapértelmezett algoritmus)
      • HNSW (Hierarchikus navigálható kisvilág): M30 vagy újabb (gráfalapú)
      • DiskANN: M40 vagy újabb (nagy léptékűre optimalizálva)
    • Tűzfalkonfiguráció: KÖTELEZŐ A megfelelő tűzfalkonfiguráció nélkül a csatlakozási kísérletek meghiúsulnak
    • Jelszó nélküli hitelesítés esetén a szerepköralapú hozzáférés-vezérlés (RBAC) engedélyezve van

Fejlesztői eszközök

  • Go 1.22 vagy újabb verzió
  • Azure CLI hitelesítéshez

Architecture

A minta egy kétügynök-architektúrát használ, amelyben minden ügynöknek van egy adott szerepköre.

Architektúradiagram a planner-ügynökkel, vektorkereső eszközzel és szintetizátorügynökkel rendelkező kétügynök-munkafolyamatról.

Ez a minta egy egyéni implementációt használ közvetlenül az OpenAI SDK-val, anélkül, hogy ügynök-keretrendszerre támaszkodik. Az OpenAI függvényt használja az eszközintegráció céljából, és lineáris munkafolyamatot követ az ügynökök és a keresőeszköz között. A végrehajtás állapot nélküli, beszélgetési előzmények nélkül, így alkalmas egyfordulós lekérdezési és válaszhelyzetekhez.

A mintakód lekérése

  1. A gyors kezdés követéséhez klónozza vagy töltse le az Azure DocumentDB mintákat a helyi gépére.

  2. Lépjen be a projektkönyvtárba:

    cd ai/vector-search-agent-go
    

Környezeti változók konfigurálása

Hozzon létre egy .env fájlt a projekt gyökérkönyvtárában a környezeti változók konfigurálásához. Létrehozhat egy másolatot a .env.sample fájlról az adattárból.

Szerkessze a .env fájlt, és cserélje le a helyőrző értékeket.

Ez a gyorsindítás egy kétügynökös architektúrát (tervező + szintetizátor) használ három modelltelepítéssel (két csevegőmodell + beágyazások). A környezeti változók minden modelltelepítéshez konfigurálva vannak.

  • AZURE_OPENAI_PLANNER_DEPLOYMENT: A gpt-4o-mini üzembehelyezési neve
  • AZURE_OPENAI_SYNTH_DEPLOYMENT: Az Ön gpt-4o telepítési neve
  • AZURE_OPENAI_EMBEDDING_DEPLOYMENT: Az ön text-embedding-3-small telepítési neve

Két hitelesítési módszer közül választhat: jelszó nélküli hitelesítés az Azure Identity használatával (ajánlott), vagy hagyományos kapcsolati sztring és API-kulcs.

1. lehetőség: Jelszó nélküli hitelesítés

Használjon jelszó nélküli hitelesítést az Azure OpenAI-val és az Azure DocumentDB-vel is. Beállítás USE_PASSWORDLESS=true, AZURE_OPENAI_ENDPOINT, és AZURE_DOCUMENTDB_CLUSTER.

# Enable passwordless authentication
USE_PASSWORDLESS=true

# Azure OpenAI Configuration (passwordless)
AZURE_OPENAI_ENDPOINT=your-openai-endpoint

# Azure DocumentDB (passwordless)
AZURE_DOCUMENTDB_CLUSTER=your-mongo-cluster-name
AZURE_DOCUMENTDB_DATABASENAME=Hotels
AZURE_DOCUMENTDB_COLLECTION=hotel_data
AZURE_DOCUMENTDB_INDEX_NAME=vectorIndex

A jelszó nélküli hitelesítés előfeltételei:

  • Győződjön meg arról, hogy bejelentkezett az Azure-ba: az login

  • Adja meg identitásának a következő szerepköröket:

    • Cognitive Services OpenAI User az Azure OpenAI-erőforráson
    • DocumentDB Account Contributor és Cosmos DB Account Reader Role az Azure DocumentDB-erőforráson

    A szerepkörök hozzárendelésével kapcsolatos további információkért lásd: Azure-szerepkörök hozzárendelése az Azure Portal használatával.

2. lehetőség: Kapcsolati sztring és API-kulcs hitelesítése

Használjon kulcsalapú hitelesítést a USE_PASSWORDLESS=false beállításával (vagy kihagyásával), és adja meg a AZURE_OPENAI_API_KEY és AZURE_DOCUMENTDB_CONNECTION_STRING értékeket a .env fájlban.

# Disable passwordless authentication
USE_PASSWORDLESS=false

# Azure OpenAI Configuration (API key)
AZURE_OPENAI_ENDPOINT=your-openai-endpoint
AZURE_OPENAI_API_KEY=your-azure-openai-api-key

# Azure DocumentDB (connection string)
AZURE_DOCUMENTDB_CONNECTION_STRING=mongodb+srv://username:password@cluster.mongocluster.cosmos.azure.com/
AZURE_DOCUMENTDB_DATABASENAME=Hotels
AZURE_DOCUMENTDB_COLLECTION=hotel_data
AZURE_DOCUMENTDB_INDEX_NAME=vectorIndex

A projekt szerkezete

A projekt a szokásos Go-projektelrendezést követi. A címtárszerkezetnek a következő struktúrához hasonlóan kell kinéznie:

mongo-vcore-agent-go/
├── cmd/
│   ├── agent/          # Main agent application
│   │   └── main.go
│   ├── upload/         # Data upload utility
│   │   └── main.go
│   └── cleanup/        # Database cleanup utility
│       └── main.go
├── internal/
│   ├── agents/         # Agent and tool implementations
│   │   ├── agents.go   # Planner and synthesizer agents
│   │   └── tools.go    # Vector search tool
│   ├── clients/        # Azure OpenAI client
│   │   └── openai.go
│   ├── models/         # Hotel data models
│   │   └── hotel.go
│   ├── prompts/        # System prompts and tool definitions
│   │   └── prompts.go
│   └── vectorstore/    # Azure DocumentDB vector store operations
│       └── store.go
├── .env                # Environment variable configuration
├── go.mod              # Go module file
└── go.sum              # Go module checksum file

A kód megismerése

Ez a szakasz az AI-ügynök munkafolyamatának alapvető összetevőit ismerteti. Kiemeli, hogy az ügynökök hogyan dolgozzák fel a kéréseket, hogyan csatlakoztatják az eszközök az AI-t az adatbázishoz, és hogy a kérések hogyan irányítja az AI viselkedését.

Ügynök alkalmazás

A cmd/agent/main.go fájl egy AI-alapú szállodaajánlási rendszert vezényl.

Az alkalmazás két Azure-szolgáltatást használ:

  • A lekérdezéseket megértő és javaslatokat generáló AI-modelleket használó Azure OpenAI
  • Azure DocumentDB, amely szállodai adatokat tárol, és vektoros hasonlósági keresést végez

Ügynök- és eszközösszetevők

A három összetevő együttműködve dolgozza fel a szálloda keresési kérését:

  • Planner-ügynök – Értelmezi a kérést, és eldönti, hogyan kell keresni
  • Vektorkereső eszköz – A Planner-ügynök által leírthoz hasonló szállodák keresése
  • Szintetizátorügynök – Hasznos javaslatot ír a keresési eredmények alapján

Alkalmazás munkafolyamata

Az alkalmazás két lépésben dolgozza fel a szálloda keresési kérését:

  • Tervezés: A munkafolyamat meghívja a planner-ügynököt, amely elemzi a felhasználó lekérdezését (például "futó nyomvonalak közelében lévő szállodák"), és megkeresi az adatbázisban az egyező szállodákat.
  • Szintetizáló: A munkafolyamat meghívja a szintetizátor-ügynököt, amely áttekinti a keresési eredményeket, és személyre szabott javaslatot ír, amely ismerteti, hogy mely szállodák felelnek meg a legjobban a kérésnek.
// Run planner agent
hotelContext, err := plannerAgent.Run(ctx, query, nearestNeighbors)
if err != nil {
    log.Fatalf("Planner agent failed: %v", err)
}

if debug {
    fmt.Printf("\n--- HOTEL CONTEXT ---\n%s\n", hotelContext)
}

// Run synthesizer agent
finalAnswer, err := synthesizerAgent.Run(ctx, query, hotelContext)
if err != nil {
    log.Fatalf("Synthesizer agent failed: %v", err)
}

Agents

A internal/agents/agents.go forrásfájl implementálja azokat a tervező- és szintetizátorügynököket, amelyek együttműködve dolgozzák fel a szállodai keresési kéréseket.

Planner-ügynök

A planner-ügynök az a döntéshozó , amely meghatározza a szállodák keresésének módját.

A planner-ügynök megkapja a felhasználó természetes nyelvi lekérdezését, és elküldi azt egy AI-modellnek a használható eszközökkel együtt. Az AI úgy dönt, hogy meghívja a vektorkereső eszközt, és keresési paramétereket biztosít. Az ügynök ezután kinyeri az eszköz nevét és argumentumait az AI válaszából, végrehajtja a keresőeszközt, és visszaadja a megfelelő szállodákat. A keresési logika keménykódolása helyett az AI értelmezi a felhasználó által kívánt adatokat, és kiválasztja a keresés módját, így a rendszer rugalmassá válik a különböző típusú lekérdezésekhez.

// PlannerAgent orchestrates the tool calling
type PlannerAgent struct {
    openAIClients *clients.OpenAIClients
    searchTool    *VectorSearchTool
    debug         bool
}

// NewPlannerAgent creates a new planner agent
func NewPlannerAgent(openaiClients *clients.OpenAIClients, searchTool *VectorSearchTool, debug bool) *PlannerAgent {
    return &PlannerAgent{
        openAIClients: openaiClients,
        searchTool:    searchTool,
        debug:         debug,
    }
}

// Run executes the planner agent workflow
func (a *PlannerAgent) Run(ctx context.Context, userQuery string, nearestNeighbors int) (string, error) {
    fmt.Println("\n--- PLANNER ---")

    userMessage := fmt.Sprintf(
        `Search for hotels matching this request: "%s". Use nearestNeighbors=%d.`,
        userQuery,
        nearestNeighbors,
    )

    // Get tool definition
    toolDef := a.searchTool.GetToolDefinition()

    // Call planner with tool definitions
    resp, err := a.openAIClients.ChatCompletionWithTools(ctx, prompts.PlannerSystemPrompt, userMessage, []openai.ChatCompletionToolUnionParam{toolDef})
    if err != nil {
        return "", fmt.Errorf("planner failed: %w", err)
    }

    // Extract tool call
    toolName, argsMap, err := clients.ExtractToolCall(resp)
    if err != nil {
        return "", fmt.Errorf("failed to extract tool call: %w", err)
    }

    if toolName != prompts.ToolName {
        return "", fmt.Errorf("unexpected tool called: %s", toolName)
    }

    // Parse arguments using typed struct
    args, err := parseToolArgumentsFromMap(argsMap)
    if err != nil {
        return "", fmt.Errorf("failed to parse tool arguments: %w", err)
    }

    // Use default if nearestNeighbors not provided
    if args.NearestNeighbors == 0 {
        args.NearestNeighbors = nearestNeighbors
    }

    fmt.Printf("Tool: %s\n", toolName)
    fmt.Printf("Query: %s\n", args.Query)
    fmt.Printf("K: %d\n", args.NearestNeighbors)

    // Execute the tool
    searchResults, err := a.searchTool.Execute(ctx, args.Query, args.NearestNeighbors)
    if err != nil {
        return "", fmt.Errorf("search tool execution failed: %w", err)
    }

    return searchResults, nil
}

Szintetizátorügynök

A szintetizátorügynök az az író, aki hasznos javaslatokat hoz létre.

A szintetizátorügynök megkapja az eredeti felhasználói lekérdezést a szálloda keresési eredményeivel együtt. Mindent elküld egy AI-modellnek a javaslatok megírására vonatkozó útmutatással. Természetes nyelvi választ ad vissza, amely összehasonlítja a szállodákat, és elmagyarázza a legjobb lehetőségeket. Ez a megközelítés azért fontos, mert a nyers keresési eredmények nem felhasználóbarátak. A szintetizátor beszélgetési javaslattá alakítja az adatbázisrekordokat, amely elmagyarázza, hogy egyes szállodák miért felelnek meg a felhasználó igényeinek.

// NewSynthesizerAgent creates a new synthesizer agent
func NewSynthesizerAgent(openaiClients *clients.OpenAIClients, debug bool) *SynthesizerAgent {
    return &SynthesizerAgent{
        openAIClients: openaiClients,
        debug:         debug,
    }
}

// Run executes the synthesizer agent workflow
func (a *SynthesizerAgent) Run(ctx context.Context, userQuery, hotelContext string) (string, error) {
    fmt.Println("\n--- SYNTHESIZER ---")
    fmt.Printf("Context size: %d characters\n", len(hotelContext))

    userMessage := prompts.CreateSynthesizerUserPrompt(userQuery, hotelContext)

    // Call synthesizer (no tools)
    finalAnswer, err := a.openAIClients.ChatCompletion(ctx, prompts.SynthesizerSystemPrompt, userMessage)
    if err != nil {
        return "", fmt.Errorf("synthesizer failed: %w", err)
    }

    return finalAnswer, nil
}

Ügynökeszközök

A internal/agents/tools.go forrásfájl határozza meg a planner-ügynök által használt vektorkeresési eszközt.

Az eszközfájl egy keresőeszközt határoz meg, amelyet az AI-ügynök használhat a szállodák kereséséhez. Az ügynök így csatlakozik az adatbázishoz. Az AI nem keres közvetlenül az adatbázisban. Kéri a keresőeszköz használatát, és az eszköz végrehajtja a tényleges keresést.

Eszközdefiníció

A GetToolDefinition metódus az eszközt az AI-modell számára az általa ismert formátumban írja le. Megadja az eszköz nevét, az eszköz nevének leírását, valamint azokat a paramétereket, amelyek meghatározzák, hogy az eszköznek milyen bemenetekre van szüksége. Ez a definíció tudatja az AI-t az eszköz meglétéről és helyes használatáról.

// GetToolDefinition returns the Azure OpenAI tool definition
func (t *VectorSearchTool) GetToolDefinition() openai.ChatCompletionToolUnionParam {
    paramSchema := map[string]any{
        "type": "object",
        "properties": map[string]any{
            "query": map[string]any{
                "type":        "string",
                "description": "Natural language search query describing desired hotel characteristics",
            },
            "nearestNeighbors": map[string]any{
                "type":        "integer",
                "description": "Number of results to return (1-20)",
                "default":     5,
            },
        },
        "required": []string{"query", "nearestNeighbors"},
    }

    return openai.ChatCompletionToolUnionParam{
        OfFunction: &openai.ChatCompletionFunctionToolParam{
            Function: openai.FunctionDefinitionParam{
                Name:        prompts.ToolName,
                Description: openai.String(prompts.ToolDescription),
                Parameters:  paramSchema,
            },
        },
    }
}

Eszköz végrehajtása

Amikor az AI meghívja az eszközt, a Execute metódus fut. Beágyazást hoz létre úgy, hogy a szöveges lekérdezést numerikus vektorsá alakítja az Azure OpenAI beágyazási modelljével. Ezután megkeresi az adatbázist úgy, hogy elküldi a vektort az Azure DocumentDB-nek, amely hasonló, hasonló leírást jelentő vektorokkal rendelkező szállodákat talál. Végül úgy formázhatja az eredményeket, hogy az adatbázisrekordokat olvasható szöveggé alakítja, amelyet a szintetizátorügynök megérthet.

// Execute performs the vector search
func (t *VectorSearchTool) Execute(ctx context.Context, query string, nearestNeighbors int) (string, error) {
    // Generate embedding for query
    queryVector, err := t.openAIClients.GenerateEmbedding(ctx, query)
    if err != nil {
        return "", fmt.Errorf("failed to generate embedding: %w", err)
    }

    // Perform vector search
    results, err := t.vectorStore.VectorSearch(ctx, queryVector, nearestNeighbors)
    if err != nil {
        return "", fmt.Errorf("vector search failed: %w", err)
    }

    // Format results for synthesizer
    var formattedResults []string
    for i, result := range results {
        fmt.Printf("Hotel #%d: %s, Score: %.6f\n", i+1, result.Hotel.HotelName, result.Score)
        formattedResults = append(formattedResults, vectorstore.FormatHotelForSynthesizer(result))
    }

    return strings.Join(formattedResults, "\n\n"), nil
}

Miért érdemes ezt a mintát használni?

Az eszköz az ügynöktől való elválasztása rugalmasságot biztosít. Az AI dönti el, hogy mikor és mire keressen, míg az eszköz kezeli a keresés módját. Az ügynöklogika módosítása nélkül további eszközöket is hozzáadhat.

Felkérések

A internal/prompts/prompts.go forrásfájl rendszerkéréseket és eszközdefiníciókat tartalmaz az ügynökök számára.

A parancssori fájl meghatározza az AI-modelleknek adott utasításokat és kontextust mind a tervező, mind a szintetizáló ügynökök számára. Ezek a kérések útmutatást adnak az AI viselkedéséhez, és biztosítják, hogy megértse a munkafolyamatban betöltött szerepét.

Az AI-válaszok minősége nagymértékben függ az egyértelmű utasításoktól. Ezek a kérések határokat határoznak meg, definiálják a kimeneti formátumot, és a felhasználó döntési céljára összpontosítják az AI-t. Ezeket a kéréseket testreszabhatja úgy, hogy kód módosítása nélkül módosítsa az ügynökök viselkedését.

const PlannerSystemPrompt = `You are a hotel search planner. Your job is to help users find hotels by calling the search tool.

CRITICAL INSTRUCTION: You MUST call the "search_hotels_collection" tool for every request. This is the ONLY way to search the database.

When you call the tool, use these parameters:
- query: A clear, detailed natural language description of what the user is looking for. Expand vague requests (e.g., "nice hotel" → "hotel with high ratings, good reviews, and quality amenities").
- nearestNeighbors: Number of results (1-20). Use 3-5 for specific requests, 10-15 for broader searches.

EXAMPLES of how you should call the tool:
- User: "cheap hotel" → Call tool with query: "budget-friendly hotel with good value and affordable rates", nearestNeighbors: 10
- User: "hotel near downtown with parking" → Call tool with query: "hotel near downtown with good parking and wifi", nearestNeighbors: 5

IMPORTANT: Always call the tool. Do not provide answers without calling the tool first.`

const SynthesizerSystemPrompt = `You are an expert hotel recommendation assistant using vector search results.
Only use the TOP 3 results provided. Do not request additional searches or call other tools.

GOAL: Provide a concise comparative recommendation to help the user choose between the top 3 options.

REQUIREMENTS:
- Compare only the top 3 results across the most important attributes: rating, score, location, price-level (if available), and key tags (parking, wifi, pool).
- Identify the main tradeoffs in one short sentence per tradeoff.
- Give a single clear recommendation with one short justification sentence.
- Provide up to two alternative picks (one sentence each) explaining when they are preferable.

FORMAT CONSTRAINTS:
- Plain text only (no markdown).
- Keep the entire response under 220 words.
- Use simple bullets (•) or numbered lists and short sentences (preferably <25 words per sentence).
- Preserve hotel names exactly as provided in the tool summary.

Do not add extra commentary, marketing language, or follow-up questions. If information is missing and necessary to choose, state it in one sentence and still provide the best recommendation based on available data.`

A minta futtatása

  1. Az ügynök futtatása előtt töltse fel a szálloda adatait beágyazásokkal. A cmd/upload/main.go parancs betölti a szállodákat a JSON-fájlból, beágyazásokat hoz létre minden szállodához az Azure DocumentDB használatával text-embedding-3-small, dokumentumokat szúr be az Azure DocumentDB-be, és létrehoz egy vektorindexet.

    go run cmd/upload/main.go
    
  2. Futtassa a szállodai ajánlási ügynököt a cmd/agent/main.go parancs használatával. Az ügynök meghívja a tervezőügynököt, a vektorkeresést és a szintetizátor-ügynököt. A kimenet hasonlósági pontszámokat és a szintetizátorügynök javaslatokkal végzett összehasonlító elemzését tartalmazza.

    go run cmd/agent/main.go
    
    Query: quintessential lodging near running trails, eateries, retail
    Nearest Neighbors: 5
    
    --- PLANNER ---
    Tool: search_hotels_collection
    Query: quintessential lodging near running trails, eateries, and retail shops with good amenities and access to outdoor activities
    K: 5
    Hotel #1: Nordick's Valley Motel, Score: 0.498665
    Hotel #2: White Mountain Lodge & Suites, Score: 0.487320
    Hotel #3: Trails End Motel, Score: 0.479854
    Hotel #4: Country Comfort Inn, Score: 0.474320
    Hotel #5: Lakefront Captain Inn, Score: 0.457873
    
    --- SYNTHESIZER ---
    Context size: 3233 characters
    
    --- FINAL ANSWER ---
    1. COMPARISON SUMMARY:  
    • Nordick's Valley Motel has the highest rating (4.5) and offers free parking, air conditioning, and continental breakfast. It is located in Washington D.C., near historic attractions and trails.
    • White Mountain Lodge & Suites is a resort with unique amenities like a pool, restaurant, and meditation gardens, but has the lowest rating (2.4). It is located in Denver, surrounded by forest trails.
    • Trails End Motel is budget-friendly with a moderate rating (3.2), free parking, free wifi, and a restaurant. It is close to downtown Scottsdale and eateries.
    
    Key tradeoffs:
    - Nordick's Valley Motel excels in rating and proximity to historic attractions but lacks a pool or free wifi.
    - White Mountain Lodge & Suites offers resort-style amenities and forest trails but has the lowest rating.
    - Trails End Motel balances affordability and essential amenities but has fewer unique features compared to the others.
    
    2. BEST OVERALL:
    Nordick's Valley Motel is the best choice for its high rating, proximity to trails and attractions, and free parking.
    
    3. ALTERNATIVE PICKS:
    • Choose White Mountain Lodge & Suites if you prioritize resort amenities and forest trails over rating.
    • Choose Trails End Motel if affordability and proximity to downtown Scottsdale are your main concerns.
    

Adatok megtekintése és kezelése a Visual Studio Code-ban

  1. Válassza ki a DocumentDB bővítményt a Visual Studio Code-ban az Azure DocumentDB-fiókhoz való csatlakozáshoz.

  2. Az adatok és indexek megtekintése a Hotels adatbázisban.

    A Visual Studio Code DocumentDB bővítmény a vektorkeresési indexet és a szállodai dokumentumokat mutatja.

Erőforrások tisztítása

A törlési paranccsal törölheti a tesztadatbázist, amikor végzett. Futtassa a következő parancsot:

go run cmd/cleanup/main.go

Törölje az erőforráscsoportot, a DocumentDB-fiókot és az Azure OpenAI-erőforrást, ha nincs rájuk szüksége a többletköltségek elkerülése érdekében.