Google Gemini کا استعمال کرتے ہوئے Node.js میں فنکشن کالز کے ساتھ AI ایجنٹ کیسے بنایا جائے۔

پچھلے سال، ایک گاہک نے ہم سے اپنے اندرونی رپورٹنگ ٹول میں بات چیت کا انٹرفیس شامل کرنے کو کہا۔ جیسے ہی ملازمین سوالات درج کرتے ہیں، سسٹم ڈیٹا بیس سے حقیقی وقت کے جوابات نکالتا ہے۔

پہلا ورژن ایک دن میں تیار اور چل رہا تھا۔ ایک ہی سوال نے کام کیا۔ تاہم، ایک ہفتے بعد ٹیسٹر نے ٹائپ کیا: "برلن میں موسم کیسا ہے؟ ابھی 500 EUR کو USD میں کتنا بدلا ہے؟”

ماڈل نے اس جواب کو واپس کرنے کے لیے موسم کی تقریب کو بلایا اور سوال کے دوسرے نصف حصے کو مکمل طور پر نظر انداز کر دیا۔

یہ چیٹ بوٹس اور ایجنٹوں کے درمیان فرق ہے۔ چیٹ بوٹس تربیتی ڈیٹا کی بنیاد پر کام کرتے ہیں۔ یہ تو حد ہے۔ ایجنٹوں پر ایسی کوئی پابندی نہیں ہے۔ ٹول کو طلب کریں، جو واپس آتا ہے اسے پڑھیں، اور فیصلہ کریں کہ آیا آگے بڑھنا ہے۔

زیادہ تر سوالات ایک یا دو ٹول کالز سے حل ہو جاتے ہیں۔ ملٹی لیول کو کچھ اور چیزوں کی ضرورت ہوتی ہے: اگر آپ اس لوپ کو ہٹا دیتے ہیں تو سب کچھ ٹوٹ جاتا ہے۔

یہ ٹیوٹوریل دکھاتا ہے کہ گوگل جیمنی میں ایسے فنکشنز کا استعمال کرتے ہوئے اس لوپ کو کیسے بنایا جائے جو API اور Node.js کو کال کرتے ہیں۔ آپ ایک ایسا ایجنٹ بنائیں گے جو حقیقی دنیا کے بیرونی ٹولز کو کال کر سکے، جیسے ریئل ٹائم موسم کے لیے Open-Meteo، ریئل ٹائم ایکسچینج ریٹ کے لیے Frankfurter.app، یا حسابات کے لیے ریاضی کا جائزہ لینے والا۔ تینوں مکمل طور پر مفت ہیں۔ آپ کو صرف ایک API کلید کی ضرورت ہے Gemini، اور Google AI اسٹوڈیو بھی مفت میں روزانہ 1,500 درخواستوں کے ساتھ آتا ہے۔

سب کچھ GitHub (github.com/ziaogit/nodejs-gemini-agent) پر ہے۔

انڈیکس

فنکشن کالز کیسے کام کرتی ہیں۔

زیادہ تر LLM ٹیوٹوریلز فنکشن کالز کو اس طرح دکھاتے ہیں: فنکشن ڈیفائنڈ، ماڈل کال، مکمل۔ وہ فریمنگ دراصل اہم حصہ کو چھوڑ دیتی ہے۔

ماڈل فنکشن کو کال نہیں کرتا ہے۔ ایسا ممکن نہیں ہو سکتا۔ جو کچھ ہوتا ہے وہ مذاکرات سے ملتا جلتا ہے۔

ٹول ٹپس کی فہرست کے ساتھ ماڈل کو پیغام بھیجتا ہے۔ ہر تفصیل ایک JSON اسکیما ہے، بشمول فنکشن کا نام، فنکشن، اور مطلوبہ دلائل۔ جیمنی ان کو پڑھتا ہے جب آپ ان کی درخواست کرتے ہیں اور اس بات کا تعین کرتے ہیں کہ آیا کوئی ٹول آپ کی درخواست سے میل کھاتا ہے۔

یہ وہ حصہ ہے جو لوگوں کو حیران کر دیتا ہے۔ جیمنی کوڈ نہیں چلاتا۔ اس طرح ایک ساختی آبجیکٹ واپس بھیجیں: get_weather، city = Berlin. آپ کا کوڈ اسے اٹھاتا ہے، اصل فنکشن چلاتا ہے، اور نتائج واپس بھیجتا ہے۔ Gemini اس بات کو یقینی بناتا ہے کہ جواب دینے کے لیے یہ کافی ہے۔ اگر نہیں، تو کوئی اور آلہ طلب کریں۔

تبادلہ ایک لوپ ہے:

User message
      │
      ▼
Model + tool schemas
      │
      ▼
