بناء وكلاء ذكاء اصطناعي باستخدام Google ADK مع TypeScript

AI Bot
بواسطة AI Bot ·

جاري تحميل مشغل تحويل النص إلى كلام الصوتي...

المتطلبات الأساسية

قبل البدء، تأكد من توفر التالي:

  • Node.js 20+ مثبت على جهازك
  • TypeScript 5.x مثبت عالمياً
  • حساب Google Cloud مع تفعيل Gemini API
  • مفتاح API من Google AI Studio
  • معرفة أساسية بـ TypeScript وبيئة Node.js
  • محرر أكواد مثل VS Code

ما الذي ستبنيه

في هذا الدليل، ستبني نظام وكلاء ذكاء اصطناعي متكامل يتضمن:

  1. وكيل بحث — يبحث في الويب ويلخص النتائج
  2. وكيل تحليل — يحلل البيانات ويقدم تقارير
  3. وكيل منسق — ينسق بين الوكلاء المختلفين لإنجاز المهام المعقدة

سنستخدم Google Agent Development Kit (ADK) — إطار العمل الجديد من Google لبناء وكلاء ذكاء اصطناعي قابلين للتوسع والإنتاج.

ما هو Google ADK؟

Google Agent Development Kit (ADK) هو إطار عمل مفتوح المصدر أطلقته Google لتسهيل بناء وكلاء ذكاء اصطناعي. يتميز بـ:

  • تكامل أصلي مع Gemini — يعمل بسلاسة مع نماذج Gemini 2.x
  • نظام أدوات مرن — إضافة أدوات مخصصة بسهولة
  • إدارة ذاكرة مدمجة — حفظ واسترجاع السياق بين المحادثات
  • دعم الوكلاء المتعددين — بناء أنظمة وكلاء متعاونة
  • بنية قابلة للتوسع — من النماذج الأولية إلى الإنتاج

الخطوة 1: إعداد المشروع

ابدأ بإنشاء مشروع TypeScript جديد وتثبيت التبعيات اللازمة:

mkdir google-adk-agents
cd google-adk-agents
npm init -y

ثبّت الحزم المطلوبة:

npm install @google/adk @google/generative-ai zod dotenv
npm install -D typescript @types/node tsx

أنشئ ملف إعداد TypeScript:

npx tsc --init

عدّل ملف tsconfig.json:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "esModuleInterop": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "declaration": true,
    "sourceMap": true
  },
  "include": ["src/**/*"]
}

أنشئ هيكل المشروع:

mkdir -p src/{agents,tools,config}
touch src/index.ts src/config/env.ts

الخطوة 2: إعداد المتغيرات البيئية

أنشئ ملف .env في جذر المشروع:

GOOGLE_API_KEY=your_gemini_api_key_here
GOOGLE_CLOUD_PROJECT=your_project_id
ADK_LOG_LEVEL=info

ثم أنشئ ملف التكوين src/config/env.ts:

import dotenv from "dotenv";
import { z } from "zod";
 
dotenv.config();
 
const envSchema = z.object({
  GOOGLE_API_KEY: z.string().min(1, "Google API key is required"),
  GOOGLE_CLOUD_PROJECT: z.string().optional(),
  ADK_LOG_LEVEL: z.enum(["debug", "info", "warn", "error"]).default("info"),
});
 
export const env = envSchema.parse(process.env);

نستخدم Zod للتحقق من صحة المتغيرات البيئية عند بدء التشغيل، مما يمنع أخطاء وقت التشغيل.

الخطوة 3: إنشاء الأدوات المخصصة

الأدوات هي الطريقة التي يتفاعل بها الوكلاء مع العالم الخارجي. سنبني أداتين:

أداة البحث في الويب

أنشئ الملف src/tools/search-tool.ts:

import { Tool, ToolContext } from "@google/adk";
import { z } from "zod";
 
const searchInputSchema = z.object({
  query: z.string().describe("The search query to look up"),
  maxResults: z.number().default(5).describe("Maximum number of results"),
});
 
