Phase 16: Multi-Agent & Swarms

بروتوكولات الاتصال

العملاء الذين لا يستطيعون التحدث بنفس اللغة ليسوا فريق إنهم غرباء يصرخون في الفراغ

Type: Build

Languages: TypeScript

Prerequisites: Phase 14 (Agent Engineering), Lesson 16.01 (Why Multi-Agent)

Time: ~120 minutes

أهداف التعلم

  • تنفيذ اكتشاف أداة MCP ودعوة حتى يتمكن العملاء من استخدام الأدوات التي تعرض لها الخوادم الخارجية
  • قم ببناء بطاقة وكيل A2A ونقطة نهاية المهمة التي تسمح لوكيل واحد بتفويض العمل إلى آخر عبر HTTP
  • مقارنة MCP (الوصول إلى الأدوات) ، A2A (من وكيل إلى وكيل) ، ACP (دقيق المؤسسات) ، و ANP (الثقة اللامركزية) و شرح أي بروتوكول يحل أي مشكلة
  • توصيل بروتوكولات متعددة معا في نظام واحد حيث يقوم العملاء بتكتشيف الأدوات عبر MCP وتمرير المهام عبر A2A

المشكلة

تقسم نظامك إلى عدة وكلاء باحث ومدفوع ومتحلل إنهم بارعون في وظائفهم الفردية ولكن الآن تحتاجون إليهم للتحدث مع بعضهم البعض

محاولة أولى واضحة: إرسال السلاسل حول. الباحث يعيد بقعة من النص، ويقوم البرمجة بتفحصها على أي حال كان بإمكانه. يعمل حتى يفسر البرمجة بشكل خاطئ ملخص البحث، أو اثنين من العاملين في حالة تعطل تنتظر بعضها البعض، أو تحتاج إلى العاملين الذين بنيتهم فرق مختلفة للتعاون. فجأة "فقط إرسال السلاسل" تفكك.

هذه هي مشكلة بروتوكول الاتصال بدون عقد مشترك حول كيفية تبادل العملاء للمعلومات، أنظمة متعددة العملاء هشة، غير قابلة للدراسة،

استجاب نظام الإيكولوجيا الذكية الذكية بأربعة بروتوكولات، وحل كل منها جزء مختلف من المشكلة:

  • MCPللوصول إلى الأدوات
  • A2Aللتعاون بين العملاء
  • ACPلتحقيق قابلية للمؤسسات
  • ANPلتحقيق الهوية والثقة اللامركزية

هذه الدروس تذهب عميقة. سوف تقرأ أشكال الأسلاك الحقيقية من كل مواصفات، وبناء تنفيذات العمل، والربط الأربعة في نظام موحد.

المفهوم

منظرة البروتوكول

فكروا في هذه البروتوكولات الأربعة كطبقات، كل منها يُعالج سؤال مختلف:

flowchart TD
  ANP["ANP — How do agents trust strangers?<br/>Decentralized identity (DID), E2EE, meta-protocol"]
  A2A["A2A — How do agents collaborate on goals?<br/>Agent Cards, task lifecycle, streaming, negotiation"]
  ACP["ACP — How do agents talk in auditable systems?<br/>Runs, trajectory metadata, session continuity"]
  MCP["MCP — How does an agent use a tool?<br/>Tool discovery, execution, context sharing"]

  style ANP fill:#f3e8ff,stroke:#7c3aed
  style A2A fill:#dbeafe,stroke:#2563eb
  style ACP fill:#fef3c7,stroke:#d97706
  style MCP fill:#d1fae5,stroke:#059669

إنهم ليسوا منافسين، إنهم يحلون مشاكل مختلفة على مستويات مختلفة.

المعدل المعدني (إعادة التأهيل)

يتم تغطية MCP بعمق في المرحلة 13. التجريب السريع: MCP يوحد كيفية اتصال LLM بالأدوات الخارجية ومصادر البيانات.client-serverبروتوكول يكتشف وكيل (عميل) ويدعو الأدوات التي كشفها الخادم.

sequenceDiagram
    participant Agent as Agent (client)
    participant MCP1 as MCP Server<br/>(database, API, files)

    Agent->>MCP1: list tools
    MCP1-->>Agent: tool definitions
    Agent->>MCP1: call tool X
    MCP1-->>Agent: result

المملكة المتحدةagent-to-toolلا يساعد العملاء على التحدث مع بعضهم البعض

A2A (بروتوكول الوكيل2الوكيل)

Created by:جوجل (الآن تحت مؤسسة لينكس)lf.a2a.v1)

Spec version:1.0.1

Problem:كيف يتعاون وكلاء مستقلون ويتفاوضون ويمنحون بعضهم بعضهم بعضاً من المهام؟

A2A هو بروتوكول لpeer-to-peer agent collaborationحيث يربط MCP وكيل مع الأدوات، يربط A2A وكيل مع وكلاء آخرين.Agent Cardفي عنوان URL معروف، وكلاء آخرون يكتشفون، يتفاوضون معه، ويمنحون مهام له.

#### كيف يعمل A2A

sequenceDiagram
    participant Client as Client Agent
    participant Remote as Remote Agent

    Client->>Remote: GET /.well-known/agent-card.json
    Remote-->>Client: Agent Card (skills, modes, security)

    Client->>Remote: POST /message:send (returnImmediately)
    Remote-->>Client: Task (TASK_STATE_SUBMITTED or TASK_STATE_WORKING)

    alt Polling
        Client->>Remote: GET /tasks/{id}
        Remote-->>Client: Task status + artifacts
    else Streaming
        Client->>Remote: POST /message:stream
        Remote-->>Client: SSE: statusUpdate
        Remote-->>Client: SSE: artifactUpdate
        Remote-->>Client: SSE: statusUpdate TASK_STATE_COMPLETED, stream closes
    end

#### بطاقة العميل الحقيقي

هذا ما تبدو عليه بطاقة عميل A2A في البريةGET /.well-known/agent-card.json:

json{
  "name": "Research Agent",
  "description": "Searches documentation and summarizes findings",
  "version": "1.0.0",
  "supportedInterfaces": [
    {
      "url": "https:TOK0
      "protocolBinding": "JSONRPC",
      "protocolVersion": "1.0"
    },
    {
      "url": "https://research-agent.example.com/a2a/rest",
      "protocolBinding": "HTTP+JSON",
      "protocolVersion": "1.0"
    }
  ],
  "provider": {
    "organization": "Your Company",
    "url": "https:TOK2
  },
  "capabilities": {
    "streaming": true,
    "pushNotifications": false
  },
  "defaultInputModes": ["text/plain", "application/json"],
  "defaultOutputModes": ["text/plain", "application/json"],
  "skills": [
    {
      "id": "web-research",
      "name": "Web Research",
      "description": "Searches the web and synthesizes findings",
      "tags": ["research", "search", "summarization"],
      "examples": ["Research the latest changes in React 19"]
    },
    {
      "id": "doc-analysis",
      "name": "Documentation Analysis",
      "description": "Reads and analyzes technical documentation",
      "tags": ["docs", "analysis"],
      "inputModes": ["text/plain", "application/pdf"],
      "outputModes": ["application/json"]
    }
  ],
  "securitySchemes": {
    "bearer": {
      "httpAuthSecurityScheme": {
        "scheme": "Bearer",
        "bearerFormat": "JWT"
      }
    }
  },
  "securityRequirements": [{ "schemes": { "bearer": { "list": [] } } }]
}