Response: functionCall?
      │
   YES │                          NO
      ▼                            ▼
Run the function(s)         Return text answer
      │
      ▼
Send result(s) back to model
      │
      └──── loop back ────────────┘

لوپ اس وقت تک چلتا رہتا ہے جب تک کہ ماڈل فیصلہ نہ کرے کہ یہ جواب دینے کے لیے کافی ہے۔ یہ وہی چیز ہے جو زنجیر کالوں کو ممکن بناتی ہے۔ موسم کی جانچ کریں اور دیکھیں کہ آیا درجہ حرارت 25 ° C سے زیادہ ہے، پھر فیصلہ کریں کہ کیا آپ کو جواب دینے سے پہلے ایکسچینج ریٹ بھی حاصل کرنے کی ضرورت ہے۔

ایک ایسی تفصیل ہے جو پہلے پہل لوگوں کو چوکس کر دیتی ہے۔ جب جیمنی ایک ہی جواب کے ساتھ متعدد ٹولز کی درخواست کرتا ہے، تو یہ ان سب کو چلاتا ہے اور تمام نتائج ایک ہی پیغام میں لوٹاتا ہے۔ انہیں الگ الگ پیغامات میں ایک وقت میں واپس کرنے سے ماڈل کی گردش سے باخبر رہنے کا عمل ٹوٹ جائے گا اور ناقابل بھروسہ آؤٹ پٹ پیدا ہوگا۔

ہم کیا بنا رہے ہیں

اس ٹیوٹوریل میں، ہم تین ٹاسک ٹولز کا استعمال کرتے ہوئے ایک AI ایجنٹ بناتے ہیں:

  • get_weather اوپن میٹیو کے ذریعے کسی بھی شہر کے لیے موجودہ موسم حاصل کریں (مفت، کوئی API کلید نہیں)

  • calculate — JavaScript میں ریاضی کے تاثرات کا محفوظ طریقے سے جائزہ لیں۔

  • get_exchange_rate — Frankfurter.app کے ذریعے ریئل ٹائم ایکسچینج ریٹ حاصل کریں (مفت، کوئی API کیز نہیں)

ایسا کرنے کے دو طریقے ہیں: فوری مقامی جانچ کے لیے ریڈ لائن CLI اور حقیقی ایپلی کیشنز سے منسلک ہونے کے لیے ایکسپریس HTTP اینڈ پوائنٹ۔

مکمل ٹیکنالوجی اسٹیک:

  • Node.js 20: رن ٹائم (مقامی درآمد کے لیے کم از کم نوڈ 18)

  • @google/generative-ai: آفیشل جیمنی SDK

  • Dotenb: ماحول کے متغیرات کو لوڈ کیا جا رہا ہے۔

  • اظہار: API اینڈ پوائنٹ کے لیے HTTP سرور

  • OpenMeteo API: مفت موسم اور جیو کوڈنگ، کوئی چابیاں درکار نہیں۔

  • frankfurt.app: مفت زر مبادلہ کی شرح، کوئی کلید درکار نہیں۔

فن تعمیر:

┌─────────────────────────────────────────────────┐
│                   Client                         │
│         CLI (readline) / HTTP POST               │
└──────────────────────┬──────────────────────────┘
                       │  user message
                       ▼
┌─────────────────────────────────────────────────┐
│               agent.js — Agentic Loop            │
│                                                  │
│  1. Send message + tool schemas to Gemini        │
│  2. Receive response                             │
│  3. functionCalls() present?                     │
│      YES → execute tools in parallel             │
│            send all results back                 │
│            go to step 2                          │
│      NO  → return final text answer              │
└──────────────────────┬──────────────────────────┘
                       │  tool calls
                       ▼
┌─────────────────────────────────────────────────┐
│                  Tool Handlers                   │
│                                                  │
│  get_weather(city)                               │
│    └─► geocoding-api.open-meteo.com              │
│        api.open-meteo.com                        │
│                                                  │
│  calculate(expression)                           │
│    └─► JS safe evaluator (no external call)      │
│                                                  │
│  get_exchange_rate(from, to, amount?)            │
│    └─► api.frankfurter.app                       │
└─────────────────────────────────────────────────┘

شرطیں

شروع کرنے سے پہلے، آپ کے پاس ہونا ضروری ہے:

  • Node.js 18+ — چلائیں۔ node --version چیک کریں

  • aistudio.google.com پر Gemini API کلید — مفت اور کارڈ سے پاک۔ مفت درجے میں روزانہ 1,500 درخواستیں پیش کی جاتی ہیں۔

  • آپ کو یہ بھی جاننا ہوگا کہ کیسے async/await یہ Node.js میں کام کرتا ہے۔ بس۔

پروجیکٹ کی ترتیبات

