AI Engineering Academy · บทเรียน

หน่วยความจำร่วมและการสื่อสารระหว่างเอเจนต์

สร้างชั้นหน่วยความจำร่วมด้วยที่จัดเก็บข้อมูลแบบคีย์-ค่า ซึ่งเอเจนต์สามารถอ่านและเขียนได้ ทำให้ทำงานร่วมกันแบบอะซิงโครนัสโดยไม่ต้องเชื่อมโยงเอเจนต์อย่างแน่นหนา

บทเรียน 4 จาก 413 ขั้นตอน

หน่วยความจำร่วมและการสื่อสารระหว่างเอเจนต์ เป็นบทเรียน AI Engineering Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน AI Engineering Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส AI Engineering Academy มีบทเรียนทั้งหมด 4 บทเรียน

ปัญหาการแยกตัวของตัวแทน

ในระบบหลายตัวแทน ตัวแทนแต่ละตัวทำงานในบริบทของตนเอง และไม่รับรู้ว่าตัวแทนอื่นกำลังทำอะไรหรือทำอะไรไปแล้ว หากตัวแทนนักค้นคว้าค้นพบข้อเท็จจริงสำคัญ ตัวแทนนักเขียนจะรู้ได้อย่างไร ตัวแทนตรวจสอบจะรู้ได้อย่างไรว่าตัวแทนเขียนโค้ดพบข้อผิดพลาด เมื่อไม่มีกลไกการสื่อสารร่วม ตัวแทนจะกลายเป็นส่วนแยกที่ไม่สามารถทำงานร่วมกันได้อย่างมีประสิทธิภาพ

หน่วยความจำร่วม: โมเดลกระดานดำ

วิธีแก้ปัญหาแบบดั้งเดิมสำหรับการสื่อสารระหว่างตัวแทนคือ โมเดลกระดานดำ ซึ่งเป็นแหล่งจัดเก็บข้อมูลร่วมที่ตัวแทนใด ๆ สามารถอ่านหรือเขียนได้ ตัวแทนจะโพสต์สิ่งที่ค้นพบ อ่านข้อมูลจากตัวแทนอื่น และประสานงานกันโดยอาศัยสถานะร่วมโดยปริยาย โมเดลนี้แยกตัวแทนออกจากกัน ตัวแทนจึงไม่จำเป็นต้องรู้ว่าตัวแทนอื่นมีอยู่ เพียงต้องรู้โครงสร้างของหน่วยความจำร่วมเท่านั้น

# Simple in-memory blackboard using a dictionary
from threading import Lock

class Blackboard:
    def __init__(self):
        self._data = {}
        self._lock = Lock()  # thread-safe for parallel agents

    def write(self, key: str, value, agent_id: str):
        with self._lock:
            self._data[key] = {'value': value, 'written_by': agent_id}
            print(f'[{agent_id}] wrote: {key}')

    def read(self, key: str):
        with self._lock:
            return self._data.get(key, {}).get('value')

    def keys(self):
        with self._lock:
            return list(self._data.keys())

blackboard = Blackboard()

หน่วยความจำร่วมแบบคงอยู่ด้วย Redis

สำหรับระบบหลายตัวแทนในสภาพแวดล้อมใช้งานจริงที่ตัวแทนทำงานเป็นกระบวนการหรือบริการแยกกัน พจนานุกรมในหน่วยความจำไม่เพียงพอ Redis เป็นตัวเลือกยอดนิยมสำหรับหน่วยความจำร่วมของตัวแทน เพราะทำงานเร็ว รองรับชนิดข้อมูลที่หลากหลาย (สตริง แฮช รายการ และเซตเรียงลำดับ) มี TTL ในตัวสำหรับการหมดอายุ และจัดการการอ่านเขียนพร้อมกันได้อย่างปลอดภัยด้วยการดำเนินการแบบอะตอมิก

import redis
import json