أشياء مهمة يجب ملاحظتها:

  • Skillsكل واحد لديه معرف، علامات، وأنواع MIME المدعومة المدخل / الخروج. هكذا يقرر وكيل العميل ما إذا كان هذا وكيل عن بعد يمكن التعامل مع طلبه.
  • supportedInterfacesيدرج العديد من روابط البروتوكول. وكيل واحد يمكن أن يتحدث JSON-RPC، REST، و gRPC في نفس الوقت.
  • Securityيتم دمجها في البطاقة: securitySchemesأسماء كل خطة وsecurityRequirementsيُقرر أيّ منها ينطبق. العميل يعرف ما الذي يحتاجه قبل أن يقدم طلباً واحداً.

#### دورة حياة المهام

المهام هي الوحدة الأساسية للعمل في A2A. تتحرك عبر الحالات المحددة (الرسومات تنسحب TASK_STATE_المقبل الذي يحمل كل دولة على السلك):

stateDiagram-v2
    [*] --> SUBMITTED
    SUBMITTED --> WORKING
    WORKING --> INPUT_REQUIRED: needs more info
    INPUT_REQUIRED --> WORKING: client sends data
    WORKING --> COMPLETED: success
    WORKING --> FAILED: error
    WORKING --> CANCELED: client cancels
    SUBMITTED --> REJECTED: agent declines

    COMPLETED --> [*]
    FAILED --> [*]
    CANCELED --> [*]
    REJECTED --> [*]

    note right of COMPLETED
        Terminal states are immutable.
        Follow-ups create new tasks
        within the same contextId.
    end note

جميع الدول الثمانية (التفاصيل تعريف أيضا UNSPECIFIEDكحارس، يتم حذفها هنا):

StateTerminal?Meaning
TASK_STATE_SUBMITTEDNoAcknowledged, not yet processing
TASK_STATE_WORKINGNoActively being processed
TASK_STATE_INPUT_REQUIREDNoAgent needs more info from client
TASK_STATE_AUTH_REQUIREDNoAuthentication needed
TASK_STATE_COMPLETEDYesFinished successfully
TASK_STATE_FAILEDYesFinished with error
TASK_STATE_CANCELEDYesCanceled before completion
TASK_STATE_REJECTEDYesAgent declined the task

بمجرد أن تصل المهمة إلى حالة نهائية، فهي لا تتغير. لا مزيد من الرسائل. التتابع يخلق مهمة جديدة داخل نفسها contextId. . .

#### تنسيق الأسلاك

A2A يستخدم JSON-RPC 2.0 هنا ما يبدو عليه تبادل الرسائل الحقيقية:

Client sends a message:

json{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "SendMessage",
  "params": {
    "message": {
      "messageId": "msg-001",
      "role": "ROLE_USER",
      "parts": [{ "text": "Research React 19 compiler features" }]
    },
    "configuration": {
      "acceptedOutputModes": ["text/plain", "application/json"],
      "historyLength": 10
    }
  }
}

Agent responds with a task:

json{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "task": {
      "id": "task-abc-123",
      "contextId": "ctx-xyz-789",
      "status": {
        "state": "TASK_STATE_COMPLETED",
        "timestamp": "2026-03-27T10:30:00Z"
      },
      "artifacts": [
        {
          "artifactId": "art-001",
          "name": "research-results",
          "parts": [{
            "data": {
              "findings": [
                "React 19 compiler auto-memoizes components",
                "No more manual useMemo/useCallback needed",
                "Compiler runs at build time, not runtime"
              ]
            },
            "mediaType": "application/json"
          }]
        }
      ]
    }
  }
}

Streaming via SSE:

textPOST /message:stream HTTP/1.1
Content-Type: application/a2a+json
A2A-Version: 1.0

data: {"task":{"id":"task-123","contextId":"ctx-123","status":{"state":"TASK_STATE_WORKING"}}}

data: {"statusUpdate":{"taskId":"task-123","contextId":"ctx-123","status":{"state":"TASK_STATE_WORKING","message":{"messageId":"msg-002","role":"ROLE_AGENT","parts":[{"text":"Searching documentation..."}]}}}}

data: {"artifactUpdate":{"taskId":"task-123","contextId":"ctx-123","artifact":{"artifactId":"art-1","parts":[{"text":"partial findings..."}]},"append":true,"lastChunk":false}}

data: {"statusUpdate":{"taskId":"task-123","contextId":"ctx-123","status":{"state":"TASK_STATE_COMPLETED"}}}

ACP (بروتوكول الاتصال بالوكيل)

Created by:آي بي إم / بي آي آي

Spec version:0.2.0 (OpenAPI 3.1.1)

Status:الاندماج في A2A تحت مؤسسة لينكس

Problem:كيف يتواصل العملاء مع قابلية التدقيق الكاملة، استمرارية الجلسات، وتتبع المسار؟

ACP هوenterprise protocolعلى عكس ما يزعمه العديد من الموجبات، فإن ACP تفعل notاستخدام JSON-LD. إنه API REST / JSON بسيط محدد عن طريق OpenAPI. ما يجعله مميز هو TrajectoryMetadata: كل رد العميل يمكن أن يحمل سجل مفصل من خطوات التفكير ودعوات الأدوات التي أنتجتها.

sequenceDiagram
    participant Client
    participant ACP as ACP Agent
    participant Audit as Audit Log

    Client->>ACP: POST /runs (mode: sync)
    ACP->>ACP: Process request...
    ACP->>Audit: Log trajectory:<br/>reasoning + tool calls
    ACP-->>Client: Response + TrajectoryMetadata
    Note over Audit: Every step recorded:<br/>tool_name, tool_input,<br/>tool_output, reasoning

#### العميل "ديسكفري" في "إكسي"

يحدد ACP أربعة طرق للاكتشاف:

graph LR
    A[Agent Discovery] --> B["Runtime<br/>GET /agents"]
    A --> C["Open<br/>.well-known/agent.yml"]
    A --> D["Registry<br/>Centralized catalog"]
    A --> E["Embedded<br/>Container labels"]

    style B fill:#dbeafe,stroke:#2563eb
    style C fill:#d1fae5,stroke:#059669
    style D fill:#fef3c7,stroke:#d97706
    style E fill:#f3e8ff,stroke:#7c3aed
  • نعمAgentManifestهو أبسط من بطاقة وكيل A2A:
json{
  "name": "summarizer",
  "description": "Summarizes documents with source citations",
  "input_content_types": ["text/plain", "application/pdf"],
  "output_content_types": ["text/plain", "application/json"],
  "metadata": {
    "tags": ["summarization", "RAG"],
    "framework": "BeeAI",
    "capabilities": [
      {
        "name": "Document Summarization",
        "description": "Condenses long documents into key points"
      }
    ],
    "recommended_models": ["llama3.3:70b-instruct-fp16"],
    "license": "Apache-2.0",
    "programming_language": "Python"
  }
}

