article content thumbnail

A-MEM: Agentic Memory for LLM Agents 리뷰

AI Agent의 기억 메모리 조직화 시스템 방법론

prompt 기반으로만 동작하는 LLM과 RAG는 기억력 관점에서 한계가 있다. 지속적으로 사용자와 interaction 해야 하는 상황에서 사용자의 정보를 활용할 수 없다면, 좋은 성능을 내기 어렵다.


ORB라는 프로젝트를 진행하면서, 사용자와 채팅을 하는 챗봇을 구현했다.

하지만 챗봇을 테스트 해보면서 아쉬운 상황들이 있었는데 대표적으로 아래와 같은 상황이었다.


user: 끝말잇기 할까 ?

character: 좋은데! 내가 먼저 시작할게. 사과

user: 과자.

character: 과자는 맛있지 !

user: 끝말잇기 잖아 다시 해.

character: 끝말잇기 좋아! 시작할게 사과.


이렇게 기억력을 보존하지 못해서 대화가 자연스럽지 못한 문제가 생겼다.

따라서 문제 상황을 해결하기 위해서 인간의 기억력과 관련된 방법론에 대해서 고민이 필요했다.

방법론에 대해서 서칭하던 중 A-MEM: Agentic Memory for LLM Agents 논문을 리뷰하게 되었다.

해당 논문은 Zettelkasten 원칙을 기반으로 한 동적 메모리 조직화 시스템을 제안하고 있다.

Zettelkasten principle은 지식을 분리하여 노트에 기록하고, 노트끼리의 연결될 수 있는 메타 데이터들을 만들고, 인덱스를 만들어서 빠르게 검색할 수 있는 지식 관리 방법이다.


Note를 구성하는 방법.

memory는 아래와 같이 정의될 수 있다.


c_i : original interaction content

t_i : timstamp of the interaction 

K_i :LLM-generated Ketwords

G_i : LLM-generated tags for categorization

X_i : LLM-generated contextual description


Link Generation

기억력은 미리 정의된 방법으로 형성되는 것이 아닌 유사도 검색을 기반으로 이루어진다.

아래와 같이 memory로 similarity score를 계산한다.


  • 가장 연관성이 높은 K개의 메모리를 검색해서 Link를 업데이트 한다.


Memory Evolution

  • 인간의 기억처럼 memory를 정교하게 진화시킴에 대해서 언급하고 있다.

  • Link를 생성한 뒤에는 memory의 context, keyword, tag를 업데이트 할지 결정한다.


Retrieve Relative Memory

  • 새로운 기억이 추가될 때 기존 기억들을 변화한다.

  • 현재 존재하는 memory에 대해서 cosine similarity 계산하고, 가장 유사한 K개의 memory를 가져와 입력된 기억과 연관시킨다.


논문에 대한 구현이 github에 code로 되어 있어서, 간단하게 직접 돌려볼 수 있었다.

음식을 먹은 경험을 기억으로 작성한 다음에 햄버거 검색하는 결과까지 검색하는 결과를 찍어봤다.