mkdir nodejs-gemini-agent && cd nodejs-gemini-agent
npm init -y
npm install @google/generative-ai dotenv express
mkdir src

اضافہ .gitignoreجیسے آپ نہیں چاہتے .env آپ کے ذخیرے میں:

node_modules/
.env

ڈراپ .env جڑ سے:

GEMINI_API_KEY=your_api_key_here
PORT=3000

# Optional: override the default model (gemini-2.0-flash)
# Uncomment if you hit free-tier quota limits
# GEMINI_MODEL=gemini-2.0-flash-lite

پروجیکٹ کی ساخت:

nodejs-gemini-agent/
├── src/
│   ├── tools.js        ← tool schemas for Gemini
│   ├── functions.js    ← actual implementations
│   ├── agent.js        ← the agentic loop
│   ├── index.js        ← CLI entry point
│   └── server.js       ← Express HTTP server
├── .env
├── .env.example
├── .gitignore
└── package.json

جیمنی آپ کا کوڈ نہیں دیکھ سکتا۔ یہ مکمل طور پر آپ کے پاس کردہ JSON اسکیما کی بنیاد پر ایک ٹول کا انتخاب کرتا ہے۔ ہر اسکیما کا ایک نام، تفصیل اور پیرامیٹر کی تعریف ہوتی ہے۔

تفصیل وہی ہے جو روٹنگ کو چلاتی ہے۔ Gemini اسے درخواست پر پڑھتا ہے اور تعین کرتا ہے کہ آپ کے سوال کے لیے کون سا ٹول صحیح ہے۔ کسی فنکشن کو کب کال کرنا ہے اس پر توجہ مرکوز کریں، نہ کہ یہ کیا کرتا ہے۔

// src/tools.js

const toolDefinitions = [
  {
    name: 'get_weather',
    description:
      'Get the current weather for a city. Returns temperature in Celsius, ' +
      'humidity percentage, and wind speed. Use this when the user asks about ' +
      'weather, temperature, or climate conditions in any location.',
    parameters: {
      type: 'OBJECT',
      properties: {
        city: {
          type: 'STRING',
          description: 'The city name, e.g. Tokyo, London, New York',
        },
      },
      required: ['city'],
    },
  },
  {
    name: 'calculate',
    description:
      'Evaluate a mathematical expression and return the numeric result. ' +
      'Use this for arithmetic, percentage calculations, or any numeric computation ' +
      'the user asks for. Do not guess at math — always call this tool.',
    parameters: {
      type: 'OBJECT',
      properties: {
        expression: {
          type: 'STRING',
          description:
            'A valid mathematical expression, e.g. "47.50 * 0.18" or "1500 / 12"',
        },
      },
      required: ['expression'],
    },
  },
  {
    name: 'get_exchange_rate',
    description:
      'Get the current exchange rate between two currencies. Can also convert ' +
      'a specific amount. Use this when the user asks about currency conversion, ' +
      'exchange rates, or how much a foreign currency amount is worth.',
    parameters: {
      type: 'OBJECT',
      properties: {
        from: {
          type: 'STRING',
          description: 'The source currency code, e.g. USD, EUR, JPY, GBP',
        },
        to: {
          type: 'STRING',
          description: 'The target currency code, e.g. USD, EUR, JPY, GBP',
        },
        amount: {
          type: 'NUMBER',
          description:
            'Amount to convert. Optional — defaults to 1 if not provided.',
        },
      },
      required: ['from', 'to'],
    },
  },
];

module.exports = { toolDefinitions };

مبہم وضاحتیں زیادہ تر معاملات میں کام کرتی ہیں۔ مسئلہ کناروں پر ظاہر ہوتا ہے۔ "کیا آپ فون سے متعلق کوئی کام کرتے ہیں؟” ایک سادہ سا سوال ہے جو اچھی طرح بولتا ہے۔ جب ابہام کی بات آتی ہے تو یہ الگ ہوجاتا ہے۔ "دو کرنسیوں کے درمیان موجودہ شرح مبادلہ حاصل کریں۔ جب صارفین کرنسی کی تبدیلی کے بارے میں پوچھیں تو استعمال کریں۔” پکڑو۔ اضافی الفاظ بنیادی طور پر کچھ بھی نہیں خرچ کرتے ہیں. غلط روٹنگ کو ڈیبگ کرنا زیادہ مہنگا ہے۔

یہ اصل فنکشن ہے جو چلتا ہے جب ماڈل اس کی درخواست کرتا ہے۔ ہر ایک کو جو بھی دلائل موصول ہوتے ہیں جو ماڈل پاس کرنے کا فیصلہ کرتا ہے، اصل کام کرتا ہے، اور ایک سادہ JavaScript آبجیکٹ واپس کرتا ہے۔

