# AI Ajanlarını Kurumsal Sistemlere (ERP/CRM) Güvenle Bağlamak: LLM’ler için Idempotent API, Outbox Pattern ve Hata Tolerans Mimarisi (Blueprint)

ERP siparişi oluşturdu. Ajan bunu bilmiyor. Çünkü kayıt commit edildikten sonra bağlantı zaman aşımına uğradı. Modelin önünde bir hata mesajı var; deponun önünde ise gerçek bir sipariş. Ajan yeni bir tool çağrısı üretip aynı işi tekrar denediğinde problem artık halüsinasyon değil, aynı niyetin iki ticari işleme dönüşmesidir.

RAG sistemlerinde yanlış cevap önemli bir kalite sorunudur. Yazma yetkili ajanlarda yanlış veya tekrar eden işlem, stok ayırabilir, CRM kaydını değiştirebilir, iade başlatabilir ya da satış ekibine iki ayrı iş açabilir. Bu blueprint, modelin önerisini kalıcı bir kurumsal işleme dönüştüren sınırı tasarlar. Tek senaryomuz, onaylanmış bir müşteri siparişinin web/API katmanından ERP’ye taşınması; CRM bildirimi aynı protokolün ayrı tüketicisidir.

Önerdiğimiz temel sözleşme şu: model bir işlem önerir; güvenilir servis kimliği, yetkiyi, güncel iş kurallarını ve onayı doğrular; işlem kararlı bir iş niyeti altında kabul edilir; yerel kayıt ile outbox aynı transaction’da yazılır; dış teslimat tekrar edebilir, fakat alıcı aynı ticari etkiyi yeniden üretmez. “Exactly once” ifadesini bu sınırlar belirtilmeden kullanmıyoruz.

Bu yazıda gerçekten çalıştırdığımız bir deney de var. TankDev’in VPS’inde ayrı bir PostgreSQL veritabanı ve loopback HTTP uç noktalarıyla 3.600 yük isteği ve yedi doğruluk senaryosu yürüttük. Kaynak, ham gecikme örnekleri ve sonuç JSON’u indirilebilir. Bu deney LLM üretimi, AWS API Gateway veya gerçek bir müşteri ERP’si üzerinde çalışmadı; ölçülen şey idempotent komut kabulü ile transaction/inbox davranışıdır.

## 1. Önce doğru çözümü seçmek: Prompt, RAG, fine-tuning ve agentik iş akışı

Güncel fiyatı bilmeyen modelin sorunu her zaman daha iyi prompt değildir. Model doğru ürünü buluyor ama siparişi iki kez açıyorsa da fine-tuning bu hatanın sınırını değiştirmez. Aşağıdaki matris, hangi bileşenin hangi problemi üstlendiğini ayırır. Yöntemler birlikte kullanılabilir; özellikle yazma akışı, diğer üç yöntemin üzerine bir işlem güvenliği katmanı gerektirir.

Karar matrisi: yöntem, maliyet, gecikme ve kurulum

| Yöntem | Ne zaman? | Maliyet profili | Gecikme profili | Kurulum beklentisi | Çözmediği sınır |
| --- | --- | --- | --- | --- | --- |
| Prompt engineering | Talimat, çıktı biçimi ve görev tanımı eksik | Düşük başlangıç; her çağrının token maliyeti sürer | Ek retrieval yok; uzun prompt yine süreyi artırabilir | Saatler–birkaç gün | Güncel kurumsal veri, yetki veya duplicate write çözmez |
| RAG | Yanıtın güncel ve izinli kaynaklara dayanması gerekiyor | İndeksleme + depolama + retrieval + inference | Retrieval/reranking eklenir; ölçülmelidir | Birkaç gün–birkaç hafta | Kaynağın doğruluğu veya yazma atomikliği garantisi vermez |
| Fine-tuning | Etiketli örneklerle tekrar eden davranış/biçim hatası var | Veri hazırlığı + eğitim + değerlendirme + inference | Modele bağlı; otomatik olarak daha hızlı değildir | Haftalar; veri hazır değilse daha uzun | Canlı stok/fiyat kaynağı ve işlem dedup mekanizması değildir |
| Agentik iş akışı | Araç kullanımı, çok adımlı karar ve kurumsal aksiyon gerekiyor | Orkestrasyon + araçlar + retry + onay/işletim | Birden fazla çağrı ve kuyruk beklemesi; ayrı bütçe gerekir | Haftalar–aylar; ERP sözleşmesine bağlı | Policy, idempotency, outbox ve reconciliation olmadan güvenli yazma sağlamaz |

Kurulum süreleri; kullanılabilir API, erişilebilir veri ve küçük bir başlangıç kapsamı için planlama aralıklarıdır, deney sonucu veya teklif değildir. ERP’ye erişim izni, etiketli veri ve kabul testleri takvimi değiştirebilir. Gecikme sütununda evrensel milisaniye rakamı vermememizin nedeni de budur: model, bağlam, araç ve ağ aynı olmadan yöntemleri sayısal olarak sıralamak yanıltır. Matrisi [Markdown olarak kopyalayabilirsiniz](/uploads/blog/agent-write-decision-matrix.tr.md).

