본문으로 건너뛰기

스킬 소스

인라인 스킬은 데모에는 적합하지만 실제 스킬은 저장소의 폴더, 빌드 타임에 포함한 번들 또는 데이터베이스의 행에 있습니다. SkillSource를 통해 withSkills가 이를 읽습니다. 이 페이지에서는 세 가지 기본 제공 소스와 결합 방법을 설명합니다.

모든 소스는 바이트만 다루므로 동일한 미들웨어가 edge, Worker 또는 서버에서 작동합니다. 스킬이 저장된 위치에 맞는 소스를 선택하세요.

폴더에서​

skillDirectory는 폴더에서 SKILL.md 파일을 탐색합니다. 파일 시스템을 읽으므로 /node entry point 아래에 있으며 edge가 아닌 서버에서 사용하세요.

import { chat, toServerSentEventsResponse } from '@tanstack/ai'
import { anthropicText } from '@tanstack/ai-anthropic'
import { withSkills } from '@tanstack/ai-skills'
import { skillDirectory } from '@tanstack/ai-skills/node'

export async function POST(request: Request) {
const { messages } = await request.json()

const stream = chat({
adapter: anthropicText('claude-sonnet-4-5'),
messages,
middleware: [withSkills(skillDirectory('./skills'))],
})

return toServerSentEventsResponse(stream)
}

스킬 폴더는 SKILL.md를 포함하는 모든 디렉터리입니다. references/와 assets/ 아래의 번들 파일은 스킬의 리소스가 되고, scripts/ 아래의 파일도 나열됩니다(이 릴리스에서는 목록만 만들고 실행하지 않습니다).

기본적으로 skillDirectory는 strict합니다. 잘못된 SKILL.md는 오류이므로 손상된 파일이 조용히 카탈로그에 들어가지 않습니다. 잘못된 파일을 건너뛰고 나머지를 로드하려면 { strict: false }를 전달하세요.

빌드 타임 번들에서(edge 안전)​

edge에 배포하면 요청 시 파일 시스템을 읽을 수 없습니다. Vite plugin이 빌드 타임에 스킬을 glob하여 번들에 포함하므로 staticSkills는 런타임에 파일 시스템이 필요하지 않습니다.

Vite 설정에 플러그인을 추가합니다:

import { defineConfig } from 'vite'
import { skillsCatalogPlugin } from '@tanstack/ai-skills/node'

export default defineConfig({
plugins: [skillsCatalogPlugin({ dir: 'skills' })],
})

그런 다음 생성된 카탈로그를 감쌉니다.

import { chat, toServerSentEventsResponse } from '@tanstack/ai'
import { anthropicText } from '@tanstack/ai-anthropic'
import { withSkills } from '@tanstack/ai-skills'
import { staticSkills } from '@tanstack/ai-skills/static'
import { catalog } from 'virtual:tanstack-skills'

const skills = staticSkills(catalog)

export async function POST(request: Request) {
const { messages } = await request.json()

const stream = chat({
adapter: anthropicText('claude-sonnet-4-5'),
messages,
middleware: [withSkills(skills)],
})

return toServerSentEventsResponse(stream)
}

카탈로그가 빌드 타임에 포함되므로 skills.names는 스킬 이름의 typed list이고 load_skill 도구의 name은 이 목록으로 제한됩니다.

자체 저장소에서​

DB, S3 또는 registry 기반 스킬은 직접 SkillSource를 정의합니다. 스킬을 나열하고 이름으로 하나를 로드하는 작은 interface입니다. 자세한 설명은 스킬 소스 작성에서 전체 안내와 어댑터 동작을 검증하는 conformance suite를 확인하세요.

소스 결합​

실제 설정에서는 조직 전체, 프로젝트별, tenant별로 스킬을 계층화합니다. combinator로 결합한 뒤 결과를 withSkills에 전달합니다.

import { aggregate, dedupe } from '@tanstack/ai-skills'

// Org skills plus this tenant's skills, org first on a name clash.
const source = dedupe(aggregate([orgSkills, tenantSkills]))
Combinator동작
aggregate([a, b])순서대로 소스를 연결합니다. 중복 제거하지 않습니다.
dedupe(source)이름의 첫 번째 발생이 우선하며 충돌 시 경고합니다.
filter(source, fn)predicate가 거부하는 스킬을 숨깁니다. 숨겨진 스킬은 카탈로그에 도달하지 않습니다.
cache(source)list()와 load()를 메모이즈합니다. 동시 호출에서 하나의 fetch를 공유합니다.

배열을 withSkills([a, b])에 직접 전달하는 것은 다음의 축약형입니다. dedupe(aggregate([a, b]))의 축약형입니다. 단일 소스는 그대로 사용되고 래핑되지 않으므로 tenant 범위 소스가 실수로 공유 bucket에 캐시되지 않습니다. 공유해도 안전한 소스일 때만 직접 cache를 사용하세요.

다음 단계​