구현 완료 오류 처리 · 최종 테스트 1.2

A2A 멀티에이전트

한 문장으로 지시하면 관리자가 실무자에게 맡기고, 검증자가 그 코드를 검사합니다. 만드는 쪽과 검사하는 쪽이 나뉘어 있습니다.

개발은 마쳤습니다. 이 문서에 적은 기능은 전부 구현했고, 지금은 예외 처리 점검과 최종 테스트 단계입니다 — 타임아웃 · 재시도 · 상한 초과 같은 실패 경로를 확인하고 회귀 테스트와 종단(E2E) 테스트를 돌립니다.

지시 한 건1.80원테스트 21개 포함 · 실측
에이전트3관리자 · 실무자 · 검증자
A2A 메서드6구버전과 호환된다

01

무엇이 나오는가

이메일 주소가 올바른지 검사하는 함수를 만들어줘 — 이 한 줄을 넣고 받은 실행 결과입니다. 아래 코드와 비용은 그 실행에서 그대로 옮겼습니다.

[사람]      이메일 주소가 올바른지 검사하는 함수를 만들어줘
[검증자]    반려 · [docstring] docstring 이 없는 함수: test_valid_emails, …
[검증자]    통과
[실무자]    결과 제출
[관리자]    결과 제출
import re
import unittest

def is_valid_email(email: str) -> bool:
    """Determine whether the provided string is a valid email address."""
    if email is None:
        return False
    if not isinstance(email, str):
        return False
    local_part  = r"(?:[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[…]+)*)"
    domain_part = r"(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?…)"
    regex = re.compile(rf"^{local_part}@{domain_part}$", re.IGNORECASE)
    if not regex.match(email):
        return False
    domain = email.split("@", 1)[1]
    if "." not in domain:              # 도메인에 점이 하나는 있어야 한다
        return False
    …

class TestIsValidEmail(unittest.TestCase):
    def test_valid_emails(self):
        """Test that a variety of valid emails are recognized."""
        valid_emails = ["simple@example.com", "x@example.com",
                        "user.name+tag+sorting@example.com", …]   # 9개
        for email in valid_emails:
            with self.subTest(email=email):
                self.assertTrue(is_valid_email(email))

    def test_invalid_emails(self):                                 # 12개
        invalid_emails = ["plainaddress", "@missinglocal.org",
                          "john..doe@example.com", "A@b@c@example.com", …]
        …

────────────────────────────────────────────────────────
  재작업 1회 · 검증 2회 · 호출 5회 · 토큰 4431/2278 · 비용 1.59원
이 한 건에서실제로 벌어진 일
검증자가 반려했습니다 첫 산출물에 테스트 함수 설명이 빠져 있었습니다. 실무자가 고쳐 다시 냈고 두 번째에 통과했습니다
테스트가 함께 나왔습니다 유효 9개 · 무효 12개, 모두 21개. 검증자가 이 테스트를 격리된 프로세스에서 실제로 돌려 통과를 확인했습니다. 테스트를 낼지는 배치가 정합니다 — 이 배치가 요구했기 때문에 나왔고, 상담처럼 테스트가 뜻 없는 일에는 내지 않습니다
비용 1.59원. 같은 지시를 다시 돌리면 1.80원 이 나왔습니다 — 모델이 매번 같은 코드를 내지 않기 때문입니다
사람은 무엇을 하나

지시를 넣고, 나온 결과를 보고 승인할지 다시 시킬지 정합니다. 마음에 들지 않으면 같은 대화에서 "이것도 고쳐 주세요"라고 이어서 지시하면 그 코드를 기반으로 고칩니다. 새로 만들지 않습니다. 에이전트끼리 주고받는 중간 과정에는 사람이 끼어들지 않습니다 — 지시와 최종 판단만 사람 몫입니다.

02

A2A 프로토콜

A2A 는 에이전트끼리 일을 주고받기 위한 공개 표준입니다. 이 시스템이 쓰는 것은 셋입니다 — SendMessage(일을 맡긴다), GetTask(진행을 묻는다), 그리고 부르기 전에 상대가 무엇을 할 수 있는지 확인하는 Agent Card 입니다. 이 셋만 지키면 서로의 속을 몰라도 함께 일할 수 있습니다.

맡기는 쪽 받는 쪽 GET /.well-known/agent-card.json Agent Card — 이름 · 스킬 · 주소 SendMessage — 일을 맡긴다 taskId · WORKING — 끝나기를 기다리지 않는다 GetTask — 어떻게 되고 있나 아직 진행 중 GetTask 완료 + 결과물(Artifact) 맡기는 것과 받아 오는 것을 나눠 두면, 오래 걸리는 일에도 연결을 붙잡고 있을 필요가 없다
주고받는 순서. 부르기 전에 Agent Card 를 읽어 상대가 할 수 있는 일인지 확인합니다. 이름이나 주소를 코드에 적어 두지 않고 Agent Card 를 보고 고르기 때문에, 에이전트가 바뀌거나 늘어나도 부르는 쪽 코드는 그대로입니다.

이 시스템이 표준의 어디까지 지키나

항목상태내용
Method 6종구현 SendMessage · GetTask · CancelTask · ListTasks · SendStreamingMessage · SubscribeToTask
버전 호환구현 규격이 한 번 바뀌며 메서드 이름이 달라졌습니다. 두 이름을 모두 받습니다 — 참고자료가 구버전인 경우가 많아 어느 예제를 보고 붙여도 막히지 않습니다
Agent Card구현 표준 경로로 엽니다. 구버전 경로와 호환됩니다
TaskState 9종구현 사양이 정한 이름을 그대로 씁니다 — 검증자 반려는 REJECTED, 사람 판단이 필요할 때는 INPUT_REQUIRED 입니다
Artifact구현 결과는 Message 가 아니라 Artifact 에 담습니다
Error Code구현 사양이 정한 코드로 돌려줍니다
Authentication일부 HTTP Bearer 1종입니다. OAuth 2.0 · OIDC · API Key · mTLS 는 이번 범위 밖입니다

표준 문서는 a2a-protocol.org 에 있습니다. Google Codelab 은 구버전(v0.3)이고 현행은 v1.0 입니다. 둘은 메서드 이름과 Agent Card 경로가 달라 섞으면 통신이 되지 않습니다 — 그래서 서버가 양쪽을 다 받습니다.

03

계층 격리

에이전트 하나의 영향 범위를 최소화하는 구조입니다. A2A 표준에는 에이전트끼리의 통신을 제한하는 기능이 없습니다. 그래서 부르는 쪽과 받는 쪽 양쪽에서 막았습니다.

