ماسٹرا بمقابلہ لینگ چین: بلڈنگ AI ایجنٹ پائپ لائن اور ڈیٹا تجزیہ

ایک ہفتہ پہلے میں نے مندرجہ ذیل ٹویٹ دیکھا:

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

میں نے اسے پسند کیا .dowhile() لوپس، ان پٹ سٹیپ اسکیما اور طریقے createWorkflow آرکیسٹریشن منطق کو ایک جگہ رکھا گیا۔ جو چیز مجھے پسند نہیں تھی وہ ٹوکن اوور ہیڈ تھا۔ ایجنٹ کے تمام اقدامات، قطع نظر اس کے کہ کسی ٹول کی ضرورت ہے یا نہیں، چار مراحل کی پائپ لائن کے ذریعے انجام دیے جاتے ہیں جو ماسٹرا کے ٹول لوپ مینیجر کو شروع کرتی ہے اور اس میں کئی سیکنڈز تک اضافی تاخیر اور ہزاروں اضافی ٹوکنز فی ایگزیکیوشن شامل ہوتی ہیں۔

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

وعدہ زیادہ جامع عملدرآمد اور ہر ماڈل کال میں کیا جاتا ہے اس پر واضح کنٹرول ہے۔ یہ بالکل وہی تھا جو میں نے ماسٹرا کے ساتھ دیکھا ٹوکن اوور ہیڈ پر غور کرتے ہوئے درست کرنا چاہتا تھا۔

لہذا دستاویزات اور احساس کی بنیاد پر ایک کو منتخب کرنے کے بجائے، ہم نے دونوں کے لیے ایک ہی پائپ لائن بنائی اور ہر چیز کی پیمائش کی۔ وہی پانچ مرحلوں پر مشتمل تحقیق اور ترکیب کی پائپ لائن (ہر حصے میں آلہ بنایا گیا ہے): ٹوکن فی اسٹیج، فی اسٹیج میں تاخیر، ہر مرحلے پر کلاڈ کو بھیجے گئے قطعی اشارے، خام Tavily تلاش کے نتائج، اور ایک پروڈکشن گریڈنگ سسٹم جو حقیقت میں ہر چیز کو 7 دینے کے بجائے مختلف قسم کے اسکور تیار کرتا ہے۔

اس کے بعد ہم Convex اور Next.js پر ایک ریئل ٹائم ویب ڈیش بورڈ بنا سکتے ہیں تاکہ صارف براہ راست کسی بھی موضوع پر جا سکیں اور وہاں تک پہنچنے کے لیے دونوں فریم ورک کے ہر فیصلے کو دیکھ سکیں۔

ماسٹرا بمقابلہ لینگ چین ڈیش بورڈ دونوں پائپ لائنوں کو ساتھ ساتھ مکمل کر رہا ہے۔ ماسٹرا نے 9,846 ٹوکنز کا استعمال کرتے ہوئے 25.2 سیکنڈ میں 9/10 اسکور کیا اور LangChain نے 7,875 ٹوکنز کا استعمال کرتے ہوئے 19.8 سیکنڈ میں 8/10 اسکور کیا۔

انڈیکس

شرطیں

اس کی پیروی کرنے اور اسے خود چلانے کے لیے، آپ کو چار چیزوں کی ضرورت ہوگی:

  • Node.js 22+: پائپ لائن پیکج جدید ترین TypeScript خصوصیات کا استعمال کرتا ہے، جس کے لیے نوڈ کے تازہ ترین ورژن کی ضرورت ہوتی ہے۔

  • انتھروپک API کلید: آپ اسے console.anthropic.com پر حاصل کر سکتے ہیں۔ Claude Haiku 4.5 سستا ہے، اس بینچ مارک کو 12 بار چلانے کے لیے صرف چند سینٹ خرچ ہوتے ہیں۔

  • Tavily API کلید: آپ اسے tavily.com پر خرید سکتے ہیں۔ مفت درجے میں ہر ماہ 1,000 تلاشیں ملتی ہیں، جو اس بینچ مارک کو بار بار چلانے کے لیے کافی ہے۔

  • محدب اکاؤنٹ: آپ Convex.dev پر سائن اپ کر سکتے ہیں۔ مفت درجے میں یہاں سب کچھ شامل ہے۔

اگر آپ کے پاس وہ ہیں تو، اس مضمون کے آخر میں سیٹنگز سیکشن آپ کو ان کے صحیح مقام کی طرف رہنمائی کرے گا۔

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

Mastra AI پر مبنی ایپلی کیشنز اور ایجنٹس بنانے کے لیے TypeScript کا پہلا فریم ورک ہے۔ خیال یہ ہے کہ آپ ان پٹ اور آؤٹ پٹ اسکیموں کا استعمال کرتے ہوئے انفرادی مراحل کی وضاحت کرتے ہیں، انہیں ورک فلو سے جوڑتے ہیں، اور فریم ورک ان کے درمیان ڈیٹا کے بہاؤ کو سنبھالتا ہے۔ اس میں ڈھانچے کے ایک خصوصیت یا رکاوٹ ہونے کے بارے میں تبصرے شامل ہیں اس پر منحصر ہے کہ آپ کیا بنانے کی کوشش کر رہے ہیں۔

لینگ چین یہ LLM ایپلیکیشنز کی تعمیر کے لیے سب سے زیادہ استعمال ہونے والے فریم ورک میں سے ایک ہے۔ یہ Python سے شروع ہوا اور اس کا TypeScript ورژن ہے۔

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

کلاڈ ہائیکو 4.5 یہ ایک ایسا ماڈل ہے جو تمام ایجنٹوں کو سپورٹ کرتا ہے۔ یہ Anthropic کا تیز ترین اور سب سے زیادہ لاگت والا ماڈل ہے، جو اسے یہاں صحیح انتخاب بناتا ہے۔

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

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

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

Next.js ڈیش بورڈز کے لیے ایک ویب فریم ورک۔ ایک ایپ روٹر، پائپ لائنوں کو چلانے کے لیے ایک API پاتھ، اور سرور کے مناسب اجزاء۔

اس پائپ لائن کو کیوں استعمال کریں؟

فریم ورک کے درمیان فرق صرف اس وقت ظاہر ہوتا ہے جب آپ انہیں حقیقت میں آگے بڑھاتے ہیں، لہذا سادہ موازنہ مفید معلومات فراہم نہیں کرتا ہے۔

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

Topic
  ↓
1. RESEARCH   (Tavily web search, 5 results with relevance scores)
2. ANALYSIS   (Extract 5 key findings, 3 themes, 1 central argument)
3. WRITE      (Draft a structured ~400-word report)
4. CRITIC     (Score the draft, provide dimension-level feedback)
5. LOOP       (Revise if score below 7, output if passes or 3 iterations used)

