Vai al contenuto principale
Caricare fonti statiche come dati di addestramento per i tuoi agenti IA è utile – ma cosa fare quando il tuo database è enorme, fortemente strutturato, ospitato esternamente o aggiornato in tempo reale?
Non esiste un modo pratico per caricare l’intero database nella libreria di conoscenza statica di INNOCHAT mantenendo allo stesso tempo una connessione live
È proprio qui che entra in gioco il Function Calling.
Tramite il Function Calling puoi fornire al tuo agente IA in INNOCHAT dati on-demand durante una conversazione in corso.
In questo esempio mostriamo come realizzare un arricchimento RAG con abstract di pubblicazioni scientifiche provenienti da un aggregatore esterno: l’API di Semantic Scholar.

Configurazione e test della funzione

Innanzitutto hai bisogno di una chiave API del tuo fornitore di dati esterno, se offre un’API protetta.
Nel nostro caso abbiamo richiesto una chiave direttamente a Semantic Scholar.
Poiché vogliamo arricchire le risposte del LLM con informazioni dalla ricerca scientifica, dobbiamo individuare l’endpoint API corretto per la ricerca.
Semantic Scholar fornisce una buona documentazione.

Cosa restituisce questo endpoint?

Per ispezionare la risposta abbiamo scritto un piccolo script che esegue una richiesta con parametri fissi.
Il codice sorgente è riportato qui sotto.
Avrai bisogno della tua chiave API se vuoi provarlo tu stesso.
Nell’esempio cerchiamo lavori rilevanti su “Multifidelity Optimization” e “Gaussian Processes”:
import requests
import json
import os

# Set up the headers with the API key
headers = {
    'X-API-KEY': "LA TUA CHIAVE API"
}

# Specify the fields you want to fetch for each recommended paper
fields = "paperId,title,authors,abstract,url,referenceCount"

# Define the limit for the number of recommendations to return
limit = 20

# Make the request to get paper recommendations
response = requests.get(
    'https://api.semanticscholar.org/graph/v1/paper/search',
    headers=headers,
    params={'fields': fields, 'limit': limit, 'query':'multifidelity optimization, gaussian processes' }
)

# Check if the request was successful
if response.status_code == 200:
    print(json.dumps(response.json(), indent=2))
else:
    print(f"Error: {response.status_code}")
    print(response.text)
L’output assomiglia approssimativamente a questo:
{
  "total": 12096,
  "offset": 0,
  "next": 20,
  "data": [
    {
      "paperId": "b108e6e11f4a96d5058945f3b582a032e8204ade",
      "url": "https://www.semanticscholar.org/paper/b108e6e11f4a96d5058945f3b582a032e8204ade",
      "title": "Multifidelity Gaussian processes for failure boundary andprobability estimation",
      "abstract": "...",
      "referenceCount": 49,
      "authors": [
        { "authorId": "98543101", "name": "Ashwin Renganathan" },
        { "authorId": "144321616", "name": "Vishwas Rao" },
        { "authorId": "143672238", "name": "Ionel M. Navon" }
      ]
    },
    {
      "paperId": "963a5c60ada159d27641a284008f57d6419b26f2",
      "url": "https://www.semanticscholar.org/paper/963a5c60ada159d27641a284008f57d6419b26f2",
      "title": "Generative Transfer Optimization for Aerodynamic Design",
      "abstract": "...",
      "referenceCount": 16,
      "authors": [
        { "authorId": "2149505113", "name": "Zhendong Guo" },
        ...
      ]
    }
    ...
  ]
}
La funzione di Semantic Scholar restituisce i primi N risultati per rilevanza in base ai nostri parametri di ricerca. Come vedi, la risposta può essere piuttosto voluminosa; qui è stata abbreviata per motivi di spazio. Idealmente il tuo endpoint restituisce una risposta JSON ben strutturata, come sopra. La nostra analisi di questo endpoint (con i campi richiesti) mostra: Ogni risultato occupa in media 400–500 token. A seconda del limite di token riservato per gli output delle funzioni, potrai inserire nel contesto del LLM solo un numero limitato di risultati. Tienilo presente quando decidi quali informazioni dare priorità al LLM. Ora sappiamo cosa riceve il LLM come contesto aggiuntivo tramite il Function Call e possiamo collegarlo al nostro agente innoChat.
È SEMPRE consigliabile scrivere il tuo script e testare preventivamente la risposta dell’API. Devi sapere esattamente quali informazioni verranno trasmesse al tuo agente IA.

Creare e preparare l’agente IA

Nel tuo chatbot innoChat devi prima creare un agente IA adatto che riceverà questa capacità di Function Calling. Nel nostro esempio l’agente si chiama “The Professor”. Definiamo una descrizione dell’agente e un prompt di base.
Utilizziamo qui il modello GPT-4-0125-8k. Il prompt semplice è visibile nella schermata qui sotto:
Successivamente salviamo l’agente e passiamo alla scheda Knowledge per disattivare il RAG statico proveniente dalla libreria di conoscenza interna. Questo è necessario solo se non vuoi utilizzare fonti di addestramento statiche. Nel nostro esempio non abbiamo comunque caricato dati di addestramento, ma lo disattiviamo per maggiore chiarezza.
Salva l’agente.