사람 관리자 :8001 실무자 :8002 검증자 :8003 지시 · 최종 판단 위임 1:N 검증 요청 1:N 관리자 → 검증자 차단 겹 1 · 부르는 쪽 관리자 config 에 검증자 주소가 없다. 부르지 않기로 약속한 것이 아니라 주소를 얻을 수 없다. 겹 2 · 받는 쪽 검증자가 accepts_from 에 없는 발신자를 거부한다. 주소를 알아내도 문 앞에서 막힌다. 거부 응답 error.code = -32010 Task 자체가 만들어지지 않는다
왜 두 겹인가. 부르는 쪽만 막으면 포트가 열린 환경에서 주소를 직접 적어 넣는 것으로 우회됩니다. 받는 쪽에서 한 번 더 보기 때문에, 거부된 요청은 처리하다 중간에 멈추는 것이 아니라 작업이 생성되기 전에 돌아갑니다.

통신 허용표

보내는 쪽 → 받는 쪽허용비고
사람 → 관리자○지시와 최종 판단
관리자 → 실무자○1:N — 나눠 맡긴다
실무자 → 검증자○1:N — 판정을 모은다
관리자 → 검증자✕막혀 있습니다
사람 → 실무자 · 검증자✕사람은 관리자만 부릅니다

직접 확인하는 법

에이전트를 띄운 상태에서, 관리자인 척하고 검증자를 직접 불러 보십시오.

curl -X POST http://127.0.0.1:8003/ -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":"t1","method":"SendMessage","params":{"message":
      {"role":"ROLE_USER","content":[{"text":"검사해줘"}],"messageId":"m1",
       "metadata":{"issued_by":"manager"}}}}'
── 실제 응답 ──
{"jsonrpc": "2.0", "id": "t1", "error": {"code": -32010,
 "message": "'reviewer' 는 'manager' 의 요청을 받지 않는다. 허용: ['worker']"}}
인증에 대해

발신자 이름은 자기 신고로 받습니다. 위 curl 처럼 이름을 다르게 적으면 그 이름으로 취급됩니다. 로컬(127.0.0.1)에서는 충분하지만 외부에 열린 환경에서는 설정의 auth.token 을 채워야 실제 차단이 됩니다. 채우면 Authorization: Bearer 검사가 함께 돌아 두 조건을 모두 만족해야 통과합니다. 인증은 HTTP Bearer 1종만 넣었습니다. OAuth 2.0 · OIDC · API Key · mTLS 는 이번 범위 밖입니다.

04

검증과 재작업

검증자는 실무자보다 상위 권한입니다. 반려를 실무자가 요약하거나 눌러버릴 수 없고, 상태를 통과로 올릴 수도 없습니다. 재작업 횟수는 관리자가 예산으로 내려보내는 것이 아니라 실무자가 자기 횟수만 셉니다.

초안 작성 검증 요청 ? 통과 완료 보고 반려 ? 여유 있음 — 사유를 안고 다시 쓴다 상한 소진 반려 보고 max_rework 기본 3 — 조건부 엣지가 강제한다. 에이전트가 우회할 경로가 없다. 0 이면 해제.
상한이 구조로 강제됩니다. 재작업 여부를 판단하는 것은 코드의 if 문이 아니라 State Machine의 조건부 엣지입니다. 상한을 소진하면 완료가 아니라 반려로 보고되고, 그때의 사유가 사람에게 그대로 올라옵니다.

검증자가 하는 일 — 세 단계

단계무엇을 보나내용
정적 검사 6종서식이 맞는가 문법 · 함수 존재 · docstring · 이름 규약(snake_case) · 빈 except 금지 · 미완성 표시(TODO·FIXME·XXX) 잔존 금지
이름 검사요구한 이름 그대로인가 binary_search 를 요구했는데 BinarySearch 로 내면 반려합니다. 실무자가 자기 이름으로 테스트를 쓰므로 실행 검사만으로는 잡히지 않습니다
실행 검사실제로 도는가 test_ 로 시작하는 함수와 unittest.TestCase 를 격리된 별도 프로세스에서 돌립니다. 여러 파일이면 한 자리에 풀어 함께 돌립니다 — 서로 부르는 산출물이 따로 돌다 죽지 않게
판단요구한 일을 하는가 동작방식이 유료 LLM 일 때만. 요구사항과 코드를 함께 읽습니다

실행 검사의 격리 범위

별도 인터프리터 · -I(환경변수와 사용자 설정 무시) · 임시 디렉토리 · 시간 제한 5초. 네트워크와 파일 시스템까지는 막지 않습니다 — 그것은 컨테이너의 몫이라 상용 단계에서 붙입니다. 검사 항목과 시간 제한은 검증자 설정에서 조절하고, require_tests 를 켜면 테스트가 없는 산출물을 반려합니다.

판정은 원문 그대로 올라옵니다

실무자는 검증 결과를 편집 없이 그대로 첨부합니다. 전달자이지 편집자가 아닙니다. 검증자가 셋이면 판정문 셋이 그대로 붙습니다. 검증자가 죽어 판정을 받지 못한 경우에도 통과로 올리지 않습니다 — 조용히 통과되면 검증자 우위가 무너지기 때문입니다.

판정 서명 — 실무자가 바꿀 수 없게

두 가지 제약이 여기서 만납니다 — 검증자가 상위 권한이라는 것과 관리자는 검증자를 부를 수 없다는 것입니다. 둘을 같이 지키면 빈 자리가 하나 생깁니다. 판정은 실무자를 거쳐 올라오는데, 격리 때문에 관리자가 검증자에게 "정말 당신이 이렇게 판정했습니까" 하고 물어볼 길이 없습니다.

지금까지 이 자리를 지킨 것은 "실무자는 편집 없이 그대로 첨부한다"는 약속뿐이었습니다. 약속은 우리 코드가 지키는 것이지 강제되는 것이 아닙니다 — 타사 에이전트가 실무자 자리에 들어오면 그대로 무너집니다.

검증자 판정 + 서명 실무자 거쳐서 올린다 관리자 서명을 확인한다 여기서 고치면 서명이 깨진다 주소가 없다 — 물어볼 수 없다 서명은 판정 metadata 에 실린다 — 누가 · 어느 작업 · 무슨 판정 · 본문까지 묶어 계산한다. 사양 밖 필드를 만들지 않는다. metadata 는 A2A 가 정한 자리다.
키를 나눠 주는 것은 통신이 아닙니다. 관리자 설정에는 여전히 검증자 주소가 없습니다. 관리자는 검증자를 부를 수 없고, 다만 올라온 서명이 진짜인지 볼 수 있을 뿐입니다 — 격리는 그대로입니다.
막는 것막지 못하는 것
판정문 고치기 · 반려를 통과로 바꾸기 · 키 없이 서명하기 · 키를 모르는 이름으로 서명하기 · 서명을 떼어내고 올리기 검증자 자신이 잘못 판정하는 것. 서명은 "누가 말했나"를 보장하지 "옳은가"를 보장하지 않습니다 — 그건 검사와 판단의 몫입니다