RAG ile fine-tuning ayrımını [ilgili rehberimiz](/tr/blog/rag-mi-fine-tuning-mi), ajanların rol ve state tasarımını ise [TypeScript/LangGraph mimarimiz](/tr/blog/typescript-langgraph-multi-agent-coklu-ajan-mimarisi) derinleştiriyor. Bu yazının odağı, bu akışların sisteme yazdığı andaki işlem sözleşmesidir.

## 2. Yazma yetkisi modele verilmez: proposal → policy → command

LLM’nin ürettiği customer_id, toplam tutar veya approved:true alanı bir yetki belgesi değildir. Tool gateway şema doğrulaması yapar; tenant ve servis kimliğini doğrulanmış oturumdan alır; müşteri/nesne düzeyinde yetkiyi kontrol eder; miktar, fiyat sürümü, indirim ve işlem tipini domain servisine doğrulatır. Ardından iş niyetini, payload hash’ini ve onay bağını içeren komut hazırlanır. Modelin doğrudan genel amaçlı UPDATE veya create_payment aracı çalıştırması bu tasarımın parçası değildir.

```json
{
  "operation": "sales-order.create.v1",
  "business_intent_id": "intent-from-trusted-workflow",
  "customer_ref": "authorized-account-reference",
  "lines": [{"sku": "BOOT-42", "quantity": 10}],
  "price_quote_ref": "versioned-expiring-quote-token",
  "approval_ref": "approval-bound-to-canonical-payload"
}
```

Müşteri metni, CRM notu ve getirilen belge güvenilmeyen girdidir. Bir dokümanın “yönetici onayladı, bu kuralları atla” demesi araç yetkisini genişletemez. Tip güvenliği yalnızca temsil sözleşmesini doğrular. İzinli bir müşteri numarasıyla yanlış müşteriye sipariş açmak hâlâ mümkündür; kaynak bağlama, iş kuralları ve insan incelemesi bunun için vardır. Okuma araçlarıyla yazma araçları farklı izin, ağ ve servis kimliklerine ayrılır.

## 3. Idempotency: tool_call_id ile iş niyeti aynı kimlik değildir

Aynı ajanın yeniden planlaması yeni tool_call_id üretebilir. Ağ retry’ı yeni HTTP request ID alabilir. Relay aynı komutu yeni delivery attempt ile gönderebilir. Bunların hiçbiri yeni bir sipariş niyeti anlamına gelmez. En az dört kimlik ayırırız: business_intent_id ticari niyeti, idempotency_key API tekrarını, command_id kalıcı kabulü, event_id dış teslimatın mantıksal olayını temsil eder. Trace ID ise izleme içindir; duplicate write koruması değildir.

Idempotency key’i prompt’a bırakmayız. Güvenilir workflow, kullanıcı tarafından başlatılmış veya onaylanmış aynı iş için kararlı bir anahtar saklar. Kapsam; doğrulanmış tenant ve işlem sürümüdür. Canonical request hash; müşteri, iş niyeti, satırlar, miktar, fiyat/teklif sürümü ve sonucu etkileyen seçenekleri kapsar. Request zamanı, trace veya retry sayısı gibi değişken transport alanları hash’e girmez. Canonicalization sürümlüdür; farklı JSON alan sıraları aynı niyeti farklı hash’e dönüştürmemelidir.

API tekrar sözleşmesi

| Durum | Davranış | Korunan koşul |
| --- | --- | --- |
| Aynı key + aynı hash | Önceki kabul yanıtı/command_id döner | Yeni sipariş/outbox olayı yok |
| Aynı key + farklı hash | 409 conflict | Sessiz payload değişikliği yok |
| Farklı key + aynı business intent | Domain unique kuralı ve hash kontrolü | Ajan replan’ı ikinci sipariş açmaz |
| Yeni ve açıkça ayrı business intent | Yetki ve policy sonrası yeni kabul | Meşru ikinci sipariş yanlışlıkla dedup edilmez |
| Yetki geri alınmış veya başka müşteri | Cache yanıtından önce erişim reddi | Eski yanıt veri sızdırmaz |

