말벗(Malbut)은 집 안을 이동하며 사용자와 대화하고 상호작용하는 바퀴형 AIoT 반려 로봇이다. 소프트웨어 마에스트로 팀 프로젝트로 진행하고 있으며, ROS 2 기반 주행과 사람 인식·추적, 홈캠, 대화 에이전트를 하나의 시스템으로 연결하고 있다.
내가 집중하고 있는 부분은 사용자의 말을 이해하고, 필요한 정보를 기억하며, 로봇 기능의 실행으로 이어 주는 Agent 계층이다. 대화 모델이 문장을 생성하는 순간부터 실제 시스템이 작업을 끝내는 순간까지 어떤 확인과 처리가 필요한지 설계하고 구현하고 있다.
현재까지는 안전한 이동 실행 경로와 대화·기억 처리, 노드 간 통신을 각각 검증했다. 다음 단계는 이 기반을 자연어 명령과 실제 음성 입출력으로 연결하는 것이다.
처음에는 자연어 요청을 로봇 행동으로 바꾸는 과정에서 실행 권한을 어떻게 통제할 것인가에 집중했다. “거실로 가줘”라는 문장을 이해했더라도, 로봇이 바로 움직여도 되는지는 별도의 문제다. 목적지가 현재 지도에 존재하는지, 로봇 상태가 최신인지, 비상 정지 상태인지, 같은 요청이 이미 처리됐는지 확인해야 한다.
초기에 구축한 텍스트 기반 이동 경로에서는 모델의 행동 제안, 사용자 확인, 작업 기록, 실행 직전 상태 검사를 분리했다. 승인 이후에 지도나 로봇 상태가 달라졌다면 실행을 차단하고, 중복 요청이나 동시 승인으로 같은 이동이 추가되지 않도록 처리했다.
실행 결과를 알 수 없는 상황도 별도로 다뤘다. 로봇이 요청을 받았는데 응답만 유실됐다면, 다시 보내는 것이 중복 이동을 만들 수 있다. 그래서 확인되지 않은 결과는 UNKNOWN으로 남기고 자동으로 재전송하지 않도록 했다. 이 경로는 Gazebo에서 정상 실행, 중복 요청, 안전 조건에 따른 차단, 응답 유실을 포함한 15개 시나리오로 검증했다. 당시 기록은 15개 모두 통과했으며, 승인 전 이동 목표와 중복 요청으로 인한 추가 실행은 모두 0개였다. Gazebo 검증 기록
최근에는 기능을 연결하기 위한 Agent와 Manager의 책임 구분을 구체화했다. Agent는 사용자 발화와 대화 문맥을 해석하고 필요한 기능과 입력을 구성한다. 독립된 Manager는 등록된 기능의 실행을 관리하고, 진행 상황과 최종 결과를 돌려준다. 실제 주행이나 사람 추적은 각 기능 노드가 담당한다.
이 구조에서는 “요청을 접수했다”, “실행 중이다”, “완료했다”를 서로 다른 상태로 다룬다. 취소도 마찬가지다. 취소 요청을 받았다는 응답만으로 로봇이 실제로 멈췄다고 안내할 수는 없다. Agent가 사용자에게 말하는 내용은 시스템에서 확인한 상태와 일치해야 한다.
현재 Agent와 Manager 사이에는 실행 요청, 진행 정보, 결과, 취소를 주고받는 ROS 2 Action 통신이 구현돼 있다. 다만 이 경로는 개발용 구조화 명령으로 검증한 상태다. 자연어 발화를 해석한 결과를 Manager의 실행 요청으로 넘기는 연결은 다음 작업으로 남아 있다. 통합 검증 및 남은 연결
대화 쪽에서 가장 크게 추가한 기능은 사용자 동의를 바탕으로 하는 장기기억이다. 말벗이 다음 대화에서도 사용자의 이름이나 반려동물 정보를 활용하려면, 대화 기록을 보관하는 것에 더해 어떤 내용을 사실로 저장하고 언제 활용할지 정해야 한다.
현재는 개인화에 동의한 사용자가 직접 말한 이름, 호칭, 반려동물 정보, 취향 등을 저장하고 관련된 대화에서 활용한다. 사용자는 기억을 조회하거나 정정·삭제할 수 있고, 개인화를 중단할 수도 있다. 개인화 중단과 기존 기억 삭제는 별개의 요청으로 처리한다.
기억 처리에서는 문장의 의미를 잘못 확정하는 경우를 특히 신경 썼다. 예를 들어 “두부가 아니라 초코야”라는 정정에서 이전 이름인 ‘두부’를 다시 저장해서는 안 된다. 모델이 제안한 기억 후보를 현재 발화와 대조하고, 대상이나 의미를 확정하기 어려운 경우에는 저장을 보류하고 질문하도록 했다.
저장 시점도 중요한 선택이었다. 답변과 기억 후보를 함께 생성한 뒤 저장하는 방식, 답변을 먼저 준비하고 저장을 나중에 하는 방식, 기억 추출까지 별도 호출로 미루는 방식을 비교했다. 최종적으로는 답변과 기억 후보 생성 → 검증과 저장 확정 → 응답 순서를 유지했다. 사용자가 결과를 들었을 때 실제 저장 상태도 그 설명과 맞도록 하기 위해서다. 비교 과정과 측정 결과도 함께 남겼다. 기억 처리 방식 비교
삭제한 기억이 다시 답변에 섞이는 문제도 다뤘다. 모델이 답변을 생성하는 동안 사용자가 기억을 삭제하거나 개인화 동의를 철회할 수 있다. 이때 늦게 도착한 답변을 그대로 전달하면 이미 철회한 정보를 다시 사용하는 셈이다. 이를 막기 위해 저장 확정 시점과 음성 응답 발행 직전에 기억 상태를 다시 확인하고, 과거 대화·요약·대기 중인 응답을 통해 삭제된 기억이 재사용되지 않도록 검사했다. 동의 기반 장기기억 구현
최근 통합 검증에서는 STT의 발화 처리 파이프라인에서 Agent의 대화·기억 처리를 거쳐 TTS 텍스트 수신기까지 실제 ROS Topic으로 연결했다. 같은 발화 ID가 중복 전달됐을 때 한 번만 처리되는지, Agent 노드와 대화 worker를 다시 생성한 뒤에도 기억을 조회할 수 있는지, 삭제된 기억이 다시 사용되지 않는지도 확인했다.
현재까지 확보한 주요 검증 기록은 다음과 같다.
| 검증 대상 | 기록된 결과 | 확인한 범위 |
|---|---|---|
| Gazebo 이동 실행 경로 | 정상·장애 시나리오 15/15 통과 | 승인, 중복 방지, 안전 조건 검사, 결과 불명 처리 |
| 실제 대화 모델과 장기기억 | 최종 사례 11개 발화·6회 API 호출 | 동의, 저장, 새 대화 조회, 정정, 삭제, 개인화 중단 |
| 대화·기억·ROS 통신 통합 | Ubuntu에서 1,054개 통과, 3개 생략, 실패 0 | 관련 5개 패키지 빌드와 구현된 Topic·Action 통신 |
각 결과는 검증 환경과 시점이 다르다. Gazebo 기록은 시뮬레이션에서의 이동 검증이고, 실제 모델 시험은 제한된 한국어 사례에서 HTTP와 대화 worker의 처리를 확인한 것이다. ROS 통합 시험에서는 음성 인식 결과와 모델 출력을 시험용 대역으로 제어했다. 이 기록들을 합쳐 실제 마이크부터 로봇 동작과 스피커 응답까지 완료됐다고 볼 수는 없다. 이동 검증, 모델·기억 검증, ROS 통합 검증
다음 작업은 세 가지로 좁혀졌다.
- 자연어 명령을 Manager 실행으로 연결하기. 사용자의 의도와 대상, 필요한 입력을 확인한 뒤 실행 요청을 보내고, 진행과 결과를 같은 대화에 연결한다.
- TTS 음성 합성과 재생 구현하기. 현재 텍스트 수신 단계에서 실제 합성, 순차 재생, 오류 처리까지 이어 간다.
- 실제 장비에서 전체 흐름 검증하기. 마이크 입력부터 대화·명령 처리, 로봇 동작, 음성 안내까지 확인하고, 취소나 통신 실패 상황에서도 안내와 실제 상태가 일치하는지 검증한다.
지금까지 가장 많이 고민한 부분은 모델의 판단과 시스템의 실제 상태를 어떻게 맞출 것인가였다. “기억했다”는 답변에는 저장 결과가 있어야 하고, “이동했다”는 안내에는 실행 결과가 있어야 한다. 확인할 수 없는 상황에서는 그 불확실성도 유지해야 한다.
다음 목표는 사용자의 한 문장이 실제 행동과 음성 안내까지 이어지는 장면을 만들고, 그 과정에서 기억·실행 권한·상태 관리가 함께 유지되는지 확인하는 것이다.
작성 기준은 2026년 9월 11일 확인한 GitHub main의 커밋 e701c5a과 병합된 PR·검증 문서다. 위 시험 수치는 저장된 기록을 확인한 것으로, 이번 글 작성 중 시험을 새로 실행한 결과는 아니다.