class RedisSharedMemory:
    def __init__(self, prefix='agent:'):
        self.redis = redis.Redis(host='localhost', port=6379, decode_responses=True)
        self.prefix = prefix

    def set(self, key: str, value, ttl_seconds=3600):
        full_key = self.prefix + key
        self.redis.setex(full_key, ttl_seconds, json.dumps(value))

    def get(self, key: str):
        full_key = self.prefix + key
        raw = self.redis.get(full_key)
        return json.loads(raw) if raw else None

    def append_to_list(self, key: str, item):
        full_key = self.prefix + key
        self.redis.rpush(full_key, json.dumps(item))

    def get_list(self, key: str):
        full_key = self.prefix + key
        return [json.loads(x) for x in self.redis.lrange(full_key, 0, -1)]

memory = RedisSharedMemory(prefix='research_project:')

การกำหนดเนมสเปซให้หน่วยความจำร่วม

ในระบบหลายตัวแทนที่ซับซ้อน ตัวแทนจะเขียนข้อมูลหลายประเภท และเนมสเปซของคีย์แบบแบนจะกลายเป็นระเบียบยุ่งเหยิงอย่างรวดเร็ว ให้ใช้ การกำหนดเนมสเปซแบบลำดับชั้น เพื่อจัดระเบียบหน่วยความจำร่วมให้ชัดเจน รูปแบบที่ใช้กันทั่วไปคือ project_id:agent_role:data_type เช่น proj_123:researcher:findings หรือ proj_123:coder:error_log วิธีนี้ทำให้ค้นข้อมูลทั้งหมดของโครงการหนึ่ง หรือผลลัพธ์ทั้งหมดจากตัวแทนเฉพาะตัวได้ง่าย

class NamespacedMemory:
    def __init__(self, project_id: str, agent_id: str, redis_client):
        self.base = f'{project_id}:{agent_id}'
        self.redis = redis_client

    def write_finding(self, topic: str, content: str):
        key = f'{self.base}:findings:{topic}'
        self.redis.set(key, content)

    def read_all_findings(self, project_id: str):
        # Read findings from ALL agents in this project
        pattern = f'{project_id}:*:findings:*'
        keys = self.redis.keys(pattern)
        return {k: self.redis.get(k) for k in keys}

# Usage
researcher_memory = NamespacedMemory('proj_123', 'researcher', redis_client)
researcher_memory.write_finding('competitors', 'OpenAI, Anthropic, Google...')

writer_memory = NamespacedMemory('proj_123', 'writer', redis_client)
all_findings = writer_memory.read_all_findings('proj_123')

หน่วยความจำแบบมีโครงสร้างเทียบกับไม่มีโครงสร้าง

เนื้อหาในหน่วยความจำร่วมอาจเป็นแบบ ไม่มีโครงสร้าง (กลุ่มข้อความดิบที่ LLM จะอ่าน) หรือแบบ มีโครงสร้าง (ออบเจ็กต์ JSON/Python ที่มีฟิลด์ระบุชนิดข้อมูล) หน่วยความจำแบบมีโครงสร้างเหมาะสมกว่า เพราะช่วยให้สอบถาม ตรวจสอบความถูกต้อง และผสานข้อมูลด้วยโปรแกรมได้ ควรกำหนดสคีมาสำหรับข้อมูลที่ตัวแทนแต่ละตัวเขียนลงในหน่วยความจำร่วม จัดทำเอกสารกำกับ และตรวจสอบการเขียนให้ตรงตามสคีมาเสมอ เพื่อป้องกันไม่ให้ตัวแทนที่มีข้อบกพร่องทำให้แหล่งจัดเก็บหน่วยความจำเสียหาย

from pydantic import BaseModel
from typing import Optional, list
from datetime import datetime

class ResearchFinding(BaseModel):
    topic: str
    summary: str
    sources: list[str]
    confidence: float  # 0.0 to 1.0
    written_by: str
    timestamp: datetime

# Validated write - bad data is caught before it enters shared memory
def write_finding(memory, finding_dict: dict):
    finding = ResearchFinding(**finding_dict)  # validates on creation
    memory.set(f'findings:{finding.topic}', finding.model_dump())
    print(f'Validated finding written for topic: {finding.topic}')