ہر قدم کا انتخاب اس لیے کیا گیا کہ یہ فریم ورک پر مختلف انداز میں زور دیتا ہے۔

تحقیق کے مرحلے کے لیے اصل ٹول کالز کی ضرورت ہوتی ہے، جس میں ماسٹرا کے ایجنٹ ایبسٹریکشن سب سے زیادہ بھاری وزن اٹھاتا ہے۔ تجزیہ کے مرحلے میں یہ جانچنے کے لیے JSON آؤٹ پٹ کی ضرورت ہوتی ہے کہ ہر فریم ورک آؤٹ پٹ کی شکل کو کیسے لاگو کرتا ہے۔ تحریری مرحلے میں سخت مواد کے تقاضے ہیں جو خالصتاً فوری انجینئرنگ کے ذریعے نافذ کیے گئے ہیں۔ نقاد کو فکری استدلال کا سلسلہ انجام دینا چاہیے اور ساتھ ہی ساختہ JSON تیار کرنا چاہیے، جو آپ کے خیال سے کہیں زیادہ مشکل ہے۔ اور نظرثانی لوپ ٹیسٹ شاید دو فریم ورک کے درمیان سب سے بنیادی فرق ہے: ہر ایک کس طرح مشروط تکرار کا اظہار کرتا ہے۔

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

منصوبے کی ساخت

این پی ایم ورک اسپیس کا استعمال کرتے ہوئے، سب کچھ ایک ہی ذخیرہ میں ہے۔ اس کا مطلب ہے کہ تمام پیکجز ایک ہی ذخیرہ کا اشتراک کرتے ہیں۔ node_modules آپ جڑ سے براہ راست ایک دوسرے کو درآمد کر سکتے ہیں۔

mastra-vs-langchain/
├── packages/
│   ├── mastra-pipeline/          # Mastra implementation
│   ├── langchain-pipeline/       # LangChain/LangGraph implementation
│   ├── web/                      # Next.js 16 App Router dashboard
│   └── shared/                   # Shared TypeScript types
├── convex/                       # Real-time backend
└── package.json                  # Workspace root

مشترکہ پیکج کا سب سے اہم حصہ ہے۔ PipelineCallbacks ایک انٹرفیس جو دونوں پائپ لائن کے نفاذ کو پورا کرنا ضروری ہے۔ یہ ایک معاہدہ ہے جو ڈیش بورڈ کو دونوں فریم ورک سے لائیو ایونٹس حاصل کرنے کی اجازت دیتا ہے: مرحلہ شروع، مرحلہ تکمیل، ٹوکن کاؤنٹ، اور Tavily نتائج۔ یہ سب کچھ خاص طور پر ماسٹرا یا لینگ چین کے بارے میں جانے بغیر ممکن ہے۔

// packages/shared/src/types.ts
export interface PipelineCallbacks {
  onPipelineStart: () => Promise;
  onPipelineComplete: (id: string, data: PipelineCompleteData) => Promise;
  onPipelineError: (id: string, error: string) => Promise;
  step: {
    onStepStart: (stepName: string, iteration: number, input: string) => Promise;
    onStepComplete: (stepId: string, data: StepCompleteData) => Promise;
    onStepError: (stepId: string, error: string) => Promise;
  };
}

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

مسترا پائپ لائن کی تعمیر

اگر آپ نے پہلے کبھی ماسٹرا کا استعمال نہیں کیا ہے، تو یہاں بنیادی ذہنی ماڈل ہے: آپ ان پٹ اور آؤٹ پٹ اسکیموں کے ساتھ انفرادی مراحل کی وضاحت کرتے ہیں اور انہیں ورک فلو میں جوڑتے ہیں، اور ماسٹرا ان کے درمیان ڈیٹا کے بہاؤ کا انتظام کرتا ہے۔

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

تلاش کا آلہ

ماسٹرا ٹولز استعمال کرکے بنائے گئے ہیں: createToolیہ Zod ان پٹ اسکیما ہے اور execute ایک فنکشن جو براہ راست توثیق شدہ ان پٹ وصول کرتا ہے:

// packages/mastra-pipeline/src/tools/search.ts
import { createTool } from "@mastra/core/tools";
import { z } from "zod";
import { tavily } from "@tavily/core";

const client = tavily({ apiKey: process.env.TAVILY_API_KEY! });

export let lastTavilyCapture: { query: string; results: any[] } = {
  query: "",
  results: [],
};

export function resetTavilyCapture() {
  lastTavilyCapture = { query: "", results: [] };
}

export const searchTool = createTool({
  id: "web-search",
  description: "Search the web for information on a topic",
  inputSchema: z.object({ query: z.string() }),
  execute: async ({ query }) => {
    lastTavilyCapture = { query, results: [] };
    const results = await client.search(query, {
      maxResults: 5,
      searchDepth: "basic",
    });
    lastTavilyCapture.results = results.results;
    return { results: results.results };
  },
});

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

ہمیں Tavily کے سوالات اور نتائج کو ڈیش بورڈ پر کیپچر کرنے کی ضرورت تھی تاکہ صارفین ہر عمل کے لیے اصل یو آر ایل اور متعلقہ سکور دیکھ سکیں، لیکن ہمیں ایجنٹ کے ٹول ایگزیکیوشن سیاق و سباق کے ذریعے کال بیکس کو تھریڈ کرنے کے لیے ماسٹر انٹرنلز کو بھی پیچ کرنا تھا۔ کیپچر کریں اور ماڈیول اسکوپ پر کال کریں۔ resetTavilyCapture() یہ ہر مطالعہ کے مرحلے کے آغاز میں کم خوبصورت، لیکن مکمل طور پر قابل اعتماد ہے اور پچھلے رنز کے باسی ڈیٹا کو موجودہ رن میں جانے سے روکتا ہے۔

ایجنٹ

مسترا پائپ لائن میں ہر قدم کو ایک الگ قدم کے طور پر انجام دیا جاتا ہے۔ Agent مثال اگر آپ ابھی ماسٹرا کے ساتھ شروعات کر رہے ہیں، تو آپ کو ایک چیز جاننے کی ضرورت ہے وہ یہ ہے۔ id ساتھ ساتھ میدان name. اگر آپ اسے چھوڑ دیتے ہیں، تو TypeScript مطلوبہ فیلڈز کے غائب ہونے کے بارے میں مبہم غلطیاں پھینک دے گا جو اصل مسئلہ کی طرف اشارہ نہیں کرتی ہیں۔

// packages/mastra-pipeline/src/agents/researcher.ts
export const researcherAgent = new Agent({
  name: "Researcher",
  id: "researcher",           // required in v1.41 - easy to miss
  instructions: `You are a research agent. When given a topic, use the 
  web-search tool to find 5 relevant results. Return ALL the raw search 
  results including titles, URLs, and content snippets as a formatted string.`,
  model: anthropic("claude-haiku-4-5"),
  tools: { searchTool },
});