def main():
    # Initialize memory system with OpenAI controller
    logger.info("Initializing AgenticMemorySystem...")
    memory_system = AgenticMemorySystem(
        llm_backend="openai",
        llm_model="gpt-4o-mini",
        evo_threshold=3  # Trigger memory evolution after 3 memories
    )
    
    # Create food memories
    logger.info("Creating food memories...")
    
    # Memory 1: Hamburger
    hamburger_memory = """
    Today I had a delicious hamburger at Joe's Diner. The patty was juicy and cooked to medium rare perfection.
    It had melted cheddar cheese, crispy lettuce, fresh tomatoes, and a special sauce. The bun was toasted
    just right with a slight crunch. I paired it with some crispy fries and a milkshake. Definitely one of
    the best burgers I've had in months.
    """
    hamburger_id = memory_system.create(hamburger_memory)
    logger.info(f"Created hamburger memory with ID: {hamburger_id}")
    
    # Memory 2: Pizza
    pizza_memory = """
    I ordered a fantastic pizza from Napoli's Pizzeria for dinner. It was a classic Margherita with
    homemade tomato sauce, fresh mozzarella, basil leaves, and olive oil. The crust was thin and crispy
    on the outside but still had that nice chew. The flavors were perfectly balanced - not too salty, 
    with just the right amount of tanginess from the tomatoes. I ate the whole thing by myself!
    """
    pizza_id = memory_system.create(pizza_memory)
    logger.info(f"Created pizza memory with ID: {pizza_id}")
    
    # Memory 3: Spaghetti
    spaghetti_memory = """
    Had homemade spaghetti bolognese for lunch. I slow-cooked the sauce for three hours with ground beef,
    carrots, celery, onions, garlic, and a splash of red wine. The pasta was cooked al dente and mixed directly
    with the sauce to absorb the flavors. Topped it with freshly grated Parmesan cheese and chopped parsley.
    The rich, meaty sauce paired perfectly with the pasta. Comfort food at its finest.
    """
    spaghetti_id = memory_system.create(spaghetti_memory)
    logger.info(f"Created spaghetti memory with ID: {spaghetti_id}")
    
    # Memory 4: Salad
    salad_memory = """
    I had a refreshing garden salad for lunch today. It was a colorful mix of crisp romaine lettuce, cherry tomatoes, 
    cucumber slices, red onion, and avocado. I topped it with grilled chicken breast for protein and sprinkled some 
    feta cheese and toasted walnuts. The homemade balsamic vinaigrette dressing tied everything together perfectly. 
    It was light yet satisfying - exactly what I needed on this hot summer day.
    """
    salad_id = memory_system.create(salad_memory)
    logger.info(f"Created salad memory with ID: {salad_id}")
    
    # Memory 5: Sandwich
    sandwich_memory = """
    I made an incredible club sandwich for lunch today. Used three layers of toasted sourdough bread with mayo on each slice.
    Filled it with roasted turkey, crispy bacon, aged cheddar cheese, avocado slices, fresh tomatoes, and lettuce.
    Added a touch of dijon mustard for some tanginess. The combination of textures was perfect - crunchy, creamy, and juicy.
    Served it with a side of kettle chips and a pickle spear. Definitely going to make this again soon.
    """
    sandwich_id = memory_system.create(sandwich_memory)
    logger.info(f"Created sandwich memory with ID: {sandwich_id}")
    
    # Memory 6: Taco
    taco_memory = """
    Tried the new taco truck downtown for dinner. I ordered three street-style tacos - carne asada, al pastor, and carnitas.
    Each came on small corn tortillas topped with diced onions, fresh cilantro, and lime wedges on the side.
    The meat was incredibly tender and well-seasoned, especially the al pastor with its hint of pineapple sweetness.
    Their homemade hot sauces (red and green) added the perfect amount of heat. Authentic Mexican flavors that 
    transported me straight to Mexico City.
    """
    taco_id = memory_system.create(taco_memory)
    logger.info(f"Created taco memory with ID: {taco_id}")
    
    # Create exercise memories
    logger.info("Creating exercise memories...")
    
    # Memory 7: Baseball
    baseball_memory = """
    Played baseball with friends at Central Park this weekend. I was pitcher for most of the game and managed to strike
    out five batters! Had a couple of good hits too - even got a double in the fourth inning. The weather was perfect - 
    sunny but not too hot. Our team won 7-5 after a tense final inning. My shoulder is a bit sore today from all the 
    pitching, but it was totally worth it. Nothing beats the feeling of connecting with the ball perfectly and hearing 
    that satisfying crack of the bat.
    """
    baseball_id = memory_system.create(baseball_memory)
    logger.info(f"Created baseball memory with ID: {baseball_id}")
    
    # Memory 8: Basketball
    basketball_memory = """
    Had an intense basketball game at the community center last night. Played full-court 5-on-5 for almost two hours.
    I scored 18 points including two three-pointers and had a few good assists. My defense was on point too - blocked 
    two shots and had several steals. By the end, I was completely drenched in sweat but feeling great. The cardio 
    workout was incredible. Our team lost by just three points, but it was one of the most enjoyable games I've played 
    in a while. Need to work on my free throws though - only made 2 out of 5.
    """
    basketball_id = memory_system.create(basketball_memory)
    logger.info(f"Created basketball memory with ID: {basketball_id}")
    
    # Memory 9: Tennis
    tennis_memory = """
    Played tennis with Sarah at the local courts this morning. We had a great rally going for most of the match.
    My serve was particularly good today - got several aces and had good placement. Backhand still needs work though,
    as I missed several shots on that side. We played three sets and I won 2-1, though the last set went to a tiebreak.
    The sun was quite strong so I got a bit of a tan (and maybe slight sunburn). My new racket definitely made a 
    difference in my game. Need to remember to bring more water next time - almost got dehydrated by the third set.
    """
    tennis_id = memory_system.create(tennis_memory)
    logger.info(f"Created tennis memory with ID: {tennis_id}")
    
    # Display all memories with their metadata
    logger.info("\n=== All Memories ===")
    for memory_id, memory in memory_system.memories.items():
        logger.info(f"ID: {memory_id}")
        logger.info(f"Content: {memory.content[:100]}...")
        logger.info(f"Context: {memory.context}")
        logger.info(f"Keywords: {memory.keywords}")
        logger.info(f"Tags: {memory.tags}")
        logger.info("---")
    
    # Demonstrate search capabilities
    logger.info("\n=== Search Results ===")
    
    # Search for "burger"
    burger_results = memory_system.search("burger", k=3)
    logger.info("Search results for 'burger':")
    for result in burger_results:
        logger.info(f"ID: {result['id']}")
        logger.info(f"Content snippet: {result['content'][:50]}...")
        logger.info(f"Score: {result['score']}")
        logger.info("---") 

    # Get a specific memory and display its details
    hamburger_memory = memory_system.read(hamburger_id)
    if hamburger_memory:
        logger.info("\n=== Hamburger Memory Details ===")
        logger.info(f"Content: {hamburger_memory.content}")
        logger.info(f"Keywords: {hamburger_memory.keywords}")
        logger.info(f"Context: {hamburger_memory.context}")
        logger.info(f"Tags: {hamburger_memory.tags}")
        logger.info(f"Links to other memories: {hamburger_memory.links}")
        logger.info(f"Creation timestamp: {hamburger_memory.timestamp}")



