τ³-bench · SOPBench · τ²-bench

[policy harness]

추가 학습 없이 공개 27B 모델로
τ³-bench banking 57.2, 공개 1위를 넘었습니다

Policy Harness는 LLM 에이전트가 제안한 도구 호출을 실행되기 직전에 검사합니다. 검사하는 것은 대화 기록만 보면 참·거짓이 정해지는 조건뿐이고, 어긴 호출은 실행하지 않고 그 사실과 정책 문장을 모델에게 돌려줍니다.

2026년 10월 4일

LLM 에이전트 → 정책 층 → 통과하면 도구가 실행되고, 어기면 사실과 정책 문장이 모델에게 돌아갑니다.

τ³-bench banking: 규정을 읽고 지키는 과제

τ³-bench의 banking_knowledge는 은행 상담 에이전트를 시험합니다. 에이전트는 지식 문서를 검색해 읽고, 고객과 대화하면서 계좌를 조회하고, 해지나 분쟁 신청처럼 기록을 바꾸는 쓰기 도구를 호출합니다. 과제는 97개이고 각각 네 번씩 돌립니다. 그래서 한 번 성공한 비율(pass^1)과 네 번 모두 성공한 비율(pass^4)을 함께 봅니다.

공개 리더보드 1위는 Qwen3.8 Max의 pass^1 55.2입니다. 같은 계열의 공개 27B 모델은 층 없이 49.5에 머뭅니다.

그림 1. τ³-bench banking의 pass^1~pass^4. 같은 Qwen3.8-27B를 층 없이(회색), Policy Harness를 붙여(마젠타) 97과제 × 4회 돌렸고, 빈 원은 공개 1위입니다. 사용자 시뮬레이터는 세 조건 모두 gpt-5.2입니다. 층 없는 조건의 pass^4는 시뮬레이션 한 건이 인프라 오류로 끝나 정의되지 않습니다.

Policy Harness를 붙이면 같은 27B 모델이 추가 학습 없이 pass^1 49.5에서 57.2로 오르고, 네 번 모두 실패하던 과제는 35개에서 25개로 줄어듭니다. 가중치와 도구, 벤치마크의 정책 문서는 그대로입니다. 달라진 것은 모델의 호출과 실제 도구 사이에 들어간 검사 한 단계입니다.

banking 규칙은 이 97과제를 보며 만들었습니다. 그래서 정답 풀이에 맞춰 고른 규칙은 이 실행 전에 모두 뺐고, 처음 보는 과제로 따로 확인한 결과는 그림 9에 있습니다.

요점: 남은 실패의 상당수는 규칙을 몰라서가 아니라, 아는 규칙을 실행하는 순간 지키지 않아서 생깁니다.

쓰기 직전의 실수

층 없는 27B의 banking 실패 196건 가운데 32건을 무작위로 골라 대화 기록을 끝까지 읽었습니다. 30건에서는 필요한 문서가 이미 검색 결과에 들어와 있었습니다. 지식이 모자란 것이 아니었습니다. 14건(44%)은 모델 자신의 실수였습니다. 정해진 조회를 건너뛰고 바로 쓰거나, 계산을 머릿속으로 하다 틀리거나, 도구 출력 어디에도 없는 값을 인자에 넣는 식이었습니다.

이런 실수는 대화만 읽어서는 잘 보이지 않습니다. 말투는 자연스럽고, 틀린 것은 인자 하나이기 때문입니다. 그런데 기록에 한 번 쓰고 나면 되돌릴 수 없습니다. 아래는 항공 예약 취소 과제에서 이 일이 일어난 장면입니다.

고객
모델
정책 층
도구 · 기록
1예약을 취소하고 싶어요. 10시간 전쯤 예약했어요.
2get_reservation_details
3기록 created_at 2024-05-02 · 정책 시각 05-15
4cancel_reservation(…) 고객 말만 믿음
실행됨
예약 취소

거부 · 실행 안 함

24시간 이내 예약인가?
기록 05-02 · 정책 시각 05-15

① 실행 안 한 호출 cancel_reservation

② 기록의 사실 created_at 2024-05-02

③ 정책의 취소 조건 원문

실행 안 됨
기록 그대로
5거부문 (값·다음 행동 없음)
6기록상 5월 2일 예약이라 24시간이 지나 그 사유로는 취소할 수 없어요. 다른 조건에 해당하는지 볼게요.
결과 · 취소가 실행되어 과제 실패
결과 · 취소하지 않음 · 기록 그대로