การสื่อสารที่ขับเคลื่อนด้วยเหตุการณ์ด้วย Pub/Sub

แทนที่จะตรวจสอบหน่วยความจำร่วมซ้ำ ๆ เพื่อดูว่ามีการอัปเดตหรือไม่ ตัวแทนสามารถใช้การสื่อสารแบบ เผยแพร่/สมัครรับ (pub/sub) เพื่อแจ้งตัวแทนอื่นเมื่อทำงานเสร็จ ตัวแทน A เผยแพร่เหตุการณ์ ('research_complete') และตัวแทน B ซึ่งสมัครรับเหตุการณ์นั้นอยู่จะตื่นขึ้นและเริ่มประมวลผล Redis pub/sub และคิวข้อความอย่าง RabbitMQ หรือ Kafka รองรับรูปแบบนี้

import redis

# Publisher (researcher agent)
def researcher_agent(topic, redis_client):
    findings = do_research(topic)
    redis_client.set(f'findings:{topic}', findings)
    
    # Notify all subscribers that research is done
    redis_client.publish('agent_events', f'research_complete:{topic}')
    print(f'Research complete, published event for topic: {topic}')

# Subscriber (writer agent) - runs in separate process
def writer_agent_listener(redis_client):
    pubsub = redis_client.pubsub()
    pubsub.subscribe('agent_events')
    
    for message in pubsub.listen():
        if message['type'] == 'message':
            event = message['data']
            if event.startswith('research_complete:'):
                topic = event.split(':')[1]
                findings = redis_client.get(f'findings:{topic}')
                write_draft(findings)  # start writing immediately

หน่วยความจำร่วมใน LangGraph

ใน LangGraph หน่วยความจำที่ใช้ร่วมกันระหว่างเอเจนต์คือ ออบเจ็กต์สถานะของกราฟ เอง แต่ละโหนดจะอ่านและเขียนลงในพจนานุกรมสถานะที่มีชนิดข้อมูลเดียวกัน LangGraph จัดการประสานงานการอ่านและการเขียนให้โดยอัตโนมัติ สำหรับสถานการณ์ที่ซับซ้อนยิ่งขึ้น คุณยังสามารถแทรกไคลเอ็นต์หน่วยความจำภายนอก (Redis, ฐานข้อมูล) เข้าไปในฟังก์ชันของแต่ละโหนดผ่านการฉีดการพึ่งพาได้

from langgraph.graph import StateGraph
from typing import TypedDict

class SharedState(TypedDict):
    # All shared data lives here - every node can read any field
    query: str
    research_findings: str   # written by researcher, read by writer
    written_draft: str       # written by writer, read by reviewer
    review_notes: str        # written by reviewer, read by writer (loop)
    final_output: str        # written by synthesizer

# Researcher writes to 'research_findings'
def researcher(state: SharedState) -> dict:
    findings = search_and_summarize(state['query'])
    return {'research_findings': findings}  # partial state update

# Writer reads 'research_findings', writes 'written_draft'
def writer(state: SharedState) -> dict:
    draft = write_from_findings(state['research_findings'])  # reads researcher output
    return {'written_draft': draft}

ข้อขัดแย้งและความสอดคล้องของหน่วยความจำ

เมื่อเอเจนต์หลายตัวเขียนลงในหน่วยความจำที่ใช้ร่วมกันพร้อมกัน อาจเกิด ข้อขัดแย้งในการเขียน ได้ เอเจนต์สองตัวอาจเขียนทับงานของกันและกัน หรืออ่านข้อมูลเก่าระหว่างการอ่านกับการเขียน คุณสามารถจัดการเรื่องนี้ได้ด้วยการล็อกแบบมองโลกในแง่ดี (ตรวจสอบเวอร์ชันก่อนเขียน) การดำเนินการเปรียบเทียบและสลับแบบอะตอมิกใน Redis หรือการจัดลำดับการเขียนผ่านเอเจนต์ผู้ประสานงาน ซึ่งเป็นผู้เขียนเพียงรายเดียวสำหรับฟิลด์หน่วยความจำที่สำคัญ

