AI 에이전트 hooks 운영법: tool call 전후에 검증 스크립트를 넣는 실전 패턴
AI 에이전트 운영에서 가장 위험한 문장은 “모델에게 잘 지시하면 된다”입니다. 프롬프트는 필요하지만 충분하지 않습니다. 에이전트가 파일을 쓰고, 코드를 실행하고, 외부 API를 호출한다면 정책은 프롬프트 바깥에도 있어야 합니다. 그래서 tool call 전후에 hooks를 넣는 패턴이 중요해지고 있습니다.
Google Gemini Managed Agents 업데이트에서 environment hooks가 추가된 것도 같은 흐름입니다. pre_tool_execution과 post_tool_execution 이벤트에 스크립트를 연결해 tool call을 막거나, lint하거나, 감사 로그를 남길 수 있습니다. 이 방식은 특정 벤더 기능을 넘어 에이전트 운영의 표준 패턴으로 볼 만합니다.
hooks가 해결하는 문제
에이전트는 사람보다 빠르게 많은 행동을 만듭니다. 문제는 그 행동이 항상 안전하지 않다는 점입니다.
- write_file이 금지 경로에 파일을 만들 수 있습니다.
- code_execution이 destructive command를 실행할 수 있습니다.
- 외부 문서의 프롬프트 인젝션을 따라 할 수 있습니다.
- 생성한 JSON, SQL, 이미지 manifest가 형식만 맞고 내용은 틀릴 수 있습니다.
- 테스트 없이 “완료”라고 말할 수 있습니다.
hooks는 이 지점에 강제 검문소를 넣습니다. 모델이 무엇을 하려고 했는지 보고, 실행 전에 막거나 실행 후에 검증합니다.
pre hook: 실행 전에 막아야 하는 것
pre_tool_execution hook은 tool call이 실행되기 전에 동작합니다. 여기서는 “위험한 행동을 차단”하는 것이 목적입니다.
대표 규칙은 다음입니다.
- production credential 파일 접근 금지.
- .env, private key, token 파일 읽기 금지.
- rm -rf, git reset --hard, git clean -fd 차단.
- main/master/develop 브랜치 직접 수정 차단.
- migrations, billing, auth 디렉터리 수정은 별도 승인 요구.
- 외부 curl | bash 형태 명령 차단.
예를 들어 command 문자열을 검사해 위험 패턴이 있으면 deny를 반환하는 식입니다.
{
"decision": "deny",
"reason": "git reset --hard is blocked in agent sessions"
}
중요한 것은 hook의 결과가 모델 컨텍스트로 돌아가야 한다는 점입니다. 단순히 실패시키는 것보다 “왜 거부됐는지”를 알려줘야 에이전트가 안전한 대안을 찾습니다.
post hook: 실행 후에 검증해야 하는 것
post_tool_execution hook은 tool call 이후에 동작합니다. 여기서는 결과 품질과 형식을 확인합니다.
좋은 후보는 다음입니다.
- 코드 파일 수정 후 formatter 실행.
- TypeScript typecheck 실행.
- JSON, YAML, SQL schema validation.
- 생성 이미지의 크기, 투명도, contrast 검사.
- markdown 링크 깨짐 검사.
- 테스트 실패 로그를 요약해 다음 단계에 전달.
post hook의 장점은 에이전트가 “검증을 깜빡하는” 문제를 줄인다는 점입니다. 사람이 매번 “lint 돌렸어?”라고 묻지 않아도 파일 수정 뒤 자동으로 검증이 붙습니다.
matcher 설계: 모든 tool을 잡지 말고 위험도별로 나눈다
hooks를 처음 붙일 때 흔한 실수는 모든 tool call에 무거운 검사를 붙이는 것입니다. 그러면 느려지고, 비용이 늘고, 개발자가 hooks를 꺼버리고 싶어집니다.
위험도별로 나누는 편이 좋습니다.
read_file: 감사 로그만
write_file: 경로 검사 + formatter
code_execution: 위험 명령 차단 + timeout
network_call: allowlist 검사
final_output: 링크/형식/금칙어 검사
정규식 matcher를 쓸 수 있다면 write_file과 code_execution은 강하게, read-only tool은 가볍게 처리합니다.
timeout은 짧게 잡아야 한다
hook 자체가 장애 지점이 되면 안 됩니다. pre hook은 특히 짧아야 합니다. 5~10초 안에 끝나지 않는 검사는 pre hook에 넣지 않는 편이 낫습니다. 오래 걸리는 검증은 post hook이나 별도 CI로 넘깁니다.
권장 기준은 다음입니다.
- pre hook: 1~10초, 로컬 규칙 검사 중심.
- post hook: 10~60초, lint/test/schema 중심.
- full validation: CI에서 실행, agent에는 결과만 전달.
에이전트 루프 안에 너무 무거운 검증을 넣으면 모델이 기다리는 시간이 늘고, 전체 작업 비용도 올라갑니다.
감사 로그는 반드시 남긴다
hooks를 붙였다면 통과와 차단을 모두 기록해야 합니다. 차단 로그만 남기면 정상 행동의 기준을 만들기 어렵습니다.
최소 로그 필드는 다음입니다.
- session id 또는 interaction id.
- tool name.
- command 또는 file path.
- decision: allow, deny, warn.
- reason.
- timestamp.
- repo와 branch.
- user 또는 automation id.
이 로그는 나중에 권한 정책을 조정하는 데이터가 됩니다. deny가 너무 많으면 에이전트 생산성이 떨어지고, allow가 너무 넓으면 리스크가 커집니다.
적용하기 좋은 업무
hooks는 특히 산출물 검증이 명확한 업무에 잘 맞습니다.
- dependency upgrade 후 test/lint 자동 실행.
- 문서 생성 후 링크 검사.
- API client 코드 생성 후 schema 검증.
- 디자인 asset 생성 후 크기/포맷 검사.
- 데이터 변환 후 row count와 checksum 확인.
반대로 요구사항 자체가 모호한 기획 업무에는 hooks 효과가 제한적입니다. hooks는 의미 판단보다 실행 안전성과 형식 검증에 강합니다.
실패 처리 규칙
hook이 실패했을 때 무조건 전체 작업을 중단하면 에이전트가 자주 막힙니다. 실패 유형을 나눠야 합니다.
- deny: 위험 행동이므로 실행하지 않음.
- warn: 실행은 허용하되 final report에 포함.
- retryable: formatter 실패처럼 에이전트가 수정 후 재시도 가능.
- system_error: hook 자체 오류이므로 사람에게 알림.
이 구분이 없으면 정책이 너무 거칠어집니다.
실행 체크리스트
- 에이전트가 사용하는 tool 목록을 정리한다.
- write_file, code_execution, network_call부터 hook을 붙인다.
- pre hook에는 위험 명령, 금지 경로, credential 접근 차단을 넣는다.
- post hook에는 formatter, linter, schema validator를 넣는다.
- hook timeout을 짧게 설정하고 무거운 검증은 CI로 넘긴다.
- allow, deny, warn 로그를 모두 저장한다.
- 실패 유형을 deny, warn, retryable, system_error로 나눈다.
- 첫 적용은 dependency audit, 문서 검증, schema 생성처럼 결과 검증이 쉬운 업무부터 시작한다.
AI 에이전트 hooks의 핵심은 모델을 불신하자는 것이 아닙니다. 모델이 잘하는 계획과 생성은 살리고, 시스템이 잘하는 검증과 차단은 코드로 강제하자는 것입니다. 운영 환경에서 에이전트를 쓰려면 이 분리가 필요합니다.