وقتی ساخت اولین ایجنت هوش مصنوعی خود را به پایان میرسانید، همهچیز در سناریوهای تستی ساده خوب پیش میرود؛ اما با ورود به پروژههای دنیای واقعی و مخازن کد بزرگ، سیستم ناگهان از نفس میافتد. پر شدن پنجرهی بافتار (Context Window)، فراموشی جزئیات پس از دهها فراخوانی ابزار، و سردرگمی مدل میان وظایف متعدد مثل تحلیل، کدنویسی و بازبینی، سقف توانمندی تکایجنتها را نمایان میکند.
راهکار حرفهای در چنین شرایطی، تلاش برای ساخت یک ایجنت غولپیکر با پرامپتهای طولانی نیست؛ بلکه شکستن مسئله و پیادهسازی معماری چندایجنت (Multi-Agent System) است. با تقسیم وظایف میان چند ایجنت تخصصی و تنظیم قراردادهای ارتباطی شفاف، هر ایجنت بافتار تمیز و تمرکز بالایی برای اجرای وظیفهی خود حفظ میکند.
در این درس یاد میگیرید چه زمانی باید از تکایجنت به سیستم چندایجنت مهاجرت کنید، الگوهای ارکستراسیون نظیر پایپلاین، توزیع موازی و ناظر را مقایسه کنید، و پیچیدگیهایی مانند افزایش هزینهی توکن و تأخیر فراخوانیها را بسنجید تا بیدلیل معماری سیستم را پیچیده نکنید.
یک ایجنت بالاخره به بنبست میخورد. راهکار هوشمندانه ساختن ایجنت بزرگتر نیست؛ استفاده از ایجنتهای بیشتر است.
اهداف یادگیری
- سقف توانمندی تکایجنت (سرریز بافتار، تداخل تخصصها و گلوگاه ترتیبی) را بشناسید و بگویید چه زمانی تقسیم کار میان چند ایجنت تصمیم درستی است.
- الگوهای ارکستراسیون (ارکستراسیون یا Orchestration: پایپلاین، توزیع موازی، ناظر و سلسلهمراتبی) را با هم مقایسه کنید و بسته به ساختار وظیفه، الگوی مناسب را برگزینید.
- یک سیستم چندایجنت را با مرزبندی شفاف نقشها، وضعیت مشترک و قرارداد ارتباطی مشخص طراحی کنید.
- بدهبستانهای پیچیدگی چندایجنت (تاخیر، هزینه و دشواری دیباگ) را در برابر سادگی تکایجنت بسنجید.
صورت مسئله
در فاز 14 یک تکایجنت ساختید. کار هم میکند: فایلها را میخواند، دستورها را اجرا میکند، سراغ APIها میرود و دربارهی نتایج استدلال میکند. سپس آن را روی یک مخزن کد واقعی رها میکنید: 200 فایل، سه زبان مختلف، تستهایی که به زیرساخت وابستهاند، و لزوم تحقیق دربارهی APIهای خارجی پیش از نوشتن کد.
ایجنت از نفس میافتد. نه به این خاطر که مدل زبانی کمهوش است؛ ماجرا این است که وظیفه از گنجایش یک حلقهی ایجنت فراتر میرود. پنجرهی بافتار با محتوای فایلها پر میشود. ایجنت فراموش میکند 40 فراخوانی ابزار قبل چه چیزی خوانده بود. تلاش میکند همزمان محقق، برنامهنویس و بازبین باشد، و در هر سه نقش هم ضعیف عمل میکند.
این همان سقف توانمندی تکایجنت است. هر بار که وظیفه نیازمند موارد زیر باشد، به این سقف برمیخورید:
- بافتاری فراتر از گنجایش یک پنجره؛ خواندن 50 فایل بهراحتی از 200k توکن عبور میکند.
- تخصصهای متفاوت در مراحل گوناگون؛ پرامپت مناسب برای مرحلهی تحقیق با پرامپت تولید کد کاملاً فرق دارد.
- کاری که قابلیت اجرای موازی دارد؛ وقتی میشود سه فایل را همزمان خواند، چرا آنها را پشت سر هم بخوانیم؟
مفاهیم پایه
سقف توانمندی تکایجنت
تکایجنت یعنی یک حلقه، یک پنجرهی بافتار و یک پرامپت سیستم. تصویر زیر را ببینید:
┌─────────────────────────────────────────┐
│ SINGLE AGENT │
│ │
│ ┌───────────────────────────────────┐ │
│ │ Context Window │ │
│ │ │ │
│ │ research notes │ │
│ │ + code files │ │
│ │ + test output │ │
│ │ + review feedback │ │
│ │ + API docs │ │
│ │ + ... │ │
│ │ │ │
│ │ ██████████████████████ FULL ███ │ │
│ └───────────────────────────────────┘ │
│ │
│ One system prompt tries to cover │
│ research + coding + review + testing │
│ │
│ Result: mediocre at everything │
└─────────────────────────────────────────┘
سه مشکل اساسی پیش میآید:
-
اشباع بافتار؛ نتایج ابزارها روی هم تلنبار میشوند. تا نوبت 30 گفتوگو، ایجنت 150k توکن از محتوای فایلها، خروجی دستورها و استدلالهای پیشین را مصرف کرده است. جزئیات حیاتیِ نوبت 5 در این میان گم میشوند.
-
سردرگمی نقش؛ وقتی پرامپت سیستم میگوید «تو محقق، برنامهنویس، بازبین و تستر هستی»، خروجی ایجنتی است که سرسری تحقیق میکند، نصفهنیمه کد میزند و هرگز کار بازبینی را به پایان نمیرساند.
-
گلوگاه ترتیبی؛ ایجنت ابتدا فایل A را میخواند، سپس فایل B و بعد فایل C. سه فراخوانی متوالی مدل؛ سه اجرای متوالی ابزار؛ بدون ذرهای پردازش موازی.
راهکار چندایجنت
کار را خرد کنید. به هر ایجنت یک وظیفه، یک پنجرهی بافتار و یک پرامپت سیستمِ تنظیمشده برای همان وظیفه بدهید:
┌──────────────────────────────────────────────────────────┐
│ ORCHESTRATOR │
│ │
│ "Build a REST API for user management" │
│ │
│ ┌──────────┬──────────┬──────────┐ │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │RESEARCHER│ │ CODER │ │ REVIEWER │ │ TESTER │ │
│ │ │ │ │ │ │ │ │ │
│ │ Reads │ │ Writes │ │ Checks │ │ Runs │ │
│ │ docs, │ │ code │ │ code │ │ tests, │ │
│ │ finds │ │ based on │ │ quality, │ │ reports │ │
│ │ patterns │ │ research │ │ finds │ │ results │ │
│ │ │ │ + spec │ │ bugs │ │ │ │
│ └─────┬────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │ │
│ └───────────┴────────────┴─────────────┘ │
│ │ │
│ Merge results │
└──────────────────────────────────────────────────────────┘
هر ایجنت موارد زیر را دارد:
- پرامپت سیستم متمرکز («تو بازبین کد هستی. تنها وظیفهی تو پیدا کردن باگهاست.»)
- پنجرهی بافتار مستقل خودش (که با کار سایر ایجنتها آلوده نشده است)
- قرارداد ورودی و خروجی شفاف (یادداشتهای تحقیق را میگیرد، کد تحویل میدهد)
سیستمهای واقعی با این معماری
سابایجنتهای Claude Code؛ وقتی Claude Code با Task یک سابایجنت میسازد، در واقع یک ایجنت فرزند با دامنهی کاری مشخص ایجاد میکند. بافتار والد تمیز میماند؛ فرزند کار متمرکزش را انجام میدهد و خلاصه را برمیگرداند.
Devin؛ سه ایجنت مجزا اجرا میکند: برنامهریز، برنامهنویس و مرورگر وب. برنامهریز کار را به مراحل خرد میشکند؛ برنامهنویس کد میزند؛ مرورگر وب در مستندات تحقیق میکند. هر کدام بافتار جداگانهای دارند.
تیمهای چندایجنت کدنویسی (SWE-bench)؛ برترین سیستمها در بنچمارک SWE-bench از یک محقق (برای خواندن مخزن کد)، یک برنامهریز (برای طراحی راهحل) و یک کدنویس (برای پیادهسازی) استفاده میکنند. سیستمهای تکایجنت امتیاز کمتری میگیرند.
قابلیت Deep Research در ChatGPT؛ چند ایجنت جستوجو را بهطور موازی راه میاندازد که هر کدام زاویهی متفاوتی را بررسی میکنند، و در نهایت نتایج را تلفیق میکند.
طیف سیستمها
چندایجنت بودن وضعیت صفر و یکی نیست؛ یک طیف است:
SIMPLE ──────────────────────────────────────────── COMPLEX
Single Sub- Pipeline Team Swarm
Agent agents
┌───┐ ┌───┐ ┌───┐───┐ ┌───┐───┐ ┌─┐┌─┐┌─┐
│ A │ │ A │ │ A │ B │ │ A │ B │ │ ││ ││ │
└───┘ └─┬─┘ └───┘─┬─┘ └─┬─┘─┬─┘ └┬┘└┬┘└┬┘
│ │ │ │ ┌┴──┴──┴┐
┌─┴─┐ ┌───┘───┐ │ │ │shared │
│ a │ │ C │ D │ ┌─┴───┴─┐ │ state │
└───┘ └───┘───┘ │ msg │ └───────┘
│ bus │
1 loop Parent + Stage by │ │ N peers,
1 context child tasks stage └───────┘ emergent
Explicit behavior
roles
تکایجنت؛ یک حلقه، یک پرامپت. برای وظایف ساده عالی است.
سابایجنتها؛ یک والد برای زیروظایف مشخص، فرزند میسازد. والد برنامه را نگه میدارد و فرزندان گزارش میدهند؛ دقیقاً همان کاری که Claude Code انجام میدهد.
پایپلاین؛ ایجنتها بهصورت ترتیبی اجرا میشوند. خروجی ایجنت A ورودی ایجنت B میشود. مناسب جریانهای کاری مرحلهبهمرحله: تحقیق -> کدنویسی -> بازبینی -> تست.
تیم؛ ایجنتها بهصورت موازی با یک گذرگاه پیام مشترک کار میکنند. هر کدام نقشی دارند و یک هماهنگکننده آنها را مدیریت میکند. وقتی به مهارتهای گوناگون بهطور همزمان نیاز داریم، این الگو کاربرد دارد.
ازدحام (Swarm)؛ انبوهی از ایجنتهای یکسان یا شبیه به هم با وضعیت مشترک، بدون هماهنگکنندهی ثابت. ایجنتها کارها را از صف برمیدارند. برای کارهای موازی با نرخ پردازش بالا ایدهآل است.
چهار الگوی چندایجنت
الگوی 1: پایپلاین
Input ──▶ Agent A ──▶ Agent B ──▶ Agent C ──▶ Output
(research) (code) (review)
هر ایجنت داده را تبدیل میکند و به مرحلهی بعد میفرستد. درک منطق آن ساده است، اما شکست در یک مرحله کل فرآیند را متوقف میکند.
الگوی 2: توزیع موازی / تجمیع (Fan-out / Fan-in)
┌──▶ Agent A ──┐
│ │
Input ──▶ Split ├──▶ Agent B ──├──▶ Merge ──▶ Output
│ │
└──▶ Agent C ──┘
کار میان ایجنتهای موازی پخش میشود و سپس نتایج ادغام (merge) میشوند. برای وظایفی که به زیروظایف مستقل خرد میشوند بسیار مناسب است.
الگوی 3: هماهنگکننده و کارگر (Orchestrator-Worker)
┌──────────┐
│ Orch. │
└──┬───┬───┘
task │ │ task
┌─────┘ └─────┐
▼ ▼
┌──────────┐ ┌──────────┐
│ Worker A │ │ Worker B │
└──────────┘ └──────────┘
یک هماهنگکنندهی هوشمند تصمیم میگیرد چه کاری باید انجام شود، آن را به کارگران محول میکند و نتایج را سرهم میکند. خود هماهنگکننده ایجنتی است که ابزارهایی برای ساخت ایجنتهای کارگر دارد.
الگوی 4: ازدحام همتا (Peer Swarm)
┌───┐ ◄──── msg ────▶ ┌───┐
│ A │ │ B │
└─┬─┘ └─┬─┘
│ │
msg │ ┌───────────┐ │ msg
└───▶│ Shared │◄────┘
│ State │
┌───▶│ / Queue │◄────┐
│ └───────────┘ │
msg │ │ msg
┌─┴─┐ ┌─┴─┐
│ C │ ◄──── msg ────▶ │ D │
└───┘ └───┘
هیچ هماهنگکنندهی مرکزی در کار نیست. ایجنتها بهصورت همتابههمتا با یکدیگر در ارتباطند. تصمیمها از دل تعاملات پدیدار میشوند. دیباگ کردن این الگو سختتر است، اما برای تعداد بالای ایجنتها مقیاسپذیر خواهد بود.
چه زمانی نباید از چندایجنت استفاده کنیم؟
چندایجنت پیچیدگی سیستم را بالا میبرد. هر پیامی که بین ایجنتها ردوبدل میشود، یک نقطهی شکست بالقوه است. دیباگ کردن از «خواندن یک گفتوگو» به «ردگیری پیامها میان پنج ایجنت» تبدیل میشود.
چه زمانی روی تکایجنت بمانیم:
- وظیفه در یک پنجرهی بافتار جا میشود (کمتر از حدود 100k توکن دادهی کاری)
- برای مراحل مختلف نیازی به پرامپتهای سیستم متفاوت ندارید
- اجرای ترتیبی سرعت کافی دارد
- وظیفه به قدری ساده است که خرد کردنش بار اضافه میآورد تا فایده
هزینهی پیچیدگی:
- مرز میان هر دو ایجنت مثل یک فشردهسازی اطلاعات با اتلاف (lossy compression) عمل میکند: کل بافتار ایجنت A خلاصه میشود تا پیامی برای ایجنت B ساخته شود.
- منطق هماهنگی (چه کسی چه کاری را، چه زمانی و با چه ترتیبی انجام دهد) خودش منشأ باگهای تازه است.
- تاخیر بالا میرود: N ایجنت یعنی حداقل N فراخوانی متوالی مدل، و اگر لازم باشد با هم رفتوبرگشت داشته باشند این رقم بیشتر هم میشود.
- هزینه چند برابر میشود: هر ایجنت بهطور مستقل توکن میسوزاند.
یک قاعدهی سرانگشتی: اگر کاری کمتر از 20 فراخوانی ابزار میخواهد و در 100k توکن جا میشود، همان تکایجنت کفایت میکند.
پیادهسازی
مرحلهی 1: تکایجنتِ زیر بار مانده
اینجا یک تکایجنت را میبینید که میخواهد همهکار را خودش انجام دهد. یک پرامپت سیستم غولپیکر دارد و یک پنجرهی بافتار که تحقیق، کدها و بازبینیها را همزمان نگه میدارد:
type AgentResult = {
content: string;
tokensUsed: number;
toolCalls: number;
};
async function singleAgentApproach(task: string): Promise<AgentResult> {
const systemPrompt = `You are a full-stack developer. You must:
1. Research the requirements
2. Write the code
3. Review the code for bugs
4. Write tests
Do ALL of these in a single conversation.`;
const contextWindow: string[] = [];
let totalTokens = 0;
let totalToolCalls = 0;
const research = await fakeLLMCall(systemPrompt, `Research: ${task}`);
contextWindow.push(research.output);
totalTokens += research.tokens;
totalToolCalls += research.calls;
const code = await fakeLLMCall(
systemPrompt,
`Given this research:\n${contextWindow.join("\n")}\n\nNow write code for: ${task}`
);
contextWindow.push(code.output);
totalTokens += code.tokens;
totalToolCalls += code.calls;
const review = await fakeLLMCall(
systemPrompt,
`Given all previous context:\n${contextWindow.join("\n")}\n\nReview the code.`
);
contextWindow.push(review.output);
totalTokens += review.tokens;
totalToolCalls += review.calls;
return {
content: contextWindow.join("\n---\n"),
tokensUsed: totalTokens,
toolCalls: totalToolCalls,
};
}
مشکلات این رویکرد:
- پنجرهی بافتار در هر مرحله بزرگتر میشود. تا زمان بازبینی، هم یادداشتهای تحقیق را در خود دارد، هم کدها را و هم استدلالهای پیشین را.
- پرامپت سیستم کلی است و نمیتوان آن را برای هر مرحله بهینهسازی کرد.
- هیچ کاری موازی پیش نمیرود.
مرحلهی 2: ایجنتهای متخصص
حالا کار را تفکیک میکنیم. به هر ایجنت یک وظیفه اختصاص مییابد:
type SpecialistAgent = {
name: string;
systemPrompt: string;
run: (input: string) => Promise<AgentResult>;
};
function createSpecialist(name: string, systemPrompt: string): SpecialistAgent {
return {
name,
systemPrompt,
run: async (input: string) => {
const result = await fakeLLMCall(systemPrompt, input);
return {
content: result.output,
tokensUsed: result.tokens,
toolCalls: result.calls,
};
},
};
}
const researcher = createSpecialist(
"researcher",
"You are a technical researcher. Read documentation, find patterns, and summarize findings. Output only the facts needed for implementation."
);
const coder = createSpecialist(
"coder",
"You are a senior TypeScript developer. Given requirements and research notes, write clean, tested code. Nothing else."
);
const reviewer = createSpecialist(
"reviewer",
"You are a code reviewer. Find bugs, security issues, and logic errors. Be specific. Cite line numbers."
);
هر متخصص پرامپتی متمرکز دارد و پنجرهی بافتاری تمیز که فقط ورودی مورد نیازش در آن قرار میگیرد.
مرحلهی 3: هماهنگی از طریق پیامها
متخصصها را با انتقال پیام صریح به یکدیگر متصل کنید:
type AgentMessage = {
from: string;
to: string;
content: string;
timestamp: number;
};
async function multiAgentApproach(task: string): Promise<AgentResult> {
const messages: AgentMessage[] = [];
let totalTokens = 0;
let totalToolCalls = 0;
const researchResult = await researcher.run(task);
messages.push({
from: "researcher",
to: "coder",
content: researchResult.content,
timestamp: Date.now(),
});
totalTokens += researchResult.tokensUsed;
totalToolCalls += researchResult.toolCalls;
const coderInput = messages
.filter((m) => m.to === "coder")
.map((m) => `[From ${m.from}]: ${m.content}`)
.join("\n");
const codeResult = await coder.run(coderInput);
messages.push({
from: "coder",
to: "reviewer",
content: codeResult.content,
timestamp: Date.now(),
});
totalTokens += codeResult.tokensUsed;
totalToolCalls += codeResult.toolCalls;
const reviewerInput = messages
.filter((m) => m.to === "reviewer")
.map((m) => `[From ${m.from}]: ${m.content}`)
.join("\n");
const reviewResult = await reviewer.run(reviewerInput);
messages.push({
from: "reviewer",
to: "orchestrator",
content: reviewResult.content,
timestamp: Date.now(),
});
totalTokens += reviewResult.tokensUsed;
totalToolCalls += reviewResult.toolCalls;
return {
content: messages.map((m) => `[${m.from} -> ${m.to}]: ${m.content}`).join("\n\n"),
tokensUsed: totalTokens,
toolCalls: totalToolCalls,
};
}
هر ایجنت فقط پیامهایی را میگیرد که خطاب به خودش ارسال شدهاند؛ بنابراین بافتارش آلوده نمیشود. 50k توکن مستنداتی که محقق خوانده، اصلاً وارد بافتار بازبین نمیشود.
مرحلهی 4: مقایسه
async function compare() {
const task = "Build a rate limiter middleware for an Express.js API";
console.log("=== Single Agent ===");
const single = await singleAgentApproach(task);
console.log(`Tokens: ${single.tokensUsed}`);
console.log(`Tool calls: ${single.toolCalls}`);
console.log("\n=== Multi-Agent ===");
const multi = await multiAgentApproach(task);
console.log(`Tokens: ${multi.tokensUsed}`);
console.log(`Tool calls: ${multi.toolCalls}`);
}
نسخهی چندایجنت در مجموع توکنهای بیشتری مصرف میکند (سه ایجنت و سه فراخوانی مجزای مدل)، اما بافتار هر ایجنت تمیز میماند. کیفیت خروجی هر مرحله نیز بهخاطر تخصصی بودن پرامپت سیستم ارتقا پیدا میکند.
کاربرد عملی
در این درس یک پرامپت کاربردی برای تصمیمگیری دربارهی انتخاب معماری چندایجنت ساخته میشود؛ فایل outputs/prompt-multi-agent-decision.md را بررسی کنید.
تمرینها
- یک متخصص چهارم اضافه کنید: ایجنت «تستر» که کد را از برنامهنویس و بازخوردهای بازبینی را از بازبین تحویل بگیرد و سپس تستها را بنویسد.
- پایپلاین را طوری تغییر دهید که بازبین بتواند برای اصلاح کد، بازخوردها را در قالب یک چرخهی ویرایش (حداکثر 2 دور) به برنامهنویس برگرداند.
- پایپلاین ترتیبی را به توزیع موازی (fan-out) تبدیل کنید: ایجنت محقق و ایجنت «تحلیلگر نیازمندیها» را بهطور موازی اجرا کنید و پیش از ارسال به برنامهنویس، خروجیهای آنها را با هم merge کنید.
اصطلاحات کلیدی
| اصطلاح | چیزی که بقیه میگویند | معنای واقعی آن |
|---|---|---|
| Swarm (ازدحام) | «ذهن کندویی ایجنتهای هوش مصنوعی» | مجموعهای از ایجنتهای همتا با وضعیت مشترک و بدون رهبر ثابت، که رفتار کلی سیستم از دل تعاملات محلی آنها شکل میگیرد. |
| Orchestrator (هماهنگکننده) | «ایجنت رئیس» | ایجنتی که ابزارهایش شامل ساخت و مدیریت سایر ایجنتهاست. برنامهریزی میکند و کارها را میسپارد، ولی شاید خودش کار اجرایی نکند. |
| Coordinator (هماهنگکننده منطقی) | «پلیس راهنماییورانندگی» | بخشی از سیستم که ایجنت نیست (غالباً فقط کد است، نه مدل زبانی) و پیامها را طبق یکسری قواعد بین ایجنتها هدایت میکند. |
| Consensus (اجماع) | «ایجنتها به توافق رسیدند» | پروتکلی که در آن چند ایجنت پیش از ادامهی کار باید به تفاهم برسند؛ زمانی به کار میآید که حل اختلاف در خروجیهای متناقض لازم باشد. |
| Emergent behavior (رفتار نوظهور) | «ایجنتها خودشان راهش را پیدا کردند» | الگوهایی در سطح کل سیستم که از تعامل ایجنتها سرچشمه میگیرند اما مستقیماً کدنویسی نشدهاند؛ این رفتارها گاهی مفیدند و گاهی مخرب. |
| Fan-out / fan-in (توزیع موازی / تجمیع) | «همان مپریدیوس برای ایجنتها» | خرد کردن یک وظیفه میان چند ایجنت موازی (fan-out) و سپس یکی کردن نتایج آنها (fan-in). |
| Message passing (انتقال پیام) | «ایجنتها با هم حرف میزنند» | سازوکار ارتباطی میان ایجنتها؛ دادههای ساختیافتهای که از یک ایجنت به دیگری فرستاده میشود و جایگزین پنجرههای بافتار مشترک میشود. |
برای مطالعهی بیشتر
- The Landscape of Emerging AI Agent Architectures - مروری جامع بر الگوهای طراحی چندایجنت
- AutoGen: Enabling Next-Gen LLM Applications - فریمورک مایکروسافت برای گفتوگوی چندایجنت
- Claude Code subagents documentation - شیوهی تفویض وظایف با ابزار Task در Claude Code
- CrewAI documentation - فریمورک ساخت سیستمهای چندایجنت مبتنی بر نقش