아래와 같은 결과를 나타냈다.

Keywords: ['hamburger', 'juicy', 'cheddar cheese', 'lettuce', 'tomatoes', 'special sauce', 'toasted bun', 'crispy fries', 'milkshake']

Context: The content reviews a dining experience at Joe's Diner, highlighting the quality and taste of a hamburger and its accompaniments, aimed at food enthusiasts or potential customers.

Tags: ['food', 'restaurant review', 'culinary experience', 'hamburgers', 'casual dining']

Links to other memories: []

Creation timestamp: 202503221647


실험 결과


BLEU-1, F1 Score로 성능 테스트를 했을 때, LoCoMo, ReadAgent, MemoryBank, MemGPT보다 더 좋은 성능을 보이고 있다. (BLUE-1, F1 score 성능 평가 참고 자료 https://devocean.sk.com/blog/techBoardDetail.do?ID=166716&boardType=techBlog)



해당 논문을 기반으로 현재 프로젝트로 진행하고 있는 챗봇 성능을 개선해보려고 한다.

References

https://zettelkasten.de/overview/

https://brunch.co.kr/@kys4620/104

https://github.com/agiresearch/A-mem


최신 아티클
Article Thumbnail
최윤한
|
2025.03.08
IT 커뮤니티 SIPE 3기 운영진 마침표.
SIPE 운영진 활동 회고와 SIPE를 고민하는 하는 사람을 위한 후기와 추천글
(python) spotlight로 시각화 feature vector
최윤한
|
2025.03.02
(python) spotlight로 시각화 feature vector
Spotlight로 Feature Vector 시각화
Article Thumbnail
최윤한
|
2025.02.16
[Python] 캐릭터 챗봇 장소 추천 기능 연구
RAG를 기반으로 Chatbot 개선 해보기.