export const webSearchTool = new Tool({
  name: "web_search",
  description:
    "Search the web for current information on any topic. " +
    "Use this when you need up-to-date facts, news, or data.",
  inputSchema: searchInputSchema,
  async execute(input: z.infer<typeof searchInputSchema>, context: ToolContext) {
    const { query, maxResults } = input;
 
    // In production, replace with actual search API (Google Custom Search, Serper, etc.)
    const response = await fetch(
      `https://api.search-provider.com/search?q=${encodeURIComponent(query)}&num=${maxResults}`,
      {
        headers: {
          Authorization: `Bearer ${process.env.SEARCH_API_KEY}`,
        },
      }
    );
 
    if (!response.ok) {
      return {
        error: `Search failed with status ${response.status}`,
        results: [],
      };
    }
 
    const data = await response.json();
 
    return {
      query,
      results: data.results.map((r: any) => ({
        title: r.title,
        url: r.url,
        snippet: r.snippet,
      })),
      totalResults: data.totalResults,
    };
  },
});

أداة تحليل البيانات

أنشئ الملف src/tools/analysis-tool.ts:

import { Tool } from "@google/adk";
import { z } from "zod";
 
const analysisInputSchema = z.object({
  data: z.string().describe("The data to analyze (JSON string or text)"),
  analysisType: z
    .enum(["summary", "trends", "comparison", "sentiment"])
    .describe("Type of analysis to perform"),
});
 
export const dataAnalysisTool = new Tool({
  name: "analyze_data",
  description:
    "Analyze data to extract insights, trends, and patterns. " +
    "Supports summary, trend analysis, comparison, and sentiment analysis.",
  inputSchema: analysisInputSchema,
  async execute(input: z.infer<typeof analysisInputSchema>) {
    const { data, analysisType } = input;
 
    let parsedData: any;
    try {
      parsedData = JSON.parse(data);
    } catch {
      parsedData = data;
    }
 
    // Process based on analysis type
    switch (analysisType) {
      case "summary":
        return {
          type: "summary",
          dataPoints: Array.isArray(parsedData) ? parsedData.length : 1,
          summary: `Analyzed ${typeof parsedData === "object" ? Object.keys(parsedData).length : 1} data dimensions`,
          timestamp: new Date().toISOString(),
        };
 
      case "trends":
        return {
          type: "trends",
          direction: "upward",
          confidence: 0.85,
          periods: Array.isArray(parsedData) ? parsedData.length : 0,
          timestamp: new Date().toISOString(),
        };
 
      case "sentiment":
        return {
          type: "sentiment",
          overall: "positive",
          score: 0.72,
          breakdown: {
            positive: 0.72,
            neutral: 0.2,
            negative: 0.08,
          },
        };
 
      default:
        return {
          type: analysisType,
          result: "Analysis complete",
          data: parsedData,
        };
    }
  },
});

الخطوة 4: بناء وكيل البحث

الآن سنبني الوكيل الأول — وكيل البحث الذي يستخدم أداة البحث.

أنشئ الملف src/agents/search-agent.ts:

import { Agent, AgentConfig } from "@google/adk";
import { webSearchTool } from "../tools/search-tool";
 
const searchAgentConfig: AgentConfig = {
  name: "search_agent",
  model: "gemini-2.5-flash",
  description:
    "A specialized agent for searching the web and summarizing findings. " +
    "Excels at finding current information and presenting it clearly.",
  instruction: `You are a research assistant specialized in web search.
 
Your responsibilities:
1. Search for information using the web_search tool
2. Synthesize results from multiple searches
3. Present findings in a clear, structured format
4. Always cite your sources with URLs
 
Guidelines:
- Perform multiple searches to verify information
- Prioritize recent and authoritative sources
- If you cannot find reliable information, say so clearly
- Respond in the same language as the user's query`,
 
  tools: [webSearchTool],
 
  // Configure generation parameters
  generationConfig: {
    temperature: 0.3, // Lower temperature for factual responses
    maxOutputTokens: 2048,
  },
};
 
export const searchAgent = new Agent(searchAgentConfig);

الخطوة 5: بناء وكيل التحليل

أنشئ الملف src/agents/analysis-agent.ts:

import { Agent, AgentConfig } from "@google/adk";
import { dataAnalysisTool } from "../tools/analysis-tool";
 
