<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://thakicloud.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://thakicloud.github.io/" rel="alternate" type="text/html" /><updated>2026-07-16T01:55:36+09:00</updated><id>https://thakicloud.github.io/feed.xml</id><title type="html">Thaki Cloud Tech Blog | ThakiCloud | 다키클라우드 기술 블로그</title><subtitle>Thaki Cloud (ThakiCloud, 다키클라우드, thaki cloud, THAKI CLOUD, ثاكي كلاود)는 AI/ML Engineering, LLMOps, DevOps 분야의 최신 기술과 실무 경험을 공유하는 전문 기술 블로그입니다. 머신러닝 모델 운영, 쿠버네티스, 클라우드 인프라, AI 엔지니어링 커리어, 인공지능 기술 블로그, 다키클라우드 개발 팀의 깊이 있는 인사이트를 제공합니다. مدونة تقنية متخصصة في هندسة الذكاء الاصطناعي والحوسبة السحابية.</subtitle><author><name>{&quot;name&quot;=&gt;nil, &quot;avatar&quot;=&gt;nil, &quot;bio&quot;=&gt;nil, &quot;location&quot;=&gt;&quot;Seoul, Korea&quot;, &quot;email&quot;=&gt;&quot;info@thakicloud.co.kr&quot;, &quot;uri&quot;=&gt;nil, &quot;home&quot;=&gt;nil, &quot;links&quot;=&gt;[{&quot;label&quot;=&gt;&quot;Website&quot;, &quot;icon&quot;=&gt;&quot;fas fa-fw fa-link&quot;, &quot;url&quot;=&gt;&quot;https://thakicloud.co.kr&quot;}, {&quot;label&quot;=&gt;&quot;GitHub&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-github&quot;, &quot;url&quot;=&gt;&quot;https://github.com/thakicloud&quot;}]}</name><email>info@thakicloud.co.kr</email></author><entry xml:lang="ko"><title type="html">자율 조치할까, 사람을 부를까: Kubernetes GPU 인시던트 대응의 안전 경계를 계산하다</title><link href="https://thakicloud.github.io/ko/research/safe-autonomy-k8s-remediation/" rel="alternate" type="text/html" title="자율 조치할까, 사람을 부를까: Kubernetes GPU 인시던트 대응의 안전 경계를 계산하다" /><published>2026-07-16T00:00:00+09:00</published><updated>2026-07-16T00:00:00+09:00</updated><id>https://thakicloud.github.io/ko/research/safe-autonomy-k8s-remediation</id><content type="html" xml:base="https://thakicloud.github.io/ko/research/safe-autonomy-k8s-remediation/"><![CDATA[<p>멀티테넌트 GPU 클러스터를 운영하면서 온콜 부담을 줄이려고 LLM 에이전트에게 인시던트 원격조치를 맡길지 고민해본 SRE와 MLOps 엔지니어라면, 이 글에서 소개하는 논문이 던지는 질문에 이미 한 번쯤 부딪혀 봤을 것입니다. 에이전트가 스스로 판단해 조치하도록 둘 것인가, 아니면 사람을 호출할 것인가. 이 경계를 직관이나 팀 회의에서의 감으로 정하는 대신, 인시던트 유형별로 위험도를 수식화하고 안전 상한선 아래에서 회복 시간을 최대한 줄이는 임계값을 실제로 계산해낸 연구입니다. Kueue 큐잉과 Kyverno 어드미션 정책으로 GPU 워크로드를 운영하는 조직이라면 곧바로 참고할 만한 방법론을 담고 있습니다.</p>

<h2 id="자율-조치와-완전-회피-둘-다-답이-아니다">자율 조치와 완전 회피, 둘 다 답이 아니다</h2>

<p>스케줄러 설정 하나가 어긋나거나, 퍼시스턴트 볼륨이 멈추거나, 노드가 메모리 압박에 시달리면 그 위에서 돌아가던 학습·추론 워크로드가 멈춰 서고, 결국 온콜 엔지니어가 시간에 쫓기며 원인을 파악해 고쳐야 합니다. 여기서 부딪히는 비용은 두 가지입니다. 하나는 평균 복구 시간(MTTR)으로, GPU 워크로드가 멈춰 있는 매 순간이 낭비된 용량이자 깨진 서비스 수준 목표입니다. 다른 하나는 온콜 부담으로, 기계적으로 되돌릴 수 있는 단순한 문제 때문에 사람을 매번 호출하는 일은 느릴 뿐 아니라 운영자를 소진시킵니다. LLM 에이전트가 텔레메트리와 컨트롤 플레인 API를 관찰하고 판단해 조치하는 폐루프를 사람 없이 돌리자는 제안이 매력적으로 들리는 이유입니다.</p>

<p>문제는 그 매력만큼 위험도 크다는 점입니다. 모든 것을 자율로 조치하는 에이전트는 언젠가 되돌릴 수 없는 실수를 저지릅니다. 오래된 스냅샷에서 볼륨을 복원하다 실제 데이터를 지워버리거나, 용량을 확보하려고 다른 테넌트의 살아 있는 GPU 작업을 선점해버리는 식입니다. 반대로 모든 것을 사람에게 넘기는 에이전트는 안전하지만 아무것도 자율로 복구하지 못해 애초에 자동화를 도입한 이유를 무색하게 만듭니다. 이 논문의 벤치마크에서도 두 극단의 대가가 뚜렷하게 드러납니다. “항상 에스컬레이션” 정책은 파국적 방치율이 0%지만 MTTR 개선율도 정확히 0%였고, “항상 자율조치” 정책은 MTTR을 96.7% 줄였지만 진짜 위험한 인시던트의 100%를 잘못 자율조치해버렸습니다. 관심을 가져야 할 지점은 자동화를 할지 말지가 아니라, 자율 행동과 에스컬레이션 사이의 경계를 어디에 어떻게 방어 가능하게 그을 것인가 하는 점입니다.</p>

<h2 id="위험도-공식과-176개-인시던트로-경계선을-계산하다">위험도 공식과 176개 인시던트로 경계선을 계산하다</h2>

<p>연구진은 이 경계선을 out-of-memory(OOM), 퍼시스턴트 볼륨 클레임(PVC) 실패, 노드 압박, 스케줄러 기아 네 가지 인시던트 유형에 걸쳐 다룹니다. 코드 생성 분야의 loop-engineering에서 나온 “컴파일러를 보상 신호로 쓴다”는 아이디어를 인프라 운영으로 확장한 프레임입니다. 코드에서는 컴파일러나 테스트 스위트가 성공 여부를 객관적으로 판정했다면, 인프라 원격조치에서는 kubectl로 얻는 진단 신호가 그 역할을 맡습니다. 다만 이 신호도 코드의 테스트 스위트와 마찬가지로 완벽한 잣대는 아니어서, 진단 신호가 초록불이라고 해서 조치가 진짜로 안전했다는 보장까지는 되지 않는다는 전제를 논문 전체에서 분명히 하고 있습니다.</p>

<p>실제 살아있는 클러스터에 에이전트를 붙여 실험하면 통제 불가능한 변수가 너무 많아지기 때문에, 연구진은 실제 조직의 GitOps 저장소에서 가져온 22개의 Kueue·Kyverno YAML 매니페스트를 8가지 원격조치 액션 클래스와 교차시켜 176개의 인시던트 이벤트를 만들었습니다. 각 이벤트의 위험/안전 정답 라벨은 되돌릴 수 있는지, 데이터가 손실되는지, 테넌트 경계를 넘는지를 기준으로 한 명시적 기준표에서 나왔습니다. 실제 배포된 에이전트의 확신도 대신, 액션 클래스의 되돌릴 수 있는 정도에 따른 기본 위험도, YAML 라인 수로 정규화한 구조적 폭발반경 지표, 클러스터 전역에 영향을 미치는 Kyverno 어드미션 정책인지 여부라는 세 요소를 가중합산한 투명한 위험도 공식을 세웠습니다. 이 공식은 학습된 모델이 아니라 사람이 설계한 대리 지표라는 점을 논문은 반복해서 강조합니다.</p>

<p>이 위험도 점수가 임계값 아래면 자율조치, 그 이상이면 사람에게 넘기는 단순한 결정 규칙 위에서, 파국적 방치율을 2% 이하로 묶는 안전 상한선을 걸고 임계값을 훑었습니다. 그 결과 얻어진 전역 최적 임계값(τ=0.325)은 파국적 방치가 전혀 없는 상태에서 MTTR을 41.7% 줄였고, 이는 항상 에스컬레이션과 항상 자율조치라는 두 극단을 모두 지배하는 지점이었습니다.</p>

<p><img src="/assets/images/posts/research/safe-autonomy-k8s-remediation/pareto-frontier.png" alt="MTTR-vs-Safety Pareto Frontier" />
<em>임계값 τ가 0.35를 넘어서면 파국적 방치율(실선)이 가파르게 치솟는 반면, 불필요한 에스컬레이션율(점선)은 계속 낮아집니다. 삼각형으로 표시된 전역 최적점(τ=0.325)에서 파국적 방치 없이 MTTR을 41.7% 줄였습니다. AI Platform Demo 클러스터의 로컬 벤치마크(176개 합성 인시던트 이벤트)로 측정한 결과이며, 자율조치 지연은 40초, 에스컬레이션 지연은 1200초로 가정했습니다.</em></p>

<h2 id="진짜-핵심-인시던트-유형별로-임계값을-따로-잡아야-한다">진짜 핵심: 인시던트 유형별로 임계값을 따로 잡아야 한다</h2>

<p>논문의 중심 발견은 여기서 한 걸음 더 나아갑니다. 인시던트 유형마다 폭발반경과 테넌트 노출도가 크게 다르기 때문에, 하나의 전역 임계값으로는 이 차이를 담아낼 수 없다는 것입니다. 네 가지 유형별로 안전 상한선(2%)을 유지하면서 각각 최적 임계값을 따로 계산했더니, 노드 압박은 보수적인 τ=0.30(28.6% 개선), PVC 실패는 τ=0.35(43.9% 개선), 스케줄러 기아는 τ=0.45(39.5% 개선), OOM은 훨씬 관대한 τ=0.475(96.7% 개선)로 서로 크게 갈렸습니다. 이 네 유형의 개선율을 평균 내면 52.2%로, 단일 전역 임계값을 모든 유형에 똑같이 적용했을 때의 41.7%보다 약 10.4%포인트 더 높습니다. 같은 안전 상한선을 지키면서도 유형별로 임계값을 나눠 잡는 것만으로 그만큼의 자율성을 추가로 확보할 수 있다는 뜻입니다.</p>

<p><img src="/assets/images/posts/research/safe-autonomy-k8s-remediation/per-type-mttr-reduction.png" alt="Per-Incident-Type MTTR Reduction Under 2% Safety Ceiling" />
<em>인시던트 유형별로 임계값을 따로 보정하면 평균 52.2%의 MTTR 개선을 얻어, 단일 전역 임계값의 41.7%를 웃돕니다. 유형마다 폭발반경과 테넌트 노출도가 다르기 때문입니다. 같은 로컬 벤치마크에서 측정했으며, OOM은 이 기준표에서 위험 라벨이 붙은 액션이 하나도 없어 유독 관대한 임계값(τ=0.475)을 쓸 수 있었습니다.</em></p>

<p>이 격차가 생기는 이유는 명확합니다. 전역 임계값은 가장 위험한 유형(노드 압박이나 테넌트를 넘나드는 스케줄러·PVC 조치)까지 안전 상한선 안에 묶어두려다 보니 보수적으로 잡힐 수밖에 없고, 그 대가는 원래 훨씬 더 자율적으로 돌아도 괜찮았을 유순한 유형들이 함께 치르게 됩니다. 유형별 보정은 이 결합을 풀어냅니다. 실무적으로 보면, 자율 운영 플랫폼이 “위험 허용치” 하나짜리 전역 손잡이만 노출하는 대신, 각 인시던트 클래스가 가진 되돌릴 수 있는 정도와 테넌트 경계 프로필에 맞춰 에스컬레이션 임계값을 따로 잡아야 한다는 설계 시사점으로 이어집니다.</p>

<h2 id="회사와-커뮤니티에-남기는-것">회사와 커뮤니티에 남기는 것</h2>

<p>이 결과는 ThakiCloud가 Kueue·Kubernetes 기반 GPU 인시던트 대응을 실제로 자동화해나갈 때 실측 가능한 자율성 경계 프레임워크로 곧바로 쓸 수 있습니다. MTTR과 온콜 부담을 줄이겠다는 계획을 감이 아니라 근거 데이터 위에서 세울 수 있게 됩니다. 더 넓게는 무인 인프라 운영을 시도하는 다른 조직도 재사용할 수 있는 안전 경계 설계와 에스컬레이션 정책 방법론을 제시한다는 점에서 의미가 있습니다. GPU 클러스터뿐 아니라 스키마 마이그레이션 대 단순 행 수정을 오가는 데이터베이스, 라우팅 변경 대 장비 초기화를 오가는 네트워크, 스냅샷 복원을 다루는 스토리지 등 되돌릴 수 있는 조치와 되돌릴 수 없는 조치가 섞여 있는 어떤 멀티테넌트 컨트롤 플레인에도 같은 구조가 그대로 적용됩니다. 학술적으로는 코드 생성에서 쓰이던 “컴파일러를 보상 신호로” 삼는 loop-engineering 아이디어를 인프라 원격조치 영역으로 명확히 확장하고, 자율성과 안전성의 트레이드오프를 인시던트 유형별로 정량화하는 새로운 측정 방법론을 더했다는 데 기여가 있습니다.</p>

<h2 id="한계도-분명히-짚어야-합니다">한계도 분명히 짚어야 합니다</h2>

<p>이 결과를 읽을 때 반드시 기억해야 할 전제가 있습니다. 연구진은 실제 살아있는 클러스터에 LLM 에이전트를 배치해 실험하지 않았습니다. 22개의 YAML 매니페스트는 실제 GitOps 저장소에서 가져온 진짜 자원이지만 176개의 인시던트 이벤트와 그 결과는 구성된 것이지 실제 운영 로그에서 관측한 것이 아닙니다. 위험도 공식 역시 학습된 모델이 아니라 사람이 설계한 투명한 대리 지표이며 실제 배포된 에이전트의 확신도를 재현한다는 보장은 없습니다. 자율조치 40초, 에스컬레이션 1200초라는 지연 시간 가정도 실제 인시던트 로그에서 측정한 값이 아니라 전형적인 컨트롤러 재조정 시간과 온콜 서비스 수준 목표를 참고한 추정치입니다. 2%라는 안전 상한선도 데이터에서 유도한 값이 아니라 되돌릴 수 없는 조치를 향한 보수적 태도를 반영한 정책적 선택입니다.</p>

<p>OOM 유형이 52.2%라는 평균 개선율을 크게 끌어올린다는 점도 짚어야 합니다. 이번 기준표에서 OOM 액션 두 가지가 모두 안전으로 분류돼 있기 때문에 생긴 결과이며, 다른 테넌트의 파드를 강제 종료하는 조치까지 OOM 대응에 포함시키면 이 수치는 달라질 수 있다고 논문 스스로 밝히고 있습니다. 그래서 이 연구는 특정 배포된 에이전트의 성능을 측정한 것이 아니라 임계값 보정 방법론 자체의 타당성을 검증한 것으로 읽어야 합니다. 다음 단계로는 실제 에이전트의 검증 루프 신호로 위험도 공식을 대체하고 실제 인시던트 로그로 검증하는 작업, 그리고 컨포멀 위험 제어를 얹어 경험적 안전 보장을 분포 무관 보장으로 끌어올리는 작업이 남아 있습니다.</p>

<p>논문 상세 페이지는 다음에서 확인할 수 있습니다: <a href="https://huggingface.co/datasets/thaki-AI/daily-paper-2026-07-16-safe-autonomy-k8s-remediation">https://huggingface.co/datasets/thaki-AI/daily-paper-2026-07-16-safe-autonomy-k8s-remediation</a></p>]]></content><author><name>{&quot;name&quot;=&gt;nil, &quot;avatar&quot;=&gt;nil, &quot;bio&quot;=&gt;nil, &quot;location&quot;=&gt;&quot;Seoul, Korea&quot;, &quot;email&quot;=&gt;&quot;info@thakicloud.co.kr&quot;, &quot;uri&quot;=&gt;nil, &quot;home&quot;=&gt;nil, &quot;links&quot;=&gt;[{&quot;label&quot;=&gt;&quot;Website&quot;, &quot;icon&quot;=&gt;&quot;fas fa-fw fa-link&quot;, &quot;url&quot;=&gt;&quot;https://thakicloud.co.kr&quot;}, {&quot;label&quot;=&gt;&quot;GitHub&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-github&quot;, &quot;url&quot;=&gt;&quot;https://github.com/thakicloud&quot;}]}</name><email>info@thakicloud.co.kr</email></author><category term="research" /><category term="autonomous-agents" /><category term="kubernetes" /><category term="incident-remediation" /><category term="gpu-scheduling" /><category term="closed-loop-verification" /><category term="safe-autonomy" /><category term="escalation-policy" /><category term="multi-tenant-clusters" /><category term="mttr" /><summary type="html"><![CDATA[LLM 에이전트에게 K8s GPU 인시던트 원격조치를 맡기려는 팀이라면 결국 이 질문과 마주칩니다. 언제까지는 에이전트 혼자 고치게 두고, 언제부터는 사람을 불러야 하는가. 이 경계선을 감으로 정하지 않고 위험도 공식과 안전 상한선으로 계산해낸 논문을 소개합니다.]]></summary></entry><entry xml:lang="ar"><title type="html">في المهام الصعبة، اجعله يكتب الهدف أولًا: أسلوب تفويض الأهداف في Codex</title><link href="https://thakicloud.github.io/ar/agentops/codex-goal-delegation/" rel="alternate" type="text/html" title="في المهام الصعبة، اجعله يكتب الهدف أولًا: أسلوب تفويض الأهداف في Codex" /><published>2026-07-15T00:00:00+09:00</published><updated>2026-07-15T00:00:00+09:00</updated><id>https://thakicloud.github.io/ar/agentops/codex-goal-delegation</id><content type="html" xml:base="https://thakicloud.github.io/ar/agentops/codex-goal-delegation/"><![CDATA[<h2 id="نظرة-عامة">نظرة عامة</h2>

<p>تنتشر بين المطورين الذين يعتمدون على وكلاء البرمجة نصيحة قصيرة. حين تُسند إلى Codex هدفًا <code class="language-plaintext highlighter-rouge">/goal</code> صعبًا فعلًا، لا تطلب منه أن يبدأ العمل فورًا. اطلب منه أولًا أن “يكتب الهدف بحيث يستطيع خيط آخر تحقيقه.” للوهلة الأولى يبدو الأمر لعبًا بالكلمات. ما الفرق بين أن تطلب من النموذج كتابة الهدف وبين أن تطلب منه تحقيقه؟</p>

<p>غير أن هذه النصيحة تلمس بدقة أمرًا يعرفه كل من شغّل الوكلاء لفترة. المهام الصعبة تفشل غالبًا لا لأن النموذج ضعيف، بل لأن الهدف لم يُكتب أصلًا بصيغة تستطيع الآلة الحكم عليها. يظن الناس أن جملة مثل “نظّف عملية إعادة الهيكلة هذه” هدف، لكنها بالنسبة للوكيل تترك كل شيء فارغًا: متى يتوقف، وما الذي يُعدّ نجاحًا، وأين الحدّ. لذا يفكّك هذا المقال أسلوب “اجعله يكتب الهدف” قطعة قطعة، ويبيّن كيف تفرض ThakiCloud، التي تشغّل منصة AI/ML على Kubernetes ومنصة للوكلاء، المبدأ نفسه في الشيفرة.</p>

<h2 id="ما-هي-أهداف-codex">ما هي أهداف Codex</h2>

<p>أولًا، لننظر عن قرب إلى المكوّن الخام. ميزة <code class="language-plaintext highlighter-rouge">/goal</code> في Codex تربط هدفًا دائمًا بالخيط. وفقًا لكتيّب OpenAI المنشور “Using Goals in Codex”، ينبغي وصف الهدف بثلاثة أجزاء: نتيجة قابلة للقياس، وسطح تحقّق يتيح تأكيد التقدّم، وقيود. متى توفّرت هذه الثلاثة صار الهدف هدفًا دائمًا مرتبطًا بالخيط.</p>

<p>الآلية مهمة. في نهاية كل دور، يفحص Codex الأدلة المتراكمة حتى الآن ويحكم بنفسه هل تحقّق الهدف. إن لم يتحقّق، وكان الهدف لا يزال نشطًا وضمن الميزانية، يواصل من أحدث حالة. باختصار، بدلًا من استجابة واحدة، يكرّر الملاحظة والحكم حتى يتحقّق الهدف بوصفه شرط إنهاء. جاذبية الميزة أن مهمة طويلة الأمد يمكن أن تتحوّل إلى سير عمل من نوع “اضبطه وانسه.”</p>

<p>النقطة الجوهرية هنا أن جودة الهدف تحسم كل شيء. إن كان سطح التحقّق ضبابيًا لم يستطع Codex تحديد متى يتوقف؛ وبلا قيود يتجاوز نطاقه ويمسّ ملفات لا صلة لها؛ وبلا نتيجة قابلة للقياس يصلح ملفًا واحدًا ثم يعلن أنه انتهى. كتابة هدف جيّد مهارة قائمة بذاتها إذًا، وحين تنقص هذه المهارة تنهار المهام الصعبة.</p>

<pre><code class="language-mermaid">flowchart TB
    A[فكرة مهمة صعبة] --&gt; B{هل الهدف بصيغة&lt;br/&gt;قابلة للتحقّق آليًا؟}
    B --&gt;|لا| C[حلقة تدور بلا طائل&lt;br/&gt;أو إنهاء مبكر]
    B --&gt;|نعم| D[نتيجة قابلة للقياس]
    B --&gt;|نعم| E[سطح التحقّق]
    B --&gt;|نعم| F[القيود]
    D --&gt; G[هدف دائم&lt;br/&gt;مرتبط بالخيط]
    E --&gt; G
    F --&gt; G
    G --&gt; H[يحكم على نفسه بالأدلة&lt;br/&gt;عند نهاية كل دور]
    H --&gt;|غير محقّق، ضمن الميزانية| G
    H --&gt;|محقّق| I[تقارب وانتهاء]
