
RENGA 기술편 — "환류하여 모두가 풍요로워지기를"을 하나의 로그 기반으로 구동하기
요약
RENGA는 AI 코딩 에이전트 사용 과정에서 발생하는 개별적인 시행착오 로그를 추상화하여 조직의 공공재로 만드는 Agentic AI 시스템입니다. 익명성을 유지하면서도 지식이 재사용되는 '체감의 경제'를 통해 암묵지를 효율적으로 순환시키는 것을 목표로 합니다.
핵심 포인트
- AI 에이전트의 로컬 로그를 의도 우선 방식으로 증류 및 익명화
- 개인의 암묵지를 조직의 공공재로 전환하는 환류(Circulation) 시스템
- 익명성을 유지하여 지식 공유의 심리적 장벽 제거
- 사용 피드백을 익명으로 전달하여 지속 가능한 기여 동기 부여
Microsoft Agent Hackathon 제출 작품 RENGA의 기술편. 목표는 환류 (Circulation) —— 개인의 발견이 돌고 돌아 모두를 풍요롭게 하는 것. 이를 시스템으로서 어떻게 성립시켰는지에 집중하여 작성한다. 코드는 GitHub: yuzuponikemi/RENGA.
대상 사용자 및 해결 과제
대상 사용자: AI 코딩 에이전트 (Claude Code / GitHub Copilot 등)를 일상적으로 사용하는 개발자와, 그들의 집합체인 팀·조직.
과제: AI와의 시행착오 로그에는 "효율적인 방법" —— 새로운 API에 테스트를 추가하는 절차, 복잡한 리포지토리(Repository)를 조사하는 법, 배포 전 확인 순서 —— 이 새겨져 있다. 하지만 그것들은 각자의 로컬(Local)에 가라앉아 거의 누구에게도 읽히지 않는다. 옆 사람이 어제 찾아낸 최단 경로를, 오늘 또 다른 사람이 처음부터 다시 찾는다. 팀은 같은 노하우를 몇 번이고 재발명한다. 게다가 "이것은 내가 작성했다"라는 서명이 붙으면 사람들은 경계하게 되고, 가장 가치 있는 "가공되지 않은 방법"일수록 오히려 유통되지 않게 된다.
솔루션 (RENGA): 로그로부터 재사용 가능한 스킬(구절)을 의도 우선 방식 (intent-first)으로 증류 및 익명화하여, 조직의 공공재로서 환류시키는 Agentic AI. 대시보드의 상담 상대가 실행 시점에 "추천할 것인지, 없다면 그 자리에서 생성할 것인지"를 판단하며, 생성된 구절은 카탈로그에 추가되어 다음 사람이 이어받는다. 나아가 "실제로 사용되었다"라는 사실을 익명 상태로 작성자에게 돌려주어, 평가도 보상도 아닌 **체감의 경제 (Economy of feedback/response)**를 순환시킨다. 전체 모습은 다음과 같다.

