ဒီ သင်ခန်းစာမှာ TypeScript၊ Vercel AI SDK နဲ့ OpenRouter တို့ကို အသုံးပြုပြီး AI Agent တစ်ခုကို အတူတူ တည်ဆောက်ကြည့်ကြပါမယ်။
သင်ခန်းစာ ပြီးဆုံးသွားတဲ့အခါ -
- Language model ခေါ်ယူခြင်း၊
- Agent Tool ဖန်တီးခြင်း၊
- Agent Tool အသုံးပြုခြင်း၊
- Agent Loop ဖန်တီးခြင်း၊
- Memory စနစ် ထည့်သွင်းခြင်း၊
- Subagent တည်ဆောက်ခြင်း၊
- Sequential Agents အကြောင်းနဲ့
- Parallel Agents အကြောင်းတို့ကို
သိရှိသွားမှာပဲ ဖြစ်ပါတယ်။ အခြေခံအဆင့်တွေပဲ ဖြစ်လို့ Database တွေ၊ Vector Search တွေ၊ Web UI တွေ မပါသေးပါဘူး။
ပထမဆုံးအနေနဲ့ Agent ဆိုတာဘာလဲ၊ ဒီလို အကျဉ်းချုပ်မှတ်ပါ။
Agent ဆိုတာ ဘာလဲ?Agent ဆိုတာ AI Model တစ်ခုနဲ့အတူ ပေးထားတဲ့ Tool တွေကို ပေါင်းစပ် အသုံးပြုပြီး အဖြေတစ်ခု ထွက်လာတဲ့အထိ အဆင့်ဆင့် လုပ်ဆောင်သွားနိုင်တဲ့ ကွန်ပျူတာပရိုဂရမ်တစ်ခု ဖြစ်ပါတယ်။
အရင်ဆုံး မိမိနှစ်သက်ရာနေရာမှာ ပရောဂျက်တစ်ခု တည်ဆောက်ပါ။ package.json ဖိုင်တစ်ခုလည်း တည်ဆောက်လိုက်ပါ။ ဥပမာ -
mkdir my-agent
cd my-agent
npm init -y
ဆက်လက်ပြီး လိုအပ်တဲ့ Package တွေကို Install လုပ်ပါ -
npm install ai @openrouter/ai-sdk-provider zod dotenv
အဓိကနည်းပညာအဖြစ် အသုံးပြုလိုတဲ့ Vercel AI SDK နဲ့ OpenRouter Provider တို့ကို ထည့်သွင်းလိုက်တာပါ။ နောက်ထပ် လိုအပ်တဲ့ Development Dependencies တွေကိုလည်း ထပ်ပြီး Install လုပ်ပါ -
npm install -D typescript tsx @types/node
TypeScript ကို အသုံးပြုရေးသားမှာဖြစ်လို့ သက်ဆိုင်တာတွေ ထည့်သွင်းလိုက်တာပါ။
OpenRouter အတွက် API Key လိုအပ်ရင် ဒီလိပ်စာမှာ ရယူလို့ရပါတယ်။
ဆက်လက်ပြီး ပရောဂျက်မှာ ပါဝင်မည့်ဖိုင်တွေ အပြည့်အစုံနဲ့ အခုလို Folder Structure တစ်ခုကို တည်ဆောက်လိုက်ပါ -
my-agent/
├── src/
│ ├── 01-basic.ts
│ ├── 02-tool.ts
│ ├── 03-agent-loop.ts
│ ├── 04-memory.ts
│ ├── 05-subagent.ts
│ ├── 06-sequential.ts
│ └── 07-parallel.ts
├── .env
├── .gitignore
├── package.json
└── tsconfig.json
TypeScript နဲ့ပတ်သက်ပြီး လိုအပ်တာတွေ အသင့်ဖြစ်သွားအောင် tsconfig.json
ဖိုင်ထဲမှာ အောက်ပါအတိုင်း ရေးသားပေးပါ -
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"types": ["node"],
"strict": true,
"esModuleInterop": true
},
"include": ["src"]
}
package.json
ဖိုင်ထဲမှာ scripts
တွေကို အခုလို ကြိုတင်ထည့်သွင်းထားလိုက်ပါ။ ကျန်တာတွေက ပြင်စရာမလိုပါဘူး၊ အသင့်ကူးယူလို့ရအောင်သာ အစုံထည့်ပေးလိုက်တာပါ -
{
"name": "my-agent",
"version": "1.0.0",
"type": "module",
"scripts": {
"basic": "tsx src/01-basic.ts",
"tool": "tsx src/02-tool.ts",
"loop": "tsx src/03-agent-loop.ts",
"memory": "tsx src/04-memory.ts",
"subagent": "tsx src/05-subagent.ts",
"sequential": "tsx src/06-sequential.ts",
"parallel": "tsx src/07-parallel.ts",
"check": "tsc --noEmit"
},
"dependencies": {
"@openrouter/ai-sdk-provider": "latest",
"ai": "latest",
"dotenv": "latest",
"zod": "latest"
},
"devDependencies": {
"@types/node": "latest",
"tsx": "latest",
"typescript": "latest"
}
}
.env
ဖိုင်ထဲမှာ OpenRouter API Key နဲ့ အသုံးပြုလိုတဲ့ Model တို့ကို အောက်ပါအတိုင်း ထည့်သွင်းပါမယ် -
OPENROUTER_API_KEY=your-openrouter-api-key
OPENROUTER_MODEL=xiaomi/mimo-v2.5
နမူနာမှာ xiaomi/mimo-v2.5
ကို Model အနေနဲ့ ရွေးချယ်ထားပြီး၊ အခြားနှစ်သက်ရာ Model ကို အစားထိုးရွေးချယ်နိုင်ပါတယ်။ အခမဲ့ရတဲ့ Model တွေ သုံးပြီး စမ်းလို့လည်း ရပါတယ်။ ကိုယ်ရွေးချယ်တဲ့ Model က Tool Calling ရတဲ့ Model ဖြစ်ရမယ်ဆိုတာကိုတော့ သတိပြုပါ။
.gitignore
ဖိုင်ထဲမှာလည်း အခုလို ရေးသားပေးပါ၊ မဖြစ်မနေ လိုအပ်ချက်မဟုတ်ပေမဲ့ .env
လိုဖိုင်မျိုးတွေ မျှဝေတဲ့အခါ ပါမသွားစေဖို့ပါ -
node_modules
dist
.env
ပထမဆုံးကုဒ်အနေနဲ့ src/01-basic.ts
ဖိုင်ထဲမှာ အောက်ပါအတိုင်း ရေးပါမယ် -
import "dotenv/config";
import { generateText } from "ai";
import { createOpenRouter } from "@openrouter/ai-sdk-provider";
const apiKey = process.env.OPENROUTER_API_KEY;
const modelName = process.env.OPENROUTER_MODEL;
if (!apiKey) {
throw new Error("OPENROUTER_API_KEY is missing.");
}
if (!modelName) {
throw new Error("OPENROUTER_MODEL is missing.");
}
const openrouter = createOpenRouter({
apiKey,
});
const model = openrouter(modelName);
const result = await generateText({
model,
prompt: "Explain what an AI agent is in two simple sentences.",
});
console.log(result.text);
ရေးပြီးသွားရင် Terminal ကနေ အောက်ပါအတိုင်း Run ပြီး စမ်းကြည့်လို့ ရပါပြီ။ လိုအပ်တဲ့ NPM Script ကို စောစောက ကြိုထည့်ခဲ့ပြီးသားပါ -
npm run basic
ဒီကုဒ်လေးက OpenRouter provider တစ်ခုကို တည်ဆောက်လိုက်တာ ဖြစ်ပါတယ် -
const openrouter = createOpenRouter({
apiKey,
});
ဒီကုဒ်ကတော့ အသုံးပြုလိုတဲ့ model ကို ရွေးချယ်လိုက်တာပါ -
const model = openrouter(modelName);
Model ဆီကို request လှမ်းပို့တဲ့အခါ အခုလို ပို့ရပါတယ် -
const result = await generateText({
model,
prompt: "...",
});
နောက်ဆုံးမှာ Model ဆီကနေ ရလာတဲ့ ရလဒ်ကို Console မှာပဲ ပြပေးလိုက်တာ ဖြစ်ပါတယ် -
console.log(result.text);
generateText()
function ကို အဓိကအားဖြင့် စာသားတွေ ထုတ်ခိုင်းဖို့ သုံးတာ ဖြစ်ပါတယ်။ Streaming လို လုပ်ဆောင်ချက်တွေ ထည့်သုံးမထားလို့၊ ရလဒ်ကို တစ်လုံးချင်းပြန်ထုတ်ပေးတာမျိုး မဟုတ်ဘဲ အားလုံးပြီးမှ တစ်ခါတည်း ပေးထားတာ ဖြစ်ပါတယ်။
အခုအဆင့်က Agent မဟုတ်သေးပါဘူး။ Model Request တစ်ခုသာ ရှိပါသေးတယ်။ သူ့ရဲ့ Flow က အောက်ပါအတိုင်း ဖြစ်ပါတယ် -
Program
↓
Prompt
↓
Model
↓
Text response
Tool ဆိုတာ Model က လှမ်းခေါ်ခွင့် ပြုထားတဲ့ ရိုးရိုး function တစ်ခုသာ ဖြစ်ပါတယ်။ အဓိကအားဖြင့် အစိတ်အပိုင်း ၃ ခု ပါဝင်ပါတယ် -
- Description
- Input Schema
- Execution Function
Schema နဲ့ Model ထည့်ပေးရမဲ့ Arguments သတ်မှတ်ပါတယ်။ Model က ပြန်ပေးတဲ့ arguments တွေ မှန်/မမှန်ကိုလည်း အလုပ်မလုပ်ခင် ဒီ Schema နဲ့ပဲ စစ်ဆေးပေးပါတယ်။
နမူနာအနေနဲ့ အလွန်ရိုးရှင်းလွယ်ကူတဲ့ Calculator Tool လေးတစ်ခုလောက် လုပ်ကြပါမယ်။ src/02-tool.ts
ဖိုင်မှာ အောက်ပါအတိုင်း ရေးသား လိုက်ပါ -
import "dotenv/config";
import { generateText, tool } from "ai";
import { createOpenRouter } from "@openrouter/ai-sdk-provider";
import { z } from "zod";
const apiKey = process.env.OPENROUTER_API_KEY;
const modelName = process.env.OPENROUTER_MODEL;
if (!apiKey || !modelName) {
throw new Error(
"OPENROUTER_API_KEY and OPENROUTER_MODEL must be configured.",
);
}
const openrouter = createOpenRouter({
apiKey,
});
const model = openrouter(modelName);
const calculatorTool = tool({
description:
"Perform basic arithmetic using two numbers. Use this instead of calculating mentally.",
inputSchema: z.object({
operation: z.enum(["add", "subtract", "multiply", "divide"]),
a: z.number(),
b: z.number(),
}),
execute: async ({ operation, a, b }) => {
switch (operation) {
case "add":
return {
result: a + b,
};
case "subtract":
return {
result: a - b,
};
case "multiply":
return {
result: a * b,
};
case "divide":
if (b === 0) {
return {
error: "Cannot divide by zero.",
};
}
return {
result: a / b,
};
}
},
});
const result = await generateText({
model,
prompt:
"Use the calculator to multiply 37 by 14. Do not calculate it yourself.",
tools: {
calculator: calculatorTool,
},
});
console.log("Text:");
console.log(result.text);
console.log("\nTool calls:");
console.dir(result.toolCalls, {
depth: null,
});
console.log("\nTool results:");
console.dir(result.toolResults, {
depth: null,
});
ရေးပြီးသွားရင် အခုလို Run ပြီး စမ်းကြည့်လို့ ရနေပါပြီ -
npm run tool
Model က ခေါ်ယူအသုံးပြုလို့ရမယ့် Tool ရဲ့ အမည် အခုလို သတ်မှတ်ပေးပါတယ် -
tools: {
calculator: calculatorTool,
}
Description ကို ကြည့်ပြီး Model က ဒီ tool ကို ဘယ်အချိန်မှာ သုံးသင့်လဲဆိုတာ အလိုအလျှောက် ဆုံးဖြတ်သွားမှာပါ၊ ဒါကြောင့် ကိုယ့် tool အကြောင်းကို သေချာရှင်းပြထားရမှာ ဖြစ်ပါတယ် -
description:
"Perform basic arithmetic using two numbers..."
Input schema ကတော့ အထက်မှာ ပြောခဲ့သလို ဘယ်လို input မျိုး လက်ခံမလဲဆိုတာ စစ်ဆေးပေးပါတယ် -
inputSchema: z.object({
operation: z.enum([
"add",
"subtract",
"multiply",
"divide",
]),
a: z.number(),
b: z.number(),
})
Execution function ကတော့ ပုံမှန် TypeScript function code ပါပဲ -
execute: async ({ operation, a, b }) => {
// deterministic application code
}
Model က ဒီ function ကို သူကိုယ်တိုင် တိုက်ရိုက်ဝင် run တာတော့ မဟုတ်ပါဘူး။ လုပ်ငန်းစဉ်က အောက်ပါအတိုင်း သွားတာပါ -
1. Model က calculator ကိုခေါ်ဖို့ တောင်းဆိုတယ်။
2. AI SDK က arguments တွေကို စစ်ဆေးတယ်။
3. AI SDK က calculatorTool.execute() ကို run ပေးတယ်။
4. AI SDK က ရလာတဲ့ tool ရလဒ်ကို Model ဆီ ပြန်ပို့ပေးပါတယ်။
ဒီနည်းနဲ့ Model က ခေါ်ချင်တဲ့ Tool ကို ပြန်ပေးပြီး SDK က တစ်ကယ်ခေါ် အလုပ်လုပ်ပြီး ရလဒ်ကို Model ထံ ပြန်ပေးလိုက်တာ ဖြစ်ပါတယ်။
စမ်းကြည့်တဲ့အခါ Tool ရလဒ် ထွက်လာပေမယ့် အဖြေ ပြန်မရတာမျိုး ကြုံရနိုင်ပါတယ်။ Model က အလုပ်လုပ်ပုံက Tool ကို လှမ်းခေါ်ဖို့ တောင်းဆိုလိုက်တာနဲ့တင် ပြီးဆုံးသွားလို့ ဖြစ်ပါတယ်။
Model request
↓
Tool call
↓
Tool executes
↓
Generation ends
Model အနေနဲ့ ရလာတဲ့ Tool ရလဒ်ကို ကြည့်ပြီး ဆက်အလုပ်လုပ်ခွင့် မရလိုက်ပါဘူး။ ဒါကြောင့် Agent Loop တစ်ခု လိုအပ်လာတာ ဖြစ်ပါတယ်။
Agent Loop တစ်ခု စမ်းသပ်တည်ဆောက်ကြည့်ဖို့အတွက် src/03-agent-loop.ts
ဖိုင်ထဲမှာ အောက်ပါအတိုင်း ရေးလိုက်ပါ -
import "dotenv/config";
import {
generateText,
stepCountIs,
tool,
} from "ai";
import { createOpenRouter } from "@openrouter/ai-sdk-provider";
import { z } from "zod";
const apiKey = process.env.OPENROUTER_API_KEY;
const modelName = process.env.OPENROUTER_MODEL;
if (!apiKey || !modelName) {
throw new Error(
"OPENROUTER_API_KEY and OPENROUTER_MODEL must be configured.",
);
}
const openrouter = createOpenRouter({
apiKey,
});
const model = openrouter(modelName);
const calculatorTool = tool({
description: "Perform basic arithmetic accurately.",
inputSchema: z.object({
operation: z.enum(["add", "subtract", "multiply", "divide"]),
a: z.number(),
b: z.number(),
}),
execute: async ({ operation, a, b }) => {
console.log(`Executing: ${operation}(${a}, ${b})`);
switch (operation) {
case "add":
return { result: a + b };
case "subtract":
return { result: a - b };
case "multiply":
return { result: a * b };
case "divide":
if (b === 0) {
return { error: "Division by zero is not allowed." };
}
return { result: a / b };
}
},
});
const result = await generateText({
model,
system: `
You are a careful assistant.
Use the calculator whenever arithmetic is needed.
After using a tool, explain the result clearly.
`,
prompt: `
A shop sold 18 boxes.
Each box contained 24 books.
Then 35 books were returned.
How many books remained sold?
`,
tools: {
calculator: calculatorTool,
},
stopWhen: stepCountIs(5),
});
console.log("\nFinal answer:");
console.log(result.text);
console.log("\nNumber of steps:");
console.log(result.steps.length);
for (const [index, step] of result.steps.entries()) {
console.log(`\nStep ${index + 1}`);
console.log("Text:");
console.log(step.text || "(no text)");
console.log("Tool calls:");
console.dir(step.toolCalls, {
depth: null,
});
console.log("Tool results:");
console.dir(step.toolResults, {
depth: null,
});
}
ပြီးတဲ့အခါ အခုလို Run ကြည့်လိုက်ပါ -
npm run loop
Model က Tool ကို အသုံးပြုပြီး နောက်ဆုံးရလဒ်ထွက်တဲ့အထိ အလုပ်လုပ်သွားတာကို တွေ့ရမှာပဲ ဖြစ်ပါတယ်။
အထက်က Agent Loop ကုဒ်မှာ ဒီပိုင်းက အဓိက ဖြစ်ပါတယ် -
stopWhen: stepCountIs(5)
သူက SDK ကို Tool အလုပ်လုပ်လို့ ပြီးသွားရင်လည်း ရပ်မပစ်ဘဲ သတ်မှတ်ထားတဲ့ အကြိမ်ရေအထိ ဆက်ပြီး loop ပတ်ခိုင်းလိုက်တာ ဖြစ်ပါတယ်။ လုပ်ငန်းစဉ်က အောက်ပါအတိုင်း ဖြစ်သွားပါမယ် -
Step 1:
Model က multiply(18, 24) ကို လှမ်းခေါ်ပါတယ်။
Step 2:
Model က ရလဒ် 432 ကို လက်ခံရရှိပြီး subtract(432, 35) ကို ထပ်ခေါ်ပါတယ်။
Step 3:
Model က ရလဒ် 397 ကို လက်ခံရရှိပြီး နောက်ဆုံးအဖြေကို ပြန်ပေးသွားမှာပါ။
stopWhen
ကြောင့် SDK က Tool ကို run တယ်၊ ရလဒ်ကို model ဆီ ပြန်ပေးပါတယ်၊ ပြီးတော့ Model က အဖြေထုတ်ပေးနိုင်တဲ့အထိ ဆက်တိုက် အလုပ်လုပ်သွားပါတယ်။ stepCountIs(5)
လို့ ကန့်သတ်ထားလိုက်တာက အဆုံးမရှိ loop ပတ် မနေအောင် ကာကွယ်ပေးတာ ဖြစ်ပါတယ်။
ဒါဟာ ကျွန်တော်တို့ရဲ့ ပထမဆုံး တကယ့် Agent တစ်ခုပဲ ဖြစ်ပါတယ် -
User task
↓
Model decides action
↓
Tool executes
↓
Result returns to model
↓
Model decides next action
↓
Final answer
ကျွန်တော်တို့ရဲ့ Agent မှာ အဓိကအကျဆုံး အစိတ်အပိုင်း ၄ ခု ပါဝင်တာကို နောက်တစ်ကြိမ်လောက် သတိပြုကြည့်လိုက်ပါ -
1. Model
2. Instructions
3. Tools
4. Loop
Code အနေနဲ့ အောက်ပါအတိုင်း ဖြစ်ပါတယ် -
generateText({
model,
system,
prompt,
tools,
stopWhen,
});
ဒီနေရာမှာ Memory ဆိုတာ မှတ်တမ်းတွေကို ယာယီသိမ်းဆည်းထားခြင်းသာ ဖြစ်ပါတယ်။ ဒါကြောင့် Program ပိတ်လိုက်ရင် ပျောက်သွားမှာဖြစ်ပြီး Database တွေဘာတွေနဲ့ သိမ်းထားတာ မဟုတ်ပါဘူး။
ကျွန်တော်တို့ လုပ်မှာက User နဲ့ Model ကြားထဲက အပြန်အလှန် ဆက်သွယ် အလုပ်လုပ်ထားတဲ့ အချက်အလက်တွေကို ခပ်ရိုးရိုးပဲ Array တစ်ခုနဲ့ သိမ်းထားလိုက်မှာ ဖြစ်ပါတယ်။
နမူနာစမ်းကြည့်ဖို့အတွက် src/04-memory.ts
ဖိုင်မှာ အခုလိုရေးသားပေးပါ -
import "dotenv/config";
import { createInterface } from "node:readline/promises";
import { stdin as input, stdout as output } from "node:process";
import {
generateText,
stepCountIs,
tool,
type ModelMessage,
} from "ai";
import { createOpenRouter } from "@openrouter/ai-sdk-provider";
import { z } from "zod";
const apiKey = process.env.OPENROUTER_API_KEY;
const modelName = process.env.OPENROUTER_MODEL;
if (!apiKey || !modelName) {
throw new Error(
"OPENROUTER_API_KEY and OPENROUTER_MODEL must be configured.",
);
}
const openrouter = createOpenRouter({
apiKey,
});
const model = openrouter(modelName);
const calculatorTool = tool({
description: "Perform basic arithmetic accurately.",
inputSchema: z.object({
operation: z.enum(["add", "subtract", "multiply", "divide"]),
a: z.number(),
b: z.number(),
}),
execute: async ({ operation, a, b }) => {
switch (operation) {
case "add":
return { result: a + b };
case "subtract":
return { result: a - b };
case "multiply":
return { result: a * b };
case "divide":
if (b === 0) {
return { error: "Cannot divide by zero." };
}
return { result: a / b };
}
},
});
const memory: ModelMessage[] = [];
async function runAgent(userText: string): Promise<string> {
memory.push({
role: "user",
content: userText,
});
const result = await generateText({
model,
system: `
You are a helpful assistant with access to a calculator.
Use previous messages to understand references such as
"it", "that number" and "my name".
`,
messages: memory,
tools: {
calculator: calculatorTool,
},
stopWhen: stepCountIs(5),
});
memory.push({
role: "assistant",
content: result.text,
});
return result.text;
}
const readline = createInterface({
input,
output,
});
console.log('Type "exit" to stop.');
try {
while (true) {
const userText = await readline.question("\nYou: ");
if (userText.trim().toLowerCase() === "exit") {
break;
}
if (!userText.trim()) {
continue;
}
const answer = await runAgent(userText);
console.log(`Agent: ${answer}`);
}
} finally {
readline.close();
}
ပြီးတဲ့အခါ အခုလို Run ကြည့်လို့ ရပါပြီ -
npm run memory
အောက်ပါအတိုင်း Chat ပုံစံ စကားပြောကြည့်ပြီး စမ်းသပ်လိုက်ပါ -
You: Hello, how can you assist me today?
You: Calculate 18 times 7.
You: Add 20 to that number.
ပထမဆုံး အောက်ပါအတိုင်း Array တစ်ခုကို တည်ဆောက်ထားပါတယ် -
const memory: ModelMessage[] = [];
Model ဆီ မပို့ခင် User ရဲ့ Prompt ကို Array ထဲမှာ ထည့်သွင်းပါတယ် -
memory.push({
role: "user",
content: userText,
});
ပြီးရင် Model messages နေရာမှာ Array ထဲက သိမ်းထားသမျှ အကုန်ထည့်ပေးလိုက်ပါတယ် -
messages: memory
မော်ဒယ်ဆီက အဖြေရလာတော့လည်း အလားတူ Array ထဲမှာ ထပ်တိုးပြီး မှတ်ခိုင်းပါတယ် -
memory.push({
role: "assistant",
content: result.text,
});
အခုလိုပုံစံဖြစ်မှာပါ -
Request 1:
[user message 1]
Request 2:
[user message 1]
[assistant response 1]
[user message 2]
Request 3:
[user message 1]
[assistant response 1]
[user message 2]
[assistant response 2]
[user message 3]
ကြာလာတာနဲ့အမျှ Array က တဖြည်းဖြည်း ကြီးမားလာမှာ ဖြစ်လို့ trimMemory
function ထည့်သွင်းပြီး မှတ်တမ်း အဟောင်းတွေကို ဖြတ်ထုတ်နိုင်ပါတယ် -
function trimMemory(maxMessages: number): void {
if (memory.length > maxMessages) {
memory.splice(0, memory.length - maxMessages);
}
}
မော်ဒယ်ဆီ မပို့ခင် trimMemory
ကို လှမ်းခေါ်ပေးလိုက်ရုံပါပဲ -
async function runAgent(userText: string): Promise<string> {
memory.push({
role: "user",
content: userText,
});
trimMemory(10);
const result = await generateText({
// ...
});
memory.push({
role: "assistant",
content: result.text,
});
return result.text;
}
ဒါက အခြေခံအကျဆုံး Context management နည်းလမ်းလေးတစ်ခုကို တစ်ခါတည်း ထည့်ကြည့်လိုက်တဲ့ သဘောပါ။
Subagent ဆိုတာ ပင်မအလုပ်ကနေ ခွဲထုတ်ပြီး သီးခြားအလုပ်လုပ်ခိုင်းလိုက်တဲ့ သီးခြား Specialist အေးဂျင့်လေးတွေ ဖြစ်ပါတယ်။
နမူနာမှာတော့ -
- Research Subagent ခေါ် အချက်အလက်တွေကို စုဆောင်းပေးမယ့် Agent တစ်ခုနဲ့၊
- Writer Agent ခေါ် ရလာတဲ့ အချက်အလက်တွေကို သေသေချာချာ ပြန်ရေးပေးတဲ့ Agent တို့ကို လုပ်ကြည့်ကြပါမယ်။
src/05-subagent.ts
ဖိုင်မှာ အခုလိုရေးပေးလိုက်ပါ -
import "dotenv/config";
import { generateText } from "ai";
import { createOpenRouter } from "@openrouter/ai-sdk-provider";
const apiKey = process.env.OPENROUTER_API_KEY;
const modelName = process.env.OPENROUTER_MODEL;
if (!apiKey || !modelName) {
throw new Error(
"OPENROUTER_API_KEY and OPENROUTER_MODEL must be configured.",
);
}
const openrouter = createOpenRouter({
apiKey,
});
const model = openrouter(modelName);
async function researchAgent(topic: string): Promise<string> {
const result = await generateText({
model,
system: `
You are a research assistant.
Your job is to identify:
1. The central idea
2. Important supporting points
3. Common misunderstandings
Do not write a polished article.
Return concise research notes.
`,
prompt: `Research this topic: ${topic}`,
});
return result.text;
}
async function writerAgent(
topic: string,
researchNotes: string,
): Promise<string> {
const result = await generateText({
model,
system: `
You are a teacher.
Turn supplied research notes into a clear beginner explanation.
Do not claim that the notes were externally verified.
Use a simple example.
`,
prompt: `
Topic:
${topic}
Research notes:
${researchNotes}
`,
});
return result.text;
}
async function main(): Promise<void> {
const topic = "Why AI agents need tools";
console.log("Running research subagent...\n");
const notes = await researchAgent(topic);
console.log("Research notes:");
console.log(notes);
console.log("\nRunning writer agent...\n");
const article = await writerAgent(topic, notes);
console.log("Final explanation:");
console.log(article);
}
await main();
ပြီးတဲ့အခါ အခုလို Run ကြည့်လို့ ရပါပြီ -
npm run subagent
Research agent မှာ ကိုယ်ပိုင် Instruction နဲ့ ရလဒ်တွေ ရှိပါတယ်။ ပင်မ Agent က အဲ့ဒီ ရလဒ်ကို ယူပြီး -
const notes = await researchAgent(topic);
နောက် Agent တစ်ခုဆီ အခုလို လွှဲပေးလိုက်တာပါ -
const article = await writerAgent(topic, notes);
ဖွဲ့စည်းပုံက အောက်ပါအတိုင်း ဖြစ်ပါတယ် -
Parent agent
│
├── Research subagent
│ ↓
│ Research notes
│
└── Writer agent
↓
Final answer
Subagent ဆိုတာ ဒီလိုမျိုး သီးခြားအလုပ်လုပ်နိုင်တဲ့ အစိတ်အပိုင်းလေးတွေပဲ ဖြစ်ပါတယ်။ ဒီအစိတ်အပိုင်းလေးတွေကို အဆင့်လိုက် Sequential တစ်ခုပြီးတစ်ခု လုပ်အောင် စီစဉ်ထားလို့ရသလို၊ Parallel ပြိုင်တူလုပ်အောင်လည်း စီစဉ်ထားလို့ ရပါတယ်။
Sequential workflow ဆိုတာ အလုပ်တစ်ခုပြီးမှ နောက်အလုပ်တစ်ခုကို အဆင့်ဆင့် လက်ဆင့်ကမ်း လုပ်သွားတဲ့ အလုပ်တွေ ဖြစ်ပါတယ် -
ဒီနေရာမှာ အစီအစဉ်က အရေးကြီးပါတယ်။ ကျွန်တော်တို့ နမူနာ လုပ်မယ့် Sequential အစီအစဉ်ကတော့ -
၁။ Outline ထုတ်မယ်။ ၂။ Review စစ်မယ်။ ၃။ သင်ခန်းစာ ရေးမယ်။
ဆိုတဲ့အဆင့်တွေပဲ ဖြစ်ပါတယ်။
နမူနာအနေနဲ့ src/06-sequential.ts
မှာ အခုလို ရေးပေးပါ -
import "dotenv/config";
import { generateText } from "ai";
import { createOpenRouter } from "@openrouter/ai-sdk-provider";
const apiKey = process.env.OPENROUTER_API_KEY;
const modelName = process.env.OPENROUTER_MODEL;
if (!apiKey || !modelName) {
throw new Error(
"OPENROUTER_API_KEY and OPENROUTER_MODEL must be configured.",
);
}
const openrouter = createOpenRouter({
apiKey,
});
const model = openrouter(modelName);
async function createOutline(topic: string): Promise<string> {
const result = await generateText({
model,
system: `
Create a short beginner lesson outline.
Return only the outline.
`,
prompt: topic,
});
return result.text;
}
async function reviewOutline(
topic: string,
outline: string,
): Promise<string> {
const result = await generateText({
model,
system: `
You are an educational editor.
Review the supplied outline.
Fix unclear ordering and remove unnecessary complexity.
Return the improved outline only.
`,
prompt: `
Topic:
${topic}
Outline:
${outline}
`,
});
return result.text;
}
async function writeLesson(
topic: string,
approvedOutline: string,
): Promise<string> {
const result = await generateText({
model,
system: `
Write a concise beginner lesson based strictly on the supplied outline.
Include one practical analogy.
`,
prompt: `
Topic:
${topic}
Approved outline:
${approvedOutline}
`,
});
return result.text;
}
async function main(): Promise<void> {
const topic = "How an AI agent loop works";
console.log("Step 1: Creating outline");
const outline = await createOutline(topic);
console.log("\nStep 2: Reviewing outline");
const reviewedOutline = await reviewOutline(topic, outline);
console.log("\nStep 3: Writing lesson");
const lesson = await writeLesson(topic, reviewedOutline);
console.log("\nInitial outline:");
console.log(outline);
console.log("\nReviewed outline:");
console.log(reviewedOutline);
console.log("\nFinal lesson:");
console.log(lesson);
}
await main();
ပြီးတဲ့အခါ အခုလို Run ကြည့်လိုက်ပါ -
npm run sequential
လုပ်ရမယ့် အစီအစဉ်အဆင့်ဆင့်ကို Model က ဆုံးဖြတ်တာ မဟုတ်ဘဲ ကျွန်တော်တို့ရဲ့ TypeScript code ကပဲ အခုလို ဆုံးဖြတ်ထားတာ သတိပြုပါ -
const outline = await createOutline(topic);
const reviewedOutline = await reviewOutline(
topic,
outline,
);
const lesson = await writeLesson(
topic,
reviewedOutline,
);
ဒါဟာ အရေးကြီးတဲ့ ကွဲပြားမှု ဖြစ်ပါတယ် -
Agentic decision:
Model က သူ ဘယ် Tool ကို သုံးရမလဲဆိုတာ ရွေးချယ်တာ ဖြစ်ပါတယ်။
Workflow decision:
Program က နောက်ထပ် ဘယ်အဆင့်ကို သွားရမလဲဆိုတာ သတ်မှတ်ထားတာ ဖြစ်ပါတယ်။
ရှေ့က အလုပ်ရဲ့ ရလဒ်ပေါ် မူတည်ပြီး နောက်တစ်ဆင့်ကို လုပ်ရမယ့် နေရာမျိုးတွေမှာ ဒီလို Sequential workflow တွေက အသုံးဝင်ပါတယ်။
Parallel workflow အလုပ်လုပ်ပုံဆိုတာကတော့ အလုပ်တစ်ခုကို တစ်ခုက စောင့်ဆိုင်းနေစရာမလိုဘဲ တစ်ပြိုင်တည်း အလုပ်လုပ်ခြင်း ဖြစ်ပါတယ် -
┌── Explain benefits ──┐
Topic ────────────┼── Explain risks ─────┼── Combine
└── Give example ──────┘
ဒီနမူနာ Flow မှာ Task ၃ ခုလုံးဟာ တစ်ခုရဲ့ အဖြေကို တစ်ခုက စောင့်နေဖို့ မလိုပါဘူး။ ဒါကြောင့် Parallel ပြိုင်တူလုပ်လို့ ရပါတယ်။
နမူနာအနေနဲ့ src/07-parallel.ts
ဖိုင်မှာ အခုလိုရေးပေးပါ -
import "dotenv/config";
import { generateText } from "ai";
import { createOpenRouter } from "@openrouter/ai-sdk-provider";
const apiKey = process.env.OPENROUTER_API_KEY;
const modelName = process.env.OPENROUTER_MODEL;
if (!apiKey || !modelName) {
throw new Error(
"OPENROUTER_API_KEY and OPENROUTER_MODEL must be configured.",
);
}
const openrouter = createOpenRouter({
apiKey,
});
const model = openrouter(modelName);
async function askSpecialist(
role: string,
task: string,
): Promise<string> {
const result = await generateText({
model,
system: `
You are the ${role}.
Complete only your assigned task.
Be concise and suitable for a beginner.
`,
prompt: task,
});
return result.text;
}
async function combineResults(
topic: string,
benefits: string,
risks: string,
example: string,
): Promise<string> {
const result = await generateText({
model,
system: `
Combine the supplied specialist reports into one coherent explanation.
Use this order:
1. Main idea
2. Benefits
3. Risks
4. Example
`,
prompt: `
Topic:
${topic}
Benefits report:
${benefits}
Risks report:
${risks}
Example report:
${example}
`,
});
return result.text;
}
async function main(): Promise<void> {
const topic = "Using AI agents for software development";
console.log("Running three specialists in parallel...");
const [benefits, risks, example] = await Promise.all([
askSpecialist(
"benefits analyst",
`Explain the main benefits of ${topic}.`,
),
askSpecialist(
"risk analyst",
`Explain the main risks and limitations of ${topic}.`,
),
askSpecialist(
"example designer",
`Create one realistic beginner example of ${topic}.`,
),
]);
console.log("Combining the reports...\n");
const finalAnswer = await combineResults(
topic,
benefits,
risks,
example,
);
console.log("Benefits:");
console.log(benefits);
console.log("\nRisks:");
console.log(risks);
console.log("\nExample:");
console.log(example);
console.log("\nCombined answer:");
console.log(finalAnswer);
}
await main();
ပြီးတဲ့အခါ အခုလို Run ကြည့်လိုက်ပါ -
npm run parallel
Sequential တစ်ခုပြီးတစ်ခု အလုပ်လုပ်ပုံက ဒီလိုပါ -
const benefits = await getBenefits();
const risks = await getRisks();
const example = await getExample();
Parallel ပြိုင်တူ အလုပ်လုပ်ပုံက ဒီလိုဖြစ်သွားပါတယ် -
const [benefits, risks, example] = await Promise.all([
getBenefits(),
getRisks(),
getExample(),
]);
တချို့နေရာတွေမှာ Sequential နည်းလိုအပ်ပြီး တချို့နေရာတွေမှာ Parallel က အသုံးဝင်မှာပဲ ဖြစ်ပါတယ်။
Subagent တစ်ခုမှာ ကိုယ်ပိုင် Model, Instructions, Tools နဲ့ Loop တွေ ပါဝင်နိုင်ပါတယ်၊ ဒီလိုပါ -
async function mathSubagent(
task: string,
): Promise<string> {
const result = await generateText({
model,
system: `
You are a mathematics subagent.
Use the calculator for all arithmetic.
`,
prompt: task,
tools: {
calculator: calculatorTool,
},
stopWhen: stepCountIs(5),
});
return result.text;
}
ပင်မ workflow ကနေ သူ့ကို ဒီလို လှမ်းခေါ်ရုံပါပဲ -
const result = await mathSubagent(
"Calculate the total cost of 17 items at $24 each.",
);
ဖွဲ့စည်းပုံက အောက်ပါအတိုင်း ဖြစ်ပါတယ် -
Parent workflow
↓
Math subagent
↓
Model
↓
Calculator tool
↓
Model
↓
Subagent result
↓
Parent workflow
ဘယ်အချိန်မှာ ဘာတွေခေါ်ပြီး ဘာတွေလုပ်သွားလဲ အဆင့်လိုက် သိရဖို့ဟာ အရေးပါတဲ့ လိုအပ်ချက်တစ်ခုပါ။ ဒါကြောင့် အဲ့ဒီလို လုပ်ဆောင်ချက် ရရှိဖို့ အခုလို Helper function တစ်ခုကို သုံးနိုင်ပါတယ် -
function printTrace(result: {
text: string;
steps: Array<{
text: string;
toolCalls: unknown[];
toolResults: unknown[];
}>;
}): void {
console.log("\n=== Final answer ===");
console.log(result.text);
console.log("\n=== Trace ===");
for (const [index, step] of result.steps.entries()) {
console.log(`\nStep ${index + 1}`);
if (step.text) {
console.log("Text:");
console.log(step.text);
}
if (step.toolCalls.length > 0) {
console.log("Tool calls:");
console.dir(step.toolCalls, {
depth: null,
});
}
if (step.toolResults.length > 0) {
console.log("Tool results:");
console.dir(step.toolResults, {
depth: null,
});
}
}
}
ရလဒ်တွေ ရိုက်ထုတ်တဲ့အခါ အခုလို ခေါ်ယူအသုံးပြုလိုက်ရုံပါပဲ -
const result = await generateText({
// ...
});
printTrace(result);
Prompt → Model → Text
await generateText({
model,
prompt,
});
Prompt → Model chooses tool → Application executes tool → Tool result
await generateText({
model,
prompt,
tools,
});
Prompt → Model chooses tool → Tool executes → Result returns to model → Model continues
await generateText({
model,
prompt,
tools,
stopWhen: stepCountIs(5),
});
Previous messages + Current message → Model
await generateText({
model,
messages: memory,
});
Parent → Specialized agent → Result returns to parent
js
const notes = await researchAgent(topic);
A → B → C
js
const a = await taskA();
const b = await taskB(a);
const c = await taskC(b);
┌→ A →┐
├→ B →┼→ Combine
└→ C →┘
const [a, b, c] = await Promise.all([
taskA(),
taskB(),
taskC(),
]);
ဒါက ရိုးရိုး Model call သာ ဖြစ်ပါတယ် -
await generateText({
model,
prompt,
});
ဒါမှသာ Agent စနစ် ဖြစ်ပါတယ် -
await generateText({
model,
prompt,
tools,
stopWhen: stepCountIs(5),
});
မဖြစ်သင့်သောပုံစံ: manageEverything
ဖြစ်သင့်သောပုံစံ: calculate
, getWeather
, findCustomer
, createInvoice
Tool က သေးပြီး တိကျလေလေ၊ Model အတွက် နားလည်ရလွယ်လေလေ ဖြစ်ပါတယ်။
AI Model တွေဟာ ထုံးစံအတိုင်း ရလဒ်ကို ခန့်မှန်းအလုပ်လုပ်ခြင်းသာ ဖြစ်ပါတယ်။ တိကျမှာ မဟုတ်ပါဘူး။ တိကျဖို့လိုတဲ့ ကိစ္စတွေကို ကုဒ်တွေ Function တွေနဲ့ပဲ တိတိကျကျ လုပ်ပေးရပါတယ်။
execute: async ({ a, b }) => {
return {
result: a * b,
};
}
အကန့်အသတ်မရှိ ပတ်နေမယ့် loop မျိုးကို ရှောင်ကြရပါမယ်။ အမြဲတမ်း stopWhen: stepCountIs(5)
လိုမျိုး ပါအောင် ထည့်ပေးပါ။
const memory: ModelMessage[] = [];
ဒီ Memory က program ပိတ်လိုက်ရင် ပျောက်သွားမှာ ဖြစ်ပါတယ်။ ဒါကို အမြဲသုံးဖို့ မသင့်တော်ပါဘူး။ ရေရှည်အတွက်ဆိုရင် ဖိုင် သို့မဟုတ် Database ထဲမှာ သိမ်းဖို့ လိုအပ်ပါတယ်။
မဖြစ်သင့်သောပုံစံ:
await Promise.all([
createOutline(),
writeArticleUsingOutline(),
]);
မှန်ကန်သောပုံစံ:
const outline = await createOutline();
const article = await writeArticleUsingOutline(outline);
တိတိကျကျ အလုပ်လုပ်ပါတယ်ဆိုတဲ့ Tool ရှိနေပေမယ့်လည်း အမြဲတမ်း လက်လွတ်မယုံသင့်ပါဘူး။ Model က parameter အမှားတွေ ထည့်ပေးလိုက်တာမျိုး ဖြစ်နိုင်လို့ လုပ်ဆောင်ချက် အဆင့်ဆင့်ကို အမြဲစစ်ဆေးကြည့်ဖို့ လိုပါတယ်။
ဒီအထိ ရသွားပြီးဆိုရင်တော့ Agent တွေကို ကိုယ်တိုင်တည်ဆောက်ဖို့ လိုအပ်တဲ့ အခြေခံလေးတွေ ရရှိသွားပြီ ဖြစ်ပါတယ်။ အသေးစိတ်ကို အောက်ပါ Documentation မှာ ဆက်လက်လေ့လာနိုင်ပါတယ်။
အားလုံးပဲ အဆင်ပြေကြပါစေ။