표준 라이브러리만 씁니다. 키가 비어 있으면 아무 일도 하지 않습니다 — 지금까지와 완전히 같습니다(로컬 데모 기본값). 켜는 것은 배치가 정하고, 상용에서는 채웁니다. 켠 뒤에는 서명이 없는 판정도 사유가 되어, 떼어내는 것으로 검사를 피할 수 없습니다.

05

전문 실무자

실무자를 종류별로 둘 수 있습니다. 자바 실무자, HTML 실무자처럼요. 관리자는 이름을 코드에 갖고 있지 않고 Agent Card 를 읽어 맞는 상대를 고릅니다. 종류를 늘리는 일은 설정 파일 하나 + 관리자 목록 한 줄로 끝나고, 에이전트 코드는 한 줄도 달라지지 않습니다.

관리자 카드를 읽는다 지시에 맞는 역할을 고른다 실무자 · 자바 tags: [java] "자바로 add 메서드를" 실무자 · HTML tags: [html, implement] "로그인 화면을" 실무자 · 범용 역할을 안 내걸었다 맞는 전문가가 없으면 여기로 아무도 못 하는 일 위임하기 전에 멈춘다 돈이 들기 전에 사람에게 알린다
코드에 역할 목록이 없습니다. 실무자가 자기 Agent Card 에 무엇을 할 수 있다고 적어 두면, 관리자가 그것을 읽고 고릅니다. 실무자를 하나 더 늘리셔도 관리자 코드는 그대로입니다.

설정 한 장이 실무자의 역할을 정합니다

# 자바 실무자 — 카드에 java 를 내건다
skills:
  - id: implement.java
    name: 자바 메서드 구현
    description: 자바로 코드와 JUnit 테스트를 작성한다
    tags: [java]
    examples:
      - '두 수를 더하는 add 메서드를 작성하라'

# 나에게만 주는 지시 — 산출물이 역할을 실제로 지키게 한다
instruction: '반드시 자바(Java)로 작성한다. public class 와 JUnit 테스트를 포함한다.'

tags 가 관리자가 보는 자리입니다. examples 는 상대가 카드만 보고 우리를 부를 수 있게 하는 자리이고, 검증 항목이 이 예시를 그대로 보내 실제로 되는지 확인합니다 — 동작하지 않는 예시는 넣을 수 없습니다.

못 하는 일은 맡기기 전에 거부합니다

예전에는 맞는 상대가 없어도 전원에게 나눠 주었습니다. 그래서 개발자에게 건강 상담을 시키고 9.59원을 쓴 뒤에야 사람이 엉뚱한 결과를 봤습니다. 지금은 관리자가 위임하기 전에 카드를 읽고, 아무도 할 수 없는 일이면 거기서 멈춥니다.

멈출 때는 부를 수 있는 상대와 그들이 할 수 있다고 밝힌 일의 목록을 함께 보여 줍니다 — 무엇을 고쳐야 할지 알 수 있어야 하기 때문입니다. 판단 근거는 상대가 카드에 적은 것뿐이고, 코드에는 업무 목록이 없습니다.

개발이 아닌 일도 같은 구조로 돕니다

에이전트가 무엇을 하는 사람인지도 설정이 정합니다. 코드는 그릇이고, 무엇을 담을지는 설정이 정합니다. 그래서 같은 코드로 개발팀이 아닌 팀도 세울 수 있습니다.

배치구성비고
1x1x1관리자 1 · 실무자 1 · 검증자 1기본 배치. 여기서 시작합니다
roles실무자 3 — 범용 · 자바 · HTML관리자가 Agent Card 를 읽고 고른다
1x3x123실무자 3 · 검증자 6 (10노드)나눠 맡기고 종합하는 것을 본다

역할을 바꾸는 일은 설정 파일을 더하거나 지우고 관리자 목록에서 한 줄 고치는 것으로 끝납니다. DBA·설계자 같은 자문 역할도 같은 방법으로 세웁니다 — 설정 예시를 매뉴얼에 실었습니다. 상담처럼 기계로 검사할 수 없는 일은 검증 루프를 아예 끄는 것도 설정 한 줄입니다 — 다만 그때는 기계가 대신 봐 줄 수 없다는 점을 알고 쓰셔야 합니다.

실무자를 바꾸면 검증자도 함께 바꿉니다

자바 실무자에 파이썬 검증자를 붙이면 [문법] invalid syntax 로 반려만 돕니다. HTML 실무자의 산출물에 "테스트 함수가 없다"고 반려한 일도 실제로 겪었습니다. 그래서 실무자의 역할을 바꾸면 그 실무자에 물린 검증자 설정도 같이 고칩니다. 검증자도 실무자와 같은 방식으로 자기 기준을 설정에서 받습니다.

06

분배와 집계

한 지시를 여러 실무자에게 분배하고 결과를 종합합니다. 실무자 쪽과 검증자 쪽 양쪽 모두 여럿을 수용하며, 집계 규칙은 서로 다릅니다.

관리자 쪼갠다 못 쪼개면 복제 실무자 1 실무자 2 실무자 3 검증자 1 검증자 1 검증자 2 반려 검증자 1 검증자 2 검증자 집계 하나라도 반려면 반려 판정을 못 받으면 통과로 올리지 않는다 실무자 집계 하나라도 완료면 완료 일부 실패가 전체 실패는 아니다 — 사유는 보고문에 남는다
두 집계 규칙이 반대입니다. 검증은 엄격한 쪽(하나라도 반려면 반려)이고, 분배는 관대한 쪽(하나라도 완료면 완료)입니다. 검증은 품질의 문턱이고 분배는 작업량의 분산이라 기준이 다릅니다. 실패한 갈래의 사유는 버려지지 않고 보고문에 실려 사람이 판단합니다.
종합에 LLM 을 부르지 않습니다

여러 실무자의 결과를 합칠 때 모델을 다시 부르지 않고 표시를 붙여 이어 붙입니다. 검증자가 통과시킨 코드를 LLM 이 다시 쓰면 그 판정이 무의미해지기 때문입니다. 비용도 들지 않습니다. 쪼개지 못한 지시는 실패로 만들지 않고 같은 지시를 복제해 여러 명에게 맡깁니다 — 서로 다른 답이 나오는 것도 분배입니다.

배치를 골라 띄웁니다 — 코드를 고치지 않습니다

동봉한 배치는 셋입니다 — 1x1x1(3) · roles(5) · 1x3x123(10). 배치를 바꾸는 데 코드를 고치지 않습니다. 명령에 이름만 줍니다.

a2a sets                       쓸 수 있는 배치 보기 — 로컬과 서버를 한 화면에
a2a run --list --set 1x3x123   띄우지 않고 무엇이 뜰지만 본다
a2a start --set 1x3x123        10 노드로 기동 — 화면까지 함께 뜬다

포트 블록이 갈려 있어 셋을 동시에 띄울 수도 있습니다. 이름·포트 충돌은 기동하기 전에 잡습니다. 실무자를 하나 더 늘리시려면 설정 파일을 복사해 이름과 포트만 바꾸고, 부르는 쪽 목록에 한 줄 더하면 됩니다.