// src/functions.js

async function get_weather({ city }) {
  // Open-Meteo uses a two-step approach: geocode the city first, then fetch weather.
  // Both APIs are free with no key required.
  const geoUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(city)}&count=1`;
  const geoRes  = await fetch(geoUrl);
  const geoData = await geoRes.json();

  if (!geoData.results?.length) {
    return { error: `City not found: ${city}` };
  }

  const { latitude, longitude, name, country } = geoData.results[0];

  const weatherUrl =
    `https://api.open-meteo.com/v1/forecast` +
    `?latitude=${latitude}&longitude=${longitude}` +
    `¤t=temperature_2m,relative_humidity_2m,wind_speed_10m,weather_code`;

  const weatherRes  = await fetch(weatherUrl);
  const weatherData = await weatherRes.json();
  const current     = weatherData.current;

  return {
    city:        `${name}, ${country}`,
    temperature: `${current.temperature_2m}°C`,
    humidity:    `${current.relative_humidity_2m}%`,
    wind_speed:  `${current.wind_speed_10m} km/h`,
  };
}

function calculate({ expression }) {
  try {
    // Strip anything that is not a number or basic operator before eval.
    // This is not a complete sandbox — use a proper math parser like mathjs
    // in production if expressions come from untrusted users.
    const safe = expression.replace(/[^0-9+\-*/.() %]/g, '');
    if (!safe.trim()) return { error: 'Invalid or empty expression' };

    const result = Function('"use strict"; return (' + safe + ')')();
    return { expression, result };
  } catch {
    return { error: `Could not evaluate: ${expression}` };
  }
}

async function get_exchange_rate({ from, to, amount = 1 }) {
  const url  = `https://api.frankfurter.app/latest?from=${from.toUpperCase()}&to=${to.toUpperCase()}`;
  const res  = await fetch(url);
  const data = await res.json();

  if (data.error) return { error: data.error };

  const rate      = data.rates[to.toUpperCase()];
  if (!rate) return { error: `No rate found for ${from} → ${to}` };

  const converted = parseFloat((amount * rate).toFixed(4));

  return { from: from.toUpperCase(), to: to.toUpperCase(), rate, amount, converted };
}

module.exports = { get_weather, calculate, get_exchange_rate };

یہاں چند باتیں قابل توجہ ہیں۔

Open-Meteo موسم لانے سے پہلے جیو کوڈنگ کا استعمال کرتا ہے۔ طول البلد اور طول البلد کو براہ راست موسم کے اختتامی نقطہ پر منتقل کرنا شہر کے نام کی تار سے زیادہ قابل اعتماد ہے، اور geocoding API ہجے کی غلطیوں کو معقول حد تک ہینڈل کرتا ہے۔ یہاں دو بازیافت کالیں ہیں، لیکن یہ درستگی کے لیے ایک تجارت ہے۔

کہ calculate فنکشن تشخیص سے پہلے نمبرز اور آپریٹرز کے علاوہ ہر چیز کو ہٹا دیتا ہے۔ یہ انجیکشن کے خطرے کو کم کرتا ہے، لیکن یہ ایک حقیقی سینڈ باکس نہیں ہے۔ اگر آپ اسے HTTP کے ذریعے گمنام صارفین کے سامنے لاتے ہیں، تو ایک مناسب ریاضی کا تجزیہ کار استعمال کریں جیسے کہ mathjs۔

فرینکفرٹ درخواست کرنے سے پہلے کرنسی کوڈز کو بڑے میں بدل دیتا ہے۔ صارف "usd” یا "Usd” ٹائپ کر سکتے ہیں اور دونوں کام کریں گے۔ API آخر میں کیس حساس ہے۔

ایک ایجنٹ لوپ بنانا

یہ وہ فائل ہے جسے باقی سب سپورٹ کرتے ہیں۔ لوپ خود تقریباً 20 لائنوں کا ہے۔ باقی لاگنگ اور ایرر ہینڈلنگ ہے۔

// src/agent.js
const { GoogleGenerativeAI } = require('@google/generative-ai');
const { toolDefinitions }    = require('./tools');
const { get_weather, calculate, get_exchange_rate } = require('./functions');

const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);

// Map tool names to handler functions
const toolHandlers = { get_weather, calculate, get_exchange_rate };

