Stwórz agenta do weryfikacji kandydatów na stanowisko lidera w dziedzinie AI w Pythonie przy użyciu FastAPI i Pydantic
Przekształć surowe leady w wyselekcjonowane: strukturyzowane wydobywanie danych za pomocą LLM, walidacja za pomocą Pydantic, ocenianie na podstawie reguł, przechowywanie w PostgreSQL, kolejki oraz proces przeglądu przez człowieka.
Źródła: I Built an AI Lead Filtering Agent in Python — From Raw Leads to Qualified Customers
Większość firm nie cierpi na brak potencjalnych klientów. Ich problemem jest ich weryfikacja. Setki zapytań mogą przychodzić przez formularze internetowe, kampanie e-mailowe i narzędzia marketingowe, a ktoś musi je wszystkie otworzyć, przeczytać wiadomość, zrozumieć, czego chce klient, sprawdzić jego budżet i zdecydować, czy zasługuje na uwagę. W miarę wzrostu ilości takich zapytań ta ręczna selekcja staje się kosztowna.
Prawdziwe pytanie brzmi, czy agent AI może przyjmować przychodzące zapytania, zrozumieć intencję klienta, sprawdzić je pod kątem zasad biznesowych i skierować te odpowiednie do działu sprzedaży. Może to zrobić, ale nie poprzez wklejanie każdego zapytania do modelu językowego i poleganie na jego odpowiedzi. Niezawodny system wymaga ustrukturyzowanych wyników, jasnych zasad, weryfikacji, przechowywania danych oraz sprawnej procedury pracy. Poniższe sekcje pokazują, jak stworzyć taki system w Pythonie.
Co robi system
Proces jest prosty: pojawia się potencjalny klient, system go interpretuje, ocenia, zapisuje wynik i uruchamia następny krok.
Weźmy tę wiadomość od potencjalnego klienta:
"Nasz zespół sprzedaży potrzebuje specjalnie dostosowanego CRM na około 30 użytkowników, który ma zostać dostarczony w ciągu dwóch miesięcy. Ile to mniej więcej będzie kosztować?"
Człowiek od razu wyróżniłby kilka faktów:
- istnieje wyraźna potrzeba biznesowa
- projekt dotyczy oprogramowania dostosowanego pod potrzeby klienta
- zespół ma około 30 użytkowników
- istnieje określony termin dostawy
- kluczowym pytaniem jest koszt
Agent powinien wyróżnić te same fakty i pomóc zespołowi sprzedaży w decydowaniu, co robić dalej. Nie powinien zakładać, że każda szczegółowa wiadomość to dobry potencjalny klient. Musi ocenić informacje pod kątem rzeczywistych kryteriów wyboru firmy.
Architektura
Planowany przepływ pracy przedstawiono poniżej:
┌──────────────────┐
│ Incoming Lead │
│ Website / Email │
└────────┬─────────┘
│
▼
┌──────────────────┐
│ Lead Ingestion │
│ Validate & Store │
└────────┬─────────┘
│
▼
┌──────────────────┐
│ AI Extraction │
│ Intent, Need, │
│ Budget, Timeline │
└────────┬─────────┘
│
▼
┌──────────────────┐
│ Business Rules │
│ Qualification │
└────────┬─────────┘
│
▼
┌──────────────────┐
│ Lead Scoring │
│ Qualified / │
│ Review / Reject │
└────────┬─────────┘
│
▼
┌──────────────────┐
│ PostgreSQL │
│ Store Result │
└────────┬─────────┘
│
▼
┌──────────────────┐
│ Automation │
│ CRM / Email / │
│ Sales Notification│
└──────────────────┘
Jedna decyzja projektowa ma największe znaczenie: trzeba oddzielić zrozumienie AI od decyzji biznesowych. LLM wydobywa informacje z leadu, natomiast twój własny kod decyduje, w jaki sposób te informacje wpływają na ocenę kwalifikacji. Dzięki takiemu podziałowi system jest łatwiejszy do testowania, naprawiania i modyfikowania.
Krok 1: Zdecyduj, co kwalifikuje leada
Zasady biznesowe przychodzą przed kodem. Weźmy za przykład agencję rozwoju oprogramowania – może ona uznać leada za kwalifikującego się wtedy, gdy:
- klient ma rzeczywisty wymóg dotyczący oprogramowania
- wymóg odpowiada usługom oferowanym przez agencję
- wiadomość zawiera wystarczająco dużo szczegółów, aby zrozumieć projekt
- budżet lub intencja zakupu spełniają wymagania agencji
- wiadomość nie jest spamem ani wyraźnie nieistotnym zapytaniem
Te zasady mają charakter ilustracyjny, a rzeczywisty biznes powinien ustalić własne progi. Wypełniony rekord może wyglądać tak: usługa to dostosowanie CRM, budżet wynosi 500 000 ₹, termin realizacji to dwa miesiące, liczba użytkowników w firmie to 30, intensywność potrzeb jest wysoka, a decyzja jest uzasadniona.
Sztuczna inteligencja powinna wydobyć dane. Ostateczną decyzję powinny podjąć zasady biznesowe.
Krok 2: Stworzenie projektu w Pythonie
Python nadaje się do tego zadania dzięki swojemu ekosystemowi obejmującemu API, integracje z LLM, przetwarzanie danych oraz automatyzację. Struktura projektu wygląda w ten sposób:
ai-lead-agent/
│
├── app/
│ ├── main.py
│ ├── config.py
│ │
│ ├── agents/
│ │ └── lead_agent.py
│ │
│ ├── schemas/
│ │ └── lead.py
│ │
│ ├── services/
│ │ ├── lead_service.py
│ │ └── scoring_service.py
│ │
│ └── db/
│ └── database.py
│
├── tests/
│ └── test_scoring.py
│
├── requirements.txt
└── .env
Zainstaluj wymagane pakiety:
pip install openai pydantic fastapi uvicorn python-dotenv
Komponenty to:
- FastAPI do API backendu
- Pydantic do strukturalnej walidacji
- API OpenAI do przykładu z LLM
- PostgreSQL jako baza danych produkcyjna
- zwykły Python do oceny potencjalnych klientów
Dostawcę LLM można później zastąpić innym.
Krok 3: Zdefiniuj strukturalny schemat potencjalnych klientów
Powszechnym błędem w aplikacjach AI jest przyjmowanie tekstu wolnego jako wyniku końcowego. Taką odpowiedź trudno jest przetwarzać w sposób niezawodny:
This looks like a good lead.
The customer wants a CRM and seems interested.
Celem jest przewidywalny JSON. Stwórz plik app/schemas/lead.py i zacznij od importów:
from typing import Optional, Literal
from pydantic import BaseModel, Field
Następnie zdefiniuj modele, począwszy od przychodzącego potencjalnego klienta, a następnie przechodząc do analizy, którą model musi zwrócić:
class LeadInput(BaseModel):
name: str
email: str
company: Optional[str] = None
message: str
class LeadAnalysis(BaseModel):
summary: str service_type: Optional[str] = None intent: Literal[
"high",
"medium",
"low",
"unknown"
] budget: Optional[float] = None currency: Optional[str] = None timeline: Optional[str] = None is_spam: bool = False missing_information: list[str] = Field(
default_factory=list
) qualification_notes: str recommended_action: Literal[
"contact_sales",
"request_more_information",
"reject",
"manual_review"
]
Teraz odpowiedź AI ma określony kształt. Jeśli model zwróci nieważną wartość, aplikacja może ją odrzucić lub ją przetworzyć, zamiast po cichu przechowywać błędne dane.
Krok 4: Stworzenie funkcji analizy leadów
Następnie przychodzi plik app/agents/lead_agent.py. Model powinien interpretować to, co mówi lead, i nie może wymyślać niczego, czego nie ma. Zacznijmy od importów:
import json
import os
Następnie przychodzi sama funkcja analizy. Wysyła dane do modelu, prosi o wynik zgodny ze schematem i weryfikuje to, co wraca:
from openai import OpenAIfrom app.schemas.lead import (
LeadInput,
LeadAnalysis
)
client = OpenAI(
api_key=os.getenv("OPENAI_API_KEY")
)
SYSTEM_PROMPT = """
You are a lead analysis assistant for a software
development agency.Your task is to analyze incoming customer leads.Extract:
- Customer requirement
- Service type
- Buying intent
- Budget if explicitly mentioned
- Timeline if explicitly mentioned
- Spam indicators
- Missing informationRules:
1. Never invent a budget.
2. Never invent a timeline.
3. If information is missing, return null.
4. Return valid structured JSON.
5. Do not make a final business decision based
only on assumptions.
"""
def analyze_lead(lead: LeadInput) -> LeadAnalysis: user_prompt = f"""
Analyze this incoming lead: Name: {lead.name}
Email: {lead.email}
Company: {lead.company}
Message: {lead.message}
""" response = client.chat.completions.create(
model="gpt-4o-mini",
temperature=0,
response_format={
"type": "json_object"
},
messages=[
{
"role": "system",
"content": SYSTEM_PROMPT
},
{
"role": "user",
"content": user_prompt
}
]
) result = json.loads(
response.choices[0].message.content
) return LeadAnalysis.model_validate(result)
Dlaczego temperatura wynosi zero
Przy ekstrakcji potrzebna jest spójność, a nie kreatywny styl pisania. Niska temperatura zmniejsza zmienność odpowiedzi, ale nie gwarantuje ich poprawności. Dlatego nadal konieczna jest weryfikacja schematu oraz reguły biznesowe.
Nazwy modeli i funkcje API również zmieniają się z czasem. Przy wdrażaniu rozwiązania w środowisku produkcyjnym wybierz model oraz metodę strukturyzowanego wyjścia, które są obecnie obsługiwane przez twojego dostawcę.
Krok 5: Dodanie reguł kwalifikacji
Tę część nie należy w całości powierzać modelowi językowemu. Załóżmy, że przykładowe kryteria agencji są następujące:
- projekt stanowi istotną pracę nad oprogramowaniem
- jeśli podano budżet, to wynosi on co najmniej ₹2,00,000
- wiadomość nie jest spamem
- istnieje wystarczająco dużo informacji, aby zrozumieć wymagania
Stwórz plik app/services/scoring_service.py, zaczynając od importu:
from app.schemas.lead import LeadAnalysis
Następnie funkcja oceny, która zaczyna się od zera, zbiera powody każdej korekty i zwraca natychmiast zero dla spamu:
def score_lead(analysis: LeadAnalysis) -> dict: score = 0
reasons = [] if analysis.is_spam:
return {
"score": 0,
"status": "rejected",
"reasons": ["Spam detected"]
} if analysis.service_type:
score += 25
reasons.append(
"Service requirement identified"
) if analysis.intent == "high":
score += 30
reasons.append(
"High buying intent"
) elif analysis.intent == "medium":
score += 15
reasons.append(
"Medium buying intent"
) if analysis.budget is not None:
if analysis.budget >= 200000:
score += 25
reasons.append(
"Budget meets example threshold"
)
else:
reasons.append(
"Budget below example threshold"
) if analysis.timeline:
score += 10
reasons.append(
"Timeline provided"
) if analysis.missing_information:
score -= 10
reasons.append(
"Some information is missing"
) score = max(0, min(score, 100)) if score >= 70:
status = "qualified" elif score >= 40:
status = "review" else:
status = "unqualified" return {
"score": score,
"status": status,
"reasons": reasons
}
To jest prosty, ilustracyjny schemat oceniania. Rzeczywista agencja może brać pod uwagę inne czynniki:
- rozmiar projektu
- sektor przemysłowy
- lokalizacja
- dostępność usługi
- pilność żądania klienta
- poprzednia współpraca
- pewność co do podanego budżetu
- powtórne zapytania
Przed tym, jak pozwolić systemowi automatycznie odrzucać zapytania, przetestuj funkcję oceniania na rzeczywistych przykładach.
Krok 6: Połączenie agenta z FastAPI
Stwórz plik app/main.py i zaimportuj FastAPI:
from fastapi import FastAPI
Pozostała część pliku łączy schemat, funkcję analizy oraz usługę oceniania za pośrednictwem jednego punktu końcowego:
from app.schemas.lead import LeadInput
from app.agents.lead_agent import analyze_lead
from app.services.scoring_service import score_lead
app = FastAPI(
title="AI Lead Filtering Agent"
)
@app.get("/health")
def health_check():
return {
"status": "ok"
}
@app.post("/analyze-lead")
def analyze_incoming_lead(
lead: LeadInput
): analysis = analyze_lead(lead) score = score_lead(analysis) return {
"lead": lead,
"analysis": analysis,
"qualification": score
}
Rozpocznij serwer:
uvicorn app.main:app --reload
Następnie otwórz interaktywne dokumentacje API:
http://127.0.0.1:8000/docs
Stamtąd możesz wysłać lead i przejrzeć strukturalną odpowiedź.
Krok 7: Spróbuj zrealistowanego leadu
Wyślij próbny wniosek taki jak ten:
{
"name": "Rahul Sharma",
"email": "rahul@example.com",
"company": "Example Technologies",
"message": "We need a custom CRM for around 30 users. Our budget is approximately 500000 INR and we want to launch within 2 months."
}
Prawdopodobny wynik wydobywania wygląda następująco:
{
"summary": "Customer needs a custom CRM.",
"service_type": "CRM development",
"intent": "high",
"budget": 500000,
"currency": "INR",
"timeline": "2 months",
"is_spam": false,
"missing_information": [],
"qualification_notes": "Clear requirement, budget, and timeline.",
"recommended_action": "contact_sales"
}
Usługa oceny następnie analizuje wydobyte dane, przy czym wynik wygląda następująco:
{
"score": 90,
"status": "qualified",
"reasons": [
"Service requirement identified",
"High buying intent",
"Budget meets example threshold",
"Timeline provided"
]
}
Należy pamiętać, że ten wynik jest jedynie ilustracją tego, czego można się spodziewać, a nie pomiarem uzyskanym podczas rzeczywistego uruchomienia API.
Krok 8: Przechowywanie leadów w PostgreSQL
Dla rzeczywistego zastosowania biznesowego przechowywanie wyników wyłącznie w pamięci nie wystarcza, dlatego konieczna jest trwałość danych. Prosta tabela wygląda w ten sposób:
CREATE TABLE leads (
id BIGSERIAL PRIMARY KEY,
Pozostałe kolumny zawierają szczegóły lidera oraz analizę:
name VARCHAR(150) NOT NULL, email VARCHAR(255) NOT NULL, company VARCHAR(255), message TEXT NOT NULL, service_type VARCHAR(255), intent VARCHAR(20), budget NUMERIC(14, 2), currency VARCHAR(10), timeline VARCHAR(100), is_spam BOOLEAN DEFAULT FALSE, ai_score INTEGER, qualification_status VARCHAR(30), analysis JSONB, created_at TIMESTAMPTZ DEFAULT NOW()
);
Kolumna analysis przechowuje oryginalny, ustrukturyzowany wynik generowany przez sztuczną inteligencję, co jest przydatne, gdy musisz zdiagnozować, dlaczego dany lead otrzymał określoną klasifikację.
Dla środowiska produkcyjnego należy również zaplanować:
- unikalny identyfikator dla każdego leadu
- sposób wykrywania duplikatów
- indeksy obejmujące status i czas utworzenia
- szifrowanie oraz ścisłą kontrolę dostępu, ponieważ dane leadów są wrażliwe
- migracje schematu
- ślad audytowy
Krok 9: Dodanie automatyzacji
W tym momencie agent staje się czymś więcej niż zwykłą API. Wyobraź sobie ten przepływ:
New Lead
│
▼
Save in PostgreSQL
│
▼
Analyze with AI
│
▼
Calculate Qualification
│
├── Qualified ────────► Notify Sales
│
├── Review ───────────► Human Review Queue
│
└── Unqualified ─────► Store for Reporting
Gdy pojawi się kwalifikowany lead, system może:
- przechować go w bazie danych
- poinformować zespół sprzedaży
- stworzyć rekord w CRM
- przydzielić przedstawiciela sprzedaży
- umówić się na kolejne spotkanie
- aktualizować status leada
Słoj automatyzacji może stanowić n8n, proces w tle lub system oparty na kolejce. W środowisku produkcyjnym nie jest rozsądne polegać w całości na jednym synchronicznym żądaniu HTTP. Lepszy projekt umieszcza kolejkę pomiędzy poszczególnymi etapami:
Lead API
│
▼
Message Queue
│
▼
Background Worker
│
▼
AI Analysis
│
▼
Database
│
▼
Automation
Leady są następnie przetwarzane asynchronicznie, a nieudane zlecenia można spróbować ponownie.
Krok 10: Dodanie przeglądu przez człowieka
To może być najważniejszy element. Sztuczna inteligencja może błędnie zinterpretować leada. Rozważmy następującą wiadomość:
"W tej chwili porównujemy opcje CRM i nie ustaliliśmy budżetu, choć chcielibyśmy mieć pojęcie o cenach."
Model może oznaczyć intencję jako średnią lub wysoką, podczas gdy firma woli skierować leada do osoby zamiast automatycznie uznać go za odpowiedniego. Dlatego istnieją trzy statusy:
- Odpowiedni: lead spełnia wymagania i trafia do zespołu sprzedaży.
- W przeglądzie: lead zawiera przydatne informacje, ale decyzję powinien podjąć człowiek.
- Nieodpowiedni: lead nie spełnia ustawionych kryteriów.
Przegląd przez człowieka jest najbardziej pomocny wtedy, gdy:
- nie podano budżetu
- potrzeba jest niejasna
- model wydaje się niepewny swojego wyniku
- detale w wiadomości są ze sobą sprzeczne
- nadawca działa w branży, której firma nie obsługuje
Dobry system AI nie ukrywa niepewności. Uczynia ją widoczną.
Co czyni to agentem
Zwykłe wezwanie LLM to po prostu dane wejściowe, model, wynik:
Input → LLM → Output
Przepływ pracy agenta robi o wiele więcej. Rozumie przychodzące zadanie, wydobywa istotne informacje, stosuje narzędzia lub zasady biznesowe, wybiera następny krok, przechowuje stan, uruchamia działanie oraz próbuje ponownie lub eskaluje sytuację, gdy coś się psuje. Dla filtru leadów pełna ścieżka wygląda w ten sposób:
Incoming Lead
│
▼
AI Analysis
│
▼
Business Rules
│
▼
Qualification Decision
│
▼
Action / Human Review
Sztuczna inteligencja to tylko jeden z elementów. Aplikacja backendowa sprawia, że cały proces jest niezawodny, a ta różnica ma znaczenie.
Ulepszenia przed wdrożeniem
Pierwsza wersja wystarcza, aby zobaczyć przepływ pracy, ale nie powinna trafiać do użytkowników w takim stanie.
Przetwarzanie w tle. Wykonuj analizę leadów za pomocą kolejki zadań, takiej jak Celery z Redis, RQ, zarządzanej chmurą kolejki lub systemu zadań opartego na bazie danych. To ułatwia ponawianie prób i obsługę dużych ilości danych.
Wykrywanie duplikatów. Jeden lead może pojawić się dwa razy – raz z strony internetowej, a raz z kampanii e-mailowej. Porównuj adres e-mail, nazwę firmy oraz inne identyfikatory.
Wersjonowanie promptów. Przechowuj wersję promptu obok każdego wyniku generowanego przez sztuczną inteligencję. Gdy zmienią się kryteria, można wtedy określić, który prompt i reguły doprowadziły do wcześniejszego wyniku.
Obserwowalność. Śledź opóźnienia w działaniu AI, błędy API, użycie tokenów, koszt za potencjalnego klienta, rozkład wyników weryfikacji oraz to, jak często ludzie przejmują kontrolę nad agentem.
Zbiór danych do oceny. Zbieraj rzeczywiste potencjalne klientów z etykietami sprawdzonymi przez ludzi i testuj system na ich podstawie. To mówi o wiele więcej niż ocena agenta na podstawie jednego dobrego przykładu.
Bезpieczeństwo. Unikaj umieszczania kluczy API w kodzie frontendu, sprawdzaj każdą przychodzącą prośbę, chronij dane osobowe i ogranicz dostęp do informacji o potencjalnych klientach.
Lekcja z architektury
Budowa agenta AI to nie tylko wywoływanie modelu LLM. Prawdziwa inżynieria dotyczy samego modelu: jasnego problemu biznesowego, ustrukturyzowanych danych, niezawodnej weryfikacji, reguł deterministycznych, zachowania danych, automatyzacji, ludzkiej oceny oraz monitoringu. Bez tych elementów powstaje chatbot, który wydaje się inteligentny, ale nie rozwiązuje problemu biznesowego.
Filtr leadów nie powinien jedynie generować odpowiedzi – powinien tworzyć przydatny, śledzalny proces pracy. Model rozumie nieuporządkowane wiadomości klientów, Python uruchamia ten proces, reguły biznesowe określają kryteria kwalifikacji, PostgreSQL przechowuje dane, a automatyzacja łączy wynik z zespołem sprzedaży. Razem przekształcają one demonstrację AI w działającą aplikację.
Naturalnym krokiem jest połączenie API z rzeczywistym źródłem leadów, dodanie zadań w tle oraz stworzenie panelu kontrolnego, który umożliwi sprzedaży sprawdzanie, które leady są odpowiednie. Celem nie jest zastąpienie każdej decyzji sprzedażowej sztuczną inteligencją, lecz zmniejszenie ilości powtarzalnej pracy, aby pracownicy mogli skupić się na leadach, które na to zasługują.