#### إدارة دورة الحياة

يستخدم ACP "Runs" بدلاً من "Task". Run هو تنفيذ وكيل مع ثلاثة أنظمة:

ModeBehavior
syncBlocking. Response contains the complete result.
asyncReturns 202 immediately. Poll GET /runs/{id} for status.
streamSSE stream. Events fire as the agent works.
stateDiagram-v2
    [*] --> created
    created --> in_progress
    in_progress --> completed: success
    in_progress --> failed: error
    in_progress --> awaiting: needs input
    awaiting --> in_progress: client resumes
    in_progress --> cancelling: cancel request
    cancelling --> cancelled

    completed --> [*]
    failed --> [*]
    cancelled --> [*]

#### المسار البيانات المعدنية (مسار المراجعة)

هذا هو المُختلف الرئيسي لـ ACP. كل جزء من الرسالة يمكن أن يحتوي على بيانات متادية تظهر بالضبط ما فعله الوكيل:

json{
  "role": "agent/researcher",
  "parts": [
    {
      "content_type": "text/plain",
      "content": "The weather in San Francisco is 72F and sunny.",
      "metadata": {
        "kind": "trajectory",
        "message": "I need to check the weather for this location",
        "tool_name": "weather_api",
        "tool_input": { "location": "San Francisco, CA" },
        "tool_output": { "temperature": 72, "condition": "sunny" }
      }
    }
  ]
}

بالنسبة للصناعات المنظمة هذا هو الذهب. كل إجابة تأتي مع سلسلة دليل يمكن إثباتها: أدوات تم استدعائها، ما هي المدخلات التي تم استخدامها، ما هي النتائج التي تم تلقيها. لا يوجد مربع أسود.

كما يدعم ACP CitationMetadataلخصم المصدر:

json{
  "kind": "citation",
  "start_index": 0,
  "end_index": 47,
  "url": "https:TOK0
  "title": "NWS San Francisco Forecast"
}

(بروتوكول شبكة الوكلاء)

Created by:مجتمع المصدر المفتوح (الذي أسسه غاووي تشانغ)

Repo: github.com/agent-network-protocol/AgentNetworkProtocol

Problem:كيف يثق العملاء من المنظمات المختلفة ببعضهم البعض بدون سلطة مركزية؟

النظام الأساسي هوdecentralized identity protocolيُبني الثقة باستخدام المُعرّفات الامتناعية W3C (DIDs) وتشفير من نهاية إلى نهاية. على عكس A2A حيث تكتشف العملاء من خلال نقاط نهاية معروفة، يسمح ANP للعملاء بإثبات هويتهم من خلال التشفير.

إنب يحتوي على ثلاث طبقات:

graph TB
    subgraph Layer3["Layer 3: Application Protocol"]
        AD[Agent Description Documents]
        DISC[Discovery endpoints]
    end
    subgraph Layer2["Layer 2: Meta-Protocol"]
        NEG[AI-powered protocol negotiation]
        CODE[Dynamic code generation]
    end
    subgraph Layer1["Layer 1: Identity & Secure Communication"]
        DID["did:wba (W3C DID)"]
        HPKE[HPKE E2EE - RFC 9180]
        SIG[Signature verification]
    end

    Layer3 --> Layer2
    Layer2 --> Layer1

    style Layer1 fill:#d1fae5,stroke:#059669
    style Layer2 fill:#dbeafe,stroke:#2563eb
    style Layer3 fill:#f3e8ff,stroke:#7c3aed

#### وثائق DID (الهيكل الحقيقي)

ANP يستخدم طريقة DID المخصصة تسمى did:wba(عميل على شبكة الإنترنت)did:wba:example.com:user:aliceيقررhttps://example.com/user/alice/did.json:

json{
  "@context": [
    "https:TOK0
    "https://w3id.org/security/suites/jws-2020/v1",
    "https:TOK2
  ],
  "id": "did:wba:example.com:user:alice",
  "verificationMethod": [
    {
      "id": "did:wba:example.com:user:alice#key-1",
      "type": "EcdsaSecp256k1VerificationKey2019",
      "controller": "did:wba:example.com:user:alice",
      "publicKeyJwk": {
        "crv": "secp256k1",
        "x": "NtngWpJUr-rlNNbs0u-Aa8e16OwSJu6UiFf0Rdo1oJ4",
        "y": "qN1jKupJlFsPFc1UkWinqljv4YE0mq_Ickwnjgasvmo",
        "kty": "EC"
      }
    },
    {
      "id": "did:wba:example.com:user:aliceTOK4
      "type": "X25519KeyAgreementKey2019",
      "controller": "did:wba:example.com:user:alice",
      "publicKeyMultibase": "z9hFgmPVfmBZwRvFEyniQDBkz9LmV7gDEqytWyGZLmDXE"
    }
  ],
  "authentication": [
    "did:wba:example.com:user:alice#key-1"
  ],
  "keyAgreement": [
    "did:wba:example.com:user:aliceTOK6
  ],
  "humanAuthorization": [
    "did:wba:example.com:user:alice#key-1"
  ],
  "service": [
    {
      "id": "did:wba:example.com:user:aliceTOK8
      "type": "AgentDescription",
      "serviceEndpoint": "https://example.com/agents/alice/ad.json"
    }
  ]
}

أشياء مهمة يجب ملاحظتها:

  • Key separationيتم تطبيقها. مفاتيح التوقيع (secp256k1) منفصلة عن مفاتيح التشفير (X25519).
  • humanAuthorizationهذه المفاتيح تتطلب موافقة بشرية صريحة (بيومترية، كلمة مرور، HSM) قبل استخدامها. العمليات عالية المخاطر مثل تحويلات الأموال تمر عبر هذه المسار.
  • keyAgreementيتم استخدام المفاتيح لتشفير HPKE من نهاية إلى نهاية (RFC 9180).
  • - نعمserviceالروابط في القسم إلى وثيقة وصف الوكيل.

#### كيف يعمل الثقة في ANP

إنب يفعلnotاستخدام شبكة الثقة أو الرسم البياني للتأييد. الثقة ثنائية ومحققة لكل تفاعل:

sequenceDiagram
    participant A as Agent A
    participant Domain as Agent A's Domain
    participant B as Agent B

    A->>B: HTTP request + DID + signature
    B->>Domain: Fetch DID document (HTTPS)
    Domain-->>B: DID document + public key
    B->>B: Verify signature with public key
    B-->>A: Issue access token
    A->>B: Subsequent requests use token
    Note over A,B: Trust = TLS domain verification<br/>+ DID signature verification<br/>+ Principle of least trust

الثقة تأتي من ثلاثة مصادر:

  1. Domain-level TLSيُحقق من استضافة الوثيقة DID
  2. DID cryptographic signaturesالتحقق من هوية الوكيل
  3. Principle of least trustيمنح الحد الأدنى من الإذنات فقط

