← همه‌ی بوک‌لت‌ها
بوک‌لت · ۱۳ خرداد ۱۴۰۵ · ۱۹ دقیقه خواندن · برگرفته از: یادداشتی از @zodchiii بازنویسی و توسعه: آزمایشگاه هوش مصنوعی Raderon سطح: متوسط تا پیشرفته
جزوهٔ آموزشی · مهندسی عامل‌های هوش مصنوعی

خط لولهٔ چهار-عاملی

چگونه تیمی از عامل‌های هوش مصنوعی بسازیم که شب‌هنگام و بدون حضور شما، یک قابلیت نرم‌افزاری را از ایده تا بازبینی نهایی تحویل دهد؟

برگرفته از: یادداشتی از @zodchiii بازنویسی و توسعه: آزمایشگاه هوش مصنوعی Raderon سطح: متوسط تا پیشرفته

۱.چرا یک «خط لوله» بهتر از یک «انبوه عامل» است

آنچه یک مشت عاملِ پراکنده را از یک تیم واقعی جدا می‌کند، تنها یک چیز است: تحویل (handoff). همین‌که هر عامل خروجی‌اش را جایی بنویسد که عامل بعدی بتواند بخواند، زنجیره‌ای شکل می‌گیرد که هر حلقه‌اش بر حلقهٔ پیش از خود سوار می‌شود؛ نه آنکه هر بار از صفر آغاز کند.

بیشتر مردم عامل‌های هوش مصنوعی را «تک‌تیرانداز» به کار می‌گیرند: اینجا یکی را برای بازبینی کد صدا می‌زنند، آنجا یکی دیگر را برای ساختن تست؛ همه دستی، یکی پس از دیگری، و هیچ‌کدام خبر ندارد عاملِ پیشین چه کرده است. حاصلش این است که خودِ شما به گلوگاه تبدیل می‌شوید، چون باید پیوسته خروجی یکی را بردارید و به دست دیگری بسپارید.

چاره، یک خط لولهٔ چهارمرحله‌ای است که حلقه‌هایش خودبه‌خود به هم می‌پیوندند:

مرحلهٔ ۱
برنامه‌ریز
Opus
spec.md
مرحلهٔ ۲
کدنویس
Sonnet
changes.md
مرحلهٔ ۳
آزمونگر
Sonnet
test-results.md
مرحلهٔ ۴
بازبین
Opus
review.md

یک ماشهٔ واحد، چهار مرحله، و یک قابلیتِ کامل تا صبح. شب پیش از خواب فرمان را می‌زنید و صبح، کنار قهوه، فقط «حکم نهایی» را می‌خوانید.


۲.مشکل ریشه‌ای: آلودگی پنجرهٔ زمینه

هر مدل زبانی پنجرهٔ زمینه (Context Window) دارد؛ یعنی یک حافظهٔ کاریِ محدود که تمام ورودی‌ها و خروجی‌های گفت‌وگوی جاری در آن جا می‌گیرند. این حافظه نه بی‌پایان است و نه رایگان.

حالا تصور کنید یک عامل به‌تنهایی بخواهد همه‌کاره باشد. پنجره‌اش کم‌کم از انبوهی داده‌های درهم پر می‌شود: یادداشت‌های برنامه‌ریزی، تکه‌کدهای میانی، خروجی ابزارها، نتایج تست، حاشیه‌های بازبینی، و حتی بن‌بست‌هایی که به جایی نرسیدند. هرچه این انباشت سنگین‌تر شود:

  • مدل تصمیم‌هایی را که یک ساعت پیش گرفته بود از یاد می‌برد.
  • پیشنهادهای کدش کم‌کم از الگوهای جاافتادهٔ پروژه فاصله می‌گیرند (drift).
  • هر توکن اضافه در تاریخچه، هم بر پاسخ بعدی هزینه می‌گذارد و هم جا را برای فایلی که واقعاً به آن نیاز دارید تنگ می‌کند.
  • و کیفیت خروجی، آرام و بی‌صدا، افت می‌کند.
💡 ایدهٔ محوری