07

전달 방식

세 가지 전달 방식을 같은 규격으로 추상화했고, 세 가지를 동시에 쓸 수 있습니다. 어느 구간에 무엇을 쓸지는 설정 한 줄이 정합니다.

관리자 실무자 검증자 streaming 진행을 흘려보낸다 (SSE) 재작업 루프로 오래 걸린다. 「재작업 2/3」 이 사람 화면까지 그대로 올라온다. streaming 검사 진행이 위로 온다 정적 검사 · 테스트 실행이 단계마다 보인다. 끊기면 폴링이 받는다. 구간마다 다르게 걸 수 있다 — delegates 의 delivery 한 줄이 blocking · polling · streaming 을 고른다.
동봉한 설정에 실제로 걸려 있는 값입니다. 관리자는 실무자를, 실무자는 검증자를 스트리밍으로 부릅니다. 사람 화면과 관리자 사이도 같습니다 — 관리자 Agent Card 가 streaming 을 광고하므로 화면이 스트리밍으로 붙고, 광고를 끄면 한 번에 받는 방식으로 내려갑니다. 부르는 쪽 코드는 어느 방식이 꽂혀 있는지 모릅니다 — 설정만 바꾸면 방식이 바뀝니다.
방식상태동작과 쓰는 곳
blocking동작 답이 올 때까지 기다립니다. 아무것도 적지 않았을 때의 기본값이고, 몇 초에 끝나는 구간에 맞습니다
polling동작 맡기고 끝날 때까지 주기적으로 물어봅니다. 연결을 붙잡지 않으므로 끊겨도 Task 가 남습니다
streaming동작 동봉한 설정이 세 구간에 모두 걸어 둔 방식입니다. 진행을 이벤트(SSE)로 받고, 스트림이 끊기면 폴링으로 최종 상태를 확인합니다 — 스트리밍이 폴링을 안전망으로 씁니다
push미구현 세 방식과 같은 자리에 등록돼 있어 보내는 부분만 채우면 됩니다. 받을 주소는 서버가 이미 보관합니다. 지금 부르면 "이번 범위가 아니다"라고 명시적으로 알리고, Agent Card 에도 없는 기능이라고 표시합니다
진행이 실제로 흘러옵니다

사양의 스트리밍 메서드(SendStreamingMessage · SubscribeToTask)를 구현했고, 동봉한 설정에 실제로 걸어 두었습니다. 「지시를 다듬는 중」 · 「실무자 2명을 찾았다」 · 「재작업 2/3」 처럼 중간 단계가 단계마다 올라옵니다. 검증자의 검사 진행도 체인을 타고 위로 옵니다.

연결이 끊겨도 SubscribeToTask 로 다시 붙을 수 있습니다. 그래도 놓친 구간은 폴링이 받아 줍니다 — 스트리밍이 폴링을 안전망으로 씁니다. 폴링 간격(0.3초)은 코드 상수라 설정으로 빼려면 한 줄 작업이 남아 있습니다. 포기 시간은 설정의 wait_timeout 으로 조절합니다(기본 300초, 0 이면 무제한).

08

기록과 이어하기

결과물과 과정을 기록으로 남겨 재사용합니다. 실행이 파일로 남고, 같은 대화에서 추가 지시를 하면 지난 산출물이 실려 갑니다. 서버를 재시작한 뒤에도 그렇습니다.

1차 지시 "함수를 만들어줘" 산출물 파일로 저장 _data/<대화>.json DB 가 아니라 파일 서버 재시작 메모리는 전부 사라진다 2차 지시 — 같은 대화 "이것도 고쳐 주세요" 되읽는다 지시 + 지난 산출물 [이전 산출물 — 이 코드를 기반으로 수정한다] 실무자 새 함수를 만드는 것이 아니라 그 코드를 고친다. 이것이 "재사용" 의 실체다. 회귀 테스트가 이 경로를 검사한다 — "재시작 뒤에도 지난 산출물이 실려 간다".
재사용의 실체를 그대로 적었습니다. 지난 산출물의 본문을 머리말과 함께 다음 지시 뒤에 붙여 보냅니다. 완성된 저장소나 검색 기능이 아니라 기록과 이어하기입니다 — 기록을 직접 통제·관리할 수 있는 구조의 첫 자리입니다.

데이터베이스를 쓰지 않은 이유

작업 기록은 중첩된 문서라 관계형으로 쪼갤 것이 아니면 결국 JSON 칸 하나가 됩니다. 저장한 형식이 통신 형식 그대로라 스키마가 없고, 구조가 바뀌어도 이전 작업이 필요 없습니다. 무엇보다 사람도 AI 도 그냥 열어 읽을 수 있습니다. 기록이 수만 건이 되어 조회가 필요해지면 고칠 파일은 하나입니다.

쓰다 만 파일이 남지 않도록 임시 파일에 쓰고 한 번에 바꿔치기합니다. 기록이 깨져도 그 건만 건너뛰고 에이전트는 죽지 않습니다. 보관 한도(max_runs)를 주면 오래된 것부터 지웁니다 — 하루 이상 돌려 보실 때 디스크가 차지 않게 하기 위해서입니다.

09

비용

키 없이 도는 경로가 있지만 거기서는 쓸 만한 코드가 나오지 않습니다. 실제로 쓸 때 드는 비용을 먼저 적습니다.

실측비용결과
이메일 검사 함수1.59원 · 1.80원 같은 지시를 두 번 돌린 값입니다. 재작업 1회, 테스트 21개 포함
파이썬 함수 하나0.2~0.4원 한 번에 통과했을 때
최악 — 재작업 3회 소진2.5원 안팎 상한에 걸려 반려로 끝나는 경우
Spring Boot 골격0.79원 7개 파일. 한 번에 통과

100번 돌려도 200원 안쪽입니다. 단가는 설정한 모델을 따라가지 않으므로, 모델을 바꾸면 표시 금액도 함께 손봐야 합니다.

검증자 자기 호출 실무자 자기 + 검증자 관리자 자기 + 실무자 더해서 올린다 더해서 올린다 사람이 보는 숫자 체인 전체의 합계 이전에는 관리자 몫만 보여서, 가장 많이 부르는 실무자의 비용이 빠져 있었다. 지금은 호출 횟수와 원화가 항상 함께 보인다.
합산은 보고에 실려 올라옵니다. 각 에이전트가 자기 호출에 아래에서 올라온 몫을 더해 보고합니다. 상용 단계에서 비용을 따지지 않더라도 관측값으로 남깁니다.

동작방식 셋

동작방식비용무엇을 하나
유료 LLM
openai
실제로 쓰는 것
지시당 0.2~1.8원 모델이 코드를 쓰고 검증자도 읽고 판단합니다. 위에 보신 결과가 전부 이 경로에서 나왔습니다
기계적 규칙
rule
키 없이 도는 것
0원 쓸 만한 코드가 나오지 않습니다 — 아래 설명 참조. 키가 없어도 전 과정이 도는지 확인하는 용도입니다
로컬 LLM미구현 비용 0원으로 내용 있는 코드를 얻는 유일한 길 — 별건
무료 경로의 한계