لا توجد نشر ثقة مبني على الشائعات أو تسجيل صفحة المرتبة يمكنك التحقق من كل عميل مباشرة من خلال هوية الشخصية

#### التفاوض في البروتوكول المنتظم

هذه هي أحدث ميزة في ANP عندما يلتقي اثنان من العملاء من النظم البيئية المختلفة، فإنهم لا يحتاجون إلى تنسيقات بيانات متفق عليها مسبقا.

json{
  "action": "protocolNegotiation",
  "sequenceId": 0,
  "candidateProtocols": "I can communicate using:\n1. JSON-RPC with hotel booking schema\n2. REST with OpenAPI 3.1 spec\n3. Natural language over HTTP",
  "modificationSummary": "Initial proposal",
  "status": "negotiating"
}
sequenceDiagram
    participant A as Agent A
    participant B as Agent B

    A->>B: protocolNegotiation (candidateProtocols)
    B->>A: protocolNegotiation (counter-proposal)
    A->>B: protocolNegotiation (accepted)
    Note over A,B: Agents dynamically generate code<br/>to handle the agreed format.<br/>Max 10 rounds, then timeout.

يقوم العملاء بالذهاب والعودة (حوالي 10 جولات) حتى يتفقوا على شكل، ثم يقومون بتوليد رمز ديناميكي للتعامل معه.negotiating،rejected،accepted،timeout. . .

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

المقارنة (مصححة)

MCPA2AACPANP
Created byAnthropicGoogle / Linux FoundationIBM / BeeAICommunity
Spec formatJSON-RPCJSON-RPC / REST / gRPCOpenAPI 3.1 (REST)JSON-RPC
Primary useAgent to ToolAgent to AgentAgent to AgentAgent to Agent
DiscoveryTool listing/.well-known/agent-card.jsonGET /agents, /.well-known/agent.yml/.well-known/agent-descriptions, DID service endpoints
IdentityImplicit (local)Security schemes (OAuth, mTLS)Server-levelW3C DID (did:wba) with E2EE
Audit trailN/ABasic (task history)TrajectoryMetadata (tool calls, reasoning)Not formally specified
State machineN/A9 task states7 run statesN/A
StreamingN/ASSESSETransport-agnostic
Unique featureTool schemasAgent Cards + SkillsTrajectory audit trailMeta-protocol negotiation
Best forTools & dataDynamic collaborationRegulated industriesCross-org trust
StatusStableStable (v1.0)Merging into A2AActive development

كيف يعملون معاً

هذه البروتوكولات ليست متبادلة. نظام مؤسسة واقعي يستخدم العديد من:

graph TB
    subgraph org["Your Organization"]
        RA[Research Agent] <-->|A2A| CA[Coding Agent]
        RA -->|MCP| SS[Search Server]
        CA -->|MCP| GS[GitHub Server]
        AUDIT["All agent responses carry<br/>ACP TrajectoryMetadata"]
    end

    subgraph ext["External (DID verified via ANP)"]
        EA[External Agent]
        PA[Partner Agent]
    end

    RA <-->|ANP + A2A| EA
    CA <-->|ANP + A2A| PA

    style org fill:#f8fafc,stroke:#334155
    style ext fill:#fef2f2,stroke:#991b1b
    style AUDIT fill:#fef3c7,stroke:#d97706
  • MCPيربط كل عامل بأدواته
  • A2Aيتعامل مع التعاون بين الوكلاء (الداخليين والخارجيين)
  • ACPيحتوي على الاستجابات في بيانات المياه المتحركة من أجل قابلية التحقيق
  • ANPيوفر التحقق من الهوية للعملاء الذين لا تسيطر عليهم

بناءها

الخطوة الأولى: أنواع الرسائل الأساسية

كل نظام متعدد الوكلاء يبدأ بتصميم رسالة، ونحن نعرّف أنواع التي تعرض ما تستخدمه البروتوكولات الحقيقية:

typescriptimport crypto from "node:crypto";

type MessageRole = "ROLE_USER" | "ROLE_AGENT";

type MessagePart =
  | { text: string }
  | { data: unknown; mediaType: string }
  | { url: string; filename: string; mediaType: string };

type TrajectoryEntry = {
  reasoning: string;
  toolName?: string;
  toolInput?: unknown;
  toolOutput?: unknown;
  timestamp: number;
};

type AgentMessage = {
  id: string;
  role: MessageRole;
  parts: MessagePart[];
  trajectory?: TrajectoryEntry[];
  replyTo?: string;
  timestamp: number;
};

function createMessage(
  role: MessageRole,
  parts: MessagePart[],
  replyTo?: string
): AgentMessage {
  return {
    id: crypto.randomUUID(),
    role,
    parts,
    replyTo,
    timestamp: Date.now(),
  };
}

function textMessage(role: MessageRole, text: string): AgentMessage {
  return createMessage(role, [{ text }]);
}

لاحظ:MessagePartهو متعددة الحركات (نص، بيانات مهيكلة، ملفات) تماما مثل المواصفات الحقيقية A2A و ACP. كما هو الحال في A2A 1.0, الحقل الذي موجود (text،dataأوurl) يقول ما هو الجزء ، لا يوجدkind-أجلTrajectoryEntryيحتوي على سلسلة التفكير، مماثلة لتقنية "ميتاداتا" التي يستخدمها أوكي.

الخطوة الثانية: بطاقة وكيل A2A و سجل

بناء اكتشاف وكيل الذي يطابق المواصفات الحقيقية A2A:

typescripttype Skill = {
  id: string;
  name: string;
  description: string;
  tags: string[];
  inputModes: string[];
  outputModes: string[];
};

type AgentInterface = {
  url: string;
  protocolBinding: string;
  protocolVersion: string;
};

type AgentCard = {
  name: string;
  description: string;
  version: string;
  supportedInterfaces: AgentInterface[];
  capabilities: {
    streaming: boolean;
    pushNotifications: boolean;
  };
  defaultInputModes: string[];
  defaultOutputModes: string[];
  skills: Skill[];
};

class AgentRegistry {
  private cards: Map<string, AgentCard> = new Map();

  register(card: AgentCard) {
    this.cards.set(card.name, card);
  }

  discoverBySkillTag(tag: string): AgentCard[] {
    return [...this.cards.values()].filter((card) =>
      card.skills.some((skill) => skill.tags.includes(tag))
    );
  }

  discoverByInputMode(mimeType: string): AgentCard[] {
    return [...this.cards.values()].filter(
      (card) =>
        card.defaultInputModes.includes(mimeType) ||
        card.skills.some((skill) => skill.inputModes.includes(mimeType))
    );
  }

  resolve(name: string): AgentCard | undefined {
    return this.cards.get(name);
  }

  listAll(): AgentCard[] {
    return [...this.cards.values()];
  }
}

هذا أكثر غنى بكثير من خريطة سمة إلى قدرة بسيطة. يمكنك اكتشاف العاملين من خلال علامات المهارات، من خلال أشكال إدخال MIME، أو من خلال الاسم، تماما كما يدعم المواصفات الحقيقية A2A.