const analysisAgentConfig: AgentConfig = {
  name: "analysis_agent",
  model: "gemini-2.5-pro",
  description:
    "An expert data analyst that processes information and generates insights.",
  instruction: `You are a data analysis expert.
 
Your responsibilities:
1. Analyze data provided to you using the analyze_data tool
2. Identify patterns, trends, and anomalies
3. Generate clear reports with actionable insights
4. Create visualizations descriptions when helpful
 
Guidelines:
- Always explain your methodology
- Quantify findings when possible
- Highlight key takeaways prominently
- Flag any data quality issues you notice
- Respond in the same language as the user's query`,
 
  tools: [dataAnalysisTool],
 
  generationConfig: {
    temperature: 0.2,
    maxOutputTokens: 4096,
  },
};
 
export const analysisAgent = new Agent(analysisAgentConfig);

الخطوة 6: بناء الوكيل المنسق (Multi-Agent)

هذا هو الجزء الأهم — الوكيل المنسق الذي يدير الوكلاء الآخرين.

أنشئ الملف src/agents/coordinator-agent.ts:

import { Agent, AgentConfig, AgentTool } from "@google/adk";
import { searchAgent } from "./search-agent";
import { analysisAgent } from "./analysis-agent";
 
// Wrap sub-agents as tools for the coordinator
const searchAgentTool = new AgentTool({
  agent: searchAgent,
  name: "research",
  description:
    "Delegate research tasks to the search agent. " +
    "Use this for finding current information from the web.",
});
 
const analysisAgentTool = new AgentTool({
  agent: analysisAgent,
  name: "analyze",
  description:
    "Delegate analysis tasks to the analysis agent. " +
    "Use this for processing data and generating insights.",
});
 
const coordinatorConfig: AgentConfig = {
  name: "coordinator",
  model: "gemini-2.5-pro",
  description:
    "The main coordinator that orchestrates research and analysis tasks.",
  instruction: `You are an AI coordinator managing a team of specialized agents.
 
Your team:
1. **Research Agent** - Use the "research" tool for web searches
2. **Analysis Agent** - Use the "analyze" tool for data processing
 
Workflow:
1. Understand the user's request
2. Break it into sub-tasks
3. Delegate to the appropriate agent(s)
4. Synthesize the results into a coherent response
 
Guidelines:
- Clearly explain your plan before executing
- Use both agents when the task requires research AND analysis
- Provide a unified, well-structured final response
- Handle errors gracefully and try alternative approaches
- Respond in the same language as the user's query`,
 
  tools: [searchAgentTool, analysisAgentTool],
 
  generationConfig: {
    temperature: 0.4,
    maxOutputTokens: 8192,
  },
};
 
export const coordinatorAgent = new Agent(coordinatorConfig);

الخطوة 7: إضافة إدارة الذاكرة

Google ADK يوفر نظام ذاكرة مدمج للحفاظ على السياق بين المحادثات.

أنشئ الملف src/config/memory.ts:

import { MemoryService, InMemoryStore, Session } from "@google/adk";
 
// For development: in-memory store
const memoryStore = new InMemoryStore();
 
// For production: use a persistent store
// import { FirestoreStore } from "@google/adk/stores";
// const memoryStore = new FirestoreStore({ projectId: env.GOOGLE_CLOUD_PROJECT });
 
export const memoryService = new MemoryService({
  store: memoryStore,
  // Configure memory retrieval
  searchConfig: {
    maxResults: 10,
    similarityThreshold: 0.7,
  },
});
 
export async function createSession(userId: string): Promise<Session> {
  return memoryService.createSession({
    userId,
    metadata: {
      createdAt: new Date().toISOString(),
      source: "tutorial-app",
    },
  });
}
 
export async function getOrCreateSession(userId: string): Promise<Session> {
  const existingSessions = await memoryService.listSessions({ userId });
 
  if (existingSessions.length > 0) {
    return existingSessions[0];
  }
 
  return createSession(userId);
}

الخطوة 8: بناء التطبيق الرئيسي

الآن سنجمع كل شيء في ملف التطبيق الرئيسي.

أنشئ الملف src/index.ts:

