Strands Agents 위에 에이전트 하네스를 직접 제작하여 공개했습니다 — 기억, 내부 상태, 승인 게이트를 추가한
요약
Strands Agents SDK 위에 에이전트의 기억, 내부 상태 관리 및 인간 승인(HITL) 게이트를 추가한 오픈소스 하네스 StiraCore가 공개되었습니다. 이 프레임워크는 NXP (Narrative Experience Protocol)라는 이름으로 작동하며, 3계층 메모리 구조와 안전 제어 장치를 제공합니다. 현재 알파 버전이며 로컬 환경에서 에이전트의 동작 원리를 실험하는 데 적합합니다.
핵심 포인트
- StiraCore는 Strands Agents SDK 위에 구축된 에이전트 하네스입니다.
- 3계층 메모리(Episodic/Semantic/Procedural), 내부 상태, 승인 게이트를 추가했습니다.
- NXP 프레임워크가 기억 및 안전 제어 역할을 담당하며, Amygdala Pass 등이 핵심 요소입니다.
- 현재 알파 버전이며 Amazon Bedrock에서 검증 가능합니다. 로컬 실험에 추천됩니다.
Strands Agents SDK 위에 올라가는 에이전트 하네스
StiraCore를 OSS(Apache-2.0)로 공개했습니다. 알파 버전입니다. 추가된 세 가지 요소는 다음과 같습니다.
① 3계층의 기억(Markdown + SQLite), ② 내부 상태(Neural State)와 서킷 브레이커, ③ 인간 승인(HITL)을 도구 인수에 바인딩하는 게이트
- '감정'은 주관적이거나 의식적인 것을 주장하는 것이 아니라,
에이전트의 상태 관리 및 안전 제어를 위한 수치 모델로 취급하고 있습니다. - 모델 없이도
StiraEngine
단독으로 작동합니다. 실제 모델 검증은 Amazon Bedrock에서만 가능하며, 작동하지 않거나 미완성인 부분은 README의 "Alpha status"에 모두 기재했습니다. 이 글에서도 언급하겠습니다. - 시각적인 계층으로서 상태를 읽을 수 있는 픽셀 아트 화면인 Stage도 있습니다. 캐릭터의 표정이나 움직임을 '장식'으로 만들지 않기 위한 설계는 이 글 후반부에서 소개하겠습니다.
- 추천 사용자: 로컬 환경에서 혼자 구동하며 에이전트의 기억, 중단 방법, 승인 설계를 만져보고 싶은 사람.
비추천 사용자: 로그인 기반의 멀티 유저 서비스를 바로 만들고 싶은 사람(Web 앱은 loopback 전용)이나, Bedrock 외 다른 곳에서 실제 운영 실적을 원하는 사람
리포지토리: https://github.com/Resolver-TNG/StiraCore
에이전트를 오랫동안 구동하면 같은 종류의 문제에 부딪힙니다.
기억하는 것이 뒤섞입니다. 대화 로그 전체를 넣으면 문맥은 채워지지만, 버리면 관계성이 사라집니다. 무엇을 남기고 무엇을 버릴지에 대한 기준이 없습니다.
- 오래 함께할수록 '개성'이 흐트러집니다. 아첨(迎合)이 쌓이고, 컨텍스트 압축으로 설정이 희미해지는 등의 문제가 발생합니다.
- 쓰기 계열 도구를 맡기는 것이 두렵습니다. '승인을 거치게 한다'는 것만으로는, 승인할 때와 실제로 실행될 때 내용이 달라도 알아차리기 어렵습니다.
Strands Agents SDK는 에이전트 루프(loop), 도구(tool), 모델 추상화가 깔끔하게 정리되어 있어 훌륭한 기반입니다. 다만 위에서 언급된 세 가지 요소는 SDK의 책임 범위가 아닙니다. 따라서 SDK를 건드리지 않고, 그 위에 계층을 쌓는 형태로 제작했습니다.
┌──────────────────────────────────────────────────────────────┐
│ NXP Memory Layer │
│ ├── Episodic / Semantic / Procedural (Markdown + SQLite) │
...
NXPAgent가 한 턴을 pre_turn()
→ 도구 필터링 및 컨텍스트 구성 → Strands 호출 → 자극 분류 및 post_turn()
순서로 구동합니다. 호출하는 쪽에서 pre_turn / post_turn을 직접 호출할 필요가 없습니다.
도표에 나온 이름들을 먼저 정리하겠습니다.
- NXP: 이 프로젝트의 기억/내부 상태 프레임워크 명칭(Narrative Experience Protocol)입니다.
NXPAgent가 Strands 에이전트를 감싸는 역할을 합니다. - Amygdala Pass: '이 사건을 기억할 것인가'를 결정하는 중요도 필터(기둥 1)입니다.
- Harvest: 일일 로그(Episodic)에서 증류된 지식(Semantic)을 만드는 처리 과정(기둥 1)입니다.
- Sokudan: 일본어 발화를 '자극(刺激)'으로 분류하는 분류기입니다. 옵션(
jevextra, Python 3.11)이 있으며, 기본값은 규칙 기반(기둥 2)입니다.
아래에서 기둥별로 소개하겠습니다.
| 계층 | 내용 |
|---|---|
| Episodic | 일일 로그 |
| ... |
Markdown이 원본이며, SQLite는 재구축 가능한 검색 인덱스입니다. 손상되어도 Markdown에서 복원할 수 있습니다. 에이전트가 스스로 쓸 수 있는 것은 Episodic 계층뿐입니다(memory_write). 쓰기 측면에는 Amygdala Pass라는 중요도 필터가 존재합니다. 턴 본문에 대한 결정적인 스코어링을 하며, < 0.4는 폐기되고 ≥ 0.7은 저장됩니다.
는 인간 검토 대기(staging)로 전송됩니다. 0.4~0.7은 기본적으로 staging으로 가며, Episodic에서 Semantic으로의 증류(Harvest)는 기본적으로 모델 호출이 없는 규칙 기반입니다. LLM 증류는 옵션입니다.
승인/거부는 CLI(stira_ctl.sh staging)를 통해 수행됩니다. 거부된 내용은 기억하여 재제안하지 않습니다.
'모든 것을 기억한다'도 아니고 '모든 것을 버린다'도 아닌, 기억하기 전에 인간의 관문(gate)을 두는 것이 이 계층의 사고방식입니다.
에이전트의 내부 상태를 6개의 수치로 가집니다.
trust
/ curiosity
/ vigilance
/ attachment
/ stability
/ satisfaction
사용자의 발화를 '자극'(connection, achievement, uncertainty 등)으로 분류하고 상태가 변합니다. 방치하면 기준값으로 돌아갑니다(Lazy Decay. 시간 기반의 망각 모델).
(재게시) '감정'은 상태 관리와 안전 제어를 위한 수치 모델이며, 주관적 감정이나 의식의 주장이 아닙니다.
상태 자체가 주인공이 아니라, stability를 모니터링하는 브레이커가 주인공입니다.
| 레벨 | 기본 조건 | 발생하는 일 |
|---|---|---|
| WARNING | stability < 0.5 | 쓰기(write) 계열 도구를 제거합니다. 아이덴티티(Anchors)를 재주입합니다 |
| ... |
히스테리시스(WARNING에서는 0.6 초과 시 복귀)와 쿨다운(CRITICAL에서는 0.45 초과 및 3턴 이상)이 있어 경계에서 흔들리지 않습니다. 임계값은 모두 StiraConfig로 변경할 수 있습니다.
모델 없이도 작동하므로, 동작을 직접 확인할 수 있습니다 (공식 Quickstart 참고):
from stiracore.core import BreakLevel, NeuralState, StiraConfig, StiraEngine
clock = [1000.0]
def now():
...
실제 채팅 화면에서는 6가지 값과 추이, 턴별 변화가 답변 아래에 표시됩니다.
- 기본 규칙 기반 분류기는 패턴이 영어여야 하며, 일본어는 거의 포착하지 못합니다. 일본어의 경우
jevextra(Python 3.11) 분류기가 필요합니다 - 실패/좌절/압박에 해당하는 자극 카테고리가 아직 없습니다. - 일방적인 긴 대화가 진행되면 stability가 0을 향해 붙어 CRITICAL 상태로 계속 유지되며 쓰기 계열이 제한됩니다. 이는 사양이지만, 포화를 조정하는 설정은 마련되어 있습니다.
'승인 버튼을 두었습니다'만으로는 부족하다는 것이 이 게이트의 출발점입니다. 승인은 보여준 내용 그 자체에 구속됩니다.
| 구속되는 항목 | 거부되는 조건 |
|---|---|
agent_id | 다른 에이전트가 사용하려고 시도했을 때 |
tool_name | 다른 작업에 사용하려고 시도했을 때 |
args_hash | 인수가 하나라도 다를 경우 (승인 후 훅이 교체된 경우 포함) |
expires_at | 답변이 느리거나/아무도 답하지 않을 때 (기본 120초) |
request_id | 다른 요청을 지칭하는 결정 |
args_hash는 정규화된 JSON(키를 정렬하고 NaN/∞가 없는)의 sha256입니다.
- 도구마다 Always / Ask / Never 규칙을 설정할 수 있으며, 규칙 → 브레이커 → 플로어(최소 보장) 중 가장 엄격한 것이 승리합니다. 승인 스토어는 **해시 체인(hash chain)**으로 영속화됩니다. 재부팅해도 대기 중인 승인은 남아있으며, 승인하면 도구 배치가 재개됩니다. 손상되거나 변조된 스토어는 모두 거부됩니다 - 규칙을 저장하면, 그 시점에 열려 있던 승인은 모두 무효화됩니다. 규칙을 변경하면서 오래된 승인이 통하는 구멍을 막기 위함입니다.
실행 계열 도구(shell / batch / cron / graph / swarm / think / use_agent)는 기본적으로 비활성화됩니다. STIRA_ENABLE_EXEC_TOOLS=1로 설정하더라도, 브릿지 부분이 감사된 것은 strands-agents-tools 0.8.9 뿐이므로, 그 외 버전에서는 등록을 거부합니다. pyproject.toml은 >=0.8.0,<0.8.10으로 고정되어 있습니다 (안전성을 위한 의도적인 선택).
일반 사용자에게 에이전트의 안전 설계를 전달할 때, 로그나 설정 파일만으로는 충분하지 않습니다. 무슨 일이 일어나고 있는지 화면으로 볼 수 있어야 합니다. 그래서 StiraCore에는 에이전트의 상태를 2.5D 픽셀 아트로 보여주는 Stage라는 화면을 추가했습니다 (STIRA_STAGE=1로 활성화).
캐릭터가 움직이고 반응만 하는 하네스는 다른 것도 있습니다. 하지만 Stage가 다른 점은, 움직임을 연출이 아닌 상태의 읽기(reading of state)로 설계했다는 점입니다.
- 장식으로 만들지 않습니다. 표정, 머그컵의 김, 소품의 빛, 네온 색상은 이벤트가 전달하는 상태(Neural State, 차단기(breaker), 열린 턴(turn), 실행 중인 도구(tool), 승인 대기)에서만 결정됩니다. 이벤트가 없으면 '바쁜' 모습은 나타나지 않습니다. 숨 쉬는 것, 눈 깜빡임, 머리카락의 흔들림처럼 아무 의미 없는 생명감만이 멋대로 움직일 뿐입니다.
- 값마다 원인을 명시합니다. 화면상의 값은 '김 = 2 ← 턴 시작(#3)'와 같이, 결정된 이벤트와 함께 유지됩니다.
Tab키를 누르면 캐릭터가 사라지고, 같은 상태가 숫자와 원인, 그리고 이벤트 로그로 볼 수 있습니다. 이는 그림이 데이터보다 더 신뢰받지 못하도록 하기 위함입니다. - 드리프트(Drift)를 감지합니다. 동일한 상태가 다른 포즈를 보이면, 원본 표시창에 'DRIFT detected'라고 출력합니다. 캐릭터의 일관성을 관찰 가능한 형태로 만든 것입니다.
- 에이전트는 자신을 좋게 보이게 할 수 없습니다. 에이전트가 선택할 수 있는 것은 제스처(머리, 귀, 팔, 머리카락, 눈, 입)뿐입니다 (선택 도구 자체는 다음 단계의 계획). 상태와 연결된 김, 소품, 네온, 흔들림은 움직일 수 없으며, WARNING / CRITICAL 사이에는 표정도 덮어쓸 수 없습니다. 실제보다 침착하게 보이게 하거나 바쁘게 보이게 할 수도 없습니다.
- 애니메이션 확장은 데이터만 가능합니다. 움직임 카탈로그는 허가된 곡선과 채널만을 가진 데이터로 구성되어 있으며, 에이전트가 작성한 JavaScript는 실행하지 않습니다. 이는 XSS나 권한 상승(privilege escalation)의 진입점이 되지 않도록 하기 위한 판단입니다.
답변에 포함된 ```svg 블록은 화면상의 화이트보드에 그림 형태로 그려집니다. 스크립트, 링크, 외부 리소스, 애니메이션은 허용 목록(whitelist)을 거쳐 재구축되기 때문에, 에이전트의 출력이 그대로 브라우저에서 실행되는 일은 없습니다 (기본 활성화 상태이며, 설정에서 비활성화할 수 있습니다).
도식화된 자료를 제공하는 것만으로 설명 전달 방식이 상당히 달라집니다. 여기서도 '보이는 것'이 안전성에 효과적입니다. 보이는 것은 인간이 확인할 수 있기 때문입니다.
...
git clone https://github.com/Resolver-TNG/StiraCore
cd StiraCore
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
pip install -e .
Python 3.11을 대상으로 합니다. 모델이 없는 StiraEngine입니다.
...
from stiracore import NXPAgent
agent = NXPAgent(
model_id="<your-bedrock-model-id>",
region_name="us-east-1",
agent_id="quickstart",
system_prompt="You are a concise assistant.",
)
result = agent("Remember that I prefer concise answers.")
print(result)
print(agent.last_turn_summary)
AWS를 사용하지 않는 경우에는 model=에 ModelSpec을 전달합니다 (Ollama, OpenAI 등. 자세한 내용은 docs/providers.md).
숨겨도 금방 알 수 있으니 미리 적어둡니다.
- 안정성 보장 없음.
0.1.0.dev0. API, 설정 키(config key), 파일 형식, 데이터 디렉토리 구성은 커밋마다 변경될 수 있습니다. - 로컬 단독 사용자용. 웹 애플리케이션에 로그인 과정이 없고, 루프백(loopback)으로만 대기합니다.
- CI 현황. 공개 리포지토리의 CI는 Ubuntu (Python 3.11 / 3.12)를 모든 PR에서, macOS (3.11)를 main 브랜치에 푸시할 때 실행하며, 둘 중 하나라도 실패하면 병합(merge)할 수 없도록 설정되어 있습니다. 가장 최근 동기화일(11/7) 이후의
main브랜치입니다.
녹색으로 되어 있습니다. **Windows는 CI 대상이 아닌 베스트 에포트(Best Effort)**로, 코드는 작동한다는 전제하에 작성했지만 테스트가 자동으로 통과할지는 보장하지 않습니다(수백 건이 실패하는 상태로 Issue #662에 남겨두었습니다). 공개 CI를 돌려보고 나서야 발견한 문제들이 많았습니다. symlink 경유 데이터 디렉토리, 테스트의 파일 디스크립터(fd) 누수, OS 의존적인 시간 처리 방식 등입니다. 개인 Mac 환경에서만 개발하면 알아차리기 어렵습니다. 한 예로,
파일의 동일성이라는 실질적인 격차 때문에, 이전에는 (dev, inode)만으로 보고 있었기 때문에, Linux(ext4 또는 tmpfs)에서 inode가 즉시 재사용될 경우 다른 파일을 같은 것으로 오인하는 것을 방지하기 위해 size와 st_ctime_ns까지 포함하여 판별하도록 수정했습니다. YOLO(일시적으로 승인을 완화하는 창)는 시계를 실측 가능한 macOS와 Linux에서만 제공합니다(Windows나 일시 정지될 수 있는 가상 머신에서는 제공하지 않습니다).
distiller_mode: "jev"
은 스텁이며, 모든 에피소드가 실패합니다. rule(기본값) 또는 llm을 사용하는 동안 가장 강하게 느낀 것은, 에이전트의 '지능'보다 '멈추는 방법', '기억하는 방법', '제약하는 방법'을 설계하는 데 시간이 많이 걸린다는 것이었습니다. 수치적인 내부 상태도 브레이커(breaker)도 '멈출 근거를 갖기 위한' 부품으로 배치하고 있습니다.
또 하나, 이 글에서 말씀드리고 싶은 방향이 있습니다. StiraCore는 '멈추게 하거나', '제약하는' 도구처럼 보일 수 있지만, 궁극적으로 목표하는 것은 **정렬(Alignment)**입니다 (에이전트가 인간의 가치나 의도와 일치하게 되는 것). 현재의 알파 버전은 정렬을 달성한 것이 아닙니다. 그곳으로 나아가기 위한 발판으로서, ① 기억하기 전에 인간의 관문(checkpoint)을 두는 메모리, ② 흔들림을 수치로 보고 멈추게 하는 내부 상태, ③ 승인을 실행 내용에 묶는 게이트를 작고 검증 가능한 형태로 쌓아 올리는 단계입니다. '일치하게 만드는 것'을 기꺼이 따르는 것과 혼동하지 않기 위해, 먼저 멈출 수 있고, 고칠 수 있고, 확인할 수 있는 상태를 인간 측에 남겨둡니다. 이 순서는 앞으로도 바꾸지 않을 것입니다.
여기는 미완성이고, 여기는 작동하지 않는다는 점도 그대로 공개했습니다. 사용해 보시고 막히거나 부족한 부분이 있다면 Issue로 알려주시면 감사하겠습니다.
- 리포지토리: https://github.com/Resolver-TNG/StiraCore
- 라이선스: Apache-2.0 (Stage의 아트 이미지는 CC BY 4.0)
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기