หน่วยความจำร่วมและการสื่อสารระหว่างเอเจนต์
สร้างชั้นหน่วยความจำร่วมด้วยที่จัดเก็บข้อมูลแบบคีย์-ค่า ซึ่งเอเจนต์สามารถอ่านและเขียนได้ ทำให้ทำงานร่วมกันแบบอะซิงโครนัสโดยไม่ต้องเชื่อมโยงเอเจนต์อย่างแน่นหนา
หน่วยความจำร่วมและการสื่อสารระหว่างเอเจนต์ เป็นบทเรียน 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- เหตุใดเอเจนต์เดี่ยวจึงไปต่อไม่ได้
- รูปแบบผู้ประสานงาน-เอเจนต์ย่อย
- การสร้างกระบวนการหลายเอเจนต์ด้วย LangGraph
- หน่วยความจำร่วมและการสื่อสารระหว่างเอเจนต์