الخطوة الثالثة: دورة حياة المهام A2A

قم ببناء آلة حالة المهمة الكاملة:

typescripttype TaskState =
  | "TASK_STATE_SUBMITTED"
  | "TASK_STATE_WORKING"
  | "TASK_STATE_INPUT_REQUIRED"
  | "TASK_STATE_AUTH_REQUIRED"
  | "TASK_STATE_COMPLETED"
  | "TASK_STATE_FAILED"
  | "TASK_STATE_CANCELED"
  | "TASK_STATE_REJECTED";

const TERMINAL_STATES: TaskState[] = [
  "TASK_STATE_COMPLETED",
  "TASK_STATE_FAILED",
  "TASK_STATE_CANCELED",
  "TASK_STATE_REJECTED",
];

type TaskStatus = {
  state: TaskState;
  message?: AgentMessage;
  timestamp: number;
};

type Artifact = {
  id: string;
  name: string;
  parts: MessagePart[];
};

type Task = {
  id: string;
  contextId: string;
  status: TaskStatus;
  artifacts: Artifact[];
  history: AgentMessage[];
};

type TaskEvent =
  | { statusUpdate: { taskId: string; status: TaskStatus } }
  | {
      artifactUpdate: {
        taskId: string;
        artifact: Artifact;
        append: boolean;
        lastChunk: boolean;
      };
    };

type TaskHandler = (
  task: Task,
  message: AgentMessage
) => AsyncGenerator<TaskEvent>;

class TaskManager {
  private tasks: Map<string, Task> = new Map();
  private handlers: Map<string, TaskHandler> = new Map();
  private listeners: Map<string, ((event: TaskEvent) => void)[]> = new Map();

  registerHandler(agentName: string, handler: TaskHandler) {
    this.handlers.set(agentName, handler);
  }

  subscribe(taskId: string, listener: (event: TaskEvent) => void) {
    const existing = this.listeners.get(taskId) ?? [];
    existing.push(listener);
    this.listeners.set(taskId, existing);
  }

  async sendMessage(
    agentName: string,
    message: AgentMessage,
    contextId?: string
  ): Promise<Task> {
    const handler = this.handlers.get(agentName);
    if (!handler) {
      const task = this.createTask(contextId);
      task.status = {
        state: "TASK_STATE_REJECTED",
        timestamp: Date.now(),
        message: textMessage("ROLE_AGENT", `No handler for ${agentName}`),
      };
      return task;
    }

    const task = this.createTask(contextId);
    task.history.push(message);
    task.status = { state: "TASK_STATE_SUBMITTED", timestamp: Date.now() };

    this.processTask(task, handler, message).catch((err) => {
      task.status = {
        state: "TASK_STATE_FAILED",
        timestamp: Date.now(),
        message: textMessage("ROLE_AGENT", String(err)),
      };
    });
    return task;
  }

  getTask(taskId: string): Task | undefined {
    return this.tasks.get(taskId);
  }

  cancelTask(taskId: string): boolean {
    const task = this.tasks.get(taskId);
    if (!task || TERMINAL_STATES.includes(task.status.state)) return false;
    task.status = { state: "TASK_STATE_CANCELED", timestamp: Date.now() };
    this.emit(taskId, {
      statusUpdate: { taskId, status: task.status },
    });
    return true;
  }

  private createTask(contextId?: string): Task {
    const task: Task = {
      id: crypto.randomUUID(),
      contextId: contextId ?? crypto.randomUUID(),
      status: { state: "TASK_STATE_SUBMITTED", timestamp: Date.now() },
      artifacts: [],
      history: [],
    };
    this.tasks.set(task.id, task);
    return task;
  }

  private async processTask(
    task: Task,
    handler: TaskHandler,
    message: AgentMessage
  ) {
    task.status = { state: "TASK_STATE_WORKING", timestamp: Date.now() };
    this.emit(task.id, {
      statusUpdate: { taskId: task.id, status: task.status },
    });

    try {
      for await (const event of handler(task, message)) {
        if (TERMINAL_STATES.includes(task.status.state)) break;

        if ("statusUpdate" in event) {
          task.status = event.statusUpdate.status;
        }
        if ("artifactUpdate" in event) {
          const update = event.artifactUpdate;
          const existing = task.artifacts.find(
            (a) => a.id === update.artifact.id
          );
          if (existing && update.append) {
            existing.parts.push(...update.artifact.parts);
          } else {
            task.artifacts.push(update.artifact);
          }
        }
        this.emit(task.id, event);
      }
    } catch (err) {
      task.status = {
        state: "TASK_STATE_FAILED",
        timestamp: Date.now(),
        message: textMessage("ROLE_AGENT", String(err)),
      };
      this.emit(task.id, {
        statusUpdate: { taskId: task.id, status: task.status },
      });
    }
  }

  private emit(taskId: string, event: TaskEvent) {
    for (const listener of this.listeners.get(taskId) ?? []) {
      listener(event);
    }
  }
}

هذا ينفذ دورة حياة المهمة الحقيقية A2A: TASK_STATE_SUBMITTED،TASK_STATE_WORKING،TASK_STATE_INPUT_REQUIREDالمُعاملون هم مولدات التسلسل التي تُعطىstatusUpdateوartifactUpdateالأحداث، نفس الملفات التي يحملها تيار SSE.

الخطوة الرابعة: مسار مراجعة النمط الأفريقي

إغلاق الاتصالات مع تتبع المسار:

typescripttype AuditEntry = {
  runId: string;
  agentName: string;
  input: AgentMessage[];
  output: AgentMessage[];
  trajectory: TrajectoryEntry[];
  status: "created" | "in-progress" | "completed" | "failed" | "awaiting";
  startedAt: number;
  completedAt?: number;
  sessionId?: string;
};

class AuditableRunner {
  private log: AuditEntry[] = [];
  private handlers: Map<
    string,
    (input: AgentMessage[]) => Promise<{
      output: AgentMessage[];
      trajectory: TrajectoryEntry[];
    }>
  > = new Map();

  registerAgent(
    name: string,
    handler: (input: AgentMessage[]) => Promise<{
      output: AgentMessage[];
      trajectory: TrajectoryEntry[];
    }>
  ) {
    this.handlers.set(name, handler);
  }

  async run(
    agentName: string,
    input: AgentMessage[],
    sessionId?: string
  ): Promise<AuditEntry> {
    const entry: AuditEntry = {
      runId: crypto.randomUUID(),
      agentName,
      input: structuredClone(input),
      output: [],
      trajectory: [],
      status: "created",
      startedAt: Date.now(),
      sessionId,
    };
    this.log.push(entry);

    const handler = this.handlers.get(agentName);
    if (!handler) {
      entry.status = "failed";
      return entry;
    }

    entry.status = "in-progress";
    try {
      const result = await handler(input);
      entry.output = structuredClone(result.output);
      entry.trajectory = structuredClone(result.trajectory);
      entry.status = "completed";
      entry.completedAt = Date.now();
    } catch (err) {
      entry.status = "failed";
      entry.trajectory.push({
        reasoning: `Error: ${String(err)}`,
        timestamp: Date.now(),
      });
      entry.completedAt = Date.now();
    }
    return entry;
  }