Configurare la funzione

All’interno dell’agente vai nella scheda Functions. Imposta Response Context Limit al valore massimo consentito e clicca su Add function.
Qui spieghi al LLM: cosa fa la funzione come deve essere chiamata quali parametri si aspetta Il LLM deciderà autonomamente quando ha bisogno della funzione e con quali parametri chiamarla.
Il nome e la descrizione della funzione sono essenziali affinché l’IA comprenda lo scopo. Scrivi una descrizione chiara e dettagliata. Non deve superare i 1024 caratteri (spazi inclusi). Nel nostro caso:
Function name: paper_relevance_search

Function description: 
Questa funzione ricerca in Semantic Scholar, un database di letteratura scientifica. I parametri di input saranno definiti in base alle informazioni estratte dal contesto della conversazione. Restituisce risultati di ricerca contenenti metadati degli articoli (con abstract) in formato JSON.
I campi restituiti sono i seguenti:
- title: titolo dellarticolo
- abstract: abstract dellarticolo
- paperId: uuid dellarticolo
- authors: autori dellarticolo
- year: anno di pubblicazione
- url: link allarticolo
- referenceCount: numero di riferimenti inclusi nellarticolo
- citationCount: numero di citazioni di questo articolo


Definire l’endpoint API

L’endpoint di Semantic Scholar che utilizziamo è:
https://api.semanticscholar.org/graph/v1/paper/search

Utilizziamo il metodo HTTP GET. La documentazione del tuo endpoint indica se devi usare GET, POST, ecc.

Parametri fissi (Fixed Parameters)

I parametri fissi rimangono uguali per tutte le chiamate API. Rappresentano impostazioni globali (formato, campi attivi, funzionalità…). Alcune API richiedono che questi parametri siano aggiunti direttamente all’URL. Nel nostro esempio Semantic Scholar non servono parametri fissi. Un endpoint più complesso come: https://app.outscraper.com/api-docs#tag/Businesses-and-POI/paths/~1maps~1search-v3/get potrebbe apparire così:
https://api.app.outscraper.com/maps/search-v3?async=false&fields=name,full_address,phone,site

Headers e autenticazione

Le API pubbliche ma sicure richiedono quasi sempre autenticazione. Semantic Scholar non fa eccezione. Trasmettiamo la nostra chiave API negli headers. Il nome del campo header dipende dal fornitore. Nel nostro esempio si chiama x-api-key:

Parametri variabili

Passiamo ora ai parametri variabili (dinamici). Questi parametri dipendono dalla richiesta corrente dell’utente e vengono determinati in fase di esecuzione. Il LLM estrae dal dialogo stesso i valori da impostare e decide se e come effettuare la chiamata alla funzione. Per la nostra funzione definiamo:
{
  "type": "object",
  "properties": {
    "query": {
      "type": "string",
      "description": "Le parole chiave, nomi di autori o ID esatti degli articoli da cercare"
    },
    "fields": {
      "type": "string",
      "description": "Le informazioni da restituire, di default: 'title,abstract,paperId,authors,year,url,referenceCount,citationCount'"
    },
    "limit": {
      "type": "string",
      "description": "Il numero di articoli desiderati, di default 2. Usa il valore predefinito in tutti i casi."
    }
  },
  "required": [
    "query"
  ]
}

Punti importanti: In cima c’è “type”: “object” – l’intero set di parametri è un oggetto JSON. Sotto properties definisci ogni parametro con tipo e descrizione. type può essere string, integer, boolean, array, ecc. La description spiega precisamente al LLM cosa rappresenta il parametro (e possibilmente i valori di default). Più sei chiaro qui, meno è probabile che il LLM scelga valori errati. Esempio di schema più complesso con array:
{
  "type": "object",
  "properties": {
    "tags": {
      "type": "array",
      "description": "etichette da assegnare alla richiesta dell’utente",
      "items": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Il nome dell’etichetta"
          },
          "color": {
            "type": "string",
            "description": "Il colore dell’etichetta"
          }
        },
        "required": ["name", "color"]
      }
    }
  },
  "required": ["tags"]
}

La funzione verrà chiamata solo quando tutti i parametri elencati in required sono disponibili. Se ne manca anche solo uno, la chiamata non può essere eseguita. Una buona riferimento allo standard JSON Schema: https://json-schema.org/understanding-json-schema/reference/type

Testare il chatbot

Una volta configurato tutto: Salva la funzione Salva l’agente Passa alla scheda Preview
Puoi attivare la Debug Mode in alto a destra. Questo ti permette di vedere se e come è stata chiamata la funzione e quali dati sono tornati:
Ed ecco fatto: il tuo agente IA è ora connesso con successo a dati on-demand provenienti da un fornitore esterno. In futuro forniremo anche una guida su come implementare e ospitare una tua funzione di ricerca database personalizzata e integrarla successivamente con innoChat.