import { Runner } from "@google/adk";
import { coordinatorAgent } from "./agents/coordinator-agent";
import { getOrCreateSession, memoryService } from "./config/memory";
import { env } from "./config/env";
import * as readline from "readline";
 
async function main() {
  console.log("🤖 Starting AI Agent System...");
  console.log(`📋 Log level: ${env.ADK_LOG_LEVEL}`);
 
  // Create a runner for the coordinator agent
  const runner = new Runner({
    agent: coordinatorAgent,
    appName: "ai-research-assistant",
    memoryService,
  });
 
  // Get or create a session
  const userId = "demo-user";
  const session = await getOrCreateSession(userId);
  console.log(`📍 Session: ${session.id}`);
  console.log("✅ System ready! Type your questions below.\n");
 
  // Interactive CLI loop
  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
  });
 
  const askQuestion = () => {
    rl.question("You: ", async (input) => {
      const trimmed = input.trim();
 
      if (trimmed.toLowerCase() === "exit") {
        console.log("👋 Goodbye!");
        rl.close();
        process.exit(0);
      }
 
      if (!trimmed) {
        askQuestion();
        return;
      }
 
      try {
        console.log("\n🔄 Processing...\n");
 
        const response = await runner.run({
          userId,
          sessionId: session.id,
          newMessage: {
            role: "user",
            parts: [{ text: trimmed }],
          },
        });
 
        // Print the agent's response
        for (const event of response) {
          if (event.content?.parts) {
            for (const part of event.content.parts) {
              if (part.text) {
                console.log(`Agent: ${part.text}\n`);
              }
            }
          }
        }
      } catch (error) {
        console.error("❌ Error:", error);
      }
 
      askQuestion();
    });
  };
 
  askQuestion();
}
 
main().catch(console.error);

الخطوة 9: إضافة معالجة الأخطاء والمراقبة

أنشئ ملف src/config/logging.ts لتتبع أداء الوكلاء:

import { CallbackHandler, AgentEvent } from "@google/adk";
 
export class AgentLogger implements CallbackHandler {
  private startTimes = new Map<string, number>();
 
  onAgentStart(event: AgentEvent): void {
    const agentName = event.agentName;
    this.startTimes.set(agentName, Date.now());
    console.log(`[${this.timestamp()}] ▶️  Agent "${agentName}" started`);
  }
 
  onAgentEnd(event: AgentEvent): void {
    const agentName = event.agentName;
    const startTime = this.startTimes.get(agentName);
    const duration = startTime ? Date.now() - startTime : 0;
    console.log(
      `[${this.timestamp()}] ✅ Agent "${agentName}" completed in ${duration}ms`
    );
    this.startTimes.delete(agentName);
  }
 
  onToolCall(event: AgentEvent): void {
    console.log(
      `[${this.timestamp()}] 🔧 Tool "${event.toolName}" called by "${event.agentName}"`
    );
  }
 
  onError(event: AgentEvent): void {
    console.error(
      `[${this.timestamp()}] ❌ Error in "${event.agentName}":`,
      event.error
    );
  }
 
  private timestamp(): string {
    return new Date().toISOString().split("T")[1].split(".")[0];
  }
}

عدّل src/index.ts لاستخدام المراقب:

import { AgentLogger } from "./config/logging";
 
const runner = new Runner({
  agent: coordinatorAgent,
  appName: "ai-research-assistant",
  memoryService,
  callbacks: [new AgentLogger()],
});

الخطوة 10: إضافة واجهة HTTP API

لنجعل نظام الوكلاء متاحاً عبر HTTP API.

أنشئ الملف src/server.ts:

import { createServer, IncomingMessage, ServerResponse } from "http";
import { Runner } from "@google/adk";
import { coordinatorAgent } from "./agents/coordinator-agent";
import { getOrCreateSession, memoryService } from "./config/memory";
import { AgentLogger } from "./config/logging";
 
const runner = new Runner({
  agent: coordinatorAgent,
  appName: "ai-research-assistant",
  memoryService,
  callbacks: [new AgentLogger()],
});
 
