Felo API PlatformFelo API Platform

Felo APIs

Chat API

Dodaj wyszukiwanie konwersacyjne AI z analizą zapytań, źródłami internetowymi i cytowaniami.

POST/v2/chat

Uwierzytelnianie

Bearer API key

Typ zawartości

application/json

Uwagi o limitach

Per API key and per user windows. Read X-RateLimit headers.

API Chat umożliwia integrację wyszukiwania konwersacyjnego opartego na AI z aplikacjami. Wyślij zapytanie w języku naturalnym i otrzymaj inteligentną odpowiedź wygenerowaną na podstawie wyników wyszukiwania w sieci w czasie rzeczywistym.

Informacje o limitach szybkości, odpowiedziach błędów i zachowaniu przy ponawianiu znajdziesz w Błędach, limitach i ponawianiu.

Przegląd

API Chat wykonuje następujące operacje:

  1. Analizuje i optymalizuje zapytanie
  2. Przeszukuje sieć w poszukiwaniu istotnych informacji
  3. Ranguje i filtruje wyniki wyszukiwania
  4. Generuje kompleksową odpowiedź AI na podstawie źródeł
  5. Zwraca odpowiedź wraz z cytowaniami źródeł

Zastosowania:

  • konwersacyjne asystenty AI
  • narzędzia do badań i wyszukiwania informacji
  • chatboty wsparcia klienta z wiedzą z sieci
  • aplikacje edukacyjne
  • narzędzia do tworzenia treści

Uwierzytelnianie

Wszystkie żądania do API Chat wymagają uwierzytelnienia kluczem API. Dołącz klucz API do nagłówka Authorization:

Authorization: Bearer YOUR_API_KEY

Szczegóły uzyskiwania i używania klucza API znajdziesz w przewodniku uwierzytelniania.

Użycie z agentami AI

Zainstaluj kompletny pakiet felo-ai, gdy chcesz, aby agent używał Search i każdego innego dostępnego Felo Skill. Instalator dynamicznie wykrywa każdy katalog pakietu zawierający SKILL.md, więc obejmuje przyszłe Skills, a nie stały podzbiór. Zainstaluj je w natywnym katalogu swojego agenta: Codex używa ~/.codex/skills, Claude Code używa ~/.claude/skills, OpenClaw używa ~/.agents/skills, a Hermes Agent używa ~/.hermes/skills. Bezpieczne dowiązania, klucz API i kroki weryfikacji dla każdej platformy znajdziesz w podręczniku konfiguracji agenta AI.

Endpoint

POST https://openapi.felo.ai/v2/chat

Żądanie

Nagłówki

NagłówekWymaganyOpis
AuthorizationTakTwój klucz API w formacie: Bearer YOUR_API_KEY
Content-TypeTakMusi mieć wartość application/json

Parametry treści

ParametrTypWymaganyOpisOgraniczenia
querystringTakPytanie użytkownika lub zapytanie wyszukiwaniaod 1 do 2000 znaków

Przykładowe żądanie

{
  "query": "What are the latest developments in quantum computing?"
}

Odpowiedź

Odpowiedź sukcesu (200 OK)

Gdy żądanie się powiedzie, API zwraca odpowiedź JSON o następującej strukturze:

{
  "status": "ok",
  "message": null,
  "data": {
    "id": "HabCj883yHLSXc8mWqu4Eq",
    "message_id": "18ea8517-5559-4f48-a355-1f8a79e73b71",
    "answer": "Recent developments in quantum computing include...",
    "query_analysis": {
      "queries": [
        "quantum computing latest developments 2025",
        "quantum computing breakthroughs"
      ]
    },
    "resources": [
      {
        "link": "https://example.com/quantum-news",
        "title": "Latest Quantum Computing Breakthroughs",
        "snippet": "Scientists have achieved a major milestone..."
      },
      {
        "link": "https://example.com/quantum-research",
        "title": "Quantum Computing Research 2025",
        "snippet": "New quantum algorithms show promise..."
      }
    ]
  }
}

Pola odpowiedzi