0원짜리 경로에서는 쓸 만한 코드가 나오지 않습니다. 같은 이메일 지시를 키 없이 넣으면 나오는 것이 이것입니다.

def handle_request(data):
    """이메일 주소가 올바른지 검사하는 함수를 만들어줘"""
    if data is None:
        raise ValueError("data 가 필요하다")
    return True          # 무엇을 넣든 참이다 — 검사하지 않는다


def test_handle_request():
    assert handle_request("data") is True   # 스스로 만든 틀을 스스로 통과시킨다

이름도 is_valid_email 이 아니라 handle_request 입니다. 지시문을 이해한 것이 아니라 낱말을 보고 틀을 찍어낸 것이기 때문입니다. 여기서 검증자가 "통과"를 주더라도, 그것은 기계가 자기가 만든 틀의 서식을 본 것이지 이메일 검사가 맞는지 본 것이 아닙니다 — 그래서 이 경로에서는 검증자가 코드를 판단하지 않고 "판단하지 않았다"를 남깁니다.

그러니 0원은 "키가 없어도 전 과정이 돈다"를 확인하는 값이지 결과물을 얻는 값이 아닙니다. 비용 0원으로 쓸 만한 코드까지 얻으시려면 로컬 모델(Ollama·Qwen)을 붙여야 하고, 그것은 이번 범위 밖입니다.

비용이 새지 않게 하는 장치

항목기본값하는 일
max_rework3재작업 반복 상한
max_depth5위임 깊이 상한
max_llm_calls관리자 4작업 하나에 모델을 부르는 상한
max_workers · max_reviewers0 (전부)한 번에 부르는 폭의 상한
순환 감지항상A→B→C→A 를 감지해 중단합니다
재시도0 (끔)연결이 아예 안 될 때만. 답을 받은 뒤의 실패는 다시 부르지 않습니다

0 을 넣으면 해당 제한이 풀립니다. 코드에 박힌 상한은 없습니다. 상한에 걸리면 조용히 멈추지 않고 사유를 남기고 실패로 보고합니다. 키가 없거나 패키지가 없으면 자동으로 무료 동작방식으로 내려가 시연이 죽지 않습니다.

10

화면

왼쪽이 무엇을 시켰는가, 가운데가 누가 무엇을 했는가, 오른쪽이 결과와 판단입니다. 아래는 오늘 실제로 돌려 찍은 화면입니다.

A2A 콘솔 화면. 왼쪽에 실행 목록, 가운데에 관리자·실무자·검증자 런 트리와 로그, 오른쪽에 생성된 코드.
실행 화면. 가운데 트리에 관리자 → 실무자(재작업 1회) → 검증자(2회, 검사 8개 통과)가 계층 그대로 보입니다. 각 줄에 상태·소요 시간·비용이 붙습니다. 그 아래 로그는 스트리밍으로 올라온 진행입니다 — 「지시를 해석하는 중」 · 「정적 검사 - docstring」 · 「재작업 1/3」 처럼 단계마다 찍힙니다. 상단에는 관리자 연결 상태, 동작방식, 세션 누적 비용, 에이전트 생사(3/3) 가 상시 표시됩니다.
판정 탭. 통과 표시와 함께 검사 8개, 테스트 1개 실행이라고 적혀 있다.
판정 탭. 검증자 노드를 누르면 무엇을 봤는지 나옵니다 — 「통과 · 검사 8개 · 테스트 1개 실행」. 로그에는 첫 판정이 반려였고 재작업 1/3 을 거쳐 통과한 과정이 그대로 남습니다. 이 문장은 검증자가 쓴 그대로이며 실무자가 손대지 못합니다.
C# 지시에 대한 판정 탭. 검사 안 함, 자동 검사 대상 아님, 검사 0개, 실행 검사 건너뜀으로 표시된다.
파이썬이 아닌 언어 · 무료 경로. "C# 으로 …" 라고 지시하면 코드는 만들지만 기계 검사 도구가 없고 판단도 돌지 않아 「검사 안 함」으로 끝납니다. 검사하지 않은 것을 통과라고 말하지 않습니다 — 거짓 통과가 검증자 우위를 무너뜨리기 때문입니다. 유료 경로에서는 검증자가 그 코드를 읽고 판단합니다(아래 표).

언어는 어떻게 정해지나

언어를 지정하지 않으면 파이썬입니다. "두 수를 더하는 함수를 만들어주세요" 는 파이썬으로 나옵니다. 다른 언어는 지시문에 적습니다 — "C# 으로", "자바로".

지시문언어검증자
두 수를 더하는 함수를 만들어주세요파이썬 검사 6종 + 테스트 실행
파이썬으로 두 수를 더하는 함수를 …파이썬 검사 6종 + 테스트 실행
C# 으로 두 수를 더하는 함수를 …C# 범용 검증자는 읽고 판단합니다.
무료 경로면 「검사하지 않음」
자바로 add 메서드를 … (roles 배치)자바 자바 검증자가 자기 기준으로 판정

무슨 언어인지는 코드가 알아내지 않습니다. 지시문이 그대로 모델에게 전달되어 모델이 읽고 정합니다 — 코드가 먼저 정해 버리면 모델의 판단과 어긋날 수 있기 때문입니다. 코드가 가리는 것은 딱 하나, "기계 검사 도구를 가진 언어인가" 입니다. 기본 검증자의 정적 검사가 파이썬 문법 분석기라 자바 코드를 넣으면 무조건 문법 오류가 납니다. 그래서 파이썬이 아니면 기계 검사를 건너뛰고 건너뛰었다고 적습니다. 언어별 검증자를 세우면 그 검증자가 자기 기준으로 봅니다 — 자바·HTML 검증자가 그렇게 돌고 있습니다. 다만 그 판정은 코드를 읽은 결과이지 돌려 본 결과는 아닙니다.

화면 구성

영역내용
상단바관리자 연결 · 동작방식 · 세션 누적 비용 · 에이전트 생사
실행 목록지시 한 건이 한 줄. 검색과 상태 필터(전체·진행·완료·반려·실패)
런 트리누가 무엇을 했는지 계층 그대로. 노드를 누르면 오른쪽에 상세
상세 패널출력(코드·복사) · 입력 · 판정 · 메타(사용량·경로)
판단승인 · 반려 · 추가 지시 — 같은 대화로 이어집니다. 승인·반려는 사람의 기록으로 남고 에이전트에게 다시 보내지 않습니다
격리를 깨지 않고 트리를 그립니다