실제 거부문 · 같은 규칙, τ² airline 과제 43 (발췌)

…The reservation record read in this conversation shows created_at 2024-05-04T07:38:29 (current time stated in the policy: 2024-05-15 15:00:00), cabin basic_economy, insurance no; flight status reads in this conversation showing a segment of it cancelled: 0. …

들어 있는 값은 이 대화에서 읽은 기록의 사실뿐입니다. 정책 원문 인용은 이 발췌에서 생략했습니다.

그림 2. τ²-bench airline 과제 48의 한 턴. 층이 없으면 모델은 고객이 말한 "10시간 전"을 믿고 취소를 실행합니다. 층이 있으면 취소는 실행되지 않고, 모델은 예약 기록의 날짜와 정책 문장을 돌려받습니다. ID는 지우고 기록과 거부문은 줄였으며, 6번 답장은 예시입니다.

기록으로 판정할 수 있는 것만

정책 조건 가운데 일부는 대화 기록만 보면 참·거짓이 정해집니다. 예약을 조회했는지, 그 기록의 created_at이 정책이 기준으로 삼는 현재 시각(정책 시각) 기준 24시간 안인지, 쓰려는 우편번호가 도구 출력에 나온 적이 있는지가 그렇습니다.

고객이 정말 해지를 원하는지, 이 불만을 상위 담당자에게 넘길지는 다릅니다. 읽는 사람의 판단이 필요합니다. 앞의 것을 닫힌 조건, 뒤의 것을 열린 조건이라 부르겠습니다. 층은 닫힌 조건으로만 막고, 열린 조건은 모델에게 남깁니다.

닫힌 조건 · 층이 실행 전에 막음

사건, 기록의 필드, 대화 속 문자열만으로 답이 정해집니다.

  • 사건cancel 전에 예약을 조회했는가?
  • 기록created_at이 정책 시각 기준 24시간 이내인가?
  • 문자열쓰려는 우편번호가 도구 출력이나 고객 말에 나오는가?
  • 계산환불액이 가져온 기록으로 계산한 값과 같은가?

열린 조건 · 모델이 판단

층은 관련 정책 문장을 보여 줄 수는 있어도, 이 조건으로 막지 않습니다.

  • 의도고객이 정말 계좌를 닫고 싶은가?
  • 어조상위 담당자에게 넘길 불만인가?
  • 적합성세 상품 중 고객 설명에 맞는 것은?
  • 의미"며칠 전"은 기간 안인가?
그림 3. 닫힌 조건과 열린 조건의 예. 왼쪽 조건은 층이 실행 전에 확인하고, 오른쪽 조건은 모델의 판단에 맡깁니다.

핵심. 해석이 필요한 검사를 층이 하려면 또 하나의 모델이 필요하고, 그 모델도 틀립니다. 기록으로 판정할 수 있는 조건만 막으면, 층이 내린 거부는 늘 에이전트가 직접 확인할 수 있는 사실 하나로 설명됩니다.

한 턴 안에서 일어나는 일

모델이 고른 호출 하나가 실제 도구에 닿기까지의 길입니다.

제안. 모델이 대화를 읽고 다음 턴을 내놓습니다. 도구 호출이든 고객에게 보낼 문장이든, 이 시점에는 아무것도 실행되지 않았습니다.
읽기. 엔진이 선언 파일(그 도메인의 규칙을 적은 파일 하나)과 지금까지의 기록을 읽습니다. 어떤 도구가 무엇을 돌려줬고, 고객이 무슨 말을 했는지가 여기에 들어 있습니다.
검사. 검사 항목인 레버 일곱 개가 각자 맡은 닫힌 조건을 확인합니다. 대부분은 조용히 지나가고, 위반을 찾은 레버만 확인되지 않은 사실 하나를 보고합니다.
통과. 걸린 것이 없으면 호출은 인자 그대로 도구로 갑니다. 층이 값을 고쳐 쓰는 일은 없습니다.
거부. 걸리면 호출은 실행되지 않습니다. 모델은 그 호출과 확인되지 않은 사실, 정책 문장을 받아 다시 제안하고, 재시도는 정해진 횟수 안에서만 합니다.
기록. 통과와 거부, 계산값 주입, 재시도는 근거가 된 도구 출력과 함께 감사 로그에 남습니다. 같은 입력에는 같은 판정이 나옵니다.
그림 4. 호출 한 번의 흐름. 단계를 따라 내리면 그림에서 해당 경로가 켜집니다.

