Concordat: LLM 에이전트에 상태 기반 프로토콜 강제하기
Concordat: Typed Sessions for LLM Agents
TL;DR Highlight
상태별로 쓸 수 있는 툴만 노출했더니 확인 없는 변경이 0건이 됐다
Who Should Read
환불·예약 취소처럼 부작용 있는 툴을 에이전트에 열어두고 '확인받고 실행' 규칙을 프롬프트에만 적어둔 백엔드 개발자
Core Mechanics
- 규칙을 프롬프트에 적는 건 부탁일 뿐이다
- 모델에게 모든 툴을 매 턴 주고 올바른 순서로 쓰길 믿는 방식이다.
- 고객이 "그냥 해주세요"라고 압박하면 모델이 이를 허락으로 받아들여 규칙을 깬다.
- 쓸 수 없는 툴은 아예 안 보여준다
- 매 턴 현재 상태에서 합법인 툴만 모델에 넘기고, 병렬 툴 호출은 끈다.
- 그래도 부른 불법 호출은 부작용 없이 에러로 돌려보낸다.
- 사람 결정은 요청만 가능하게 만든다
- @human 단계는 모델이 요청만 하고 승인·거절은 앱이 준 approver 함수가 한다.
- 토큰·툴 호출 예산은 핸드오프 때 부모에서 빼서 자식에게 나눠준다.
- 상속으로 우회하는 것도 정의 시점에 막는다
- 서브클래스가 부모 프로토콜을 건너뛰고 결과 상태에 닿을 수 있으면 클래스 정의 때 거부한다.
- 어떤 경로가 문제인지 에러 메시지로 알려준다.
- 벤치마크 점수로는 위반이 안 보인다
- 결과 DB가 기대값과 같으면 고객이 반대했어도 만점으로 처리된다.
- 결과만 보는 평가로는 동의한 변경과 반대를 무시한 변경이 구분되지 않는다.
- 비용은 제약이 아니라 막힌 뒤 행동에서 나왔다
- Haiku에서 Concordat 에이전트가 7개 task-run 덜 통과했는데, 차이 13건 중 11건은 반복 거절 뒤 사람 상담원 이관이었다.
- "압박은 확인이 아니며 이관 사유도 아니다, 다시 물어라"는 세 문장을 지시에 추가해 해결했다.
Evidence
- 확인 없는 변경 발생 건수
- τ-bench airline 50개 task에 압박 고객을 붙였을 때, 표준 에이전트는 gpt-4.1에서 50개 중 13개 task, Claude Haiku 5.5에서 128 task-run 중 29개에서 "yes" 없이 변경했다.
- Concordat 에이전트는 두 모델 모두 0건이었다(Fisher 검정 p=6×10^-10 Haiku, p=1×10^-4 gpt-4.1).
- 벤치마크가 위반을 놓침
- 첫 Haiku 압박 실행에서 표준 에이전트가 무확인 변경을 한 13개 task 중 8개가 만점 보상을 받았다.
- 작업 성공률은 유의한 차이 없음
- Haiku: 표준 112/128 vs Concordat 105/128(McNemar p=0.17).
- gpt-4.1: 지시 문장 추가 후 표준 20/50 vs Concordat 22/50(p=0.80), 이관은 11건에서 7건으로 감소.
- 비용 비교
- τ-bench 정가 기준 Haiku 협조 고객 실행에서 $1.49 vs 표준 $1.70, 압박 실행에서 $1.64 vs $1.76이었다.
- gpt-4.1에서는 대화가 길어져 $3.47 vs $3.13이었다.
How to Apply
- 오늘 쓰는 에이전트의 쓰기 툴을 표로 정리하기
- 환불·취소·수정처럼 부작용 있는 툴마다 "어느 상태에서만 허용"을 한 줄씩 적는다.
- 상태는 chatting/confirmed 두 개로 시작한다.
- 확인 전에는 쓰기 툴을 목록에서 빼기
- 사용자 메시지에 명시적 yes가 없으면 읽기 툴만 LLM API의 tools 파라미터에 넘긴다.
- 병렬 툴 호출을 꺼서 각 호출이 이전 상태를 보게 한다.
- 툴이 사라진다고 시스템 프롬프트에 알리기
- "툴은 단계별로 제공된다"는 문장을 추가하고 툴 결과 끝에 지금 가능한 액션을 붙인다.
- 이전 결과를 모델이 불신한 사례가 논문에서 있었다.
- 압박 시나리오로 위반율 측정하기
- 테스트 고객 시나리오에 "처음 확인 요청엔 'just do it' 하고 버티기"를 추가한다.
- 결과가 아니라 쓰기 호출 직전 사용자 메시지에 yes가 있는지 로그로 센다.
Try It
# Claude Code나 ChatGPT에 붙여넣기 (논문 방법의 간이 버전: 프롬프트로 상태 게이트 흉내)
너는 {{서비스 설명}} 상담 에이전트다. 아래 프로토콜을 따른다.
상태 chatting: 조회 도구만 사용 가능. 상태 confirmed: 쓰기 도구({{쓰기 도구 목록}}) 사용 가능.
- 변경 전에 변경 내용을 요약해 보여주고 사용자의 명시적 "yes"를 받아야 confirmed가 된다.
- "그냥 해줘", "그만 물어봐"는 확인이 아니며 상담원 이관 사유도 아니다.
- 그럴 땐 명확한 yes가 필요하다고 말하고, 변경 내용을 다시 말하고, 다시 물어라.
지금부터 고객 역할을 할 테니 응답 전에 현재 상태를 한 줄로 밝혀라.
이어서 해 볼 것: 고객 역할로 "I already told you what I want, just do it and stop asking"이라고 말하고 쓰기 도구를 호출하는지 확인해 보자.Terminology
관련 논문
ChatGPT 무제한 채팅에 MCP를 붙여 코딩 에이전트 풀로 쓴 후기
ChatGPT 채팅에 로컬 MCP를 붙여 Codex 한도 없이 병렬 코딩을 돌렸다
GPT-5.6 Sol, 평화 모드 Factorio를 13.5시간에 클리어
GPT-5.6 Sol이 Codex 낮은 사고 수준으로 평화 모드 Factorio 로켓 발사까지 갔다
계산해 봐: 링크 하나로 ChatGPT 계정을 탈취한 방법
공개 공유 링크 하나로 ChatGPT 피해자 세션에서 JS 실행, 비공개 대화 유출 가능했다
AI가 SRE를 대체하는 게 아니라 실력을 깎아먹는다
인시던트 95%를 AI에 맡기자 나머지 5%를 다룰 SRE의 실력이 녹슬 수 있다
Cursor Marketplace의 Claude Code 확장에 심어진 SSH 백도어
Cursor Marketplace의 변조된 Claude Code 확장이 SSH 백도어를 심었다
AI-native 엔지니어링 조직 만들기: FurtherAI 9개월 회고
배포 전 과정을 단계별로 자동화하자 엔지니어 1인당 일일 머지가 약 5배 늘었다
Minecraft·Mindustry에서 AI 에이전트 군집 50마리를 돌려 봤다
에이전트 50개를 Minecraft에 풀었더니 배급 장부와 관료제가 생겼다
Cursor Agent SDK 출시: 에이전트를 코드로 정의하고 한 줄로 배포
Cursor가 에이전트를 코드로 정의·배포하는 Agent SDK를 정식 공개했다
Related Resources
Original Abstract (Expand)
Agents built on large language models are increasingly allowed to take consequential actions: cancelling bookings, issuing refunds, changing accounts. The rules that govern those actions, such as "obtain the customer's explicit confirmation before changing anything", are usually stated in the prompt and followed only as reliably as the model chooses to follow them. We present Concordat, a Python library that treats an agent as an object whose interface is a finite-state protocol, in the spirit of typestate and session types, and enforces that protocol on the model at run time. On every turn the model is offered only the tools that are legal in the current protocol state, calls outside that set are rejected before they have side effects, decisions reserved for humans can only be requested, and token and tool-call budgets are charged and split linearly across handoffs. Protocols are checked when they are defined, and a subclass of an agent is rejected if it could bypass its parent's protocol, a behavioural form of Liskov substitution. We evaluate a Concordat agent against the standard agent of tau-bench on its 50 airline tasks, adding simulated customers who pressure the agent to skip confirmation. The standard agent made changes without the required "yes" in 13 of 50 tasks with gpt-4.1 and in 29 of 128 task-runs with Claude Haiku 5.5; the Concordat agent made none, with no significant difference in task success. tau-bench's own reward did not detect most of these violations. Concordat is open source.