</code></pre>

<h2 id="الأسلوب-اكتب-هدفًا-لخيط-آخر">الأسلوب: “اكتب هدفًا لخيط آخر”</h2>

<p>لنعد الآن إلى النصيحة. أمام مهمة صعبة، نادرًا ما يكتب المرء هدفًا جيّدًا من المحاولة الأولى. تحديد ما هي النتيجة القابلة للقياس، وما الذي سيتحقّق من التقدّم، وأي القيود يجب وضعها، هو بحدّ ذاته مهمة تصميم غير بسيطة. ما تقترحه هذه النصيحة هو تفويض ذلك التصميم إلى النموذج أولًا.</p>

<p>بشكل ملموس، يجري الأمر هكذا. يُطلب من الخيط الأول أن “يكتب هدفًا يمكّن خيطًا آخر من تحقيق هذه المهمة الصعبة ذاتيًا.” النموذج لا ينجز العمل هنا. بل يفهم المهمة ويُنتج مواصفة هدف تبيّن ما هو النجاح، وكيف يُتحقّق منه، وأين الحدّ. يراجع الإنسان تلك المواصفة ويشحذها، ثم يُدخلها هدفًا في خيط جديد لتشغيل التنفيذ الفعلي. ينطلق خيط التنفيذ بشرط إنهاء محدّد جيدًا، فيكون أقل عرضة بكثير للحلقات التي تدور بلا طائل أو للإنهاء المبكر الموصوفَين آنفًا.</p>

<p>ينجح هذا الأسلوب لسببين. الأول أنه يفصل كتابة الهدف عن تحقيق الهدف. الأمران مختلفان في طبيعتهما. كتابة الهدف تدور حول فهم المشكلة على نطاق واسع وتثبيت معايير النجاح في اللغة؛ أما تحقيق الهدف فحفرٌ ضيّق نحو تلك المعايير. حين يحاول خيط واحد القيام بالأمرين معًا، يندفع إلى التنفيذ وهو لا يزال يقرّر معايير التحقّق، وينتهي به الأمر إلى تقييم نفسه بمعايير لم يضعها أصلًا. بالفصل، يركّز كل خيط على أمر واحد.</p>

<p>الثاني أنه يخلق نقطة مراجعة للإنسان. مواصفة الهدف التي يُنتجها النموذج قطعةٌ يستطيع الإنسان قراءتها وتحريرها قبل التنفيذ. إن كان سطح التحقّق ضعيفًا أمكن تعزيزه في هذه المرحلة؛ وإن كان النطاق واسعًا أمكن إضافة قيود. اكتشاف خطأ بعد بدء التنفيذ باهظ الثمن؛ والتقاطه في مرحلة مواصفة الهدف رخيص. بعبارة أخرى، هذا ليس حيلة برومبت بل أداة بنيوية تُدرج طبقة واحدة من المراجعة الرخيصة.</p>

<p>بالطبع ليس دواءً لكل داء. أطّرت إحدى نشرات المطورين هذا النهج بأنه يحوّل “مهمة من أربع ساعات إلى سير عمل من نوع اضبطه وانسه”، لكن ذلك انطباع عن حالة ناسبته، لا ضمان. حتى لو نجحت في جعل النموذج يكتب هدفًا جيّدًا، يبقى تقارب خيط التنفيذ نحوه مسألة منفصلة. لذا لا يؤتي الأسلوب ثماره إلا مقترنًا ببوابات التحقّق المذكورة أدناه.</p>

<h2 id="دلالات-على-منتجات-thakicloud">دلالات على منتجات ThakiCloud</h2>

<p>ثمة سبب لألّا يبدو هذا الأسلوب غريبًا: تفرض ThakiCloud المبدأ نفسه فعلًا، لا بوصفه طلب برومبت بل انضباطًا في الشيفرة. وبما أن الموضوع تشغيل الوكلاء، نضع هنا منظور منصّتنا للوكلاء Paxis في المركز، مع ربطه ببنية ai-platform التحتية أسفلها.</p>

<p>Paxis هي سحابة ThakiCloud الأصيلة للوكلاء (Agent-Native Cloud)، مستوى تحكّم يعامل المهارات والأدوات والسياسات وسجلات التدقيق كموارد من الدرجة الأولى. بداخلها مُنفّذ يُدعى Goal Mode. حين ننشئ هدفًا في Goal Mode، كتبنا القواعد بحيث لا يمكن ترك <code class="language-plaintext highlighter-rouge">check_cmd</code> و<code class="language-plaintext highlighter-rouge">success_criteria</code> والميزانية فارغة. هذه الثلاثة تقابل تقريبًا واحدًا لواحد أجزاء هدف Codex الثلاثة: <code class="language-plaintext highlighter-rouge">success_criteria</code> هي النتيجة القابلة للقياس، و<code class="language-plaintext highlighter-rouge">check_cmd</code> هو سطح التحقّق الذي يحكم على التقدّم، والميزانية هي القيد. إن أُنشئ الهدف قشرةً فارغة، فمصمَّم ليفشل عند البوابة في التكرار الأول، فتضمن الشيفرة حالة “إن لم تكتب الهدف جيدًا فلن يبدأ أصلًا.”</p>

<p>بنية التفويض المتمثّلة في “اكتب هدفًا لخيط آخر” موجودة داخلنا أيضًا. حين يصل طلب معقّد، يفكّكه الوكيل الرئيسي إلى مهام فرعية ويفوّض كلًّا منها إلى وكيل فرعي منفصل. مَن يفكّك ومَن ينفّذ منفصلان، وهذه هي الفكرة ذاتها لفصل هذا المقال بين خيط كتابة الهدف وخيط تنفيذ الهدف. التفكيك يحتاج حكمًا، فيتولّاه نموذج من طبقة أعلى؛ والتنفيذ عمل ضيّق، فيُرسَل إلى نموذج أرخص. من هنا يأتي مبدأ العمّال رخيصون والبوابات باهظة.</p>

<p>وفوق ذلك كله، لا ندمج أبدًا نتائج التوزّع دون تحقّق. مهما أحسنت كتابة الهدف وتفويضه، يجب أن تحكم على صحّة النتيجة مرحلةُ تحقّق منفصلة لا المُنفِّذ. تُحكَم مخرجات الشيفرة بتشغيل الاختبارات فعليًا وقراءة رمز الخروج؛ وتُصفّى مخرجات المحتوى أو الحكم بتصويت أغلبية من عدة مدقّقين بمنظورات مختلفة. جملة يقول فيها النموذج “يبدو أن هذا انتهى” لا يمكن أن تكون شرط إنهاء الحلقة. يبيّن هذا الانضباط كيف نصلّب سلوك هدف Codex “احكم على نفسك بالأدلة عند نهاية كل دور” إلى صيغة جديرة بالثقة.</p>

<p>وثمة ارتباط عبر عدسة البنية التحتية أيضًا. الحلقة التي تُقطّع الأهداف بدقّة وتشغّلها مع خطوات تحقّق تستهلك موارد الحوسبة باطّراد. ai-platform هي الطبقة التي توفّر جدولة GPU على Kubernetes وKueue، وخدمة vLLM، وعزل متعدّد المستأجرين، فتبني أرضية تستطيع فوقها هذه الحلقات الوكيلة أن تعمل بثمن رخيص وموثوقية. الخدمة منخفضة التكلفة تصنع اقتصاديات الوكلاء، وفوقها تصبح أهداف Paxis المفوَّضة وحلقات التحقّق قابلة للحياة عمليًا. العدستان تكمّلان إحداهما الأخرى.</p>

<h2 id="الحدود-والحجج-المضادة">الحدود والحجج المضادة</h2>

<p>كي لا نبالغ في تقدير هذا الأسلوب، لنأخذ الجانب الآخر.</p>

<p>أولًا، خطوة كتابة الهدف نفسها قد تفشل. إن أنتج النموذج هدفًا معقولًا لكنه غير قابل للتحقّق، انطلق خيط التنفيذ وهو لا يعرف ما الذي يُعدّ نجاحًا. ثمة حالات كثيرة يكون فيها كتابة الإنسان هدفًا قصيرًا ومتينًا مباشرةً أفضل. لذا يجب أن تمرّ مواصفة الهدف التي يكتبها النموذج بنقطة مراجعة بشرية، وتسليمها مباشرة إلى التنفيذ دون مراجعة هدرٌ لنقطة المراجعة الرخيصة التي كسبتها.</p>

<p>ثانيًا، هذا العبء غير مبرَّر لكل مهمة. كتابة الهدف نيابةً وتقسيم الخيوط في تصحيح ملف واحد أو سؤال سريع مبالغة. لا يؤتي هذا الأسلوب ثماره إلا في المهام الصعبة حيث يكون شرط الإنهاء ضبابيًا، والتشغيل طويلًا، والتنفيذ الذاتي ذا قيمة حقيقية. قواعدنا الداخلية ترسم الخطّ ذاته: استخدم أدوات الحلقة للتنفيذ التكراري أو العمل المتقارب فقط، ولا تفرضها على تعديلات لمرة واحدة.</p>

<p>ثالثًا، كلما طال التنفيذ الذاتي مال الناس أكثر إلى الثقة بالنتيجة والتوقّف عن المراجعة. راحة أنك فوّضت الهدف جيدًا هي الخطر نفسه. إن لم يُصفِّ المدقّق شيئًا، فليس ذلك إشارة إلى أن كل شيء نجح بل الأرجح إشارة إلى أن المدقّق معطّل. لذا يجب أن يفحص إنسان المخرجات الجوهرية بأخذ عيّنات دوريًا، وأن يُصمَّم المدقّقون ليصوّبوا نحو الدحض لا التأكيد.</p>

<p>خلاصة القول، “في المهام الصعبة، اكتب الهدف أولًا” ليست براعة برومبت بل نصيحة بنيوية بفصل كتابة الهدف عن تنفيذه، وإدراج نقطة مراجعة بينهما. إن كانت ميزة الهدف في Codex وضعت هذا في أيدي المطورين الأفراد، فإن ThakiCloud تفرض المبدأ نفسه على مستوى الفريق عبر Goal Mode في Paxis وحلقات التحقّق. أن تكون كتابة هدف جيّد هي معنى إدارة الوكيل جيّدًا لا يتغيّر مهما كانت الأداة.</p>

<h2 id="المصادر">المصادر</h2>

<ul>
  <li>OpenAI Cookbook, “Using Goals in Codex” (developers.openai.com/cookbook/examples/codex/using_goals_in_codex)</li>
  <li>التغريدة الأصلية: nickbaumann_ (أُعيد نشرها في x.com/hjguyhan/status/2077331299648635303)</li>