چاره، «از نو آغازکردن» نیست؛ چون با هر بار شروعِ دوباره، همهٔ درکِ انباشته را از دست می‌دهید. چاره این است که کار را میان چهار متخصص تقسیم کنید، که هر یک در پنجره‌ای تمیز، باریک و متمرکز کار می‌کند. هیچ‌کدام لازم نیست کل تصویر را در ذهن نگه دارد؛ هر کدام فقط آن‌قدر می‌داند که مرحلهٔ خودش می‌طلبد.

در Claude Code، این متخصص‌ها قالبی به نام زیرعامل (Subagent) دارند: نسخه‌ای تخصصی از Claude که در پنجرهٔ زمینهٔ مستقلِ خودش، با یک پرامپتِ سیستمیِ سفارشی و فهرستی محدود از ابزارها اجرا می‌شود. عاملِ اصلی (والد) کار را به زیرعامل می‌سپارد، زیرعامل آن را در انزوا انجام می‌دهد و در پایان فقط خلاصه را به والد بازمی‌گرداند.


۳.ایدهٔ کلیدی: تخصص‌گرایی + فایل تحویل

قلب این الگو، فایل تحویل (handoff file) است: هر عامل خروجی‌اش را جایی می‌نویسد که عامل بعدی بتواند آن را بردارد. یک پوشهٔ مشترک — مثلاً .pipeline/ — نقشِ «میز کارِ مشترک» را بازی می‌کند:

عاملمی‌خوانَد ازمی‌نویسد در
برنامه‌ریزکدِ پروژه.pipeline/spec.md
کدنویسspec.md.pipeline/changes.md
آزمونگرchanges.md + spec.md.pipeline/test-results.md
بازبینهمهٔ فایل‌های بالا + git diff.pipeline/review.md

کل ماجرا همین است: چهار زیرعامل، یک فرمان، و یک پوشهٔ مشترک برای تحویل‌ها. آن هماهنگ‌کننده‌ای هم که این چهار عامل را پشت‌سرِ هم به‌کار می‌اندازد، خودش چیزی نیست جز یک «فرمان اسلش (slash command)».

📌 چرا فایل، نه حافظهٔ مشترک؟

فایل‌های تحویل سه برتری دارند: ۱) شفافیت — دقیقاً می‌بینید هر مرحله چه تصمیمی گرفته است؛ ۲) امکان بازرسی — می‌توانید پیش از ادامه، خروجی هر مرحله را خودتان اصلاح کنید؛ ۳) ایزولاسیون — هیچ عاملی مجبور نیست کل تاریخچهٔ عاملِ پیشین را در پنجره‌اش نگه دارد و تنها همان خلاصهٔ ساختاریافته را می‌خواند.


۴.نقشهٔ کلی معماری

پیش از آنکه به جزئیات هر عامل بپردازیم، بد نیست ساختار فایل‌ها را یک‌جا ببینیم. در Claude Code، هر زیرعامل یک فایل Markdown است که در ابتدای آن یک «فرامتر YAML» قرار دارد و بدنهٔ فایل، پرامپتِ سیستمیِ همان عامل را می‌سازد:

project-root/
.claude/
├── agents/
│   ├── planner.md      # عامل ۱  (model: opus)
│   ├── coder.md        # عامل ۲  (model: sonnet)
│   ├── tester.md       # عامل ۳  (model: sonnet)
│   └── reviewer.md     # عامل ۴  (model: opus)
└── commands/
    └── ship.md         # هماهنگ‌کننده: فرمان ‎/ship‎

.pipeline/              # میز کار مشترک (فایل‌های تحویل)
├── spec.md
├── changes.md
├── test-results.md
└── review.md
💡 انتخاب مدل بر اساس نقش

مدلِ هر عامل را با جنسِ کارش هماهنگ می‌کنیم. مرحله‌هایی که «سقفِ کیفیت» را تعیین می‌کنند — یعنی برنامه‌ریزی و بازبینی — روی مدلِ قوی‌تر (Opus) اجرا می‌شوند، و مرحله‌های اجرایی که در برابر یک مشخصاتِ روشن انجام می‌گیرند — یعنی کدنویسی و تست — روی مدلِ متعادل‌تر و ارزان‌تر (Sonnet). همین تطبیقِ ساده، هم کیفیت را نگه می‌دارد و هم هزینه را پایین.