# Optimistic locking with Redis
def safe_write(redis_client, key, new_value, expected_version):
    with redis_client.pipeline() as pipe:
        try:
            pipe.watch(key + ':version')  # watch for concurrent modification
            current_version = int(pipe.get(key + ':version') or 0)
            
            if current_version != expected_version:
                raise ValueError(f'Version conflict: expected {expected_version}, got {current_version}')
            
            pipe.multi()  # start transaction
            pipe.set(key, new_value)
            pipe.set(key + ':version', current_version + 1)
            pipe.execute()  # atomic commit
            print('Write successful')
        except redis.WatchError:
            print('Conflict detected, retry write')

TTL และการล้างหน่วยความจำ

หน่วยความจำที่ใช้ร่วมกันของเอเจนต์จะสะสมเพิ่มขึ้นตามเวลาและอาจขยายโดยไม่มีขอบเขตหากไม่จัดการ ควรกำหนด อายุการใช้งาน (TTL) ให้กับรายการในหน่วยความจำเสมอ เพื่อให้รายการหมดอายุโดยอัตโนมัติ สำหรับหน่วยความจำที่จำกัดขอบเขตอยู่ในโครงการ ให้ล้างรายการทั้งหมดเมื่อโครงการเสร็จสิ้น ใช้ค่า TTL ให้สอดคล้องกับระยะเวลาที่คาดไว้ของเวิร์กโฟลว์: TTL สั้น (ระดับนาที) สำหรับข้อมูลชั่วคราว และ TTL ยาวกว่า (ระดับชั่วโมงถึงวัน) สำหรับผลลัพธ์ที่อาจนำกลับมาใช้ซ้ำ

def cleanup_project_memory(redis_client, project_id: str):
    pattern = f'{project_id}:*'
    keys = redis_client.keys(pattern)
    if keys:
        redis_client.delete(*keys)
        print(f'Cleaned up {len(keys)} memory entries for project {project_id}')

# Set TTL when writing
def write_with_ttl(redis_client, key, value, ttl_hours=2):
    redis_client.setex(
        key,
        ttl_hours * 3600,  # convert to seconds
        json.dumps(value)
    )

# Register cleanup callback when workflow completes
def on_workflow_complete(project_id):
    cleanup_project_memory(redis_client, project_id)
    print(f'Workflow {project_id} complete, memory cleaned up')

หน่วยความจำในฐานะประวัติของเอเจนต์

หน่วยความจำที่ใช้ร่วมกันยังสามารถเก็บ ประวัติการดำเนินการของเอเจนต์ ไม่ใช่เพียงผลลัพธ์เท่านั้น การบันทึกว่าเอเจนต์ใดทำอะไร เมื่อใด และเพราะเหตุใด จะสร้างบันทึกตรวจสอบที่มีคุณค่าอย่างยิ่งสำหรับการแก้ไขข้อผิดพลาด การทำความเข้าใจว่าผลลัพธ์สุดท้ายถูกสร้างขึ้นอย่างไร และการดำเนินเวิร์กโฟลว์ที่หยุดชะงักต่อ บันทึกการดำเนินการนี้เป็นสิ่งเทียบเท่าการติดตามของ LangSmith ที่อาศัยหน่วยความจำ

import time
from dataclasses import dataclass

@dataclass
class AgentAction:
    agent_id: str
    action_type: str     # 'research', 'write', 'review', 'tool_call'
    input_summary: str
    output_summary: str
    timestamp: float
    success: bool

def log_action(memory, action: AgentAction):
    key = f'action_log:{action.agent_id}:{action.timestamp}'
    memory.set(key, vars(action))

# Usage in an agent
def researcher_with_logging(state, memory):
    start = time.time()
    findings = do_research(state['query'])
    log_action(memory, AgentAction(
        agent_id='researcher',
        action_type='research',
        input_summary=state['query'][:100],
        output_summary=findings[:100],
        timestamp=start,
        success=True
    ))
    return findings