async function runAgent(userMessage) {
  const model = genAI.getGenerativeModel({
    model: process.env.GEMINI_MODEL || 'gemini-2.0-flash',
    tools: [{ functionDeclarations: toolDefinitions }],
  });

  const chat = model.startChat();

  console.log(`\nUser: ${userMessage}`);
  console.log('---');

  let response = await chat.sendMessage(userMessage);
  let iterations = 0;
  const MAX_ITERATIONS = 10; // safety cap against infinite loops

  // Agentic loop
  while (iterations < MAX_ITERATIONS) {
    iterations++;
    const calls = response.response.functionCalls();

    // No tool calls — model is done, return the answer
    if (!calls || calls.length === 0) break;

    // Run all requested tools, collect results
    const toolResults = await Promise.allSettled(
      calls.map(async (call) => {
        console.log(`Calling tool: ${call.name}(${JSON.stringify(call.args)})`);

        const handler = toolHandlers[call.name];

        if (!handler) {
          return {
            functionResponse: {
              name:     call.name,
              response: { error: `Unknown tool: ${call.name}` },
            },
          };
        }

        try {
          const result = await handler(call.args);
          console.log(`Tool result: ${JSON.stringify(result)}`);
          return {
            functionResponse: {
              name:     call.name,
              response: result,
            },
          };
        } catch (err) {
          return {
            functionResponse: {
              name:     call.name,
              response: { error: err.message },
            },
          };
        }
      })
    );

    // Extract values from allSettled (fulfilled only — errors already caught above)
    const parts = toolResults
      .filter(r => r.status === 'fulfilled')
      .map(r => r.value);

    // Send all results back to the model in one message
    response = await chat.sendMessage(parts);
  }

  return response.response.text();
}

module.exports = { runAgent };

کہ MAX_ITERATIONS ٹوپی پاگل نہیں ہے. اگر ٹول غلطیاں واپس کرتا رہتا ہے اور ماڈل دوبارہ کوشش کرتا رہتا ہے، تو ماڈل ایک لوپ میں پھنس سکتا ہے۔ حقیقی سوالات کے لیے، 10 تکرار کافی ہیں۔ پیچیدہ ملٹی ٹول سوالات عام طور پر 2-3 موڑ میں حل ہوتے ہیں۔

Promise.allSettled تمام درخواست کردہ ٹولز کو ترتیب وار کے بجائے متوازی طور پر چلاتا ہے۔ اگر ماڈل ایک ہی جواب میں موسم اور شرح مبادلہ دونوں کی درخواست کرتا ہے، تو وہ بیک وقت حاصل کیے جائیں گے۔ انفرادی ٹول کی غلطیاں نقشے کے اندر پکڑی جاتی ہیں، بغیر ایک غلطی کے دوسری خرابی کے۔

لاگنگ جان بوجھ کر ہے۔ جیسا کہ آپ اپنے ایجنٹوں کو بناتے اور جانچتے ہیں، آپ حقیقی وقت میں ہونے والی ٹول کالز کو دیکھ کر بتا سکتے ہیں کہ آیا آپ کی روٹنگ کام کر رہی ہے۔ پروڈکشن کوڈ اسے کنسول آؤٹ پٹ کے بجائے ایک سٹرکچرڈ لاگر کی طرف لے جاتا ہے، لیکن معلومات ایک جیسی ہے۔

CLI انٹری پوائنٹ

require('dotenv').config() یہ پہلے چلتا ہے، لہذا آپ کی API کلید کسی اور چیز سے پہلے لوڈ ہو جاتی ہے۔ اس کے بعد ایک معیاری ریڈ لائن لوپ ہے۔ درج کی گئی ہر لائن ہے۔ runAgentجواب پرنٹ کیا جاتا ہے اور لوپ اگلے ان پٹ کا انتظار کرتا ہے۔

// src/index.js
require('dotenv').config();
const readline     = require('readline');
const { runAgent } = require('./agent');

const rl = readline.createInterface({
  input:  process.stdin,
  output: process.stdout,
});

function ask(prompt) {
  return new Promise(resolve => rl.question(prompt, resolve));
}

async function main() {
  console.log('Gemini Agent — type your question, or "exit" to quit\n');

  while (true) {
    const input = await ask('You: ');
    if (input.toLowerCase() === 'exit') break;
    if (!input.trim()) continue;

    try {
      const answer = await runAgent(input);
      console.log(`\nAgent: ${answer}\n`);
    } catch (err) {
      console.error(`Error: ${err.message}`);
    }
  }

  rl.close();
}

main();

ایکسپریس HTTP سرور شامل کریں۔

CLI جانچ کے لیے مفید ہے۔ آپ کی ایپ میں انضمام کے لیے ایک HTTP اینڈ پوائنٹ درکار ہے۔

// src/server.js
require('dotenv').config();
const express      = require('express');
const { runAgent } = require('./agent');

const app  = express();
const PORT = process.env.PORT || 3000;

app.use(express.json());

app.post('/agent', async (req, res) => {
  const { message } = req.body;

  if (!message || typeof message !== 'string') {
    return res.status(400).json({ error: 'message is required and must be a string' });
  }

  try {
    const answer = await runAgent(message);
    res.json({ answer });
  } catch (err) {
    console.error('[agent error]', err.message);
    res.status(500).json({ error: 'Agent failed to process the request' });
  }
});

