The 6 blog post bodies were English-only even in Persian mode. Add natural Persian translations and select the body by locale (IsFa ? BodyFa : BodyEn), so a Persian reader gets a fully Persian article. Also removed the em/en dashes from the English bodies (taste compliance) and stripped stray bidi control chars (kept ZWNJ). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+167
-38
@@ -14,24 +14,25 @@ public class PostModel(ContentService content) : BasePageModel
|
|||||||
public string BodyHtml { get; private set; } = "";
|
public string BodyHtml { get; private set; } = "";
|
||||||
public bool PostNotFound { get; private set; }
|
public bool PostNotFound { get; private set; }
|
||||||
|
|
||||||
// Default bodies (Markdown-lite, rendered server-side)
|
// Default bodies (Markdown-lite, rendered server-side). Body is locale-aware.
|
||||||
private static readonly Dictionary<string, (string Cat, string TitleEn, string TitleFa, int RT, string Body)> _defaults = new()
|
private static readonly Dictionary<string, (string Cat, string TitleEn, string TitleFa, int RT, string BodyEn, string BodyFa)> _defaults = new()
|
||||||
{
|
{
|
||||||
["rag-eval-framework"] = ("LLM", "A RAG evaluation framework that holds up in production", "چارچوب ارزیابی RAG که در عمل جواب میدهد", 8, DefaultBodies.RagEval),
|
["rag-eval-framework"] = ("LLM", "A RAG evaluation framework that holds up in production", "چارچوب ارزیابی RAG که در عمل جواب میدهد", 8, DefaultBodies.RagEval, DefaultBodies.RagEvalFa),
|
||||||
["agentic-n8n-patterns"] = ("Automation", "Agentic patterns with n8n for the enterprise", "الگوهای عاملمحور با n8n برای سازمان", 11, DefaultBodies.N8nPatterns),
|
["agentic-n8n-patterns"] = ("Automation", "Agentic patterns with n8n for the enterprise", "الگوهای عاملمحور با n8n برای سازمان", 11, DefaultBodies.N8nPatterns, DefaultBodies.N8nPatternsFa),
|
||||||
["vertex-cost-control"] = ("Google Stack", "Vertex AI cost control at scale", "کنترل هزینه روی Vertex AI در مقیاس بالا", 6, DefaultBodies.VertexCost),
|
["vertex-cost-control"] = ("Google Stack", "Vertex AI cost control at scale", "کنترل هزینه روی Vertex AI در مقیاس بالا", 6, DefaultBodies.VertexCost, DefaultBodies.VertexCostFa),
|
||||||
["k8s-llm-inference"] = ("Infra", "Sub-50ms LLM inference on Kubernetes", "اجرای LLM روی Kubernetes با تأخیر زیر ۵۰ میلیثانیه",14, DefaultBodies.K8sInference),
|
["k8s-llm-inference"] = ("Infra", "Sub-50ms LLM inference on Kubernetes", "اجرای LLM روی Kubernetes با تأخیر زیر ۵۰ میلیثانیه", 14, DefaultBodies.K8sInference, DefaultBodies.K8sInferenceFa),
|
||||||
["flutter-on-device-ai"] = ("Mobile", "On-device AI in Flutter", "هوش مصنوعی روی دستگاه در Flutter", 9, DefaultBodies.FlutterAI),
|
["flutter-on-device-ai"] = ("Mobile", "On-device AI in Flutter", "هوش مصنوعی روی دستگاه در Flutter", 9, DefaultBodies.FlutterAI, DefaultBodies.FlutterAIFa),
|
||||||
["enterprise-ai-roadmap"] = ("Strategy", "A 90-day enterprise AI roadmap", "نقشهی راه هوش مصنوعی سازمانی در ۹۰ روز", 7, DefaultBodies.EnterpriseRoadmap),
|
["enterprise-ai-roadmap"] = ("Strategy", "A 90-day enterprise AI roadmap", "نقشهی راه هوش مصنوعی سازمانی در ۹۰ روز", 7, DefaultBodies.EnterpriseRoadmap, DefaultBodies.EnterpriseRoadmapFa),
|
||||||
};
|
};
|
||||||
|
|
||||||
public void OnGet()
|
public void OnGet()
|
||||||
{
|
{
|
||||||
if (!_defaults.TryGetValue(Slug, out var def)) { PostNotFound = true; return; }
|
if (!_defaults.TryGetValue(Slug, out var def)) { PostNotFound = true; return; }
|
||||||
|
|
||||||
|
string body = IsFa ? def.BodyFa : def.BodyEn;
|
||||||
|
|
||||||
// Check for DB override (stored under "posts" key as slug→{body,...})
|
// Check for DB override (stored under "posts" key as slug→{body,...})
|
||||||
var overrides = content.GetPostOverrides();
|
var overrides = content.GetPostOverrides();
|
||||||
string body = def.Body;
|
|
||||||
if (overrides.TryGetValue(Slug, out var node) && node["body"]?.GetValue<string>() is { } dbBody)
|
if (overrides.TryGetValue(Slug, out var node) && node["body"]?.GetValue<string>() is { } dbBody)
|
||||||
body = dbBody;
|
body = dbBody;
|
||||||
|
|
||||||
@@ -83,13 +84,13 @@ public class PostModel(ContentService content) : BasePageModel
|
|||||||
private static string Esc(string s) => s.Replace("&","&").Replace("<","<").Replace(">",">");
|
private static string Esc(string s) => s.Replace("&","&").Replace("<","<").Replace(">",">");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Default article bodies (Markdown).
|
/// Default article bodies (Markdown). EN + FA per post.
|
||||||
internal static class DefaultBodies
|
internal static class DefaultBodies
|
||||||
{
|
{
|
||||||
public const string RagEval = """
|
public const string RagEval = """
|
||||||
## Why standard metrics fail for RAG
|
## Why standard metrics fail for RAG
|
||||||
|
|
||||||
BLEU and ROUGE measure n-gram overlap against a reference answer. In a RAG system, there is often no single correct reference — a question about company policy may have dozens of valid phrasings. High BLEU does not mean the system cited the right source; low BLEU does not mean it was wrong.
|
BLEU and ROUGE measure n-gram overlap against a reference answer. In a RAG system there is often no single correct reference: a question about company policy may have dozens of valid phrasings. High BLEU does not mean the system cited the right source; low BLEU does not mean it was wrong.
|
||||||
|
|
||||||
## The three metrics that actually matter
|
## The three metrics that actually matter
|
||||||
|
|
||||||
@@ -97,55 +98,117 @@ BLEU and ROUGE measure n-gram overlap against a reference answer. In a RAG syste
|
|||||||
|
|
||||||
**Context Precision** asks: of the passages retrieved, how many were actually relevant to the question? Low precision wastes context window and increases hallucination risk.
|
**Context Precision** asks: of the passages retrieved, how many were actually relevant to the question? Low precision wastes context window and increases hallucination risk.
|
||||||
|
|
||||||
**Answer Relevancy** checks whether the final response actually addresses what was asked — not just whether it sounds good.
|
**Answer Relevancy** checks whether the final response actually addresses what was asked, not just whether it sounds good.
|
||||||
|
|
||||||
## Building an eval harness
|
## Building an eval harness
|
||||||
|
|
||||||
Start with a **golden dataset**: 100–200 question/answer pairs that domain experts have verified. Run your pipeline against them nightly. Track the three metrics above over time. A drop in Faithfulness after a model upgrade is a red flag; a drop in Context Precision after a chunking change means your retrieval is degrading.
|
Start with a **golden dataset**: 100-200 question/answer pairs that domain experts have verified. Run your pipeline against them nightly. Track the three metrics above over time. A drop in Faithfulness after a model upgrade is a red flag; a drop in Context Precision after a chunking change means your retrieval is degrading.
|
||||||
|
|
||||||
The harness does not have to be complex. A spreadsheet with automatic scoring via the OpenAI or Anthropic API is enough to start catching regressions before they reach production.
|
The harness does not have to be complex. A spreadsheet with automatic scoring via the OpenAI or Anthropic API is enough to start catching regressions before they reach production.
|
||||||
|
""";
|
||||||
|
|
||||||
|
public const string RagEvalFa = """
|
||||||
|
## چرا معیارهای استاندارد برای RAG جواب نمیدهند
|
||||||
|
|
||||||
|
BLEU و ROUGE میزان همپوشانی n-gram را با یک پاسخ مرجع میسنجند. در یک سامانهی RAG معمولاً پاسخ مرجع واحدی وجود ندارد؛ یک پرسش دربارهی سیاستهای سازمان میتواند دهها بیان درست داشته باشد. BLEU بالا به این معنا نیست که سیستم به منبع درست ارجاع داده، و BLEU پایین هم به این معنا نیست که اشتباه کرده.
|
||||||
|
|
||||||
|
## سه معیاری که واقعاً مهماند
|
||||||
|
|
||||||
|
**وفاداری (Faithfulness)** میسنجد که آیا هر ادعای پاسخ تولیدشده را میتوان به یک قطعهی بازیابیشده ردیابی کرد. امتیاز وفاداری ۱.۰ یعنی مدل چیزی از خودش نساخته. ابزارهایی مثل RAGAS این را با یک داور LLM پیاده میکنند.
|
||||||
|
|
||||||
|
**دقت زمینه (Context Precision)** میپرسد: از میان قطعههای بازیابیشده، چند تا واقعاً به پرسش مربوط بودند؟ دقت پایین، پنجرهی زمینه را هدر میدهد و خطر توهم را بالا میبرد.
|
||||||
|
|
||||||
|
**مرتبطبودن پاسخ (Answer Relevancy)** بررسی میکند که پاسخ نهایی واقعاً به آنچه پرسیده شده جواب میدهد، نه اینکه فقط خوب به نظر برسد.
|
||||||
|
|
||||||
|
## ساختن یک بستر ارزیابی
|
||||||
|
|
||||||
|
با یک **دیتاست طلایی** شروع کنید: ۱۰۰ تا ۲۰۰ جفت پرسش و پاسخ که کارشناسان حوزه تأییدشان کردهاند. هر شب پایپلاین را روی آنها اجرا کنید و این سه معیار را در طول زمان دنبال کنید. افت وفاداری بعد از ارتقای مدل یک هشدار جدی است؛ افت دقت زمینه بعد از تغییر قطعهبندی یعنی بازیابیتان دارد بدتر میشود.
|
||||||
|
|
||||||
|
بستر ارزیابی لازم نیست پیچیده باشد. یک صفحهگسترده با امتیازدهی خودکار از طریق API اوپنایآی یا Anthropic، برای شروع و گرفتن افت کیفیت پیش از رسیدن به تولید کافی است.
|
||||||
""";
|
""";
|
||||||
|
|
||||||
public const string N8nPatterns = """
|
public const string N8nPatterns = """
|
||||||
## The problem with "just use n8n"
|
## The problem with "just use n8n"
|
||||||
|
|
||||||
n8n is excellent for integrating SaaS tools. It becomes fragile when you try to use it as an agent orchestrator — long-running loops, conditional retries, and LLM calls that can fail in non-obvious ways.
|
n8n is excellent for integrating SaaS tools. It becomes fragile when you try to use it as an agent orchestrator: long-running loops, conditional retries, and LLM calls that can fail in non-obvious ways.
|
||||||
|
|
||||||
## Separating orchestration from integration
|
## Separating orchestration from integration
|
||||||
|
|
||||||
The pattern that works: **n8n handles triggers and integrations; LangGraph handles agent logic**.
|
The pattern that works: **n8n handles triggers and integrations; LangGraph handles agent logic**.
|
||||||
|
|
||||||
An n8n workflow watches a Slack channel. When a message matches a pattern, it calls a LangGraph endpoint with the raw payload. LangGraph runs the multi-step reasoning loop, maintains state, and returns a structured result. n8n takes that result and routes it — posts to Jira, sends an email, updates a database row.
|
An n8n workflow watches a Slack channel. When a message matches a pattern, it calls a LangGraph endpoint with the raw payload. LangGraph runs the multi-step reasoning loop, maintains state, and returns a structured result. n8n takes that result and routes it: posts to Jira, sends an email, updates a database row.
|
||||||
|
|
||||||
## Making agents auditable
|
## Making agents auditable
|
||||||
|
|
||||||
Every LangGraph state transition should emit an event to a structured log. We use a Postgres table with columns: `run_id`, `step`, `input`, `output`, `timestamp`. This table becomes the audit trail that compliance teams and on-call engineers both need.
|
Every LangGraph state transition should emit an event to a structured log. We use a Postgres table with columns: `run_id`, `step`, `input`, `output`, `timestamp`. This table becomes the audit trail that compliance teams and on-call engineers both need.
|
||||||
|
|
||||||
Add a `human_in_the_loop` node for any action that cannot be undone — deleting records, sending external emails, approving payments. The node pauses execution and posts to Slack; a human approves or rejects; execution resumes.
|
Add a `human_in_the_loop` node for any action that cannot be undone: deleting records, sending external emails, approving payments. The node pauses execution and posts to Slack; a human approves or rejects; execution resumes.
|
||||||
|
|
||||||
## Handling failures gracefully
|
## Handling failures gracefully
|
||||||
|
|
||||||
LLM calls fail. Build **retry with exponential backoff** into every LangGraph node that calls an LLM. Set a hard limit of 3 retries, then route to a dead-letter state that pages the on-call engineer. Never silently swallow errors in agentic pipelines — a swallowed error is an invisible outage.
|
LLM calls fail. Build **retry with exponential backoff** into every LangGraph node that calls an LLM. Set a hard limit of 3 retries, then route to a dead-letter state that pages the on-call engineer. Never silently swallow errors in agentic pipelines. A swallowed error is an invisible outage.
|
||||||
|
""";
|
||||||
|
|
||||||
|
public const string N8nPatternsFa = """
|
||||||
|
## مشکلِ «فقط از n8n استفاده کن»
|
||||||
|
|
||||||
|
n8n برای اتصال ابزارهای SaaS عالی است. اما وقتی بخواهید از آن بهعنوان ارکستراتورِ عامل استفاده کنید شکننده میشود؛ حلقههای طولانی، تلاشهای مجدد شرطی، و فراخوانیهای LLM که میتوانند به شکلهای غیرمنتظره شکست بخورند.
|
||||||
|
|
||||||
|
## جدا کردن ارکستراسیون از یکپارچهسازی
|
||||||
|
|
||||||
|
الگویی که جواب میدهد: **n8n تریگرها و یکپارچهسازیها را مدیریت کند، LangGraph منطقِ عامل را**.
|
||||||
|
|
||||||
|
یک گردشکار n8n یک کانال Slack را زیر نظر میگیرد. وقتی پیامی با الگو مطابقت کرد، یک endpoint از LangGraph را با دادهی خام صدا میزند. LangGraph حلقهی استدلال چندمرحلهای را اجرا میکند، حالت را نگه میدارد و یک نتیجهی ساختارمند برمیگرداند. بعد n8n آن نتیجه را مسیردهی میکند؛ در Jira ثبت میکند، ایمیل میفرستد، یا یک ردیف پایگاهداده را بهروز میکند.
|
||||||
|
|
||||||
|
## قابلممیزی کردنِ عاملها
|
||||||
|
|
||||||
|
هر گذارِ حالت در LangGraph باید یک رویداد در یک لاگ ساختارمند ثبت کند. ما از یک جدول Postgres با ستونهای `run_id`، `step`، `input`، `output` و `timestamp` استفاده میکنیم. این جدول همان ردِ ممیزیای میشود که هم تیمهای انطباق و هم مهندسان کشیک به آن نیاز دارند.
|
||||||
|
|
||||||
|
برای هر کاری که برگشتپذیر نیست یک گرهی `human_in_the_loop` اضافه کنید؛ حذف رکورد، ارسال ایمیل بیرونی، تأیید پرداخت. این گره اجرا را متوقف میکند و در Slack پیام میگذارد؛ یک انسان تأیید یا رد میکند و اجرا ادامه پیدا میکند.
|
||||||
|
|
||||||
|
## مدیریت درستِ خطاها
|
||||||
|
|
||||||
|
فراخوانیهای LLM شکست میخورند. در هر گرهی LangGraph که LLM را صدا میزند **تلاش مجدد با backoff نمایی** بسازید. سقف سه بار تلاش بگذارید، بعد به یک حالت dead-letter مسیردهی کنید که مهندس کشیک را خبر کند. در پایپلاینهای عاملمحور هیچوقت خطا را بیصدا فرو نخورید؛ یک خطای فروخورده، یک قطعی نامرئی است.
|
||||||
""";
|
""";
|
||||||
|
|
||||||
public const string VertexCost = """
|
public const string VertexCost = """
|
||||||
## Anti-pattern 1: calling Gemini Ultra for everything
|
## Anti-pattern 1: calling Gemini Ultra for everything
|
||||||
|
|
||||||
Gemini Ultra (or GPT-4-class models) costs 10–30× more per token than smaller models. Many teams default to the most capable model because it "just works" during prototyping, then never re-evaluate.
|
Gemini Ultra (or GPT-4-class models) costs 10 to 30 times more per token than smaller models. Many teams default to the most capable model because it "just works" during prototyping, then never re-evaluate.
|
||||||
|
|
||||||
**Fix**: build a **model router**. Classify each incoming request by complexity. Simple lookups, short summaries, and classification tasks go to Gemini Flash or Haiku. Only complex reasoning, multi-step synthesis, and long-context tasks go to Pro or Ultra. In most production systems, 60–80% of requests can be served by the cheaper tier.
|
**Fix**: build a **model router**. Classify each incoming request by complexity. Simple lookups, short summaries, and classification tasks go to Gemini Flash or Haiku. Only complex reasoning, multi-step synthesis, and long-context tasks go to Pro or Ultra. In most production systems, 60-80% of requests can be served by the cheaper tier.
|
||||||
|
|
||||||
## Anti-pattern 2: no context caching
|
## Anti-pattern 2: no context caching
|
||||||
|
|
||||||
Vertex AI supports prompt caching (as does the Anthropic API). A system prompt that is 10k tokens, sent with every request at $3/M tokens, costs $30 for every million calls before the user has typed a single word.
|
Vertex AI supports prompt caching (as does the Anthropic API). A system prompt that is 10k tokens, sent with every request at $3/M tokens, costs $30 for every million calls before the user has typed a single word.
|
||||||
|
|
||||||
**Fix**: cache any context that is static or changes infrequently — system prompts, retrieved document sets, few-shot examples. Cache hits cost ~10% of full input price.
|
**Fix**: cache any context that is static or changes infrequently: system prompts, retrieved document sets, few-shot examples. Cache hits cost about 10% of full input price.
|
||||||
|
|
||||||
## Anti-pattern 3: synchronous batch jobs
|
## Anti-pattern 3: synchronous batch jobs
|
||||||
|
|
||||||
Teams run nightly document processing jobs synchronously — one document at a time, each blocked on the previous. This is slow and expensive because you pay for idle wait time between calls.
|
Teams run nightly document processing jobs synchronously, one document at a time, each blocked on the previous. This is slow and expensive because you pay for idle wait time between calls.
|
||||||
|
|
||||||
**Fix**: use the Vertex AI batch prediction API for jobs over ~1,000 documents. Batch jobs run asynchronously, are eligible for spot discounts, and typically cost 50% less per token than online serving.
|
**Fix**: use the Vertex AI batch prediction API for jobs over ~1,000 documents. Batch jobs run asynchronously, are eligible for spot discounts, and typically cost 50% less per token than online serving.
|
||||||
|
""";
|
||||||
|
|
||||||
|
public const string VertexCostFa = """
|
||||||
|
## ضدالگوی اول: صدا زدن Gemini Ultra برای همهچیز
|
||||||
|
|
||||||
|
Gemini Ultra (یا مدلهای همردهی GPT-4) به ازای هر توکن ۱۰ تا ۳۰ برابر گرانتر از مدلهای کوچکترند. خیلی از تیمها در مرحلهی نمونهسازی سراغ توانمندترین مدل میروند چون «همینجوری کار میکند» و بعد دیگر هیچوقت بازنگری نمیکنند.
|
||||||
|
|
||||||
|
**راهحل**: یک **مسیردهندهی مدل (model router)** بسازید. هر درخواست ورودی را بر اساس پیچیدگی دستهبندی کنید. جستوجوهای ساده، خلاصههای کوتاه و کارهای دستهبندی به Gemini Flash یا Haiku بروند. فقط استدلالهای پیچیده، ترکیب چندمرحلهای و کارهای با زمینهی طولانی به Pro یا Ultra. در بیشتر سامانههای تولیدی، ۶۰ تا ۸۰ درصد درخواستها را میشود با ردهی ارزانتر سرویس داد.
|
||||||
|
|
||||||
|
## ضدالگوی دوم: نبودِ کشِ زمینه
|
||||||
|
|
||||||
|
Vertex AI از کش کردن prompt پشتیبانی میکند (مثل API اَنتروپیک). یک system prompt دههزار توکنی که با هر درخواست و با نرخ ۳ دلار به ازای هر میلیون توکن فرستاده میشود، پیش از آنکه کاربر حتی یک کلمه تایپ کند، برای هر میلیون فراخوانی ۳۰ دلار خرج برمیدارد.
|
||||||
|
|
||||||
|
**راهحل**: هر زمینهای که ثابت است یا کم تغییر میکند را کش کنید؛ system promptها، مجموعهی اسناد بازیابیشده، نمونههای few-shot. هزینهی hit کش حدود ۱۰ درصد قیمت کامل ورودی است.
|
||||||
|
|
||||||
|
## ضدالگوی سوم: کارهای دستهای همگام
|
||||||
|
|
||||||
|
تیمها کارهای شبانهی پردازش سند را همگام اجرا میکنند؛ سند به سند، هرکدام منتظر قبلی. این کُند و گران است چون بابت زمان انتظارِ بیکار بین فراخوانیها هم پول میدهید.
|
||||||
|
|
||||||
|
**راهحل**: برای کارهای بالای حدود ۱۰۰۰ سند از batch prediction API در Vertex AI استفاده کنید. کارهای دستهای ناهمگام اجرا میشوند، واجد تخفیف spot هستند و معمولاً به ازای هر توکن ۵۰ درصد ارزانتر از سرویسدهی آنلاین تمام میشوند.
|
||||||
""";
|
""";
|
||||||
|
|
||||||
public const string K8sInference = """
|
public const string K8sInference = """
|
||||||
@@ -155,25 +218,47 @@ A single Kubernetes `Deployment` behind a `ClusterIP` `Service`, fronted by an I
|
|||||||
|
|
||||||
## Autoscaling with KEDA
|
## Autoscaling with KEDA
|
||||||
|
|
||||||
HPA (Horizontal Pod Autoscaler) scales on CPU and memory. LLM inference is GPU-bound and queue-depth-bound — neither maps to CPU utilization well.
|
HPA (Horizontal Pod Autoscaler) scales on CPU and memory. LLM inference is GPU-bound and queue-depth-bound, and neither maps to CPU utilization well.
|
||||||
|
|
||||||
KEDA (Kubernetes Event-Driven Autoscaling) scales on arbitrary metrics — queue depth, Pub/Sub lag, Redis list length. We publish inference request counts to a Redis stream; KEDA scales the model server pods when the stream depth exceeds a threshold. Scaling-up latency drops from minutes (cluster autoscaler cold start) to seconds (replica scale-up from 1 to N).
|
KEDA (Kubernetes Event-Driven Autoscaling) scales on arbitrary metrics: queue depth, Pub/Sub lag, Redis list length. We publish inference request counts to a Redis stream; KEDA scales the model server pods when the stream depth exceeds a threshold. Scaling-up latency drops from minutes (cluster autoscaler cold start) to seconds (replica scale-up from 1 to N).
|
||||||
|
|
||||||
## GPU sharing with time-slicing
|
## GPU sharing with time-slicing
|
||||||
|
|
||||||
For models that fit in 4–8 GB VRAM, full GPU dedication is wasteful. NVIDIA's time-slicing MIG (Multi-Instance GPU) lets multiple pods share one A100, each getting a guaranteed slice.
|
For models that fit in 4 to 8 GB VRAM, full GPU dedication is wasteful. NVIDIA's time-slicing MIG (Multi-Instance GPU) lets multiple pods share one A100, each getting a guaranteed slice.
|
||||||
|
|
||||||
Configure `nvidia.com/gpu: 1` and set the time-slice profile to `1g.10gb`. A single A100 80GB can serve 8 concurrent model instances at 10 GB each — 8× the throughput per GPU.
|
Configure `nvidia.com/gpu: 1` and set the time-slice profile to `1g.10gb`. A single A100 80GB can serve 8 concurrent model instances at 10 GB each, 8 times the throughput per GPU.
|
||||||
|
|
||||||
## Request hedging for tail latency
|
## Request hedging for tail latency
|
||||||
|
|
||||||
p50 latency is 12ms. p99 is 280ms. The tail is dominated by KV-cache misses and occasional GC pauses. **Hedged requests**: after 40ms, send a duplicate request to a second replica. Take whichever response arrives first; cancel the other. This cuts p99 from 280ms to ~45ms with only ~15% increase in total compute.
|
p50 latency is 12ms. p99 is 280ms. The tail is dominated by KV-cache misses and occasional GC pauses. **Hedged requests**: after 40ms, send a duplicate request to a second replica. Take whichever response arrives first; cancel the other. This cuts p99 from 280ms to ~45ms with only ~15% increase in total compute.
|
||||||
|
""";
|
||||||
|
|
||||||
|
public const string K8sInferenceFa = """
|
||||||
|
## معماری پایه
|
||||||
|
|
||||||
|
یک `Deployment` در Kubernetes پشتِ یک `Service` از نوع `ClusterIP` که یک Ingress جلویش قرار گرفته. تا حدود ۵۰ درخواست بر ثانیه برای یک مدل کوچک خوب کار میکند. اما وقتی ترافیک ناگهان بالا میرود، یا زمانبندی podهای GPU سه دقیقه طول میکشد، یا سرور مدل دو ثانیه cold-start دارد، از هم میپاشد.
|
||||||
|
|
||||||
|
## مقیاس خودکار با KEDA
|
||||||
|
|
||||||
|
HPA (مقیاسگذار افقی pod) بر اساس CPU و حافظه مقیاس میدهد. اما استنتاج LLM به GPU و عمق صف وابسته است و هیچکدام با مصرف CPU خوب نگاشت نمیشوند.
|
||||||
|
|
||||||
|
KEDA (مقیاس خودکار رویدادمحور Kubernetes) بر اساس هر معیار دلخواهی مقیاس میدهد؛ عمق صف، تأخیر Pub/Sub، طول لیست Redis. ما تعداد درخواستهای استنتاج را در یک stream در Redis منتشر میکنیم؛ KEDA وقتی عمق stream از یک آستانه عبور کند podهای سرور مدل را مقیاس میدهد. تأخیر مقیاسگرفتن از چند دقیقه (cold-start مقیاسگذار خوشه) به چند ثانیه (افزایش replica از ۱ به N) میرسد.
|
||||||
|
|
||||||
|
## اشتراک GPU با time-slicing
|
||||||
|
|
||||||
|
برای مدلهایی که در ۴ تا ۸ گیگابایت VRAM جا میشوند، اختصاص کاملِ GPU اسراف است. فناوری time-slicing و MIG انویدیا (GPU چنداینستنسه) اجازه میدهد چند pod یک A100 را به اشتراک بگذارند و هرکدام یک سهم تضمینشده بگیرند.
|
||||||
|
|
||||||
|
`nvidia.com/gpu: 1` را تنظیم کنید و پروفایل time-slice را روی `1g.10gb` بگذارید. یک A100 هشتادگیگابایتی میتواند ۸ اینستنس مدل را همزمان، هرکدام با ۱۰ گیگابایت، سرویس بدهد؛ یعنی ۸ برابرِ توان عبوری به ازای هر GPU.
|
||||||
|
|
||||||
|
## hedging درخواست برای تأخیر دنباله
|
||||||
|
|
||||||
|
تأخیر p50 برابر ۱۲ میلیثانیه است و p99 برابر ۲۸۰ میلیثانیه. دنباله را عمدتاً missهای KV-cache و مکثهای گاهبهگاه GC میسازند. **درخواستهای hedged**: بعد از ۴۰ میلیثانیه یک درخواست تکراری به replica دوم بفرستید. هر پاسخی زودتر رسید همان را بردارید و دیگری را لغو کنید. این کار p99 را از ۲۸۰ به حدود ۴۵ میلیثانیه میرساند، با تنها حدود ۱۵ درصد افزایش در کل محاسبات.
|
||||||
""";
|
""";
|
||||||
|
|
||||||
public const string FlutterAI = """
|
public const string FlutterAI = """
|
||||||
## Why on-device inference matters
|
## Why on-device inference matters
|
||||||
|
|
||||||
Cloud inference requires a network round-trip, exposes user data to a server, and fails in offline scenarios. For consumer apps — messaging, health, productivity — on-device inference is often a requirement, not a nice-to-have.
|
Cloud inference requires a network round-trip, exposes user data to a server, and fails in offline scenarios. For consumer apps (messaging, health, productivity) on-device inference is often a requirement, not a nice-to-have.
|
||||||
|
|
||||||
## Gemini Nano and LiteRT
|
## Gemini Nano and LiteRT
|
||||||
|
|
||||||
@@ -183,34 +268,78 @@ LiteRT (formerly TensorFlow Lite) handles vision and custom small models. For cl
|
|||||||
|
|
||||||
## Streaming UX without a network
|
## Streaming UX without a network
|
||||||
|
|
||||||
The key insight: users tolerate slightly slower responses if they can see text appearing token by token. Even on-device inference can stream — Gemini Nano's Dart SDK exposes a `generateContentStream` method. Pipe tokens directly to a Flutter `StreamBuilder` for a responsive feel regardless of total generation time.
|
The key insight: users tolerate slightly slower responses if they can see text appearing token by token. Even on-device inference can stream. Gemini Nano's Dart SDK exposes a `generateContentStream` method. Pipe tokens directly to a Flutter `StreamBuilder` for a responsive feel regardless of total generation time.
|
||||||
|
|
||||||
## Battery and thermal management
|
## Battery and thermal management
|
||||||
|
|
||||||
On-device inference heats the chip. Implement **thermal throttling**: check `DeviceInfo.thermalState` (iOS) or subscribe to the battery API on Android. Reduce `maxTokens` from 512 to 128 during sustained load. Schedule background inference tasks during charging. Users notice neither the throttling nor the scheduling — they notice when their phone gets too hot.
|
On-device inference heats the chip. Implement **thermal throttling**: check `DeviceInfo.thermalState` (iOS) or subscribe to the battery API on Android. Reduce `maxTokens` from 512 to 128 during sustained load. Schedule background inference tasks during charging. Users notice neither the throttling nor the scheduling. They notice when their phone gets too hot.
|
||||||
|
""";
|
||||||
|
|
||||||
|
public const string FlutterAIFa = """
|
||||||
|
## چرا استنتاج روی دستگاه مهم است
|
||||||
|
|
||||||
|
استنتاج ابری یک رفتوبرگشتِ شبکه میخواهد، دادهی کاربر را در معرض سرور میگذارد، و در حالت آفلاین شکست میخورد. برای اپهای مصرفی مثل پیامرسان، سلامت و بهرهوری، استنتاج روی دستگاه اغلب یک الزام است، نه یک امکانِ خوببهداشتن.
|
||||||
|
|
||||||
|
## Gemini Nano و LiteRT
|
||||||
|
|
||||||
|
Gemini Nano گوگل یک مدل ۱.۸ میلیارد پارامتری است که کوانتیزه شده تا روی NPUهای موبایل (واحدهای پردازش عصبی) اجرا شود. یکپارچهسازی با Flutter از پکیج `google_ai_dart_sdk` و `GeminiNanoModel` استفاده میکند و وقتی مدلِ روی دستگاه در دسترس نباشد به استنتاج ابری برمیگردد.
|
||||||
|
|
||||||
|
LiteRT (همان TensorFlow Lite سابق) بینایی و مدلهای کوچک سفارشی را مدیریت میکند. برای کارهای دستهبندی و embedding، یک مدل کوانتیزهی ۵۰ مگابایتی روی یک گوشی اندرویدی میانرده در کمتر از ۲۰ میلیثانیه اجرا میشود.
|
||||||
|
|
||||||
|
## تجربهی استریم بدون شبکه
|
||||||
|
|
||||||
|
نکتهی کلیدی: کاربرها پاسخ کمی کندتر را تحمل میکنند اگر ببینند متن توکنبهتوکن ظاهر میشود. حتی استنتاج روی دستگاه هم میتواند استریم کند. Dart SDK مربوط به Gemini Nano متد `generateContentStream` را در اختیار میگذارد. توکنها را مستقیم به یک `StreamBuilder` در Flutter بدهید تا فارغ از کل زمان تولید، حسی پاسخگو داشته باشید.
|
||||||
|
|
||||||
|
## مدیریت باتری و دما
|
||||||
|
|
||||||
|
استنتاج روی دستگاه تراشه را گرم میکند. **throttling حرارتی** پیاده کنید: `DeviceInfo.thermalState` را در iOS بررسی کنید یا در اندروید به API باتری گوش بدهید. زیر بار طولانی `maxTokens` را از ۵۱۲ به ۱۲۸ کم کنید. کارهای استنتاجِ پسزمینه را برای زمان شارژ زمانبندی کنید. کاربر نه throttling را میفهمد و نه زمانبندی را؛ فقط وقتی گوشیاش داغ شود متوجه میشود.
|
||||||
""";
|
""";
|
||||||
|
|
||||||
public const string EnterpriseRoadmap = """
|
public const string EnterpriseRoadmap = """
|
||||||
## Days 1–30: discovery
|
## Days 1-30: discovery
|
||||||
|
|
||||||
The most expensive mistake in enterprise AI is building the wrong thing fast. Discovery is not a formality — it is the work.
|
The most expensive mistake in enterprise AI is building the wrong thing fast. Discovery is not a formality. It is the work.
|
||||||
|
|
||||||
Interview 8–12 stakeholders across business units. For each, ask: what manual task takes more than 2 hours per week? What decision do you make with incomplete information? What report do you wish existed but is too expensive to build?
|
Interview 8 to 12 stakeholders across business units. For each, ask: what manual task takes more than 2 hours per week? What decision do you make with incomplete information? What report do you wish existed but is too expensive to build?
|
||||||
|
|
||||||
Map the candidates on a 2×2: **impact** (revenue, cost, risk) vs **feasibility** (data quality, integration complexity, regulatory constraints). The top-right quadrant is your first sprint.
|
Map the candidates on a 2x2: **impact** (revenue, cost, risk) vs **feasibility** (data quality, integration complexity, regulatory constraints). The top-right quadrant is your first sprint.
|
||||||
|
|
||||||
## Days 31–60: prototype and validate
|
## Days 31-60: prototype and validate
|
||||||
|
|
||||||
Pick one use case from the top-right. Build a prototype in 3 weeks. The prototype does not have to be production-grade — it has to be **testable by domain experts**.
|
Pick one use case from the top-right. Build a prototype in 3 weeks. The prototype does not have to be production-grade. It has to be **testable by domain experts**.
|
||||||
|
|
||||||
Run a structured eval: 100 questions, domain expert scores each answer 1–5. Set a threshold (e.g., ≥4.0 average) before the sprint begins. If the prototype clears it, proceed to production hardening. If it doesn't, investigate root cause — usually data quality or chunking strategy — before committing engineering resources.
|
Run a structured eval: 100 questions, domain expert scores each answer 1 to 5. Set a threshold (e.g. 4.0 average or higher) before the sprint begins. If the prototype clears it, proceed to production hardening. If it does not, investigate root cause (usually data quality or chunking strategy) before committing engineering resources.
|
||||||
|
|
||||||
## Days 61–90: first production deployment
|
## Days 61-90: first production deployment
|
||||||
|
|
||||||
Scope the first deployment to a single team of 10–20 people. This limits blast radius and generates real usage data fast.
|
Scope the first deployment to a single team of 10 to 20 people. This limits blast radius and generates real usage data fast.
|
||||||
|
|
||||||
Instrument everything: latency, cost per query, thumbs-up/thumbs-down from users, faithfulness score from the automated harness. Review metrics weekly with the business owner. Adjust chunking, retrieval strategy, or model tier based on what the data shows — not intuition.
|
Instrument everything: latency, cost per query, thumbs-up/thumbs-down from users, faithfulness score from the automated harness. Review metrics weekly with the business owner. Adjust chunking, retrieval strategy, or model tier based on what the data shows, not intuition.
|
||||||
|
|
||||||
At day 90, you have a live system, a tuned eval harness, and a clear picture of what the second use case should be. That is the foundation for a credible 12-month roadmap.
|
At day 90, you have a live system, a tuned eval harness, and a clear picture of what the second use case should be. That is the foundation for a credible 12-month roadmap.
|
||||||
|
""";
|
||||||
|
|
||||||
|
public const string EnterpriseRoadmapFa = """
|
||||||
|
## روز ۱ تا ۳۰: کشف
|
||||||
|
|
||||||
|
گرانترین اشتباه در هوش مصنوعی سازمانی، سریعساختنِ چیز اشتباه است. کشف یک تشریفات نیست؛ خودِ کار است.
|
||||||
|
|
||||||
|
با ۸ تا ۱۲ ذینفع در واحدهای مختلفِ کسبوکار مصاحبه کنید. از هرکدام بپرسید: کدام کار دستی بیش از دو ساعت در هفته وقت میگیرد؟ کدام تصمیم را با اطلاعات ناقص میگیرید؟ کدام گزارش را آرزو دارید داشته باشید ولی ساختنش گران است؟
|
||||||
|
|
||||||
|
نامزدها را روی یک ماتریس ۲×۲ بچینید: **اثر** (درآمد، هزینه، ریسک) در برابر **امکانپذیری** (کیفیت داده، پیچیدگی یکپارچهسازی، محدودیتهای مقرراتی). ربعِ بالا-راست، اولین sprint شماست.
|
||||||
|
|
||||||
|
## روز ۳۱ تا ۶۰: نمونهی اولیه و اعتبارسنجی
|
||||||
|
|
||||||
|
یک مورد کاربری از ربعِ بالا-راست بردارید. در سه هفته یک نمونهی اولیه بسازید. نمونه لازم نیست در سطح تولید باشد؛ باید **توسط کارشناسان حوزه قابلآزمون** باشد.
|
||||||
|
|
||||||
|
یک ارزیابی ساختارمند اجرا کنید: ۱۰۰ پرسش، کارشناس حوزه به هر پاسخ از ۱ تا ۵ امتیاز میدهد. پیش از شروع sprint یک آستانه بگذارید (مثلاً میانگین ۴.۰ یا بالاتر). اگر نمونه از آن گذشت، به سمتِ سختسازی برای تولید بروید. اگر نگذشت، ریشه را پیدا کنید (معمولاً کیفیت داده یا راهبرد قطعهبندی) و بعد منابع مهندسی را متعهد کنید.
|
||||||
|
|
||||||
|
## روز ۶۱ تا ۹۰: اولین استقرار تولید
|
||||||
|
|
||||||
|
اولین استقرار را به یک تیم ۱۰ تا ۲۰ نفره محدود کنید. این کار شعاع آسیب را کم میکند و سریع دادهی استفادهی واقعی میسازد.
|
||||||
|
|
||||||
|
همهچیز را اندازه بگیرید: تأخیر، هزینه به ازای هر پرسش، بازخورد مثبت و منفی کاربرها، امتیاز وفاداری از بسترِ خودکار. هفتگی با صاحب کسبوکار معیارها را مرور کنید. قطعهبندی، راهبرد بازیابی یا ردهی مدل را بر اساس آنچه داده نشان میدهد تنظیم کنید، نه بر اساس حدس.
|
||||||
|
|
||||||
|
در روز ۹۰ یک سامانهی زنده، یک بسترِ ارزیابیِ تنظیمشده، و تصویری روشن از اینکه دومین مورد کاربری چه باید باشد دارید. این، پایهی یک نقشهی راهِ ۱۲ماههی معتبر است.
|
||||||
""";
|
""";
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user