거부문에 값을 넣지 않는 이유. 층이 "환불 0으로 취소하라"처럼 고칠 값을 적어 주면, 규칙에 실수가 있을 때 그 실수가 그대로 행동이 됩니다. 사실과 정책 문장만 돌려주면 다음 행동은 여전히 모델이 정합니다.

일곱 레버

레버는 실패한 대화에서 되풀이되는 실수에 하나씩 이름을 붙인 것입니다. 레버마다 무엇을 읽고 무엇을 판정하는지와 함께, 그 레버만 끄고 다시 돌렸을 때의 점수를 붙여 두었습니다.

그림 5. 레버별 읽는 것·판정·하는 일과 예시. 아래 막대는 층 전체가 발동한 과제에서 그 레버 하나만 껐을 때의 pass^1이고, 붉은 구간은 층 없는 점수 이하입니다. 예시는 이 페이지를 위해 쓴 것으로 선언 파일의 규칙 원문이 아닙니다.

다른 도메인으로 옮기기

엔진 코드에는 카드나 항공편 같은 도메인 단어가 없습니다. 도메인에 딸린 내용, 곧 쓰기마다 먼저 필요한 조회, 출처가 있어야 하는 인자, 쓸 수 있는 계산, 도구마다 붙는 정책 문장은 선언 파일 하나에 들어갑니다.

banking에서 만든 엔진을 SOPBench library와 τ² airline으로 옮길 때 새로 쓴 것은 이 파일이었습니다. airline에서는 시간 차이 계산처럼 범용 연산자가 몇 개 더 필요했지만, 도메인 단어는 여전히 엔진에 들어가지 않았습니다.

그림 6. 같은 엔진에 선언 파일만 바꿔 넣은 결과(pass^1). airline으로 옮길 때 엔진에 연산자 4개(hours_between · count_of · prefix · eq)와 피연산자 1개(now)를 더했고(+74줄), 그 뒤에도 기록된 banking 6,197턴의 판정은 바이트 단위로 같았습니다.

수치가 말하는 것

선언 파일만 바꿔 같은 층을 SOPBench library와 τ²-bench의 airline·retail에서, 여러 모델로 돌렸습니다.

이득은 모델이 닫힌 규칙을 어기는 만큼 생깁니다. SOPBench library에서는 다섯 모델 모두 6~15점이 올랐고, airline에서는 기준 점수가 낮은 GPT-4o-mini와 Qwen2.5-32B가 22점 이상 올랐습니다. 이미 정책을 지키는 27B의 airline, 그리고 실패 대부분이 판단 문제인 retail에서는 거의 움직이지 않았습니다.

SOPBench 채점

그림 7. 도메인·모델별 pass^1, 층 없음(회색)과 층 있음(마젠타). 두 번째 보기에서는 가로가 층 없는 점수, 세로가 층이 더한 점수입니다. SOPBench는 공식 채점기 값이 기본이고, 채점기 오류를 고친 값은 27B만 측정했습니다. SOPBench hotel은 공식 채점으로 +11.0이지만 오류를 고치면 −0.4라서 그림에 넣지 않았습니다.

어떤 레버가 점수를 떠받치나. 세 설정에서 레버를 하나씩 끄고 다시 돌렸습니다. 근거 레버(LB3)를 끄면 세 설정 모두 층 없는 점수 이하로 떨어집니다. 다른 레버가 넣어 주는 계산값과 정책 문장이 출처 검사 없이 모델의 추측과 섞이기 때문으로 봅니다.

절차 레버(LB1)의 몫은 모델이 순서를 얼마나 자주 어기는지에 따라 달랐습니다. 순서 위반으로 거부된 호출이 40건이던 GPT-4o-mini는 LB1을 끄면 9.2점 떨어졌고, 10건이던 Qwen3-8B는 그대로였습니다.

그림 8. 레버 하나씩 끄기. 층 전체가 발동한 과제(27B banking 16개, GPT-4o-mini airline 30개, Qwen3-8B airline 24개)에서의 pass^1입니다. 붉은 구간은 층 없는 점수 이하, 세로선은 층 전체입니다. LB4는 airline에서 끄면 오히려 올라 주장에서 뺐습니다.

처음 보는 과제에서는? airline 50과제를 규칙 작성용 30개와 시험용 20개로 나눠, 30개만 보고 규칙을 다시 만들었습니다. 시험 20과제에서 GPT-4o-mini는 31.2에서 52.5로 올랐고, 올바른 행동을 잘못 막은 경우는 없었습니다.

따로 떼어 둔 시험 과제 · airline 20과제

같은 조건 비교 · Reason Less, Verify More