app.listen(PORT, () => {
  console.log(`Agent server running on http://localhost:${PORT}`);
});

شروع کریں:

node src/server.js

براہ کرم کال کریں:

curl -X POST http://localhost:3000/agent \
  -H "Content-Type: application/json" \
  -d '{"message": "What is the weather in Paris?"}'

جواب:

{
  "answer": "The current weather in Paris, France is 19°C with 65% humidity and wind speeds of 12 km/h."
}

POST باڈی آسان ہے۔ { message } اعتراض جواب صاف ہے۔ { answer } تار آپ کا ایجنٹ باقی کو سنبھالے گا۔

ایجنٹ ٹیسٹ

CLI شروع کریں۔

node src/index.js

کہ You: پرامپٹ ریڈ لائن سے آتا ہے۔ index.js. کہ User: لائن اور --- حد بندی بذریعہ لکھا گیا ہے: agent.js ہر رن کے آغاز میں۔ یہ وہی لاگنگ ہے جسے ایجنٹ لوپ سیکشن میں بیان کیا گیا ہے۔

سنگل ٹول – موسم:

You: What's the weather in Tokyo?

User: What's the weather in Tokyo?
---
Calling tool: get_weather({"city":"Tokyo"})
Tool result: {"city":"Tokyo, JP","temperature":"31°C","humidity":"72%","wind_speed":"8 km/h"}

Agent: The current weather in Tokyo, Japan is 31°C with 72% humidity and wind speeds of 8 km/h.

دو ٹولز – سلسلہ کا اندازہ:

You: What is the weather in Tokyo? If it's above 20°C, convert 10000 JPY to EUR.

User: What is the weather in Tokyo? If it's above 20°C, convert 10000 JPY to EUR.
---
Calling tool: get_weather({"city":"Tokyo"})
Tool result: {"city":"Tokyo, JP","temperature":"31°C","humidity":"72%","wind_speed":"8 km/h"}

Calling tool: get_exchange_rate({"from":"JPY","to":"EUR","amount":10000})
Tool result: {"from":"JPY","to":"EUR","rate":0.006,"amount":10000,"converted":60.0}

Agent: The current temperature in Tokyo is 31°C, which is above 20°C.
Converting 10,000 JPY to EUR at the current exchange rate gives approximately 60.00 EUR.

کیا ہوا نوٹس کریں۔ get_weatherیہ نتیجہ (31 ° C) پڑھتا ہے، صارف کے سوال کے لیے اپنی مشروط منطق کا اطلاق کرتا ہے، اور اسے کال کرتا ہے۔ get_exchange_rate. آپ نے کوئی برانچنگ منطق نہیں لکھی ہے۔ ماڈل نے اسے صرف تفصیل کے ساتھ سنبھالا۔

کیلکولیٹر:

You: How much is 18% tip on a $47.50 restaurant bill?

User: How much is 18% tip on a $47.50 restaurant bill?
---
Calling tool: calculate({"expression":"47.50 * 0.18"})
Tool result: {"expression":"47.50 * 0.18","result":8.55}

Agent: An 18% tip on a $47.50 bill is $8.55, making your total $56.05.

ایک سوال میں تین ٹولز ہیں:

You: What's the weather in London and Berlin? And what is 250 GBP in EUR?

User: What's the weather in London and Berlin? And what is 250 GBP in EUR?
---
Calling tool: get_weather({"city":"London"})
Calling tool: get_weather({"city":"Berlin"})
Calling tool: get_exchange_rate({"from":"GBP","to":"EUR","amount":250})
Tool result: {"city":"London, GB","temperature":"16°C","humidity":"78%","wind_speed":"20 km/h"}
Tool result: {"city":"Berlin, DE","temperature":"22°C","humidity":"55%","wind_speed":"14 km/h"}
Tool result: {"from":"GBP","to":"EUR","rate":1.17,"amount":250,"converted":292.5}

Agent: London is currently 16°C with 78% humidity and 20 km/h winds.
Berlin is warmer at 22°C with 55% humidity and lighter winds of 14 km/h.
250 GBP converts to approximately 292.50 EUR at the current exchange rate.

تینوں اوزار متوازی طور پر چلائے جاتے تھے۔ Promise.allSettled یہی وجہ ہے۔ ترتیب وار لوپ تین سیریل نیٹ ورک کی درخواستوں کو انجام دیتا ہے۔ متوازی تقریباً سب سے سست واحد درخواست کے وقت پر وہی نتائج دیتا ہے۔

مسئلہ حل