PoleTypOpis
statusstring | numberStan odpowiedzi: "ok" przy powodzeniu; odpowiedzi błędów używają kodu statusu HTTP jako liczby
messagestring | nullDodatkowy komunikat (null dla skutecznych żądań)
dataobjectDane odpowiedzi (obecne tylko wtedy, gdy status to "ok")
data.idstringUnikalny identyfikator tej sesji czatu
data.message_idstringUnikalny identyfikator tej konkretnej wiadomości
data.answerstringOdpowiedź wygenerowana przez AI na zapytanie
data.query_analysisobjectAnaliza zapytania użytkownika
data.query_analysis.queriesstring[]Zoptymalizowane zapytania wyszukiwania wyprowadzone z danych wejściowych użytkownika
data.resourcesarrayLista źródeł sieciowych użytych do wygenerowania odpowiedzi
data.resources[].linkstringAdres URL źródła
data.resources[].titlestringTytuł strony źródłowej
data.resources[].snippetstringIstotny fragment ze źródła

Odpowiedź błędu

Gdy wystąpi błąd, API zwraca wspólną kopertę błędów:

{
  "status": 401,
  "code": "UNAUTHORIZED",
  "message": "API Key is required",
  "request_id": "..."
}

Pola odpowiedzi błędu

PoleTypOpis
statusnumberKod statusu HTTP; odpowiedzi sukcesu używają "ok"
codestringKod błędu identyfikujący typ błędu
messagestringCzytelny dla człowieka opis błędu
request_idstringUnikalny identyfikator tego żądania (przydatny w pomocy technicznej)

Kody błędów

HTTPKodZnaczenie
400kod walidacji endpointuPole query jest brakujące, puste lub zbyt długie; przeczytaj message, aby poznać konkretny problem
401UNAUTHORIZEDKlucz API jest brakujący, nieprawidłowy lub unieważniony
429RATE_LIMITEDPrzekroczono limit szybkości
502CHAT_FAILEDWewnętrzny błąd usługi
503SERVICE_UNAVAILABLEUsługa tymczasowo niedostępna

Informacje o wspólnej kopercie, innych kodach błędów i zasadach ponawiania znajdziesz w Błędach, limitach i ponawianiu.

Przykłady

cURL

curl -X POST https://openapi.felo.ai/v2/chat \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "What are the benefits of renewable energy?"
  }'

Odpowiedź:

{
  "status": "ok",
  "message": null,
  "data": {
    "id": "HabCj883yHLSXc8mWqu4Eq",
    "message_id": "18ea8517-5559-4f48-a355-1f8a79e73b71",
    "answer": "Renewable energy offers numerous benefits including reduced greenhouse gas emissions, decreased air pollution, energy independence, job creation, and long-term cost savings. Solar, wind, and hydroelectric power are sustainable alternatives to fossil fuels that help combat climate change while providing reliable electricity.",
    "query_analysis": {
      "queries": [
        "renewable energy benefits",
        "advantages of renewable energy sources"
      ]
    },
    "resources": [
      {
        "link": "https://example.com/renewable-benefits",
        "title": "Top Benefits of Renewable Energy",
        "snippet": "Renewable energy sources provide clean, sustainable power..."
      }
    ]
  }
}

Python

import requests
import os

# Get API key from environment variable
api_key = os.environ.get('FELO_API_KEY')

url = 'https://openapi.felo.ai/v2/chat'
headers = {
    'Authorization': f'Bearer {api_key}',
    'Content-Type': 'application/json'
}
data = {
    'query': 'What are the benefits of renewable energy?'
}

try:
    response = requests.post(url, headers=headers, json=data)
    response.raise_for_status()  # Raise exception for HTTP errors

    result = response.json()

    if result['status'] == 'ok':
        print('Answer:', result['data']['answer'])
        print('\nSources:')
        for resource in result['data']['resources']:
            print(f"- {resource['title']}: {resource['link']}")
    else:
        print(f"Error: {result['code']} - {result['message']}")

except requests.exceptions.RequestException as e:
    print(f'Request failed: {e}')

JavaScript (Node.js)

const fetch = require('node-fetch');

const apiKey = process.env.FELO_API_KEY;
const url = 'https://openapi.felo.ai/v2/chat';

