회고 에이전트 구현하기: 작동 방식
이전 글에서 저는 엔지니어링 시간이 어디에 쓰이는지 측정하려는 이유와, 작은 LLM 에이전트가 그 측정을 팀의 스프린트 회고에 녹여내는 데 어떻게 도움이 될 수 있는지 설명했습니다. 몇 달이 지난 지금, 여러 팀에 에이전트를 적용했고 이전에는 없었던 논의를 촉발하는 데 도움이 되고 있습니다.
이번 글에서는 에이전트가 어떻게 동작하는지, 데이터를 어떻게 전달받는지, 그리고 프롬프트가 어떻게 발전해 왔는지에 집중합니다. 기반이 되는 데이터 플랫폼, 특히 DORA 지표가 어떻게 도출되는지는 다음 글에서 따로 다룰 예정입니다.
개요
에이전트는 생산성 지표 데이터 플랫폼에서 지표와 활동 데이터를 가져와 스프린트를 요약하고 논의할 만한 주제를 제안하는 사전 회고 리포트를 생성합니다.
모든 원시 데이터를 모델에 쏟아붓는 대신, 에이전트에는 세 개 스프린트에 걸친 지표 요약과 특정 티켓, 머지 리퀘스트, 실패한 릴리스의 세부 정보를 조회할 수 있는 도구가 제공됩니다.
에이전트 설계
초기 프롬프트
초기 프롬프트는 세 개 스프린트에 걸친 지표를 요약하며, 각 지표를 [BASELINE] 또는 [LATEST - FOCUS SPRINT]로 태깅합니다. 지표는 Jira 딜리버리와 DORA 지표로 구성됩니다:
| DORA 지표 | Jira 지표 |
|---|---|
| 배포 빈도 | 이슈 및 스토리 포인트 완료율 |
| 변경 리드 타임(코딩 + 리뷰 + 배포) | 커밋한 범위 대비 스프린트 중 추가된 범위 |
| 변경 실패율 | 이월 |
| 서비스 복구 시간 | 사이클 타임 |
모든 지표는 데이터 플랫폼에서 결정적 코드로 계산되며, 모델에 원시 데이터로부터 직접 계산을 시도하도록 요청하지 않습니다. 프롬프트는 이 점을 명확히 합니다: "the metrics summary is authoritative, do not attempt to recalculate or second-guess it".
요약에는 사이클 타임이나 리드 타임이 75퍼센타일을 초과하는 등 이상치에 해당하는 티켓과 머지 리퀘스트 목록, 그리고 포커스 스프린트에서 발생한 실패한 릴리스 목록도 포함됩니다. 에이전트는 이 목록들을 분석의 출발점으로 활용하도록 지시받습니다. 티켓은 인라인에서 KEY (16.8d, 3.0SP) 형식으로, MR은 project!iid (308.7h: coding 116.3h, review 170.0h, deploy 22.4h) 형식으로 표기됩니다.
조회 도구
PydanticAI 에이전트에는 세부 정보를 조회할 수 있도록 세 가지 도구가 등록되어 있습니다:
@agent.tool
def lookup_jira_ticket(ctx: RunContext[AgentDeps], ticket_key: str) -> str:
"""Look up a Jira ticket by its key (e.g. PROJ-1363).
Returns summary, status, assignee, story points, sprint, dates, cycle time,
and full status transition history.
"""
@agent.tool
def lookup_merge_request(ctx: RunContext[AgentDeps], query: str) -> str:
"""Search merge requests by title substring, Jira key, or MR reference (e.g. !1049).
Returns up to 10 matching MRs with title, author, dates, lead time, and release info.
"""
@agent.tool
def lookup_failure(ctx: RunContext[AgentDeps], query: str) -> str:
"""Search detected failed releases by tag, project name, evidence, or alert tiny id.
Returns up to 10 matching failures with signal (alert/revert), evidence,
resolution time, and correlated alert detail where available.
"""독스트링은 모델이 추론하는 스키마 역할을 겸하고, 반환 페이로드는 에이전트가 서사를 만들기 시작하는 재료가 됩니다. 티켓은 전체 status_history가 읽기 쉬운 체인 형태(예: "In Progress → Code Review → Awaiting Release → Done")로 반환되어 "Blocked" 상태를 오가며 불안정했던 티켓을 식별하는 데 도움이 됩니다. MR은 코딩/리뷰/배포 시간이 구분되어 있고 해당 MR을 포함한 릴리스 정보가 함께 제공되어, MR 간의 공통 패턴과 릴리스 사이클에 미치는 영향을 파악하는 데 도움이 됩니다.
시스템 프롬프트는 에이전트가 이 도구들을 활용하도록 독려합니다: "use these tools proactively ... look it up before drawing conclusions".
출력 구조
에이전트의 출력 타입은 단순 문자열입니다. 구조화된 출력 스키마도, 후처리도 없습니다. 리포트를 만드는 유일한 기준은 프롬프트에 정의된 작업입니다. 최신 스프린트에 대한 간결한 요약, 베이스라인 대비 눈에 띄는 트렌드 2~4개("both positive and negative"), 그리고 세 가지 필수 헤딩(Sprint Summary, Notable Trends, Retrospective Talking Points) 아래에 작성되는 구체적인 논의 주제 또는 토론 질문 3~5개입니다.
트렌드는 2~4개, 논의 주제는 3~5개로 개수를 지정하면 선택과 집중을 강제할 수 있습니다. 세 번째 섹션을 결론이 아닌 질문 형태로 구성하면 리포트가 판정이 아닌 사전 공유 자료로 유지되며, 트렌드를 해석하고 대응을 결정할 수 있는 충분한 맥락은 팀이 가지고 있다는 신뢰를 전제로 합니다.
일반적인 실행 과정
일반적인 에이전트 실행 과정을 예시로 살펴보겠습니다. 요약에는 티켓과 MR 11개가 언급되었고, 에이전트는 필요한 세부 정보를 얻기 위해 11번의 조회를 병렬로 수행했습니다. 리포트는 한 번의 LLM 호출로 생성되었으며, 출력은 세 개 섹션으로 구성된 마크다운 리포트였습니다.
조회를 통해 리포트는 더 구체화되었습니다. 사이클 타임이 가장 길었던 이상치(16.8일)는 두 개 스프린트에 걸쳐 진행된 것으로 드러났고, 해당 머지 리퀘스트는 첫 커밋부터 릴리스까지 308.7시간이 걸렸습니다(코딩 116.3시간, 리뷰 170.0시간, 배포 22.4시간으로 구분). 다른 MR 하나는 전체 99.7시간 중 99.5시간을 리뷰에 썼습니다.
리포트는 병목이 배포가 아니라 리뷰 지연(중앙값 58시간, 이전 스프린트 대비 약 3배)에 있음을 짚어내고 논의할 구체적인 티켓/MR을 제시했습니다. 또한 릴리스 횟수가 23회에서 6회로 줄어든 반면 변경 실패율은 8.7%에서 0%로 개선된 점을 지적하며, 흐름이 느려진 것이 의도적인 리스크 관리인지 아니면 단순히 리뷰 단계에서 변경 사항이 적체된 결과인지 질문을 던졌습니다.
전체 실행은 두 번의 LLM 호출로 이루어졌습니다. 입력 토큰은 약 11,400개(두 번째 호출 중 3분의 1은 캐시 읽기), 출력 토큰은 2,200개였습니다. 집필 시점의 GPT-5.4 API 가격 기준으로 약 0.05달러이며, 대부분은 출력 토큰 비용입니다.
실전 프롬프트 엔지니어링
엔지니어 이름은 언급하지 않기
초기 프로토타입에서는 에이전트가 진행이 느린 티켓을 논할 때 엔지니어 이름을 자주 직접 언급했습니다. 비난 없는 회고 문화를 유지하기 위해 이를 방지하는 가드레일을 프롬프트에 추가했습니다. 에이전트는 개인 성과가 아니라 팀 전반의 트렌드와 작업 자체에 집중하도록 지시되었습니다.
이는 결정적 평가(deterministic eval)로도 커버할 수 있었습니다. 평가는 입력에 포함된 모든 담당자와 MR 작성자를 추출해 출력에 등장하면 실패 처리합니다. 프롬프트와 평가가 함께 규칙을 강제합니다.
스키마도 프롬프트의 일부입니다
에이전트는 필드 이름을 바탕으로 추론하므로 네이밍이 중요합니다. 초기 버전에서는 Jira의 status_category 필드를 기준으로 티켓의 상태와 완료 여부를 잘못 판단했습니다. 티켓 스키마에 is_done 불리언을 추가하자 문제가 해결되었습니다. 모호한 필드명이나 값을 모델이 해석하도록 두는 대신, 결정적 로직과 데이터 구조로 의미를 인코딩한 덕분입니다.
지시보다 구조가 우선합니다
프롬프트는 산출물이 가설임에도 "hypothesis"라는 단어를 쓰지 않습니다. 세 번째 섹션은 결론이 아니라 논의 주제와 토론 질문으로 구성됩니다. 회고는 사람이 주도해야 하며, 리포트 형식 자체가 이를 인코딩하므로 모델이 기억하도록 요구할 필요가 없습니다.
원래 프롬프트는 핵심 지표를 한눈에 볼 수 있는 요약 테이블도 요청했지만, 모델은 매번 다른 형식의 요약을 생성했습니다. 에이전트를 감싸는 웹 UI를 구축하면서 요약 테이블은 생성된 서사 옆에 배치되는 결정적 컴포넌트가 되었습니다. 출력의 일부가 매번 동일해야 한다면 LLM에 생성을 맡기지 않는 것이 좋습니다.
마무리
회고 에이전트는 팀에 작지만 유용한 도구로, 엔지니어링 회고에서 논의와 성찰을 촉발하는 데 도움이 됩니다. 프롬프트 엔지니어링과 조회 도구의 활용이 팀 역학을 존중하면서 실행 가능한 인사이트에 집중하는 가치 있는 AI 어시스턴트를 어떻게 만들 수 있는지 보여줍니다.
그 유용성의 상당 부분은 에이전트가 추론의 근거로 삼는 신뢰할 수 있는 데이터를 제공하는 하단의 지표 데이터 플랫폼에서 비롯됩니다. 이를 위해서는 어떤 지표를 추적하고 개발 워크플로에서 어떻게 계산할지에 대한 신중한 선택이 필요합니다. 다음 글에서는 그 플랫폼이 어떻게 동작하는지, DORA 지표를 어떻게 도출하는지, 그리고 이 모든 것이 엔지니어링 팀을 지원하기 위해 어떻게 연결되는지 자세히 살펴보겠습니다.
글을 무작위로 읽기