Branch Agent: LLM 대화를 위한 Git 스타일의 브랜칭 (Branching)
요약
LLM 대화 과정을 Git의 브랜칭 모델처럼 관리할 수 있는 Branch Agent 아키텍처를 소개합니다. 대화를 트리 구조로 설계하여 모델, 프롬프트, 설정을 독립적으로 실험하고 병렬 비교 및 머지할 수 있는 효율적인 워크플로우를 제공합니다.
핵심 포인트
- 대화를 리스트가 아닌 트리 구조로 관리하여 포크, 브랜치, 머지 가능
- 포인터 참조 방식을 통해 O(1) 복잡도로 효율적인 브랜치 생성
- Convex를 활용한 ACID 트랜잭션 및 타입 안정성 확보
- Agno 프레임워크를 통한 다중 모델 및 도구 통합 지원
코드처럼 AI 대화를 포크(Fork), 브랜치(Branch), 머지(Merge)하세요 — 각 병렬 타임라인마다 서로 다른 모델, 프롬프트, 제공업체를 사용할 수 있습니다.
문제점 (The Problem)
LLM을 실험할 때 아마 이런 경험을 해보셨을 것입니다: 시스템 프롬프트(System Prompt)를 수정하고, 대화를 다시 실행하고, 두 개의 브라우저 탭에서 출력을 나란히 비교하며, 더 나은 응답을 수동으로 복사하여 붙여넣고, 이 과정을 반복하는 것입니다. 이는 지저분하고, 재현이 불가능하며, 버전 기록(Version History)도 남지 않습니다.
만약 LLM 대화가 Git과 동일한 브랜칭 모델을 가진다면 어떨까요?
아이디어 (The Idea)
대화는 리스트(List)가 아니라 **트리(Tree)**입니다. 모든 메시지는 포크 지점(Fork Point)이 될 수 있습니다. 새로운 브랜치는 포인터 참조(Pointer Reference)를 통해 해당 시점까지의 전체 컨텍스트를 상속받습니다 (O(1), 복사 불필요). 각 브랜치는 시스템 프롬프트, 모델, 제공업체(Provider), 온도(Temperature), 도구(Tools)와 같은 자체적인 에이전트 설정(Agent Configuration)을 가집니다. 브랜치들은 나란히 비교될 수 있으며, AI "판사 에이전트(Judge Agent)"를 통해 다시 머지(Merge)될 수 있습니다.
아키텍처 (Architecture)
┌──────────────┐ Convex hooks ┌──────────────────┐
│ Next.js UI │ ◄─────────────────────► │ Convex Database │
│ (React 19) │ useQuery/mutation │ (workspaces, │
...
왜 Convex인가?
Convex는 다음을 제공합니다:
- ACID 변이 (ACID mutations) —
forkBranch는 원자적(Atomic)이며 격리(Isolated)됩니다. - 결정론적 액션 (Deterministic actions) —
chatWithAgent액션은 트랜잭션 외부에서 실행되지만 내부 쿼리/변이를 안전하게 호출할 수 있습니다. - 타입 안정성 (Type-safe) — 스키마로부터 생성된 완전한 TypeScript 타입을 지원합니다.
왜 Agno인가?
Agno는 다음과 같은 기능을 지원하는 Python 네이티브 에이전트 프레임워크입니다:
- 통합 인터페이스를 통한 다중 모델 제공업체 지원
- 도구 통합 (웹 검색, 계산기, 파일 I/O 등)
- 중간 이벤트(도구 호출, 추론 단계)를 포함한 스트리밍 응답
- Pydantic 스키마를 통한 구조화된 출력 (Structured Output)
브랜치 모델 (데이터베이스 스키마)
스키마는 트리 순회(Tree Traversal)를 지원하기 위해 의도적으로 관계형(Relational)으로 설계되었습니다:
// convex/schema.ts
export const agentConfigSchema = v.object({
systemPrompt: v.optional(v.string()),
...
핵심 통찰: 브랜치의 snapshotMessageId는 해당 브랜치가 분기(fork)된 시점의 메시지를 가리킵니다. 히스토리 재구성(History reconstruction)은 parentBranchId → snapshotMessageId 포인터를 재귀적으로 따라갑니다. 이를 통해 분기는 **저장 공간 측면에서 O(1)**의 복잡도를 가집니다 — 메시지 중복이 발생하지 않습니다.
O(1) 분기 (Forking)
export const forkBranch = mutation({
args: {
sourceBranchId: v.id("branches"),
...
히스토리 순회 (History Traversal)
사용자가 메시지를 보내면, 액션(action)은 브랜치 트리(branch tree)를 순회하여 전체 컨텍스트(context)를 가져옵니다:
export const internalGetBranchHistory = internalQuery({
handler: async (ctx, args) => {
const branch = await ctx.db.get(args.branchId);
...
에이전트 응답 스트리밍 (Streaming Agent Responses)
chatWithAgent 액션은 전체 히스토리를 Python Agno 서비스로 전송하며, 해당 서비스는 SSE를 통해 토큰을 다시 스트리밍합니다:
// Convex 액션이 브랜치 설정을 읽어 Agno 서비스로 전송
const agnoPayload = {
messages: conversationMessages,
...
각 토큰 델타(delta)는 Convex 문서를 업데이트하며, 이는 프론트엔드의 반응형 useQuery 훅을 트리거합니다 — 이를 통해 UI는 응답을 부드럽게 스트리밍합니다.
Python Agno 서비스
# agno_service/agent_handler.py
def create_agent(
system_prompt: str = None,
...
이 서비스는 요청마다 새로운 Agent를 생성합니다 — 브랜치 간의 상태 누출(state leakage)이 없습니다. 각 브랜치는 완전히 다른 프로바이더(provider)를 가리킬 수 있습니다.
UI: 나란히 비교하기 (Side-by-Side Compare)
비교 뷰(compare view)를 통해 두 브랜치를 동시에 볼 수 있습니다. 이는 동일한 대화 히스토리에 대해 서로 다른 시스템 프롬프트(system prompts)나 모델을 테스트할 때 특히 유용합니다:
<CompareView
leftBranch={{ name: "main (GPT-4o)", messages }}
rightBranch={{ name: "fork (Llama)", messages: compareMessages }}
...
두 패널은 독립적으로 스크롤되며, 분기된 히스토리의 메시지에는 해당 소스 브랜치 이름이 태그로 붙습니다.
Judge Agent를 이용한 병합 (Merging with a Judge Agent)
포크(fork)가 질문에 대한 답변을 완료하면, 이를 다시 부모 브랜치(parent branch)로 병합(merge)할 수 있습니다. mergeWithJudge 액션은 두 브랜치의 히스토리(history)를 핵심 학습 내용을 요약하는 "judge" 프롬프트와 함께 Agno 에이전트(agent)로 전송합니다:
당신은 병합 심판(merge judge)입니다. SOURCE 브랜치로부터 얻은 핵심 학습 내용, 차이점, 통찰(insights)을 요약하고, 간결한 병합 요약본을 생성하세요.
요약된 내용은 대상 브랜치(target branch)의 시스템 메시지(system message)로 삽입되며, 소스 브랜치(source branch)는 병합된 것으로 표시됩니다.
프로젝트 실행하기 (Running the Project)
# 세 개의 터미널 필요:
npx convex dev # Convex 백엔드 (backend)
cd agno_service && python3 main.py # Agno Python 서비스 (service)
...
또는 단일 명령어로 실행 가능합니다: ./start.sh
향후 계획 (What's Next)
이 프로젝트는 쿡북(cookbook) / 참조 구현(reference implementation)입니다. 프로젝트를 확장하기 위한 아이디어는 다음과 같습니다:
- 차이점 보기 (Diff view) — 브랜치 간에 갈라진 메시지들을 강조 표시
- 프롬프트 플레이그라운드 (Prompt playground) — 초안 메시지에 대해 모든 브랜치가 어떻게 응답할지 미리 보기
- 브랜치 내보내기/가져오기 (Export/import branches) — 실험 내용을 JSON 파일로 공유
- 병합 충돌 자동 해결 (Auto-resolve merge conflicts) — 두 브랜치가 동일한 컨텍스트(context)를 수정했을 때, Judge Agent를 사용하여 조정
- 브랜치 템플릿 (Branch templates) — 특정 작업(연구, 코드 리뷰, 창의적 글쓰기)을 위해 사전 구성된 브랜치
기술 스택 요약 (Tech Stack Summary)
| 구성 요소 (Component) | 기술 (Technology) | 이유 (Why) |
|---|---|---|
| 데이터베이스 (Database) | Convex | 반응형 웹소켓 (Reactive WebSockets), ACID, 타입 안정성 (type-safe) |
| ... |
코드 및 기타 정보: https://www.dailybuild.xyz/project/177-convex-branch-agent
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기