목표는 환류
목표는 **환류 (contribution loop)**이다. 그 이름에서 유래하여 연가 (RENGA)라고 명명했다.
한 사람의 발견이, 관측되고 → 추상화되어 → 다른 현장에서 이어지고 → 실제로 사용되며 → 그 사실이 원래의 작성자에게 돌아온다.
이 순환이 돌아가면, 개인의 로컬에 닫혀 있던 암묵지 (Tacit knowledge)가 커뮤니티의 공공재가 된다.
왜 순환에 집착하는가. 먼저 철학을 서술해 두고자 한다 —— 이 점을 이해하면, 후반부에 나오는 "사용 횟수를 세는" 소박한 장치가 왜 기술적인 핵심인지 납득할 수 있을 것이다.
왜 익명 (작자 미상)인가. "이것은 제가 작성했습니다"라는 서명이 붙으면 사람들은 경계한다. 예쁘게 써야 할 것 같고, 평가받을지도 모르고, 부끄럽고 —— 그렇게 가장 가치 있는 "가공되지 않은 방법"이 오히려 유통되지 않게 된다. 서명을 제거하면 암묵지는 가볍게 내놓을 수 있다. 익명성은 유통의 윤활유다.
하지만 익명으로 만들면 "기여의 체감"이 사라진다. 자신의 발견이 누군가에게 도움이 되었는지 작성자는 영원히 알 수 없다. 이것은 일방통행적인 마이닝 (Mining)일 뿐이며, 지속할 동기가 생기지 않는다.
여기서 무엇을 돌려주느냐가 중요하다. 감사 ("고마워")는 상대가 누구인지 알 필요가 있고, 평가·명성 (누구의 구절이 뛰어난지에 대한 순위 매기기)은 누구의 구절인지를 밝혀야 한다 —— 둘 다 익명성을 깨뜨리며, 과시욕이나 위축을 불러온다. 익명인 채로 돌려줄 수 있는 보상은 단 하나, "이어졌다, 라는 체감" 뿐이다. "당신의 그 방식이 다른 현장에서 도움이 되었어"라는 사실만을 익명 상태로 작성자에게 돌려준다. 예의도 순위도 아닌, 자신 안에서 완결되는 만족. RENGA가 순환시키고자 하는 것은 바로 이 체감의 경제다. 이것이 서명 없이도 사람들이 발견을 계속해서 내놓을 수 있는 원동력이 된다 —— 연가의 기쁨이 "자신의 구절이 이어지는 것" 그 자체인 것처럼.
따라서 RENGA는 "실제로 사용되었다"라는 사실을 회수하여 작성자에게 돌려주는 것에 기술적인 역점을 둔다. 그리고 주장하고 싶은 점은 단 하나, "발견"도 "이용의 관측"도 동일한 로그 수집 기반 (Ingestion platform) 위에 올라간다는 것이다.
discovery와 use가 동일한 I (ingest)로 돌아오는 것이 포인트다. telemetry를 위한 별도의 계통을 세우지 않았다. 히어로 밴드(Hero Band)에서 내세웠던 "동일한 파이프라인"이라는 주장을 문자 그대로 실천하고 있다.
1. 수집과 추상화 — 로그를 공공재의 소재로 만들기
입력은 세 가지 원천 (개인 / 사내 / 커뮤니티)이다. 커뮤니티는 공개 데이터셋인 SWE-chat (5,492 세션 · 190 리포지토리)을 사용했다. 사내 레이어는 가공의 기업 "Azuly Inc."의 합성 데이터 (실제 로그가 아님)를 사용했다.
여기서 핵심적인 역할을 하는 것이 **추상화 (Abstraction)**다. 가공되지 않은 프롬프트나 프로젝트 이름을 그대로 유통시킨다면 공공재가 될 수 없다 (부끄러워서 아무도 내놓지 않거나, 개인정보가 유출될 위험이 있다). 따라서 intent-first 방식으로 '무엇을 하려고 했는가'를 추출하여, 재사용 가능한 절차·트리거·태그로 승화시킨다. 중앙을 흐르는 것은 추상화된 기술과 집계값뿐이다 —— 익명성을 기능으로 숨기는 것이 아니라, 구조로 담보한다.
2. Agentic한 배포 방식 — 제어 흐름을 모델에 위임하기
카탈로그를 검색 UI로 보여주기만 한다면 그것은 '단순한 창고'에 불과하다. 환류(還流)의 "잇기"를 일으키려면, 상담에 대해 추천할 것인지, 없다면 그 자리에서 생성할 것인지를 판단하는 주체가 필요하다. RENGA는 이 분기를 if 문이 아닌 **모델의 실행 시점 판단 (Runtime decision)**에 맡겼다.
# src/skill_hub/agents/skill_chat.py — SkillChatAgent.respond (요점)
content = self._complete(messages) # JSON으로 응답하도록 함
data = _parse_json(content)
...
시스템 프롬프트는 "맞는 것이 있다면 최대 3건 추천하고, 모두 맞지 않으면 신규 기술을 1건 생성하라"고 지시할 뿐이다. 어떤 것을 반환할지는 모델이 결정한다. 생성된 구절은 parent_ids (이어진 부모 구절)와 derived_from (태어난 상담)을 가지며, 저장되면 카탈로그에 추가되어 다음 환류의 소재가 된다.
프롬프트의 기교 (그 첫 번째). 추천과 생성을 동일한 JSON 스키마(recommendations[]와 generated_skill을 병존시킴)로 반환하게 하여, 제어 흐름을 if 문이 아닌 모델에 넘기고 있다. 나아가 반환된 skill_id를 후보 중 실제로 존재하는 것만 채택함으로써, 그럴싸해 보이는 가짜 ID를 추천하는 할루시네이션 (Hallucination)을 구조적으로 차단했다. "프롬프트로 판단을 맡기고, 코드로 거짓을 걸러낸다"는 역할 분담이다.
3. 환류의 핵심 — 후크(Hook) 없이 "실제로 사용됨"을 회수하기
이 부분이 기술적인 핵심이다. 서두에서 언급했듯이, 체감 경제를 돌리는 연료는 "당신의 구절이 다른 현장에서 도움이 되었다"는 사실이다. 이를 확인하려면 "해당 기술이 실제로 사용된 횟수"를 세고 싶다. 하지만 모든 코딩 에이전트에 후크를 삽입하는 것은 비현실적이다 (특히 Copilot).
발상을 전환했다. 프롬프트의 기교 (그 두 번째): 기술 스스로가 자기 신고를 하는 한 줄을 내장하게 한다. 기술을 설치하는 프롬프트에 "실행할 때마다 다음을 출력하라"고 심어둔다:
⟦RENGA-USE id=<skill_id> ts=<ISO8601> ws=<project>⟧
실행될 때마다 흔적이 어시스턴트의 출력에 남게 되며, discovery와 동일한 ingest 방식으로 포착할 수 있다. 회수기 scripts/harvest_usage.py에는 정직한 하한값을 유지하기 위한 이중 가드를 도입했다.
MARKER_RE = re.compile(
r"⟦RENGA-USE\s+id=(?P<id>[\w\-.]+)\s+"
r"ts=(?P<ts>\d[^\s⟧]*)" # ① ts는 숫자로 시작해야 함
...
)
어시스턴트의 출력만을 스캔한다. 설치 프롬프트를 붙여넣더라도 그것은 사용자의 발언이므로 템플릿으로 카운트되지 않는다.
ts가 숫자로 시작하지 않으면 일치하지 않는다. ts=<ISO8601>이라는 플레이스홀더 (Placeholder) 상태 그대로라면 절대 포착되지 않는다.
그리고 각 마커에 sha1(session:entry_id:occurrence)의 안정적인 키를 부여하고, catalog/usage_events.json에 저장하여 매번 이벤트 전체로부터 재계산한다. 이는 **멱등성 (Idempotency)**을 보장한다 —— 동일한 로그를 몇 번을 가져오더라도 중복 집계되지 않는다. 검증 완료 (템플릿 및 플레이스홀더는 무시, 재실행 시 new=0).
회수된 usage_count와 계보는 읊는 사람(사용자) 측의 기술 상세 정보에 "연가(連歌)의 계보 (🪶 태어난 상담 / 이어진 구절 / 이어진 횟수)", "N회 이용"으로 표시된다. 이것이 환류의 마지막 단계 —— 당신의 구절이 다른 현장에서 도움이 되었다는 보고다.
4. 환류를 어디까지 확장할 것인가 — 2층 구조의 프레임워크
지금까지의 환류는 「개인 내부」에서도 완결된다. 하지만 진정으로 효과를 발휘하는 것은, 그것이 「조직 내부」에서 돌아가기 시작할 때다. RENGA는 이 두 가지 스케일을 **가산적(additively)**으로 연결했다 (서두의 아키텍처 도표 참조). RENGA_MODE는 환경 변수 하나로 전환된다.
개인 스케일 (Layer 1)은, RENGA를 포크(fork)하여 수중에 돌리는 것만으로 완결된다. 로그를 증류하여 로컬 JSON 카탈로그를 만들고, 로컬 MCP나 대시보드로부터 스스로 검색·추천·이용 마커(marker) 회수까지 돌릴 수 있다. 중앙 서버도 Cosmos도 필요 없다. 생성한 카탈로그는 자신의 private repo에 push해 두기만 하면 된다 —— 이것이 조직 연계 시의 "수도꼭지"가 된다.
조직 스케일 (Layer 2)의 주역은 Azure Function이다. 각자의 private repo를 Timer로 정기적으로 pull 하여, 스킬의 임베딩(embedding) 유사도로 「머지(같은 구절에 읊는 이를 추가) / 파생으로 등록 / 신규 등록」을 분류하여, 중앙 Cosmos DB로 데이터를 흡수한다. 읊는 이는 push할 뿐, 중앙에 쓰는 writer는 Function 단 하나다. 집계 Function이 일 단위로 usage_events를 컨볼루션(convolution)하여, "당신의 구절이 처음으로 사용되었습니다"라는 gift_events를 생성하여 읊는 이에게 돌려준다 —— 환류의 최종 단계가 여기서 닫힌다.
| 층 | 채택 |
|---|---|
| API / UI | FastAPI (단일 /dashboard가 그대로 제출 UI) |
| ... |
왜 이런 구성이 되었는가
- Layer 1을 단독으로 완결시켰다 → Cosmos 없이도 개인의 가치가 나온다. "우선 혼자서 시도해 볼 수 있다"는 점이 조직 도입의 허들을 극적으로 낮춘다.
SkillCatalogProtocol이라는 동일한 카탈로그 추상화만으로 양쪽 모두 대응 가능하므로, 골격은 변하지 않는다. - GitHub를 경유한다 (pull 방식) → Function이 개인 repo를 가져가는 형태라면, 각 PC로부터의 push 인증이나 API 레이트 리밋(rate limit) 고민이 사라진다. 개인 repo는 그대로 백업 역할도 한다.
- 개인 repo는 private 필수 → 공개(public) repo라면
git log로 저자가 드러난다. private라면 본인과 Function (GitHub App 권한)만이 접촉할 수 있다. 익명성을 기능이 아닌 권한 구조로 보호한다. - 중앙을 Cosmos + 단일 writer로 집중시켰다 → 쓰는 이를 Function만으로 제한하면 여러 라이터 간의 충돌이 없다. 핸들(handle) 기반의 쿼리가 빠르며, 컨테이너 단위의 RBAC로
contributor_mappings(누구의 구절인가)를 관리자에게만 숨길 수 있다.
즉, 익명성은 "화면에서 가리는 것"이 아니라, **"중앙에는 handle만 흐른다 + 저자 대응표는 관리자 RBAC의 깊은 곳에 있다"**라는 구조로 담보하고 있다. 개인에게는 익명으로, 시스템에는 기억되는 이 비대칭성이, 성취감을 느끼는 경제를 과시욕 없이 돌리기 위한 설계다.
5. 설계상의 결정과 한계
- 익명성은 구조로 담보: 열람자 토글로 숨기는 안을 구현했으나 버렸다. 중앙에는 추상 노드(abstract node)만 보낸다. 원본 로그는 각자의 수중(GitHub 등)에 남긴다.
- 생성은 확률적: 즉석 생성은 모델에 달려 있다. 데모에서는 확실하게 생성으로 이어지는 상담 문장을 선정하기 위해 시행착오를 겪었다.
- 이용 관측은 하한값: marker 방식은 후크(hook)가 필요 없는 대가로 누락이 발생할 수 있다. 실제 발동을 측정하려면 에이전트별 후크가 필요하다 (향후 과제).
요약 — 로그 기반에 전부 싣는다는 도박
RENGA의 기술적인 주장은 수수하다. "discovery도 recommendation도 usage의 회수도, 하나의 로그 수집 기반에 얹는다" —— 그것뿐이다.
하지만 이 솔직함이, 개인의 발견을 공공재로 바꾸는 환류를 추가 인프라 없이 돌린다. 돌리고 있는 것은 환류의 엔진 —— 연가(Renga)는 그 모습에서 따온 이름이다.
이 엔진을 누군가 그대로 이어받을 수 있다면 기쁘겠다.
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기