
【비망록】 공식 정보를 통해 확인하는 Genkit Middleware ― AI 에이전트에 삽입할 수 있는 제어 포인트 정리
요약
Google Developers Blog를 통해 발표된 Genkit Middleware는 AI 에이전트의 `generate()` 호출 과정에 추가적인 제어 포인트를 삽입할 수 있는 메커니즘입니다. 이 미들웨어는 generate, model, tool의 세 가지 계층에서 동작하며, 도구 호출 루프(tool loop) 사이클에 개입하여 에이전트의 동작을 정교하게 제어할 수 있습니다.
핵심 포인트
- Genkit Middleware는 generate, model, tool의 3개 계층에서 각각 다른 타이밍에 제어를 삽입할 수 있습니다.
- retry, fallback, toolApproval, skills, filesystem 등 5종류의 내장 미들웨어가 제공됩니다.
- 단순 프롬프트 제어를 넘어 도구 실행 및 모델 호출 외부에서 에이전트의 동작을 하드닝(harden)할 수 있습니다.
- 현재 TypeScript, Go, Dart에서 사용 가능하며 Python은 출시 예정입니다.
2026년 5월 14일에 Google Developers Blog에서 Genkit Middleware가 발표되었습니다.
공식 발표와 공식 문서를 읽었으므로, 우선 "무엇이 추가되었고 어디에 영향을 미치는가"를 정리하기 위한 메모를 남겨둡니다. 직접적인 구현 검증이라기보다, 앞으로 Genkit으로 agentic app을 만들기 전의 사전 확인이라는 위치에 있습니다.
본 기사의 전제 조건입니다.
- 확인일: 2026년 5월 19일
- 주요 정보원: Google Developers Blog 및 Genkit 공식 문서
- 코드 예시는 공식 정보의 사고방식을 바탕으로 발췌하였으며, 본문 중에서는 API 명칭을 JavaScript / TypeScript용 문서를 중심으로 정리했습니다.
- 공식 발표에서는 middleware system은 TypeScript / Go / Dart에서 이용 가능하며, Python은 coming soon이라고 되어 있습니다. 실제 프로덕션 적용 시에는 사용 중인 Genkit / SDK / 모델의 버전 확인이 필요합니다.
※ 본 기사는 개인적인 정리 메모입니다. 잘못 읽은 부분이 있다면 수시로 수정할 생각으로 작성하고 있습니다.
Google Developers Blog의 발표에서는, Genkit Middleware는 agentic app의 generate() 호출에 대해 추가적인 제어를 삽입하는 메커니즘으로 설명되어 있습니다.
발표일과 공식 링크는 다음과 같습니다.
- 발표일: 2026년 5월 14일
- 공식 발표: Announcing Genkit Middleware: Intercept, extend, and harden your agentic apps
- 공식 문서: Middleware | Genkit
공식 정보의 범위를 "확인할 수 있는 것"과 "이 기사에서 다루지 않는 것"으로 나누어 도식화해 두겠습니다.
포인트를 문장으로 쓰면 다음 세 가지입니다.
generate()처리에 middleware를 삽입할 수 있음- generate / model / tool의 각 계층에서 제어 가능
- retry / fallback / toolApproval / skills / filesystem의 5종류 내장 middleware가 준비되어 있음
Genkit의 generate()는 단순한 1회의 LLM 호출뿐만 아니라, 도구 호출(tool calling)을 포함한 루프로 동작합니다.
공식 발표에서는 모델이 출력 → 요청된 도구가 실행 → 결과가 다음 모델 호출로 돌아오는 사이클이 모델이 종료라고 판단할 때까지 반복되는 tool loop로 설명되어 있습니다 (공식 발표 내용 요약).
이를 도식화하면 다음과 같은 흐름입니다.
Genkit Middleware는 이 흐름 중간에 제어를 삽입하기 위한 메커니즘입니다.
공식 발표에서는 middleware의 hook은 크게 다음의 3개 계층으로 나뉩니다.
| hook | 실행 타이밍 | 용도 |
|---|---|---|
| generate | tool loop의 각 반복 | 컨텍스트 주입, 메시지 재작성, 대화 전체의 제어 |
| model | 모델 API 호출 시마다 | retry, fallback, 캐시, 레이턴시(latency) 측정 |
| tool | 도구 실행 시마다 | human-in-the-loop, sandboxing, 도구 단위의 로그 |
이 부분이 개인적으로 가장 중요하다고 생각했습니다.
프롬프트에 "위험한 조작은 하지 마"라고 쓰는 것뿐만 아니라, 도구 실행이나 모델 호출의 외부에서 제어할 수 있다는 관점을 가질 수 있습니다.
공식 문서에서는 JavaScript / TypeScript용 공식 middleware는 @genkit-ai/middleware 패키지로 안내되고 있습니다.
npm install @genkit-ai/middleware
확인 가능한 내장 middleware는 5종류입니다. 도식으로 정리합니다.
| middleware | 개요 | 실무 활용 사례 |
|---|---|---|
| filesystem | 지정된 root 하위로 한정하여 파일 조작 도구(tool)를 주입 | 로컬 워크스페이스 조작, 코드 생성 지원 |
| skills | SKILL.md를 스캔하여 system prompt에 스킬 정보를 주입. 필요에 따라 use_skill 도구로 상세 정보 취득 | 절차서·운영 규칙·개발 규약의 주입 |
| toolApproval | 미승인 도구 실행 시 중단(interrupt), 수동 승인 후 재개 | 삭제, 전송, 외부 API 실행 등의 확인 |
| retry | 일시적인 실패 시 지수 백오프 (exponential backoff) + jitter를 사용하여 재시도 | 할당량(quota), 통신 단절, 내부 에러에 대한 내성 |
| fallback | 지정된 에러 발생 시 다른 모델로 전환 | 할당량 초과 시 경량 모델로 전환, 다른 프로바이더(provider)로 전환 |
참고로, filesystem middleware가 주입하는 구체적인 도구 이름은 언어 버전에 따라 표기가 약간 다릅니다.
JavaScript / TypeScript 버전: list_files, read_file, write_file, search_and_replace가 안내되어 있습니다. 또한, 쓰기 작업은 allowWriteAccess 설정에 의존하며, 공식 문서에서는 기본값이 false로 되어 있습니다.
Go 버전 (공식 발표): list_files, read_file, 쓰기 활성화 시의 write_file, edit_file이 있습니다.
이러한 부분은 구현 시 사용하는 언어의 공식 문서를 확인하는 것이 좋습니다.
이 중에서 개인적으로 테스트해 본다면 toolApproval과 retry가 이해하기 쉬울 것 같다고 느꼈습니다.
AI 에이전트를 만들 때 무서운 점은 모델이 도구를 호출할 수 있게 된 순간입니다.
예를 들어, 다음과 같은 조작은 멋대로 실행되면 곤란합니다.
- 파일 삭제
- 메일 전송
- 티켓 업데이트
- 외부 API 쓰기
- 과금이나 구매로 이어지는 조작
toolApproval은 도구 실행을 허용 리스트(allowlist)로 제한하고, 미승인된 도구 호출을 중단할 수 있는 middleware입니다. 공식 발표된 Go 예제에서는 빈 리스트를 전달하면 "모든 도구 호출에서 interrupt를 발생시키는" 설정이 가능하다는 점이示されています.
이미지로 표현하면 다음과 같은 흐름이 됩니다.
JavaScript 버전의 공식 문서에서는 interrupt 발생 시의 감지는 response.finishReason === 'interrupted'로 수행하며, restartTool로 승인 플래그가 포함된 tool request를 만들어 resume 하는 흐름이 소개되어 있습니다.
import { genkit, restartTool } from 'genkit';
import { toolApproval } from '@genkit-ai/middleware';
// 1. 첫 번째 호출
...
위 내용은 공식 문서 [Middleware | Genkit]의 샘플을 바탕으로 발췌한 것입니다. 실제 이용 시에는 사용 중인 버전의 API 동작을 확인해 주세요.
이러한 사고방식은 AI 에이전트를 업무용 애플리케이션에 도입할 때 매우 중요하다고 느꼈습니다.
"모델을 신뢰할 것인가"가 아니라, "모델이 제안한 조작을 어디서 멈출 것인가"라는 설계로 전환할 수 있기 때문입니다.
LLM 애플리케이션에서는 모델 API 호출이 매번 반드시 성공한다고 보장할 수 없습니다.
공식 발표에 따르면, retry middleware는 일시적인 에러(RESOURCE_EXHAUSTED, UNAVAILABLE 등)에 대해 지수 백오프(exponential backoff)와 jitter를 사용하여 재시도한다고 설명되어 있습니다. JavaScript 버전 공식 문서를 보면, 기본 대상 에러는 다음 5종류입니다.
UNAVAILABLE
DEADLINE_EXCEEDED
RESOURCE_EXHAUSTED
ABORTED
INTERNAL
또한 fallback middleware는 지정된 에러 발생 시 다른 모델로 전환하는 용도로 설명되어 있습니다. 공식 발표에서는 Gemini가 할당량(quota)을 초과했을 때 Anthropic Claude와 같은 다른 프로바이더(provider)로 전환하는 예시가 소개되어 있습니다.
이 두 가지는 화려하지는 않지만, 실운영(production)에서는 매우 중요합니다.
예를 들어, 다음과 같은 방침을 middleware (미들웨어)로 표현할 수 있을 것입니다.
- 통신 계통의 일시적인 에러라면 최대 3회까지만 retry (재시도)한다
- quota (할당량) 계통의 에러라면 경량 모델로 fallback (폴백)한다
- 실패 시 로그를 남겨 나중에 관측할 수 있도록 한다
단, retry를 넣는다고 해서 모든 것이 안전해지는 것은 아닙니다. 공식 발표에서는 retry에 대해 다음과 같이 명시하고 있습니다.
Only the model call is retried; the surrounding tool loop is not replayed.
즉, retry는 model (모델) 호출만을 재시도하는 것이며, 툴 실행을 포함한 tool loop (툴 루프) 전체를 되돌리는 것이 아닙니다. 이 부분은 구현 시 동작을 제대로 확인해야 할 대목입니다.
공식 발표에서는 커스텀 middleware (커스텀 미들웨어)의 예시로, 모델 응답에 금지어가 포함되어 있는지 확인하는 **ContentFilter (콘텐츠 필터)**를 소개하고 있습니다. Go 언어에서는 20줄 정도의 심플한 코드로 제시되어 있습니다.
JavaScript 버전 문서에서도 generateMiddleware라는 헬퍼를 사용하여 model / tool / generate 중 하나의 hook (훅)을 구현하는 방식으로 커스텀할 수 있다고 설명되어 있습니다.
여기서 흥미로운 점은 규칙을 프롬프트(prompt)에만 가두지 않는다는 점입니다.
예를 들어, 다음과 같은 규칙은 middleware 측에 두는 것이 관리하기 쉬울 수 있습니다.
- 특정 키워드를 포함하는 응답을 거부한다
- 외부 전송 전에 개인정보로 보이는 문자열을 검사한다
- 특정 툴의 인자(argument)를 로그에 남긴다
- 조작 대상의 경로(path)나 ID를 검증한다
- 사내 정책에 반하는 처리를 중단한다
물론, middleware만으로 완전한 안전성을 얻을 수 있는 것은 아닙니다.
다만, AI 에이전트의 제어를 '프롬프트'뿐만 아니라 **'코드상의 명시적인 제어점'**으로 다룰 수 있다는 점은 설계상 상당히 고무적이라고 느낍니다.
공식 발표에서 개인적으로 인상 깊었던 점은, middleware의 스택 순서(stack order)가 명시적이다라는 점입니다.
공식 발표의 예시에서는 다음과 같이 Retry와 ContentFilter를 함께 지정하고 있습니다.
ai.WithUse(
&middleware.Retry{MaxRetries: 3},
&ContentFilter{ ForbiddenTerms: []string{"CompetitorCRM", "RivalCo", "internal price"},
...```
이때, `Retry`가 바깥쪽, `ContentFilter`가 안쪽, 그 안에 model 호출이 들어가는 중첩 구조가 됩니다.
공식 발표에서는 다음과 같이 설명합니다.
Here Retry wraps ContentFilter, which wraps the model call. Order matters, and Genkit makes it explicit.
즉, 안쪽의 `ContentFilter`에서 발생한 에러를 바깥쪽의 `Retry`가 처리할 수 있는 배치입니다. 실제로 재시도 대상이 될지는 retry middleware의 대상 에러나 구현에 따라 달라지므로, 순서를 바꾸면 동작이 변할 수 있다는 점에 주의해야 합니다.
middleware를 스택(stack)할 수 있고, 그 순서가 '왼쪽에서 바깥쪽'이라고 명시되어 있다는 점은 설계 시 가독성이 매우 좋습니다.
공식 정보를 확인한 범위 내에서, 이 기사에서는 다음 사항들을 미확인 사항 또는 향후 확인이 필요한 사항으로 취급합니다.
- 각 언어 버전별로 이용 가능한 middleware 기능·API 명칭·주입 툴 명칭의 완전한 차이
- Python 대응의 구체적인 제공 시기 (공식 발표에서는 coming soon으로만 표기)
- 실제 운영 환경에서의 권장 구성 및 운용 사례
- Vertex AI / Gemini API의 요금이나 quota (할당량)에 대한 직접적인 변경 사항
- 일본 리전이나 국내 제공 조건에 관한 변경 사항
특히 이번 발표는 **Genkit Middleware**에 관한 이야기이며, Gemini API나 Vertex AI의 요금·모델 제공 상황이 바뀌었다는 발표가 아닙니다.
이 두 가지를 혼동하지 않는 것이 좋아 보입니다.
처음 시도해 본다면 다음과 같은 작은 데모가 적당할 것입니다.
**테마: 위험한 조작에 대해서만 인간의 확인을 거치는 TODO 에이전트**
기능 안입니다.
- TODO 목록 읽기
- TODO 추가하기
- TODO 완료하기
- TODO 삭제하기
-
**삭제만** `toolApproval`로 인간의 확인을 구함 - 모델 호출에는 `retry`를 넣음
이 정도라면 middleware (미들웨어)의 의미를 상당히 쉽게 파악할 수 있을 것입니다.
구현 기사로 작성할 경우에는 다음과 같은 구성으로 하면 읽기 편할 것 같습니다.
- 먼저 승인 없이 툴 (tool)을 실행할 수 있는 상태를 만든다
- 삭제 조작만이 위험하다는 것을 확인한다
- `toolApproval`을 넣는다 - 중단, 승인, 재개 흐름을 확인한다
- `retry`를 추가한다 - 로그를 보면서 어느 계층에서 middleware (미들웨어)가 작동하고 있는지 확인한다
Genkit Middleware (Genkit 미들웨어)는 AI 에이전트(AI agent)에 대해 다음과 같은 제어점(control point)을 추가하는 메커니즘으로 이해하면 정리하기 쉬울 것입니다.
- 모델 호출을 **retry / fallback** 한다
- 툴 실행 전에 **인간의 확인 (toolApproval)**을 끼워 넣는다
- 파일 조작 등의 범위를 **filesystem (파일 시스템)**으로 제한한다
- 스킬이나 컨텍스트를 **skills (스킬)**로 주입한다
- 독자적인 검사나 로그를 **커스텀 middleware (커스텀 미들웨어)**로 추가한다
- middleware (미들웨어)는 **왼쪽에서 바깥쪽**으로 스택(stack)된다
👉 개인적으로는 `toolApproval`이 특히 중요하다고 느꼈습니다.
AI 에이전트를 업무나 개발 지원에 도입할 때, "무엇을 자동화할 것인가"만큼이나 "**어디서 멈출 것인가**"가 중요해집니다. Genkit Middleware (Genkit 미들웨어)는 그 정지점이나 관측점을 코드로 정리하기 위한 입구가 될 것입니다.
시도해 본다면, 우선 실제로 TODO 에이전트의 작은 샘플을 만들어 `toolApproval`과 `retry`의 동작을 확인해 보는 것도 좋을 것 같습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기