项目文件夹

文件

Sampling - uddelegér funktioner til klienten

Nogle gange har du brug for, at MCP-klienten og MCP-serveren samarbejder for at opnå et fælles mål. Du kan have en situation, hvor serveren har brug for hjælp fra en LLM, der kører på klienten. Til denne situation er sampling det, du skal bruge.

Lad os udforske nogle anvendelsestilfælde og hvordan man bygger en løsning, der involverer sampling.

Oversigt

I denne lektion fokuserer vi på at forklare, hvornår og hvor man skal bruge sampling, og hvordan man konfigurerer det.

Læringsmål

I dette kapitel vil vi:

  • Forklare hvad sampling er, og hvornår det skal bruges.
  • Vise, hvordan man konfigurerer sampling i MCP.
  • Give eksempler på sampling i brug.

Hvad er sampling, og hvorfor bruge det?

Sampling er en avanceret funktion, der fungerer på følgende måde:

sequenceDiagram
    participant User
    participant MCP Client
    participant LLM
    participant MCP Server

    User->>MCP Client: Forfatter blogindlæg
    MCP Client->>MCP Server: Værktøjskald (udkast til blogindlæg)
    MCP Server->>MCP Client: Prøvetagningsanmodning (opret resumé)
    MCP Client->>LLM: Generer blogindlægsresumé
    LLM->>MCP Client: Resumé resultat
    MCP Client->>MCP Server: Prøvetagningssvar (resumé)
    MCP Server->>MCP Client: Færdigt blogindlæg (udkast + resumé)
    MCP Client->>User: Blogindlæg klar

Sampling anmodning

Ok, nu har vi et overordnet overblik over et troværdigt scenarie, lad os tale om sampling-anmodningen, som serveren sender tilbage til klienten. Her er, hvordan sådan en anmodning kan se ud i JSON-RPC format:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "sampling/createMessage",
  "params": {
    "messages": [
      {
        "role": "user",
        "content": {
          "type": "text",
          "text": "Create a blog post summary of the following blog post: <BLOG POST>"
        }
      }
    ],
    "modelPreferences": {
      "hints": [
        {
          "name": "claude-3-sonnet"
        }
      ],
      "intelligencePriority": 0.8,
      "speedPriority": 0.5
    },
    "systemPrompt": "You are a helpful assistant.",
    "maxTokens": 100
  }
}

Der er et par ting her værd at fremhæve:

  • Prompt, under content -> text, er vores prompt, som er en instruktion til LLM om at opsummere indholdet af et blogindlæg.

  • modelPreferences. Denne sektion er netop det, en præference, en anbefaling af, hvilken konfiguration der skal bruges med LLM. Brugeren kan vælge, om de vil følge disse anbefalinger eller ændre dem. I dette tilfælde er der anbefalinger om model at bruge samt prioritering af hastighed og intelligens.

  • systemPrompt, det er din normale systemprompt, som giver din LLM en personlighed og indeholder vejledende instruktioner.

  • maxTokens, er en anden egenskab, der bruges til at angive, hvor mange tokens der anbefales brugt til denne opgave.

Sampling svar

Dette svar er, hvad MCP-klienten ender med at sende tilbage til MCP-serveren, og er resultatet af klientens kald til LLM, venter på det svar og derefter konstruerer denne meddelelse. Her er, hvordan det kan se ud i JSON-RPC:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "role": "assistant",
    "content": {
      "type": "text",
      "text": "Here's your abstract <ABSTRACT>"
    },
    "model": "gpt-5",
    "stopReason": "endTurn"
  }
}

Bemærk, hvordan svaret er en abstrakt udgave af blogindlægget, lige som vi bad om. Bemærk også, hvordan den anvendte model ikke er den, vi bad om, men "gpt-5" over "claude-3-sonnet". Dette illustrerer, at brugeren kan ændre mening om, hvad der skal bruges, og at din sampling-anmodning er en anbefaling.

Ok, nu hvor vi forstår hovedflowet, og en nyttig opgave at bruge det til er "oprettelse af blogindlæg + abstrakt", lad os se, hvad vi skal gøre for at få det til at fungere.

Beskedtyper

Sampling-beskeder er ikke begrænset til bare tekst, men du kan også sende billeder og lyd. Her er, hvordan JSON-RPC ser anderledes ud:

Tekst

{
  "type": "text",
  "text": "The message content"
}

Billedindhold

{
  "type": "image",
  "data": "base64-encoded-image-data",
  "mimeType": "image/jpeg"
}

Lydindhold

{
  "type": "audio",
  "data": "base64-encoded-audio-data",
  "mimeType": "audio/wav"
}

NOTE: for mere detaljeret info om Sampling, se den officielle dokumentation

Sådan konfigureres Sampling i klienten

Bemærk: hvis du kun bygger en server, behøver du ikke gøre meget her.

I en klient skal du angive følgende funktion sådan her:

{
  "capabilities": {
    "sampling": {}
  }
}

Dette vil så blive registreret, når din valgte klient initialiseres med serveren.

Eksempel på Sampling i aktion - Opret et blogindlæg

Lad os kode en sampling-server sammen, vi skal gøre følgende:

  1. Opret et værktøj på serveren.
  2. Det pågældende værktøj skal oprette en sampling-anmodning.
  3. Værktøjet skal vente på, at klientens sampling-anmodning besvares.
  4. Derefter skal værktøjets resultat produceres.