  getFullAuditLog(): AuditEntry[] {
    return structuredClone(this.log);
  }

  getAuditLogForAgent(agentName: string): AuditEntry[] {
    return structuredClone(
      this.log.filter((e) => e.agentName === agentName)
    );
  }

  getAuditLogForSession(sessionId: string): AuditEntry[] {
    return structuredClone(
      this.log.filter((e) => e.sessionId === sessionId)
    );
  }

  getTrajectoryForRun(runId: string): TrajectoryEntry[] {
    const entry = this.log.find((e) => e.runId === runId);
    return entry ? structuredClone(entry.trajectory) : [];
  }
}

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

الخطوة 5: التحقق من الهوية في نمط ANP

بناء الهوية والتحقق القائم على DID:

typescripttype VerificationMethod = {
  id: string;
  type: string;
  controller: string;
  publicKeyDer: string;
};

type DIDDocument = {
  id: string;
  verificationMethod: VerificationMethod[];
  authentication: string[];
  keyAgreement: string[];
  humanAuthorization: string[];
  service: { id: string; type: string; serviceEndpoint: string }[];
};

type AgentIdentity = {
  did: string;
  document: DIDDocument;
  privateKey: crypto.KeyObject;
  publicKey: crypto.KeyObject;
};

class IdentityRegistry {
  private documents: Map<string, DIDDocument> = new Map();

  publish(doc: DIDDocument) {
    this.documents.set(doc.id, doc);
  }

  resolve(did: string): DIDDocument | undefined {
    return this.documents.get(did);
  }

  verify(did: string, signature: string, payload: string): boolean {
    const doc = this.documents.get(did);
    if (!doc) return false;

    const authKeyIds = doc.authentication;
    const authKeys = doc.verificationMethod.filter((vm) =>
      authKeyIds.includes(vm.id)
    );

    for (const key of authKeys) {
      const publicKey = crypto.createPublicKey({
        key: Buffer.from(key.publicKeyDer, "base64"),
        format: "der",
        type: "spki",
      });
      const isValid = crypto.verify(
        null,
        Buffer.from(payload),
        publicKey,
        Buffer.from(signature, "hex")
      );
      if (isValid) return true;
    }
    return false;
  }

  requiresHumanAuth(did: string, operationKeyId: string): boolean {
    const doc = this.documents.get(did);
    if (!doc) return false;
    return doc.humanAuthorization.includes(operationKeyId);
  }
}

function createIdentity(domain: string, agentName: string): AgentIdentity {
  const did = `did:wba:${domain}:agent:${agentName}`;
  const { publicKey, privateKey } = crypto.generateKeyPairSync("ed25519");

  const publicKeyDer = publicKey
    .export({ format: "der", type: "spki" })
    .toString("base64");

  const keyId = `${did}#key-1`;
  const encKeyId = `${did}#key-x25519-1`;

  const document: DIDDocument = {
    id: did,
    verificationMethod: [
      {
        id: keyId,
        type: "Ed25519VerificationKey2020",
        controller: did,
        publicKeyDer,
      },
      {
        id: encKeyId,
        type: "X25519KeyAgreementKey2019",
        controller: did,
        publicKeyDer,
      },
    ],
    authentication: [keyId],
    keyAgreement: [encKeyId],
    humanAuthorization: [],
    service: [
      {
        id: `${did}#agent-description`,
        type: "AgentDescription",
        serviceEndpoint: `https://${domain}/agents/${agentName}/ad.json`,
      },
    ],
  };

  return { did, document, privateKey, publicKey };
}

function signPayload(identity: AgentIdentity, payload: string): string {
  return crypto
    .sign(null, Buffer.from(payload), identity.privateKey)
    .toString("hex");
}

هذا يعكس نموذج الهوية الحقيقي لـ ANP: لدى العملاء وثائق DID مع تصديق منفصل وموافقة مفتاحية ومفاتيح تصريح بشرية.IdentityRegistryيحاكي قرار DID (في الإنتاج هذا سيكون HTTP جلب إلى نطاق الوكيل).

الخطوة 6: بوابة البروتوكول

قم بتوصيل جميع البروتوكولات الأربعة إلى نظام موحد:

graph LR
    REQ[Incoming Request] --> ANP_V{ANP: Verify DID}
    ANP_V -->|Valid| A2A_D{A2A: Discover Agent}
    ANP_V -->|Invalid| REJECT[Reject]
    A2A_D -->|Found| ACP_A[ACP: Audit Run]
    A2A_D -->|Not Found| REJECT
    ACP_A --> A2A_T[A2A: Create Task]
    A2A_T --> RESULT[Task + Audit Entry]

    style ANP_V fill:#d1fae5,stroke:#059669
    style A2A_D fill:#dbeafe,stroke:#2563eb
    style ACP_A fill:#fef3c7,stroke:#d97706
    style A2A_T fill:#dbeafe,stroke:#2563eb
typescriptclass ProtocolGateway {
  private registry: AgentRegistry;
  private taskManager: TaskManager;
  private auditRunner: AuditableRunner;
  private identityRegistry: IdentityRegistry;

  constructor(
    registry: AgentRegistry,
    taskManager: TaskManager,
    auditRunner: AuditableRunner,
    identityRegistry: IdentityRegistry
  ) {
    this.registry = registry;
    this.taskManager = taskManager;
    this.auditRunner = auditRunner;
    this.identityRegistry = identityRegistry;
  }

  async delegateTask(
    fromDid: string,
    signature: string,
    targetAgent: string,
    message: AgentMessage,
    sessionId?: string
  ): Promise<{ task: Task; audit: AuditEntry } | { error: string }> {
    if (!this.identityRegistry.verify(fromDid, signature, message.id)) {
      return { error: "Identity verification failed" };
    }

    const card = this.registry.resolve(targetAgent);
    if (!card) {
      return { error: `Agent ${targetAgent} not found in registry` };
    }

    const audit = await this.auditRunner.run(
      targetAgent,
      [message],
      sessionId
    );
    const task = await this.taskManager.sendMessage(targetAgent, message);

    return { task, audit };
  }

  discoverAndDelegate(
    fromDid: string,
    signature: string,
    skillTag: string,
    message: AgentMessage
  ): Promise<{ task: Task; audit: AuditEntry } | { error: string }> {
    const candidates = this.registry.discoverBySkillTag(skillTag);
    if (candidates.length === 0) {
      return Promise.resolve({
        error: `No agents found with skill tag: ${skillTag}`,
      });
    }
    return this.delegateTask(
      fromDid,
      signature,
      candidates[0].name,
      message
    );
  }
}