۵.عامل ۱ — برنامه‌ریز (Planner)

برنامه‌ریز هرگز کد نمی‌نویسد. کارش این است که یک درخواستِ مبهمِ قابلیت را به مشخصاتی روشن و دقیق بدل کند؛ مشخصاتی که کدنویس بتواند بی هیچ حدسی دنبالش کند.

فایل .claude/agents/planner.md را بسازید:

.claude/agents/planner.md
---
name: planner
description: Turns a feature request into an implementation spec. Use as the first stage of the feature pipeline.
tools: Read, Grep, Glob, Write
model: opus
---

You are a planning specialist. You do NOT write implementation code.

Given a feature request:
1. Read the relevant parts of the codebase to understand current patterns.
2. Write a spec to `.pipeline/spec.md` containing:
   - Files to create or modify, with exact paths
   - The interface or function signatures needed
   - Edge cases the implementation must handle
   - Which existing patterns to follow (name the file to copy from)
3. Flag anything ambiguous as an OPEN QUESTION at the top of the spec.

Keep the spec tight. The Coder reads this and nothing else, so leave
no gaps and invent no requirements that weren't asked for.

چرا روی Opus اجرا می‌شود؟

چون این مرحله، سقفِ کیفیتِ هر چه پس از آن می‌آید را تعیین می‌کند. مشخصاتِ مبهم، هر چقدر هم کدنویس قوی باشد، کدِ مبهم می‌سازد. پس سرمایه‌گذاریِ کیفیت در همین نقطه، بیش از هر جای دیگری بازده دارد.

⚠️ نکتهٔ طلایی: OPEN QUESTIONS

اگر برنامه‌ریز به ابهامی برخورد، به‌جای حدس‌زدن آن را به‌صورت «پرسشِ باز» در بالای مشخصات علامت می‌زند. این یک دروازهٔ کنترلی است: تا وقتی مشخصات پرسشِ بازی دارد، خط لوله می‌ایستد و منتظر تصمیم شما می‌ماند — به‌جای آنکه ساعت‌ها روی فرضی نادرست کد بزند.


۶.عامل ۲ — کدنویس (Coder)

کدنویس مشخصات را می‌خواند و پیاده‌سازی را می‌نویسد. نه برنامه‌ریزی می‌کند و نه کارِ خودش را بازبینی؛ فقط همان چیزی را می‌سازد که مشخصات می‌گوید.

فایل .claude/agents/coder.md را بسازید:

.claude/agents/coder.md
---
name: coder
description: Implements the spec at .pipeline/spec.md. Use as the second stage of the feature pipeline, after the planner.
tools: Read, Write, Edit, Grep, Glob, Bash
model: sonnet
---

You are an implementation specialist.

1. Read `.pipeline/spec.md` in full. If it has OPEN QUESTIONS, stop and
   surface them instead of guessing.
2. Implement exactly what the spec describes. Follow the patterns it
   names. Do not add features it didn't ask for.
3. Write a short summary to `.pipeline/changes.md`: which files changed,
   what each change does, and anything the Tester should focus on.

You write code that matches the repo. You do not refactor unrelated
code or "improve" things outside the spec's scope.

چرا روی Sonnet اجرا می‌شود؟

پیاده‌سازی در برابرِ یک مشخصاتِ روشن، درست همان کارِ «متعادل از نظر هزینه و کیفیت» است که Sonnet در آن می‌درخشد. وقتی برنامه‌ریز کارِ سختِ تصمیم‌گیری را پیش‌تر انجام داده، کدنویس فقط باید با وفاداری اجرا کند.

یادداشتِ تحویل در changes.md همان چیزی است که به آزمونگر اجازه می‌دهد دقیقاً همان سطحِ درست را هدف بگیرد، نه آنکه کورکورانه تست بنویسد.


۷.عامل ۳ — آزمونگر (Tester)