Lad os se på koden trin for trin:

-1- Opret værktøjet

python

@mcp.tool()
async def create_blog(title: str, content: str, ctx: Context[ServerSession, None]) -> str:
    """Create a blog post and generate a summary"""

-2- Opret en sampling-anmodning

Udvid dit værktøj med følgende kode:

python

post = BlogPost(
        id=len(posts) + 1,
        title=title,
        content=content,
        abstract=""
    )

prompt = f"Create an abstract of the following blog post: title: {title} and draft: {content} "

result = await ctx.session.create_message(
        messages=[
            SamplingMessage(
                role="user",
                content=TextContent(type="text", text=prompt),
            )
        ],
        max_tokens=100,
)

-3- Vent på svaret og returner svaret

python

post.abstract = result.content.text

posts.append(post)

# returner det komplette produkt
return json.dumps({
    "id": post.title,
    "abstract": post.abstract
})

-4- Fuld kode

python

from starlette.applications import Starlette
from starlette.routing import Mount, Host

from mcp.server.fastmcp import Context, FastMCP

from mcp.server.session import ServerSession
from mcp.types import SamplingMessage, TextContent

import json


from uuid import uuid4
from typing import List
from pydantic import BaseModel


mcp = FastMCP("Blog post generator")

# app = FastAPI()

posts = []

class BlogPost(BaseModel):
    id: int
    title: str
    content: str
    abstract: str

posts: List[BlogPost] = []

@mcp.tool()
async def create_blog(title: str, content: str, ctx: Context[ServerSession, None]) -> str:
    """Create a blog post and generate a summary"""

    post = BlogPost(
        id=len(posts) + 1,
        title=title,
        content=content,
        abstract=""
    )

    prompt = f"Create an abstract of the following blog post: title: {title} and draft: {content} "

    result = await ctx.session.create_message(
        messages=[
            SamplingMessage(
                role="user",
                content=TextContent(type="text", text=prompt),
            )
        ],
        max_tokens=100,
    )

    post.abstract = result.content.text

    posts.append(post)

    # returnerer det komplette blogindlæg
    return json.dumps({
        "id": post.title,
        "abstract": post.abstract
    })

if __name__ == "__main__":
    print("Starting server...")
    # mcp.kør()
    mcp.run(transport="streamable-http")

# kør app med: python server.py

-5- Test det i Visual Studio Code

For at teste dette i Visual Studio Code, gør følgende:

  1. Start server i terminalen

  2. Tilføj den til mcp.json (og sørg for, at den er startet), f.eks. sådan her:

    "servers": {
       "blog-server": {
         "type": "http",
         "url": "http://localhost:8000/mcp"
       }
    }
    
  3. Skriv en prompt:

    create a blog post named "Where Python comes from", the content is "Python is actually named after Monty Python Flying Circus"
    
  4. Tillad sampling at ske. Første gang du tester dette, vil du blive præsenteret for en ekstra dialog, som du skal accepterer, derefter vil du se den normale dialog, der beder dig om at køre et værktøj.

  5. Inspicer resultaterne. Du vil se resultaterne både flot gengivet i GitHub Copilot Chat, men du kan også inspicere det rå JSON-svar.

Bonus. Visual Studio Code-værktøjet har god støtte til sampling. Du kan konfigurere sampling-adgang på din installerede server ved at navigere til den sådan her:

  1. Naviger til udvidelsessektionen.
  2. Vælg tandhjulsikonet for din installerede server under sektionen "MCP SERVERS - INSTALLED".
  3. Vælg "Configure Model Access", her kan du vælge, hvilke modeller GitHub Copilot må bruge, når sampling udføres. Du kan også se alle sampling-anmodninger, der er sket for nylig ved at vælge "Show Sampling requests".

Opgave

I denne opgave skal du bygge en lidt anderledes sampling, nemlig en sampling-integration, der understøtter generering af en produktbeskrivelse. Her er dit scenarie:

Scenarie: Backoffice-medarbejderen hos en e-handelsvirksomhed har brug for hjælp, det tager alt for lang tid at generere produktbeskrivelser. Derfor skal du bygge en løsning, hvor du kan kalde et værktøj "create_product" med "title" og "keywords" som argumenter, og det skal producere et komplet produkt inklusive et "description"-felt, der skal udfyldes af en LLM på klienten.

TIP: brug det, du lærte tidligere, til at konstruere denne server og dens værktøj ved hjælp af en sampling-anmodning.

Løsning

Løsning

Vigtige pointer

Sampling er en kraftfuld funktion, der gør det muligt for serveren at uddelegere opgaver til klienten, når den har brug for hjælp fra en LLM.

Hvad er det næste


Ansvarsfraskrivelse: Dette dokument er blevet oversat ved hjælp af AI-oversættelsestjenesten Co-op Translator. Selvom vi bestræber os på nøjagtighed, skal du være opmærksom på, at automatiserede oversættelser kan indeholde fejl eller unøjagtigheder. Det originale dokument på dets oprindelige sprog bør betragtes som den autoritative kilde. For kritisk information anbefales professionel menneskelig oversættelse. Vi påtager os intet ansvar for misforståelser eller fejltolkninger, der opstår som følge af brugen af denne oversættelse.