🤖 LLM Providers Guide / Yapay Zeka Sağlayıcıları Rehberi
Automation Sandbox includes built-in AI providers and an environment-driven factory for LLM healing fallback, triggered when the heuristic match is not confident (score, evidence coverage, or candidate margin below threshold).
💡 Select Language / Dil Seçin:
🇬🇧 English Guide
📊 Provider Comparison Matrix
| Provider | Default Model | Setup Method | Cost | Privacy |
|---|---|---|---|---|
| Gemini | gemini-3.6-flash |
GEMINI_API_KEY |
Very Low | Cloud |
| Claude | claude-haiku-4-5-20251001 |
ANTHROPIC_API_KEY |
Very Low | Cloud |
| OpenAI | gpt-4o-mini |
OPENAI_API_KEY |
Very Low | Cloud |
| Grok (xAI) | Explicit (GROK_MODEL) |
GROK_API_KEY + GROK_MODEL |
Low | Cloud |
| Kimi (Moonshot) | Explicit (KIMI_MODEL) |
KIMI_API_KEY + KIMI_MODEL |
Low | Cloud |
| Groq | Explicit (GROQ_MODEL) |
GROQ_API_KEY + GROQ_MODEL |
Low | Cloud |
| OpenRouter | Explicit (OPENROUTER_MODEL) |
OPENROUTER_API_KEY + OPENROUTER_MODEL |
Varies (per routed model) | Cloud |
| Cloudflare Workers AI | Explicit (CLOUDFLARE_MODEL) |
Token + account ID + model | Free daily allocation | Cloud |
| Ollama | llama3.2 |
OLLAMA_HOST / OLLAMA_MODEL |
100% Free ($0) | Local by default; host-controlled |
[!CAUTION] Provider setup is also a data-disclosure decision. DOM/UI text is untrusted, and every configured provider receives the bounded prompt. Built-in redaction masks common PII/secret patterns by default but is not exhaustive and can be disabled (
SensitiveDataSanitizer.PassThrough). Read the LLM Healing Security Model before adding cloud or remote endpoints.
🏭 Dynamic Environment Provider Factory (LlmProviderFactory)
LlmProviderFactory.CreateConfiguredProviders() automatically discovers and instantiates available providers based on active environment variables without needing code changes:
[!IMPORTANT] No provider is required, and none of these keys is mandatory. A well-known provider exists only when its own
*_API_KEYis present; everything else is skipped silently. InvalidLLM_CUSTOM_PROVIDERSinput is skipped with a credential-safe diagnostic instead. The agreement quorum needs two independent providers, so two keys is the practical minimum.Never point one provider slot at another provider’s endpoint.
OpenAiHealingProvideraccepts any OpenAI-compatible URL, which makes it tempting to reuse theOPENAI_*slot for a different vendor. Two slots proxying the same model are one voter with two names: their agreement is not independent and the quorum becomes meaningless (#19). If you need a second opinion, use a second vendor. TheOPENAI_*slot is reserved for a genuine OpenAI credential; leave it unset otherwise.
- Well-known auto-discovery:
ANTHROPIC_API_KEY(+ optionalANTHROPIC_MODEL) $\rightarrow$ClaudeHealingProviderGEMINI_API_KEY(+ optionalGEMINI_MODEL) $\rightarrow$GeminiHealingProviderOPENAI_API_KEY(+ optionalOPENAI_MODEL,OPENAI_ENDPOINT) $\rightarrow$OpenAiHealingProviderGROK_API_KEY+GROK_MODEL(+ optionalGROK_ENDPOINT) $\rightarrow$OpenAiHealingProvider(named"Grok") — both required; there is no guessed default modelKIMI_API_KEY+KIMI_MODEL(+ optionalKIMI_ENDPOINT) $\rightarrow$OpenAiHealingProvider(named"Kimi") — both required; there is no guessed default modelGROQ_API_KEY+GROQ_MODEL$\rightarrow$OpenAiHealingProvider(named"Groq") — both required; there is no guessed default modelOPENROUTER_API_KEY+OPENROUTER_MODEL$\rightarrow$OpenAiHealingProvider(named"OpenRouter") — both required; the model id decides which underlying model answersCLOUDFLARE_API_TOKEN+CLOUDFLARE_ACCOUNT_ID+CLOUDFLARE_MODEL$\rightarrow$OpenAiHealingProvider(named"Cloudflare")MISTRAL_API_KEY+MISTRAL_MODEL$\rightarrow$OpenAiHealingProvider(named"Mistral")NVIDIA_API_KEY+NVIDIA_MODEL$\rightarrow$OpenAiHealingProvider(named"Nvidia")OLLAMA_CLOUD_API_KEY+OLLAMA_CLOUD_MODEL$\rightarrow$OpenAiHealingProvider(named"OllamaCloud")OLLAMA_ENABLED=trueorOLLAMA_HOST$\rightarrow$OllamaHealingProvider(local daemon onlocalhost:11434)
[!WARNING]
OLLAMA_CLOUD_*andOLLAMA_*are deliberately separate and must never be conflated. The local variables build a provider aimed atlocalhost:11434, where no daemon exists on a CI runner. PointingOLLAMA_MODELat a cloud model therefore produces a provider that fails every request while still counting toward the two-provider agreement quorum, which is the opposite of what adding a provider is meant to achieve.
- Arbitrary Custom Endpoints (
LLM_CUSTOM_PROVIDERS): Provide a JSON array string to configure additional OpenAI-compatible endpoints:[ { "name": "DeepSeek", "endpoint": "https://api.deepseek.com/v1", "model": "deepseek-chat", "apiKeyEnvVar": "DEEPSEEK_API_KEY", "timeoutSeconds": 20 } ]Every entry requires a non-empty
name,endpoint,model, and eitherapiKeyor a resolvableapiKeyEnvVar.endpointandmodelare never inherited from theOPENAI_*variables: an entry missing either value is skipped so it cannot silently send a custom credential to OpenAI or add a mislabeled vote to the agreement quorum. Malformed JSON skips the custom array without discarding already discovered built-in providers. If the array itself is valid but one entry has the wrong JSON shape, only that entry is skipped and valid custom siblings are still constructed. Diagnostics never echo the JSON or API key. They go to standard error by default, or can be routed to the application’s logger:var providers = LlmProviderFactory.CreateConfiguredProviders( httpClient: null, getEnv: null, log: message => logger.LogWarning("{Message}", message));
// Discover all available providers dynamically:
var providers = LlmProviderFactory.CreateConfiguredProviders();
var result = await SelfHealingResolver.ResolveAsync(expected, treeRoot, llmProviders: providers);
⏱️ Timeouts & Resilience Patterns
All LLM providers derive from HttpLlmHealingProvider and support configurable per-attempt timeouts, overall total operation timeouts, and automatic retry with exponential backoff:
| Setting | Default (Cloud) | Default (Ollama) | Description |
|---|---|---|---|
Timeout |
15s |
30s |
Per-attempt HTTP timeout. Prevents any single hanging request from blocking the pipeline. |
TotalTimeout |
35s |
70s |
Overall operation ceiling across all retries + backoffs. |
MaxRetries |
2 |
2 |
Number of retry attempts on transient errors (total up to 3 attempts). |
Retry Rules:
- Transient Errors Retried: HTTP 429 (Rate Limited), HTTP 500, 502, 503, 504, and
HttpRequestException(transient network drops) are automatically retried with exponential backoff and jitter. - Fail-Fast on Permanent Errors: HTTP 400, 401, 403, and 404 fail immediately without wasting retry attempts.
Retry-AfterHeader & Quota Guard: If a response includes aRetry-Afterheader $\le 10\text{s}$, the transport pauses for the requested delay. IfRetry-After$> 10\text{s}$ (e.g. daily quota exhaustion), the provider fails fast immediately.
If an HTTP provider returns a successful response that cannot be parsed, its provider error includes the raw response body, bounded to 4096 characters. This applies uniformly to Claude, Gemini, Ollama, and every OpenAI-compatible endpoint. Only the response body is captured; request headers and configured API credentials are not appended to the diagnostic.
🤝 Independent Model Agreement (Consensus API)
An LLM pick is accepted only when at least two providers independently name the same candidate. The public API calls this MinimumConsensusVotes, and reports use no-consensus; these names describe the quorum mechanism, not a correctness guarantee. Self-reported confidence is recorded but never compared or thresholded: Claude’s 0.72 and Gemini’s 0.95 do not live on the same scale.
[!WARNING] Agreement is an additional signal, not proof that the chosen element is correct. Across four live runs, providers unanimously agreed in 34 deleted-element scenarios and all 34 verdicts were false heals, including cases where three independently sourced model families chose the same decoy. The measured separation came from providers disagreeing more often when an element was absent, not from agreement establishing correctness. See the formal finding.
| Situation | Outcome |
|---|---|
| Two or more providers name the same candidate | Accepted; the voters are recorded in HealResult.AgreedProviders |
| Only one provider is configured | Never accepted — one provider cannot agree with itself |
| Every provider names a different candidate | Not accepted — reported as split vote / disagreement |
| Two candidates tie for the most votes | Not accepted — a tie is disagreement |
| A provider fails or times out | Vote is discarded; remaining valid votes determine whether the quorum is met |
Independence is the point. Two
OpenAiHealingProviderinstances pointed at the same endpoint and model are the same model voting twice, not independent agreement. Prefer providers backed by genuinely different models. Even genuinely independent agreement remains a quorum signal, not a correctness guarantee.
The nightly workflow enforces this rule with a live gate using Groq and Mistral on the known Desktop_AmbiguousSiblingTabs scenario. Both raw votes must remain inside the shortlist, name the same ground-truth CandidateId, and appear in HealResult.AgreedProviders; otherwise the workflow fails. The broader multi-provider evaluation still runs afterward as non-gating telemetry. With no credentials the opt-in test skips cleanly, while a deliberate one-provider configuration fails before making an API call. Releases are not gated on third-party availability; this gate belongs to the nightly workflow only.
Naming providers
HealResult.AgreedProviders identifies voters by ILlmHealingProvider.Name, so names must be unique within a run — LlmProviderFactory throws on a duplicate rather than producing an unreadable report. Because OpenAiHealingProvider speaks to any OpenAI-compatible endpoint, several instances of it can legitimately be configured at once. The factory handles the well-known ones for you; construct them by hand and each needs a name:
var providers = new ILlmHealingProvider[]
{
new OpenAiHealingProvider(name: "Groq", endpoint: "https://api.groq.com/openai/v1", apiKey: groqKey),
new OpenAiHealingProvider(name: "Cerebras", endpoint: "https://api.cerebras.ai/v1", apiKey: cerebrasKey),
};
Without name, both would report "OpenAI" and their votes would be indistinguishable in the report.
Setting Up Free Offline AI (Ollama)
- Download & install Ollama.
- Open terminal and pull the lightweight Llama model:
ollama run llama3.2 - Pass
OllamaHealingProviderin C# code:var provider = new OllamaHealingProvider(host: "http://localhost:11434");
On modest hardware, prefer a smaller model (llama3.2:1b, qwen2.5:0.5b) — set it with OLLAMA_MODEL or the model: parameter. Ollama alone cannot satisfy the agreement quorum: it is one provider, so pair it with a second one if you want LLM picks accepted rather than only recorded.
🌐 Free Cloud AI with Cloudflare Workers AI
Cloudflare Workers AI exposes an account-scoped OpenAI-compatible endpoint and includes a daily free allocation. Configure all three values; the factory deliberately skips Cloudflare when any one is missing because neither the account path nor a currently available model can be guessed safely:
CLOUDFLARE_API_TOKEN=<repository secret>
CLOUDFLARE_ACCOUNT_ID=<repository variable>
CLOUDFLARE_MODEL=@cf/zai-org/glm-4.7-flash
The resulting provider is named Cloudflare and calls https://api.cloudflare.com/client/v4/accounts/{account-id}/ai/v1/chat/completions. The Cloudflare request uses response_format: { "type": "json_object" } and max_tokens: 2000, leaving room for Qwen reasoning plus the complete JSON response without depending on a provider-specific output default. Model availability and free-plan eligibility can change; run provider-diagnostics.yml before selecting a model and consult Workers AI pricing. Keep model ids in repository variables rather than secrets.
Choose a model family different from the other voters. Two endpoints serving the same underlying model do not provide independent agreement. The free allocation is appropriate for low-volume nightly or manual evaluation, not a guaranteed per-PR release gate.
OpenAiHealingProvider also supports other OpenAI-compatible endpoints such as Azure OpenAI, vLLM, and LM Studio. GitHub Models is not an option: its inference API was fully retired on July 30, 2026.
🛠️ Custom LLM Providers (ILlmHealingProvider / HttpLlmHealingProvider)
If you want to integrate a proprietary internal model, a cloud vendor without an OpenAI-compatible interface, or a custom heuristic-AI pipeline, you can implement ILlmHealingProvider directly or subclass HttpLlmHealingProvider.
1. Option A: Subclassing HttpLlmHealingProvider (Recommended for REST Endpoints)
HttpLlmHealingProvider encapsulates constructor parameter validation, retry with exponential backoff (LlmHttpTransport), transient error detection (HTTP 429/500s), per-attempt and total timeout ceilings, text sanitization, prompt construction (LlmHealingPrompt.Build), and the Hallucination Guard.
You need to supply four members: IsAvailable, UnavailableErrorMessage, CreateRequest, and ExtractText:
using System.Net.Http;
using System.Text;
using System.Text.Json;
using LlmHealing;
public sealed class CustomApiHealingProvider : HttpLlmHealingProvider
{
private readonly string _endpoint;
private readonly string? _apiKey;
public override bool IsAvailable => !string.IsNullOrEmpty(_apiKey);
protected override string UnavailableErrorMessage => "CUSTOM_API_KEY environment variable is not configured.";
public CustomApiHealingProvider(
string endpoint = "https://ai.internal.corp/v1/heal",
string? apiKey = null,
string? name = null)
: base(
defaultName: "InternalAi",
defaultTimeout: TimeSpan.FromSeconds(15),
defaultTotalTimeout: TimeSpan.FromSeconds(35),
name: name)
{
_endpoint = endpoint;
_apiKey = apiKey ?? Environment.GetEnvironmentVariable("CUSTOM_API_KEY");
}
protected override HttpRequestMessage CreateRequest(string prompt)
{
var payload = JsonSerializer.Serialize(new { prompt = prompt });
var request = new HttpRequestMessage(HttpMethod.Post, _endpoint)
{
Content = new StringContent(payload, Encoding.UTF8, "application/json")
};
if (!string.IsNullOrEmpty(_apiKey))
{
request.Headers.Add("Authorization", $"Bearer {_apiKey}");
}
return request;
}
protected override string ExtractText(string responseBody)
{
using var doc = JsonDocument.Parse(responseBody);
// Extracts the raw JSON text containing {"candidateId": "c0", "confidence": 0.95, "reasoning": "..."}
return doc.RootElement.GetProperty("reply").GetString() ?? string.Empty;
}
}
2. Option B: Direct Implementation of ILlmHealingProvider
For non-HTTP models, local in-process models (e.g. ONNX runtime), or custom agent frameworks, implement ILlmHealingProvider directly:
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using LlmHealing;
using UiModel;
public sealed class MyLocalModelProvider : ILlmHealingProvider
{
public string Name => "MyLocalModel";
public bool IsAvailable => true;
public Task<LlmHealingResult> ResolveAsync(
UiElementInfo expected,
IReadOnlyList<CandidateScore> candidates,
string? platform = null,
CancellationToken cancellationToken = default)
{
// 1. Evaluate your model on the shortlist:
var chosenId = "c0"; // e.g. from local model inference
// 2. Hallucination Guard Contract:
// Must match an existing CandidateId from the provided candidate shortlist!
var validCandidate = candidates.FirstOrDefault(c => c.CandidateId == chosenId);
if (validCandidate == null)
{
return Task.FromResult(new LlmHealingResult
{
ProviderName = Name,
Success = false,
ErrorMessage = "Model returned candidateId outside shortlist."
});
}
return Task.FromResult(new LlmHealingResult
{
ProviderName = Name,
Success = true,
MatchedCandidateId = validCandidate.CandidateId,
Confidence = 0.92,
Reasoning = "Matched control type and layout position."
});
}
}
3. Hallucination Guard Contract & Quorum Rules
- Shortlist Candidate IDs (
c0,c1, …): The engine passes a synthetic shortlist where candidates are identified solely by opaque candidate IDs (c0,c1, …). The provider must return one of these IDs inMatchedCandidateId. - Invalid IDs are Discarded: If a provider hallucinates an ID that is not present in the candidate shortlist (or returns an unparseable response), its vote is marked invalid and discarded without failing other providers’ votes.
- Quorum Requirement: LLM healing acceptance requires at least two independent providers to agree on the same
CandidateId. A single custom provider will have its verdict recorded in reports and telemetry, but will safely fallback to the heuristic outcome unless paired with a second independent provider.
4. Registering Custom Providers
Pass custom providers directly to SelfHealingResolver.ResolveAsync, SelfHealingEngine, or SelfHealingTestFixture:
// Combine custom provider with built-in discovered providers:
var providers = LlmProviderFactory.CreateConfiguredProviders().ToList();
providers.Add(new CustomApiHealingProvider(apiKey: "secret-token"));
// Use in SelfHealingEngine:
var engine = new SelfHealingEngine(repository, llmProviders: providers);
// Or in SelfHealingTestFixture:
var fixture = SelfHealingTestFixture.Create(new SelfHealingTestOptions
{
LlmProviders = providers
});
🇹🇷 Türkçe Kılavuz
📊 Sağlayıcı Karşılaştırma Tablosu
| Sağlayıcı | Varsayılan Model | Kurulum / Değişken | Maliyet | Gizlilik |
|---|---|---|---|---|
| Gemini | gemini-3.6-flash |
GEMINI_API_KEY |
Çok Düşük | Bulut |
| Claude | claude-haiku-4-5-20251001 |
ANTHROPIC_API_KEY |
Çok Düşük | Bulut |
| OpenAI | gpt-4o-mini |
OPENAI_API_KEY |
Çok Düşük | Bulut |
| Grok (xAI) | Açıkça belirtilir (GROK_MODEL) |
GROK_API_KEY + GROK_MODEL |
Düşük | Bulut |
| Kimi (Moonshot) | Açıkça belirtilir (KIMI_MODEL) |
KIMI_API_KEY + KIMI_MODEL |
Düşük | Bulut |
| Groq | Açıkça belirtilir (GROQ_MODEL) |
GROQ_API_KEY + GROQ_MODEL |
Düşük | Bulut |
| OpenRouter | Açıkça belirtilir (OPENROUTER_MODEL) |
OPENROUTER_API_KEY + OPENROUTER_MODEL |
Yönlendirilen modele göre değişir | Bulut |
| Cloudflare Workers AI | Açıkça belirtilir (CLOUDFLARE_MODEL) |
Token + hesap kimliği + model | Günlük ücretsiz kota | Bulut |
| Ollama | llama3.2 |
OLLAMA_HOST / OLLAMA_MODEL |
%100 Ücretsiz ($0) | Varsayılan yerel; host’a bağlı |
[!CAUTION] Sağlayıcı kurulumu aynı zamanda bir veri ifşası kararıdır. DOM/UI metni güvenilmeyen girdidir ve yapılandırılmış her sağlayıcı sınırlı prompt’u alır. Yerleşik maskeleme varsayılan olarak yaygın PII/secret desenlerini maskeler, ancak kapsamlı değildir ve devre dışı bırakılabilir (
SensitiveDataSanitizer.PassThrough). Bulut veya uzak endpoint eklemeden önce LLM Healing Güvenlik Modelini okuyun.
🏭 Dinamik Sağlayıcı Fabrikası (LlmProviderFactory)
LlmProviderFactory.CreateConfiguredProviders() ortamdaki anahtarları otomatik keşfeder ve kod değiştirmeden sağlayıcı listesini hazırlar:
[!IMPORTANT] Hiçbir sağlayıcı zorunlu değildir; bu anahtarların hiçbiri gerekli değildir. Bilinen bir sağlayıcı yalnızca kendi
*_API_KEYdeğeri varsa kurulur, aksi halde sessizce atlanır. GeçersizLLM_CUSTOM_PROVIDERSgirdisi ise kimlik bilgilerini açığa çıkarmayan bir tanı mesajıyla atlanır. Uzlaşma quorum’u iki bağımsız sağlayıcı gerektirdiği için pratik alt sınır iki anahtardır.Bir sağlayıcı slotunu başka bir sağlayıcının uç noktasına yönlendirmeyin.
OpenAiHealingProviderherhangi bir OpenAI-uyumlu adresi kabul ettiği içinOPENAI_*slotunu başka bir sağlayıcı için yeniden kullanmak cazip gelir. Aynı modeli çağıran iki slot, iki isimli tek bir oy demektir: aynı sistem oldukları için anlaşırlar ve aralarındaki uzlaşma anlamsızdır (#19). İkinci bir görüş gerekiyorsa ikinci bir sağlayıcı kullanın.OPENAI_*slotu gerçek bir OpenAI kimlik bilgisine ayrılmıştır; başka bir amaçla doldurmayın, boş bırakın.
Cloudflare için CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID ve CLOUDFLARE_MODEL değerlerinin üçü de zorunludur. Tam yapılandırma "Cloudflare" adlı bir OpenAiHealingProvider oluşturur; herhangi biri eksikse bozuk bir uç nokta veya tahmini model üretmek yerine sağlayıcı atlanır.
Aynı kural Grok (GROK_API_KEY + GROK_MODEL $\rightarrow$ "Grok"), Kimi (KIMI_API_KEY + KIMI_MODEL $\rightarrow$ "Kimi"), Groq (GROQ_API_KEY + GROQ_MODEL $\rightarrow$ "Groq"), OpenRouter (OPENROUTER_API_KEY + OPENROUTER_MODEL $\rightarrow$ "OpenRouter"), Mistral (MISTRAL_API_KEY + MISTRAL_MODEL $\rightarrow$ "Mistral"), NVIDIA NIM (NVIDIA_API_KEY + NVIDIA_MODEL $\rightarrow$ "Nvidia") ve Ollama Cloud (OLLAMA_CLOUD_API_KEY + OLLAMA_CLOUD_MODEL $\rightarrow$ "OllamaCloud") için de geçerlidir; hepsi OpenAI uyumludur, ayrı sağlayıcı sınıfı gerektirmez.
[!WARNING]
OLLAMA_CLOUD_*ileOLLAMA_*bilinçli olarak ayrıdır ve karıştırılmamalıdır. Yerel değişkenlerlocalhost:11434adresini hedefleyen bir sağlayıcı kurar; CI runner’ında orada çalışan bir daemon yoktur. DolayısıylaOLLAMA_MODEL‘i bir bulut modeline yönlendirmek, her istekte başarısız olan ama yine de iki sağlayıcılı mutabakat eşiğine sayılan bir sağlayıcı üretir — sağlayıcı eklemenin amacının tam tersi.
Ek OpenAI uyumlu uç noktaları yapılandırmak için LLM_CUSTOM_PROVIDERS değerine bir JSON dizisi verin:
[
{
"name": "DeepSeek",
"endpoint": "https://api.deepseek.com/v1",
"model": "deepseek-chat",
"apiKeyEnvVar": "DEEPSEEK_API_KEY",
"timeoutSeconds": 20
}
]
LLM_CUSTOM_PROVIDERS dizisindeki her giriş boş olmayan name, endpoint, model
ve doğrudan apiKey ya da çözümlenebilir bir apiKeyEnvVar içermelidir. endpoint
ve model, OPENAI_* değişkenlerinden devralınmaz. Bu alanlardan biri eksikse özel
kimlik bilgisinin yanlışlıkla OpenAI’a gönderilmemesi ve mutabakata yanlış etiketli bir
oy eklenmemesi için yalnızca ilgili giriş atlanır. JSON bütünüyle bozuksa daha önce
keşfedilmiş yerleşik sağlayıcılar korunur. Dizinin kendisi geçerli olup bir elemanın JSON
şekli bozuksa yalnızca o eleman atlanır ve geçerli özel sağlayıcı kardeşleri yine oluşturulur.
Tanı mesajları ham JSON’u ve API anahtarını içermez; varsayılan olarak standart hataya
yazılır veya uygulamanın logger’ına yönlendirilebilir:
var providers = LlmProviderFactory.CreateConfiguredProviders(
httpClient: null,
getEnv: null,
log: message => logger.LogWarning("{Message}", message));
// Ortamdaki tüm geçerli sağlayıcıları otomatik al:
var providers = LlmProviderFactory.CreateConfiguredProviders();
var result = await SelfHealingResolver.ResolveAsync(expected, treeRoot, llmProviders: providers);
⏱️ Zaman Aşımı (Timeout) ve Dayanıklılık (Resilience)
Tüm sağlayıcılar HttpLlmHealingProvider tabanından türer; deneme başına zaman aşımı, toplam işlem tavanı ve üstel geri çekilmeli (exponential backoff) otomatik yeniden deneme destekler:
| Ayar | Varsayılan (Bulut) | Varsayılan (Ollama) | Açıklama |
|---|---|---|---|
Timeout |
15s |
30s |
Deneme başına HTTP zaman aşımı. Tek bir asılı isteğin akışı kilitlemesini önler. |
TotalTimeout |
35s |
70s |
Tüm denemeler ve bekleme süreleri dahil toplam işlem tavanı. |
MaxRetries |
2 |
2 |
Geçici hatalarda yeniden deneme sayısı (toplam en fazla 3 deneme). |
Yeniden Deneme (Retry) Kuralları:
- Yeniden denenen geçici hatalar: HTTP 429 (kota aşımı), 500, 502, 503, 504 ve
HttpRequestException(geçici ağ kopmaları) üstel geri çekilme ve jitter ile otomatik olarak yeniden denenir. - Kalıcı hatalarda hızlı başarısızlık: HTTP 400, 401, 403 ve 404 yeniden deneme hakkı harcamadan anında başarısız döner.
Retry-AfterBaşlığı ve Kota Koruması: YanıttaRetry-Afterbaşlığı $\le 10\text{s}$ ise belirtilen süre kadar beklenir. $> 10\text{s}$ ise (ör. günlük kota tükenmesi) boşuna beklenmez, doğrudan başarısız dönülür.
Bir HTTP sağlayıcısı ayrıştırılamayan başarılı bir yanıt döndürürse sağlayıcı hatası, 4096 karakterle sınırlandırılmış ham yanıt gövdesini içerir. Bu davranış Claude, Gemini, Ollama ve tüm OpenAI uyumlu uç noktalara aynı şekilde uygulanır. Yalnızca yanıt gövdesi yakalanır; istek başlıkları ve yapılandırılmış API kimlik bilgileri tanı mesajına eklenmez.
🤝 Bağımsız Model Uzlaşması (Consensus API)
Bir LLM seçimi yalnızca en az iki bağımsız sağlayıcı aynı adayı seçtiğinde kabul edilir. Public API bu eşiği MinimumConsensusVotes, raporlar ise başarısız sonucu no-consensus olarak adlandırır; bu adlar doğruluk garantisini değil quorum mekanizmasını ifade eder. Modellerin kendi beyan ettiği güven puanları karşılaştırılmaz.
[!WARNING] Uzlaşma ek bir sinyaldir; seçilen elemanın doğru olduğunun kanıtı değildir. Dört canlı koşuda sağlayıcılar 34 silinmiş-eleman senaryosunda oybirliğine ulaştı ve 34 kararın tamamı yanlış iyileştirmeydi; üç bağımsız kaynaklı model ailesinin aynı yanlış komşuyu seçtiği vakalar da buna dahildi. Ölçülen ayrışma, eleman yokken sağlayıcıların daha sık anlaşamamasından doğdu; anlaşmaları doğruluğu kanıtlamadı. Resmi bulguya bakın.
| Durum | Sonuç |
|---|---|
| İki veya daha fazla sağlayıcı aynı adayı seçer | Kabul edilir; oy verenler HealResult.AgreedProviders içine yazılır |
| Yalnızca tek sağlayıcı yapılandırılmış | Asla kabul edilmez — tek sağlayıcı kendisiyle mutabakat sağlayamaz |
| Her sağlayıcı farklı bir aday seçer | Kabul edilmez — ayrık oy (split vote) olarak raporlanır |
| İki aday en yüksek oyda berabere kalır | Kabul edilmez — beraberlik anlaşmazlıktır |
| Bir sağlayıcı hata verir veya zaman aşımına uğrar | O oy elenir; kalan geçerli oylar quorum sağlanıp sağlanmadığını belirler |
Asıl mesele bağımsızlık. Aynı uç noktaya ve aynı modele bakan iki
OpenAiHealingProviderörneği, bağımsız uzlaşma değil aynı modelin iki kez oy vermesidir. Gerçekten farklı modellere dayanan sağlayıcıları tercih edin. Gerçekten bağımsız uzlaşma bile bir quorum sinyalidir; doğruluk garantisi değildir.
Nightly workflow bu kuralı bilinen Desktop_AmbiguousSiblingTabs senaryosunda Groq ve Mistral kullanan canlı bir gate ile uygular. İki ham oyun da shortlist içinde kalması, aynı ground-truth CandidateId değerini seçmesi ve HealResult.AgreedProviders içinde görünmesi gerekir; aksi halde workflow başarısız olur. Daha geniş çok-sağlayıcılı değerlendirme bunun ardından gate olmayan telemetri olarak çalışmaya devam eder. Hiç credential yoksa opt-in test temiz biçimde atlanır; bilinçli tek-sağlayıcı yapılandırması ise API çağrısı yapmadan başarısız olur. Üçüncü taraf erişilebilirliği release’i engellemesin diye gate yalnızca nightly workflow’dadır.
Sağlayıcılara isim verme
HealResult.AgreedProviders oy verenleri ILlmHealingProvider.Name ile tanımlar; bu yüzden isimler bir çalıştırma içinde benzersiz olmalıdır — LlmProviderFactory yinelenen bir isimde okunmaz bir rapor üretmek yerine hata fırlatır. OpenAiHealingProvider OpenAI uyumlu her uç noktayla konuştuğu için aynı anda birden çok örneği meşru biçimde yapılandırılabilir. Bilinen sağlayıcıları fabrika sizin için kurar; elle kuruyorsanız her birine name verin:
var providers = new ILlmHealingProvider[]
{
new OpenAiHealingProvider(name: "Groq", endpoint: "https://api.groq.com/openai/v1", apiKey: groqKey),
new OpenAiHealingProvider(name: "Cerebras", endpoint: "https://api.cerebras.ai/v1", apiKey: cerebrasKey),
};
name verilmezse ikisi de "OpenAI" olarak raporlanır ve oyları raporda birbirinden ayırt edilemez.
0 TL Maliyetli Çevrimdışı Yapay Zeka (Ollama) Kurulumu
- Ollama Resmi Sitesinden Ollama’yı indirip kurun.
- Terminal açıp hafif Llama modelini indirin:
ollama run llama3.2 - C# kodunuzda
OllamaHealingProvidernesnesini verin:var provider = new OllamaHealingProvider(host: "http://localhost:11434");
Bilgisayarınız zayıfsa daha küçük bir model tercih edin (llama3.2:1b, qwen2.5:0.5b) — OLLAMA_MODEL ile veya model: parametresiyle ayarlanır. Ollama tek başına uzlaşma quorum’unu sağlayamaz: tek sağlayıcıdır, dolayısıyla LLM seçimlerinin yalnız kaydedilmesi değil kabul edilmesi isteniyorsa yanına ikinci bir sağlayıcı gerekir.
🌐 Cloudflare Workers AI ile Ücretsiz Bulut Yapay Zekası
Cloudflare Workers AI hesap kapsamlı, OpenAI uyumlu bir uç nokta ve günlük ücretsiz kota sunar. Üç değerin tamamını yapılandırın:
CLOUDFLARE_API_TOKEN=<repository secret>
CLOUDFLARE_ACCOUNT_ID=<repository variable>
CLOUDFLARE_MODEL=@cf/zai-org/glm-4.7-flash
Oluşan sağlayıcının adı Cloudflare, uç noktası https://api.cloudflare.com/client/v4/accounts/{account-id}/ai/v1/chat/completions olur. Cloudflare isteği response_format: { "type": "json_object" } ve max_tokens: 2000 gönderir; böylece Qwen reasoning çıktısı ve tamamlanmış JSON yanıtı için yeterli alan bırakılır, çıktı sağlayıcı varsayılanına bırakılmaz. Model erişilebilirliği ve ücretsiz plan uygunluğu değişebilir; model seçmeden önce provider-diagnostics.yml çalıştırın ve Workers AI fiyatlandırmasını kontrol edin. Model kimlikleri secret değil repository variable olarak tutulmalıdır.
Diğer oy verenlerden farklı bir model ailesi seçin. Aynı temel modeli sunan iki uç nokta bağımsız mutabakat oluşturmaz. Ücretsiz kota düşük hacimli nightly veya manuel değerlendirmeye uygundur; her PR için garantili release gate olarak kullanılmamalıdır.
OpenAiHealingProvider, Azure OpenAI, vLLM ve LM Studio gibi diğer OpenAI uyumlu uç noktaları da destekler. GitHub Models artık seçenek değildir: inference API 30 Temmuz 2026 tarihinde tamamen kapatılmıştır.
🛠️ Özel Yapay Zeka Sağlayıcıları (ILlmHealingProvider / HttpLlmHealingProvider)
Kurum içi özel bir modeli, OpenAI uyumlu olmayan bir bulut sağlayıcısını veya kendi AI/akıl yürütme motorunuzu entegre etmek istiyorsanız, doğrudan ILlmHealingProvider arayüzünü uygulayabilir veya HttpLlmHealingProvider sınıfından türetebilirsiniz.
1. A Seçeneği: HttpLlmHealingProvider Taban Sınıfını Genişletme (REST Uç Noktaları İçin Önerilen)
HttpLlmHealingProvider, parametre doğrulamalarını, LlmHttpTransport ile üstel geri çekilmeli yeniden denemeleri (retry), geçici HTTP 429/500 hata ayrımını, zaman aşımı tavanlarını, hassas veri maskelemeyi (TextSanitizer), prompt üretimini (LlmHealingPrompt.Build) ve Hallucination Guard (Halüsinasyon Koruması) mantığını otomatik olarak yönetir.
Dört üyeyi tanımlamanız gerekir: IsAvailable, UnavailableErrorMessage, CreateRequest ve ExtractText:
using System.Net.Http;
using System.Text;
using System.Text.Json;
using LlmHealing;
public sealed class CustomApiHealingProvider : HttpLlmHealingProvider
{
private readonly string _endpoint;
private readonly string? _apiKey;
public override bool IsAvailable => !string.IsNullOrEmpty(_apiKey);
protected override string UnavailableErrorMessage => "CUSTOM_API_KEY ortam değişkeni tanımlı değil.";
public CustomApiHealingProvider(
string endpoint = "https://ai.internal.corp/v1/heal",
string? apiKey = null,
string? name = null)
: base(
defaultName: "InternalAi",
defaultTimeout: TimeSpan.FromSeconds(15),
defaultTotalTimeout: TimeSpan.FromSeconds(35),
name: name)
{
_endpoint = endpoint;
_apiKey = apiKey ?? Environment.GetEnvironmentVariable("CUSTOM_API_KEY");
}
protected override HttpRequestMessage CreateRequest(string prompt)
{
var payload = JsonSerializer.Serialize(new { prompt = prompt });
var request = new HttpRequestMessage(HttpMethod.Post, _endpoint)
{
Content = new StringContent(payload, Encoding.UTF8, "application/json")
};
if (!string.IsNullOrEmpty(_apiKey))
{
request.Headers.Add("Authorization", $"Bearer {_apiKey}");
}
return request;
}
protected override string ExtractText(string responseBody)
{
using var doc = JsonDocument.Parse(responseBody);
// {"candidateId": "c0", "confidence": 0.95, "reasoning": "..."} içeren ham JSON metnini ayıklar
return doc.RootElement.GetProperty("reply").GetString() ?? string.Empty;
}
}
2. B Seçeneği: Doğrudan ILlmHealingProvider Arayüzünü Uygulama
HTTP dışı modeller, işlem içi yerel modeller (ör. ONNX) veya özel ajan mimarileri için ILlmHealingProvider arayüzünü doğrudan uygulayabilirsiniz:
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using LlmHealing;
using UiModel;
public sealed class MyLocalModelProvider : ILlmHealingProvider
{
public string Name => "MyLocalModel";
public bool IsAvailable => true;
public Task<LlmHealingResult> ResolveAsync(
UiElementInfo expected,
IReadOnlyList<CandidateScore> candidates,
string? platform = null,
CancellationToken cancellationToken = default)
{
// 1. Modelinizi aday listesi üzerinde çalıştırın:
var chosenId = "c0"; // ör. yerel model çıkarımından gelen sonuç
// 2. Hallucination Guard (Halüsinasyon Koruması) Sözleşmesi:
// Yalnızca aday listesinde bulunan geçerli bir CandidateId döndürülmelidir!
var validCandidate = candidates.FirstOrDefault(c => c.CandidateId == chosenId);
if (validCandidate == null)
{
return Task.FromResult(new LlmHealingResult
{
ProviderName = Name,
Success = false,
ErrorMessage = "Model aday listesi dışından geçersiz bir CandidateId döndürdü."
});
}
return Task.FromResult(new LlmHealingResult
{
ProviderName = Name,
Success = true,
MatchedCandidateId = validCandidate.CandidateId,
Confidence = 0.92,
Reasoning = "Kontrol türü ve düzen konumu eşleşti."
});
}
}
3. Hallucination Guard ve Uzlaşma (Quorum) Kuralları
- Aday Listesi ID’leri (
c0,c1, …): Motor, adayları yalnızca sentetik kimliklerle (c0,c1, …) tanımlayan sınırlandırılmış bir liste iletir. SağlayıcıMatchedCandidateIdalanında bu ID’lerden birini döndürmelidir. - Geçersiz ID’ler Elenir: Bir sağlayıcı listede olmayan hayali bir ID döndürürse veya yanıt ayrıştırılamazsa, o sağlayıcının oyu geçersiz sayılıp elenir; diğer sağlayıcıların oyları bundan etkilenmez.
- Uzlaşma Şartı: LLM iyileştirmesinin kabul edilmesi için en az iki bağımsız sağlayıcının aynı
CandidateIdüzerinde anlaşması gerekir. Tek bir özel sağlayıcı telemetriye kaydedilir fakat uzlaşma için ikinci bir sağlayıcıyla eşleştirilmedikçe güvenli olarak sezgisel sonuca geri döner.
4. Özel Sağlayıcıları Kaydetme ve Kullanma
Özel sağlayıcıları SelfHealingResolver.ResolveAsync, SelfHealingEngine veya SelfHealingTestFixture içine doğrudan parametre olarak verebilirsiniz:
// Yerleşik sağlayıcılar ile özel sağlayıcıyı birleştirme:
var providers = LlmProviderFactory.CreateConfiguredProviders().ToList();
providers.Add(new CustomApiHealingProvider(apiKey: "secret-token"));
// SelfHealingEngine ile kullanım:
var engine = new SelfHealingEngine(repository, llmProviders: providers);
// Veya SelfHealingTestFixture ile kullanım:
var fixture = SelfHealingTestFixture.Create(new SelfHealingTestOptions
{
LlmProviders = providers
});