رائٹر ایجنٹ تمام مواد کی ضروریات کو ایک علیحدہ توثیق کی پرت کے بجائے براہ راست ہدایات پر منتقل کرتا ہے۔ یہ رکاوٹوں کو ایک نظر میں رکھتا ہے، جو اس وقت اہم ہے جب ناقدین مخصوص تقاضوں پر رائے فراہم کرتے ہیں جن کی مسودہ کی خلاف ورزی ہوتی ہے۔

// packages/mastra-pipeline/src/agents/writer.ts
export const writerAgent = new Agent({
  name: "Writer",
  id: "writer",
  instructions: `You are a research analyst writing for a technical audience.

STRICT REQUIREMENTS:
- Opening sentence must state a specific finding from the research.
  Never open with "X is increasingly important."
- Every paragraph makes exactly one argument. State it first.
  Support it with specific evidence.
- Name specific tools, frameworks, companies, numbers, and dates.
- Conclusion must make a specific recommendation or prediction.
  It must not restate the introduction.
- Target length: 350-450 words.

FORBIDDEN PHRASES:
"it is important to note", "it is worth noting",
"organizations must consider", "in conclusion", "in summary",
"as we look to the future", "rapidly evolving landscape",
any sentence equally true if you replaced the topic`,
  model: anthropic("claude-haiku-4-5"),
});

writeCriticStep: لکھنا اور تنقید کرنا ایک ہی مرحلے میں کیوں ہیں؟

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

ماسٹرا کا .dowhile() شرط پوری ہونے تک بیان ایک قدم کو دہراتا ہے۔ اگر آپ کے پاس اعادہ کرنے کے لیے ایک چیز ہے تو یہ ٹھیک ہے، لیکن نظرثانی کے لیے دو چیزوں کی ضرورت ہوتی ہے: ایک تحریری مرحلہ اور ایک تنقیدی مرحلہ۔ آپ ان کو ایک قدم میں یکجا کر سکتے ہیں، یا ایک نیسٹڈ ورک فلو بنا سکتے ہیں جس میں اندرونی ورک فلو کے دونوں مراحل شامل ہوں۔

نیسٹڈ ورک فلو پیچیدگی کی ایک پرت کو شامل کرتے ہیں جو اس معاملے میں کچھ نہیں خریدتا ہے، لہذا تحریر اور تنقیدی مراحل ساتھ ساتھ چلتے ہیں۔ writeCriticStep. یہ مرحلہ پہلے مصنف کو چلاتا ہے، پھر فوری طور پر نقاد کو مسودہ پر، اور ایک مشترکہ آؤٹ پٹ واپس کرتا ہے جس میں مسودہ اور اسکور دونوں ہوتے ہیں۔

const writeCriticStep = createStep({
  id: "write-critic",
  inputSchema: z.object({
    topic: z.string(),
    research: z.string(),
    analysis: z.string(),
    keyFindings: z.array(z.string()),
    mainThemes: z.array(z.string()),
    centralArgument: z.string(),
    draft: z.string().optional(),       // populated after first iteration
    score: z.number().optional(),       // populated after first iteration
    feedback: z.string().optional(),    // populated after first iteration
    iterations: z.number().optional(),
  }),
  outputSchema: z.object({
    // ... all input fields plus draft, score, feedback, iterations
  }),
  execute: async ({ inputData }) => {
    const iteration = (inputData.iterations ?? 0) + 1;

    // WRITE phase
    let writerPrompt = `Topic: "({inputData.topic}"nnResearch:n){inputData.research}nnAnalysis:n${inputData.analysis}`;
    if (inputData.feedback && inputData.draft) {
      // On revisions, the writer sees its previous attempt and the specific feedback
      writerPrompt += `nnPrevious draft:n({inputData.draft}nnFeedback:n){inputData.feedback}`;
    }

    const writeStepId = await callbacks.step.onStepStart("write", iteration, writerPrompt.slice(0, 500));
    const writerResult = await writerAgent.generate(writerPrompt);
    const draft = writerResult.text;
    await callbacks.step.onStepComplete(writeStepId, { output: draft, /* token data */ });

    // CRITIC phase: runs immediately after write, on the same draft
    const criticPrompt = `RESEARCH:n({inputData.research}nnANALYSIS:n){inputData.analysis}nnDRAFT:n${draft}`;
    const criticStepId = await callbacks.step.onStepStart("critic", iteration, draft.slice(0, 500));
    const criticResult = await criticAgent.generate(criticPrompt);
    const parsed = extractJson(criticResult.text);
    const score = parsed?.score ?? 4;
    const feedback = parsed?.feedback ?? "Score parsing failed";
    await callbacks.step.onStepComplete(criticStepId, { output: criticResult.text, criticScore: score });

    return { ...inputData, draft, score, feedback, iterations: iteration };
  },
});

کہ .dowhile() حالت پھر چیک کرتی ہے کہ آیا دوبارہ لوپ کرنا ہے۔ پچھلا آؤٹ پٹ وصول کریں۔ writeCriticStep پسند inputDataآپ براہ راست اسکور پڑھ سکتے ہیں۔

const workflow = createWorkflow({
  id: `research-pipeline-${Date.now()}`,  // timestamp prevents conflicts on concurrent runs
  inputSchema: z.object({ topic: z.string() }),
})
  .then(researchStep)
  .then(analysisStep)
  .dowhile(
    writeCriticStep,
    async ({ inputData }) => inputData.score < 7 && inputData.iterations < 3
  )
  .commit();

کہ Date.now() ورک فلو آئی ڈیز موجود ہیں کیونکہ مسترا ورک فلو فکسڈ آئی ڈیز کے ساتھ کریش ہو جاتا ہے جب دو ایگزیکیوشن بیک وقت شروع ہوتے ہیں۔ ٹائم اسٹیمپ شامل کرنے سے ہر عمل کو ورک فلو کی ایک منفرد مثال ملتی ہے۔

ٹوکن کیپچر

کس کے بعد agent.generate() جب بلایا جاتا ہے، استعمال کا ڈیٹا نتیجہ آبجیکٹ میں محفوظ کیا جاتا ہے۔ چونکہ Mastra ورژن کے درمیان ظاہری شکل بدل جاتی ہے، ایک محفوظ طریقہ یہ ہے کہ دونوں ممکنہ فیلڈ ناموں کی جانچ کی جائے۔

const inputTokens =
  (result as any).usage?.promptTokens ??
  (result as any).usage?.inputTokens ??
  0;
const outputTokens =
  (result as any).usage?.completionTokens ??
  (result as any).usage?.outputTokens ??
  0;