</ul>]]></content><author><name>{&quot;name&quot;=&gt;nil, &quot;avatar&quot;=&gt;nil, &quot;bio&quot;=&gt;nil, &quot;location&quot;=&gt;&quot;Seoul, Korea&quot;, &quot;email&quot;=&gt;&quot;info@thakicloud.co.kr&quot;, &quot;uri&quot;=&gt;nil, &quot;home&quot;=&gt;nil, &quot;links&quot;=&gt;[{&quot;label&quot;=&gt;&quot;Website&quot;, &quot;icon&quot;=&gt;&quot;fas fa-fw fa-link&quot;, &quot;url&quot;=&gt;&quot;https://thakicloud.co.kr&quot;}, {&quot;label&quot;=&gt;&quot;GitHub&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-github&quot;, &quot;url&quot;=&gt;&quot;https://github.com/thakicloud&quot;}]}</name><email>info@thakicloud.co.kr</email></author><category term="agentops" /><category term="ai-coding" /><category term="agentic" /><category term="codex" /><category term="goal-mode" /><category term="agentops" /><category term="verification" /><summary type="html"><![CDATA[شارك أحد المطورين نصيحة: حين تُسند إلى Codex هدفًا /goal صعبًا حقًا، اطلب منه أولًا أن يكتب الهدف بحيث يستطيع خيط آخر تحقيقه. يبدو الأمر لعبًا بالكلمات، لكنه في جوهره نمط تشغيل فعلي للوكلاء: اجعل النموذج يكتب مواصفة هدف قابلة للتحقّق أولًا، ثم فوّض تلك المواصفة إلى خيط جديد. نستعرض كيف تعمل أهداف Codex فعليًا، ونقرأ الأسلوب من منظور Goal Mode وpge-loop وPaxis في ThakiCloud.]]></summary></entry><entry xml:lang="ar"><title type="html">تشريح عناقيد GPU وTPU: كيف يحدد الاتصال الجماعي سرعة التدريب الموزع</title><link href="https://thakicloud.github.io/ar/dev/collective-communication-clusters/" rel="alternate" type="text/html" title="تشريح عناقيد GPU وTPU: كيف يحدد الاتصال الجماعي سرعة التدريب الموزع" /><published>2026-07-15T00:00:00+09:00</published><updated>2026-07-15T00:00:00+09:00</updated><id>https://thakicloud.github.io/ar/dev/collective-communication-clusters</id><content type="html" xml:base="https://thakicloud.github.io/ar/dev/collective-communication-clusters/"><![CDATA[<h2 id="نظرة-عامة">نظرة عامة</h2>

<p>لقد مضى وقت طويل منذ أن كان من الممكن وضع نموذج لغوي كبير على GPU واحد. فالنماذج التي تحتوي على عشرات المليارات إلى تريليونات المعاملات (parameters) تُقسّم على عشرات إلى آلاف المسرّعات (accelerators)، وفي كل خطوة تدريب يجب على هذه المسرّعات أن توائم نتائجها مع بعضها البعض. هذه العملية من “المواءمة المتبادلة” هي بالضبط ما يُعرف بالاتصال الجماعي (collective communication)، والنقطة التي تستهلك الوقت فعلياً في التدريب الموزع الحديث غالباً ما تكون هذا الاتصال وليست عمليات ضرب المصفوفات.</p>

<p>هذا المقال موجّه لمهندسي البنية التحتية الذين يدرّبون أو يقدّمون النماذج على عناقيد GPU أو TPU، ولمن يتحمل مسؤولية تكلفة التقديم (serving) وقابلية التوسع. ننطلق من التحليل المعمّق الشهير الذي كتبه Aleksa Gordić بعنوان “Inside TPU and GPU Clusters: The Anatomy of Collective Communication”، ونعيد التحقق من المفاهيم الأساسية التي يتناولها بالرجوع إلى مراجع قياسية (مثل NCCL وورقة TPU v4).</p>

<p>نبدأ برسالة أساسية موجزة. أولاً، يمكن اختزال أداء التدريب الموزع في عدد قليل من عمليات الاتصال الجماعي. ثانياً، حتى العملية نفسها تختلف تكلفتها اختلافاً جذرياً بحسب البنية الطوبولوجية الفيزيائية التي تعمل عليها (بنية NVIDIA القائمة على المفاتيح switch مقابل بنية Google القائمة على التوروس). ثالثاً، استراتيجية التوازي (parallelism) المُختارة هي التي تحدد أي عملية جماعية تُستدعى ومدى تكرارها. وفهم هذه العناصر الثلاثة يوضح لماذا يؤثر مكان وكيفية توزيع عدد من وحدات GPU تأثيراً كبيراً على الأداء.</p>

<h2 id="ما-هو-الاتصال-الجماعي">ما هو الاتصال الجماعي؟</h2>

<p>العملية الجماعية هي نمط اتصال يشارك فيه عدد من العمليات (غالباً واحدة لكل مسرّع) معاً. فإذا كان الاتصال من نقطة إلى نقطة (P2P) هو أن يرسل طرف واحد بيانات إلى طرف آخر، فإن العملية الجماعية تعني أن المجموعة بأكملها تقسّم البيانات وتجمعها وفق قاعدة محددة. وفيما يلي أبرز العمليات التي تتكرر في التدريب الموزع.</p>

<ul>
  <li><strong>All-reduce</strong>: يقوم جميع المشاركين بجمع (أو أخذ متوسط) التنسور (tensor) الذي يملكه كل منهم عنصراً بعنصر، ثم تُعاد النتيجة إلى الجميع. وهذه هي العملية المستخدمة تحديداً لمواءمة التدرجات (gradients) في التدريب الموازي للبيانات (data parallel).</li>
  <li><strong>Reduce-scatter</strong>: يُحسب المجموع، لكن النتيجة لا يحتفظ بها طرف واحد بالكامل، بل تُقسّم إلى أجزاء يوزَّع كل جزء منها على طرف مختلف.</li>
  <li><strong>All-gather</strong>: تُجمع الأجزاء التي يملكها كل طرف بحيث يحصل الجميع على النسخة الكاملة. وهي العملية المقابلة لـ reduce-scatter، وعند ضمهما معاً ينتج all-reduce.</li>
  <li><strong>All-to-all</strong>: يرسل كل مشارك جزءاً مختلفاً من البيانات إلى كل واحد من المشاركين الآخرين. وهو نمط أقرب إلى النقل المقلوب (transpose)، وهو محوري في تمرير الرموز (tokens) إلى الخبراء (experts) في نماذج مزيج الخبراء (Mixture of Experts, MoE).</li>
  <li><strong>Broadcast / Reduce</strong>: عمليتان أحادّيتا الاتجاه، إما أن يبثّ طرف واحد نفس البيانات للجميع، أو أن تُجمَع بيانات الجميع وتُختزل عند طرف واحد.</li>
</ul>

<p>هناك ملاحظة مهمة هنا وهي أن all-reduce ليست عملية ذرية (atomic) بحد ذاتها. فهي تتحلل إلى <strong>reduce-scatter يليها all-gather</strong>. وهذا التحلل هو الأساس الذي تُبنى عليه معادلة التكلفة التي سنتناولها لاحقاً.</p>

<pre><code class="language-mermaid">flowchart TB
    A["كل مسرّع: تدرج/تنسور محلي"] --&gt; B["Reduce-scatter&lt;br/&gt;توزيع المجموع على شكل أجزاء"]
    B --&gt; C["All-gather&lt;br/&gt;استعادة الأجزاء لدى الجميع"]
    C --&gt; D["اكتمال All-reduce&lt;br/&gt;يمتلك الجميع المجموع نفسه"]
    A --&gt; E["All-to-all&lt;br/&gt;توجيه رموز MoE"]
    A --&gt; F["Broadcast/Reduce&lt;br/&gt;توزيع/تجميع أحادي الاتجاه"]
</code></pre>

<h2 id="البنية-الفيزيائية-لعناقيد-gpu">البنية الفيزيائية لعناقيد GPU</h2>

<p>يسهل فهم عناقيد NVIDIA إذا نظرنا إليها كطبقتين: داخل العقدة (node) الواحدة (scale-up)، وبين العقد (scale-out).</p>

<p>داخل العقدة، تربط <strong>NVLink</strong> و<strong>NVSwitch</strong> وحدات GPU ببعضها بكثافة عالية. فوحدات GPU الثماني مثلاً الموجودة داخل خادم واحد تُربط عبر NVSwitch بشكل شبه متصل بالكامل (fully connected)، بحيث يتواصل أي GPU مع أي GPU آخر بعرض نطاق ترددي (bandwidth) عالٍ وموحّد. وهذا هو سبب حصر الأعمال التي تتطلب اتصالاً متكرراً جداً، مثل التوازي التنسوري (tensor parallelism)، داخل هذا النطاق.</p>

<p>أما بين العقد، فتُستخدم شبكة من نوع ورقة الشجرة السمينة (leaf-spine / fat-tree) مبنية على <strong>InfiniBand</strong> أو <strong>RoCE</strong> (RDMA over Converged Ethernet). وهذه النسيجة الموسّعة (scale-out fabric) تربط وحدات GPU عبر الرفوف (racks) والخوادم. ومن التصاميم الشائعة هنا الطوبولوجيا المحسّنة بالمسارات (rail-optimized)، حيث يُربط منفذ الشبكة (NIC) بنفس الترتيب في كل عقدة بنفس المفتاح (“المسار” أو rail)، بحيث تمر عملية all-reduce بين العقد بأقل قدر ممكن من طبقة العمود الفقري (spine).</p>

<p>وهذه المرونة لها ثمن. فآلاف المفاتيح (switches) اللازمة للتوسع الأفقي (scale-out) تستهلك ما يقارب 5 إلى 10 بالمئة من إجمالي طاقة العنقود [تقديري وقد يختلف بحسب التهيئة]، وتتطلب نفقات رأسمالية كبيرة. أي أن نهج NVIDIA، بدلاً من الاكتفاء بجعل “أي GPU يتواصل جيداً مع أي GPU آخر”، يشتري هذا التجانس عبر مفاتيح تعالج الحزم (packets) بشكل فعّال.</p>

<h2 id="الخيار-المختلف-لعناقيد-tpu">الخيار المختلف لعناقيد TPU</h2>

<p>تسلك Google في وحدات TPU مساراً مختلفاً تماماً. فبدلاً من نسيجة مفاتيح فعّالة، تُربط شرائح TPU مباشرة بجاراتها عبر رابط عالي السرعة مخصص يُسمى <strong>ICI</strong> (Inter-Chip Interconnect). في الجيل الأحدث، تمتد روابط ICI من كل شريحة في ست اتجاهات (X موجب، X سالب، Y موجب، Y سالب، Z موجب، Z سالب) لتشكّل شبكة <strong>توروس ثلاثي الأبعاد (3D torus)</strong> (أما الأجيال الأولى فكانت تستخدم توروس ثنائي الأبعاد لتشكيل “pod” بسعة 256 شريحة). وبما أن الاتصال يتم مباشرة مع الجيران فقط، فإن طبقة المفاتيح تختفي في معظمها.</p>

<p>يبقى سؤال: كيف تُربط الشرائح البعيدة عن بعضها، أو ما هو أكبر من حجم الـ pod؟ هنا يظهر <strong>مفتاح الدارة الضوئية (OCS, Optical Circuit Switch)</strong>. وبحسب ورقة TPU v4 البحثية، يعمل OCS عبر إعادة توجيه ألياف ضوئية باستخدام مرايا MEMS، أي أنه لا يفسّر الإشارة الضوئية بشكل فعّال بل يكتفي بعكسها. وبفضل ذلك يمكن ربط ما يصل إلى 4096 شريحة بطريقة قابلة لإعادة التشكيل، بينما لا يستهلك سوى طاقة قليلة جداً مقارنة بمفاتيح InfiniBand، لأن الطاقة تُستخدم فقط للحفاظ على اتجاه المرايا. كما يمكن لف أحد محاور التوروس ضوئياً، أو إعادة توجيه الطوبولوجيا برمجياً لتجاوز عقدة معطوبة.</p>

<p>باختصار، تستثمر عناقيد GPU في مفاتيح فعّالة من أجل وصول موحّد، بينما تعتمد عناقيد TPU على توروس متصل مباشرة بالجيران مع إعادة تشكيل ضوئية لتوفير الطاقة والتكلفة. ولا يتفوق أي من الخيارين على الآخر بشكل مطلق. فالتوروس مثالي للاتصال مع الجيران لكنه يحتاج قفزات (hops) أكثر للاتصال البعيد العشوائي، بينما نسيجة المفاتيح موحّدة لكنها مكلفة وتستهلك طاقة أكبر.</p>

<h2 id="كيف-تُترجم-العمليات-الجماعية-إلى-استراتيجيات-التوازي">كيف تُترجم العمليات الجماعية إلى استراتيجيات التوازي</h2>

<p>أي عملية جماعية تُستدعى وبأي وتيرة، يتحدد في النهاية بنوع التوازي المُستخدم.</p>

<ul>
  <li><strong>التوازي البياني (Data Parallel, DP)</strong>: تعالج كل نسخة (replica) دفعة (batch) مختلفة، ثم تُوائَم التدرجات عبر <strong>all-reduce</strong>. وحجم الاتصال يتناسب مع حجم النموذج ويحدث مرة واحدة في كل خطوة.</li>
  <li><strong>التوازي البياني الكامل التشظّي (FSDP/ZeRO)</strong>: تُقسّم المعاملات (parameters) إلى أجزاء توزَّع بين المسرّعات، ثم قبل التمرير الأمامي (forward pass) مباشرة تُجمع المعاملات اللازمة عبر <strong>all-gather</strong>، وبعد التمرير الخلفي (backward pass) تُعاد تشظية التدرجات عبر <strong>reduce-scatter</strong>. توفر هذه الطريقة الذاكرة لكنها تزيد من تكرار الاتصال.</li>
  <li><strong>التوازي التنسوري (Tensor Parallel, TP)</strong>: تُقسَّم عملية طبقة واحدة على عدة وحدات GPU، وعند حدود كل طبقة تُدمج النتائج عبر <strong>all-reduce</strong> أو من خلال all-gather/reduce-scatter. والاتصال هنا متكرر للغاية، لذا يكاد يكون حصره داخل نطاق NVLink المذكور سابقاً أمراً ضرورياً.</li>
  <li><strong>التوازي عبر خطوط الأنابيب (Pipeline Parallel, PP)</strong>: يُقسَّم النموذج على مستوى الطبقات وتُوزَّع على وحدات GPU مختلفة، وتُنقل القيم المفعّلة (activations) بين المراحل غالباً عبر اتصال <strong>P2P</strong>. وهنا يسود الاتصال من نقطة إلى نقطة بدلاً من العمليات الجماعية.</li>
  <li><strong>التوازي على مستوى الخبراء (Expert Parallel, EP/MoE)</strong>: يجب إرسال الرموز (tokens) إلى المسرّع الذي يستضيف الخبير المعني، لذا فإن <strong>all-to-all</strong> هو جوهر هذا النوع. وعدد أزواج الاتصال في all-to-all يزداد تربيعياً مع زيادة عدد المشاركين، ما يجعله حساساً بشكل خاص للطوبولوجيا.</li>
</ul>

<p>في الممارسة العملية تُستخدم هذه الأنواع مجتمعة. فمثلاً يُصمَّم التوزيع بحيث يُوضع TP داخل نطاق NVLink في العقدة الواحدة، وتُنقل عمليات all-reduce الخاصة بـ DP عبر InfiniBand بين العقد، ويربط PP بين هذه الأجزاء. وإذا أُسيء التوزيع، فقد يتسرب اتصال التوازي التنسوري المتكرر إلى رابط أبطأ بين العقد، مما يبطئ التدريب بأكمله.</p>

<h2 id="القاعدة-التي-تحكم-الأداء-الحلقة-والشجرة">القاعدة التي تحكم الأداء: الحلقة والشجرة</h2>

<p>توجد خوارزميات متعددة لتنفيذ العمليات الجماعية فعلياً، لكن الأشهر من منظور عرض النطاق الترددي هي <strong>all-reduce الحلقي (ring all-reduce)</strong>. حيث يُربط المشاركون في شكل دائري واحد، وفي كل خطوة يُرسل كل طرف جزءه إلى الجار التالي، وتُنفَّذ عمليتا reduce-scatter وall-gather كل منهما عبر N-1 خطوة.</p>

<p>ومن المعروف أن إجمالي حجم البيانات التي يحملها كل رابط يُحسب تقريباً على النحو التالي. عند تنفيذ all-reduce لتنسور بحجم S عبر N مشارك، تكون حركة المرور لكل رابط تقريباً</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2 × (N − 1) / N × S
</code></pre></div></div>

<p>وذلك لأن (N−1)/N × S تتدفق في مرحلة reduce-scatter، ومثلها مرة أخرى في مرحلة all-gather. والخاصية المهمة هنا أن (N−1)/N تقترب من 1 كلما كبر N، أي أن حركة المرور لكل رابط تستقر عند نحو 2S تقريباً. لهذا السبب يُوصف ring all-reduce بأنه أمثل من حيث عرض النطاق الترددي (bandwidth-optimal)، وهو ما استخدمته مكتبات مثل NCCL وGloo لفترة طويلة.</p>

<p>المشكلة تكمن في زمن الوصول (latency). فالحلقة تمر عبر N−1 خطوة بشكل متسلسل، لذا فإن زمن الوصول الثابت (α) المرتبط بكل خطوة يتراكم بما يتناسب مع عدد المشاركين. فإذا نفّذت أعداد كبيرة جداً من العقد عملية all-reduce على تنسور صغير، يتبقى عرض النطاق الترددي فائضاً بينما يصبح زمن الوصول هو عنق الزجاجة. لهذا السبب تختار المكتبات الفعلية تلقائياً بين خوارزميات الحلقة والشجرة (أو الهرمية) بحسب حجم التنسور وعدد العقد. فطريقة الشجرة تقلّل زمن الوصول ليقترب من log(N)، لكنها تتنازل عن جزء من كفاءة عرض النطاق الترددي. وهذا هو سبب اختيار NCCL خوارزميات مختلفة بحسب حجم الرسالة.</p>

<p>والدلالة العملية لهذه القاعدة واضحة: عند تغيير حجم الدفعة (batch)، أو حجم النموذج، أو عدد العقد، ينتقل عنق الزجاجة المهيمن بين عرض النطاق الترددي وزمن الوصول. ولهذا لا يمكن الافتراض، من دون قياس فعلي، أن “مضاعفة عدد العقد يعني مضاعفة السرعة”.</p>

<h2 id="دلالات-تطبيقية-على-منتجات-thakicloud">دلالات تطبيقية على منتجات ThakiCloud</h2>

<p>هذا الموضوع يلامس جوهر البنية التحتية، وهو ذو أهمية عملية خاصة من منظور <strong>ai-platform</strong> التابعة لـ ThakiCloud (بنية تحتية لـ AI/ML كخدمة SaaS قائمة على K8s).</p>

<p>أولاً، <strong>الجدولة الواعية بالطوبولوجيا (topology-aware scheduling)</strong>. تستخدم ai-platform أداة Kueue لجدولة أعباء عمل GPU، ومبدأ التوزيع الذي يضع مهام التوازي التنسوري داخل نطاق NVLink نفسه (أي العقدة نفسها)، ويوجّه عمليات all-reduce الخاصة بالتوازي البياني عبر روابط بين العقد محسّنة بالمسارات (rail-optimized)، يتطابق تماماً مع خصائص الاتصال الجماعي التي عرضناها في هذا المقال. فمعرفة أي عملية جماعية تسري عبر أي رابط هي ما يجعل توزيع المهام يُترجَم فعلياً إلى أداء.</p>

<p>ثانياً، <strong>التوازي التنسوري في التقديم (serving)</strong>. عند تقديم نموذج كبير عبر عدة وحدات GPU بتوازٍ تنسوري باستخدام محرّك مثل vLLM، تحدث عملية all-reduce في كل طبقة. وإذا وُزِّعت الحاويات (pods) بحيث يبقى هذا الاتصال داخل نطاق NVLink، يسهل الحفاظ على هدف زمن الوصول، أما إذا تجاوز حدود العقدة فإن زمن الوصول لكل رمز (token) يزداد بشكل ملحوظ. وفي بيئة متعددة المستأجرين (multi-tenant)، ينعكس هذا الانضباط في التوزيع مباشرة على تكلفة التقديم واتفاقيات مستوى الخدمة (SLA).</p>

<p>ثالثاً، <strong>جدوى التكلفة في السحابة المحلية والسيادية (on-prem/sovereign cloud)</strong>. حقيقة أن مفاتيح شبكة GPU تستهلك حصة كبيرة من الطاقة تعني أنه عند تصميم عنقود في بيئة داخلية أو سيادية محلية، لا تُعد الشبكة عنصراً ثانوياً، بل متغيراً محورياً في إجمالي تكلفة الملكية (TCO). والاستضافة الذاتية (self-hosting) وكفاءة التكلفة التي تسعى إليها ThakiCloud لا تقوم إلا على قرارات تصميم شبكي من هذا النوع.</p>

<p>وهناك أيضاً نقطة تقاطع مع منتج تنسيق الوكلاء (agent orchestration) <strong>Paxis</strong>. ففي سياق تنسيق مهام التدريب الموزع والاستدلال (inference) الكبير عبر رسم بياني موجّه غير دوري (DAG) وتنفيذها بعزل، فإن فهم البروفايل الاتصالي لكل عملية جماعية تستدعيها كل مرحلة يتيح تصميماً أدق لحجز الموارد وبوابات السياسات. لكن ثقل هذا المقال ينصبّ على طبقة البنية التحتية، لذا يبقى منظور ai-platform هو المحور الرئيسي.</p>

<h2 id="القيود-والاعتراضات">القيود والاعتراضات</h2>

<p>هذا الطرح ليس بلا اعتراضات. أولاً، توفّر أطر العمل تجريداً (abstraction) كبيراً للعمليات الجماعية. فعند استخدام واجهات برمجة عليا مثل PyTorch أو JAX، تتم معظم قرارات التوزيع تلقائياً داخل المكتبة والمجدول (scheduler)، ولا يحتاج مطوّر التطبيق لمعرفة هذه التفاصيل. وعليه، فإن السؤال “هل يجب على كل فريق أن يعرف معادلات التوروس والحلقة؟” يكون جوابه أقرب إلى لا.</p>

<p>غير أن هذا التجريد ينهار في اللحظة التي يصبح فيها الأداء مشكلة. فعندما يكون التدريب أبطأ من المتوقع أو يتذبذب زمن وصول التقديم، فإن إيجاد السبب يتطلب في النهاية معرفة أي عملية جماعية تسري عبر أي رابط. فالتجريد مريح على المسار الطبيعي، لكنه يتحول إلى تجريد “متسرّب” (leaky abstraction) عند تشخيص عنق الزجاجة.</p>

<p>كما أن القواعد التي عرضها هذا المقال تتغير باستمرار مع كل جيل من الأجهزة. فعرض النطاق الترددي لـ NVLink وInfiniBand، وعدد روابط ICI في TPU، وحجم OCS، تختلف من جيل إلى آخر، لذا يجب دائماً التحقق من الأرقام الدقيقة عبر المصادر الرسمية الخاصة بكل جيل. توفر معادلات هذا المقال وبنيته إطاراً للتفكير، لكن القرار الإنتاجي يجب أن يُحسم عبر قياسات فعلية (benchmark). وأخيراً، تبقى الفجوة بين البرمجيات والأجهزة واقعاً قائماً، فحتى الطوبولوجيا المثلى نظرياً تصبح عديمة الجدوى إذا لم تستطع النواة (kernel) ومكتبة الاتصال استغلالها بالكامل.</p>

<h2 id="المصادر">المصادر</h2>

<ul>
  <li>Aleksa Gordić، “Inside TPU and GPU Clusters: The Anatomy of Collective Communication”: https://www.aleksagordic.com/blog/collective-operations</li>
  <li>وثائق NVIDIA NCCL ونموذج تكلفة اتصال ring all-reduce (reduce-scatter + all-gather، الأمثلية من حيث عرض النطاق الترددي)</li>
  <li>ورقة Google TPU v4 البحثية، “TPU v4: An Optically Reconfigurable Supercomputer for Machine Learning with Hardware Support for Embeddings” (توروس ICI ثلاثي الأبعاد، OCS): https://arxiv.org/abs/2304.01433</li>
</ul>]]></content><author><name>{&quot;name&quot;=&gt;nil, &quot;avatar&quot;=&gt;nil, &quot;bio&quot;=&gt;nil, &quot;location&quot;=&gt;&quot;Seoul, Korea&quot;, &quot;email&quot;=&gt;&quot;info@thakicloud.co.kr&quot;, &quot;uri&quot;=&gt;nil, &quot;home&quot;=&gt;nil, &quot;links&quot;=&gt;[{&quot;label&quot;=&gt;&quot;Website&quot;, &quot;icon&quot;=&gt;&quot;fas fa-fw fa-link&quot;, &quot;url&quot;=&gt;&quot;https://thakicloud.co.kr&quot;}, {&quot;label&quot;=&gt;&quot;GitHub&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-github&quot;, &quot;url&quot;=&gt;&quot;https://github.com/thakicloud&quot;}]}</name><email>info@thakicloud.co.kr</email></author><category term="dev" /><category term="dev" /><category term="distributed-training" /><category term="gpu" /><category term="tpu" /><category term="nccl" /><category term="nvlink" /><category term="infiniband" /><category term="kubernetes" /><category term="self-hosting" /><category term="paxis" /><summary type="html"><![CDATA[عند تدريب أو تقديم نموذج كبير موزّع على عدة مسرّعات، لا تكون عملية الحساب هي عنق الزجاجة الحقيقي، بل البيانات المتنقلة بين المسرّعات. يشرح هذا المقال ماهية العمليات الجماعية (collective operations) مثل all-reduce وall-gather وreduce-scatter وall-to-all، وكيف تعمل هذه العمليات فوق بنيتين فيزيائيتين مختلفتين تماماً: عناقيد GPU (عبر NVLink وNVSwitch وInfiniBand) وعناقيد TPU (عبر توروس ICI ثلاثي الأبعاد ومفاتيح الدارة الضوئية). من معادلة تكلفة عرض النطاق الترددي في ring all-reduce إلى العمليات الجماعية التي يستدعيها كل من التوازي البياني والتنسوري وخطوط الأنابيب والتوازي على مستوى الخبراء، يتناول المقال هذه الموضوعات من منظور ThakiCloud القائم على تشغيل بنية تحتية لوحدات GPU.]]></summary></entry><entry xml:lang="ar"><title type="html">نفّذ مرة واحدة واخدم بسرعة vLLM الأصلية: خلفية Transformers تُنهي البناء المزدوج</title><link href="https://thakicloud.github.io/ar/llmops/vllm-transformers-native-speed/" rel="alternate" type="text/html" title="نفّذ مرة واحدة واخدم بسرعة vLLM الأصلية: خلفية Transformers تُنهي البناء المزدوج" /><published>2026-07-15T00:00:00+09:00</published><updated>2026-07-15T00:00:00+09:00</updated><id>https://thakicloud.github.io/ar/llmops/vllm-transformers-native-speed</id><content type="html" xml:base="https://thakicloud.github.io/ar/llmops/vllm-transformers-native-speed/"><![CDATA[<h2 id="نظرة-عامة">نظرة عامة</h2>

<p>إذا سبق لك أن استضفت نماذج مفتوحة الأوزان ذاتيًا، فأنت تعرف جدارًا مألوفًا. يصدر نموذج رائع، لكن لخدمته بسرعة فعليًا عليك الانتظار حتى يدعم محرك الخدمة تلك البنية. البنية الجديدة التي تصل إلى مكتبة Transformers قابلة للاستخدام فورًا للتدريب والبحث، لكن لبلوغ السرعة الكاملة في محرك استدلال عالي الأداء مثل vLLM كان على أحدهم إعادة تنفيذ تلك البنية من الصفر داخل vLLM. أي أنك تبني النموذج نفسه مرتين عمليًا.</p>

<p>هذا المقال موجّه لقادة الهندسة المسؤولين عن كلفة الاستدلال وزمن الخدمة، وللممارسين الذين يشغّلون نماذج مفتوحة الأوزان محليًا أو في بيئات سيادية، ولعلماء البيانات الذين يجرّبون بنى جديدة مع القلق بشأن سرعة النشر. في يوليو 2026، شارك Clement Delangue من Hugging Face نقطة تحوّل كبيرة للاستدلال مفتوح المصدر: بدءًا من vLLM v0.25.0، يمكن تشغيل نماذج Transformers داخل vLLM <strong>بالسرعة الأصلية</strong>، وغالبًا بما يضاهي التطبيقات المكتوبة يدويًا أو يتفوق عليها.</p>

<p>الفكرة الجوهرية هي التالية. بمجرد أن ينفّذ مؤلف النموذج بنية في Transformers، يمكنه الاستفادة من كومة الاستدلال المُحسّنة في vLLM مجانًا، دون أي عمل نقل منفصل. لم نأخذ هذا الادعاء تسليمًا. أعدنا إنتاج خطوة تحليل الرسم التي تنفّذها الخلفية داخليًا على كتلة مُفكّك صغيرة وقِسناها. يشرح هذا المقال الآلية وقياساتنا وما تعنيه لبنية تحتية تخدم نماذج مختلفة كثيرة تحت سقف واحد متعدد المستأجرين.</p>

<h2 id="ما-هذه-التقنية">ما هذه التقنية</h2>

<p>براية واحدة هي <code class="language-plaintext highlighter-rouge">--model-impl transformers</code>، يُحمّل vLLM تعريف النموذج مباشرة من مكتبة Transformers بدلًا من تطبيق منقول مخصص، ويخدمه. ظاهريًا يبدو ذلك طبقة توافق، لكن ما يميّز خلفية v0.25.0 هو أن هذا التوافق لم يعد يكلّف سرعة. كان مسار التوافق القديم أقرب إلى بديل «يعمل لكنه بطيء». أما الآن فتُطبَّق عمليات دمج الطبقات الخاصة بالاستدلال ديناميكيًا في وقت التشغيل، فتضاهي الخلفية سرعة الشيفرة المخصصة للبنى المتوافقة.</p>

<p>بالنظر عن قرب، تنقسم الآلية إلى مرحلتين. أولًا تستخدم الخلفية <code class="language-plaintext highlighter-rouge">torch.fx</code> لتحليل رسم حسابات النموذج بشكل ثابت، بحثًا عن أنماط قابلة للتحسين مثل حساب درجات الانتباه، وتطبيع RMSNorm، وطبقات SwiGLU MLP، ومزيج الخبراء Mixture-of-Experts. ثم تعالج شجرة الصياغة المجردة لإعادة كتابة تلك الشيفرة في مكانها، وتربط العمليات المكتشفة بنوى vLLM المُحسّنة. في نموذج MoE يعني ذلك نوى Expert Parallelization، وفي الانتباه عائلة paged attention. في النهاية، يُحسّن vLLM الإنتاجية وزمن الاستجابة فوق البنية التي عبّر عنها Transformers.</p>

<pre><code class="language-mermaid">flowchart TB
    A[بنية نموذج جديدة] --&gt; B[تُنفَّذ مرة واحدة في Transformers&lt;br/&gt;للتدريب والبحث]
    B --&gt; C{كيف تُخدَم في vLLM}
    C --&gt;|سابقًا| D[إعادة تنفيذ في vLLM&lt;br/&gt;نقل يدوي لنوى مخصصة]
    C --&gt;|الآن: model-impl transformers| E[تحليل رسم ثابت عبر torch.fx]
    E --&gt; F[كشف أنماط معروفة&lt;br/&gt;الانتباه، RMSNorm، SwiGLU، MoE]
    F --&gt; G[إعادة كتابة المصدر عبر ast&lt;br/&gt;دمج طبقات في وقت التشغيل]
    G --&gt; H[الربط بنوى vLLM المُحسّنة&lt;br/&gt;EP و paged attention]
    H --&gt; I[استدلال بالسرعة الأصلية&lt;br/&gt;من 4B إلى 235B، مضاهاة أو تفوّق]
    D --&gt; I
</code></pre>

<p>المعنى العملي لهذا التحول هو اختفاء الفجوة بين محرك الخدمة ومنظومة النماذج. سابقًا كانت كل بنية جديدة تتطلب قاعدتَي شيفرة، تطبيقًا للتدريب وتطبيقًا للاستدلال، وكانت الفجوة بينهما هي بالضبط نافذة «النموذج الرائع صدر لكن لا نستطيع خدمته بسرعة بعد». الآن تضيق هذه النافذة. سواء كنت فريق بحث يجرّب بنية مخصصة أو فريق تشغيل يحاول وضع نموذج صدر حديثًا في الإنتاج، يمنحك تطبيق Transformers واحد سرعة vLLM.</p>

<h2 id="التثبيت-والتكامل">التثبيت والتكامل</h2>

<p>هذه الخلفية ليست حزمة منفصلة؛ إنها تأتي داخل vLLM نفسه. ثبّت vLLM v0.25.0 أو أحدث وأضف <code class="language-plaintext highlighter-rouge">--model-impl transformers</code> إلى أمر الخدمة. الأمثلة الحقيقية التي نشرتها Hugging Face كالتالي.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># وحدة معالجة رسومات واحدة، نموذج كثيف</span>
vllm serve Qwen/Qwen3-4B <span class="nt">--model-impl</span> transformers

<span class="c"># توازٍ موتّري عبر وحدتَين، نموذج كثيف كبير</span>
vllm serve Qwen/Qwen3-32B <span class="se">\</span>
  <span class="nt">--model-impl</span> transformers <span class="se">\</span>
  <span class="nt">--tensor-parallel-size</span> 2

<span class="c"># توازي بيانات مع توازي خبراء، نموذج MoE</span>
vllm serve Qwen/Qwen3-235B-A22B-FP8 <span class="se">\</span>
  <span class="nt">--model-impl</span> transformers <span class="se">\</span>
  <span class="nt">--data-parallel-size</span> 8 <span class="se">\</span>
  <span class="nt">--enable-expert-parallel</span>
</code></pre></div></div>

<p>ويعمل الأمر نفسه من واجهة Python للاستدلال دون اتصال.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">vllm</span> <span class="kn">import</span> <span class="n">LLM</span><span class="p">,</span> <span class="n">SamplingParams</span>

<span class="n">llm</span> <span class="o">=</span> <span class="nc">LLM</span><span class="p">(</span>
    <span class="n">model</span><span class="o">=</span><span class="sh">"</span><span class="s">Qwen/Qwen3-4B</span><span class="sh">"</span><span class="p">,</span>
    <span class="n">model_impl</span><span class="o">=</span><span class="sh">"</span><span class="s">transformers</span><span class="sh">"</span><span class="p">,</span>   <span class="c1"># استخدام تعريف Transformers بدل نقل مخصص
</span><span class="p">)</span>
<span class="n">out</span> <span class="o">=</span> <span class="n">llm</span><span class="p">.</span><span class="nf">generate</span><span class="p">(</span>
    <span class="p">[</span><span class="sh">"</span><span class="s">كيف تخدم ThakiCloud النماذج مفتوحة الأوزان؟</span><span class="sh">"</span><span class="p">],</span>
    <span class="nc">SamplingParams</span><span class="p">(</span><span class="n">max_tokens</span><span class="o">=</span><span class="mi">256</span><span class="p">,</span> <span class="n">temperature</span><span class="o">=</span><span class="mf">0.7</span><span class="p">),</span>
<span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="n">out</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">outputs</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">text</span><span class="p">)</span>
</code></pre></div></div>

<p>ما يلفت النظر عبر الأمثلة الثلاثة أن خيارات الخدمة الموزعة مثل التوازي الموتّري وتوازي البيانات وتوازي الخبراء تعمل جميعها تحت خلفية Transformers. أي أنك لا تتخلى عن التوسّع الأفقي مقابل التوافق. من نموذج كثيف بحجم 4B إلى نموذج MoE بحجم 235B، تغطّي براية واحدة ذلك.</p>

<h2 id="نتائج-التجربة-الفعلية">نتائج التجربة الفعلية</h2>

<p>هذه البيئة هي macOS (Apple Silicon)، لذا لا يمكنها تشغيل نوى CUDA الخاصة بـ vLLM، ولم نتمكن من إعادة إنتاج قياس إنتاجية vLLM نفسه. بدلًا من ذلك أعدنا إنتاج <strong>الخطوة الأهم التي تنفّذها الخلفية داخليًا: استخدام torch.fx لتحليل رسم النموذج بشكل ثابت والعثور على أنماط أهداف الدمج</strong>. بنينا مُفكّكًا من أربع طبقات على نمط Llama بلغة PyTorch خالصة، بالبنية نفسها التي تستخدمها نماذج الخدمة الحقيقية (انتباه الاستعلام المجمّع GQA وطبقة SwiGLU MLP)، وتتبّعنا رسمه عبر <code class="language-plaintext highlighter-rouge">torch.fx.symbolic_trace</code>، وصنّفنا العُقد.</p>

<p>كانت القياسات كالتالي. أنتج تتبّع هذا المُفكّك الصغير البالغ 2.902 مليون معامل رسم torch.fx بإجمالي <strong>178 عقدة</strong>. حسب نوع العملية كان هناك 80 استدعاء دالة، و60 استدعاء طريقة، و28 استدعاء وحدة، و8 عمليات جلب سمات. من بين هذه، بلغت الأنماط على مستوى الدوال التي تستطيع الخلفية استبدالها فورًا بنوى دمج 16 عملية اختزال RMSNorm، و8 عمليات ضرب مصفوفات متعلقة بالانتباه، و4 عمليات softmax، و4 تفعيلات SwiGLU، أي 32 إجمالًا، إضافة إلى 28 استدعاء وحدة تحمل إسقاطات QKV والإخراج وطبقة MLP والتطبيع. بلغ زمن التمرير الأمامي عند طول تسلسل 64 في المتوسط 1.4 ملّي ثانية، مقيسًا على torch 2.13.0.</p>

<p><img src="/assets/images/vllm-transformers-native-speed-results.png" alt="مخطط أعمدة يوضح توزيع عُقد أهداف الدمج في رسم torch.fx" /></p>

<p>ما تُظهره هذه الأرقام واضح. حتى في كتلة صغيرة واحدة من 178 عقدة، تتكرر أنماط جيدة التكوين من الانتباه والتطبيع وتفعيل MLP، وهذه بالضبط النقاط التي تستهدفها الخلفية لاستبدالها بنوى vLLM. في نموذج حقيقي بعشرات الطبقات يتضاعف هذا النمط بعدد الطبقات، فيتيح تحليل رسم واحد للخلفية دمج عمليات الاختناق عبر النموذج كله دفعة واحدة. وفق Hugging Face، أتاح هذا النهج لخلفية Transformers مضاهاة إنتاجية vLLM الأصلية أو التفوّق عليها من 4B إلى 235B، شاملًا إعدادات التوازي الموتّري وMoE. لم تُعد تجربتنا إنتاج تلك الأرقام؛ بل أكّدت بالقياس <strong>الهيكل العظمي للآلية</strong> التي تنتجها.</p>

<h2 id="دلالات-لـ-thakicloud">دلالات لـ ThakiCloud</h2>

<p><strong>ai-platform</strong> من ThakiCloud هي بنية تحتية متعددة المستأجرين للذكاء الاصطناعي وتعلّم الآلة تخدم النماذج لبيئات عملاء متنوعة فوق K8s وجدولة GPU المستندة إلى Kueue. هذه الخلفية فائدة مباشرة لمشغّل خدمة مثلنا. أولًا، <strong>يتقلّص زمن إدخال النموذج.</strong> عند صدور نموذج جديد مفتوح الأوزان، كان علينا حتى الآن انتظار دعم vLLM الرسمي لتلك البنية أو قبول نقل ذاتي. إذا وُجد تطبيق Transformers، تتيح لنا <code class="language-plaintext highlighter-rouge">--model-impl transformers</code> تشغيل حجيرة خدمة بسرعة مُحسّنة فورًا. وهذا يؤثر مباشرة في السؤال التنافسي عن سرعة وصول نموذج جديد إلى الإنتاج.</p>

<p>ثانيًا، <strong>يصبح مسار خدمة البنى المخصصة أبسط.</strong> عند خدمة نموذج مضبوط أو معدّل هيكليًا لعميل محدد محليًا، فإن القدرة على النشر من تعريف Transformers وحده، دون نقل مخصص إلى vLLM، تقلّل عبء الصيانة كثيرًا. في بيئات السحابة السيادية أو المنظّمة التي تتطلب الاستضافة الذاتية، نوفّر الوقت المُنفَق في التوفيق بين إصدارات المحرك والنموذج. وبما أن التوازي الموتّري وتوازي البيانات وتوازي الخبراء يعمل كله، يمكننا تبنّي هذا المسار دون تغيير طوبولوجيات الخدمة متعددة الـGPU التي نشغّلها بالفعل.</p>

<p>من منظور الوكلاء، تنطبق عدسة <strong>Paxis</strong> أيضًا. Paxis هي مستوى تحكّم Agent-Native Cloud يعمل فوق ai-platform، ويبدّل نماذج مختلفة كالأدوات أثناء تشغيل الوكلاء. إذا استطاعت طبقة الخدمة إدخال نماذج جديدة مفتوحة الأوزان أسرع وأرخص، اتّسع مجمع النماذج الذي يمكن للوكلاء فوقها اختياره وانخفضت كلفة التبديل. ولأن الخدمة منخفضة الكلفة وزمن الاستجابة هي في النهاية ما يجعل أحمال الوكلاء اقتصادية، تتجه كفاءة خدمة ai-platform ومرونة وكلاء Paxis في الاتجاه نفسه.</p>

<h2 id="القيود-والاعتراضات">القيود والاعتراضات</h2>

<p>هذه الخلفية ليست حلًّا لكل شيء، وثمة حدود واضحة تستحق الذكر إنصافًا. أولًا، ميزة الأداء محصورة في «البنى المتوافقة». يجب أن يكون النموذج قابلًا للتتبع الثابت عبر torch.fx، وأن يطابق أنماطًا تعرفها الخلفية مسبقًا حتى ينطبق الدمج. البنية ذات تدفق تحكّم ديناميكي كثيف أو عمليات جديدة لم ترها الخلفية سترتد إلى مسارات غير مدموجة في بعض الأجزاء، فتتقلّص ميزة السرعة تبعًا لذلك. ليست كل نماذج Transformers تبلغ السرعة الأصلية تلقائيًا.</p>

<p>ثانيًا، بلغت هذه الميزة النضج في v0.25.0 لكنها لا تزال في تطوّر. لبعض تركيبات التكميم، وبعض متغيرات الانتباه، أو مخططات توجيه MoE النادرة، قد يظل التطبيق المنقول المخصص أكثر استقرارًا أو أسرع. قبل الإنتاج، الأأمن أن تقيس بنفسك الإنتاجية والدقة الفعليتين على نموذجك وعتادك المستهدفين. لهذا السبب بالذات لم نستشهد بأرقام إنتاجية vLLM مباشرة بل نسبناها إلى الإعلان الرسمي؛ فالأرقام تختلف حسب البيئة، والقياس على عنقود GPU الخاص بـ ThakiCloud مخطّط له على حدة.</p>

<p>ثالثًا، ثمة اعتراض ممكن. حين يقترن محرك الخدمة ومكتبة النموذج اقترانًا وثيقًا، قد تؤثر تغييرات Transformers في استقرار الخدمة. في زمن قاعدتَي الشيفرة المنفصلتين كان يمكنك تثبيت كومة الاستدلال باستقلال، لكن مشاركة الخلفية تفرض إعادة التفكير في إدارة الإصدارات. ومع ذلك، موازنةً بكلفة تنفيذ كل نموذج جديد مرتين، نرى أن مكسب سرعة الإدخال من هذا الاقتران أكبر في معظم سيناريوهات الخدمة.</p>

<h2 id="المصادر">المصادر</h2>

<ul>
  <li><a href="https://huggingface.co/blog/native-speed-vllm-transformers-backend">Native-speed vLLM transformers modeling backend (Hugging Face Blog)</a></li>
  <li><a href="https://daily.dev/posts/vllm-v0-25-0-transformers-backend-now-matches-native-vllm-speed-z8kvnsk7c">vLLM v0.25.0: transformers backend now matches native vLLM speed (daily.dev)</a></li>
  <li><a href="https://blog.vllm.ai/2025/04/11/transformers-backend.html">Transformers modeling backend integration in vLLM (vLLM Blog)</a></li>
  <li><a href="https://x.com/ClementDelangue/status/2076763231788339669">Clement Delangue (@ClementDelangue) on X</a></li>
  <li>شيفرة التجربة والسجلات: <code class="language-plaintext highlighter-rouge">outputs/blog-impl/vllm-transformers-native-speed/</code> (إعادة إنتاج تحليل رسم torch.fx، torch 2.13.0، وحدة المعالجة المركزية)</li>
</ul>]]></content><author><name>{&quot;name&quot;=&gt;nil, &quot;avatar&quot;=&gt;nil, &quot;bio&quot;=&gt;nil, &quot;location&quot;=&gt;&quot;Seoul, Korea&quot;, &quot;email&quot;=&gt;&quot;info@thakicloud.co.kr&quot;, &quot;uri&quot;=&gt;nil, &quot;home&quot;=&gt;nil, &quot;links&quot;=&gt;[{&quot;label&quot;=&gt;&quot;Website&quot;, &quot;icon&quot;=&gt;&quot;fas fa-fw fa-link&quot;, &quot;url&quot;=&gt;&quot;https://thakicloud.co.kr&quot;}, {&quot;label&quot;=&gt;&quot;GitHub&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-github&quot;, &quot;url&quot;=&gt;&quot;https://github.com/thakicloud&quot;}]}</name><email>info@thakicloud.co.kr</email></author><category term="llmops" /><category term="vllm" /><category term="transformers" /><category term="inference" /><category term="serving" /><category term="torch-fx" /><category term="llmops" /><category term="self-hosting" /><category term="open-weights" /><category term="paxis" /><summary type="html"><![CDATA[حتى الآن كان يجب بناء كل بنية نموذج مرتين: مرة في Transformers للتدريب والبحث، ومرة أخرى في vLLM للاستدلال الإنتاجي. خلفية Transformers بالسرعة الأصلية في vLLM v0.25.0 تُنهي هذا التكرار. تعمل عبر استخدام torch.fx لتحليل رسم النموذج بشكل ثابت، والعثور على أنماط معروفة مثل الانتباه والتطبيع وطبقات MLP، ثم إعادة توصيلها بنوى vLLM المُحسّنة. أعدنا إنتاج خطوة تحليل الرسم التي تنفّذها الخلفية فعليًا على مُفكّك من أربع طبقات وقِسنا أيًّا من عُقده الـ178 يصبح هدفًا للدمج. ثم ننظر في ما يعنيه ذلك لبنية ThakiCloud التحتية متعددة المستأجرين لخدمة النماذج مفتوحة الأوزان.]]></summary></entry><entry xml:lang="ar"><title type="html">لتوليد واجهات الشاشة انطلاقًا من نظام التصميم، يجب بناء بوابة التحقق قبل النموذج</title><link href="https://thakicloud.github.io/ar/research/tds-ui-generator/" rel="alternate" type="text/html" title="لتوليد واجهات الشاشة انطلاقًا من نظام التصميم، يجب بناء بوابة التحقق قبل النموذج" /><published>2026-07-15T00:00:00+09:00</published><updated>2026-07-15T00:00:00+09:00</updated><id>https://thakicloud.github.io/ar/research/tds-ui-generator</id><content type="html" xml:base="https://thakicloud.github.io/ar/research/tds-ui-generator/"><![CDATA[<p>هذا المقال سجل لما تعلّمه فريق المنصة لدينا أثناء بناء نموذج يُولّد تلقائيًا واجهات لوحة تحكم لسطح المكتب باستخدام نظام تصميم THAKI (<code class="language-plaintext highlighter-rouge">@thaki/tds</code>). الجمهور المستهدف هو مهندسو الواجهة الأمامية وتعلّم الآلة الذين يحاولون استخلاص واجهات مستخدم من نموذج لغوي كبير. ولنبدأ بالخلاصة مباشرة: جودة توليد الشاشات لم يحددها حجم النموذج، بل <strong>البوابة التي تُترجم المخرجات فعليًا إلى كود وتتحقق منها</strong>.</p>

<p><img src="/assets/images/posts/research/tds-ui-generator/hero.png" alt="لافتة نتائج تجربة مولّد واجهات TDS التي انقلبت من 0/40 في الضبط الدقيق إلى 39/40 في فك التشفير المقيَّد" />
<em>بدلًا من تعليم القواعد النحوية عبر التدريب، فرضنا عبر القواعد ألا يخرج سوى مخرجات صالحة.</em></p>

<h2 id="لماذا-لم-نُولّد-الكود-مباشرة">لماذا لم نُولّد الكود مباشرة</h2>

<p>توليد كود JSX طويل دفعة واحدة من لقطة شاشة أو من متطلبات نصية نمط فشل معروف منذ زمن: تُحذف عناصر، وتتشوّه التسلسلات الهرمية، وينبسط التخطيط. نقلنا إلى واجهة المستخدم مبدأً مفاده الحفاظ على التمثيل العام وتركيز التعلّم القوي على الجزء الخاص بالمجال فقط. جعلنا النموذج لا يُولّد البكسلات ولا الكود مباشرة، بل يُنتج تمثيلين وسيطين فقط. أولًا، تمثيل UX-IR المستقل عن نظام التصميم يعبّر عن “ماذا تفعل هذه الشاشة”، ثم تمثيل TDS-IR يعبّر عن “بأي مكوّنات TDS تُترجم إلى واقع”. الكود الفعلي لا يملكه النموذج بل مترجم حتمي (deterministic compiler). وبما أن TDS يُنفّذ أصلًا الحشو والطباعة والتفاعل، لا يحتاج النموذج إلى إعادة تعلّم الأنماط البصرية، بل يكفي أن يتعلّم أي مكوّن يستخدم وبأي بنية.</p>

<h2 id="أول-ما-بنيناه-لم-يكن-النموذج-بل-السجل-والبوابة">أول ما بنيناه لم يكن النموذج، بل السجل والبوابة</h2>

<p>حلّلنا مستودع <code class="language-plaintext highlighter-rouge">tds_ssot</code> واستخرجنا آليًا خصائص (props) وفتحات (slots) وقيم التعداد (enum) لواحد وستين مكوّنًا، إضافة إلى القواعد التي تحدد أي مكوّن يمكن أن يدخل في أي فتحة، وجمعنا كل ذلك في Component Registry. تدخل هنا قواعد مثل ضرورة أن يكون variant الخاص بـ Button واحدًا من ثمانية أنواع محددة، أو أن المكوّنات المسموح بها في فتحة control الخاصة بـ FormField محدودة سلفًا. من الاكتشافات اللافتة أن <code class="language-plaintext highlighter-rouge">@thaki/tds</code> ليس نظامًا للجوال، بل نظام لوحة تحكم لسطح المكتب يتمحور حول Table وDrawer وModal، وهذا هو سبب كون مسار العرض التوضيحي <code class="language-plaintext highlighter-rouge">/desktop</code>. لذلك ضبطنا أيضًا خرائط تحقيق أدوار تجربة المستخدم عبر مكوّنات TDS بما يتوافق مع أنماط لوحة التحكم.</p>

<p>جعلنا البوابة مملوكة من قبل الكود. فهي تتحقق حتميًا مما إذا كان المكوّن موجودًا فعلًا، وما إذا كانت الخاصية قيمة معرَّفة، وما إذا كانت الفتحة متوافقة، وما إذا كان العنصر القابل للنقر مرتبطًا بفعل، وما إذا كان زر primary غير مكرر. أن يُقرّ النموذج ذاتيًا بأنه “أنجز عملًا جيدًا” ليس تحققًا. التحقق هو أن يُصرَّف الكود بنجاح وأن يجتاز المخطط (schema).</p>

<h2 id="هل-تكفي-100-عينة-من-البيانات">هل تكفي 100 عينة من البيانات؟</h2>

<p>كانت طلبات المستخدمين مؤلفة من 100 عينة فقط. ولا بد من الاعتراف بصراحة هنا: إجراء ضبط دقيق كامل لنموذج بحجم 27 مليار معامل باستخدام 100 عينة فقط يعني حتمًا فرط التخصيص (overfitting) وانهيار الأنماط (mode collapse). لذلك لم نستخدم المئة عينة كمجموعة تدريب لنموذج 27B، بل كبيانات تُثبت صحة خط الأنابيب. ولّدنا أنماط شاشات لوحة التحكم الفعلية عبر نحو احتمالي (probabilistic grammar)، واشتققنا أمثلة التدريب فقط من الشاشات التي اجتازت البوابة. من كل شاشة واحدة استخرجنا مهامًا متعددة: من النص إلى UX-IR، ومن النص إلى TDS-IR، ومن تعليمات التحرير إلى JSON Patch، والاسترجاع من IR خاطئ، إضافة إلى أزواج تفضيل تقرن نسخة جيدة بأخرى تالفة. من 20 شاشة بذرية من أصل 22 اجتازت البوابة، حصلنا على 100 مثال SFT و20 زوج تفضيل. التزمنا بمبدأ أن اجتياز التحقق القابل للتنفيذ أهم من كمية البيانات.</p>

<h2 id="الرقم-الأهم">الرقم الأهم</h2>

<p>أثمن نتيجة حصلنا عليها في هذا المشروع لم تكن منحنى التدريب، بل مقارنة القدرة التمييزية بين المقاييس. حذفنا مكوّنًا واحدًا من IR الصحيح وأفسدنا قيمة تعداد إحدى الخصائص، ثم قسنا مدى قدرة كل مقياس على رصد هذا التلف.</p>

<table>
  <thead>
    <tr>
      <th>المقياس</th>
      <th>عادي</th>
      <th>تالف</th>
      <th>التغيّر</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>component F1 (التشابه)</td>
      <td>1.00</td>
      <td>0.81</td>
      <td>لم ينخفض تقريبًا</td>
    </tr>
    <tr>
      <td>valid-prop rate</td>
      <td>1.00</td>
      <td>0.30</td>
      <td>انهيار</td>
    </tr>
    <tr>
      <td>schema-valid rate</td>
      <td>0.93</td>
      <td>0.23</td>
      <td>انهيار</td>
    </tr>
    <tr>
      <td>compile-ok</td>
      <td>1.00</td>
      <td>1.00</td>
      <td>لا استجابة</td>
    </tr>
  </tbody>
</table>

<p>كان المقياس القائم على التشابه متساهلًا، بينما لم يستجب نجاح التصريف (compile) إطلاقًا. بما أن المُصرِّف يُخرج حتى الخصائص الخاطئة كما هي دون اعتراض، فإن نجاح التصريف لا يعني جودة عالية. في المقابل، استجاب التحقق من المخطط وصلاحية الخصائص بدقة للتلف، فانخفضا إلى أقل من النصف. بعبارة أخرى، إذا اعتمدنا على التشابه أو نجاح التصريف وحدهما لضبط جودة توليد الشاشات، فإننا لن نستطيع تصفية المخرجات التي تبدو صحيحة تقريبًا لكنها في الواقع خاطئة. ما يصنع الجودة هو بوابة تُغلق الحلقة عبر التصريف والمخطط والفتحات والتفاعل.</p>

<h2 id="جرّبنا-التدريب-وفشلنا-بصراحة">جرّبنا التدريب، وفشلنا بصراحة</h2>

<p>إذا كان ما سبق قصة الهيكل التنفيذي (harness)، فما يلي هو التدريب الفعلي. شغّلنا محرك البيانات وولّدنا 5924 مثال تدريب من 1185 شاشة اجتازت البوابة، وألحقنا LoRA بنموذج Qwen3.6-27B ودرّبناه على عنقود H200 الداخلي. تقارب التدريب نفسه بشكل جيد؛ انخفضت الخسارة إلى 0.07 ووصلت دقة الرموز (token accuracy) إلى 96%. ثم قدّمنا المحوّل (adapter) المدرَّب فعليًا للخدمة وقارنّا ما قبل التدريب بما بعده.</p>

<p>بصراحة، كانت النتيجة فشلًا. لم يُغيّر LoRA التشخيصي المكوَّن من 300 خطوة نتائج التوليد التلقائي إلا بالكاد. كان ملف الأخطاء متطابقًا فعليًا بين النموذج قبل التدريب وبعده. كلاهما ألحق خصائص الإدخال مباشرة بـ FormField، وألحق بـ Card عنوانًا (title) غير موجود فيه أصلًا. البنية الفعلية لنظام التصميم تجعل FormField يُغلّف الإدخال داخل فتحة متداخلة، لكن كلا النموذجين كان يتخيل بنية أكثر تسطيحًا.</p>

<p>عند تعمّق السبب وجدنا ثلاثة عوامل. أولًا، كان التدريب قصيرًا وتشبّعت دقة الرموز مبكرًا فضعفت إشارة التدرّج (gradient). والأهم من ذلك كان في البيانات: دالة realize التي ولّدت البيانات الاصطناعية لم تُظهر البنية المتداخلة الفعلية، فلم يكن بإمكان النموذج تعلّم عقد بيانات غير موجودة أصلًا في البيانات. وأخيرًا، كانت عادات نموذج 27B السابقة قوية.</p>

<p>هنا يبرز الدرس الثاني. المقاييس البديلة الثلاثة جميعها فاتتها جودة التوليد الحقيقية. لا نجاح التصريف، ولا دقة الرموز بأسلوب teacher-forcing، ولا حتى التغيّر في دقة الرموز بعد إلحاق LoRA، كان أي منها متسقًا مع معدل اجتياز البوابة. فقط بوابة التنفيذ المستندة إلى سجل كامل كشفت الفجوة الحقيقية المشتركة بين النموذجين. وفي هذه الأثناء اكتشفنا أن سجلنا نفسه كان ناقصًا وكان يُسقط مخرجات سليمة، فاستخرجنا خصائص 30 مكوّنًا بشكل شامل وصحّحناها.</p>

<h2 id="فأصلحنا-البيانات-وأعدنا-التدريب-ووجدنا-الجواب-أخيرًا">فأصلحنا البيانات، وأعدنا التدريب، ووجدنا الجواب أخيرًا</h2>

<p>أعدنا كتابة دالة realize لتُنتج البنية المتداخلة الفعلية. الآن يُغلّف FormField الإدخال داخل فتحة، ويستخدم كل مكوّن خصائصه الحقيقية. أنتجنا 2771 شاشة تجتاز البوابة بشكل كامل، واشتققنا منها 13855 مثال تدريب. وهذه المرة شغّلنا التدريب لفترة أطول بكثير، إذ نفّذنا 1500 تحديث أمثلة (optimization update).</p>

<p>ومع ذلك، ظل النموذج المدرَّب غير قادر على اجتياز البوابة. كانت النتائج قبل التدريب وبعده متطابقة تقريبًا مرة أخرى. عند هذه النقطة اتضح الأمر: عادة النموذج ذي 27 مليار معامل نحو البنى المسطّحة في هذه المسألة لا يمكن كسرها بحجم تدريب يمكننا تحمّله.</p>

<p>لذلك غيّرنا الاتجاه. بدلًا من إقناع النموذج، قررنا فرض التوليد نفسه. ولّدنا آليًا مخطط JSON من السجل، مخططًا لا يسمح إلا بأسماء المكوّنات الموجودة فعلًا وبالخصائص التي يملكها كل مكوّن فعليًا حصرًا، ويفرض البنية المتداخلة عبر التكرار (recursion). فرضنا هذا المخطط كقيد على فك التشفير (decoding constraint). كانت النتيجة واضحة: على نفس عيّنة الاختبار المحجوبة (held-out) المكوّنة من 40 حالة، ودون أي تدريب، ارتفع معدل اجتياز البوابة من 0% إلى 39 حالة، أي 97.5% (فاصل ثقة 95% بين 86.8% و99.9%).</p>

<p><img src="/assets/images/posts/research/tds-ui-generator/fig1-reversal.png" alt="مخطط أعمدة يقارن معدل اجتياز البوابة عبر أربع طرق: الأساسي، الضبط الدقيق، الإصلاح، وفك التشفير المقيَّد" />
<em>مقارنة رباعية: ارتفع معدل اجتياز البوابة إلى 39/40 بالتقييد وحده دون أي تدريب. قيم مقاسة (n=40).</em></p>

<p>هذه المقارنة الثلاثية هي خلاصة هذا المشروع. كل من النموذج الأساسي دون أي معالجة والنموذج المضبوط دقيقًا سجّلا 0/40، بينما اجتاز النموذج الأساسي المقيَّد في فك التشفير وحده 39/40. عندما نطلب مخرجات مُهيكلة من نموذج ذي عادات قوية، فإن تقييد فك التشفير بقواعد كبوابة التنفيذ كان في هذا السياق أرخص وأكثر يقينًا من محاولة محو تلك العادات عبر الضبط الدقيق.</p>

<p>من هنا يجب أن نكون صادقين تمامًا. أولًا، النسبة 97.5% وليست 100%. الحالة الوحيدة التي لم تجتز البوابة أنتجت JSON مقطوعًا في منتصفه رغم فرض القيد. أي أن تقييد المخطط لا يضمن حتى إنتاج JSON قابلًا للتحليل بشكل كامل. ثانيًا، هذا الانتصار انتصار للصلاحية لا للجودة. تشابه المكوّنات (F1) مقارنة بالشاشة الصحيحة انخفض بالفعل قليلًا عند فرض القيد (من 0.317 إلى 0.292). كون المخرجات صالحة وكونها متوافقة مع النية المطلوبة أمران مختلفان، وهذه الفجوة هي الواجب الحقيقي للمرحلة التالية. ثالثًا، لا ينبغي أن نُسيء فهم سبب ارتفاع معدل الاجتياز. ظننا في البداية أن هذه النسبة العالية سببها أن المخطط يغطي معظم قواعد البوابة، لكن عندما قارنّا القاعدتين بحالات عدائية (adversarial cases) اتضح العكس. البوابة كانت أشد صرامة من المخطط. المخطط لا يمنع سوى أكثر خطأين شيوعًا (مكوّن غير موجود، خاصية غير موجودة)، بينما يسمح بمرور مخالفات مثل غياب schemaVersion أو وضع مكوّن خاطئ في فتحة. أما الذي يرصد تلك المخالفات فهو البوابة. إذن سبب فائدة التقييد هو أن المخطط أزال أشيع أنواع الفشل، وأن المخرجات المتبقية استوفت بالمصادفة القواعد الأشد صرامة للبوابة أيضًا. أما الخطر الحقيقي لكون النتيجة صالحة by-construction فهو أن المخطط والبوابة كلاهما مُشتق من السجل نفسه، وهذا لا يمكن استبعاده إلا عبر مُتحقق خارج السجل (تصيير React وفحص أنواع TypeScript).</p>

<h2 id="الشاشة-الصالحة-لم-تكن-شاشة-جيدة">الشاشة الصالحة لم تكن شاشة جيدة</h2>

<p>لو توقفنا هنا لكانت الخلاصة “التقييد هو الحل”، لكن ذلك كان نصف الحقيقة فقط. حفرنا أعمق. استخرجنا عقد المتطلبات من الشاشات الصحيحة المحجوبة، وقسنا مدى استعادة كل طريقة للمحتوى الفعلي للشاشة. كانت النتيجة موجعة. التقييد سجّل أعلى صلاحية، لكنه سجّل أدنى استعادة لمعلومات المرجع ومكوّناته. اشترينا الصلاحية دون تدريب، لكن استعادة المحتوى كانت أدنى حتى من النموذج الأساسي دون أي معالجة. الأمر نفسه صحّ على طريقة repair التي تُصلح المخرجات الأساسية حتميًا دون GPU، وعلى طريقة وضع خطة حرة أولًا ثم فرض القيد عليها. كلتا الطريقتين قايضتا المحتوى بالصلاحية. كون المخرجات صالحة وكونها مطابقة للمتطلبات محوران مختلفان.</p>

<h2 id="فقسنا-أولًا-أين-يجب-أن-نستثمر">فقسنا أولًا أين يجب أن نستثمر</h2>

<p>كان الدافع الغريزي التالي هو تكبير النموذج أو توليد عدة نسخ ثم الاختيار من بينها. لكننا سألنا أولًا: إذا ولّدنا ثماني مرات، هل توجد نسخة جيدة من بينها أصلًا؟ ولّدنا ثماني مخرجات مقيّدة لكل مطالبة (prompt) وقارنّا عيّنة واحدة بأفضل مرشّح، فتبيّن أن أفضل مرشّح يتفوّق بوضوح على تشابه العيّنة الواحدة: 0.29 مقابل 0.45. كانت الشاشات الجيدة تُولَّد بالفعل. ما كنا عاجزين عنه هو اختيار الجيد من بينها. لم تكن العقبة في التوليد بل في الاختيار.</p>

<h2 id="المُنتقي-لم-يكن-حكمًا-بل-كان-مبنيًا-على-المتطلبات">المُنتقي لم يكن حكمًا، بل كان مبنيًا على المتطلبات</h2>

<p>لذلك بنينا مُنتقيًا لا يعرف الإجابة الصحيحة سلفًا، وقسنا كم من ذلك السقف يستطيع فعلًا التقاطه.</p>

<p><img src="/assets/images/posts/research/tds-ui-generator/fig2-verifier.png" alt="مخطط أعمدة يقارن F1 المكوّنات بين مُنتقي Top-1 والبنيوي والحَكَم والقائم على المتطلبات وOracle" />
<em>من بين المُنتقين الذين لا يعرفون الإجابة الصحيحة، استعاد المُسنِد (predicate) القائم على المتطلبات 27% من هامش التحسين، بينما كان حَكَم النموذج اللغوي الكبير أسوأ من عدم الاختيار إطلاقًا. قيم مقاسة (n=40).</em></p>

<p>اختيار المرشّح الأغنى بنيويًا لم يكن مفيدًا تقريبًا. بل إن اختيار المرشّح الذي اجتاز البوابة أدى إلى نتيجة أسوأ. رأينا هنا مرة أخرى أن الاختيار بناءً على الصلاحية يُضعف المحتوى. سؤال النموذج الأساسي مباشرة عن الأفضل من بين المرشحين كان أسوأ من عدم الاختيار إطلاقًا. الشيء الوحيد الذي نجح كان استخراج ما يجب أن تحتويه الشاشة من المطالبة أولًا، ثم اختيار المرشّح الذي يلبّي ذلك المتطلب بأفضل شكل. هذا التقط ربع هامش تحسين الاختيار. لم يكن الحَكَم هو المُنتقي، بل كانت المتطلبات هي المُنتقي.</p>

<p>في ختام المشروع، تبقى أربعة دروس. أولًا، أول مكان يستحق الاستثمار ليس نموذجًا أكبر، بل الهيكل الذي يُنفّذ المخرجات فعليًا ويتحقق منها. ثانيًا، يجب أن يكون ذلك الهيكل دقيقًا حتى يظهر الفشل والنجاح بدقة. ثالثًا، عندما تتصادم العادات القوية مع الحاجة إلى مخرجات مُهيكلة، كان فرض القيد أرخص من دفع التدريب أكثر، على الأقل في هذه المسألة تحديدًا. لا نعمّم هذا على كل الحالات. رابعًا، الصلاحية والإخلاص للمحتوى محوران مختلفان، والعقبة المتبقية ليست في التوليد بل في الاختيار، وذلك المُنتقي يجب أن يكون قائمًا على المتطلبات لا على حَكَم. الخطوة التالية التي يجب إثباتها هي رفع مستوى المُنتقي والدقة الدلالية معًا عبر عقود متطلبات مكتوبة بشرية.</p>

<h2 id="المراجع">المراجع</h2>

<p>نترك هنا المصادر الأصلية للتقنيات الخارجية التي استندت إليها هذه التجربة.</p>

<ul>
  <li>الأساس النظري لفك التشفير المقيَّد (الطريقة التي انتصرت في النهاية): Willard, Louf, <a href="https://arxiv.org/abs/2307.09702"><em>Efficient Guided Generation for Large Language Models</em></a>. هي طريقة تُقيِّد فك التشفير عبر مخطط أو نحو (grammar) بحيث لا تخرج سوى مخرجات صالحة.</li>
  <li>المكتبة مفتوحة المصدر التي نفّذت هذه الطريقة فعليًا: <a href="https://github.com/dottxt-ai/outlines">Outlines (dottxt-ai/outlines)</a>.</li>
  <li>الضبط الدقيق الفعّال من حيث المعاملات الذي جرّبناه وفشل: Hu وآخرون، <a href="https://arxiv.org/abs/2106.09685"><em>LoRA: Low-Rank Adaptation of Large Language Models</em></a>.</li>
  <li>جذر best-of-N (توليد ثماني نسخ واختيار الأفضل من بينها) والاختيار القائم على المُتحقق: Cobbe وآخرون، <a href="https://arxiv.org/abs/2110.14168"><em>Training Verifiers to Solve Math Word Problems</em></a>.</li>
</ul>]]></content><author><name>{&quot;name&quot;=&gt;nil, &quot;avatar&quot;=&gt;nil, &quot;bio&quot;=&gt;nil, &quot;location&quot;=&gt;&quot;Seoul, Korea&quot;, &quot;email&quot;=&gt;&quot;info@thakicloud.co.kr&quot;, &quot;uri&quot;=&gt;nil, &quot;home&quot;=&gt;nil, &quot;links&quot;=&gt;[{&quot;label&quot;=&gt;&quot;Website&quot;, &quot;icon&quot;=&gt;&quot;fas fa-fw fa-link&quot;, &quot;url&quot;=&gt;&quot;https://thakicloud.co.kr&quot;}, {&quot;label&quot;=&gt;&quot;GitHub&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-github&quot;, &quot;url&quot;=&gt;&quot;https://github.com/thakicloud&quot;}]}</name><email>info@thakicloud.co.kr</email></author><category term="research" /><category term="llm" /><category term="constrained-decoding" /><category term="structured-generation" /><category term="ui-generation" /><category term="design-system" /><category term="evaluation" /><category term="verifier" /><summary type="html"><![CDATA[بدأنا معتقدين أن الضبط الدقيق سيفوز، لكن البيانات قلبت التوقعات. نلخّص هنا كيف حصلنا على مولّد يحافظ على قواعد TDS دون أي تدريب، وصولًا إلى الدرس التالي: الشاشة الصالحة ليست بالضرورة شاشة جيدة.]]></summary></entry><entry xml:lang="en"><title type="html">Have It Write the Goal First on Hard Tasks: Codex Goal-Delegation Prompting</title><link href="https://thakicloud.github.io/en/agentops/codex-goal-delegation/" rel="alternate" type="text/html" title="Have It Write the Goal First on Hard Tasks: Codex Goal-Delegation Prompting" /><published>2026-07-15T00:00:00+09:00</published><updated>2026-07-15T00:00:00+09:00</updated><id>https://thakicloud.github.io/en/agentops/codex-goal-delegation</id><content type="html" xml:base="https://thakicloud.github.io/en/agentops/codex-goal-delegation/"><![CDATA[<h2 id="overview">Overview</h2>

<p>A short tip has been circulating among developers who lean on coding agents. When you hand Codex a truly hard <code class="language-plaintext highlighter-rouge">/goal</code>, do not tell it to start working right away. First ask it to “write the goal so that another thread can achieve it.” Read once, it sounds like a play on words. What difference does it make to ask the model to write the goal instead of achieving it?</p>

<p>Yet this tip lands squarely on something anyone who has run agents for a while knows in their bones. Hard tasks usually fail not because the model is weak, but because the goal was never written in a form a machine can judge. People think a sentence like “clean up this refactor” is a goal, but to an agent it leaves everything blank: when to stop, what counts as success, where the boundary is. So this post takes the “have it write the goal” technique apart piece by piece, and shows how ThakiCloud, which runs a Kubernetes-based AI/ML platform and an agent platform, already enforces the same principle in code.</p>

<h2 id="what-codex-goals-are">What Codex goals are</h2>

<p>First, look closely at the raw ingredient. Codex’s <code class="language-plaintext highlighter-rouge">/goal</code> attaches a persistent objective to a thread. According to OpenAI’s published cookbook “Using Goals in Codex,” a goal should be described in three parts: a measurable outcome, a verification surface that lets you confirm progress, and constraints. Once those three are present, the goal becomes a durable target attached to the thread.</p>

<p>The mechanics matter. At the end of each turn, Codex inspects the evidence so far and judges for itself whether the objective is satisfied. If not, and the goal is still active and within budget, it continues from the latest state. In short, instead of a single response, it repeats observing and judging until the goal, a termination condition, is met. The appeal is that a long-running task can turn into a set-it-and-forget-it workflow.</p>

<p>The key point here is that the quality of the goal decides everything. If the verification surface is blurry, Codex cannot tell when to stop; without constraints, it wanders past its scope and touches unrelated files; without a measurable outcome, it fixes one file and declares itself done. Writing a good goal is therefore its own skill, and when that skill is lacking, hard tasks fall apart.</p>

<pre><code class="language-mermaid">flowchart TB
    A[Hard task idea] --&gt; B{Is the goal in a&lt;br/&gt;machine-checkable form?}
    B --&gt;|No| C[Spinning loop&lt;br/&gt;or early exit]
    B --&gt;|Yes| D[Measurable outcome]
    B --&gt;|Yes| E[Verification surface]
    B --&gt;|Yes| F[Constraints]
    D --&gt; G[Persistent goal&lt;br/&gt;attached to thread]
    E --&gt; G
    F --&gt; G
    G --&gt; H[Self-judges on evidence&lt;br/&gt;at each turn's end]
    H --&gt;|Unmet, within budget| G
    H --&gt;|Met| I[Converged, done]
</code></pre>

<h2 id="the-technique-write-a-goal-for-another-thread">The technique: “write a goal for another thread”</h2>

<p>Now back to the tip. Facing a hard task, a person rarely writes a good goal on the first try. Filling in what the measurable outcome is, what will verify progress, and which constraints to set is itself a non-trivial design task. What this tip proposes is to delegate that design to the model first.</p>

<p>Concretely, it flows like this. The first thread is told to “write a goal that lets another thread autonomously achieve this hard task.” The model does not do the work here. Instead it understands the task and produces a goal spec that states what success is, how to verify it, and where the boundary lies. The person reviews and sharpens that spec, then feeds it as the goal into a new thread to run the actual execution. The execution thread starts with a well-defined termination condition, so it is far less prone to the spinning loops or early exits described above.</p>

<p>This technique works for two reasons. First, it separates writing the goal from achieving the goal. The two are different in character. Writing a goal is about understanding the problem broadly and fixing success criteria in language; achieving a goal is about drilling narrowly toward those criteria. When one thread tries to do both, it lurches into implementation while still deciding the verification criteria, and ends up grading itself against criteria it never even set. Separated, each thread focuses on one thing.</p>

<p>Second, it creates a review point for the person. The goal spec the model produces is an artifact a person can read and edit before execution. If the verification surface is weak, you can reinforce it at this stage; if the scope is broad, you can add constraints. Discovering a mistake after execution starts is expensive; catching it at the goal-spec stage is cheap. In other words, this is not a prompt trick but a structural device that inserts one layer of cheap review.</p>

<p>Of course it is no cure-all. One developer newsletter framed this approach as turning “a four-hour task into a set-it-and-forget-it workflow,” but that is an impression of a case that fit well, not a guarantee. Even if you succeed at making the model write a good goal, whether the execution thread actually converges toward it is a separate matter. So the technique only pays off when it is paired with the verification gates discussed below.</p>

<h2 id="implications-for-thakiclouds-products">Implications for ThakiCloud’s products</h2>

<p>There is a reason this technique does not feel foreign: ThakiCloud already enforces the same principle, not as a prompt request but as a code discipline. Since the subject is agent operations, we center the perspective of our agent platform Paxis here, while also connecting it to the ai-platform infrastructure beneath it.</p>

<p>Paxis is ThakiCloud’s Agent-Native Cloud, a control plane that treats skills, tools, policies, and audit logs as first-class resources. Inside it is an executor called Goal Mode. When we create a goal in Goal Mode, we have written the rules so that <code class="language-plaintext highlighter-rouge">check_cmd</code>, <code class="language-plaintext highlighter-rouge">success_criteria</code>, and a budget cannot be left blank. Those three map almost one-to-one to the three parts of a Codex goal: <code class="language-plaintext highlighter-rouge">success_criteria</code> is the measurable outcome, <code class="language-plaintext highlighter-rouge">check_cmd</code> is the verification surface that judges progress, and the budget is the constraint. If a goal is created as an empty shell, it is designed to fail the gate on the first iteration, so the code guarantees a state where “if you do not write the goal well, it will not even start.”</p>

<p>The delegation structure of “write a goal for another thread” also lives inside us. When a complex request arrives, the main agent decomposes it into subtasks and delegates each to a separate subagent. The one who decomposes and the one who executes are separated, which is exactly the same idea as this article’s split between the goal-writing thread and the goal-executing thread. Decomposition needs judgment, so a higher-tier model handles it; execution is narrow work, so it is sent down to a cheaper model. The principle of cheap workers, expensive gates comes from here.</p>

<p>Above all, we never merge fanned-out results without verification. However well you write and delegate a goal, whether the result is correct must be judged by a separate verification stage, not the executor. Code artifacts are judged by actually running tests and reading the exit code; content or judgment artifacts are filtered by a majority vote of several verifiers with different perspectives. A sentence where the model reports “this looks done” cannot be the termination condition of a loop. This discipline shows how we harden Codex goal’s “judge yourself on the evidence at each turn’s end” into a trustworthy form.</p>

<p>There is a connection through the infrastructure lens too. A loop that slices goals finely and runs them with verification steadily consumes compute. The ai-platform is the layer that provides Kubernetes and Kueue-based GPU scheduling, vLLM serving, and multi-tenant isolation, building a floor where these agent loops can run cheaply and reliably. Low-cost serving creates agent economics, and on top of it Paxis’s goal delegation and verification loops become practically viable. The two lenses complement each other.</p>

<h2 id="limitations-and-counterarguments">Limitations and counterarguments</h2>

<p>To avoid overrating this technique, let us take the other side.</p>

<p>First, the goal-writing step itself can fail. If the model produces a plausible but unverifiable goal, the execution thread still starts without knowing what counts as success. There are many cases where a person writing a short, solid goal directly is better. So the goal spec the model writes must have a human review point, and handing it straight to execution without review throws away the very cheap review point you gained.</p>

<p>Second, the overhead is not justified for every task. Writing the goal for it and splitting threads on a single-file fix or a quick question is overkill. This technique only pays off on hard tasks where the termination condition is blurry, the run is long, and autonomous execution is genuinely valuable. Our internal rules likewise draw a line: use loop tools only for iterative implementation or convergent work, and do not force them onto one-off edits.</p>

<p>Third, the longer autonomous execution runs, the more people tend to trust the result and stop reviewing. The comfort of having delegated the goal well is itself the danger. If the verifier filters out nothing, that is not a signal that everything passed but more likely a signal that the verifier is broken. So core outputs must be sampled and checked by a person periodically, and verifiers should be designed to aim at refutation, not confirmation.</p>

<p>In sum, “on hard tasks, write the goal first” is not a prompting knack but structural advice to separate writing the goal from executing it and to insert a review point in between. If Codex’s goal feature put this into the hands of individual developers, ThakiCloud enforces the same principle at team scale through Paxis’s Goal Mode and verification loops. That writing a good goal is what it means to run an agent well does not change, whatever the tool.</p>

<h2 id="sources">Sources</h2>

<ul>
  <li>OpenAI Cookbook, “Using Goals in Codex” (developers.openai.com/cookbook/examples/codex/using_goals_in_codex)</li>
  <li>Original tweet: nickbaumann_ (reposted at x.com/hjguyhan/status/2077331299648635303)</li>
</ul>]]></content><author><name>{&quot;name&quot;=&gt;nil, &quot;avatar&quot;=&gt;nil, &quot;bio&quot;=&gt;nil, &quot;location&quot;=&gt;&quot;Seoul, Korea&quot;, &quot;email&quot;=&gt;&quot;info@thakicloud.co.kr&quot;, &quot;uri&quot;=&gt;nil, &quot;home&quot;=&gt;nil, &quot;links&quot;=&gt;[{&quot;label&quot;=&gt;&quot;Website&quot;, &quot;icon&quot;=&gt;&quot;fas fa-fw fa-link&quot;, &quot;url&quot;=&gt;&quot;https://thakicloud.co.kr&quot;}, {&quot;label&quot;=&gt;&quot;GitHub&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-github&quot;, &quot;url&quot;=&gt;&quot;https://github.com/thakicloud&quot;}]}</name><email>info@thakicloud.co.kr</email></author><category term="agentops" /><category term="ai-coding" /><category term="agentic" /><category term="codex" /><category term="goal-mode" /><category term="agentops" /><category term="verification" /><summary type="html"><![CDATA[A developer shared a tip: when handing Codex a genuinely hard /goal, first ask it to write the goal so that another thread can achieve it. It sounds like wordplay, but underneath is a real agent-operations pattern: make the model author a verifiable goal spec first, then delegate that spec to a fresh thread. We look at how Codex goals actually work and read the technique through ThakiCloud's Goal Mode, pge-loop, and Paxis.]]></summary></entry><entry xml:lang="en"><title type="html">The Anatomy of GPU and TPU Clusters: How Collective Communication Determines the Speed of Distributed Training</title><link href="https://thakicloud.github.io/en/dev/collective-communication-clusters/" rel="alternate" type="text/html" title="The Anatomy of GPU and TPU Clusters: How Collective Communication Determines the Speed of Distributed Training" /><published>2026-07-15T00:00:00+09:00</published><updated>2026-07-15T00:00:00+09:00</updated><id>https://thakicloud.github.io/en/dev/collective-communication-clusters</id><content type="html" xml:base="https://thakicloud.github.io/en/dev/collective-communication-clusters/"><![CDATA[<h2 id="overview">Overview</h2>

<p>It has been a while since large language models could fit on a single GPU. Models with tens of billions to trillions of parameters are split across tens or thousands of accelerators, and at every training step those accelerators have to reconcile each other’s results. This “reconciling” process is collective communication, and in most modern distributed training workloads, the thing that actually eats up time isn’t matrix multiplication, it’s this communication.</p>

<p>This post is for infrastructure engineers training or serving models on GPU or TPU clusters, and for anyone responsible for serving cost and scalability. It takes Aleksa Gordic’s widely read deep dive, “Inside TPU and GPU Clusters: The Anatomy of Collective Communication,” as a starting point, and cross-checks the core concepts against standard references (NCCL, the TPU v4 paper, and so on) along the way.</p>

<p>Here’s the headline summary up front. First, the performance of distributed training reduces down to a handful of collective operations. Second, the cost of the same operation changes completely depending on the physical topology it runs on (NVIDIA’s switch-based fabric versus Google’s torus structure). Third, which parallelism strategy you use determines which collectives get called, and how often. Understanding these three points explains why placing a handful of GPUs in a particular arrangement has such an outsized effect on performance.</p>

<h2 id="what-collective-communication-actually-is">What Collective Communication Actually Is</h2>

<p>A collective operation is a communication pattern that multiple processes (typically one per accelerator) participate in together. Where point-to-point (P2P) communication is one process sending to another single process, a collective has the whole group split and merge data according to a shared rule. A few of these show up over and over in distributed training:</p>

<ul>
  <li><strong>All-reduce</strong>: every participant’s tensor is reduced element-wise (summed or averaged), and the result is sent back to everyone. This is the exact operation used to reconcile gradients in data-parallel training.</li>
  <li><strong>Reduce-scatter</strong>: a sum is computed, but instead of one participant holding the whole result, it’s split into chunks that get distributed across participants.</li>
  <li><strong>All-gather</strong>: each participant’s chunk is collected so that everyone ends up with the full set. This is the counterpart to reduce-scatter, and chaining the two together produces an all-reduce.</li>
  <li><strong>All-to-all</strong>: every participant sends a different chunk of data to every other participant. This pattern is close to a transpose, and it’s central to routing tokens to experts in mixture-of-experts (MoE) models.</li>
  <li><strong>Broadcast / Reduce</strong>: one-directional operations where one participant sends the same data to everyone, or everyone’s data is collected and reduced down to one participant.</li>
</ul>

<p>One key insight here is that all-reduce is not an atomic operation. All-reduce decomposes into a <strong>reduce-scatter followed by an all-gather</strong>. This decomposition is the root of the cost formula we’ll get to later.</p>

<pre><code class="language-mermaid">flowchart TB
    A["Each accelerator: local gradient/tensor"] --&gt; B["Reduce-scatter&lt;br/&gt;Sum split into chunks"]
    B --&gt; C["All-gather&lt;br/&gt;Chunks restored to everyone"]
    C --&gt; D["All-reduce complete&lt;br/&gt;Everyone holds the same sum"]
    A --&gt; E["All-to-all&lt;br/&gt;MoE token routing"]
    A --&gt; F["Broadcast/Reduce&lt;br/&gt;One-directional distribute/aggregate"]
</code></pre>

<h2 id="the-physical-structure-of-gpu-clusters">The Physical Structure of GPU Clusters</h2>

<p>It’s easiest to think of an NVIDIA-based cluster as two layers: within a node (scale-up) and between nodes (scale-out).</p>

<p>Within a node, <strong>NVLink</strong> and <strong>NVSwitch</strong> tie the GPUs together tightly. The eight or so GPUs inside a single server are wired through NVSwitch into something close to a full mesh, communicating at uniformly high bandwidth from any GPU to any other. This is exactly why work with extremely frequent communication, like tensor parallelism, gets confined inside this domain.</p>

<p>Between nodes, a leaf-spine (fat-tree) network built on <strong>InfiniBand</strong> or <strong>RoCE</strong> (RDMA over Converged Ethernet) is used. This scale-out fabric connects GPUs across racks and servers. A design that shows up often here is the rail-optimized topology: the same-numbered NIC on each node is attached to the same switch (a “rail”), so that inter-node all-reduce traffic passes through fewer hops at the spine layer.</p>

<p>That flexibility comes at a cost. The thousands of switches a scale-out fabric requires can consume roughly 5 to 10 percent of a cluster’s total power [the estimated range varies by configuration], and they demand significant capital expenditure. In other words, instead of relying on any GPU being able to talk cleanly to any other GPU by default, NVIDIA’s approach buys that uniformity by paying for switches that actively process packets.</p>

<h2 id="tpu-clusters-take-a-different-path">TPU Clusters Take a Different Path</h2>

<p>Google’s TPUs go a completely different route. Rather than an active switching fabric, TPU chips connect directly to their neighbors over a dedicated high-speed link called <strong>ICI (Inter-Chip Interconnect)</strong>. In the latest generation, each chip extends ICI links in six directions, plus and minus X, Y, and Z, forming a <strong>3D torus</strong> lattice (earlier generations used a 2D torus to build pods of 256 chips). Because chips only connect directly to their neighbors, most of the switching layer disappears.</p>

<p>That raises an obvious question: how do you connect chips that are far apart, or scale beyond a single pod? This is where the <strong>optical circuit switch (OCS)</strong> comes in. According to the TPU v4 paper, an OCS reconfigures optical fibers using MEMS mirrors rather than actively interpreting the optical signal, it just reflects it. That lets it reconfigurably connect up to 4096 chips while consuming far less power than an InfiniBand switch, since power is only needed to hold the mirror positions in place. It also allows one axis of the torus to be optically wrapped around, or lets the topology be rewired in software to route around a failed node.</p>

<p>Put simply, GPU clusters invest in active switches to buy uniform access, while TPU clusters lean on a neighbor-direct torus plus optical reconfiguration to save on power and cost. Neither approach is unconditionally superior. A torus is optimal for neighbor-to-neighbor traffic but adds hops for arbitrary long-distance communication, while a switch fabric is uniform but expensive and power-hungry.</p>

<h2 id="how-collectives-map-to-parallelism-strategies">How Collectives Map to Parallelism Strategies</h2>

<p>Which collective gets called, and how often, ultimately comes down to which parallelism strategy is in use.</p>

<ul>
  <li><strong>Data parallelism (DP)</strong>: each replica processes a different batch, then gradients are reconciled with <strong>all-reduce</strong>. Communication volume scales with model size and happens once per step.</li>
  <li><strong>Fully sharded data parallelism (FSDP/ZeRO)</strong>: parameters are sharded and held in pieces, gathered with <strong>all-gather</strong> right before the forward pass, and split back apart with <strong>reduce-scatter</strong> after the backward pass. It saves memory at the cost of more frequent communication.</li>
  <li><strong>Tensor parallelism (TP)</strong>: a single layer’s computation is split across multiple GPUs, and the results are merged at each layer boundary with <strong>all-reduce</strong> or all-gather/reduce-scatter. Communication is extremely frequent, which is why confining it inside the NVLink domain mentioned earlier is practically mandatory.</li>
  <li><strong>Pipeline parallelism (PP)</strong>: the model is sliced by layer and distributed across different GPUs, and activations are handed off between stages mostly via <strong>P2P</strong> transfers. Point-to-point communication dominates rather than collectives.</li>
  <li><strong>Expert parallelism (EP/MoE)</strong>: tokens have to be routed to the accelerator holding the relevant expert, so <strong>all-to-all</strong> is central. As the number of participants grows, the number of communication pairs in an all-to-all grows quadratically, making it especially sensitive to topology.</li>
</ul>

<p>In practice, these strategies are layered on top of each other. For example, a typical layout places TP inside a node’s NVLink, DP’s all-reduce over the inter-node InfiniBand, and PP spanning across both. Get the placement wrong, and frequent tensor-parallel communication leaks onto the slower inter-node links, slowing down the entire training run.</p>

<h2 id="the-rule-that-governs-performance-rings-and-trees">The Rule That Governs Performance: Rings and Trees</h2>

<p>There are several algorithms for actually implementing a collective, but from a bandwidth perspective, the best known is <strong>ring all-reduce</strong>. Participants are connected in a single ring, and at each step each one passes its chunk to its next neighbor, carrying out reduce-scatter and all-gather each over N-1 steps.</p>

<p>The total amount of data carried on each link works out to a well-known formula. For an all-reduce of a tensor of size S across N participants, the traffic per link is approximately:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2 x (N - 1) / N x S
</code></pre></div></div>

<p>That’s because (N-1)/N x S flows during reduce-scatter, and another (N-1)/N x S flows during all-gather. The key property here is that as N grows, (N-1)/N converges toward 1, so traffic per link flattens out to roughly 2S. This is why ring all-reduce is called bandwidth-optimal, and it’s why libraries like NCCL and Gloo have relied on it for a long time.</p>

<p>The problem is latency. A ring has to traverse N-1 sequential steps, so the fixed per-step latency (alpha) accumulates in proportion to the number of participants. When a lot of nodes are doing an all-reduce on a small tensor, bandwidth is left on the table while latency becomes the bottleneck. That’s why real libraries automatically choose between ring and tree (or hierarchical) algorithms depending on tensor size and node count. Tree algorithms bring latency down closer to log(N) at the cost of some bandwidth efficiency, which is why NCCL selects different algorithms depending on message size.</p>

<p>The practical implication of this rule is clear. As you change batch size, model size, and node count, the dominant bottleneck shifts back and forth between bandwidth and latency. That’s exactly why you can’t assume “doubling the number of nodes doubles the speed” without benchmarking it.</p>

<h2 id="implications-for-thakiclouds-products">Implications for ThakiCloud’s Products</h2>

<p>This topic touches the heart of infrastructure, which makes it especially practical from the perspective of ThakiCloud’s <strong>ai-platform</strong> (our Kubernetes-based AI/ML SaaS infrastructure).</p>

<p>First, <strong>topology-aware scheduling</strong>. ai-platform schedules GPU workloads with Kueue, and the placement principle of keeping tensor-parallel jobs inside the same NVLink domain (the same node) while routing a data-parallel job’s all-reduce over rail-optimized inter-node links lines up exactly with the communication characteristics of the collectives covered here. You need to know which collective flows over which link before job placement can translate into performance.</p>

<p>Second, <strong>tensor parallelism in serving</strong>. When a large model is served across multiple GPUs with tensor parallelism using an engine like vLLM, an all-reduce fires at every layer. Placing pods so that this communication stays inside NVLink makes it much easier to hit latency targets, and crossing a node boundary noticeably raises per-token latency. In a multi-tenant environment, this kind of placement discipline translates directly into serving cost and SLA outcomes.</p>

<p>Third, <strong>the economics of on-premises and sovereign cloud</strong>. The fact that GPU switches account for a meaningful share of power draw means that when designing a cluster for an on-premises or domestic sovereign environment, networking isn’t a minor add-on, it’s a core variable in total cost of ownership (TCO). The self-hosting and cost efficiency ThakiCloud aims for only holds up on top of these network design decisions.</p>

<p>There’s also a connection to <strong>Paxis</strong>, our agent orchestration product. When distributed training or large-scale inference jobs are coordinated as a DAG and executed in isolation, understanding the communication profile of the collectives each stage calls makes it possible to design more precise resource reservations and policy gates. That said, the center of gravity in this post is the infrastructure layer, so the ai-platform lens is the primary one here.</p>

<h2 id="limitations-and-counterarguments">Limitations and Counterarguments</h2>

<p>This perspective has its counterarguments too. First, frameworks abstract collectives away quite a lot. With the higher-level APIs in PyTorch or JAX, most placement decisions happen automatically inside the library and scheduler, and application developers don’t need to know these details. So if you ask, “does every team need to know torus and ring formulas,” the honest answer is closer to no.</p>

<p>But the moment performance becomes a problem, this abstraction breaks down. When training runs slower than expected or serving latency spikes, finding the root cause eventually requires looking at which collective is flowing over which link. The abstraction is convenient on the happy path, but it turns into a leaky abstraction the moment you’re diagnosing a bottleneck.</p>

<p>The rules laid out in this post also keep changing across hardware generations. NVLink and InfiniBand bandwidth, the number of TPU ICI links, and OCS scale all vary from generation to generation, so any concrete numbers should always be re-verified against the official documentation for that specific generation. The formulas and structures here provide a mental framework, but production decisions need to be closed out with real benchmarks. Finally, there’s the practical gap where software fails to keep pace with hardware. Even a theoretically optimal topology is wasted if the kernels and communication libraries can’t fully exploit it.</p>

<h2 id="sources">Sources</h2>

<ul>
  <li>Aleksa Gordic, “Inside TPU and GPU Clusters: The Anatomy of Collective Communication”: https://www.aleksagordic.com/blog/collective-operations</li>
  <li>NVIDIA NCCL documentation and the communication cost model for ring all-reduce (reduce-scatter + all-gather, bandwidth optimality)</li>
  <li>Google’s TPU v4 paper, “TPU v4: An Optically Reconfigurable Supercomputer for Machine Learning with Hardware Support for Embeddings” (ICI 3D torus, OCS): https://arxiv.org/abs/2304.01433</li>
</ul>]]></content><author><name>{&quot;name&quot;=&gt;nil, &quot;avatar&quot;=&gt;nil, &quot;bio&quot;=&gt;nil, &quot;location&quot;=&gt;&quot;Seoul, Korea&quot;, &quot;email&quot;=&gt;&quot;info@thakicloud.co.kr&quot;, &quot;uri&quot;=&gt;nil, &quot;home&quot;=&gt;nil, &quot;links&quot;=&gt;[{&quot;label&quot;=&gt;&quot;Website&quot;, &quot;icon&quot;=&gt;&quot;fas fa-fw fa-link&quot;, &quot;url&quot;=&gt;&quot;https://thakicloud.co.kr&quot;}, {&quot;label&quot;=&gt;&quot;GitHub&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-github&quot;, &quot;url&quot;=&gt;&quot;https://github.com/thakicloud&quot;}]}</name><email>info@thakicloud.co.kr</email></author><category term="dev" /><category term="dev" /><category term="distributed-training" /><category term="gpu" /><category term="tpu" /><category term="nccl" /><category term="nvlink" /><category term="infiniband" /><category term="kubernetes" /><category term="self-hosting" /><category term="paxis" /><summary type="html"><![CDATA[When training or serving a large model across many accelerators, the real bottleneck usually isn't computation, it's the data moving between accelerators. This post walks through what collective operations like all-reduce, all-gather, reduce-scatter, and all-to-all actually are, and how they run on two very different physical structures: GPU clusters (NVLink, NVSwitch, InfiniBand) and TPU clusters (the ICI 3D torus and optical circuit switches). From the bandwidth cost formula behind ring all-reduce to which collectives are triggered by data, tensor, pipeline, and expert parallelism, we cover this from the perspective ThakiCloud brings to running GPU infrastructure.]]></summary></entry><entry xml:lang="en"><title type="html">Implement Once, Serve at vLLM Native Speed: the Transformers Backend Ends the Double-Build</title><link href="https://thakicloud.github.io/en/llmops/vllm-transformers-native-speed/" rel="alternate" type="text/html" title="Implement Once, Serve at vLLM Native Speed: the Transformers Backend Ends the Double-Build" /><published>2026-07-15T00:00:00+09:00</published><updated>2026-07-15T00:00:00+09:00</updated><id>https://thakicloud.github.io/en/llmops/vllm-transformers-native-speed</id><content type="html" xml:base="https://thakicloud.github.io/en/llmops/vllm-transformers-native-speed/"><![CDATA[<h2 id="overview">Overview</h2>

<p>If you have ever self-hosted open-weight models, you know one familiar wall. A great model ships, but to actually serve it fast you have to wait until your serving engine supports that architecture. A new structure landing in the Transformers library is immediately usable for training and research, yet to reach full speed in a high-performance inference engine like vLLM, someone had to reimplement that architecture from scratch inside vLLM. You effectively built the same model twice.</p>

<p>This post is for engineering leaders who own inference cost and serving latency, for practitioners running open-weight models on-premises or in sovereign environments, and for data scientists who experiment with new architectures while worrying about deployment speed. In July 2026, Hugging Face’s Clement Delangue shared a big turning point for open-source inference: starting with vLLM v0.25.0, Transformers models can run inside vLLM at <strong>native speed</strong>, often matching or beating hand-written implementations.</p>

<p>The core idea is this. Once a model author implements an architecture in Transformers, they can enjoy vLLM’s optimized inference stack for free, with no separate porting work. We did not take this claim on faith. We reproduced the graph-analysis step the backend runs internally on a small decoder block and measured it. This post walks through the mechanism, our measurements, and what it means for infrastructure that serves many different models under one multi-tenant roof.</p>

<h2 id="what-this-technology-is">What This Technology Is</h2>

<p>With a single <code class="language-plaintext highlighter-rouge">--model-impl transformers</code> flag, vLLM loads the model definition straight from the Transformers library instead of a dedicated ported implementation, and serves it. On the surface this looks like a compatibility layer, but what makes the v0.25.0 backend special is that this compatibility no longer costs speed. The old compatibility path was closer to a “works but slow” fallback. Now inference-specific layer fusions are applied dynamically at runtime, so for compatible architectures the backend matches the speed of dedicated code.</p>

<p>Look a little closer and the mechanism splits into two stages. First the backend uses <code class="language-plaintext highlighter-rouge">torch.fx</code> to statically analyze the model’s compute graph, searching for optimizable patterns like attention-score computation, RMSNorm, SwiGLU MLPs, and Mixture-of-Experts. Then it manipulates the abstract syntax tree to rewrite that source in place and maps the discovered operations onto vLLM’s optimized kernels. For an MoE model that means the Expert Parallelization kernels; for attention, the paged-attention family. In the end, vLLM optimizes throughput and latency on top of the architecture that Transformers expressed.</p>

<pre><code class="language-mermaid">flowchart TB
    A[New model architecture] --&gt; B[Implemented once in Transformers&lt;br/&gt;for training and research]
    B --&gt; C{How to serve in vLLM}
    C --&gt;|Before| D[Reimplement in vLLM&lt;br/&gt;hand-port dedicated kernels]
    C --&gt;|Now: model-impl transformers| E[torch.fx static graph analysis]
    E --&gt; F[Detect known patterns&lt;br/&gt;attention, RMSNorm, SwiGLU, MoE]
    F --&gt; G[Rewrite source via ast&lt;br/&gt;runtime layer fusion]
    G --&gt; H[Map to vLLM optimized kernels&lt;br/&gt;EP and paged attention]
    H --&gt; I[Native-speed inference&lt;br/&gt;4B to 235B, match or beat]
    D --&gt; I
</code></pre>

<p>The practical meaning of this shift is that the lag between the serving engine and the model ecosystem disappears. Previously every new architecture required two codebases, a training implementation and an inference implementation, and the gap between them was exactly the “great model is out but we cannot serve it fast yet” window. Now that window narrows. Whether you are a research team experimenting with a custom architecture or an operations team trying to put a freshly released model into production, one Transformers implementation gives you vLLM speed.</p>

<h2 id="installation-and-integration">Installation and Integration</h2>

<p>This backend is not a separate package; it ships inside vLLM itself. Install vLLM v0.25.0 or later and add <code class="language-plaintext highlighter-rouge">--model-impl transformers</code> to your serving command. The real examples Hugging Face published are as follows.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Single GPU, dense model</span>
vllm serve Qwen/Qwen3-4B <span class="nt">--model-impl</span> transformers

<span class="c"># Tensor parallel across 2 GPUs, large dense model</span>
vllm serve Qwen/Qwen3-32B <span class="se">\</span>
  <span class="nt">--model-impl</span> transformers <span class="se">\</span>
  <span class="nt">--tensor-parallel-size</span> 2

<span class="c"># Data parallel plus expert parallel, MoE model</span>
vllm serve Qwen/Qwen3-235B-A22B-FP8 <span class="se">\</span>
  <span class="nt">--model-impl</span> transformers <span class="se">\</span>
  <span class="nt">--data-parallel-size</span> 8 <span class="se">\</span>
  <span class="nt">--enable-expert-parallel</span>
</code></pre></div></div>

<p>The same works from the Python API for offline inference.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">vllm</span> <span class="kn">import</span> <span class="n">LLM</span><span class="p">,</span> <span class="n">SamplingParams</span>

<span class="n">llm</span> <span class="o">=</span> <span class="nc">LLM</span><span class="p">(</span>
    <span class="n">model</span><span class="o">=</span><span class="sh">"</span><span class="s">Qwen/Qwen3-4B</span><span class="sh">"</span><span class="p">,</span>
    <span class="n">model_impl</span><span class="o">=</span><span class="sh">"</span><span class="s">transformers</span><span class="sh">"</span><span class="p">,</span>   <span class="c1"># use the Transformers definition, not a dedicated port
</span><span class="p">)</span>
<span class="n">out</span> <span class="o">=</span> <span class="n">llm</span><span class="p">.</span><span class="nf">generate</span><span class="p">(</span>
    <span class="p">[</span><span class="sh">"</span><span class="s">How does ThakiCloud serve open-weight models?</span><span class="sh">"</span><span class="p">],</span>
    <span class="nc">SamplingParams</span><span class="p">(</span><span class="n">max_tokens</span><span class="o">=</span><span class="mi">256</span><span class="p">,</span> <span class="n">temperature</span><span class="o">=</span><span class="mf">0.7</span><span class="p">),</span>
<span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="n">out</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">outputs</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">text</span><span class="p">)</span>
</code></pre></div></div>

<p>What stands out across the three examples is that distributed serving options like tensor parallel, data parallel, and expert parallel all still work under the Transformers backend. In other words, you do not give up scale-out in exchange for compatibility. From a dense 4B model to a 235B MoE, one flag covers it.</p>

<h2 id="real-experiment-results">Real Experiment Results</h2>

<p>This environment is macOS (Apple Silicon), so it cannot run vLLM’s CUDA kernels, and we could not reproduce the vLLM throughput benchmark itself. Instead we reproduced the <strong>single most important step the backend performs internally: using torch.fx to statically analyze the model graph and find fusion-target patterns</strong>. We built a 4-layer Llama-style decoder in pure PyTorch with the same structure real serving models use (grouped-query attention and a SwiGLU MLP), traced its graph with <code class="language-plaintext highlighter-rouge">torch.fx.symbolic_trace</code>, and classified the nodes.</p>

<p>The measurements were as follows. Tracing this small decoder of 2.902M parameters produced a torch.fx graph with a total of <strong>178 nodes</strong>. By op type there were 80 function calls, 60 method calls, 28 module calls, and 8 attribute lookups. Among these, the function-level patterns the backend can immediately swap for fusion kernels were 16 RMSNorm reductions, 8 attention-related matmuls, 4 softmaxes, and 4 SwiGLU activations, for 32 in total, plus 28 module calls carrying the QKV/output/MLP projections and normalizations. Forward latency at sequence length 64 averaged 1.4ms, measured on torch 2.13.0.</p>

<p><img src="/assets/images/vllm-transformers-native-speed-results.png" alt="Bar chart showing the distribution of fusion-target nodes in the torch.fx graph" /></p>

<p>What these numbers show is clear. Even in a single small block of 178 nodes, well-formed patterns of attention, normalization, and MLP activation recur, and these are exactly the points the backend targets to replace with vLLM kernels. In a real model with dozens of layers this pattern multiplies by the layer count, so a single graph analysis lets the backend fuse the bottleneck operations across the whole model at once. According to Hugging Face, this approach let the Transformers backend match or beat native vLLM throughput from 4B to 235B, including tensor-parallel and MoE setups. Our experiment did not reproduce those throughput figures; it confirmed by measurement the <strong>skeleton of the mechanism</strong> that produces them.</p>

<h2 id="implications-for-thakicloud">Implications for ThakiCloud</h2>

<p>ThakiCloud’s <strong>ai-platform</strong> is multi-tenant AI/ML infrastructure that serves models to diverse customer environments on top of K8s and Kueue-based GPU scheduling. This backend is a direct benefit for a serving operator like us. First, <strong>model onboarding lead time shrinks.</strong> When a new open-weight model ships, until now we had to wait for vLLM to officially support that architecture or accept a self-port. If a Transformers implementation exists, <code class="language-plaintext highlighter-rouge">--model-impl transformers</code> lets us bring up an optimized-speed serving pod right away. That directly affects the competitive question of how fast a new model reaches production.</p>

<p>Second, <strong>the serving path for custom architectures gets simpler.</strong> When we serve a model fine-tuned or structurally modified for a specific customer on-premises, being able to deploy from the Transformers definition alone, with no dedicated vLLM port, greatly reduces maintenance burden. In sovereign-cloud or regulated environments that require self-hosting, we save the time spent reconciling engine and model versions. Since tensor, data, and expert parallel all still work, we can adopt this path without changing the multi-GPU serving topologies we already run.</p>

<p>From an agent perspective, the <strong>Paxis</strong> lens applies too. Paxis is the Agent-Native Cloud control plane that runs on top of ai-platform, swapping different models like tools as it executes agents. If the serving layer can bring up new open-weight models faster and cheaper, the pool of models the agents on top can choose from widens and the cost of switching drops. Because low-cost, low-latency serving is ultimately what makes agent workloads economical, ai-platform’s serving efficiency and Paxis’s agent flexibility point in the same direction.</p>

<h2 id="limitations-and-counterarguments">Limitations and Counterarguments</h2>

<p>This backend is not a cure-all, and a few clear limits deserve mention to be fair. First, the performance advantage is limited to “compatible architectures.” The model must be statically traceable by torch.fx, and it must match patterns the backend already knows for fusion to apply. A structure with heavy dynamic control flow or novel operations the backend has not seen will fall back to unfused paths for some parts, and the speed advantage shrinks accordingly. Not every Transformers model automatically reaches native speed.</p>

<p>Second, this feature reached maturity in v0.25.0 but is still evolving. For certain quantization combinations, certain attention variants, or rare MoE routing schemes, a dedicated ported implementation may still be more stable or faster. Before going to production it is safer to benchmark actual throughput and accuracy yourself on your target model and target hardware. That is exactly why we did not cite vLLM throughput numbers directly and instead attributed them to the official announcement; the figures vary by environment, so a measurement on the ThakiCloud GPU cluster is planned separately.</p>

<p>Third, a counterargument is possible. When the serving engine and the model library become tightly coupled, changes in Transformers can affect serving stability. In the era of two separate codebases you could pin the inference stack independently, but sharing a backend forces you to rethink version management. Even so, weighed against the cost of implementing every new model twice, we judge that in most serving scenarios the onboarding-speed gain from this coupling is larger.</p>

<h2 id="sources">Sources</h2>

<ul>
  <li><a href="https://huggingface.co/blog/native-speed-vllm-transformers-backend">Native-speed vLLM transformers modeling backend (Hugging Face Blog)</a></li>
  <li><a href="https://daily.dev/posts/vllm-v0-25-0-transformers-backend-now-matches-native-vllm-speed-z8kvnsk7c">vLLM v0.25.0: transformers backend now matches native vLLM speed (daily.dev)</a></li>
  <li><a href="https://blog.vllm.ai/2025/04/11/transformers-backend.html">Transformers modeling backend integration in vLLM (vLLM Blog)</a></li>
  <li><a href="https://x.com/ClementDelangue/status/2076763231788339669">Clement Delangue (@ClementDelangue) on X</a></li>
  <li>Experiment code and logs: <code class="language-plaintext highlighter-rouge">outputs/blog-impl/vllm-transformers-native-speed/</code> (torch.fx graph-analysis reproduction, torch 2.13.0, CPU)</li>
</ul>]]></content><author><name>{&quot;name&quot;=&gt;nil, &quot;avatar&quot;=&gt;nil, &quot;bio&quot;=&gt;nil, &quot;location&quot;=&gt;&quot;Seoul, Korea&quot;, &quot;email&quot;=&gt;&quot;info@thakicloud.co.kr&quot;, &quot;uri&quot;=&gt;nil, &quot;home&quot;=&gt;nil, &quot;links&quot;=&gt;[{&quot;label&quot;=&gt;&quot;Website&quot;, &quot;icon&quot;=&gt;&quot;fas fa-fw fa-link&quot;, &quot;url&quot;=&gt;&quot;https://thakicloud.co.kr&quot;}, {&quot;label&quot;=&gt;&quot;GitHub&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-github&quot;, &quot;url&quot;=&gt;&quot;https://github.com/thakicloud&quot;}]}</name><email>info@thakicloud.co.kr</email></author><category term="llmops" /><category term="vllm" /><category term="transformers" /><category term="inference" /><category term="serving" /><category term="torch-fx" /><category term="llmops" /><category term="self-hosting" /><category term="open-weights" /><category term="paxis" /><summary type="html"><![CDATA[Until now, every new model architecture had to be built twice: once in Transformers for training and research, and again in vLLM for production inference. vLLM v0.25.0's native-speed Transformers backend ends that duplication. It works by using torch.fx to statically analyze the model graph, finding known patterns like attention, normalization, and MLP, then rewiring them onto vLLM's optimized kernels. We reproduced the graph-analysis step the backend actually runs on a 4-layer decoder and measured which of its 178 nodes become fusion targets. Then we look at what this means for ThakiCloud's multi-tenant open-weight serving infrastructure.]]></summary></entry><entry xml:lang="en"><title type="html">If You Want an LLM to Generate Screens From a Design System, Build the Gate Before the Model</title><link href="https://thakicloud.github.io/en/research/tds-ui-generator/" rel="alternate" type="text/html" title="If You Want an LLM to Generate Screens From a Design System, Build the Gate Before the Model" /><published>2026-07-15T00:00:00+09:00</published><updated>2026-07-15T00:00:00+09:00</updated><id>https://thakicloud.github.io/en/research/tds-ui-generator</id><content type="html" xml:base="https://thakicloud.github.io/en/research/tds-ui-generator/"><![CDATA[<p>This is a field report from our platform team on building a model that automatically generates
desktop console UI screens using the THAKI Design System (<code class="language-plaintext highlighter-rouge">@thaki/tds</code>). It’s written for
frontend and ML engineers who are trying to get an LLM to produce UI. The short version: what
determined the quality of the generated screens wasn’t model size, it was <strong>the gate that
actually compiles and validates what gets generated</strong>.</p>

<p><img src="/assets/images/posts/research/tds-ui-generator/hero.png" alt="Banner showing the TDS UI generator experiment result flipping from 0/40 with fine-tuning to 39/40 with constrained decoding" />
<em>Instead of teaching the grammar through training, we forced only valid outputs through rules.</em></p>

<h2 id="why-we-didnt-generate-code-directly">Why we didn’t generate code directly</h2>

<p>Generating long JSX in one shot from a screenshot or a requirement has a well-known failure
pattern: elements go missing, hierarchy gets twisted, layouts flatten out. We carried over a
principle we’d already learned elsewhere: preserve general-purpose knowledge and train hard
only on the domain-specific part, and applied it to UI. The model never touches pixels or code
directly. It only produces two intermediate representations. First, a design-system-agnostic
UX-IR that expresses “what does this screen do.” Then a TDS-IR that expresses “which TDS
components realize that.” The actual code is owned by a deterministic compiler, not the model.
TDS already implements padding, typography, and interaction behavior, so the model doesn’t need
to relearn style. It only needs to learn which components to use and how to structure them.</p>

<h2 id="what-we-built-first-wasnt-the-model-it-was-the-registry-and-the-gate">What we built first wasn’t the model, it was the registry and the gate</h2>

<p>We analyzed the <code class="language-plaintext highlighter-rouge">tds_ssot</code> repository and auto-extracted the props, slots, and enum values of 61
components, along with which components are allowed in which slots, into a Component Registry.
Rules like “Button’s variant must be one of eight values” or “only certain components are
allowed in FormField’s control slot” all live here. One interesting discovery was that
<code class="language-plaintext highlighter-rouge">@thaki/tds</code> isn’t a mobile system. It’s a desktop console system built around Table, Drawer, and
Modal, which is also why the demo lives under <code class="language-plaintext highlighter-rouge">/desktop</code>. So we mapped UX roles to TDS components
with console patterns in mind.</p>

<p>We made the code, not the model, own the gate. It deterministically checks whether a component
actually exists, whether a prop is a defined value, whether the slot compatibility holds, whether
clickable elements have an action attached, and whether primary buttons are duplicated. A model
self-reporting “I built this well” is not verification. Compiling and passing the schema is.</p>

<h2 id="is-100-samples-enough-data">Is 100 samples enough data</h2>

<p>We started with 100 user request samples. Here’s the honest part: full fine-tuning a 27B model
on 100 examples guarantees overfitting and mode collapse. So instead of treating the 100 as a
27B training set, we used them to prove out the pipeline. We synthesized realistic console screen
patterns with a probabilistic grammar, and only derived training examples from screens that
passed the gate. From a single screen we extracted multiple tasks: text-to-UX-IR, text-to-TDS-IR,
edit-instruction-to-JSON-Patch, recovery from a broken IR, and even preference pairs of matched
good and corrupt outputs. Of 22 seed screens that passed the gate, 20 yielded 100 SFT examples
and 20 preference pairs. We stuck to the principle that what matters isn’t the volume of data but
whether it passed an executable check.</p>

<h2 id="the-single-most-important-number">The single most important number</h2>

<p>The most valuable result we got from this project wasn’t a training curve, it was a comparison of
how discriminating our different metrics were. We took a correct reference IR, deleted one
component, corrupted an enum value on a prop, and measured how well various metrics caught the
damage.</p>

<table>
  <thead>
    <tr>
      <th>Metric</th>
      <th>Normal</th>
      <th>Corrupted</th>
      <th>Change</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>component F1 (similarity)</td>
      <td>1.00</td>
      <td>0.81</td>
      <td>barely moves</td>
    </tr>
    <tr>
      <td>valid-prop rate</td>
      <td>1.00</td>
      <td>0.30</td>
      <td>collapses</td>
    </tr>
    <tr>
      <td>schema-valid rate</td>
      <td>0.93</td>
      <td>0.23</td>
      <td>collapses</td>
    </tr>
    <tr>
      <td>compile-ok</td>
      <td>1.00</td>
      <td>1.00</td>
      <td>no reaction</td>
    </tr>
  </tbody>
</table>

<p>The similarity-based metric was lenient, and compile success didn’t react at all. The compiler
just emits invalid props as-is, so compiling successfully doesn’t mean the quality is good. By
contrast, schema validation and prop validity reacted precisely to the corruption, dropping to
under half. In other words, if you align generation quality to similarity or compile success
alone, you’ll get it almost right, but you won’t catch the wrong outputs. Quality is created by a
gate that closes the loop through compiling, schema, slots, and interaction.</p>

<h2 id="we-plugged-in-training-and-it-honestly-failed">We plugged in training, and it honestly failed</h2>

<p>Everything up to here is a harness story. What follows is actual training. We ran the data engine
to produce 5,924 training examples from 1,185 gate-passing screens, attached LoRA to
Qwen3.6-27B, and trained on our internal H200 cluster. Training itself converged well: loss
dropped to 0.07, and token accuracy hit 96%. Then we served the trained adapter and compared it
against the base model.</p>

<p>The result, honestly, was a failure. A 300-step diagnostic LoRA barely changed the auto-generation
output at all. The error profile before and after training was effectively identical. Both models
attached input attributes directly to FormField, and both added a title to Card, which doesn’t
support one. The real design system wraps an input inside FormField through a nested slot
structure, but both models were imagining a flatter structure.</p>

<p>Digging into the cause turned up three factors. Training was short, and token accuracy saturated
early, so the gradient signal was weak. More importantly, it was a data problem. The realize
function that generated our synthetic data never showed the true nested structure, so the model
had no way to learn a contract it never saw. And the 27B model’s existing habits were strong.</p>

<p>That’s where the second lesson came from. All three proxy metrics missed the real generation
quality. Compile success, teacher-forced token accuracy, and the change in token accuracy after
attaching LoRA all diverged from the gate pass rate. Only an execution gate against the full
registry exposed the real gap the two models shared. Along the way we also discovered our
registry itself was incomplete and had been dropping perfectly valid outputs, so we did a full
extraction of the properties of 30 components and fixed it.</p>

<h2 id="so-we-fixed-the-data-retrained-and-finally-found-the-answer">So we fixed the data, retrained, and finally found the answer</h2>

<p>We rewrote the realize function to produce the actual nested structure. FormField now wraps its
input in a slot, and each component uses its real attributes. That yielded 2,771 screens that
cleanly passed the gate, from which we generated 13,855 training examples. This time we trained
much longer, running 1,500 optimization updates.</p>

<p>Even so, the trained model still failed the gate. Before and after were nearly identical again.
At this point it became clear: for this problem, the 27B model’s flattened habit was not going to
budge with a training budget we could reasonably afford.</p>

<p>So we changed direction. Instead of trying to persuade the model, we forced the generation itself.
We auto-generated a JSON schema from the registry: only real component names, only attributes
that component actually has, and nested structures enforced recursively. We applied this as a
decoding constraint. The result was clear. On the same 40 held-out examples, with no training at
all, the gate pass rate went from 0% to 39 out of 40, or 97.5% (95% CI 86.8% to 99.9%).</p>

<p><img src="/assets/images/posts/research/tds-ui-generator/fig1-reversal.png" alt="Bar chart of gate pass rates across base, fine-tuned, repair, and constrained-decoding methods" />
<em>Four-way comparison: constraint alone, without any training, pushed the gate pass rate to 39/40. Measured (n=40).</em></p>

<p>This three-way comparison is the conclusion of the project. Both the untreated base model and the
fine-tuned model scored 0/40, while the base model with constrained decoding alone passed 39/40.
When a model with strong ingrained habits needs to produce structured output, under these
conditions, constraining decoding with rules like an execution gate was cheaper and more reliable
than trying to fine-tune the habit away.</p>

<p>From here on we have to stay honest. First, it’s 97.5%, not 100%. The one that didn’t pass was
constrained too, but the JSON got cut off mid-generation. Schema constraints don’t fully
guarantee even parseable JSON. Second, this win was a win for validity, not quality. Component
similarity (F1) against the reference screen actually went down slightly under constraint (from
0.317 to 0.292). Being valid and matching the requested intent are different things, and that gap
is the real homework for the next stage. Third, don’t misread why the pass rate is so high. We
initially wrote that this 100% was because the schema mostly subsumes the gate, but when we
actually contrasted the two rule sets against adversarial cases, it was the opposite. The gate
was stricter than the schema. The schema only blocks the two most common errors, nonexistent
components and missing attributes, and let through violations like a missing schemaVersion or
placing the wrong component in a slot. Catching those was the gate’s job. So constraint paid off
because the schema eliminated the dominant failure type, and what remained happened to also
satisfy the gate’s stricter rules. The real by-construction risk is that the schema and the gate
both come from the same registry, and that can only be ruled out by a verifier outside the
registry, such as React rendering and TypeScript type checking.</p>

<h2 id="a-valid-screen-wasnt-the-same-as-a-good-screen">A valid screen wasn’t the same as a good screen</h2>

<p>If we stopped here, the conclusion would be “constraint is the answer,” but that’s only half the
truth. We dug further. We extracted requirement contracts from the held-out reference screens and
measured how well each method actually reproduced the screen’s real content. The result stung.
Constraint had the highest validity, but the lowest reference information and component
recovery. We had bought validity with no training, but content fidelity was lower than even the
untreated base model. Repair, which deterministically patches the base output without any GPU
work, and free-planning-then-constrain both had the same problem. Both traded validity for
content. Being valid and matching the requirement turned out to be different axes.</p>

<h2 id="so-we-measured-where-to-invest-first">So we measured where to invest first</h2>

<p>The next instinct was to make the model bigger or generate several and pick the best. Before that,
we asked a simpler question: if you generate eight times, is there actually a good one in there?
We generated eight constrained candidates per prompt and compared a single sample against the
best candidate: 0.29 versus 0.45. Good screens were already being generated. What we couldn’t do
was pick the good one out of the batch. The bottleneck wasn’t generation, it was selection.</p>

<h2 id="the-selector-needed-to-be-a-requirement-not-a-judge">The selector needed to be a requirement, not a judge</h2>

<p>So we built several selectors that don’t know the ground truth, and measured how much of that
ceiling they actually captured.</p>

<p><img src="/assets/images/posts/research/tds-ui-generator/fig2-verifier.png" alt="Bar chart comparing component F1 across Top-1, structure, judge, requirement, and oracle selectors" />
<em>Among selectors that don’t know the ground truth, the requirement predicate recovered 27% of the headroom, while the LLM judge did worse than not selecting at all. Measured (n=40).</em></p>

<p>Picking the structurally richer candidate barely helped. Picking the candidate that passed the
gate actually made things worse, another confirmation that selecting for validity costs you
content. Asking the base model directly which candidate was best did worse than picking nothing
at all. One thing worked: extracting what the screen needs to contain from the prompt first, then
picking the candidate that best satisfies that requirement. That captured a quarter of the
selection headroom. The selector, it turned out, needed to be a requirement, not a judge.</p>

<p>Looking back at the whole project, four lessons remain. First, the place to invest first isn’t a
bigger model, it’s the scaffolding that actually executes and verifies what gets generated.
Second, that scaffolding has to be accurate, or both failures and successes look wrong. Third,
when strong habits collide with structured output, at least for this problem, constraining was
cheaper than pushing training harder. We’re not generalizing that to every case. Fourth, validity
and fidelity are different axes, the remaining bottleneck is selection rather than generation, and
that selector needs to be requirement-based rather than judge-based. What we need to prove next is
raising the selector and semantic accuracy together using human-written requirement contracts.</p>

<h2 id="references">References</h2>

<p>Here are the external techniques this experiment leaned on.</p>

<ul>
  <li>Theoretical foundation for constrained decoding, the method that ultimately won: Willard, Louf,
<a href="https://arxiv.org/abs/2307.09702"><em>Efficient Guided Generation for Large Language Models</em></a>.
This is the approach of constraining decoding with a schema or grammar so that only valid output
can come out.</li>
  <li>The open-source library that actually implements the above approach:
<a href="https://github.com/dottxt-ai/outlines">Outlines (dottxt-ai/outlines)</a>.</li>
  <li>The parameter-efficient fine-tuning method we tried and that failed for us: Hu et al.,
<a href="https://arxiv.org/abs/2106.09685"><em>LoRA: Low-Rank Adaptation of Large Language Models</em></a>.</li>
  <li>The root of best-of-N sampling and verifier-based selection, picking the good one out of eight
generations: Cobbe et al.,
<a href="https://arxiv.org/abs/2110.14168"><em>Training Verifiers to Solve Math Word Problems</em></a>.</li>
</ul>]]></content><author><name>{&quot;name&quot;=&gt;nil, &quot;avatar&quot;=&gt;nil, &quot;bio&quot;=&gt;nil, &quot;location&quot;=&gt;&quot;Seoul, Korea&quot;, &quot;email&quot;=&gt;&quot;info@thakicloud.co.kr&quot;, &quot;uri&quot;=&gt;nil, &quot;home&quot;=&gt;nil, &quot;links&quot;=&gt;[{&quot;label&quot;=&gt;&quot;Website&quot;, &quot;icon&quot;=&gt;&quot;fas fa-fw fa-link&quot;, &quot;url&quot;=&gt;&quot;https://thakicloud.co.kr&quot;}, {&quot;label&quot;=&gt;&quot;GitHub&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-github&quot;, &quot;url&quot;=&gt;&quot;https://github.com/thakicloud&quot;}]}</name><email>info@thakicloud.co.kr</email></author><category term="research" /><category term="llm" /><category term="constrained-decoding" /><category term="structured-generation" /><category term="ui-generation" /><category term="design-system" /><category term="evaluation" /><category term="verifier" /><summary type="html"><![CDATA[We expected fine-tuning to win. The data said otherwise. Here's how we ended up with a generator that respects TDS without any training, and the next problem we're chasing: a valid screen isn't the same as a good one.]]></summary></entry><entry xml:lang="ko"><title type="html">어려운 작업일수록 목표부터 쓰게 합니다: Codex goal 위임 프롬프팅</title><link href="https://thakicloud.github.io/ko/agentops/codex-goal-delegation/" rel="alternate" type="text/html" title="어려운 작업일수록 목표부터 쓰게 합니다: Codex goal 위임 프롬프팅" /><published>2026-07-15T00:00:00+09:00</published><updated>2026-07-15T00:00:00+09:00</updated><id>https://thakicloud.github.io/ko/agentops/codex-goal-delegation</id><content type="html" xml:base="https://thakicloud.github.io/ko/agentops/codex-goal-delegation/"><![CDATA[<h2 id="개요">개요</h2>

<p>최근 코딩 에이전트를 쓰는 개발자 사이에서 짧은 팁 하나가 오갔습니다. Codex에 정말 어려운 <code class="language-plaintext highlighter-rouge">/goal</code>을 줄 때, 곧바로 작업을 시키지 말고 먼저 “다른 스레드가 이 목표를 달성할 수 있도록, 그 목표를 대신 써달라”고 요청하라는 것입니다. 한 번 읽으면 말장난처럼 들립니다. 목표를 달성하라고 시키는 대신 목표를 쓰라고 시키는 것이 무슨 차이를 만드느냐는 의문이 자연스럽습니다.</p>

<p>그런데 이 팁은 에이전트를 오래 굴려본 사람이라면 몸으로 아는 한 가지 사실을 정확히 건드립니다. 어려운 작업이 실패하는 이유는 대개 모델이 약해서가 아니라, 목표가 기계가 판정할 수 있는 형태로 적혀 있지 않아서입니다. 사람은 “이 리팩터를 깔끔하게 끝내줘” 같은 문장을 목표라고 생각하지만, 에이전트에게 이 문장은 언제 멈춰야 할지, 무엇을 성공으로 볼지, 어디까지가 범위인지가 전부 비어 있는 지시입니다. 그래서 이 글은 “목표를 대신 쓰게 한다”는 기법을 하나씩 뜯어보고, ThakiCloud가 쿠버네티스 기반 AI/ML 플랫폼과 에이전트 플랫폼을 운영하면서 이미 같은 원리를 어떻게 코드로 강제하고 있는지 짚겠습니다.</p>

<p><img src="/assets/images/codex-goal-delegation-hero.png" alt="Codex 목표 위임 프롬프팅 개념 이미지" /></p>

<h2 id="codex-goal은-무엇인가">Codex goal은 무엇인가</h2>

<p>먼저 재료가 되는 기능을 정확히 봐야 합니다. Codex의 <code class="language-plaintext highlighter-rouge">/goal</code>은 스레드에 지속적인 목표를 붙이는 기능입니다. OpenAI가 공개한 쿠킹북 문서 “Using Goals in Codex”에 따르면, 하나의 목표는 세 가지로 기술되어야 합니다. 측정 가능한 결과, 진행을 확인할 수 있는 검증 표면, 그리고 제약입니다. 이 세 가지가 갖춰지면 목표는 스레드에 붙은 지속적 표적이 됩니다.</p>

<p>동작 방식이 중요합니다. 한 번의 턴이 끝날 때마다 Codex는 현재까지의 증거를 살펴보고 목표가 충족됐는지를 스스로 판정합니다. 아직 아니라면, 그리고 목표가 여전히 활성 상태이고 예산 안에 있다면, 가장 최근 상태에서 이어서 계속 진행합니다. 요약하면 단발 응답이 아니라, 목표라는 종료 조건이 만족될 때까지 관찰과 판정을 반복하는 구조입니다. 오래 걸리는 작업을 “걸어두고 잊는” 워크플로로 바꿀 수 있다는 점이 이 기능의 매력입니다.</p>

<p>여기서 핵심은 목표의 품질이 전부를 결정한다는 사실입니다. 검증 표면이 흐릿하면 Codex는 언제 멈춰야 할지 판단하지 못하고, 제약이 없으면 범위를 벗어나 엉뚱한 파일까지 손을 댑니다. 측정 가능한 결과가 없으면 첫 파일 하나를 고치고는 다 됐다고 종료해 버립니다. 즉 좋은 목표를 쓰는 일 자체가 별도의 기술이고, 이 기술이 부족할 때 어려운 작업이 무너집니다.</p>

<pre><code class="language-mermaid">flowchart TB
    A[어려운 작업 아이디어] --&gt; B{목표가 기계 판정&lt;br/&gt;가능한 형태인가}
    B --&gt;|아니오| C[헛도는 반복&lt;br/&gt;또는 조기 종료]
    B --&gt;|예| D[측정 가능한 결과]
    B --&gt;|예| E[검증 표면]
    B --&gt;|예| F[제약]
    D --&gt; G[스레드에 붙은&lt;br/&gt;지속적 목표]
    E --&gt; G
    F --&gt; G
    G --&gt; H[턴 종료마다&lt;br/&gt;증거로 자기 판정]
    H --&gt;|미충족·예산 내| G
    H --&gt;|충족| I[수렴 종료]
</code></pre>

<h2 id="다른-스레드를-위한-목표를-쓰게-한다는-기법">“다른 스레드를 위한 목표를 쓰게 한다”는 기법</h2>

<p>이제 팁으로 돌아갑니다. 어려운 작업을 앞에 두고, 사람이 곧바로 목표를 잘 쓰기는 어렵습니다. 측정 가능한 결과가 무엇인지, 무엇으로 진행을 검증할지, 어떤 제약을 걸어야 할지를 사람이 처음부터 완벽하게 채우려면 그 자체로 작지 않은 설계 작업입니다. 이 팁이 제안하는 것은 그 설계를 모델에게 먼저 위임하라는 것입니다.</p>

<p>구체적으로는 이렇게 흐릅니다. 첫 번째 스레드에는 “이 어려운 작업을, 다른 스레드가 자율적으로 달성할 수 있도록 하는 목표를 작성하라”고 지시합니다. 이때 모델은 작업을 직접 하지 않습니다. 대신 작업을 이해하고, 무엇이 성공인지, 어떻게 검증할지, 어디까지가 범위인지를 명시한 목표 명세를 산출합니다. 사람은 그 명세를 검토하고 다듬은 뒤, 새 스레드에 목표로 넣어 실제 실행을 맡깁니다. 실행 스레드는 잘 정의된 종료 조건을 갖고 출발하므로, 앞에서 말한 헛도는 반복이나 조기 종료에 훨씬 덜 빠집니다.</p>

<p>이 기법이 효과적인 이유는 두 가지입니다. 첫째, 목표를 쓰는 일과 목표를 달성하는 일을 분리합니다. 두 작업은 성격이 다릅니다. 목표 작성은 문제를 넓게 이해하고 성공 기준을 언어로 고정하는 일이고, 목표 달성은 그 기준을 향해 좁게 파고드는 일입니다. 한 스레드가 둘을 동시에 하려 하면 검증 기준을 정하는 도중에 성급하게 구현으로 넘어가고, 결국 자기가 세우지도 않은 기준으로 자기를 채점하는 모순에 빠집니다. 분리하면 각 스레드가 한 가지에 집중합니다.</p>

<p>둘째, 사람에게 검토 지점을 만들어 줍니다. 모델이 산출한 목표 명세는 실행 전에 사람이 읽고 고칠 수 있는 물건입니다. 검증 표면이 약하면 이 단계에서 보강할 수 있고, 범위가 넓으면 제약을 더 걸 수 있습니다. 실행이 시작되고 나서 잘못을 발견하면 비용이 크지만, 목표 명세 단계에서 잡으면 저렴합니다. 즉 이 기법은 단순한 프롬프트 재주가 아니라, 값싼 검토 지점을 한 겹 끼워 넣는 구조적 장치입니다.</p>

<p>물론 이것은 만능이 아닙니다. 한 개발자 뉴스레터는 이 방식이 “네 시간짜리 작업을 걸어두고 잊는 워크플로로 바꾼다”고 표현했는데, 이는 잘 맞은 사례에 대한 인상이지 보장이 아닙니다. 목표를 잘 쓰게 하는 데 성공하더라도, 실행 스레드가 그 목표를 향해 제대로 수렴하는지는 별개의 문제입니다. 그래서 이 기법은 뒤에서 이야기할 검증 게이트와 함께 쓰일 때 비로소 값을 합니다.</p>

<h2 id="thakicloud-제품-적용-시사점">ThakiCloud 제품 적용 시사점</h2>

<p>이 기법이 낯설지 않은 이유가 있습니다. ThakiCloud는 이미 같은 원리를 프롬프트 부탁이 아니라 코드 규율로 강제하고 있기 때문입니다. 주제가 에이전트 운용인 만큼 여기서는 우리의 에이전트 플랫폼 Paxis 관점을 중심에 두되, 그 아래 인프라인 ai-platform과의 연결도 함께 봅니다.</p>

<p>Paxis는 ThakiCloud의 Agent-Native Cloud로, 스킬과 도구와 정책과 감사 로그를 일급 리소스로 다루는 제어 평면입니다. 그 안에 Goal Mode라는 실행기가 있습니다. Goal Mode에서 목표를 만들 때 우리는 <code class="language-plaintext highlighter-rouge">check_cmd</code>와 <code class="language-plaintext highlighter-rouge">success_criteria</code>, 그리고 예산을 비워 두지 않도록 규칙으로 못 박아 두었습니다. 이 세 가지는 Codex 목표의 세 요소와 거의 일대일로 대응합니다. <code class="language-plaintext highlighter-rouge">success_criteria</code>는 측정 가능한 결과이고, <code class="language-plaintext highlighter-rouge">check_cmd</code>는 진행을 판정하는 검증 표면이며, 예산은 제약입니다. 목표가 빈 껍데기로 만들어지면 첫 반복에서 게이트가 실패하도록 설계해 두었기 때문에, “목표를 잘 쓰지 않으면 시작조차 되지 않는” 상태를 코드가 보장합니다.</p>

<p>“다른 스레드를 위한 목표를 쓰게 한다”는 위임 구조도 우리 안에 있습니다. 복잡한 요청이 들어오면 메인 에이전트가 그것을 하위 작업으로 분해하고, 각 하위 작업을 별도의 서브에이전트에 위임합니다. 이때 분해하는 주체와 실행하는 주체가 분리되는데, 이는 이 글의 기법이 목표 작성 스레드와 목표 실행 스레드를 나누는 것과 정확히 같은 발상입니다. 분해는 판단이 필요하므로 상위 모델이 맡고, 실행은 좁은 작업이므로 더 저렴한 모델에 내려보냅니다. 워커는 싸게, 게이트는 비싸게라는 원칙이 여기서 나옵니다.</p>

<p>무엇보다 우리는 팬아웃한 결과를 검증 없이 합치지 않습니다. 목표를 아무리 잘 써서 위임하더라도, 실행 결과가 옳은지는 실행 주체가 아니라 별도의 검증 단계가 판정해야 합니다. 코드 산출물은 테스트를 실제로 돌려 종료 코드로 판정하고, 콘텐츠나 판단 산출물은 서로 다른 시각의 검증기를 여러 개 띄워 다수결로 걸러냅니다. 모델이 “다 된 것 같습니다”라고 스스로 보고하는 문장은 루프의 종료 조건이 될 수 없습니다. 이 규율은 Codex goal의 “턴 종료마다 증거로 자기 판정한다”는 동작을 우리가 어떻게 신뢰 가능한 형태로 굳혔는지를 보여 줍니다.</p>

<p>인프라 렌즈에서도 연결이 있습니다. 이렇게 목표를 잘게 나누어 검증하며 돌리는 루프는 계산 자원을 꾸준히 소모합니다. ai-platform은 쿠버네티스와 Kueue 기반 GPU 스케줄링, vLLM 서빙, 멀티테넌트 격리를 제공하는 계층으로, 이런 에이전트 루프가 값싸고 안정적으로 돌 수 있는 바닥을 만듭니다. 저비용 서빙이 에이전트 경제성을 만들고, 그 위에서 Paxis의 목표 위임과 검증 루프가 실질적으로 성립합니다. 두 렌즈가 서로를 보완하는 구조입니다.</p>

<h2 id="한계-및-반론">한계 및 반론</h2>

<p>이 기법을 과대평가하지 않기 위해 반대편도 짚겠습니다.</p>

<p>첫째, 목표를 쓰게 하는 단계 자체가 실패할 수 있습니다. 모델이 그럴듯하지만 검증 불가능한 목표를 산출하면, 실행 스레드는 여전히 무엇을 성공으로 볼지 모른 채 출발합니다. 오히려 사람이 직접 짧고 단단한 목표를 쓰는 편이 나은 경우가 많습니다. 그래서 모델이 쓴 목표 명세는 반드시 사람이 검토하는 지점이 있어야 하고, 검토 없이 곧바로 실행에 넘기는 것은 값싼 검토 지점을 스스로 버리는 셈입니다.</p>

<p>둘째, 모든 작업에 이 오버헤드가 정당한 것은 아닙니다. 한 파일을 고치는 단순 수정이나 즉답형 질문에까지 목표를 대신 쓰게 하고 스레드를 나누는 것은 과잉입니다. 이 기법은 종료 조건이 흐릿하고 오래 걸리며 자율 실행이 가치가 있는 어려운 작업에서만 값을 합니다. 우리 내부 규칙도 반복 구현이나 수렴형 작업에만 루프 도구를 쓰고, 단발 편집에는 억지로 적용하지 않도록 선을 그어 두었습니다.</p>

<p>셋째, 자율 실행이 길어질수록 사람이 결과를 신뢰하고 검토를 멈추는 경향이 생깁니다. 목표를 잘 위임했다는 안도감이 오히려 위험합니다. 검증기가 아무것도 걸러내지 못한다면 그것은 전부 통과라는 신호가 아니라 검증기가 고장 났다는 신호일 가능성이 큽니다. 그래서 핵심 산출물은 주기적으로 사람이 표본을 뽑아 직접 확인해야 하고, 검증기는 통과가 아니라 반증을 지향하도록 설계해야 합니다.</p>

<p>정리하면, “어려운 작업일수록 목표부터 쓰게 하라”는 팁은 프롬프트 요령이 아니라 목표 작성과 목표 실행을 분리하고 그 사이에 검토 지점을 끼우는 구조적 조언입니다. Codex의 goal 기능이 이를 개인 개발자 손에 쥐여 주었다면, ThakiCloud는 같은 원리를 Paxis의 Goal Mode와 검증 루프로 팀 단위에서 강제합니다. 목표를 잘 쓰는 일이 곧 에이전트를 잘 굴리는 일이라는 사실은, 도구가 무엇이든 변하지 않습니다.</p>

<h2 id="출처">출처</h2>

<ul>
  <li>OpenAI Cookbook, “Using Goals in Codex” (developers.openai.com/cookbook/examples/codex/using_goals_in_codex)</li>
  <li>원 트윗: nickbaumann_ (x.com/hjguyhan/status/2077331299648635303 재게시)</li>
</ul>]]></content><author><name>{&quot;name&quot;=&gt;nil, &quot;avatar&quot;=&gt;nil, &quot;bio&quot;=&gt;nil, &quot;location&quot;=&gt;&quot;Seoul, Korea&quot;, &quot;email&quot;=&gt;&quot;info@thakicloud.co.kr&quot;, &quot;uri&quot;=&gt;nil, &quot;home&quot;=&gt;nil, &quot;links&quot;=&gt;[{&quot;label&quot;=&gt;&quot;Website&quot;, &quot;icon&quot;=&gt;&quot;fas fa-fw fa-link&quot;, &quot;url&quot;=&gt;&quot;https://thakicloud.co.kr&quot;}, {&quot;label&quot;=&gt;&quot;GitHub&quot;, &quot;icon&quot;=&gt;&quot;fab fa-fw fa-github&quot;, &quot;url&quot;=&gt;&quot;https://github.com/thakicloud&quot;}]}</name><email>info@thakicloud.co.kr</email></author><category term="agentops" /><category term="ai-coding" /><category term="agentic" /><category term="codex" /><category term="goal-mode" /><category term="agentops" /><category term="verification" /><summary type="html"><![CDATA[한 개발자가 Codex에 어려운 /goal을 줄 때 '다른 스레드가 이 목표를 달성하도록 목표를 대신 써달라'고 먼저 요청한다는 팁을 공유했습니다. 얼핏 말장난처럼 들리지만, 그 안에는 검증 가능한 목표 명세를 모델에게 먼저 작성시키고 그 명세를 새 스레드에 위임한다는 실질적인 에이전트 운용 패턴이 들어 있습니다. Codex goal의 실제 동작을 확인하고, ThakiCloud가 운용하는 Goal Mode와 pge-loop, Paxis 관점에서 이 기법을 짚습니다.]]></summary></entry></feed>