Tek başına ürün/miktar hash’ini key yapmak da yanlıştır: müşteri aynı ürünü yarın yeniden sipariş edebilir. Benzer metinleri otomatik “aynı niyet” sayan semantik dedup, ticari kararı sessizce değiştirebilir. Kalıcı iş niyeti açıkça oluşturulmalı; hash bu niyetin içeriğinin değişmediğini sınamalıdır. [HTTP semantiğindeki idempotent yöntemler](https://www.rfc-editor.org/rfc/rfc9110.html#section-9.2.2) ile POST uç noktanızın uygulama sözleşmesi de ayrı şeylerdir; header adı tek başına garanti oluşturmaz.

Stripe gibi API’lerin [idempotent request sözleşmeleri](https://docs.stripe.com/api/idempotent_requests) yararlı örneklerdir, fakat response saklama ve hata tekrar semantiği API sürümüne göre değişebilir. Kendi ERP adapter’ımızda “tekrar denemek güvenli” sonucunu yalnızca karşı sistemin belgelenmiş davranışından ve testinden çıkarırız.

## 4. PostgreSQL transaction ve Outbox Pattern: iki yazıyı aynı karara bağlamak

Önce DB’ye sipariş yazıp sonra broker’a publish edersek iki işlem arasındaki crash olayı kaybettirir. Önce publish edip DB commit’i başarısız olursa tüketici olmayan bir siparişi işleyebilir. Outbox, yerel sipariş ve aktarım niyetini aynı transaction’a koyar. Bu kapsam [AWS transactional outbox rehberinde](https://docs.aws.amazon.com/prescriptive-guidance/latest/cloud-design-patterns/transactional-outbox.html) de açıklanır. Broker’a veya ERP’ye iletim hâlâ tekrar edebilir; outbox bunu ortadan kaldırmaz.

```sql
CREATE TABLE command_receipts (
  id uuid PRIMARY KEY,
  tenant_id uuid NOT NULL,
  operation_version text NOT NULL,
  idempotency_key text NOT NULL,
  customer_ref text NOT NULL,
  request_hash text NOT NULL,
  accepted_response jsonb,
  UNIQUE (tenant_id, operation_version, idempotency_key)
);
CREATE TABLE sales_orders (
  id uuid PRIMARY KEY,
  tenant_id uuid NOT NULL,
  operation_version text NOT NULL,
  business_intent_id uuid NOT NULL,
  request_hash text NOT NULL,
  state text NOT NULL,
  UNIQUE (tenant_id, operation_version, business_intent_id)
);
CREATE TABLE outbox_events (
  event_id uuid PRIMARY KEY,
  aggregate_id uuid NOT NULL REFERENCES sales_orders(id),
  event_type text NOT NULL,
  schema_version integer NOT NULL,
  payload jsonb NOT NULL,
  published_at timestamptz,
  UNIQUE (aggregate_id, event_type, schema_version)
);
```

```sql
-- Authentication, object authorization and approved-payload checks precede this.
BEGIN;
INSERT INTO command_receipts
  (id, tenant_id, operation_version, idempotency_key, customer_ref, request_hash)
VALUES (:command_id, :tenant, :operation, :key, :customer, :hash)
ON CONFLICT DO NOTHING RETURNING id;

-- No inserted row: use a NEW statement at READ COMMITTED to read the
-- committed receipt, recheck access/hash, and return its stored acknowledgement.
-- Conflict hash => rollback and 409. Do not execute the domain write again.

INSERT INTO sales_orders
  (id, tenant_id, operation_version, business_intent_id, request_hash, state)
VALUES (:order_id, :tenant, :operation, :intent, :hash, 'PENDING_ERP')
ON CONFLICT DO NOTHING RETURNING id;

-- New key but existing intent: compare the existing order hash and reuse
-- that order, or reject 409. Insert an event ONLY for a newly created order.
INSERT INTO outbox_events
  (event_id, aggregate_id, event_type, schema_version, payload)
VALUES (:event_id, :order_id, 'sales-order.accepted', 1, :payload);
UPDATE command_receipts SET accepted_response=:response WHERE id=:command_id;
COMMIT;
-- No remote model/ERP call inside this transaction.
```

Bu SQL kritik dalları yorumla gösteren bir sözleşme taslağıdır; bütün dalları koşulsuz sırayla çalıştıran script değildir. Çalıştırılabilir laboratuvar kaynağında yeni receipt, tekrar receipt, farklı key/aynı intent ve rollback dalları ayrıdır. Unique constraint eşzamanlı yarışın hakemidir; uygulamada “SELECT yoksa INSERT” kontrolü yeterli olmaz. [PostgreSQL ON CONFLICT](https://www.postgresql.org/docs/16/sql-insert.html) davranışı ve kullanılan isolation düzeyi birlikte değerlendirilmelidir.

POST yanıtı bizim sözleşmemizde 202 Accepted ve kararlı command/order kimlikleridir. ERP’nin siparişi uyguladığı anlamına gelmez. Retry aynı kabul yanıtını alır; güncel durum ayrı, yetkili GET üzerinden okunur. Böylece ilk kabul ile dış tamamlanma aynı başarı kelimesine sıkıştırılmaz. Idempotency kaydı, retry ve replay penceresinden önce silinmez; retention dolunca aynı key’in yeniden kullanılma riski ayrıca yönetilir. Uzun ömürlü business-intent kaydı veya tombstone bu ikinci savunmayı koruyabilir.

## 5. Kopyalanabilir mimari: ajanı işlem motorundan ayırmak

Şema Mermaid kaynak kodu olarak verilmiştir. Yazma yolu, modelin içinde saklanan bir tool loop değildir; ayrı izlenebilir servis sınırları vardır. Aynı akış sipariş, CRM aktivitesi veya uygun sözleşmeyle iade talebi için uyarlanabilir. Mimarinin kaynağını kendi dokümantasyonunuzda korumak isterseniz TankDev blueprint bağlantısını açıklamayla birlikte kullanabilirsiniz.

```mermaid
flowchart LR
    A["LLM proposes a business action"] --> G["Tool gateway: schema and authorization"]
    G --> P["Policy, approval, stable intent"]
    P --> D["PostgreSQL transaction"]
    D --> C["Command receipt + order + outbox"]
    C --> R["Relay: bounded retry, lease, fencing"]
    R --> E["ERP receiver: idempotent operation"]
    E --> S["Confirmed external reference"]
    E -->|"ambiguous outcome"| X["Reconciliation or human review"]
    P -->|"not authorized"| H["Reject without business write"]
```

Relay, yalnız commit edilmiş outbox kayıtlarını alır. Bir kaydı süreli lease ile sahiplenir; ağ çağrısı transaction dışında yapılır. Sonuç yazılırken sahiplik token’ı kontrol edilir. Lease’i bitmiş worker’ın geç cevabı yeni worker’ın durumunu ezemez; fencing token dış sistemde yapılmış çağrıyı geri alamaz. Süre aşımı, attempt bütçesi ve “en eski teslim edilmemiş olay” alarmı aynı işletim sözleşmesine girer.

Broker zorunlu başlangıç bileşeni değildir. Küçük hacimde PostgreSQL outbox poller ve sınırlı worker yeterli olabilir. Bağımsız tüketiciler, retention/replay veya yüksek olay hacmi gerekiyorsa broker değerlendirilir. Kafka ya da RabbitMQ kullanmak, haricî ERP ile kendiliğinden ortak transaction kurmaz. Worker ve rate-limit tasarımını [asenkron LLM mimarisi yazımız](/tr/blog/event-driven-yapay-zeka-mimarisi-asenkron-llm-worker-kafka-rabbitmq) tamamlar.

```mermaid
sequenceDiagram
    autonumber
    participant A as Agent
    participant G as Command API
    participant D as Local PostgreSQL
    participant R as Outbox relay
    participant E as ERP receiver
    A->>G: POST, stable key and intent
    G->>D: Commit receipt, order and outbox
    D-->>G: Accepted command ID
    G--xA: Response lost after commit
    A->>G: Retry same key and payload
    G->>D: Read existing receipt, verify hash
    D-->>G: Original acceptance
    G-->>A: 202 with original identifiers
    R->>D: Claim committed outbox event
    R->>E: Deliver stable event ID
    E->>E: Commit inbox and business record
    E--xR: Acknowledgement lost
    R->>E: Redeliver same event ID
    E-->>R: Same external result, no second write
```

## 6. Inbox tam olarak nerede? Legacy ERP’de sınırın bittiği yer

Alıcı inbox’ı, event_id ve payload hash’ini tutar. Aynı event_id aynı hash ile gelirse önceki sonucu döndürür; farklı hash ile gelirse conflict/karantina gerekir. Inbox kaydı ve ticari yazı aynı yerel transaction’da yapılabiliyorsa alıcı o transaction sınırında duplicate etkiyi engelleyebilir. Deneyimizdeki ERP benzetimi tam olarak böyle çalışır.

Adapter’ın kendi DB’sine inbox yazıp uzak ERP API’sini çağırmak aynı garanti değildir. ERP başarılı olduktan sonra adapter ölürse kendi inbox’ı tamamlanmamış olabilir. Güvenilir seçenek; ERP’nin idempotent işlem desteği, ERP içinde unique external_reference ve atomik kayıt veya üreticinin desteklediği eşdeğer transaction sözleşmesidir. “Önce sorgula, yoksa oluştur” akışı da karşı tarafta unique/atomik koruma olmadan yarışabilir.

Bunlar yoksa belirsiz sonucu UNKNOWN_EXTERNAL durumuna alırız. Dış referansla sorgulama, mutabakat ve gerektiğinde insan incelemesi gerekir. Yeni anahtar üreterek yeniden create çağırmak veya “exactly once entegrasyon” demek güvenilir çözüm değildir. ERP’nin yazma sözleşmesi yetersizse bazı işlemleri otomatikleştirmemek doğru mimari karar olabilir.

Bir siparişin sonraki cancel/update olayları için de aggregate sürümü gerekir. Eski update yeni durumu ezmemeli; per-aggregate sıralama, expected version veya conflict incelemesi tasarlanmalıdır. Event ID dedup tek başına yanlış sırada uygulanmış iki farklı olayı düzeltmez. CRM aktarımı ERP aktarımından bağımsız başarısız olabilir; tek bir “tamamlandı” bayrağı bu ayrımı gizlememelidir.

## 7. Hata tolerans karar matrisi: neyi yeniden denemeliyiz?

Ajan yazma yolunda hata ve kurtarma kararı

| Belirti | Ne biliyoruz? | Güvenli sonraki adım | Kaçınılacak davranış |
| --- | --- | --- | --- |
| Schema / domain reddi | İş kabul edilmedi | Girdiyi düzelt veya kullanıcıya sor | Aynı hatayı sınırsız retry |
| 401/403 | Yetki yok veya geçersiz | Kimlik/izin sorununu çöz | Modelin farklı araçla kuralı aşması |
| Aynı key, değişmiş hash | İş kimliği altında içerik değişti | 409; yeni iş/onay kararını açık ver | Önceki kaydı sessiz overwrite |
| POST timeout | Kabul gerçekleşmiş olabilir | Aynı key ile sonucu sorgula/tekrar al | Yeni key ile yeni sipariş |
| ERP timeout | Dış etki belirsiz | Dış referans ve reconciliation | Körü körüne create |
| Geçici 429/5xx | Kota veya servis geçici sorunlu olabilir | Hata sınıfı + Retry-After + bounded backoff | Her 429’u geçici saymak |
| Policy/teklif sürümü değişti | Eski onay güncel içeriği kapsamıyor | Yeniden doğrulama/onay | Onayı yeni fiyata taşımak |
| İş kısmen tamamlandı | Bazı dış etkiler oluştu | Saga/telafi veya inceleme | Dağıtık işlemi yerel ROLLBACK sanmak |

LLM API limitleri ile ERP yazma limiti farklı bütçelerdir. Birincide token ve request kotası, ikincide kabul edilen iş/işlem sayısı önemlidir. Run genelinde toplam süre, token, attempt ve maliyet sınırı tutulur. SDK, ajan framework’ü, HTTP proxy ve worker aynı işi ayrı ayrı retry ederse çarpan oluşur. Retry’ın sahibi belirlenir; diğer katmanların davranışı sürüm bazında kontrol edilir.

Örneğin [OpenAI rate-limit belgeleri](https://developers.openai.com/api/docs/guides/rate-limits), başarısız isteklerin kota tüketebileceğini, geçerli Retry-After değerinin dikkate alınmasını ve uygulama/SDK retry’larının birlikte sınırlandırılmasını anlatır. Fatura veya kullanım limiti hatası beklemekle düzelmeyebilir. Bu sağlayıcı davranışını her LLM’e genellemeyiz; adapter kendi hata kodu ve header sözleşmesini uygular.

```text
fallback_delay = random(0, min(cap, base * 2^attempt))
delay = max(valid_retry_after, fallback_delay)
retry only if attempt_budget AND job_deadline allow it

For enterprise writes:
  preserve business_intent_id, command key and external reference
  classify UNKNOWN_EXTERNAL before deciding to repeat a side effect
  never restart the full LLM workflow merely to resend a committed event
```

Ödeme alınmış ama ERP siparişi reddetmişse telafi, veritabanında satır silmek değildir. İş kuralı; rezervasyon bırakma, ödeme iptali/iade talebi veya operasyon incelemesi isteyebilir. Telafi komutunun da ayrı ve kararlı kimliği, yetkisi, onayı ve idempotency sözleşmesi olmalıdır. Sevk edilmiş ürünü “rollback” etmek fiziksel dünyada mümkün değildir.

## 8. TankDev deneyinden gerçek ölçümler: 3.600 HTTP isteği ve yedi hata senaryosu

Deney 5 Kasım 2026 tarihinde Europe/Istanbul saat diliminde çalıştırıldı; ham dosyada UTC başlangıcı 4 Kasım 21:16:35 olarak bulunur. Üretim tablolarına dokunmayan ayrı bir veritabanı kullanıldı. İş verileri sentetiktir. HTTP istemcisi ve ASGI sunucusu aynı Python sürecinde, PostgreSQL ayrı süreçte çalıştı. Gerçek ERP yerine inbox ile sipariş benzetimini aynı transaction’da yazan yerel alıcı kullanıldı.

Tekrarlanabilir ortam ve yük sözleşmesi

| Bileşen | Gerçek ayar |
| --- | --- |
| Makine | 2 mantıksal CPU; 8.326.615.040 byte RAM; paylaşılan VPS |
| İşlem sınırı | Lab süreci: 1 CPU eşdeğeri kota, 512 MiB memory limit |
| Runtime | Python 3.12.3; asyncpg 0.31.0; HTTPX 0.28.1; Uvicorn 0.38.0 |
| DB | PostgreSQL 16.15; fsync=on; synchronous_commit=on; shared_buffers=128MB |
| Ağ | Aynı host, loopback HTTP; TLS/proxy/broker yok |
| Yük | 50 warm-up; 3 tur × (1.000 yeni + 200 tekrar); 200 offered request/s; en fazla 8 in-flight |
| Ölçüm | Nearest-rank p50/p95/p99; istemci scheduling beklemesi ayrı |
| Kapsam dışı | LLM/RAG üretimi, WAN, AWS Gateway, gerçek ERP, production RBAC ve process-kill kurtarması |

Üç turun tamamı: gecikmeler ms, CPU süresi saniye

| Tur | Yeni p50 | Yeni p95 | Yeni p99 | Tekrar p95 | Scheduling p95 | HTTP/s | Lab CPU s |
| --- | --- | --- | --- | --- | --- | --- | --- |
| 1 | 2.995 | 4.223 | 13.104 | 2.869 | 1.075 | 200.051 | 2.766954 |
| 2 | 3.078 | 4.14 | 7.219 | 3.394 | 1.071 | 200.077 | 2.791978 |
| 3 | 2.931 | 3.884 | 4.724 | 2.747 | 1.066 | 200.044 | 2.665606 |

3.000 yeni isteğin ham örnekleri birlikte sıralandığında p50 3,003 ms, p95 4,102 ms, p99 7,629 ms çıktı. 600 tekrar isteğinde p95 3,064 ms idi. Ölçülen yük isteklerinde HTTP hatası görülmedi ve her turda 1.000 sipariş ile 1.000 outbox kaydı doğrulandı. Bunlar kısa, sınırlı yük koşusunun sonuçlarıdır; üretim SLO’su veya maksimum kapasite kanıtı değildir.

Yaklaşık 200 HTTP/s değeri yük üreticisinin hedefidir; “sunucu en fazla 200 alır” veya “gerçek ERP’de aynı hız elde edilir” sonucu çıkmaz. İlk istek t=0’da gönderildiği için kısa pencere hesabında 200’ün biraz üstü görülebilir. Scheduling beklemesini gizlemedik. İstemci round-trip ve scheduling p95 değerlerini toplayıp yeni bir end-to-end p95 de üretmedik; yüzdelikler bu şekilde toplanmaz.

Gerçek transaction ve kontrollü yanıt kaybı testleri

| Senaryo | Gözlenen sonuç |
| --- | --- |
| 8 eşzamanlı istek, aynı key | 1 sipariş; aynı order_id |
| Aynı key, değişmiş miktar | 409; sipariş sayısı 1 |
| Yeni key, aynı iş niyeti | Domain unique koruması; sipariş sayısı 1 |
| Outbox öncesi enjekte hata | Rollback sonrası 0; retry sonrası 1 sipariş |
| Korumasız API’de commit sonrası yanıt gecikmesi | 2 HTTP denemesi, 2 sipariş kaydı |
| Idempotent API’de aynı yanıt kaybı | 2 HTTP denemesi, 1 sipariş kaydı |
| Alıcı commit etti, ACK zaman aşımı oldu | 2 teslim denemesi, 1 ERP benzetim kaydı |

Yanıt kaybı, commit sonrası 200 ms yanıt gecikmesi ve gerçek 50 ms istemci timeout’u ile üretildi. İşlem sonrası bağlantının sonucu okunamadı; sonra aynı iş tekrar gönderildi. Bu, ağ kablosu kesme veya PostgreSQL failover testi değildir. Ayrıca 100 outbox olayı alıcıya taşınıp kayıt sayısı doğrulandı. Laboratuvar alıcısındaki transaction sınırı gerçek bir remote ERP adapter’ına otomatik olarak aktarılmaz.

Kaynak kodu, sabitlenmiş Python bağımlılıkları, ortam bilgileri, 3.600 ham örnek ve ölçüm JSON’u [deney paketinde](/uploads/blog/tankdev-agent-write-blueprint-lab.zip) bulunuyor. [Sonuç JSON’unu](/uploads/blog/agent-write-lab-results.json) tek başına da okuyabilirsiniz. Aynı sonucu tekrar elde etmeniz beklenmez; kendi donanımınız, disk, yük ve dependency’lerinizle protokolü ve dağılımı yeniden ölçmeniz beklenir.

## 9. Gerçek maliyet girdisi: 100 USD/ay VPS ve ayrı tüketim bütçeleri

VPS’in aylık bedeli işletme sahibi tarafından 100 USD olarak bildirildi. Bu, ölçülmüş bir model token faturası değildir; paylaşılan altyapının sabit aylık gideridir. Deneyde ücretli model çağrısı ve AWS API Gateway isteği yapılmadı, dolayısıyla bu iki tüketim kalemi sıfırdı. PostgreSQL CPU’su, disk I/O ve diğer servislerin payı için ayrı muhasebe ölçümü yapılmadığından toplam marginal maliyet iddia etmiyoruz.

Aylık sunucu bedelini iş başına paylaştırma; hacimler senaryodur

| Aylık başarılı mantıksal iş | 100 USD’nin tamamı bu işlere ayrılırsa | Veri niteliği |
| --- | --- | --- |
| 10.000 | 0,010000 USD / iş | Varsayılan aylık hacim |
| 100.000 | 0,001000 USD / iş | Varsayılan aylık hacim |
| 1.000.000 | 0,000100 USD / iş | Varsayılan aylık hacim |
| Deney: 3.000 mantıksal kabul | 8,224538 lab-process CPU saniyesi | Ölçüldü; DB CPU’su dahil değil |

```text
C_host_per_success = monthly_host_bill * allocated_share / successful_jobs_month
C_llm = input_tokens / 1,000,000 * input_unit_price
      + output_tokens / 1,000,000 * output_unit_price
C_operation = allocated_host + model_attempts + retrieval + delivery
            + observability + review + expected_error_cost

For a hypothetical 10,000-input-token RAG call:
  input component = 0.01 * input_unit_price
  This is a formula, NOT a measured AWS/LLM bill from this experiment.
Use the actual model, cache usage, region, billing mode and dated invoice/rates.
```

API kabul gecikmesi 4 ms civarında ölçülmüşken LLM’in de 4 ms yanıt verdiği sonucu çıkmaz. Uçtan uca süre; retrieval, model üretimi, policy, kabul, kuyruk ve dış uygulama aşamalarını içerir. Her aşamanın dağılımı ve aynı trace içindeki toplam süre ölçülür. İş başına maliyetin paydasına HTTP retry sayısını değil, tanımlanmış başarı durumuna ulaşmış mantıksal işi koyarız. Kabul edilmiş ama ERP’de bekleyen iş, “ERP’de tamamlanan iş” maliyetinin paydasına erken eklenmez.

Idempotency’nin getirisi de yalnızca ucuz HTTP yanıtı değildir. Korumasız deneyde aynı iş iki kayda dönüştü; gerçek sistemde bunun stok, sevkiyat, müşteri iletişimi ve insan incelemesi maliyeti olabilir. Bu zararların tutarını ölçmeden para kazancı yazmıyoruz. Mükerrer etkiyi önleyen invariant, önce doğruluk gereksinimidir; ekonomik getirisi kendi operasyon kayıtlarınızdan hesaplanır.

## 10. Production kabulü: bir demo çalışınca iş bitmez

Onay, payload hash’i, fiyat/teklif sürümü ve geçerlilik süresiyle bağlıdır. Onaydan sonra müşteri, miktar veya fiyat değişirse yeniden değerlendirilir. Replay uç noktası dahil her erişimde güncel yetki kontrol edilir. Komut, outbox, dış işlem ve telafi kayıtları aynı correlation zincirinde izlenir; loglarda gereksiz müşteri metni, credential veya ham ödeme verisi tutulmaz.

Kabul testleri; commit öncesi hata, commit sonrası yanıt kaybı, relay crash’i, alıcı commit’i sonrası ACK kaybı, lease devri, iki worker yarışı, eski onay, sıra dışı event ve backup/restore senaryolarını kapsamalıdır. Bu yazıdaki laboratuvarın kapsamadığı process-kill, failover, gerçek ERP ve güvenlik sınırları üretim kabulünde ayrıca sınanır. Yedi testin geçmesi “tüm hatalarda güvenli” şeklinde genellenmez.

İşletim metrikleri arasında duplicate attempts, engellenen duplicate effects, hash conflict, UNKNOWN_EXTERNAL sayısı/yaşı, outbox oldest age, delivery attempt amplification ve reconciliation farkları bulunur. Gerçek iş SLO’su “API 200/202 verdi” değil, örneğin belirlenmiş yük altında ERP’de doğrulanmış sonuca ulaşmadır. Yeni yazmaları durduran kill switch, kabul edilmiş kayıtların görünürlüğünü ve mutabakatını korumalıdır.

TankDev’de [AI geliştirme ve entegrasyonunu](/tr/services/applied-ai), [API/sistem entegrasyonunu](/tr/services/system-integration) ve [özel yazılım sistemlerini](/tr/services/custom-software) bu işlem sınırlarıyla birlikte tasarlıyoruz. Kapsam; model bağlantısı, tool sözleşmeleri, yetki, kalıcı komut, hata kurtarma ve ölçülebilir kabul koşullarını içerir. Daha geniş üretim mimarisi için [PoC’den production’a rehberimizi](/tr/blog/pocden-productiona-olceklenebilir-mimari-guvenilirlik-maliyet) de okuyabilirsiniz.

Siparişi iki kez oluşturmayan bir sistem, modelin “bir kez yap” talimatını hatırlamasına güvenmez. Aynı işin kimliğini korur; tekrarın hangi katmanda ne üretebileceğini tanımlar. Mevcut ERP/CRM’inizde bu sınırları incelemek için [teknik kapsamı TankDev ile konuşabilirsiniz](/tr/contact). İlk soru hangi modeli kullanacağımız değil, yanıt kaybolduğunda işlemin gerçekten yapılıp yapılmadığını nasıl bileceğimizdir.

Bu metnin tamamı [Türkçe Markdown](/uploads/blog/agent-write-blueprint.tr.md) ve [İngilizce Markdown](/uploads/blog/agent-write-blueprint.en.md) olarak da sunuluyor; karar matrisi, iki Mermaid şeması ve SQL blokları kaynak biçiminde korunuyor. Aşağıdaki sorular görünür içerikle eşleşen FAQPage JSON-LD içinde de yayımlanır. Bu işaretleme bir görünürlük garantisi değildir: Google, FAQ rich result özelliğini 2026’da kaldırdığını [resmî güncelleme kaydında](https://developers.google.com/search/updates) açıklıyor. Kaynak gösterilmeyi destekleyen asıl malzeme doğrulanabilir içerik ve erişilebilir kanıttır.

## Sık Sorulan Sorular

### Yapay zekâ halüsinasyonu kurumsal veritabanını bozabilir mi?
Yazma araçları kontrolsüz açılmışsa yanlış veya tekrarlı işlemler oluşabilir. Şema doğrulaması tek başına yeterli değildir; tenant/nesne yetkisi, iş kuralı, kaynak sürümü, onay ve idempotent domain işlemi birlikte gerekir.

### LLM tool_call_id idempotency key olarak kullanılabilir mi?
Tek başına güvenilmez. Replan yeni tool_call_id üretse de ticari niyet aynı olabilir. Güvenilir workflow kararlı business_intent_id ve API key saklamalı; domain tarafında da aynı niyetin tekrar yazılması engellenmelidir.

### Aynı key ile farklı payload gelirse ne olmalı?
Önce erişim doğrulanır, sonra canonical hash karşılaştırılır. Farklı içerik 409 conflict üretir; eski kayıt sessizce değiştirilmez. Gerçekten yeni iş gerekiyorsa yeni niyet ve gerekli onay açıkça oluşturulur.

### POST timeout verirse ajan aynı siparişi tekrar göndermeli mi?
Yeni iş olarak göndermemeli. Önceki kabul gerçekleşmiş olabilir. Aynı idempotency key ve içerikle sonuç alınır veya yetkili durum endpoint’i sorgulanır. ERP sonucu belirsizse dış referansla reconciliation gerekir.

### Outbox Pattern için Kafka gerekli mi?
Hayır. Yerel transaction’da sipariş ve outbox kaydı, ardından kontrollü poller/worker yeterli bir başlangıç olabilir. Broker ihtiyacı tüketici sayısı, replay, retention, hacim ve işletim gereksinimleriyle belirlenir.

### Adapter inbox’ı uzak ERP’de exactly-once sağlar mı?
Tek başına hayır. Inbox ile ERP etkisi ortak atomik sınırda değilse crash penceresi vardır. ERP’nin native idempotency, unique dış referans veya desteklenen atomik işlem sözleşmesi gerekir; yoksa belirsizlik incelemeye alınır.

### LLM API’lerinde rate limit nasıl yönetilir?
Sağlayıcının request/token limitleri, geçerli Retry-After, global concurrency ve tenant bütçeleri birlikte uygulanır. SDK ve uygulama retry’ları çarpılmamalıdır. Billing veya kalıcı kota hataları otomatik beklemeyle çözülmeyebilir.

### RAG veya fine-tuning duplicate siparişi önler mi?
Hayır. Bunlar veri erişimi veya model davranışını iyileştirebilir; transaction, idempotency, business-intent uniqueness ve alıcı dedup mekanizmasının yerini tutmaz.

### Eski onay yeni fiyat için kullanılabilir mi?
Onay değişen içeriği kapsamamalıdır. Teklif/policy sürümü, payload hash’i, müşteri ve süre sonu kontrol edilir. Yeni fiyat veya miktar için gerektiğinde yeniden onay alınır.

### Bu yazıdaki 4,102 ms RAG veya AWS gecikmesi mi?
Hayır. 3.000 yeni istekte ölçülen pooled p95, aynı host üzerindeki idempotent HTTP kabul uç noktasına aittir. Deneyde LLM, RAG retrieval, TLS, AWS Gateway ve gerçek ERP yoktur.

### 100 USD/ay sunucuda işlem maliyeti ne olur?
Yalnız sunucu payı için 100 USD × ayrılan pay / aylık başarılı mantıksal iş hesabı yapılır. Hacim varsayımdır; model, veri, teslimat, izleme ve inceleme maliyetleri ayrıca eklenir. Bu formül tek başına ölçülmüş toplam maliyet değildir.

### TankDev bu blueprint’i mevcut ERP/CRM’e uygulayabilir mi?
Desteklenen API, erişim ve işlem sözleşmeleri uygunsa entegrasyon kapsamını tasarlayıp geliştirebiliriz. Önce veri sahipliği, yetki, dış kimlik, idempotency ve belirsiz sonuçların kurtarma koşulları incelenir; otomasyon sınırı bunlara göre belirlenir.