การเลือกสถาปัตยกรรมหน่วยความจำ

สถาปัตยกรรมหน่วยความจำที่ใช้ร่วมกันที่เหมาะสมขึ้นอยู่กับรูปแบบการนำไปใช้งานของคุณ สำหรับ เวิร์กโฟลว์ LangGraph แบบกระบวนการเดียว สถานะของกราฟก็เพียงพอแล้ว สำหรับ เอเจนต์แบบหลายกระบวนการหรือแบบกระจาย ให้ใช้ Redis สำหรับ โครงการที่ทำงานเป็นเวลานาน และต้องคงอยู่แม้เริ่มระบบใหม่ ให้ใช้ฐานข้อมูลเชิงสัมพันธ์ที่มีดัชนีอย่างเหมาะสม สำหรับ การประสานงานระหว่างบริการที่ขับเคลื่อนด้วยเหตุการณ์ ให้เพิ่มการเผยแพร่/สมาชิกไว้ด้านบนของพื้นที่จัดเก็บที่คุณเลือก

ตรวจสอบความเข้าใจอย่างรวดเร็ว

ทดสอบความเข้าใจเกี่ยวกับหน่วยความจำที่ใช้ร่วมกันและการสื่อสารระหว่างเอเจนต์จากบทเรียนนี้

ทบทวนบทเรียน

ในบทเรียนนี้ คุณได้เรียนรู้ว่า โมเดลกระดานดำ ใช้พื้นที่จัดเก็บข้อมูลร่วมกันที่เอเจนต์ทุกตัวสามารถอ่านและเขียนได้ จึงทำให้ประสานงานกันโดยปริยายโดยไม่ต้องเชื่อมโยงเอเจนต์โดยตรง Redis เป็นตัวเลือกหลักสำหรับหน่วยความจำถาวรที่ใช้ร่วมกันในระบบหลายเอเจนต์แบบกระจาย และ การเผยแพร่/สมาชิก ช่วยให้เกิดการสื่อสารที่ขับเคลื่อนด้วยเหตุการณ์ ทำให้เอเจนต์ตอบสนองได้ทันทีเมื่อการพึ่งพาเสร็จสมบูรณ์ ต่อไปเราจะสำรวจวงจรการดำเนินการโค้ดสำหรับงานของเอเจนต์

เริ่มต้นได้ฟรี

เรียนรู้ Python ด้วย AI tutor — ฟรี

เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป

คอร์ส
30
บทเรียน
120

คำถามที่พบบ่อย

บทเรียน “หน่วยความจำร่วมและการสื่อสารระหว่างเอเจนต์” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “หน่วยความจำร่วมและการสื่อสารระหว่างเอเจนต์” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส AI Engineering Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส AI Engineering Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “หน่วยความจำร่วมและการสื่อสารระหว่างเอเจนต์”

สร้างชั้นหน่วยความจำร่วมด้วยที่จัดเก็บข้อมูลแบบคีย์-ค่า ซึ่งเอเจนต์สามารถอ่านและเขียนได้ ทำให้ทำงานร่วมกันแบบอะซิงโครนัสโดยไม่ต้องเชื่อมโยงเอเจนต์อย่างแน่นหนา คุณปฏิบัติ AI Engineering Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน AI Engineering Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน AI Engineering Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “หน่วยความจำร่วมและการสื่อสารระหว่างเอเจนต์” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน AI Engineering Academy นี้ได้ไหม

ได้ บทเรียน AI Engineering Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. เหตุใดเอเจนต์เดี่ยวจึงไปต่อไม่ได้
  2. รูปแบบผู้ประสานงาน-เอเจนต์ย่อย
  3. การสร้างกระบวนการหลายเอเจนต์ด้วย LangGraph
  4. หน่วยความจำร่วมและการสื่อสารระหว่างเอเจนต์
← กลับไปที่ AI Engineering Academy