사람은 관리자만 부를 수 있어 실무자·검증자를 직접 조회할 수 없습니다. 대신 관리자가 올려 주는 결과 안에 체인의 기록이 순서대로 들어 있어, 화면이 그것으로 트리를 조립합니다. 생사 확인도 마찬가지로 체인을 타고 내려갑니다 — 화면이 검증자 주소를 알게 되는 일은 없습니다.

11

사용법

키가 없어도 전부 돕니다. Python 3.13 이상이 필요합니다.

01
설치

공통 라이브러리와 에이전트 셋, 콘솔까지 다섯을 한 번에 설치합니다. 명령은 하나입니다 — Windows 는 a2a, Linux 는 ./a2a.sh 로 부릅니다.

a2a setup
02
기동

에이전트와 웹 화면이 함께 뜹니다. 창을 닫아도 계속 돕니다. 띄우기 전에 무엇이 뜨는지만 보시려면 a2a run --list 입니다.

a2a start

────────────────────────────────────────────────
  reviewer       127.0.0.1:8003  수신 ['worker'] (끝단)
  worker         127.0.0.1:8002  수신 ['manager'] → reviewer
  manager        127.0.0.1:8001  수신 ['console'] → worker
  GUI(config)    :8080  사용자 인터페이스 (HTTP)
────────────────────────────────────────────────
03
CLI 로 지시

지시 없이 실행하면 대화 모드로 들어갑니다.

python -m console.cli "로그인 검증 함수를 만들어줘"
04
화면과 종료

화면은 기동할 때 함께 떴습니다. http://127.0.0.1:8080 을 브라우저로 엽니다. 에이전트가 살아 있는지는 a2a status 로 봅니다.

a2a stop

키를 넣는 곳

쓸 만한 코드를 받으시려면 키가 필요합니다. 프로젝트 맨 위 .env 파일에 두 줄을 넣습니다. 키는 직접 발급하며 저장소 어디에도 들어가지 않습니다.

OPENAI_API_KEY=sk-...       # 발급받은 키
BRAIN=openai                # 이 줄이 없으면 키가 있어도 무료 경로로 돕니다

키가 없거나 잘못되면 자동으로 무료 경로로 내려가 시연이 중간에 죽지 않습니다. 발급 절차는 별도 안내서로 드립니다.

지난 실행을 꺼내 쓰기

CLI 와 화면이 같은 기록을 봅니다. 화면에서 돌린 것을 CLI 로 이어갈 수 있습니다.

python -m console.cli --list                 지난 실행 목록
python -m console.cli --show <번호>          하나 자세히
python -m console.cli --resume <번호> "…"    이어서 지시 — 그때 산출물이 실려 간다
python -m console.cli --agents               에이전트 생사 확인

설정 한 장에 들어가는 것

에이전트마다 자기 설정 하나만 읽습니다. 전체 배치를 아는 파일은 없습니다.

# 관리자 — 검증자 주소가 어디에도 없다
self:         { name: manager, bind: 127.0.0.1, port: 8001 }
accepts_from: [console]              # 이 발신자만 받는다
delegates:
  - { name: worker, url: "http://127.0.0.1:8002",
      delivery: polling }            # 이 상대에게만 적용된다
limits:       { max_depth: 5, max_llm_calls: 4 }
auth:         { token: "" }          # 비면 토큰 검사 안 함
store:        { dir: ./_data, enabled: true }

이름·포트·바인드가 전부 설정에 있습니다. 코드에 이름 상수가 없어서, 같은 실무자를 둘 띄우려면 설정을 복사해 이름과 포트만 바꿉니다 — 코드 복제가 아닙니다.

12

기술 선택

에이전트 사이는 A2A 표준, 안쪽은 State Machine

두 축을 분리한 것이 이 구현의 핵심 판단입니다. 층이 다르므로 서로 경쟁하지 않습니다. 에이전트 사이를 State Machine 으로 이으면 모두가 같은 상태를 보게 되어, "관리자 ↔ 검증자 불가"가 규약으로만 남습니다.

계층채택이유
에이전트 사이A2A 표준 프로토콜
a2a-sdk 1.1.2
끝단에 외부 전문가나 타사 에이전트를 붙일 수 있어야 합니다. 자체 규약이면 상대가 우리 규약을 배워야 하지만, 표준을 쓰면 A2A 를 말하는 쪽은 그대로 붙습니다
에이전트 안쪽LangGraph
1.2.11
if 문으로 짜도 지금은 돕니다. 그러나 재작업 루프·사람 개입·중단 후 재개가 얽히면 흐름을 따라갈 수 없게 됩니다. 상한이 구조로 강제되는 것도 여기서 옵니다
전송표준 라이브러리 추가 설치가 필요 없습니다. Windows·Linux·macOS 에서 코드 수정 없이 돕니다

A2A 규약을 무엇까지 지키나

항목내용
Discovery/.well-known/agent-card.json — 구버전 경로와 호환됩니다
Method 6종SendMessage · GetTask · CancelTask · ListTasks · SendStreamingMessage · SubscribeToTask. v1.0 과 v0.3 을 모두 지원합니다 — 참고자료가 구버전인 경우가 많아, 어느 예제를 보고 붙여도 막히지 않게 했습니다
A2A-Version사양이 요구하는 A2A-Version 을 봅니다. 값이 없으면 사양대로 0.3 으로 보고, 모르는 버전은 -32004 로 거절합니다. 패치 번호는 빼고 봅니다
Data Model사양 밖 필드 0개. 선택 필드도 없는 것을 지어내지 않습니다
TaskState사양 9종. 검증자 반려는 REJECTED, 사람 대기는 INPUT_REQUIRED
Extension사양에 없는 것(깊이·경로·사용량·발신자·서명)은 metadata 에만 싣습니다. 필드를 새로 만들지 않아, 타사 에이전트가 우리 확장을 몰라도 메시지를 그대로 처리합니다
AgentSkill.examples스킬마다 실제로 돌려 본 예시를 넣었습니다. 상대가 카드만 보고 우리를 부를 수 있습니다. 검증 항목이 그 예시를 그대로 보내 전부 성공하는지 확인하므로, 동작하지 않는 예시는 넣을 수 없습니다
Capabilities카드에 내거는 기능을 설정이 정합니다. streaming: false 로 두면 그 기능은 실제로 동작하지 않습니다 — 광고와 구현이 어긋날 수 없는 구조입니다. 푸시는 없다고 적습니다

복잡한 규격 타입은 파일 한 곳에 가둬 두어 에이전트 코드에는 나오지 않습니다. 추가 개발을 AI 에게 맡기실 때 규격을 몰라도 되도록 한 조치입니다. 검증 방법은 눈으로 보는 것이 아니라, 우리 서버가 내보낸 형식을 표준 라이브러리로 되읽어 원본과 같은지 확인하고 그 검사를 회귀 테스트에 넣었습니다. 사람이 읽고 해석하는 것보다 정확하기 때문입니다.

취소의 한계

