← Blog

Az AI ügynök ír, az ember küld — így épült a saját CRM-ünk

Péter · 2026. 09. 16.

A hidegmegkeresés nagy része nem levélírás, hanem nyomozás.

Mielőtt megírom az első mondatot egy szabadulószobának, tudnom kell, hogy van-e egyáltalán online foglalásuk, ha van, akkor min fut, hány szobájuk van, egy helyszín-e vagy lánc, és hogy kit érdemes megszólítani. Ez cégenként tíz-tizenöt perc kattintgatás: megnyitni az oldalt, megnézni a forrását, rákeresni a cégjegyzékben, végigpörgetni a közösségi oldalukat. Utána jön a levél, ami öt perc.

Ez a munka nem nehéz. Csak sok. És pontosan olyan, amit egy AI-ügynök el tud végezni - feltéve, hogy van hova beírnia az eredményt.

Így lett a saját értékesítési CRM-ünkből egy olyan rendszer, ahol az AI ügynök ugyanazon a felületen dolgozik, mint az ember.

Miért nem dobozos CRM?

Ez az első kérdés, és jogos. Van sok kiforrott CRM a piacon, olcsóbban, mint amennyibe egy saját fejlesztés kerül.

Két dolog miatt nem működtek volna.

Az egyik a mezők. Nekünk az a legfontosabb adat egy cégről, hogy milyen foglalási rendszert használ. Ez dönti el, hogy érdemes-e megkeresni, és hogy mivel. Egy dobozos CRM-ben ez egy egyedi mező lenne egy legördülőben, amit valaki kézzel tölt ki - ha éppen eszébe jut. Nálunk ez egy külön entitás, saját felsorolt értékkészlettel, a felismerés forrásával, dátumával és megbízhatóságával.

A másik az írási felület. Ha azt akarom, hogy egy ügynök végezze a kutatást, akkor tudnia kell írni a rendszerbe - nem exportálnia egy CSV-t, amit aztán valaki beimportál. A legtöbb CRM erre REST API-t ad, ami elvileg elég, gyakorlatban viszont az ügynöknek kell kitalálnia, melyik végpont mit vár. Ez pontosan az a hibalehetőség, amit nem akartam.

Az alapdöntés: ugyanaz a felület, két kliens

A CRM Symfony 8.1-en fut, API Platform 4.3-mal, a felülete React Admin 5. A REST API nem utólagos kiegészítés: az adminfelület maga is azon keresztül dolgozik, tehát az API az elsődleges, a képernyő csak egy kliens.

A második kliens az ügynök. 36 eszköz Model Context Protocol (MCP) protokollon keresztül, tíz csoportban:

Csoport Eszközök
Cégek 8
Láncok 4
Kapcsolattartók 4
Ügyletek 4
Email 4
Levélsablonok 4
Tudásbázis 3
Jegyzetek 2
Interakciók 2
Keresés 1

A lényeg nem a szám, hanem hogy ezek ugyanazokon az API Platform erőforrásokon mennek keresztül, mint a felület. Ha egy mező kötelező a képernyőn, akkor kötelező az ügynöknek is. Ha egy státuszátmenet tiltott, mindkettőnek tiltott. Nincs két igazság a rendszerben, és nincs olyan validáció, amit egy „AI-integráció” megkerülne.

Két csatlakozási mód van. A helyi fejlesztői gépen stdio, ahogy a Claude Code amúgy is beszél az MCP-szerverekkel. Távolról HTTP, /_mcp végponton, személyes API-kulccsal — a kulcs a profilban készül, egyszer látszik, és bármikor visszavonható.

Egy szabály: az ügynök nem küld

A CRM-ben nincs olyan eszköz, amivel egy ügynök levelet küldhetne. Van draft_email — az ír egy piszkozatot. Nincs send_email.

Ez szándékos döntés, nem óvatoskodás. Az ügynök kiválóan összeszedi, hogy egy adott szabadulószoba mit használ, mekkora, és mi lehet a fájdalompontja. Abban viszont nem bízom, hogy megítélje: ezt a konkrét mondatot ennek a konkrét embernek most el akarom-e küldeni. Ez a döntés marad emberi, és a legegyszerűbb módja ennek az, ha a képességet be sem építem.

A gyakorlatban ez így néz ki: reggel megnyitom a postaláda-nézetet, és ott van öt piszkozat, amit éjjel írt meg valaki, aki nem alszik. Átolvasom, kettőt átírok, egyet kidobok, négyet elküldök. A kutatás megtörtént nélkülem, a döntés nem.

Amit a rendszer magától megtud a cégről

A CRM-ben van egy WebsiteInspector, ami megnyit egy céges weboldalt, és megmondja, mi van mögötte: a webplatform (WordPress, Wix, Squarespace, Webflow, Shopify), a foglalási rendszer - tizenhét rendszert ismer fel jel alapján, a Resovától a Bookeón és a FareHarboron át a Xoláig -, és a kiegészítő eszközök, például a fotórendszer vagy a digitális nyilatkozat.

Nem találgat. Csak olyan jelek alapján dönt, amik egyértelműek: harmadik féltől betöltött asset-domainek és foglalási widget-hosztok. Ha nincs ilyen, akkor az eredmény „nem találtam”, nem pedig egy tipp. Minden találat mellé eltárolja a bizonyítékot is, tehát utólag ellenőrizhető, mi alapján döntött.