آزمونگر می‌بیند چه چیزی تغییر کرده، تست‌هایی می‌نویسد که کارکردِ قابلیت را اثبات کنند، و سپس آن‌ها را اجرا می‌کند.

فایل .claude/agents/tester.md را بسازید:

.claude/agents/tester.md
---
name: tester
description: Writes and runs tests for changes described in .pipeline/changes.md. Third stage of the feature pipeline.
tools: Read, Write, Edit, Grep, Glob, Bash
model: sonnet
---

You are a test specialist.

1. Read `.pipeline/changes.md` to see what was built and where.
2. Read the changed files and the spec at `.pipeline/spec.md`.
3. Write tests covering: the happy path, the edge cases the spec named,
   and at least one failure case. Match the repo's test framework.
4. Run the tests. If any fail, write the failures to
   `.pipeline/test-results.md` and STOP. Do not fix the code yourself.
5. If all pass, note that in `.pipeline/test-results.md`.

You test behavior, not implementation details. A failing test means
the pipeline pauses for the Reviewer, not that you patch around it.
📌 چرا آزمونگر کد را تعمیر نمی‌کند؟

اگر آزمونگر اجازه داشته باشد کدِ خرابِ خودش را «وصله» کند، مرزِ میان «ساختن» و «اثبات‌کردن» محو می‌شود و چه‌بسا به‌جای آشکارکردنِ باگ، آن را پنهان کند. تستِ شکست‌خورده یعنی خط لوله برای بازبین مکث می‌کند، نه آنکه آزمونگر دورش بپیچد. کارِ آزمونگر سنجشِ رفتار است، نه جزئیاتِ پیاده‌سازی.


۸.عامل ۴ — بازبین (Reviewer)

دروازهٔ آخر. بازبین هر چه را خط لوله ساخته است می‌خواند و پیش از آنکه چیزی به شاخهٔ اصلیِ شما برسد، حکم می‌دهد.

فایل .claude/agents/reviewer.md را بسازید:

.claude/agents/reviewer.md
---
name: reviewer
description: Final review of the full pipeline output. Fourth and last stage before human sign-off.
tools: Read, Grep, Glob, Bash
model: opus
---

You are a senior reviewer. You are read-only. You do not edit code.

1. Read the spec, the changes summary, and the test results from
   `.pipeline/`.
2. Run `git diff` to see the actual changes.
3. Assess: does the code match the spec? Are the tests meaningful or
   superficial? Any security, performance, or correctness issues?
4. Write a verdict to `.pipeline/review.md`:
   - VERDICT: SHIP / NEEDS WORK / BLOCK
   - For NEEDS WORK or BLOCK, list exactly what to fix and where.

Be the last line of defense. If the tests are green but the code is
wrong, say BLOCK. Green tests are not the same as correct behavior.

چرا فقط‌خواندنی (read-only)؟

ابزارهای فقط‌خواندنی یعنی بازبین نمی‌تواند اشکال‌ها را با دست‌بردن در کد بپوشاند؛ تنها می‌تواند داوری کند. همین جداییِ نقش است که استقلالِ داوری را تضمین می‌کند. و نکتهٔ فلسفیِ این عامل: تستِ سبز با رفتارِ درست یکی نیست. اگر تست‌ها پاس شده‌اند ولی کد در بنیادِ خود نادرست است، حکم باید BLOCK باشد.


۹.هماهنگ‌کننده: یک فرمان برای اجرای همه

حالا همان قطعه‌ای که چهار عاملِ جدا را به یک خط لوله بدل می‌کند: یک فرمان اسلش که آن‌ها را پشتِ‌سر هم فرا می‌خواند و هر کدام، فایلِ تحویلی را که عاملِ پیشین نوشته است برمی‌دارد.

فایل .claude/commands/ship.md را بسازید:

.claude/commands/ship.md
Run the full feature pipeline for: $ARGUMENTS

Execute these stages in order. Do not skip ahead. After each stage,
confirm the handoff file exists before starting the next.

1. Delegate to the `planner` subagent with the feature request above.
   Wait for `.pipeline/spec.md`.
