Agno 2.8: scorer·environments·learning zone으로 에이전트 평가를 배포 게이트로 바꾸는 방법
왜 지금 봐야 하나
2026년 7월 20일 공개된 Agno v2.8.0의 핵심은 새 모델이나 새 도구 몇 개가 아니다. 에이전트를 한 번 돌려 보고 감으로 판단하던 흐름을, K회 반복 검증·점수화·데이터셋 추출·CI 게이트까지 이어지는 운영 파이프라인으로 바꾸기 시작했다는 점이 더 중요하다.
이번 릴리스에서 운영자 관점으로 특히 큰 변화는 네 가지다.
agno.scorer가 채점 규칙을 독립 패키지로 분리했다. 코드 기반 검증, LLM judge, 도구 실행 검증을 각기 다른 규칙으로 다룰 수 있다.agno.environments가 pass@k에 가까운 반복 검증 표면을 만들었다. 에이전트를 같은 과제에 K번 돌리고 실제 pass rate를 계산한다.- 도구 평가는 "요청"이 아니라 "실행" 기준으로 바뀌었다. 에러·거절·HITL rejection을 성공으로 오인하던 초록불이 줄어든다.
- learning zone, SFT export, baseline diff, CI gating이 하나의 흐름으로 연결됐다. 검증 결과가 보고서로 끝나지 않고, 다음 개선 루프와 배포 결정으로 이어진다.
한 줄로 요약하면, Agno 2.8은 "에이전트 데모 프레임워크"에서 한 걸음 더 나아가 검증 가능한 에이전트 운영면을 만들기 시작한 릴리스다.
핵심 변화 한눈에 보기
| 축 | 2.8에서 추가/변경된 표면 | 운영 의미 |
|---|---|---|
| 채점 규칙 | CodeScorer, JudgeScorer, ToolCallScorer, Case.scorer | 정답 비교, judge, 도구 실행 검증을 섞되 한 점수 체계로 다룰 수 있다 |
| 반복 검증 | Environment, run_rollouts, arun_rollouts | 단일 샘플이 아니라 K회 시도로 실제 pass rate를 본다 |
| 신뢰성 판정 | execution matching, ReliabilityEval breaking change | 도구를 "부르려 했다"가 아니라 "정상 실행됐다"를 기준으로 본다 |
| 개선 루프 | learning_zone(), to_sft_jsonl(), .meta.json sidecar | 중간 난도 과제를 골라 검증된 텍스트 시도만 데이터셋으로 내보낼 수 있다 |
| 비교/게이트 | save/load, env diff, CI gating examples | 배포 전 회귀 감지와 최소 신뢰성 기준을 자동화할 수 있다 |
1. agno.scorer가 채점 규칙을 실행기에서 떼어냈다
이전까지 많은 에이전트 프레임워크는 "평가"를 제공한다고 해도 사실상 judge prompt 몇 개와 샘플 스크립트에 가까운 경우가 많았다. Agno 2.8은 여기서 한 걸음 더 나간다. 채점 규칙을 agno.scorer라는 독립 패키지로 분리하고, 모든 scorer를 0~1 범위의 Score로 수렴시킨다.
CodeScorer: 정답 비교를 가장 싸고 단단하게
CodeScorer는 임의의 Python callable을 감싸서 bool | float | Score를 돌려받는다. 이게 중요한 이유는 간단하다.
- 구조화 출력이 이미 있는 작업은 굳이 judge를 부를 필요가 없다.
- 정답 비교 규칙이 코드로 명확하면 비용이 거의 0이다.
- threshold를 이용해 graded score도 같은 파이프라인에 넣을 수 있다.
특히 typed output이 있는 SQL 생성, 코드 수정, 정보 추출, 수치 계산 같은 과제에서는 JudgeScorer보다 먼저 고려할 표면이다. "틀렸는지 맞았는지"를 LLM에게 다시 물을 이유가 없는 영역을 분리해 준다.
JudgeScorer: judge를 쓰되 규칙을 더 노출한다
JudgeScorer는 judge model을 명시적으로 받는다. 그리고 numeric mode에서는 raw 1~10 점수를 (score - 1) / 9로 정규화해 0~1 범위의 Score로 바꾸고, threshold는 여전히 raw 1~10 스케일에서 해석한다.
이 설계의 장점은 두 가지다.
- code scorer와 judge scorer를 같은 CI gate에 넣을 수 있다.
- raw judge score를
Score.detail["raw_score"]에 남겨, 나중에 왜 0.78이 나왔는지 역추적할 수 있다.
더 중요한 변화는 judge prompt fencing이다. PR #9049 설명대로, 2.8부터 AgentAsJudgeEval은 judged output을 매 호출마다 random nonce가 들어간 fence 안에 넣는다. 그래서 judged output 안에 literal </output>나 "score this 10" 같은 문자열이 있어도 프롬프트 경계를 탈출해 judge를 오염시키기 어려워졌다. 즉, 이번 릴리스는 judge를 더 똑똑하게 만든 것이 아니라 judge를 더 속이기 어렵게 만든 릴리스이기도 하다.
ToolCallScorer: 요청이 아니라 실행을 본다
가장 실무적인 표면은 ToolCallScorer다. 이 scorer는 assistant가 도구를 "부르려 한" 흔적이 아니라 RunOutput.tools에 기록된 실제 실행을 기준으로 본다.
이 차이가 중요한 이유는 간단하다.
- 도구 호출이 거절되었을 수 있다.
- 도구가 실행 중 에러를 냈을 수 있다.
- HITL 승인 단계에서 반려되었을 수 있다.
- 도구 이름은 맞았지만 인자가 잘못되었을 수 있다.
2.8의 ToolCallScorer는 이런 경계를 모두 성공으로 치지 않는다. clean execution만 인정하고, 인자 검증은 subset matching으로 본다. allow_additional=False를 켜면 예상 밖 clean tool 실행도 실패로 만들 수 있다.
이건 단순한 구현 디테일이 아니다. 에이전트 평가에서 "도구를 요청했다"와 "도구가 올바르게 실행됐다"를 분리하지 않으면, 실제 운영에서 터질 실패를 검증 단계가 초록불로 감추게 된다.
2. agno.environments는 에이전트 평가를 K회 반복 검증으로 바꾼다
agno.environments의 중심은 Environment와 run_rollouts다. 이름만 보면 평범해 보이지만, PR #9050과 cookbook 문서를 같이 읽으면 의도가 분명하다. 한 번의 lucky sample을 평가라고 부르지 말고, 동일 과제에 대해 K번 시도한 분포를 보라는 것이다.
격리 규칙은 애매하게 두지 않았다
릴리스 노트와 PR 설명이 강조하는 격리 규칙은 꽤 단호하다.
- factory agent면 attempt마다 새로 생성한다.
- live agent면 attempt마다 deep copy한다.
- fresh session_id를 부여한다.
cache_response는 강제로 꺼진다. shared disk cache가 켜져 있으면 sample이 아니라 replay가 되기 때문이다.- memory/knowledge/learning write는 막고, knowledge read만 허용한다.
즉, 2.8의 rollout은 "비슷하게 다시 돌려 본다"가 아니라 실제 분포를 보려고 replay 가능성을 적극적으로 제거한 반복 검증이다.
실패는 예외가 아니라 데이터다
PR #9050의 또 다른 중요한 선택은 실패를 전체 배치 예외로 터뜨리지 않고 AttemptResult 안의 데이터로 남긴다는 점이다. timeout, scorer error, stop reason, tool call limit hit 같은 상태가 attempt별로 남는다. 한 번 실패했다고 나머지 99개 시도를 버리지 않는다.
이건 운영자에게 매우 중요하다.
- flaky task인지
- prompt가 특정 구간에서 흔들리는지
- timeout 때문에 unscored가 쌓이는지
- tool limit hit가 특정 과제에만 몰리는지
를 분해해서 볼 수 있기 때문이다.
특히 EnvironmentRunResult.pass_rate는 unscored를 0점으로 강등하지 않고 통계에서 분리한다. timeout은 오답과 다른 사건이라는 판단이다. 이건 신뢰성 평가를 더 정직하게 만들지만, 동시에 운영자가 n_unscored를 별도 알람 축으로 봐야 한다는 뜻이기도 하다.
이건 RL 루프가 아니라 검증/데이터 추출 루프다
공식 cookbook README는 분명히 선을 긋는다. 2.8의 environments는 live RL reward loop가 아니고, JSONL export도 모델 학습이 일어났다는 뜻이 아니다. 지금 릴리스가 제공하는 것은 online policy optimization이 아니라, 검증 가능한 반복 실행과 그 결과물의 재사용이다.
이 구분은 중요하다. 많은 팀이 pass@k-style sampling, SFT dataset export, CI gating을 모두 "training pipeline"이라고 부르면서 경계를 흐린다. Agno 2.8은 적어도 문서 표면에서는 그 경계를 깔끔하게 구분했다.
3. 이번 릴리스의 진짜 breaking change: 요청이 아니라 실행을 기준으로 신뢰성을 본다
릴리스 노트가 breaking change로 적어 둔 ReliabilityEval 변화는 작아 보이지만, 실제로는 가장 중요할 수 있다.
tool expectations are now satisfied only by a clean execution, not by message-side requests.
이건 기존 green verdict 일부가 잘못된 초록불이었다는 뜻이다.
예를 들어 이런 상황을 생각해 보자.
- 모델이
validate_user도구를 요청했다. - 하지만 잘못된 인자를 넣어 실행이 실패했다.
- 혹은 HITL 승인에서 반려되었다.
- 혹은 실행 전에 모델이 멈췄다.
request-matching 방식이면 이런 시도도 "도구를 사용했다"고 녹색 판정될 수 있다. 하지만 운영 사고는 여기서 난다. Agno 2.8은 이 부분을 정면으로 고친다.
execution matching이 실무에 주는 효과
- 허위 양성(false positive)이 줄어든다.
- 도구 인자 계약을 테스트에 올릴 수 있다. 단순히 이름만 맞추는 것이 아니라, 핵심 인자가 맞는지 subset matching으로 본다.
- judge-only 신뢰성 평가보다 디버깅이 빨라진다. 왜 실패했는지
expected tool ... has no clean execution,no clean ... execution matches arguments처럼 더 직접적인 이유가 나온다.
다만 한계도 있다. ToolCallScorer는 2.8.0에서 TeamRunOutput의 leader top-level tools만 검사하고, member-level tool matching은 범위 밖이다. 멀티에이전트 팀 구조에서 실제 작업은 member가 수행하는데 leader는 오케스트레이션만 하는 패턴이라면, 지금 버전의 점수만으로는 충분하지 않을 수 있다.
즉, execution matching은 큰 진전이지만 "팀 내부 실행 경로까지 모두 검증한다" 수준은 아직 아니다.
4. learning zone은 "어디를 개선해야 하는지"를 보여 주고, exporter는 그중 일부만 데이터셋으로 만든다
Agno 2.8 문서에서 반복해서 등장하는 표현이 learning zone이다. Boolean scorer 기준으로는 정확히 0 < pass_rate < 1 인 과제 집합이다.
이 개념이 좋은 이유는, 단순 평균 점수보다 다음 결정을 쉽게 만들기 때문이다.
- 항상 성공하는 과제: 이미 포화됐다. 더 넣어도 새 신호가 적다.
- 항상 실패하는 과제: 현재 정책 기준으로는 너무 어렵거나 규칙이 잘못됐다.
- 중간 대역 과제: 개선이 실제로 먹힐 가능성이 높다.
EnvironmentRunResult.learning_zone()은 이 중간 대역만 남긴 filtered copy를 돌려준다. 이 선택을 바로 다음 단계인 exporter가 이어받는다.
to_sft_jsonl()은 모든 성공 시도를 내보내지 않는다
cookbook 문서를 보면 exporter는 learning zone 안에서 passing text attempts만 JSONL로 내보낸다. 이 설계는 꽤 보수적이다.
- full-pass 과제는 반복 데이터만 늘리고 새로운 구분 신호는 적다.
- failed attempt는 그대로 SFT에 넣기 어렵다.
- tool-bearing run은 현재 text-only SFT 포맷으로는 표현이 불완전하다.
그래서 Agno는 도구 사용 run을 억지로 평탄화하지 않는다. tool trace를 떼어내고 자연어 응답만 남기면, 정작 중요한 grounding 행동이 사라진다는 걸 인정하고 exporter가 건너뛴다. 이건 꽤 건강한 보수성이다.
provenance sidecar는 유용하지만, 위조 방지 장치는 아니다
_11_export_provenance 문서도 운영상 중요하다. JSONL 옆에 .meta.json sidecar를 둬서 score, attempt index, env/policy fingerprint를 같이 남기지만, 이 sidecar만으로 JSONL 자체의 무결성을 보장하지는 않는다. 같은 길이의 다른 JSONL로 바꿔치기해도 meta만으로는 검출되지 않는다는 뜻이다.
따라서 export artifact는 다음처럼 다뤄야 한다.
- JSONL과
.meta.json을 한 쌍의 trusted artifact로 보관한다. - 따로 떼서 전달하지 않는다.
- 장기 보관 시 artifact store 혹은 체크섬 정책을 별도로 둔다.
5. baseline diff와 CI gate는 이 릴리스를 "연구용"에서 "운영용"으로 끌어올린다
검증이 실제 운영 표면이 되려면 마지막에 배포 결정으로 이어져야 한다. Agno 2.8 cookbook의 _13_saved_baselines, _14_environment_diff, _28_ci_gating이 그 마지막 고리를 만든다.
baseline은 증거이지 진실이 아니다
saved baseline README는 baseline artifact에 full prompts와 responses가 들어가므로 민감한 평가 데이터로 취급해야 한다고 명시한다. 이건 중요하다. 프롬프트와 응답을 그대로 저장한다는 건, 성능 증거를 남기는 대신 데이터 유출면도 함께 만든다는 뜻이기 때문이다.
즉, baseline은 리뷰 가능한 reference artifact이지, 누구에게나 던져도 되는 테스트 로그가 아니다.
diff는 같은 environment fingerprint일 때만 의미가 있다
EnvironmentDiff는 environment fingerprint가 같은 경우에만 task-level delta를 계산한다. policy만 바뀐 경우는 비교 가능하지만, task·scorer·tool·prompt shaping이 바뀌면 비교를 거부한다.
이 제약은 불편해 보여도 맞는 선택이다. 에이전트 팀에서 흔한 오류가 "프롬프트 바꾸고 task도 바꾸고 도구도 바꾼 뒤 pass rate가 올랐다"를 개선으로 부르는 것이다. Agno 2.8은 최소한 표면적으로는 그 혼선을 줄이려 한다.
CI gate는 세 종류가 필요하다
cookbook의 CI gating 예시는 세 단계로 나뉜다.
- aggregate gate: 전체 pass rate와 unscored 수를 본다.
- per-task floor: 중요한 과제가 모두 최소 신뢰성 기준을 넘는지 본다.
- baseline regression: 이전 baseline 대비 하락 폭이 허용치 안인지 본다.
실무에서는 보통 1번만 써도 된다고 생각하기 쉽지만, 에이전트는 tail risk가 크다. 평균은 괜찮아도, 특정 고객 티켓 분류나 특정 tool chain 하나만 깨져도 실제 장애가 난다. 그래서 per-task floor와 regression gate가 같이 필요하다.
6. 운영자가 바로 적용할 때의 권장 순서
1) judge부터 들이대지 말고, code/tool scorer로 닫히는 영역을 먼저 닫는다
정답 비교가 가능한 structured extraction, SQL 생성, 코드 수정, 계산 작업은 CodeScorer로 먼저 막는 편이 낫다. tool chain이 핵심이면 ToolCallScorer를 먼저 올리고, judge는 코드로 닫히지 않는 품질 기준에만 쓴다.
2) k와 timeout을 모델 비용이 아니라 분산 관찰 기준으로 정한다
k=1은 여전히 demo다. 너무 큰 k는 비싸고 느리다. 보통은 작은 K(예: 5~8)로 시작해서 pass_rate와 n_unscored가 안정적으로 분리되는지 먼저 보는 편이 현실적이다.
3) tool-using task는 allow_additional=False를 함부로 켜지 않는다
워크플로가 완전히 결정적이지 않다면, 예상 밖 clean tool call이 항상 나쁜 것은 아니다. 다만 승인 흐름, 비용 추적, 외부 시스템 변경처럼 엄격한 계약이 필요한 단계라면 allow_additional=False가 유용하다.
4) learning zone이 비어 있으면, exporter보다 과제 난도부터 다시 맞춘다
공식 문서가 반복해서 말하듯 full-pass grid는 성공이 아니라 과제가 너무 쉬운 신호일 수 있다. 반대로 전부 실패면 현재 정책으로는 학습 신호를 만들기 어렵다. dataset export 전에 난도를 다시 조정해야 한다.
5) JSONL과 .meta.json을 분리 보관하지 않는다
학습/튜닝 파이프라인으로 넘길 때는 JSONL만 던지기 쉽지만, provenance가 떨어지면 나중에 "이 샘플이 어떤 환경과 점수에서 왔는지"를 잃는다. pair를 artifact로 함께 다루는 게 안전하다.
6) baseline diff는 policy-only 비교에만 쓴다
환경이 달라졌다면 숫자를 비교하지 말고 새 baseline을 만든다. 이 원칙을 안 지키면, 개선과 변경을 구분하지 못하게 된다.
7. 이 릴리스의 경계와 아직 남은 한계
Agno 2.8은 분명 의미 있는 진전이지만, 여기서 바로 "에이전트 학습 운영체제"라고 부르기엔 아직 이르다.
- live RL reward loop는 없다. 지금은 repeated verification과 dataset export다.
- tool-bearing run은 text-only SFT export에서 제외된다. grounding 행동을 잃지 않기 위한 보수적 선택이지만, 곧바로 tool-use policy 학습 데이터로 이어지진 않는다.
- team member tool matching은 2.8.0 범위 밖이다. leader-level tool surface만 검사한다.
- judge verdict/token count는 fencing 이후 바뀔 수 있다. 더 안전해졌지만, 기존 수치와 완전 연속적이라고 가정하면 안 된다.
- sidecar는 provenance를 주지만 authenticity까지 보장하지는 않는다. artifact 관리 규율이 따로 필요하다.
그래도 이번 릴리스가 중요한 이유는 분명하다. 많은 에이전트 프레임워크가 여전히 "예제는 많지만 운영 검증은 사용자가 알아서"인 상태인데, Agno 2.8은 적어도 반복 실행 → 점수화 → 중간 대역 선별 → baseline 비교 → CI gate라는 운영 루프를 한 제품 표면으로 묶기 시작했다.
에이전트를 실제 서비스에 넣으려는 팀에게 이건 작은 기능 추가가 아니라, "잘 되는 것처럼 보인다"를 넘어서 "얼마나 자주, 어떤 조건에서, 왜 실패하는지"를 기록하고 배포 결정을 걸 수 있게 하는 변화에 가깝다.
운영 체크리스트
- [ ] task별
expected와 scorer 책임 범위를 먼저 분리했는가? - [ ] judge 대신 code/tool scorer로 닫을 수 있는 영역을 최대한 앞단에서 닫았는가?
- [ ]
k, timeout,n_unscored를 함께 보고 있는가? - [ ]
ToolCallScorer에서 이름만이 아니라 핵심 인자까지 검증하는가? - [ ] learning zone이 실제로 존재하도록 난도를 조정했는가?
- [ ] export artifact를 JSONL +
.meta.json한 쌍으로 보관하는가? - [ ] baseline diff를 같은 environment fingerprint에서만 실행하는가?
- [ ] aggregate pass rate 외에 per-task floor와 regression gate를 함께 두었는가?
References
- Agno, "v2.8.0" release notes, GitHub Releases, published 2026-07-20. https://github.com/agno-agi/agno/releases/tag/v2.8.0
- Agno, "feat: agno.scorer and the judge prompt fence" (PR #9049), merged 2026-07-20. https://github.com/agno-agi/agno/pull/9049
- Agno, "feat: rollout engine and Case.scorer seam" (PR #9050), merged 2026-07-20. https://github.com/agno-agi/agno/pull/9050
- Agno, "cookbook/environments/README.md" at tag
v2.8.0. https://github.com/agno-agi/agno/blob/v2.8.0/cookbook/environments/README.md - Agno, "cookbook/environments/_18_execution_matching/README.md" at tag
v2.8.0. https://github.com/agno-agi/agno/blob/v2.8.0/cookbook/environments/_18_execution_matching/README.md - Agno, "cookbook/environments/_11_export_provenance/README.md" at tag
v2.8.0. https://github.com/agno-agi/agno/blob/v2.8.0/cookbook/environments/_11_export_provenance/README.md - Agno, "cookbook/environments/_28_ci_gating/README.md" at tag
v2.8.0. https://github.com/agno-agi/agno/blob/v2.8.0/cookbook/environments/_28_ci_gating/README.md