const headers = {
  'Authorization': `Bearer ${apiKey}`,
  'Content-Type': 'application/json'
};

const body = JSON.stringify({
  query: 'What are the benefits of renewable energy?'
});

fetch(url, { method: 'POST', headers, body })
  .then(response => {
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return response.json();
  })
  .then(data => {
    if (data.status === 'ok') {
      console.log('Answer:', data.data.answer);
      console.log('\nSources:');
      data.data.resources.forEach(resource => {
        console.log(`- ${resource.title}: ${resource.link}`);
      });
    } else {
      console.error(`Error: ${data.code} - ${data.message}`);
    }
  })
  .catch(error => {
    console.error('Request failed:', error);
  });

JavaScript (przeglądarka/API Fetch)

const apiKey = 'YOUR_API_KEY'; // In production, get this from your backend

fetch('https://openapi.felo.ai/v2/chat', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${apiKey}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    query: 'What are the benefits of renewable energy?'
  })
})
  .then(response => {
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return response.json();
  })
  .then(data => {
    if (data.status === 'ok') {
      console.log('Answer:', data.data.answer);

      // Display sources
      const sourcesList = data.data.resources.map(resource =>
        `<li><a href="${resource.link}">${resource.title}</a></li>`
      ).join('');

      document.getElementById('answer').innerHTML = data.data.answer;
      document.getElementById('sources').innerHTML = sourcesList;
    } else {
      console.error(`Error: ${data.code} - ${data.message}`);
    }
  })
  .catch(error => {
    console.error('Request failed:', error);
  });

Go

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "os"
)

type ChatRequest struct {
    Query string `json:"query"`
}

type ChatResponse struct {
    Status  string `json:"status"`
    Message string `json:"message,omitempty"`
    Data    struct {
        ID            string `json:"id"`
        MessageID     string `json:"message_id"`
        Answer        string `json:"answer"`
        QueryAnalysis struct {
            Queries []string `json:"queries"`
        } `json:"query_analysis"`
        Resources []struct {
            Link    string `json:"link"`
            Title   string `json:"title"`
            Snippet string `json:"snippet"`
        } `json:"resources"`
    } `json:"data,omitempty"`
    Code      string `json:"code,omitempty"`
    RequestID string `json:"request_id,omitempty"`
}

func main() {
    apiKey := os.Getenv("FELO_API_KEY")
    url := "https://openapi.felo.ai/v2/chat"

    requestBody := ChatRequest{
        Query: "What are the benefits of renewable energy?",
    }

    jsonData, err := json.Marshal(requestBody)
    if err != nil {
        fmt.Printf("Error marshaling request: %v\n", err)
        return
    }

    req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
    if err != nil {
        fmt.Printf("Error creating request: %v\n", err)
        return
    }

    req.Header.Set("Authorization", "Bearer "+apiKey)
    req.Header.Set("Content-Type", "application/json")

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        fmt.Printf("Error making request: %v\n", err)
        return
    }
    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        fmt.Printf("Error reading response: %v\n", err)
        return
    }

    var chatResp ChatResponse
    err = json.Unmarshal(body, &chatResp)
    if err != nil {
        fmt.Printf("Error unmarshaling response: %v\n", err)
        return
    }

    if chatResp.Status == "ok" {
        fmt.Println("Answer:", chatResp.Data.Answer)
        fmt.Println("\nSources:")
        for _, resource := range chatResp.Data.Resources {
            fmt.Printf("- %s: %s\n", resource.Title, resource.Link)
        }
    } else {
        fmt.Printf("Error: %s - %s\n", chatResp.Code, chatResp.Message)
    }
}

Limity szybkości

Użytkownicy z aktywną płatną subskrypcją Felo (w tym subskrypcją enterprise) są zwolnieni ze wszystkich limitów szybkości /v2/chat, zarówno przy uwierzytelnianiu kluczem API, jak i OAuth. Zwolnione odpowiedzi nie zawierają nagłówków X-RateLimit-*.