2. If the spec has OPEN QUESTIONS, stop and show them to me. Otherwise
   delegate to the `coder` subagent. Wait for `.pipeline/changes.md`.
3. Delegate to the `tester` subagent. Wait for `.pipeline/test-results.md`.
   If tests failed, stop and show me the failures.
4. Delegate to the `reviewer` subagent. Show me `.pipeline/review.md`.

Report the final verdict. Do not merge anything. Leave the branch for
my morning review.

سپس یک خط، کل زنجیره را به راه می‌اندازد:

terminal
/ship add rate limiting to the login endpoint

اینجا $ARGUMENTS یک «جای‌گیرنده» است: هر متنی را که پس از نامِ فرمان تایپ کنید می‌گیرد و داخل پرامپت می‌نشاند. پس /ship add rate limiting... یعنی همان جملهٔ کامل، به‌عنوان درخواستِ قابلیت، به برنامه‌ریز سپرده می‌شود.

⚠️ به‌روزرسانی مهم برای دقت فنی

پوشهٔ .claude/commands/ این روزها قالبی «قدیمی (legacy)» شمرده می‌شود. قالبِ توصیه‌شدهٔ کنونی .claude/skills/<name>/SKILL.md است که همان فراخوانی با اسلش (/name) را پشتیبانی می‌کند و افزون بر آن، خودِ مدل هم می‌تواند به‌صورت خودکار صدایش بزند. خوشبختانه ابزارِ خط فرمان هنوز هر دو قالب را می‌پذیرد، پس مثالِ بالا کماکان درست کار می‌کند؛ ولی برای پروژه‌های تازه، قالبِ Skill انتخابِ آینده‌نگرانه‌تری است.


۱۰.مثال عملی کامل با ‎.NET / C#‎

تا اینجا الگو را دیدیم. حالا بیایید همان فرمانِ نمونه — /ship add rate limiting to the login endpoint — را روی یک پروژهٔ واقعیِ ASP.NET Core دنبال کنیم و ببینیم هر عامل دقیقاً چه می‌سازد. این مثال، خروجیِ هر چهار مرحله را برای یک قابلیتِ ملموس کنار هم می‌گذارد.

مرحلهٔ ۱ — خروجی برنامه‌ریز: spec.md

برنامه‌ریز کدِ موجود را می‌خواند، درمی‌یابد که endpointِ ورود یک Minimal API در Program.cs است، و این مشخصات را می‌نویسد:

.pipeline/spec.md
# Spec: Rate limiting for the login endpoint

## Goal
Protect POST /login from brute-force by limiting attempts per client IP.

## Files to modify
- `src/Api/Program.cs`  (register limiter + apply policy)

## Approach (follow built-in ASP.NET Core rate limiting)
- Use `AddRateLimiter` with a named policy "login".
- Partition by client IP (Connection.RemoteIpAddress).
- Fixed window: PermitLimit = 5, Window = 1 minute, QueueLimit = 0.
- RejectionStatusCode = 429 (Too Many Requests).
- Call `app.UseRateLimiter()` before endpoint mapping.
- Apply `.RequireRateLimiting("login")` to the /login endpoint only.

## Edge cases
- Null RemoteIpAddress (proxied/local) -> fall back to "unknown" key.
- Successful logins still count toward the limit (brute-force protection).
- 429 response must include a Retry-After header.

## Existing pattern to follow
- Endpoint style mirrors the existing POST /register in Program.cs.

## OPEN QUESTIONS
- (none)

مرحلهٔ ۲ — خروجی کدنویس: پیاده‌سازی + changes.md

کدنویس مو به مو همان مشخصات را پیاده می‌کند و از میان‌افزارِ داخلیِ محدودسازی نرخ در ‎.NET 7+‎ بهره می‌گیرد:

src/Api/Program.cs
using System.Threading.RateLimiting;
using Microsoft.AspNetCore.RateLimiting;

var builder = WebApplication.CreateBuilder(args);