CancelTask 는 접수만 하고 진행 중인 작업을 실제로 멈추지 않습니다. 실행 중단은 내부 흐름을 다시 짜야 하는 일이라 이번 범위 밖입니다. 상태만 「취소됨」으로 바꾸고 돌던 일은 끝까지 간 뒤 버려집니다. 그래서 판정문에 그대로 그렇게 적습니다 — 검증자의 "검사 안 함"과 같은 이유입니다.

함수 하나를 넘어 — 여러 파일

"Spring Boot 로 기본 프로그램을 짜라"를 실제로 돌려 한계를 확인했습니다. 검증자는 제대로 일했습니다 — pom.xml 과 설정 파일이 없다고 정확히 짚어 반려했습니다. 막힌 곳은 판단이 아니라 산출물의 그릇이었습니다. 한 파일 안에 함수 하나를 담도록 못박혀 있어 디렉터리를 표현할 방법이 없었습니다.

지금은 여러 파일을 한 번에 냅니다. A2A 의 Data Model 에는 파일명을 담을 자리가 없고 거기에 필드를 더하면 사양에서 벗어나므로, 본문 안에 파일 경계를 표시하는 방식을 골랐습니다. 사양을 건드리지 않고 프로젝트 골격을 나를 수 있습니다.

=== FILE: pom.xml ===
<project>…</project>

=== FILE: src/main/java/com/example/DemoApplication.java ===
package com.example;
…

함수 하나를 요청하면 예전 그대로 나옵니다. 기존 경로를 뜯지 않는 것이 조건이었고, 회귀 테스트가 그것을 확인합니다. 계층 격리 · 검증자 우위 · 비용 0원 경로도 그대로입니다. 다만 이 기능은 보내 드린 견적의 범위 밖이라는 점을 밝혀 둡니다.

확장하는 방법

하고 싶은 것무엇을 하나
같은 종류를 하나 더설정 복사 → 이름·포트 변경 → 부를 쪽에 한 줄
새로운 종류의 에이전트프로젝트 폴더 하나 + 부를 쪽·받을 쪽 설정에 한 줄씩
검증자를 사람 전문가로주소만 바꿉니다. 사람 대기 상태로 멈췄다가 답이 오면 이어 돕니다
외부 회사 에이전트같습니다. 상대가 A2A 를 지키면 됩니다
별도 서버 배포바인드 주소만 바꿉니다. 코드 변경 없음
상한 해제 (상용)설정값을 0 으로

13

지금 상태

개발은 끝났습니다

이 문서에 적은 기능은 전부 구현을 마쳤습니다. 기능 추가는 끝났고 예외 처리 점검 · 회귀 테스트 · 문서 마무리가 남았습니다.

지금 하고 있는 것

납품 전 자체 점검

넘겨 드리기 전에 회귀 점검을 돌립니다. 고쳐서 다시 드릴 때 예전에 되던 것이 깨지지 않았는지를 확인하는 장치입니다. 직접 돌려 보실 수 있게 함께 넣어 드립니다 — a2a test 한 줄이고 추가 설치는 필요 없습니다. 현재 684건 전부 통과합니다.

묶음무엇을 검사하나
공통 라이브러리프로토콜 형식 · 격리 · 사용량 집계 · 다중 파일
에이전트세 그래프 · 재작업 · 분배 · 집계 · 판단
콘솔CLI · 오케스트레이션 · 종단 흐름
웹 화면화면 서버에 판단이 없는지까지 검사합니다
배치배치 · 이름·포트 충돌 · 확장성
전달 계층추상화 · 폴링 · 스트리밍 · 구간별 혼용
기록재시작 뒤 이어하기 · 껐을 때 회귀 안전
판정 서명위조 · 수정 · 떼어내기 · 이름 바꿔치기를 막는지
사양 스트리밍진행을 흘려보내고, 끊기면 다시 붙는지
역할과 스킬카드로 고르는지 · 못 하는 일을 거부하는지

이번 범위 밖

14

향후 개선 방안

다음에 얹을 것들입니다. 지금 구조에서 어디까지 준비돼 있고 무엇을 채우면 되는지를 항목마다 적었습니다. 방향은 하나입니다 — 지금의 실행 시스템 위에 스스로 정의하고 검증하고 다시 계획하는 루프를 얹는 것입니다.

1 · 지금 구조를 고치지 않고 붙는 것

항목지금 상태채울 것
실제 취소
CancelTask
CancelTask 는 접수해서 상태를 바꾸고 결과를 버립니다. 진행 중인 LLM 호출과 테스트 실행은 끝까지 돕니다 취소 신호를 실행 그래프까지 내려보냅니다 — LLM 호출 중단 · 검사 프로세스 종료 · 아래 단계 Task 취소 · 스트림 종료. 비용이 직접 걸린 항목이라 먼저입니다
에이전트 신원 발신자 이름(issued_by)은 자기 신고입니다. 격리는 이 이름과 accepts_from 으로 막고, 토큰을 켜면 호출 자체를 막습니다 에이전트마다 자격증명을 주고 토큰에서 신원을 끌어내 발신자를 정합니다. 다음이 OAuth 2.0 · OIDC, 그다음이 mTLS 입니다. 요구 사항은 Agent Card 가 알립니다
실행 격리 강화
sandbox
별도 인터프리터 · -I · 임시 디렉토리 · 5초 제한으로 돌립니다. 네트워크와 파일 시스템 차단은 아직 없습니다 메모리 · 프로세스 수 · 네트워크 차단 · 쓰기 경로 제한을 걸고 컨테이너로 감쌉니다. 모델이 만든 코드는 믿지 않는다가 전제입니다
푸시 알림
webhook
push 가 세 방식과 같은 자리에 등록돼 있고, 서버가 push_url 을 받아 보관합니다 보내는 쪽 — HTTP 콜백 · 실패 시 재시도 · 서명. 오래 걸리는 작업과 끊긴 화면에 씁니다
파이썬 외 언어 자동 검증 검증자가 언어를 판별하고, 기계 검사 도구가 없으면 unchecked 로 끝냅니다 javac · tsc · node 를 격리 프로세스에 물립니다
로컬 LLM 연동
Ollama · Qwen
동작방식이 rule(무료) · openai(유료) 두 구현으로 갈아 끼우게 되어 있습니다 같은 인터페이스로 로컬 모델 어댑터를 하나 더 만듭니다. API 비용 없이 내용 있는 코드를 얻는 경로입니다

2 · 품질을 올리는 루프 — 다음 단계의 핵심

지금은 사람이 쓴 지시가 실무자에게 거의 그대로 갑니다. 그래서 검증자가 보는 것도 "코드가 규칙에 맞는가"에 가깝습니다. 여기에 요구사항을 먼저 확정하는 단계와 실패 원인을 분석해 계획을 고치는 단계를 넣으면, 검증자가 "요구한 것을 다 했는가"를 판정할 수 있습니다.

