Code as AI Skills (CaaS) 패턴
CaaS란 무엇인가?
**Code as AI Skills (CaaS)**는 프로덕션 함수가 번역 레이어 없이 AI 기능이 되는 패턴입니다.
핵심 아이디어: 프로덕션 코드가 곧 스킬입니다. 함수를 한 번 작성하고, 가벼운 SKILL.md 파일을 추가하면, 앱과 AI 모두가 사용할 수 있습니다.
┌───────────────────────────────────────────────────────────────────┐
│ CaaS 플라이휠 │
├───────────────────────────────────────────────────────────────────┤
│ │
│ 개발자가 코드 작성 ────────► 코드가 AI 스킬이 됨 │
│ ▲ │ │
│ │ │ │
│ │ ▼ │
│ AI가 코드 작성 ◄──────────── AI가 새로운 기능 획득 │
│ │
│ 각 반복: 개발자와 AI 모두 더 유능해짐 │
│ │
└───────────────────────────────────────────────────────────────────┘
세 가지 이점:
- 한 번 작성, 어디서나 사용 — 동일한 함수가 앱과 AI 컨텍스트에서 작동
- AI는 코드베이스와 함께 성장 — 작성한 모든 함수가 AI 스킬이 됨
- AI는 스스로 확장 가능 — AI가 작성한 코드가 새로운 스킬이 됨
작동 방식
단일 함수가 애플리케이션과 AI 에이전트 모두에 제공됩니다:
skills/user-management/
├── SKILL.md ← AI는 이것을 읽고 함수를 발견
└── createUser.ts ← 실제 함수 (둘 다 사용)
앱은 직접 임포트:
// app/api/register/route.ts 내부
import { createUser } from '@/skills/user-management/createUser';
const result = await createUser({ email: 'user@example.com', name: 'John' });
AI는 SKILL.md를 읽고, 정확히 같은 함수를 임포트:
// AI 생성 코드 (동일)
import { createUser } from '@/skills/user-management/createUser';
const result = await createUser({ email: 'user@example.com', name: 'John' });
포인트: "앱 버전"과 "AI 버전"이 없습니다. 같은 임포트, 같은 함수, 같은 실행. AI는 단지 SKILL.md를 통해 존재를 발견할 필요가 있을 뿐입니다.
┌────────────────────────────────────────────────────────────────────────────┐
│ │
│ ┌───────────────────────┐ ┌───────────────────────┐ │
│ │ 개발자 │ │ AI 에이전트 │ │
│ │ │ │ │ │
│ │ 함수를 직접 작성하고 │ │ SKILL.md를 통해 │ │
│ │ 임포트 │ │ 발견하고 사용 │ │
│ └───────────┬───────────┘ └───────────┬───────────┘ │
│ │ │ │
│ │ import { createUser } │ SKILL.md 읽기 │
│ │ from '@/skills/...' │ 그 다음 임포트│
│ │ │ │
│ ▼ ▼ │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ /skills 폴더 │ │
│ │ (공유 코드 레이어) │ │
│ │ │ │
│ │ 앱이나 AI가 호출하든 동일한 코드가 실행됨 │ │
│ │ │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────────┘
복리 효과
AI가 새로운 스킬 생성
AI는 기존 스킬을 사용하여 새로운 스킬을 생성할 수 있습니다.
예시: AI에게 "사용자 온보딩 플로우 생성"을 요청
AI가 기존 스킬을 발견하고 조합:
// skills/onboarding/onboardUser.ts (AI 생성)
import { sendWelcomeEmail } from '@/skills/email/sendWelcomeEmail';
import { createUser } from '@/skills/user-management/createUser';
export async function onboardUser(email: string, name: string) {
const user = await createUser({ email, name });
if (user.success) {
await sendWelcomeEmail(email, name);
}
return user;
}
AI는 SKILL.md도 생성하여, 이제 onboardUser가 앱, AI, 그리고 미래의 구성에서 사용 가능합니다.
당신이 새로운 스킬 생성 (같은 패턴)
당신도 동일한 작업을 수행합니다 — 기존 스킬(AI 생성 포함)을 조합:
// skills/admin/bulkOnboard.ts (당신이 작성)
import { onboardUser } from '@/skills/onboarding/onboardUser';
// AI 생성
import { assignRole } from '@/skills/permissions/assignRole';
export async function bulkOnboardAdmins(
users: Array<{ email: string; name: string }>,
) {
const results = [];
for (const user of users) {
const result = await onboardUser(user.email, user.name);
if (result.success) {
await assignRole(result.userId, 'admin');
}
results.push(result);
}
return results;
}
SKILL.md를 추가(또는 AI에게 생성 요청)하면, AI도 당신의 코드를 사용할 수 있습니다.
성장 루프
┌────────────────────────────────────────────────────────────────────┐
│ │
│ 개발자 기여 결과 │
│ ────────────────── ────── │
│ │
│ • 새로운 유틸리티 함수 작성 → AI가 이제 사용 가능 │
│ • 기존 코드 리팩토링 → AI가 개선된 버전 획득 │
│ • 새로운 도메인 폴더 추가 → AI가 새로운 기능 발견 │
│ │
│ AI 기여 결과 │
│ ────────────── ────── │
│ │
│ • AI가 새로운 함수 작성 → 개발자가 임포트 가능 │
│ • AI가 SKILL.md 생성 → 자신의 작업을 문서화 │
│ • AI가 기존 스킬 확장 → 둘 다 즉시 이익 │
│ │
└────────────────────────────────────────────────────────────────────┘
/skills 폴더
┌───────────────────────┐
1주차: │ 5개 함수 │
└───────────────────────┘
↓
┌───────────────────────┐
2주차: │ 12개 함수 │ ← 개발자 4개, AI 3개 추가
└───────────────────────┘
↓
┌───────────────────────┐
4주차: │ 28개 함수 │ ← 복리 성장
└───────────────────────┘
수학: 10개의 함수를 작성하면, 10개의 AI 스킬을 생성한 것입니다. AI가 5개를 더 작성하면, 이제 15개의 함수와 15개의 AI 스킬이 있습니다. "앱이 할 수 있는 것"과 "AI가 할 수 있는 것" 사이의 격차가 0이 됩니다.
스킬 설정
폴더 구조
/skills 폴더는 앱 폴더 외부에 위치합니다:
project-root/
├── app/ # 애플리케이션 라우트
├── skills/ # ← 스킬은 여기 (app의 형제)
│ ├── user-management/
│ │ ├── SKILL.md # ← 필수: AI 발견용
│ │ └── createUser.ts
│ ├── email/
│ │ ├── SKILL.md
│ │ └── sendWelcome.ts
│ └── {subdomain}/ # 중첩된 스킬 허용
│ └── SKILL.md
└── package.json
필수 vs 유연한 것:
| 필수 | 유연한 것 |
| ---------------------- | ------------------------ |
| 각 도메인의 SKILL.md | .ts 파일 구성 방법 |
| 도메인 폴더 이름 | _models/, _utils/ 등 |
| | 추가 .md 문서 (선택) |
| | 파일 명명 규칙 |
SKILL.md 형식
간결하게 유지 (30-50줄). AI는 이것을 자주 읽습니다.
---
name: email
description: Resend API를 통해 이메일 전송. 환영 이메일, 알림에 사용.
---
## 사용 가능한 함수
### sendWelcomeEmail
**시그니처:** `sendWelcomeEmail(to: string, name: string): Promise<{ success }>`
**설명:** 새 사용자에게 환영 이메일 전송
**위치:** `sendWelcome.ts`
## 하위 도메인
- **Templates:** `templates/SKILL.md` - 이메일 템플릿 관리
어디에 무엇을 넣을지:
| SKILL.md 내 | 별도 .md 파일 내 | | ----------------------- | ---------------------- | | 함수 시그니처 | 단계별 워크플로우 | | 한 줄 설명 | 상세한 코드 예제 | | 파일 위치 | 엣지 케이스와 주의사항 | | 다른 문서에 대한 포인터 | 전체 API 문서 |
경험 법칙: AI가 함수 사용 여부를 결정하는 데 도움이 되면 → SKILL.md. 복잡한 시나리오에서 올바르게 사용하는 데 도움이 되면 → 참조 파일.
왜 전통적인 도구보다 CaaS인가?
전통적인 AI 도구는 두 개의 별도 항목을 유지 관리해야 합니다:
┌───────────────────────────────────────────────────────────────────────┐
│ 전통적: 유지해야 할 두 가지 │
├───────────────────────────────────────────────────────────────────────┤
│ │
│ 1. JSON 스키마 (AI용) 2. 실제 함수 (앱용) │
│ ┌─────────────────────────┐ ┌─────────────────────────┐ │
│ │ { │ │ function createUser() { │ │
│ │ "name": "create_user",│ ←→ │ // 구현 │ │
│ │ "inputSchema": {...} │ │ } │ │
│ │ } │ └─────────────────────────┘ │
│ └─────────────────────────┘ │
│ │
│ 문제: 이들은 반드시 동기화되어야 함. 항상 어긋남. │
│ │
└───────────────────────────────────────────────────────────────────────┘
┌───────────────────────────────────────────────────────────────────────┐
│ CaaS: 유지해야 할 한 가지 │
├───────────────────────────────────────────────────────────────────────┤
│ │
│ 당신의 함수 + SKILL.md (그것을 가리킴) │
│ ┌─────────────────────────┐ ┌─────────────────────────┐ │
│ │ function createUser() { │ ←── │ SKILL.md 내용: │ │
│ │ // 구현 │ │ "createUser는 여기" │ │
│ │ } │ └─────────────────────────┘ │
│ └─────────────────────────┘ │
│ │
│ SKILL.md는 단지 포인터. 함수가 진실의 원천. │
│ │
└───────────────────────────────────────────────────────────────────────┘
| 전통적 | CaaS | | -------------------------------------- | ----------------------------- | | 스키마가 AI가 보는 것을 정의 | 코드가 AI가 보는 것을 정의 | | 스키마가 구현에 대해 거짓말할 수 있음 | SKILL.md는 실제 코드를 가리킴 | | 함수 업데이트 → 스키마도 업데이트 필요 | 함수 업데이트 → 완료 | | 스키마 테스트 + 함수 테스트 | 함수를 한 번만 테스트 |
결론
핵심 요점:
- 한 번 작성, 어디서나 사용 — 프로덕션 함수가 앱과 AI 모두에 제공
- 번역 불필요 — AI가 동일한 코드를 임포트하고 실행
- 간결하게 유지 — SKILL.md는 발견을 제공, 구현이 아님
- 복리 성장 — 당신과 AI 모두 스킬 폴더에 기여
시작하기:
/skills폴더 생성 (/app의 형제)- 함수가 있는 도메인 폴더 추가
- 최소한의 SKILL.md 작성
- 앱에서 함수 임포트 — AI도 이제 사용 가능
CaaS 철학: 당신의 코드베이스는 이미 기능으로 가득 차 있습니다. 발견 가능하게 만들면, 그것들이 스킬이 됩니다.