البوابة تفعل أربعة أشياء في مكالمة واحدة:

  1. ANP: يُحقق من هوية المتصل عبر توقيع DID
  2. A2A: يكتشف العميل المستهدف ويتحقق من قدرات
  3. ACP: يحتوي على تنفيذ في مسار مراجعة مع مسار
  4. A2A: يخلق مهمة مع تتبع دورة الحياة الكاملة

الخطوة السابعة: قم بتجميعها

typescriptasync function protocolDemo() {
  const registry = new AgentRegistry();
  registry.register({
    name: "researcher",
    description: "Searches and summarizes findings",
    version: "1.0.0",
    supportedInterfaces: [
      {
        url: "https:TOK0
        protocolBinding: "JSONRPC",
        protocolVersion: "1.0",
      },
    ],
    capabilities: { streaming: true, pushNotifications: false },
    defaultInputModes: ["text/plain"],
    defaultOutputModes: ["text/plain", "application/json"],
    skills: [
      {
        id: "web-research",
        name: "Web Research",
        description: "Searches the web",
        tags: ["research", "search", "summarization"],
        inputModes: ["text/plain"],
        outputModes: ["application/json"],
      },
    ],
  });
  registry.register({
    name: "coder",
    description: "Writes code from specs",
    version: "1.0.0",
    supportedInterfaces: [
      {
        url: "https://coder.local/a2a/v1",
        protocolBinding: "JSONRPC",
        protocolVersion: "1.0",
      },
    ],
    capabilities: { streaming: false, pushNotifications: false },
    defaultInputModes: ["text/plain", "application/json"],
    defaultOutputModes: ["text/plain"],
    skills: [
      {
        id: "code-gen",
        name: "Code Generation",
        description: "Generates code",
        tags: ["coding", "generation"],
        inputModes: ["text/plain", "application/json"],
        outputModes: ["text/plain"],
      },
    ],
  });

  const taskManager = new TaskManager();
  const auditRunner = new AuditableRunner();

  const researchTrajectory: TrajectoryEntry[] = [];

  taskManager.registerHandler(
    "researcher",
    async function* (task, message) {
      yield {
        statusUpdate: {
          taskId: task.id,
          status: {
            state: "TASK_STATE_WORKING" as const,
            timestamp: Date.now(),
          },
        },
      };

      researchTrajectory.push({
        reasoning: "Searching for React 19 documentation",
        toolName: "web_search",
        toolInput: { query: "React 19 compiler features" },
        toolOutput: {
          results: ["react.dev/blog/react-19", "github.com/react/react"],
        },
        timestamp: Date.now(),
      });

      researchTrajectory.push({
        reasoning: "Extracting key findings from search results",
        toolName: "doc_analysis",
        toolInput: { url: "react.dev/blog/react-19" },
        toolOutput: {
          summary:
            "React 19 compiler auto-memoizes, no manual useMemo needed",
        },
        timestamp: Date.now(),
      });

      yield {
        artifactUpdate: {
          taskId: task.id,
          artifact: {
            id: crypto.randomUUID(),
            name: "research-results",
            parts: [
              {
                data: {
                  findings: [
                    "React 19 compiler auto-memoizes components",
                    "No more manual useMemo/useCallback needed",
                    "Compiler runs at build time, not runtime",
                  ],
                  sources: ["react.dev/blog/react-19"],
                },
                mediaType: "application/json",
              },
            ],
          },
          append: false,
          lastChunk: true,
        },
      };

      yield {
        statusUpdate: {
          taskId: task.id,
          status: {
            state: "TASK_STATE_COMPLETED" as const,
            timestamp: Date.now(),
          },
        },
      };
    }
  );

  auditRunner.registerAgent("researcher", async () => ({
    output: [
      textMessage("ROLE_AGENT", "React 19 compiler auto-memoizes components"),
    ],
    trajectory: researchTrajectory,
  }));

  const identityRegistry = new IdentityRegistry();

  const coderIdentity = createIdentity("coder.local", "coder");
  const researcherIdentity = createIdentity("researcher.local", "researcher");

  identityRegistry.publish(coderIdentity.document);
  identityRegistry.publish(researcherIdentity.document);

  const gateway = new ProtocolGateway(
    registry,
    taskManager,
    auditRunner,
    identityRegistry
  );

  console.log("=== Protocol Demo ===\n");

  console.log("1. Agent Discovery (A2A)");
  const researchAgents = registry.discoverBySkillTag("research");
  console.log(
    `   Found ${researchAgents.length} agent(s):`,
    researchAgents.map((a) => a.name)
  );

  console.log("\n2. Identity Verification (ANP)");
  const message = textMessage("ROLE_USER", "Research React 19 compiler features");
  const signature = signPayload(coderIdentity, message.id);
  const verified = identityRegistry.verify(
    coderIdentity.did,
    signature,
    message.id
  );
  console.log(`   Coder DID: ${coderIdentity.did}`);
  console.log(`   Signature verified: ${verified}`);

  console.log("\n3. Task Delegation (A2A + ACP + ANP)");
  const result = await gateway.delegateTask(
    coderIdentity.did,
    signature,
    "researcher",
    message,
    "session-001"
  );

  if ("error" in result) {
    console.log(`   Error: ${result.error}`);
    return;
  }

  console.log(`   Task ID: ${result.task.id}`);
  console.log(`   Task state: ${result.task.status.state}`);
  console.log(`   Artifacts: ${result.task.artifacts.length}`);

  console.log("\n4. Audit Trail (ACP)");
  console.log(`   Run ID: ${result.audit.runId}`);
  console.log(`   Status: ${result.audit.status}`);
  console.log(`   Trajectory steps: ${result.audit.trajectory.length}`);
  for (const step of result.audit.trajectory) {
    console.log(`     - ${step.reasoning}`);
    if (step.toolName) {
      console.log(`       Tool: ${step.toolName}`);
    }
  }

  console.log("\n5. Full Audit Log");
  const fullLog = auditRunner.getFullAuditLog();
  console.log(`   Total runs: ${fullLog.length}`);
  for (const entry of fullLog) {
    const duration = entry.completedAt
      ? `${entry.completedAt - entry.startedAt}ms`
      : "in-progress";
    console.log(`   ${entry.agentName}: ${entry.status} (${duration})`);
  }
}

protocolDemo().catch((err) => {
  console.error("Protocol demo failed:", err);
  process.exitCode = 1;
});

ما الذي يذهب خطأ

البروتوكولات تحل الطريق السعيد، إليك ما يفسد الإنتاج:

Schema drift.العميل (أ) ينشر إعلان بطاقة العميلapplication/jsonالنسخة. ولكن مخطط JSON يتغير بين الإصدارات. وكيل B يحتل النموذج القديم ويستقبل القمامة. تصحيح: إصدار مهاراتك وخطط الإصدار. تطبيق A2A يدعم versionعلى العميل بطاقات لهذا السبب.

State machine violations.وكيل يُساعد على إعطاءTASK_STATE_COMPLETEDتحديث الحالة، ثم يحاول إعطاء المزيد من الأثاث. المهمة غير قابلة للتغيير. رمزك يسقط صامتًا التحديثات أو يرمي.TaskManagerأعلاه يفرض هذا مع breakبعد الحالات النهائية.