LangChain پائپ لائن کی تعمیر

LangChain/LangGraph بنیادی طور پر مختلف ذہنی ماڈل کے ساتھ ایک ہی مسئلہ کو حل کرتا ہے۔

جبکہ ماسٹرا واضح طور پر درج کردہ قدمی معاہدوں کے ساتھ ایک ورک فلو فراہم کرتا ہے، لینگ گراف ایک ہدایت شدہ گراف فراہم کرتا ہے۔ نوڈس سادہ غیر مطابقت پذیر افعال ہیں، ریاست ایک واحد مشترکہ متغیر آبجیکٹ ہے جو گراف کے ذریعے بہتی ہے، اور عمل درآمد کا حکم زنجیروں کے بجائے کناروں سے طے ہوتا ہے۔ .then() فون کال

حیثیت کی تشریح

نوڈ بنانے سے پہلے، اس بات کی وضاحت کریں کہ اس کا استعمال کرتے ہوئے مشترکہ حالت کیسی نظر آئے گی: Annotation.Root. گراف میں موجود تمام نوڈس اس آبجیکٹ سے پڑھتے اور لکھتے ہیں۔

// packages/langchain-pipeline/src/graph/state.ts
export const PipelineState = Annotation.Root({
  topic: Annotation(),
  research: Annotation(),
  analysis: Annotation(),
  draft: Annotation(),
  score: Annotation(),
  feedback: Annotation(),
  iterations: Annotation(),
  finalReport: Annotation(),
  criticDimensions: Annotation

مسترا میں، ڈیٹا کے بہاؤ میں فرق اہم ہے۔ مسترا میں، ہر قدم اس بات کا اعلان کرتا ہے کہ اسے کیا ملتا ہے اور کیا واپس آتا ہے، اور فریم ورک اس معاہدے کو TypeScript کی سطح پر نافذ کرتا ہے۔

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

فیکٹری پیٹرن

لینگ گراف نوڈس سادہ مطابقت پذیر فنکشنز ہیں، اس لیے کوئی فریم ورک اوور ہیڈ، کوئی ابتدا نہیں ہے، اور آپ کا کوڈ صرف ماڈل کو کال کرتا ہے۔

مسئلہ یہ تھا کہ مجھے کال بیکس اور مشترکہ ٹوکن جمع کرنے والے کو چاروں نوڈس کے ذریعے تھریڈ کرنے کی ضرورت تھی، اور اس کے لیے باقاعدہ فنکشن میں کوئی بلٹ ان میکانزم نہیں تھا۔

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

// packages/langchain-pipeline/src/graph/nodes.ts
export function createNodes(
  callbacks: PipelineCallbacks,
  acc: { inputTokens: number; outputTokens: number }
) {
  const tavilyClient = tavily({ apiKey: process.env.TAVILY_API_KEY! });

  async function researchNode(state: PipelineStateType): Promise> {
    const stepId = await callbacks.step.onStepStart("research", 1, state.topic);
    const results = await tavilyClient.search(state.topic, { maxResults: 5, searchDepth: "basic" });
    const research = results.results
      .map((r, i) => `[({i + 1}] ){r.title}nURL: ({r.url}nContent: ){r.content}`)
      .join("nn");
    await callbacks.step.onStepComplete(stepId, {
      output: research,
      promptSent: state.topic,
      timeMs: elapsed,
      inputTokens: 0,      // research step uses Tavily, not an LLM
      outputTokens: 0,
      model: "tavily-search",
      tavilyQuery: state.topic,
      tavilyResults: JSON.stringify(results.results),
    });
    return { research };
  }

  // analysisNode, writeNode, criticNode follow the same pattern

  return { researchNode, analysisNode, writeNode, criticNode };
}

ریسرچ نوڈ 0 ٹوکن واپس کرتا ہے کیونکہ یہ LLM مداخلت کے بغیر Tavily کو براہ راست کال کرتا ہے۔ یہ بینچ مارک ڈیٹا میں نظر آنے والے کلیدی فرقوں میں سے ایک ہے۔ ہر بعد کا نوڈ براہ راست مشترکہ نوڈ میں ٹوکن جمع کرتا ہے۔ acc اعتراض:

const inputTokens = response.usage_metadata?.input_tokens ?? 0;
const outputTokens = response.usage_metadata?.output_tokens ?? 0;
acc.inputTokens += inputTokens;
acc.outputTokens += outputTokens;

لینگ چینز ChatAnthropic استعمال میں اضافہ کریں۔ response.usage_metadataیہ صاف طور پر ٹائپ کیا گیا ہے اور اسے کسی کاسٹنگ کی ضرورت نہیں ہے۔

گراف اور نوڈ نام کے تنازعات

ایک چیز جو لینگ گراف کو یاد آتی ہے وہ یہ ہے کہ نوڈ کے نام ریاستی تشریحی کلیدوں سے نہیں ٹکراتے ہیں۔ نوڈ کا نام دینا "research" رن ٹائم کی خرابی ہوتی ہے۔ کیونکہ state.research یہ پہلے سے ہی ایک ریاستی چینل کے طور پر موجود ہے اور غلطی کا پیغام اس کی وجہ نہیں بتاتا ہے۔ نام بدل دیں۔ "researcher" اور "analyzer" اسے درست کریں:

export const pipeline = new StateGraph(PipelineState)
  .addNode("researcher", researchNode)   // NOT "research": conflicts with state.research
  .addNode("analyzer", analysisNode)     // NOT "analysis": conflicts with state.analysis
  .addNode("write", writeNode)
  .addNode("critic", criticNode)
  .addEdge(START, "researcher")
  .addEdge("researcher", "analyzer")
  .addEdge("analyzer", "write")
  .addEdge("write", "critic")
  .addConditionalEdges("critic", shouldRevise, {
    revise: "write",
    end: END,
  })
  .compile();

لینگ گراف میں ترمیمی لوپس کو روٹنگ فنکشنز کے ساتھ مشروط کناروں کے طور پر دکھایا گیا ہے۔

function shouldRevise(state: PipelineStateType): string {
  if (state.score >= 7 || state.iterations >= 3) return "end";
  return "revise";
}

تمام ناقدین کو پھانسی دینے کے بعد، shouldRevise انجام دیتا ہے اور واپس کرتا ہے۔ "revise" لکھنے کے نوڈ پر واپس لوپ کریں، یا "end" گراف کو ختم کرنے کے لیے، یہ مسترا کے برابر ریاستی مشین ہے۔ .dowhile(): وہی مشروط منطق جس کا اظہار نام لوپ کنسٹرکشن کے بجائے گراف روٹنگ کے طور پر کیا گیا ہے۔

ریپر دوبارہ کوشش کریں

دونوں فریم ورک کے نتیجے میں وقفے وقفے سے TLS سیشن کے دوبارہ استعمال میں خرابیاں پیدا ہوتی ہیں جب ہم ساتھ HTTPS درخواستیں کرتے ہیں۔ غلطی یہ ہے: SSL routines:tls_get_more_records:decryption failed or bad record mac. لکیری بیک آف کے ساتھ دوبارہ کوشش کرنے والا ریپر اسے سنبھالتا ہے۔

async function retryOnFetch(fn: () => Promise, retries = 3): Promise {
  for (let i = 0; i <= retries; i++) {
    try {
      return await fn();
    } catch (e: any) {
      const shouldRetry =
        e?.message?.includes("fetch") ||
        e?.message === "fetch failed" ||
        e?.message?.includes("SSL") ||
        e?.message?.includes("ECONNRESET") ||
        e?.message?.includes("other side closed") ||
        e?.cause?.code === "ECONNRESET";
      if (i < retries && shouldRetry) {
        await new Promise((r) => setTimeout(r, 1000 * (i + 1)));
        continue;
      }
      throw e;
    }
  }
  throw new Error("unreachable");
}

ہر llm.invoke() LangChain نوڈ سے کالیں یہاں لپیٹ دی گئی ہیں۔ ویب ایپ کے API پاتھ میں ایک مساوی راستہ ہے۔ retryMutation اسی وجہ سے ہر محدب کال کے ارد گرد ایک ریپر ہوتا ہے۔

ایک نقاد نے ہر چیز کو 10 میں سے 7 نمبر دیا۔

ہم نے دونوں پائپ لائنوں کو چلا کر کئی موضوعات کا تجربہ کیا۔ موضوع، فریم ورک، یا تکرار سے قطع نظر، تمام اسکور 10 میں سے 7 تھے۔

یہ دراصل ایک اچھی طرح سے دستاویزی ناکامی کا موڈ ہے جسے LLM-as-judge bias کہتے ہیں۔ اگر آپ کسی لینگویج ماڈل سے 1 سے 10 تک کا سکور تفویض کرنے کے لیے کہتے ہیں تو ہر اسکور کی سطح کے لیے ساختی معیار اور واضح معیار فراہم کیے بغیر، یہ 7 کی طرف بڑھتا ہے۔ یہ سماجی طور پر محفوظ جواب ہے۔ معیار کا اشارہ دینے کے لیے کافی زیادہ ہے، لیکن مناسب معلوم ہونے کے لیے کافی کم ہے اور کسی حقیقی جواز کی ضرورت نہیں ہے۔ چونکہ فوری طور پر کوئی بھی چیز امتیازی سلوک پر مجبور نہیں کرتی ہے، اس لیے ماڈل کو امتیازی سلوک کرنے کی کوئی ترغیب نہیں ہے۔

میرا اصل نقاد یہ تھا:

You are a critical editor. Score the draft 1-10 on accuracy,
clarity, and depth. Return { score, feedback }.

چونکہ وہ ایک جملہ مکمل پرامپٹ تھا، اس لیے میں نے ظاہر ہے کہ ہر چیز کو 7 دے دیا۔

پروڈکشن گریڈنگ واقعی کیسی دکھتی ہے۔

میں نے جو حل استعمال کیا ہے وہ G-Eval پیپر سے ہے، جو کہ وہ نقطہ نظر بھی ہے جو DeepEval اور RAGAS جیسے ٹولز کو زیر کرتا ہے۔ کلیدی بصیرت یہ ہے کہ تینوں کو مل کر کام کرنا چاہیے۔ ججز کو اسکور تفویض کرنے سے پہلے قدم بہ قدم استدلال کرنا چاہیے، اسکور کیے جانے والے طول و عرض ایک دوسرے سے آزاد ہونے چاہئیں، اور ہر اسکورنگ لیول میں اس کے معنی کی واضح وضاحت ہونی چاہیے، نہ کہ صرف "1 برا ہے اور 10 کامل ہے۔"

لہذا میں نے تنقید کو چھ ضروری مراحل میں دوبارہ ترتیب دیا ہے، جن میں سے سبھی کو نمبر تیار کرنے سے پہلے مکمل کرنا ضروری ہے۔

  1. بلنگ آڈٹ: رپورٹ میں تمام حقائق پر مبنی دعووں کو معاون (مخصوص نتائج سے تعاون یافتہ)، قیاس آرائی (مطالعہ کی معقول توسیع)، غیر تعاون یافتہ (نتائج میں بے بنیاد)، یا فریب کاری (نتائج سے متصادم) کے طور پر درجہ بندی کی گئی ہے۔

  2. سپیشلٹی آڈٹ: تمام عام جملے اور تمام ممنوع جملے واضح طور پر نشان زد ہیں۔

  3. بصیرت کے لیے شکریہ: اس بات کو یقینی بنائیں کہ نتیجہ اصل میں تعارف کو بحال کرنے کے علاوہ کچھ شامل کرتا ہے۔

  4. جوابی جانچ: ججز کو کم از کم ایک مخصوص عقیدہ کا ذکر کرنا چاہیے جو اس مضمون کو صرف عنوان کے عنوان سے پڑھنے کے بعد قاری کو نہیں ہو سکتا۔ اگر اس کی شناخت نہیں کی جا سکتی ہے تو بصیرت کا سکور 6 سے زیادہ نہیں ہو سکتا۔

  5. جہتی اسکورنگ: ہر سطح کے لیے واضح معیار کے ساتھ تین آزاد اسکور۔

  6. فرش کے قوانین: اگر ایک جہت میں اسکور 4 یا اس سے کم ہے، تو حتمی اسکور 6 سے زیادہ نہیں ہو سکتا، قطع نظر اس کے کہ دیگر جہتیں کچھ بھی ہوں۔

زمینی اصولوں کو مخصوص وضاحت کی ضرورت ہے کیونکہ وہ اصل ناکامی کے طریقوں کا احاطہ کرتے ہیں۔ زمینی اصول کے بغیر، ایک رپورٹ جو حقائق کو فریب دیتی ہے ماخذ کی مخلصی پر 2 پوائنٹس حاصل کر سکتی ہے، لیکن اگر خاصیت اور بصیرت کافی زیادہ ہے، تو یہ وزنی اوسط پر پاسنگ سکور کے ساتھ ختم ہو جائے گی۔ ایک جہت میں سنگین ناکامی کو رپورٹ کو نا اہل قرار دینا چاہیے اور اس پر پانی نہیں ڈالنا چاہیے۔

یہ مجموعی طور پر تنقیدی اشارہ ہے جس میں ماسٹرا اور لینگ چین کانسٹنٹ پر اشتراک کرتے ہیں۔ nodes.ts:

const CRITIC_INSTRUCTIONS = `You are a senior research editor.
Catch the specific ways AI-generated reports fail.

STEP 1: CLAIM AUDIT
Classify every claim: [GROUNDED] [INFERRED] [UNSUPPORTED] [HALLUCINATED]

STEP 2: SPECIFICITY AUDIT
List sentences that are generic, use forbidden phrases, or make no
falsifiable claims. Forbidden phrases: "it is important to note",
"organizations must consider", "rapidly evolving", "as we look to the future"

STEP 3: INSIGHT AUDIT
Does the conclusion add anything not already in the introduction?

STEP 3.5: COUNTERFACTUAL CHECK
Name one specific belief a reader holds after reading this that they
would not hold from just the topic title. If you cannot identify one,
insight cannot exceed 6.

STEP 4: SCORE EACH DIMENSION

SOURCE FIDELITY (40% weight):
5-6: Claims accurate but traced to general topic knowledge, not these specific results
7:   Most claims traceable, at least one source cited by name
8:   All major claims grounded, two or more named sources with specific details
9-10: Every claim traces to a named source, at least one statistic used

SPECIFICITY (30% weight):
5-6: Some specific claims but generic analysis between paragraphs
7:   Mostly specific, minor filler remains
8:   Every paragraph falsifiable, named entities throughout
9-10: Zero sentences survive if you swap the topic

INSIGHT (30% weight):
5-6: Some synthesis but conclusion could have been written before reading
7:   Conclusion makes a recommendation that follows from the evidence
8:   Identifies a tradeoff the reader has not considered
9-10: A senior engineer would reconsider an architectural decision after reading this

STEP 5: FLOOR RULE
If any dimension scores 4 or below, the final score cannot exceed 6.

STEP 6: CALCULATE
finalScore = round((fidelity * 0.40) + (specificity * 0.30) + (insight * 0.30))

Respond ONLY with this JSON:
{
  "fidelity": <1-10>,
  "fidelityReasoning": "",
  "specificity": <1-10>,
  "specificityReasoning": "",
  "insight": <1-10>,
  "insightReasoning": "",
  "score": ,
  "feedback": ""
}`;

کیونکہ نقاد اب JSON بنانے سے پہلے استدلال کے کئی پیراگراف لکھتا ہے۔ JSON.parse(result.text) ایسا اس لیے ہوتا ہے کیونکہ جواب اب خالص JSON نہیں ہے۔ اس سے پہلے کہ اس مسئلے کی نشاندہی کی جائے اور اسے درست کیا جائے، متبادل قدر تھی۔ 4 جب بھی کوئی تجزیہ ناکام ہوتا ہے تو یہ خود بخود واپس آجاتا ہے۔ اس کا مطلب یہ ہے کہ ہر لوپ نے ہر موضوع کے لیے کل تین تکراریں کیں۔

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

function extractJson(text: string): any {
  try { return JSON.parse(text.trim()); } catch {}

  const matches = text.match(/{[sS]*}/g);
  if (matches) {
    for (let i = matches.length - 1; i >= 0; i--) {
      try { return JSON.parse(matches[i]); } catch {}
    }
  }

  const fenced = text.match(/```(?:json)?s*([sS]*?)```/);
  if (fenced) {
    try { return JSON.parse(fenced[1].trim()); } catch {}
  }

  return null;
}

درجہ بندی کا تعصب جس نے مجھے تقریباً اسے بھیج دیا۔

ایک اہم تعمیر نو کے بعد سب کچھ ٹھیک کام کیا۔ پہلے ڈرافٹ کا سکور 4-6 تھا، جس نے نظرثانی کا آغاز کیا اور نظر ثانی دراصل پچھلی کوشش کے مقابلے میں بہتری تھی۔

تاہم، ٹیکنالوجی کے موضوعات میں واضح نمونے سامنے آئے۔ ماسٹرا ہر ایک مضمون پر مسلسل 8-9 اسکور کرتا ہے، جبکہ لینگ چین مسلسل 6-7 اسکور کرتا ہے۔

یہ دیکھتے ہوئے کہ ناقدین نے اصل میں اس مسئلے کا انکشاف کیا ہے۔ سورس فیڈیلیٹی فائنل اسکور کا 40% حصہ ہے اور انعامات کی رپورٹس جو Tavily نتائج میں مخصوص ناموں کے ساتھ ذرائع کا حوالہ دیتے ہیں۔ مسترا کی رپورٹ "Kore.ai's analysis shows" اور "ArXiv paper on coordinated multi-gent systems" جیسے جملے سے بھری ہوئی تھی۔ LangChain کی رپورٹ نے بھی یہی بات کی ہے لیکن اسے کسی مخصوص ذریعہ سے منسوب نہیں کیا ہے۔

اس کی وجہ ہر پائپ لائن کے ذریعے سیاق و سباق کا بہاؤ تھا۔ ماسٹرا کی ایجنٹ کلاس ٹول لوپ کے ذریعے تمام Tavily مواد (عنوان، URL، مواد کا ٹکڑا) گفتگو کی تاریخ میں منتقل کرتی ہے۔ جب تک مصنف کا ایجنٹ چلتا ہے، تمام ماخذ مواد سیاق و سباق میں دستیاب ہوتا ہے۔

دوسری طرف LangChain تحریری نوڈس صرف موصول ہوئے۔ state.analysisایک منظم JSON ہے جو مطالعہ سے نکالا گیا ہے (اہم نتائج، تھیمز، اور مرکزی دلائل)۔ جب JSON بنایا جاتا ہے، تو کچھ ماخذ کی تفصیلات پہلے ہی خلاصہ کر دی جاتی ہیں۔ مصنف نے ایک نتیجہ اخذ کیا لیکن اس کا حوالہ نہیں دیا۔

دونوں پائپ لائنوں کو ہر فریم ورک کے محاورے کے مطابق درست طریقے سے لاگو کیا گیا تھا، لیکن اس کا احساس کیے بغیر مختلف ان پٹ فراہم کر رہے تھے۔ تشخیصی نظام نے ایک فریم ورک کو بہتر رپورٹس پیش کرنے کے بجائے زیادہ سیاق و سباق کے ساتھ نوازا، اور تمام تکنیکی موضوعات پر مسلسل سکور کا فرق ایک اشارہ تھا۔ اصل معیار کے فرق موضوعات اور مسودوں میں مختلف ہوتے ہیں، لیکن ساختی خلاء ہر بار اسی طرح ظاہر ہوتے ہیں۔

حل LangChain رائٹ نوڈ میں ایک تبدیلی ہے۔ state.research (Raw Tavily کے نتائج) state.analysis:

async function writeNode(state: PipelineStateType): Promise> {
  const prompt = `You are a research analyst writing for a technical audience.

RESEARCH (raw search results -- cite specific sources by name):
${state.research}

ANALYSIS:
${state.analysis}
({state.feedback ? `nCRITIC FEEDBACK FROM PREVIOUS DRAFT:n){state.feedback}` : ""}

${WRITER_INSTRUCTIONS}

Return ONLY the report text.`;

  const response = await retryOnFetch(() => llm.invoke(prompt));
  return { draft: response.content as string, iterations: (state.iterations ?? 0) + 1 };
}

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

ریئل ٹائم ڈیش بورڈ

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

محدب سکیما

Convex کو خاص طور پر اس کی حقیقی وقت کی صلاحیتوں کے لیے منتخب کیا گیا تھا۔ useQuery ری ایکٹ میں ہکس ڈیٹا بیس کے سوالات کو سبسکرائب کرتے ہیں اور کسی پولنگ یا ویب ساکٹ کے انتظام کے بغیر، بنیادی ڈیٹا تبدیل ہونے پر خود بخود دوبارہ پیش ہو جاتے ہیں۔

اسکیما تمام پھانسیوں کو گرانولریٹی کی تین سطحوں پر اسٹور کرتا ہے:

steps: defineTable({
  runId: v.id("runs"),
  pipelineResultId: v.id("pipelineResults"),
  framework: v.union(v.literal("mastra"), v.literal("langchain")),
  stepName: v.union(
    v.literal("research"), v.literal("analysis"),
    v.literal("write"), v.literal("critic")
  ),
  iterationNumber: v.number(),
  status: v.union(v.literal("running"), v.literal("complete"), v.literal("error")),
  promptSent: v.optional(v.string()),
  output: v.optional(v.string()),
  timeMs: v.optional(v.number()),
  inputTokens: v.optional(v.number()),
  outputTokens: v.optional(v.number()),
  model: v.optional(v.string()),
  tavilyQuery: v.optional(v.string()),
  tavilyResults: v.optional(v.string()),
  criticScore: v.optional(v.number()),
  criticFeedback: v.optional(v.string()),
  criticDimensions: v.optional(v.object({
    fidelity: v.number(),
    specificity: v.number(),
    insight: v.number(),
    fidelityReasoning: v.string(),
    specificityReasoning: v.string(),
    insightReasoning: v.string(),
  })),
}).index("by_pipeline_result", ["pipelineResultId"]),

کہ criticDimensions فیلڈ پورے G-Eval تجزیہ کو ذخیرہ کرتی ہے، لہذا ڈیش بورڈ رنگ بارز اور طول و عرض کے مخصوص انفرنس ٹیکسٹ کا استعمال کرتے ہوئے انفرادی ڈائمینشن سکور پیش کر سکتا ہے۔

فائر اینڈ فرجٹ پیٹرن

آپ کے Next.js API پاتھ میں سب سے اہم فیصلہ ہے۔ runId پائپ لائن مکمل ہونے سے پہلے۔ اگر آپ پہلے دونوں پائپ لائنوں کا انتظار کرتے ہیں، تو براؤزر عملدرآمد کے صفحہ تک پہنچنے کے لیے 30 سے ​​60 سیکنڈ تک انتظار کرے گا، اور ریئل ٹائم اپ ڈیٹس کا کوئی بھی نقطہ ضائع ہو جائے گا۔

const activeTasks = new Map>();

export async function POST(req: NextRequest) {
  const { topic, category } = await req.json();

  // Create the Convex records synchronously (these are fast)
  const runId = await retryMutation(() =>
    fetchMutation(api.runs.createRun, { topic, category, status: "running" })
  );
  const mastraResultId = await retryMutation(() =>
    fetchMutation(api.pipelineResults.createPipelineResult, {
      runId, framework: "mastra", status: "running", iterations: 0,
    })
  );
  const langchainResultId = await retryMutation(() =>
    fetchMutation(api.pipelineResults.createPipelineResult, {
      runId, framework: "langchain", status: "running", iterations: 0,
    })
  );

  // Start both pipelines without awaiting them
  const task = Promise.allSettled([
    withRetry(() => runMastraPipeline(topic, buildCallbacks(runId, mastraResultId, "mastra"))),
    withRetry(() => runLangChainPipeline(topic, buildCallbacks(runId, langchainResultId, "langchain"))),
  ]).then(async () => {
    await retryMutation(() =>
      fetchMutation(api.runs.updateRunStatus, { runId, status: "complete" })
    );
    activeTasks.delete(runId as string);
  });

  // Hold a reference in the Map so Node.js doesn't garbage-collect the promise
  activeTasks.set(runId as string, task);
  return NextResponse.json({ runId });   // returns immediately
}

ورسل میں، یہ پیٹرن اب بھی ناکام ہوجاتا ہے کیونکہ جب روٹ ہینڈلر واپس آتا ہے، سرور لیس فنکشن ختم ہوجاتا ہے، پس منظر کے وعدے کو ختم کر دیتا ہے۔ فکس استعمال کر رہا ہے: waitUntil سے @vercel/functionsیہ وعدہ کے حل ہونے تک Vercel کو عملدرآمد کے سیاق و سباق کو برقرار رکھنے کی ہدایت کرتا ہے۔

import { waitUntil } from "@vercel/functions";

waitUntil(task);
return NextResponse.json({ runId });

ریئل ٹائم اپ ڈیٹس کو سبسکرائب کریں۔

ایگزیکیوشن پیج بیک وقت تین محدب سوالات چلاتا ہے: خود عملدرآمد، پائپ لائن کے نتائج، اور ہر پائپ لائن کے نتائج کے لیے اقدامات۔

کہ "skip" سینٹینل یہاں اہم ہے: یہ Convex سے کہتا ہے کہ استفسار پر عمل کیے بغیر سبسکرپشن کو کھلا رکھیں جب تک کہ اصل دلائل دستیاب نہ ہوں۔ یہ ریس کے حالات کو روکتا ہے جہاں پائپ لائن کے نتائج کے ریکارڈ بنائے جانے سے پہلے مرحلہ وار سوالات کیے جاتے ہیں۔

const mastraSteps = useQuery(
  api.steps.getStepsForPipelineResult,
  mastraResult ? { pipelineResultId: mastraResult._id } : "skip"
);

دوبارہ کوشش کے بعد ڈپلیکیشن مرحلہ

اگر پائپ لائن TLS کی خرابی کی وجہ سے ناکام ہو جاتی ہے اور شروع سے دوبارہ کوشش کی جاتی ہے، تو کامیاب کوشش کی تاریخ کے ساتھ Convex میں ناکام کوشش کے مراحل کی تاریخ برقرار رکھی جاتی ہے۔ UI دونوں کو پیش کرتا ہے، تحقیقی کارڈز اور بقیہ مراحل کے درمیان نمایاں فرق پیدا کرتا ہے۔

ترمیم کے گروپ مرحلہ وار کئے جاتے ہیں: stepName + iterationNumber ہر آئٹم کا بہترین ورژن رکھیں۔

const stepMap = new Map();
[...steps]
  .sort((a, b) => (a._creationTime ?? 0) - (b._creationTime ?? 0))
  .forEach((s) => {
    const key = `({s.stepName}-){s.iterationNumber}`;
    const existing = stepMap.get(key);
    if (!existing) { stepMap.set(key, s); return; }
    if (s.status === "complete") { stepMap.set(key, s); return; }
    if (existing.status !== "complete") { stepMap.set(key, s); }
  });

لائیو لاگ آٹو سکرولنگ

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

function LiveLogPanel({ logs }: { logs?: LogEntry[] }) {
  const endRef = useRef(null);

  useEffect(() => {
    endRef.current?.scrollIntoView({ behavior: "smooth" });
  }, [logs?.length]);

  return (
    
{logs?.map((entry, i) => (

[{fmtTs(entry.timestamp)}] {entry.tag} {entry.message}

))}
); }

اثر انحصار ہے logs?.lengthلہذا جب بھی محدب سے کوئی نیا لاگ انٹری آتا ہے تو اسکرولنگ کو متحرک کیا جاتا ہے۔

ڈیٹا اصل میں کیا ظاہر کرتا ہے۔

رفتار: LangChain تمام رنز پر 25-45% تیز ہے۔ چھوٹے عنوانات کے لیے، وقفہ 7 یا 8 سیکنڈ تک کم کر دیا جاتا ہے، لیکن کبھی تبدیل نہیں ہوتا۔

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

چار مرحلے والی پائپ لائن کے اس پار، فی مرحلہ 2 سے 5 سیکنڈز جمع ہوتے ہیں۔ LangGraph نوڈس سادہ غیر مطابقت پذیر فنکشنز ہیں، یعنی آپ کا کوڈ آپ اور ماڈل کے درمیان کسی فریم ورک کی ابتدا کے بغیر براہ راست چلتا ہے۔

ٹوکن: ماسٹرا 1.5-2.5 گنا زیادہ ٹوکن استعمال کرتا ہے۔ اکیلے تحقیقی مرحلے نے ان میں سے زیادہ تر خلاء کو پورا کیا، کیونکہ لینگ چین کے تحقیقی نوڈس LLM کو بالکل بھی کال نہیں کرتے ہیں، بلکہ Tavily کو براہ راست کال کرتے ہیں۔

مزید عمومی موضوع پر، Mastra تقریباً 6,200 ٹوکن چلاتا ہے اور LangChain تقریباً 3,900 ٹوکن چلاتا ہے۔ Tavily کی واپسی کے مواد کی مقدار کے لحاظ سے خلا وسیع ہوتا ہے۔ اس کی وجہ یہ ہے کہ وہ مواد ماسٹرا کے ایجنٹ کی بات چیت کی سرگزشت میں ہر اگلے مرحلے پر آتا ہے۔

معیار: تشخیصی تعصب کے لیے درست کرنے کے بعد، اسکورز فریم ورک کے بجائے تمام موضوعات پر معنی خیز طور پر مختلف ہوتے ہیں۔ جب Tavily کے نتائج مخصوص اور بھرپور ہوتے ہیں تو دونوں ہی اعلی اسکورنگ رپورٹس تیار کرتے ہیں۔ دونوں مبہم یا سوانحی موضوعات کے ساتھ جدوجہد کرتے ہیں جہاں تلاش کے نتائج عام ہیں۔

7 یا 8 کے پہلے ڈرافٹ سکور کا مطلب ہے کہ تحقیق مضبوط تھی اور مصنف نے مخصوص، اچھی طرح سے حمایت یافتہ دعوے کیے تھے۔ 4 یا 5 کا مطلب یہ ہے کہ مطالعہ کے خراب نتائج آئے، مصنفین نے بنیادی طور پر عام مشاہدات کا استعمال کیا، اور ایک نظرثانی کا لوپ اس وقت تک چلتا ہے جب تک کہ مسودہ بہتر نہ ہو جائے یا تکرار کی حد تک پہنچ جائے۔

سمجھوتہ منصوبہ: ماسٹرا فریم ورک کی آرکیسٹریشن پیچیدگیوں کو سنبھالتا ہے لہذا آپ کو اس کی ضرورت نہیں ہے۔ تم لکھو .dowhile() مشروط کناروں کے بجائے، ہم مشترکہ تغیر پذیر اسٹیٹ آبجیکٹ کے بجائے ٹائپ شدہ سٹیپ سکیموں کا استعمال کرتے ہیں، اور فریم ورک گفتگو کی ریکارڈنگ اور ٹول کے عمل کو منظم کرتا ہے۔ لاگت ہر قدم پر مستقل ٹوکن اور لیٹینسی اوور ہیڈ ہے۔

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

خود ہی آزمائیں۔

لائیو ڈیمو mastra-vs-langchain.vercel.app پر ہے اور اس موازنہ کے لیے مکمل سورس کوڈ github.com/sholajegede/mastra-vs-langchain پر ہے۔ اگر آپ کو یہ کارآمد لگا، تو براہ کرم اسے ستارہ کی درجہ بندی دینے پر غور کریں۔

git clone https://github.com/sholajegede/mastra-vs-langchain.git
cd mastra-vs-langchain
npm install
cp .env.example .env
# Add ANTHROPIC_API_KEY and TAVILY_API_KEY
npx convex dev   # Terminal 1
npm run web      # Terminal 2

کھلا localhost:3000ایک موضوع درج کریں، ایک زمرہ منتخب کریں، اور دونوں کو چلائیں۔ تمام اقدامات جیسے ہی ہوتے ہیں دکھائے جاتے ہیں، تمام ٹوکنز شمار کیے جاتے ہیں، اور تاریخ کا صفحہ زمرہ کے لحاظ سے تمام سابقہ ​​رنوں کو محفوظ کرتا ہے۔

اگر آپ CrewAI، CopilotKit، یا دوسرے فریم ورک کو اپنے بینچ مارک میں شامل کرکے اس موازنہ کو مزید تفصیل سے لینا چاہتے ہیں، PipelineCallbacks انٹرفیس packages/shared یہ واحد معاہدہ ہے جس پر عمل درآمد کی ضرورت ہے۔

اگر آپ کو یہ ٹیوٹوریل کارآمد معلوم ہوا تو بلا جھجک دوسروں کے ساتھ اس کا اشتراک کریں جو فائدہ اٹھا سکتے ہیں۔ میں واقعی میں آپ کے تبصرے کی تعریف کرتا ہوں۔ آپ X پر @wani_shola کا ذکر کر سکتے ہیں یا LinkedIn پر مجھ سے رابطہ کر سکتے ہیں۔

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