A User-Agent. Az első verzió tisztességes bot-azonosítóval kérte le az oldalakat. Rengeteg cégnél „nincs jel” lett az eredmény — aztán kézzel megnéztem párat, és ott virított a foglalási widget. A WordPress-tűzfalak (Wordfence, Sucuri, Cloudflare, SiteGround) egyszerűen 403-mal válaszoltak a botnak. Azóta a scanner normál böngésző-azonosítót küld. Ez alacsony volumenű minősítés, nem crawlelés, szóval szerintem rendben van — de a tanulság általánosabb: ha egy felismerő rendszer csendben „nincs találat”-ot ad, először azt ellenőrizd, hogy egyáltalán látta-e az oldalt.

A halott domain nem halott cég. Sok találatunk „megszűnt”-ként volt megjelölve, mert a weboldaluk nem válaszolt. Kiderült, hogy a szabadulószobák egy része egyszerűen domaint vált, és a régi cím parkolóoldalra fut. A scanner ma felismeri a parkolóoldalakat — a tipikus szövegeket és a parkoltató szolgáltatók hosztjait —, és ilyenkor „parkolt” státuszt ad, nem „elérhetetlent”. A kettő nagyon más döntést von maga után.

Minősítés struktúrában, nem prózában

Az első hónapokban a minősítés egy jegyzetmező volt: „jó lead, Resovát használnak, tulaj elérhető”. Emberként olvasható, gépként használhatatlan. Nem lehet rá szűrni, nem lehet megszámolni, és két különböző napon ugyanazt a céget kétféleképp írtam le.

Ma ez négy strukturált mező: besorolás (forró, jó, gyenge, kizárva, nem minősített), mellette szóló okok, kizáró okok, és egy egysoros indoklás.

A régi leiratot nem dobtam el: írtam egy elemzőt, ami a kézzel írt jegyzetekből kiolvassa a besorolást, és megjelölte azokat, amiket nem tudott értelmezni.

A levelezés ott van, ahol a rekord

Ez volt a legnagyobb egyedi fejlesztés, és utólag a leghasznosabb.

A CRM-ben teljes levelező van: formázott szöveg, aláírás, sablonok, csatolmány, másolat és titkos másolat. A kimenő levél Postmarkon megy, a bejövő webhookon érkezik vissza. A válasz automatikusan a meglévő szálba kerül, a kapcsolattartó státusza átáll, és az interakciót a rendszer naplózza.

Ennek az az értelme, hogy a beszélgetés és a rekord ugyanaz az objektum. Nem kell átváltani a levelezőprogramra, és nem kell utólag beírni a CRM-be, hogy „írtam nekik”. Ami a szálban van, az az előzmény.

Három részlet, amin többet gondolkodtam, mint amire számítottam:

  • Az idézett előzmény. A válaszlevélbe pontosan azt a jelölést generálom, amit a Gmail használ, hogy a címzettnél egyetlen „…” gombbá csukódjon össze, ne pedig kilométeres idézetlánccá.
  • A sablonok nem sablonmotorok. A {{company.name}} helyettesítés egy zárt helyőrzőlista, nem Twig. Aki sablont szerkeszt, az szöveget ír, nem kódot futtat.
  • Webhook sosem kap 5xx-et. Ha a bejövő levél feldolgozása elhasal, akkor is 2xx-szel nyugtázok, és naplózok. A Postmark ugyanis újrapróbálkozik, és egy idő után letiltja a hibázó végpontot.

A felület: egy képernyő, oldalsó panelek

Az adminfelület React Admin, de egy dologban eltér a szokásostól: a cég adatlapja nem fülek sorozata, hanem egy áttekintő képernyő. Fent az azonosító adatok, alatta a felismert technológia és a minősítés, majd a kapcsolattartók és a legutóbbi levelezés, végül füles nézetben az ügyletek, jegyzetek és interakciók.

Szerkeszteni pedig jobbról becsúszó panelben lehet, nem külön oldalon. Ennek egyszerű oka van: telefonálás közben nem akarok navigálni. Amíg beszélek valakivel, a képernyőn kell maradnia annak, amiről beszélünk.

Tanulság

Ha egy rendszert AI-ügynökök is használnak, akkor nem „AI-funkciókat” kell bele építeni, hanem rendes API-t és tisztességes adatmodellt. Az ügynök ugyanattól lesz használható, amitől egy jó integráció: kiszámítható erőforrásoktól, beszédes hibáktól és attól, hogy egy mező jelentése egyértelmű.

A másik: a képességek határa is tervezési döntés. Az, hogy nincs levélküldő eszköz, nem hiányosság a listán. Az a legfontosabb sor a specifikációban.

A következő részben arról írok, hogyan készült erről a rendszerről bemutatóanyag úgy, hogy egyetlen képkocka sincs megrendezve — a képernyőképektől a narrált videóig, mind a futó alkalmazásból.

  • Claude Code
  • MCP
  • Symfony
  • API Platform
  • React Admin
  • Doctrine
  • Postmark

← Olvasnék még