// --- Rate limiting: named "login" policy, partitioned by client IP ---
builder.Services.AddRateLimiter(options =>
{
    options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;

    options.AddPolicy("login", httpContext =>
        RateLimitPartition.GetFixedWindowLimiter(
            partitionKey: httpContext.Connection.RemoteIpAddress?.ToString()
                          ?? "unknown",
            factory: _ => new FixedWindowRateLimiterOptions
            {
                PermitLimit = 5,
                Window      = TimeSpan.FromMinutes(1),
                QueueLimit  = 0
            }));

    // Add a Retry-After header on rejection.
    options.OnRejected = async (ctx, token) =>
    {
        if (ctx.Lease.TryGetMetadata(MetadataName.RetryAfter, out var retry))
            ctx.HttpContext.Response.Headers.RetryAfter =
                ((int)retry.TotalSeconds).ToString();
        await ctx.HttpContext.Response.WriteAsync(
            "Too many login attempts. Try again later.", token);
    };
});

var app = builder.Build();

app.UseRateLimiter();   // must come before endpoint mapping

app.MapPost("/login", (LoginRequest req) =>
{
    // ... existing authentication logic ...
    return Results.Ok(new { token = "..." });
})
.RequireRateLimiting("login");

app.Run();

public record LoginRequest(string Username, string Password);
public partial class Program { }   // exposes Program to the test project
.pipeline/changes.md
# Changes

## Program.cs
- Registered `AddRateLimiter` with a fixed-window "login" policy
  (5 requests / 1 minute), partitioned by client IP.
- Added `OnRejected` to emit a Retry-After header + 429 body.
- Applied `.RequireRateLimiting("login")` to POST /login only.
- Added `public partial class Program {}` so the test host can boot it.

## For the Tester to focus on
- The 6th request from the same IP within 60s must return 429.
- The first 5 must NOT return 429.
- The 429 response should carry a Retry-After header.

مرحلهٔ ۳ — خروجی آزمونگر: تست‌های ‎xUnit‎ + test-results.md

آزمونگر با WebApplicationFactory یک تستِ یکپارچه (integration test) می‌نویسد که مسیرِ موفق، حالتِ مرزی و حالتِ شکست را پوشش می‌دهد:

tests/Api.Tests/LoginRateLimitTests.cs
using System.Net;
using System.Net.Http.Json;
using Microsoft.AspNetCore.Mvc.Testing;
using Xunit;

public class LoginRateLimitTests
    : IClassFixture<WebApplicationFactory<Program>>
{
    private readonly WebApplicationFactory<Program> _factory;

    public LoginRateLimitTests(WebApplicationFactory<Program> factory)
        => _factory = factory;

    private static readonly LoginRequest Payload =
        new("[email protected]", "wrong-password");

    [Fact] // happy path: first 5 attempts are allowed
    public async Task Allows_First_Five_Attempts()
    {
        var client = _factory.CreateClient();

        for (int i = 1; i <= 5; i++)
        {
            var res = await client.PostAsJsonAsync("/login", Payload);
            Assert.NotEqual(HttpStatusCode.TooManyRequests, res.StatusCode);
        }
    }

    [Fact] // failure case: the 6th attempt is blocked with 429
    public async Task Blocks_Sixth_Attempt_With_429()
    {
        var client = _factory.CreateClient();

        for (int i = 1; i <= 5; i++)
            await client.PostAsJsonAsync("/login", Payload);

        var blocked = await client.PostAsJsonAsync("/login", Payload);

        Assert.Equal(HttpStatusCode.TooManyRequests, blocked.StatusCode);
    }

    [Fact] // edge case: rejection carries a Retry-After header
    public async Task Rejection_Includes_RetryAfter_Header()
    {
        var client = _factory.CreateClient();

        for (int i = 1; i <= 6; i++)
            await client.PostAsJsonAsync("/login", Payload);

        var res = await client.PostAsJsonAsync("/login", Payload);
        Assert.True(res.Headers.Contains("Retry-After"));
    }
}
.pipeline/test-results.md
# Test results

$ dotnet test
Passed!  - Failed: 0, Passed: 3, Skipped: 0, Total: 3