Trust resolution failures.يحاول العميل A التحقق من DID العميل B، ولكن النطاق العميل B هو منخفض. الوثيقة DID لا يمكن الحصول عليها. هل تفشل في فتح (قبل وكلاء غير مصدقين) أو تفشل في إغلاق (رفض كل شيء) ؟ توصي ANP بإغلاق الفشل مع مبدأ أقل ثقة.

Trajectory bloat.تسجيل المسار ACP قوي ولكن مكلف. وكيل معقد يقوم بـ 200 مكالمة أداة في كل جولة ينتج إدخالات تدقيق ضخمة. تصحيح: سجل المسار على مستويات الكلمات المتكاملة. سجل أسماء الأدوات و IO للتوافق، تخطي خطوات التفكير لحملات العمل غير المنظمة.

Discovery thundering herd.50 عميل كل استفسار GET /agentsفي نفس الوقت عند بدء العمل. إصلاح: تخزين بطاقات وكيل مع TTL، فترات اكتشاف التفاصيل، أو استخدام التسجيل القائم على دفع بدلا من استطلاع.

استخدمها

التنفيذ الحقيقي

A2Aهو الأكثر نضجاً.official specو هو مفتوح المصدر تحت مؤسسة لينكس. SDKs ل Python و TypeScript. إذا كان عملاءك يحتاجون إلى اكتشاف ديناميكي والتعاون، تبدأ من هنا.

ACPيدمج في A2A. IBM BeeAI projectتم إنشاء ACP كبديل REST أولاً، ولكن مفهوم البيانات المتحركة في المسار يتم امتصاصها في النظام البيئي A2A. استخدم أنماط ACP (سجل المسار، دورة حياة التشغيل) حتى لو كنت تستخدم A2A كوسيلة النقل.

ANPهو الأكثر تجريبية.community repoيحتوي على بروتوكولات متتالية جديدة، تستحق المشاهدة للتنفيذ عبر المنظمات.

MCPإذا كنت تريد أن يستخدم العملاء الأدوات، فإن MCP هو المعيار.

اختيار البروتوكول المناسب

graph TD
    START{Do agents need<br/>to use tools?}
    START -->|Yes| MCP_R[Use MCP]
    START -->|No| TALK{Do agents need to<br/>talk to each other?}
    TALK -->|No| NONE[You don't need<br/>a protocol]
    TALK -->|Yes| AUDIT{Need audit trails<br/>for compliance?}
    AUDIT -->|Yes| ACP_R[A2A + ACP<br/>trajectory patterns]
    AUDIT -->|No| ORG{All agents<br/>within your org?}
    ORG -->|Yes| A2A_R[A2A<br/>Agent Cards + Tasks]
    ORG -->|No| INFRA{Shared<br/>infrastructure?}
    INFRA -->|Yes| BROKER[A2A + message broker]
    INFRA -->|No| ANP_R[ANP + A2A<br/>DID verification]

    style MCP_R fill:#d1fae5,stroke:#059669
    style A2A_R fill:#dbeafe,stroke:#2563eb
    style ACP_R fill:#fef3c7,stroke:#d97706
    style ANP_R fill:#f3e8ff,stroke:#7c3aed
    style BROKER fill:#e0e7ff,stroke:#4338ca

أرسله

هذا الدرس ينتج عن:

  • code/main.ts-- تنفيذ كامل لأربعة أنماط البروتوكول
  • outputs/prompt-protocol-selector.md-- طلب يساعدك على اختيار البروتوكولات لنظامك

التمارين

  1. Multi-hop task delegation.تمديد TaskManagerلذا يمكن للمعاملين المختصين تفويض المهام الفرعية إلى العملاء الآخرين. يحصل الباحث على مهمة، ويمنح "البحث" و"التلخيص" للمهام الفرعية إلى عملاء متخصصين، ينتظر كل منهما أن يكتمل، ثم يدمج النتائج في أثاثه الخاصة.
  1. Streaming audit trail.تعديلAuditableRunnerبدلاً من الانتظار للنتيجة الكاملة،AuditEntryتحديثات في الوقت الحقيقي مع إضافة إدخالات المسار. استخدم مولد التزامنا الذي ينتج صور الفورية المراجعة.
  1. DID rotation.إضافة دوران مفتاح إلى IdentityRegistryيجب أن يكون الوكيل قادرًا على نشر وثيقة DID الجديدة مع مفاتيح محدثة مع الحفاظ على الوصفpreviousDidالإشارة: يجب على المؤكدين قبول توقيعات من كل من المفتاح الحالي والسابق خلال فترة فترة.
  1. Protocol negotiation.تنفيذ مفهوم البروتوكول المنتظم من قبل النظام الأساسي للإنترنتprotocolNegotiationالرسائل ذات تنسيقات مرشحة (مثل "يمكنني التحدث JSON-RPC" مقابل "أفضل REST"). بعد ما يصل إلى 3 جولات ، يتفقون على تنسيق أو توقيت.TaskManagerأوAuditableRunnerيستخدمونها
  1. Rate-limited discovery.إضافةRateLimitedRegistryالملفوف الذي يحفظ البحث عن بطاقة العميل مع TTL قابلة للتكوين ويحد من استفسارات الاكتشاف لكل عميل في الثانية. محاكاة مجموعة رعد من 100 عميل يكتشف بعضهم البعض عند بدء وتقييم الفرق.

الشروط الرئيسية

TermWhat people sayWhat it actually means
MCP"The protocol for AI tools"A client-server protocol for agents to discover and use tools. Agent-to-tool, not agent-to-agent.
A2A"Google's agent protocol"A peer-to-peer protocol for agent collaboration under the Linux Foundation. Discovery via Agent Cards, 9-state task lifecycle, streaming via SSE. Supports JSON-RPC, REST, and gRPC bindings.
ACP"Enterprise agent messaging"IBM/BeeAI's REST API for agent runs with TrajectoryMetadata: every response carries the full chain of reasoning and tool calls. Merging into A2A.
ANP"Decentralized agent identity"A community protocol using did:wba (DID) for cryptographic identity, HPKE for E2EE, and AI-powered meta-protocol negotiation for agents that have never seen each other.
Agent Card"An agent's business card"A JSON document at /.well-known/agent-card.json describing skills, supported MIME types, security schemes, and protocol bindings.
DID"Decentralized ID"W3C standard for cryptographically verifiable identities hosted on the agent's own domain. ANP uses did:wba method.
TrajectoryMetadata"The audit receipt"ACP's mechanism for attaching reasoning steps, tool calls, and their inputs/outputs to every agent response.
Meta-protocol"Agents negotiating how to talk"ANP's approach where agents use natural language to dynamically agree on data formats, then generate code to handle them.
Task"A unit of work"A2A's stateful object tracking work from submission through completion. Immutable once terminal.

المزيد من القراءة

This free lesson is part of the AI Engineering from Scratch curriculum. Read the full explanation, run the lesson code, and verify the result in the interactive reader or from the repository source.

Browse the complete course catalog or open this lesson on GitHub.