async function handleChat(req: IncomingMessage, res: ServerResponse) {
  // Read the request body
  const chunks: Buffer[] = [];
  for await (const chunk of req) {
    chunks.push(chunk as Buffer);
  }
  const body = JSON.parse(Buffer.concat(chunks).toString());
 
  const { userId, message } = body;
 
  if (!userId || !message) {
    res.writeHead(400, { "Content-Type": "application/json" });
    res.end(JSON.stringify({ error: "userId and message are required" }));
    return;
  }
 
  const session = await getOrCreateSession(userId);
 
  const response = await runner.run({
    userId,
    sessionId: session.id,
    newMessage: {
      role: "user",
      parts: [{ text: message }],
    },
  });
 
  const parts: string[] = [];
  for (const event of response) {
    if (event.content?.parts) {
      for (const part of event.content.parts) {
        if (part.text) {
          parts.push(part.text);
        }
      }
    }
  }
 
  res.writeHead(200, { "Content-Type": "application/json" });
  res.end(
    JSON.stringify({
      sessionId: session.id,
      response: parts.join("\n"),
    })
  );
}
 
const server = createServer(async (req, res) => {
  // CORS headers
  res.setHeader("Access-Control-Allow-Origin", "*");
  res.setHeader("Access-Control-Allow-Methods", "POST, OPTIONS");
  res.setHeader("Access-Control-Allow-Headers", "Content-Type");
 
  if (req.method === "OPTIONS") {
    res.writeHead(204);
    res.end();
    return;
  }
 
  if (req.method === "POST" && req.url === "/chat") {
    await handleChat(req, res);
    return;
  }
 
  res.writeHead(404, { "Content-Type": "application/json" });
  res.end(JSON.stringify({ error: "Not found" }));
});
 
const PORT = process.env.PORT || 3001;
server.listen(PORT, () => {
  console.log(`🚀 Agent API server running on http://localhost:${PORT}`);
  console.log(`📡 POST /chat - Send messages to the agent`);
});

الخطوة 11: تشغيل واختبار النظام

أضف scripts التشغيل في package.json:

{
  "scripts": {
    "dev": "tsx src/index.ts",
    "server": "tsx src/server.ts",
    "build": "tsc",
    "start": "node dist/index.js"
  }
}

تشغيل الوضع التفاعلي

npm run dev

ستظهر رسالة الترحيب ويمكنك التحدث مباشرة:

🤖 Starting AI Agent System...
📋 Log level: info
📍 Session: session_abc123
✅ System ready! Type your questions below.

You: ما هي أحدث التطورات في الذكاء الاصطناعي؟

تشغيل خادم API

npm run server

اختبر باستخدام curl:

curl -X POST http://localhost:3001/chat \
  -H "Content-Type: application/json" \
  -d '{
    "userId": "user-1",
    "message": "ابحث عن أحدث أخبار Google AI وحللها"
  }'

الخطوة 12: إضافة أداة مخصصة — قاعدة بيانات

لنضف أداة للتعامل مع قاعدة بيانات لتخزين نتائج البحث:

// src/tools/storage-tool.ts
import { Tool } from "@google/adk";
import { z } from "zod";
 
// Simple in-memory storage (replace with actual DB in production)
const storage = new Map<string, any>();
 
const saveInputSchema = z.object({
  key: z.string().describe("Unique key for the data"),
  data: z.any().describe("Data to store"),
  tags: z.array(z.string()).optional().describe("Tags for categorization"),
});
 
export const storageSaveTool = new Tool({
  name: "save_data",
  description: "Save research results or analysis data for later retrieval.",
  inputSchema: saveInputSchema,
  async execute(input: z.infer<typeof saveInputSchema>) {
    const entry = {
      ...input,
      savedAt: new Date().toISOString(),
    };
    storage.set(input.key, entry);
    return { success: true, key: input.key, message: "Data saved successfully" };
  },
});
 
const retrieveInputSchema = z.object({
  key: z.string().describe("Key of the data to retrieve"),
});
 
export const storageRetrieveTool = new Tool({
  name: "retrieve_data",
  description: "Retrieve previously saved research or analysis data.",
  inputSchema: retrieveInputSchema,
  async execute(input: z.infer<typeof retrieveInputSchema>) {
    const data = storage.get(input.key);
    if (!data) {
      return { found: false, message: `No data found for key: ${input.key}` };
    }
    return { found: true, data };
  },
});