- Allows_First_Five_Attempts ............ PASS
- Blocks_Sixth_Attempt_With_429 ......... PASS
- Rejection_Includes_RetryAfter_Header .. PASS

All green. Pipeline continues to the Reviewer.

مرحلهٔ ۴ — خروجی بازبین: review.md

بازبین git diff را اجرا می‌کند و کیفیتِ واقعی را می‌سنجد — نه صرفاً سبزبودنِ تست‌ها را:

.pipeline/review.md
# Review

VERDICT: NEEDS WORK

The implementation matches the spec and tests are meaningful
(they assert behavior, not internals). However:

1. [Correctness] IP partitioning trusts RemoteIpAddress directly.
   Behind a reverse proxy (nginx/Cloudflare) every request shares the
   proxy IP, so ALL users would share one bucket. Fix: enable
   ForwardedHeaders middleware and read X-Forwarded-For, OR document
   that this limiter sits in front of the proxy.

2. [Design] An in-memory fixed-window limiter does not survive a
   restart and is per-instance only. For multi-instance deploys, note
   that a distributed store (e.g. Redis) is needed. Acceptable for now
   if single-instance — but say so in the spec.

3. [Minor] Consider SlidingWindow over FixedWindow to avoid the
   burst-at-window-boundary problem (10 requests across 2 windows).

Action: address (1) before merge. (2) and (3) can be follow-ups.
💡 چرا این مثال ارزشمند است

توجه کنید که تست‌ها همگی سبز بودند، اما بازبین حکمِ SHIP نداد. او یک اشکالِ امنیتیِ واقعی را گرفت — به‌اشتراک‌رفتنِ سطلِ محدودیت پشتِ پراکسی — که هیچ تستی آن را نمی‌دید. این درست همان «خط دفاعیِ آخر» است که در بخش ۸ گفتیم: تستِ سبز با رفتارِ درست یکی نیست.


۱۱.دام‌ها، هزینه‌ها و بهترین‌روش‌ها

۱) هزینهٔ توکن واقعی است

هر زیرعامل پنجرهٔ زمینهٔ خودش را دارد؛ به همین خاطر، جریان‌های کاریِ زیرعامل‌محور می‌توانند تا حدودِ هفت برابرِ یک نشستِ تک‌رشته‌ای توکن مصرف کنند. صورت‌حسابِ جداگانه‌ای در کار نیست، اما حجمِ توکن بالاتر است. پس خط لوله را جایی به کار ببرید که می‌ارزد — قابلیت‌های کامل، نه اصلاحِ یک‌خطی.

۲) انسان در حلقه بماند (Human-in-the-loop)

خط لوله عمداً طوری ساخته شده که ادغام (merge) نکند؛ شاخه را دست‌نخورده برای بازبینیِ صبحگاهیِ شما می‌گذارد. دروازه‌های توقف — پرسش‌های باز، تست‌های شکست‌خورده، حکمِ BLOCK — کار را به‌عمد به شما برمی‌گردانند. این یک ویژگی است، نه یک کاستی.

۳) از کوچک شروع کنید

نخست فقط برنامه‌ریز و کدنویس را بسازید و همچون یک زنجیرهٔ دومرحله‌ای اجرا کنید. همین که این جریان جا افتاد، آزمونگر و بازبین را هم اضافه کنید. تا هر چهار عامل سرِ جای خود بنشینند، شما قابلیتی را پیش از خواب آغاز می‌کنید و حکمش را کنارِ قهوهٔ صبح می‌خوانید.

۴) ابزارها را محدود کنید

به هر عامل فقط همان ابزارهایی را بدهید که نیاز دارد. بازبین فقط‌خواندنی است؛ برنامه‌ریز به Bash احتیاجی ندارد. محدودکردنِ ابزارها هم امنیت را بالا می‌برد و هم رفتارِ عامل را پیش‌بینی‌پذیرتر می‌کند.

📌 تیم‌های آزمایشی (Agent Teams)