그림 9. 왼쪽: 따로 떼어 둔 airline 시험 과제 20개(규칙 작성 30 / 시험 20, GPT-4o-mini). 오른쪽: 같은 50과제 × 4회에서 층 없음, Reason Less, Verify More의 공개 게이트(빈 원), Policy Harness의 pass^1과 pass^4. 발동한 과제에서 잃은 시뮬레이션은 게이트가 5건, 이 층이 1건입니다.

효과가 없던 곳

retail에서는 네 모델 모두 변화가 없었습니다. 실패 대부분이 어느 상품, 어느 옵션을 고를지 같은 판단 문제였고, 사용자 시뮬레이터가 대화를 일찍 끝낸 경우도 많았습니다. 기록으로 판정할 수 있는 위반은 적었습니다.

airline의 Qwen3.8-27B도 그대로였습니다. 이 모델은 이미 정책을 지켰고, 층은 한 과제에서만 발동했습니다.

SOPBench hotel의 +11.0은 우리 결과로 치지 않습니다. 195과제 중 56과제에서 채점기가 OR 조건을 AND로 읽는 오류가 있었고, 이를 고치면 차이는 −0.4입니다.

효과가 없던 곳에서 점수를 잃지도 않았습니다. 수백 번의 시뮬레이션 가운데 잃은 것은 0~3건이었고, 그중 잘못된 거부가 원인인 경우는 없었습니다.

측정 방법

비교가 공정하도록 지킨 것과, 우리 이득으로 잘못 셀 수 있었던 것을 적어 둡니다.

측정 1 · 서버두 조건은 같은 vLLM 인스턴스에서첫 응답이 바뀐 과제 30 / 66

vLLM 인스턴스를 바꾸기만 해도 SOPBench 66과제 중 30과제에서 첫 응답이 달라졌고, 층이 개입하지 않은 결과의 8.9%가 뒤집혔습니다. 실제 효과와 비슷한 크기입니다. 여기 있는 모든 비교는 층 있음·없음 두 조건을 한 인스턴스에서 돌렸습니다.

측정 2 · 귀속이득은 층이 실제로 개입한 과제에서만 셈층이 조용한 과제: 실행당 −0.25과제

층이 실제로 거부하거나 값을 넣은 과제에서만 이득을 층 덕분으로 셉니다. 층이 조용했던 과제는 잡음의 크기를 보여 줍니다(SOPBench library: 실행당 −0.25과제).

측정 3 · 채점기SOPBench 공식 채점기의 오류 세 가지공식 FC 모델 21개 점수 재현

공식 채점기는 기록된 호출을 eval()로 다시 읽어서 JSON 불리언이 실패하고 날짜가 산술식으로 계산됩니다. 값을 돌려주는 목표 행동은 늘 실패로 채점됩니다. hotel에서는 참조 그래프의 OR가 195과제 중 56과제에서 AND로 읽힙니다. 우리 수정을 끄면 공식 function-calling 모델 21개의 공개 점수가 그대로 나오며, 이 페이지는 공식 수치를 먼저 적습니다.

측정 4 · 시뮬레이터τ² 사용자 시뮬레이터의 조기 종료감사한 실패 32 / 80

감사한 실패 80건 중 32건에서 시뮬레이터가 "Yes"와 종료 신호를 한 메시지에 보냈습니다. 정책을 지키는 에이전트는 실행할 차례를 얻지 못합니다. 같은 시뮬레이터를 쓰는 모든 제출이 같은 제약을 받습니다.

측정 5 · 개발 공개banking 규칙은 평가 과제를 보며 만들었음정답 적합 항목 10개 제외

banking 규칙은 평가용 97과제를 보며, 채점 결과와 정답 풀이를 살펴 만들었습니다. 규칙마다 근거를 감사해 (A) 에이전트가 받는 정책 원문 인용, (B) 과제와 무관하게 전문가가 말할 일반 관행, (C) 정답 풀이에 맞아서 고른 것으로 나눴고, C 항목은 제출 실행 전에 모두 뺐습니다. 그래도 이 결과는 평가 과제를 보고 얻은 것입니다. 처음 보는 과제로 확인한 것은 airline 시험 과제 20개뿐입니다.

측정 6 · 정보 경계실행 중 층이 읽는 것목표·정답 접근 없음

실행 중 층은 제안된 턴, 에이전트가 받은 도구 출력, 에이전트가 받는 정책 문서, 선언 파일만 읽습니다. 과제 목표, 참조 행동, 채점기 상태에는 접근하지 않습니다.