یہاں کچھ عام مسائل ہیں جن کا آپ کو سامنا ہو سکتا ہے اور ان کا حل۔

[404 Not Found] models/gemini-1.5-flash is not found for API version v1beta

ماڈل کا نام پرانا ہے۔ Google وقت کے ساتھ ساتھ پرانے عرفی ناموں کو فرسودہ کرتا ہے۔ کے ساتھ تبادلہ کریں gemini-2.0-flash کو agent.js. یہ چیک کرنے کے لیے کہ آپ کی کلید کو اصل میں کن ماڈلز تک رسائی حاصل ہے، چلائیں:

node -e "
const { GoogleGenerativeAI } = require('@google/generative-ai');
require('dotenv').config();
const g = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);
g.listModels().then(r => r.models.forEach(m => console.log(m.name)));
"

2. [429 Too Many Requests] You exceeded your current quota

کہ gemini-2.0-flash مفت درجہ فی دن 1,500 درخواستوں تک محدود ہے۔ دبانے پر، آدھی رات تک کی تمام کالز کاونٹر کو دوبارہ ترتیب دیتے ہوئے، 429 واپس آ جائیں گی۔

غلطی براہ راست کوٹہ ID کا نام دیتی ہے۔ GenerateRequestsPerDayPerProjectPerModel-FreeTier اس کا مطلب ہے کہ آپ اپنی یومیہ حد تک پہنچ گئے ہیں۔ GenerateRequestsPerMinutePerProjectPerModel-FreeTier اس کا مطلب فی منٹ کی شرح ہے۔

فی منٹ کی حد کے لیے، غلطیوں میں شامل ہیں: retryDelay میدان براہ کرم چند سیکنڈ انتظار کریں اور دوبارہ کوشش کریں۔ روزانہ کی حدود کے لیے، کوٹہ فی پروجیکٹ کی بنیاد پر لاگو ہوتا ہے۔ ایک ہی پروجیکٹ سے تعلق رکھنے والے تمام ماڈلز اس کا اشتراک کرتے ہیں۔

تین طریقے ہیں:

  • نئے منصوبے (تیز ترین): aistudio.google.com پر جائیں، ایک نیا پروجیکٹ شروع کریں، ایک نئی API کلید حاصل کریں، اور .env. آپ کو اپنا نیا مختص فوری طور پر موصول ہو جائے گا۔

  • ادائیگی کو چالو کریں۔: بلنگ کے قابل منصوبے مفت استعمال کے درجے کو برقرار رکھتے ہوئے بہت زیادہ حدیں حاصل کرتے ہیں۔ براہ کرم اسے aistudio.google.com پر سیٹ کریں۔

  • انتظار کرو: روزانہ آدھی رات کو پیسیفک ٹائم پر ری سیٹ ہوتا ہے۔

کیونکہ agent.js ماڈل کا نام پڑھیں۔ process.env.GEMINI_MODELآپ کسی کوڈ کو چھوئے بغیر بھی ماڈلز کو تبدیل کر سکتے ہیں۔ یہ آپ کا ہے۔ .env ہلکے ماڈل کے ساتھ ٹیسٹ کرنے کے لیے:

GEMINI_MODEL=gemini-2.0-flash-lite

کوٹہ دوبارہ ترتیب دیا جاتا ہے اور ایجنٹ دوبارہ شروع ہوتا ہے۔ gemini-2.0-flash.

Error: GEMINI_API_KEY is not set

دس میں سے نو بار، require('dotenv').config() یہ غائب ہے یا دیگر ضروریات کے تحت دفن ہے۔ اسے اوپر کی طرف گھسیٹیں۔ index.js. آپ کا .env یہ آپ کے پروجیکٹ کی جڑ میں بھی ہونا چاہیے، جس میں اصل کلید موجود ہے۔ your_api_key_here.

4. GoogleGenerativeAIError: 400 INVALID_ARGUMENT

یہ تقریبا ہمیشہ غلط ٹول اسکیما ہوتا ہے۔ Gemini بڑے حروف کی قسم کے تار استعمال کرتا ہے۔ 'OBJECT'، 'STRING'، 'NUMBER'. JSON اسکیما چھوٹے حروف کا استعمال کرتا ہے۔ آپ کا parameters.type قدر

5. ٹول کو کال کیے بغیر ماڈل کا جواب

تفصیل یا تو بہت مبہم ہے یا صارف کا سوال ماڈل کے روٹ کے لیے کافی مطابقت نہیں رکھتا۔ ٹول کو کب استعمال کیا جانا چاہیے اس کی تفصیل میں مزید سیاق و سباق شامل کریں۔ جملہ "اس کو استعمال کریں جب صارف X کے بارے میں پوچھے” براہ راست روٹنگ کی درستگی کو بہتر بناتا ہے۔