지시 요구사항 수용 기준 관리자 실무자 검증자 관점별 · 여럿 판정 종합 실패 분석 · 재계획 반려 굵게 표시한 두 자리가 새로 붙는 단계다 — 지시를 검사 가능한 조건으로 바꾸고, 반려 사유로 계획을 고친다.
지금은 요구사항과 실패 분석 자리가 비어 있습니다. 관리자가 지시를 해석해 바로 맡기고, 반려되면 같은 계획 위에서 다시 만듭니다. 두 자리를 채우면 검증자가 "요구한 것을 다 했는가"로 판정하고, 반려는 계획 수정으로 이어집니다.
항목지금 상태채울 것
요구사항 · 수용 기준 관리자가 지시를 해석해 작업으로 다듬고, 여럿이면 나눠 맡깁니다. 통과 조건을 따로 못박지는 않습니다 관리자 앞에 요구사항을 정리하는 단계를 둡니다 — "정상 로그인은 200, 잘못된 비밀번호는 401" 처럼 검사 가능한 조건으로 적고, 검증자가 그 목록으로 판정합니다
관점별 검증자 검증자를 여럿 두는 구조는 이미 돕니다(실무자 하나에 검증자 1:N). 판정은 정적 검사 · 실행 검사 · 코드를 읽고 판단 세 가지입니다 검증자를 관점으로 갈라 세웁니다 — 보안 · 테스트 · 코드 품질 · 요구사항 충족. 종류가 다른 검사를 섞어야 한 검증자가 틀렸을 때 걸러집니다
판정 종합 검증자 판정에 서명이 붙어 실무자가 고치지 못합니다. 다만 서명은 "누가 말했나"를 보장할 뿐 "옳은가"는 보장하지 않습니다 여러 판정을 모아 하나로 정리하는 단계를 둡니다. 엇갈리면 사람에게 넘깁니다 — 다수결 하나로 끝내지 않습니다
실패 분석 · 재계획 반려되면 실무자가 같은 계획 위에서 다시 만듭니다(재작업 상한 3회) 반려 사유를 분류해 고칠 자리를 정합니다 — 코드만 고칠 일인지, 빠진 파일·설정을 더할 일인지, 요구사항부터 다시 볼 일인지
원인별 재시도 연결 실패 재시도가 있고 기본값은 꺼져 있습니다. 상한을 넘기면 반려로 끝냅니다 오류를 갈라 다르게 다룹니다 — 네트워크·타임아웃은 재시도, 인증·잘못된 요청은 중단, 호출 한도는 간격을 늘려 재시도, 테스트 실패는 재작업

3 · 운영과 확장

항목지금 상태채울 것
실행 추적 런 트리에 계층 · 상태 · 소요 시간 · 비용이 붙고, 로그에 주고받은 메서드가 남습니다 지시 하나에 추적 번호를 붙여 호출마다 지연 · 토큰 · 비용 · 재시도 · 모델 · 실패를 답니다. 화면에는 시간순 타임라인과 비용 내역, 왜 이 실무자를 골랐는지를 보여 줍니다
산출물 이력
Artifact
여러 파일은 === FILE: 경로 === 로 한 Artifact 에 담습니다. A2A Data Model 을 건드리지 않으려고 고른 방법입니다 파일마다 경로 · 형식 · 체크섬을 갖추고 누가 만들고 누가 검증했는지와 버전을 남깁니다. "이 코드가 어디서 나왔나"를 되짚을 수 있습니다
기억 지난 실행을 골라 이어서 지시하면 그때 산출물이 실려 갑니다. 찾아 쓰는 저장소는 아닙니다 프로젝트 단위로 요구사항 · 결정 · 산출물 · 판정을 쌓고 검색해 쓰게 합니다
에이전트 등록소 관리자가 Agent Card 를 읽어 스킬로 상대를 고르고, 아무도 못 하면 위임 전에 거부합니다 카드에 비용 · 응답 시간 · 성공률을 붙이고 요구사항 추출 → 능력 대조 → 정책 → 선택 순서로 고릅니다. 에이전트가 3개에서 30개로 늘어도 구조가 그대로입니다
예산 관리 에이전트마다 max_llm_calls · max_rework · max_depth 로 막습니다. 사용량은 관리자까지 올라와 합산됩니다 지시 하나에 금액 · 토큰 · 시간 예산을 주고, 남은 예산에 따라 검증 강도를 낮추거나 사람 승인으로 넘깁니다
평가 · 벤치마크 회귀 테스트로 기능이 깨지지 않았는지는 봅니다. 결과 품질을 재는 잣대는 없습니다 과제 묶음을 정해 두고 성공률 · 요구사항 충족률 · 재작업 횟수 · 평균 비용 · 사람 개입률을 잽니다. 고친 뒤 나아졌는지를 숫자로 확인하는 장치입니다

4 · 자율 운전 — 사람이 매번 승인하지 않게

위 항목이 갖춰지면 사람이 중간에 끼지 않고 도는 모드가 가능해집니다. 계획을 세우고, 맡기고, 검증하고, 실패를 분석해 다시 계획하는 루프를 스스로 도는 것입니다. 지금도 한 번의 지시가 재작업 3회까지는 사람 없이 돌지만, 그 범위가 지시 하나 안에 묶여 있습니다.

순서를 지킬 것

자율성은 안전장치가 먼저입니다. 실제 취소 · 실행 격리 · 예산 · 승인 정책이 갖춰지기 전에 사람을 빼면, 멈출 수 없는 작업이 비용을 쓰면서 계속 돕니다. 1번을 먼저 하는 이유입니다.

먼저 할 순서

순서할 일이유
1실제 취소비용과 자원이 직접 걸립니다. 실행 제어의 시작입니다
2에이전트 신원과 인증외부에 열려면 자기 신고를 없애야 합니다
3실행 격리 강화모델이 만든 코드를 돌리는 이상 기본 전제입니다
4요구사항 · 수용 기준결과 품질이 가장 크게 올라가는 자리입니다
5관점별 검증자와 종합검증자 하나가 틀렸을 때를 막습니다
6실패 분석 · 재계획같은 계획으로 다시 만드는 재작업에서 벗어납니다
7등록소와 능력 대조에이전트 수가 늘어도 구조가 버팁니다
8추적과 예산운영과 비용 관리의 바탕입니다
9산출물 이력결과를 되짚을 수 있게 합니다
10평가 · 벤치마크개선됐는지를 숫자로 확인합니다
설계를 먼저 정해야 하는 것

클라우드 배포(컨테이너 · 자동 확장) · 모바일 화면 · 다중 사용자 권한은 지금 구조 위에 바로 얹히지 않습니다. 배포 형태와 인증 방식을 정한 다음 작업하는 항목입니다.

위 항목은 전부 이번 범위 밖입니다. A2A 표준 객체(Task · Message · Artifact · Agent Card)는 그대로 두고 깊이 · 비용 · 출처 같은 정보는 metadata 에 싣는 지금 방식을 지키면, 나중에 다른 회사 에이전트와 붙일 때도 그대로 맞습니다.