Użytkownicy bez płatnej subskrypcji podlegają limitom szybkości w trzech wymiarach. Jeśli nie można zweryfikować statusu subskrypcji, limity nadal obowiązują:

  • Na klucz API — ogranicza żądania wykonywane jednym kluczem API w oknie 1 minuty.
  • Na użytkownika (minuta) — ogranicza łączne żądania ze wszystkich kluczy API należących do użytkownika w oknie 1 minuty.
  • Na użytkownika (godzina) — ogranicza łączne żądania ze wszystkich kluczy API należących do użytkownika w oknie 1 godziny.

Przekroczenie któregokolwiek wymiaru wywołuje odpowiedź 429 Too Many Requests.

Dokładne wartości liczbowe limitów mogą się zmieniać w czasie. Zawsze odczytuj je z nagłówków odpowiedzi poniżej, a nie z migawek dokumentacji.

Nagłówki odpowiedzi (odpowiedzi podlegające limitom szybkości, w tym 429):

NagłówekZnaczenie
X-RateLimit-LimitLimit najciaśniejszego aktualnie obowiązującego wymiaru
X-RateLimit-RemainingMinimalny pozostały limit spośród trzech wymiarów
X-RateLimit-ResetZnacznik czasu Unix (w sekundach), kiedy resetuje się bieżące okno

Przy 429 dodatkowo:

NagłówekZnaczenie
Retry-AfterZalecane opóźnienie ponowienia (w sekundach)

Przykładowa treść 429 (message odzwierciedla aktualnie skonfigurowane limity w chwili żądania):

{
  "status": 429,
  "code": "RATE_LIMITED",
  "message": "Too many requests. Limit: <N>/min per API key, <M>/min per user, <H>/hour per user.",
  "request_id": "..."
}

Zachowanie klienta: gdy są obecne, odczytuj X-RateLimit-Remaining i wycofuj się proaktywnie. Przy 429 odczekaj co najmniej Retry-After sekund (lub do X-RateLimit-Reset) przed ponowieniem. Nie wpisuj wartości limitów na stałe w kodzie.

Pełne zasady ponawiania i wskazówki dotyczące wycofywania znajdziesz w Błędach, limitach i ponawianiu. Jeśli potrzebujesz wyższych limitów szybkości, skontaktuj się pod adresem [email protected].

Najlepsze praktyki

1. Łagodna obsługa błędów

Zawsze sprawdzaj status odpowiedzi i odpowiednio obsługuj błędy:

if result['status'] == 'ok':
    # Process successful response
    answer = result['data']['answer']
else:
    # Handle error
    error_code = result['code']
    error_message = result['message']
    # Log error, show user-friendly message, etc.

2. Wdrożenie logiki ponawiania

Dla błędów przejściowych (kody statusu 5xx) wdróż wykładnicze opóźnienie:

import time

max_retries = 3
retry_delay = 1  # seconds

for attempt in range(max_retries):
    response = requests.post(url, headers=headers, json=data)

    if response.status_code < 500:
        break  # Success or client error, don't retry

    if attempt < max_retries - 1:
        time.sleep(retry_delay * (2 ** attempt))  # Exponential backoff

3. Buforowanie odpowiedzi

Rozważ buforowanie odpowiedzi dla identycznych zapytań, aby zmniejszyć liczbę wywołań API i skrócić czas odpowiedzi.

4. Walidacja danych wejściowych

Waliduj dane wejściowe użytkownika przed wysłaniem ich do API:

  • upewnij się, że zapytanie nie jest puste
  • sprawdź długość zapytania (od 1 do 2000 znaków)
  • oczyść dane wejściowe, aby zapobiec atakom iniekcji

5. Monitorowanie zużycia

Śledź zużycie API, aby mieścić się w limitach szybkości i optymalizować koszty:

  • zapisuj w logach liczby żądań i czasy odpowiedzi
  • monitoruj wskaźniki błędów
  • skonfiguruj alerty dla nietypowych wzorców

Pomoc

Potrzebujesz pomocy z API Chat?

Historia zmian

v2.0.0 (bieżąca)

  • pierwsze wydanie API Chat
  • obsługa zapytań w języku naturalnym
  • integracja wyszukiwania w sieci w czasie rzeczywistym
  • odpowiedzi generowane przez AI z cytowaniami źródeł