Yapay Zeka Asistanına FHIR R4 Entegrasyonu: NeonCore ile Sağlık Verilerine Türkçe Sorgulama
Yapay Zeka Asistanına FHIR R4 Entegrasyonu: NeonCore ile Sağlık Verilerine Türkçe Sorgulama
Sağlık sektörü, yapay zeka entegrasyonu söz konusu olduğunda diğer sektörlerden farklı bir hassasiyet taşır. Hasta verileri, tanı sonuçları, ilaç kayıtları, bunların hepsi hem yasal hem de etik açıdan son derece titiz bir şekilde ele alınmak zorunda. Bu gerçekten yola çıkarak NeonCore'a FHIR R4 entegrasyonu eklediğimde, amacım sadece teknik bir özellik eklemek değildi. Asıl hedef, Türkiye'deki sağlık profesyonellerine veri gizliliğinden ödün vermeden yapay zeka destekli bir araç sunabilmekti.
Bu yazıda sıfırdan nasıl başladığımı, hangi kararları aldığımı ve TypeScript ile MCP (Model Context Protocol) kullanarak bu entegrasyonu nasıl hayata geçirdiğimi anlatacağım.
FHIR Nedir ve Neden Önemli?
FHIR (Fast Healthcare Interoperability Resources), sağlık verilerinin farklı sistemler arasında standart bir şekilde paylaşılmasını sağlayan uluslararası bir protokoldür. HL7 organizasyonu tarafından geliştirilen bu standart, hasta kayıtlarından ilaç listelerine, laboratuvar sonuçlarından klinik notlara kadar her tür sağlık веrisini REST API üzerinden erişilebilir hale getirir.
R4, FHIR'in şu an üretim ortamlarında en yaygın kullanılan versiyonudur. Amerika'da ONC tarafından zorunlu tutulan bu standart, Türkiye'de de e-Nabız altyapısının temelini oluşturuyor. Yani FHIR R4'ü anlamak, Türkiye sağlık ekosistemiyle entegrasyon için kritik bir başlangıç noktası.
NeonCore'a Neden FHIR Ekledim?
NeonCore, Türkiye'deki profesyoneller için tasarlanmış yerel bir yapay zeka masaüstü asistanı. Hukuk, muhasebe ve sağlık sektörlerini hedefliyorum, çünkü bu üç alan, belge yoğunluğu ve veri gizliliği açısından en yüksek gereksinimlere sahip.
Sağlık kullanıcıları için şu soruyu sormam gerekiyordu: "Bir doktor NeonCore'u açıp 'Smith soyadlı hastaları listele' diyebilmeli mi?" Cevabım evet oldu. Ama bunu güvenli, standart ve genişletilebilir bir şekilde yapmak zorundaydım.
İşte bu noktada FHIR R4 devreye girdi. Mevcut MCP araç altyapımı kullanarak iki yeni tool yazarsam, NeonCore herhangi bir FHIR R4 uyumlu sunucuya sorgu atabilir hale gelecekti.
Geliştirme Yaklaşımı: MCP Tool Olarak FHIR
NeonCore'un arka planında çalışan 7 MCP aracı zaten mevcuttu: okuma, analiz, yazma, dosya oluşturma, kod yazma, PDF ve Excel. Bunların hepsini TypeScript ile server.tool() pattern'i kullanarak yazdım.
FHIR entegrasyonu için de aynı pattern'i tercih ettim. İki yeni tool tanımladım:
fhir_sorgula, FHIR bundle sorguları için. Parametre olarak resource tipi ve filtre alıyor, HAPI public R4 sunucusuna istek atıyor, dönen bundle içindeki entry'leri Türkçe formatlanmış bir çıktıya dönüştürüyor.
fhir_kayit_oku, Tek bir kaydı ID ile çekmek için. Kullanıcı önce fhir_sorgula ile listeyi görüyor, ardından ilgilendiği kaydın ID'sini bu tool'a geçiyor.
typescript
server.tool(
"fhir_sorgula",
"FHIR R4 sunucusunda kaynak sorgular",
{
resource: z.string().describe(
"FHIR kaynak tipi (Patient, Observation vb.)"
),
filtre: z.string().optional().describe(
"Arama filtresi (family=Smith gibi)"
),
},
async ({ resource, filtre }) => {
const base = "https://hapi.fhir.org/baseR4";
const url = filtre
? `${base}/${resource}?${filtre}`
: `${base}/${resource}`;
const res = await fetch(url, {
headers: { Accept: "application/fhir+json" },
});
if (!res.ok) {
return {
content: [{
type: "text",
text: "FHIR sunucusuna bağlanılamadı.",
}],
};
}
const bundle = await res.json();
const entries = bundle.entry ?? [];
if (entries.length === 0) {
return {
content: [{
type: "text",
text: "Sorgu sonucu kayıt bulunamadı.",
}],
};
}
const ozet = entries.map((e: any) => {
const r = e.resource;
const ad = r.name?.[0]?.family ?? "-";
const dogum = r.birthDate ?? "-";
return `ID: ${r.id} | Ad: ${ad} | Doğum: ${dogum}`;
});
return {
content: [{ type: "text", text: ozet.join("\n") }],
};
}
);
Bu yapının güzelliği şu: Gemini 2.5 Flash hangi tool'u ne zaman çağıracağını biliyor. Kullanıcı "Smith soyadlı hastaları getir" dediğinde, model önce fhir_sorgula'yı family=Smith filtresiyle çağırıyor. Kullanıcı bir ID seçtiğinde ise fhir_kayit_oku devreye giriyor.
HAPI Public R4 Sunucusu ile Test
Geliştirme aşamasında gerçek hasta verisi kullanmak hem etik hem yasal açıdan sorunlu olur. Bu nedenin HL7 topluluğunun sunduğu açık test sunucusu olan hapi.fhir.org/baseR4 adresini kullandım. Bu sunucu gerçek yapıda ama anonim test verisi içeriyor, geliştirme ve demo için ideal.
Test sorgularında aldığım sonuçlar şu şekildeydi: Smith soyadına sahip hastalar için gerçek ID'ler, doğum tarihleri ve kayıt tipleri döndü. Ardından tek kayıt sorgusunda ilgili hastanın tüm demografik bilgisini, kayıt tarihini ve kaynak meta verisini Türkçe formatlanmış şekilde görebildim.
Bu aşamada önemli bir şey fark ettim: FHIR bundle'ı parse ederken entry dizisinin her zaman mevcut olmayabileceğini varsaymak hata üretiyor. Bazı kaynak tipleri boş bundle döndürüyor, bazıları entry yerine farklı bir yapı kullanıyor. Bu yüzden her tool'da null check ve fallback mesajı şart.
fhir_kayit_oku Tool'u
typescript
server.tool(
"fhir_kayit_oku",
"Belirtilen ID ile FHIR R4 kaydını getirir",
{
resource: z.string().describe("FHIR kaynak tipi"),
id: z.string().describe("Kaydın FHIR ID'si"),
},
async ({ resource, id }) => {
const base = "https://hapi.fhir.org/baseR4";
const url = `${base}/${resource}/${id}`;
const res = await fetch(url, {
headers: { Accept: "application/fhir+json" },
});
if (!res.ok) {
return {
content: [{
type: "text",
text: `${id} ID'li kayıt bulunamadı.`,
}],
};
}
const k = await res.json();
const ad = k.name?.[0]?.family ?? "-";
const isim = k.name?.[0]?.given?.join(" ") ?? "-";
const detay = [
`Kaynak Tipi: ${k.resourceType}`,
`ID: ${k.id}`,
`Ad: ${ad}, ${isim}`,
`Cinsiyet: ${k.gender ?? "-"}`,
`Doğum Tarihi: ${k.birthDate ?? "-"}`,
`Son Güncelleme: ${k.meta?.lastUpdated ?? "-"}`,
].join("\n");
return {
content: [{ type: "text", text: detay }],
};
}
);
Burada dikkat ettiğim şey şu: Her alanı optional zinciriyle oku, eksik veri varsa tire ile geç. FHIR verisi her zaman eksiksiz gelmiyor, özellikle test sunucularında bazı alanlar boş.
Build Süreci ve src/index.ts Entegrasyonu
NeonCore'un MCP sunucusu src/index.ts dosyasında başlıyor. Yeni tool'ları bu dosyaya ekledikten sonra TypeScript build'ini çalıştırdım:
bash
npm run build
Build başarılı olduğunda Electron uygulamasını yeniden başlattım ve NeonCore arayüzünden ilk sorguyu yaptım: "Smith soyadlı hastaların sağlık kayıtlarından getir." Model anında fhir_sorgula'yı çağırdı, HAPI sunucusundan veri çekti ve Türkçe formatlanmış bir liste sundu.
Bu anı görünce projenin nereye gidebileceğini daha net gördüm. Bir doktor gerçek bir FHIR R4 uyumlu sistem kullanıyorsa ki Türkiye'deki pek çok hastane bilgi sistemi bu standardı destekliyor - NeonCore'u o sisteme point ederek aynı sorgulama deneyimini yaşayabilir.
KVKK ve Veri Güvenliği Boyutu
Bu entegrasyonu geliştirirken sürekli aklımda olan soru şuydu: "Bu veriler nereye gidiyor?"
NeonCore'un mimarisi şu şekilde çalışıyor: Kullanıcının isteği Electron uygulamasından çıkıyor, Express backend'e geliyor, oradan Cloudflare Worker üzerinden OpenRouter'a yönlendiriliyor. OpenRouter, Google Vertex AI'a routing yapıyor. Tüm bu süreçte ZDR (Zero Data Retention) aktif, yani hiçbir veri AI sağlayıcısının sunucularında saklanmıyor.
FHIR sorgusu ise tamamen ayrı bir hat üzerinden çalışıyor: MCP tool doğrudan FHIR sunucusuna istek atıyor, dönen veriyi model bağlamına ekliyor ve bu bağlam sadece o oturuma ait. Dosyalar zaten cihazda kalıyor. Hasta verileri buluta çıkmıyor.
Bu mimari, Türkiye'deki sağlık profesyonelleri için kritik bir avantaj. KVKK kapsamında özel nitelikli kişisel veri sayılan sağlık kayıtlarını herhangi bir cloud AI servisine yüklemek ciddi yasal riskler doğuruyor. NeonCore bu riski mimari düzeyde ortadan kaldırıyor.
Desteklenen FHIR Kaynak Tipleri
Şu an için tool'lar tüm FHIR R4 kaynak tiplerini kabul ediyor çünkü resource parametresi serbest metin. Kullanıcı veya model şunları sorgulayabilir:
Patient — Hasta demografik bilgileri, kimlik numaraları, doğum tarihleri.
Observation — Kan değerleri, vital bulgular, laboratuvar sonuçları. LOINC kodları ile filtreleme mümkün.
Condition — Tanı kayıtları, kronik hastalıklar, ICD-10 kodları.
MedicationRequest — Reçete edilmiş ilaçlar, dozaj bilgileri, prescriber bilgisi.
Encounter — Muayene ve yatış kayıtları, tarih aralıkları, klinik notlar.
Practitioner — Doktor ve sağlık personeli kayıtları.
Bu kaynak tiplerinin kombinasyonu, bir sağlık profesyonelinin günlük iş akışında ihtiyaç duyacağı bilgilerin büyük bölümünü karşılıyor.
Gerçek Kullanım Senaryosu
Bir pratisyen hekim sabah kliniğe geliyor ve NeonCore'u açıyor. Şunu soruyor: "Bugün randevusu olan diyabetik hastaların son HbA1c değerlerini getir."
NeonCore bu isteği şu adımlarla işliyor: Önce fhir_sorgula ile bugünkü Encounter kayıtlarını çekiyor. Sonra her hasta için Observation sorgusu yaparak LOINC kodu 4548-4 olan HbA1c kayıtlarını buluyor. Sonuçları hasta adı, son değer ve ölçüm tarihi ile birlikte Türkçe bir özet olarak sunuyor.
Tüm bu süreç doğal dil üzerinden gerçekleşiyor. Hekim SQL bilmek zorunda değil, API dokümantasyonu okumak zorunda değil. Sadece soruyor, NeonCore cevaplıyor.
Open Health Stack Software Foundation Başvurusu
Bu entegrasyonu tamamladıktan sonra Open Health Stack Software Foundation'a üyelik başvurusu yaptım. OHS-SF, Google ve WHO desteğiyle kurulan ve açık sağlık teknolojilerini destekleyen bir vakıf.
NeonCore'un FHIR R4 uyumluluğu bu başvuru için güçlü bir teknik dayanak oluşturuyor. Türkiye'den bir solo founder olarak uluslararası bir sağlık teknolojileri vakfına başvurmak kolay değil — ama yaptığın işin teknik kalitesi konuşuyor.
Sıradaki Adımlar
Bu entegrasyon ilk adım. Önümde duran birkaç kritik geliştirme var.
İlk olarak, gerçek kurumsal FHIR sunucularıyla bağlantı. HAPI public server test için mükemmel ama production için kurumlar kendi FHIR endpoint'lerini kullanıyor. NeonCore'un sunucu adresini yapılandırılabilir hale getirmek gerekiyor.
İkinci olarak, OAuth 2.0 entegrasyonu. Kurumsal FHIR sunucuları kimlik doğrulama istiyor. SMART on FHIR protokolü, OAuth 2.0 üzerinden FHIR erişimini standartlaştırıyor. Bu katmanı eklemek gerekecek.
Üçüncü olarak, Türkiye'ye özgü profiller. e-Nabız FHIR implementasyonu bazı ulusal uzantılar içeriyor. TC Kimlik numarası, SGK numarası gibi Türkiye'ye özgü alanları desteklemek, yerel entegrasyonlar için şart.
Sonuç
Bir yapay zeka masaüstü asistanına FHIR R4 entegrasyonu eklemek, beklediğimden çok daha az karmaşıktı. Zaten kurulu olan MCP araç altyapısı sayesinde iki yeni tool yazmak yeterliydi. Asıl mesai harcanan yer, veri güvenliği mimarisinin doğru kurulması ve FHIR bundle parse logic'inin sağlam yazılmasıydı.
Türkiye'deki sağlık profesyonelleri, verilerini buluta çıkarmadan yapay zeka kullanabilmeli. Bu hem bir teknik gereksinim hem de bir hak. NeonCore bu ihtiyacı karşılamak için var.
FHIR R4 entegrasyonu bu yolculuğun bir parçası ve daha gidilecek çok yol var.