Claude Code قابلیتی آزمایشی به نام «تیم‌های عامل (Agent Teams)» هم دارد که به‌صورت پیش‌فرض خاموش است و باید با متغیرِ محیطیِ CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS روشن شود. این قابلیت، هماهنگیِ چند عامل را یک گام جلوتر می‌برد؛ اما الگوی دستیِ این جزوه پایه‌ای‌تر، شفاف‌تر و برای یادگیری مناسب‌تر است.


۱۲.تعمیم الگو فراتر از کدنویسی

نکتهٔ مهم این است که این الگو تنها به‌دردِ کد نمی‌خورد. ساختارِ «برنامه‌ریز ← مجری ← بازبین، با تحویل از راهِ فایلِ مشترک» یک الگوی عامِ ارکستراسیون است. همین منطق می‌تواند:

  • یک تیمِ محتوا را بچرخاند: استراتژیست ← نویسنده ← ویراستار ← بازبینِ سئو.
  • یک تیمِ پژوهش را پیش ببرد: تعریفِ پرسش ← گردآوریِ منابع ← سنتز ← راستی‌آزمایی.
  • یک تیمِ پشتیبانی را خودکار کند: دسته‌بندیِ تیکت ← پیش‌نویسِ پاسخ ← بازبینیِ لحن.
📌 جایگزین‌های مدیریت‌شده

پلتفرم‌های ابریِ مدیریت‌شده‌ای هستند که مشکلِ «تحویل» را به‌جای شما حل می‌کنند: یک «هماهنگ‌کننده» کار را میان عامل‌ها مسیریابی می‌کند، زمینه را از یکی به دیگری می‌رساند و یک خلاصهٔ مشترک نگه می‌دارد — همان معماریِ این جزوه، بی‌آنکه خودتان فایل‌های تحویل را سیم‌کشی کنید. در عوض، برتریِ پیاده‌سازیِ دستیِ این جزوه شفافیت و کنترلِ کامل است: دقیقاً می‌دانید هر مرحله چه می‌کند و می‌توانید پیش از هر تحویل، آن را بازرسی و اصلاح کنید.


۱۳.جمع‌بندی و مسیر پذیرش تدریجی

آنچه «انبوهی از عامل‌ها» را از «یک خط لوله» جدا می‌کند، همان تحویل است: چهار متخصص که در فایل‌های مشترک می‌نویسند، یک هماهنگ‌کننده که آن‌ها را پشتِ‌سرِ هم اجرا می‌کند، و هر مرحله که بر مرحلهٔ پیش بنا می‌شود، نه آنکه از صفر آغاز کند.

گاماقدامنتیجهٔ مورد انتظار
۱فقط برنامه‌ریز + کدنویس را بسازیدیک زنجیرهٔ دومرحله‌ایِ پایدار
۲آزمونگر را اضافه کنیداطمینان خودکار از رفتار
۳بازبین را اضافه کنیددروازهٔ کیفیت پیش از merge
۴فرمان /ship را بسازیدیک ماشهٔ واحد برای کل خط لوله

همین که هر چهار عامل سیم‌کشی شدند، یک قابلیت را پیش از خواب راه می‌اندازید و حکمش را با قهوهٔ صبح می‌خوانید. کلیدِ همه‌چیز، همان جملهٔ ساده است: تخصص‌گرایی، به‌اضافهٔ تحویلِ شفاف.

✅ چک‌لیست شروع

۱) پوشهٔ .claude/agents/ را بسازید  •  ۲) چهار فایل عامل را با مدل مناسب اضافه کنید  •  ۳) فرمان ship را در .claude/commands/ (یا قالب جدید Skill) قرار دهید  •  ۴) روی یک قابلیت کوچک امتحان کنید  •  ۵) ابزار هر عامل را به حداقلِ لازم محدود کنید.

جزوهٔ آموزشی — بازنویسی و توسعه‌یافته از یادداشتی دربارهٔ ساخت تیم چهار-عاملی در Claude Code.
نسخهٔ توسعه‌یافته با توضیحات تکمیلی، مثال‌های متعدد و مثال عملی ‎.NET/C#‎ — آزمایشگاه هوش مصنوعی Raderon.

خواندنی‌های مرتبط