TypeError: fetch is not a function

نوڈ 17 سے نیچے کوئی مقامی نہیں ہے۔ fetch. نوڈ 18 میں شامل کیا گیا۔ node --version اپنا چیک کرنے کے لیے۔

اگر آپ اپ گریڈ نہیں کر سکتے ہیں، تو استعمال کرکے انسٹال کریں: npm install node-fetch. تمام فائلیں کال کر رہی ہیں۔ fetch پھر آپ کو اس کی ضرورت ہے۔ const fetch = require('node-fetch') پہلی لائن تک۔

7. ٹول آزادانہ طور پر کام کرتا ہے، لیکن ایجنٹ لوپ اسے کال نہیں کرتا ہے۔

نام ہے۔ toolDefinitions یہ کلید سے بالکل مماثل ہونا چاہئے۔ toolHandlers. جاوا اسکرپٹ میں، معاملات اہم ہیں۔ get_Weather اور get_weather دو مختلف چیزیں ہیں۔

8. زر مبادلہ کی شرح واپسی No rate found

آپ کا پاس کردہ کرنسی کوڈ Frankfurter.app کے ذریعے تعاون یافتہ نہیں ہے۔ API 30 بڑی کرنسیوں تک کا احاطہ کرتا ہے۔ Frankfurter.app میں تعاون یافتہ کوڈز دیکھیں۔

آگے کیا بنانا ہے۔

یہاں کے تین اوزار بنیاد ہیں۔ لوپس اسی طرح کام کرتے ہیں چاہے آپ کتنے ہی ٹولز شامل کریں۔

ڈیٹا بیس استفسار کے اوزار: کوئی راستہ نہیں search_products PostgreSQL ٹیبلز سے استفسار کرنے کی صلاحیت ایجنٹ کو پروڈکٹ اسسٹنٹ میں بدل دیتی ہے۔ کیٹلاگ کی طرف اشارہ کرکے، آپ بغیر کسی روٹنگ منطق لکھے دستیابی، قیمتوں اور وضاحتوں کے بارے میں سوالات کے جواب دے سکتے ہیں۔

تحریری اوزار: get_* فنکشن ایجنٹ کو صرف پڑھنے کے لیے بناتا ہے۔ اضافہ create_ticket یا send_notification فعالیت ایجنٹوں کو معاونت کی درخواستیں جمع کروانے، ورک فلو کو متحرک کرنے، اور ریکارڈ کو اپ ڈیٹ کرنے جیسے اقدامات کرنے کی اجازت دیتی ہے۔ تحریری اوزار شامل کرنے کے بعد، درج ذیل کے بارے میں احتیاط سے سوچیں: ایسے سوالات جن پر عمل درآمد سے پہلے تصدیق کی ضرورت ہوتی ہے۔.

کراس سیشن میموری: ابھی model.startChat() جب بھی آپ کال کریں ایک نئی گفتگو بنائیں۔ گزرنا history جب آپ چیٹنگ شروع کرتے ہیں، تو آپ صف کو ترتیب دیتے ہیں اور ماڈل آپ کے پچھلے موڑ کو یاد رکھتا ہے۔ اپنے صارف ID کے مطابق اس ریکارڈ کو PostgreSQL یا Redis میں اسٹور کریں، اور ایجنٹ پورے سیشن میں سیاق و سباق کو پاس کرتا ہے۔

سلسلہ بندی کا جواب: UI کے لیے جو مکمل جواب کا انتظار کرنے کی بجائے آپ کے ٹائپ کرتے وقت جوابات دکھاتا ہے۔ chat.sendMessage کے ساتھ chat.sendMessageStream. ٹول کال لوپ وہی رہتا ہے۔ صرف حتمی جواب کی ترسیل میں تبدیلی آتی ہے۔

ماڈل تبدیل کریں: کہ model ایک تار ڈالیں getGenerativeModel یہ صرف وہی چیز ہے جو جیمنی 2.0 فلیش پر طے شدہ ہے۔ gemini-2.0-flash-lite سادہ سوالات کے لیے یہ ہلکا اور تیز ہے۔ پیچیدہ کاموں پر زیادہ طاقتور نتائج کے لیے، چلائیں: listModels تازہ ترین دستیاب ماڈل تلاش کرنے کے لیے براہِ کرم ٹربل شوٹنگ سیکشن میں اسکرپٹ سے رجوع کریں۔ فنکشن کال انٹرفیس تمام جیمنی ماڈلز کے لیے یکساں ہے، لہذا تبدیلی کے لیے ایک لائن کی ضرورت ہے۔

اس مضمون کا مکمل سورس کوڈ GitHub (github.com/ziaogit/nodejs-gemini-agent) پر ہے۔

اوپر تک سکرول کریں۔