استكشاف الأخطاء وإصلاحها

خطأ: مفتاح API غير صالح

Error: API key not valid. Please pass a valid API key.

الحل: تأكد من تعيين GOOGLE_API_KEY بشكل صحيح في ملف .env وأن المفتاح مفعّل في Google AI Studio.

خطأ: تجاوز حد الطلبات

Error: 429 Resource has been exhausted

الحل: أضف تأخيراً بين الطلبات أو ارفع حد الاستخدام في Google Cloud Console.

خطأ: نموذج غير متاح

Error: Model gemini-2.5-pro is not available

الحل: تحقق من أن النموذج المطلوب متاح في منطقتك. يمكنك استبداله بـ gemini-2.5-flash كبديل.

الأداء البطيء

إذا كانت الاستجابات بطيئة:

  • استخدم gemini-2.5-flash بدلاً من pro للمهام البسيطة
  • قلل maxOutputTokens حسب الحاجة
  • فعّل البث (streaming) للاستجابات الطويلة

أفضل الممارسات

1. تصميم الأدوات

// ✅ جيد: أداة محددة الغرض
const weatherTool = new Tool({
  name: "get_weather",
  description: "Get current weather for a specific city",
  // ...
});
 
// ❌ سيء: أداة عامة جداً
const doAnythingTool = new Tool({
  name: "do_anything",
  description: "Does everything",
  // ...
});

2. التعليمات الواضحة

// ✅ جيد: تعليمات محددة مع أمثلة
instruction: `You are a financial analyst.
When asked about stocks, always include:
- Current price
- 30-day trend
- Key metrics (P/E, Market Cap)
Format as a structured table.`
 
// ❌ سيء: تعليمات غامضة
instruction: `Help with financial stuff.`

3. معالجة الأخطاء

// ✅ تعامل مع الأخطاء بشكل صريح
async execute(input) {
  try {
    const result = await externalAPI.call(input);
    return { success: true, data: result };
  } catch (error) {
    return {
      success: false,
      error: error.message,
      suggestion: "Try with different parameters"
    };
  }
}

الخطوات التالية

بعد إكمال هذا الدليل، يمكنك:

  • إضافة أدوات أخرى — ربط وكلائك بقواعد بيانات حقيقية، APIs خارجية، أو خدمات سحابية
  • استخدام Vertex AI — نشر وكلائك على Google Cloud مع Vertex AI Agent Builder
  • إضافة واجهة مستخدم — بناء واجهة React/Next.js للتفاعل مع الوكلاء
  • تفعيل البث — استخدام runner.runStreaming() لاستجابات في الوقت الحقيقي
  • إضافة اختبارات — اكتب اختبارات وحدة لأدواتك ووكلائك

الموارد المفيدة

الخلاصة

في هذا الدليل، تعلمنا كيفية بناء نظام وكلاء ذكاء اصطناعي متكامل باستخدام Google ADK مع TypeScript. غطينا إنشاء أدوات مخصصة، وبناء وكلاء متخصصين، وتنسيقهم معاً عبر وكيل منسق، وإضافة إدارة ذاكرة ومراقبة الأداء.

Google ADK يبسط عملية بناء وكلاء الذكاء الاصطناعي بشكل كبير مقارنة بالأطر الأخرى، خاصة مع تكامله الأصلي مع Gemini. سواء كنت تبني مساعداً بحثياً، أو نظام أتمتة، أو روبوت محادثة متقدم — ADK يوفر الأساس المتين للبدء والتوسع.


هل تريد قراءة المزيد من الدروس التعليمية؟ تحقق من أحدث درس تعليمي لدينا على برمجة R للمعلوماتية الحيوية: تعلم الأساسيات.

ناقش مشروعك معنا

نحن هنا للمساعدة في احتياجات تطوير الويب الخاصة بك. حدد موعدًا لمناقشة مشروعك وكيف يمكننا مساعدتك.

دعنا نجد أفضل الحلول لاحتياجاتك.

مقالات ذات صلة