`dynamicTool()`
dynamicTool()
dynamicTool 함수는 입력과 출력 타입이 컴파일 시점에 알려지지 않은 툴을 만듭니다. 다음과 같은 시나리오에 유용합니다.
- 스키마가 없는 MCP(Model Context Protocol) 툴
- 런타임에 로드되는 사용자 정의 함수
- 외부 소스나 데이터베이스에서 로드된 툴
- 사용자 입력에 기반한 동적 툴 생성
일반적인 tool 함수와 달리 dynamicTool은 unknown 타입을 받고 반환하여 런타임에 결정되는 스키마를 가진 툴을 다룰 수 있게 해 줍니다.
출처: 문서
본문
import { dynamicTool } from 'ai';
import { z } from 'zod';
export const customTool = dynamicTool({
description: 'Execute a custom user-defined function',
inputSchema: z.object({}),
// input is typed as 'unknown'
execute: async input => {
const { action, parameters } = input as any;
// Execute your dynamic logic
return {
result: `Executed ${action} with ${JSON.stringify(parameters)}`,
};
},
});
Import
import { dynamicTool } from "ai"
API Signature
Parameters (파라미터)
tool:Object— 동적 툴 정의입니다.description:string | ((options: { context: Context; experimental_sandbox?: Experimental_SandboxSession }) => string)(선택) — 모델이 언제 어떻게 사용할 수 있는지에 대한 세부 정보를 포함한 툴의 목적 정보입니다. 고정 설명에는 문자열을, 각 모델 호출 전에 툴별 컨텍스트와 선택적 실험적 샌드박스에서 설명을 도출하려면 함수를 제공하세요.deferLoading:boolean(선택) —toolSearch가 발견할 때까지 이 툴을 모델 컨텍스트 밖에 둡니다.toolDiscovery: 'conversation'와 함께 직접 호출 또는 코드 모드를 지원합니다. 발견된 툴은 다음 모델 스텝에서 사용 가능해집니다. 기본값은false입니다.title:string(선택) — deprecated 되었습니다. 소스별 툴 표시 메타데이터에는providerMetadata를 사용하세요.needsApproval:boolean | ((input: unknown, options: { toolCallId: string; messages: ModelMessage[]; context: Context }) => boolean | Promise<boolean>)(선택) — deprecated 되었습니다.generateText,streamText,ToolLoopAgent에서는toolApproval로 승인을 구성하세요. 기존needsApproval사용은 호환성 폴백으로 여전히 동작합니다. 사용 시 불리언이거나 툴 입력과 실행 메타데이터를 받는 함수일 수 있습니다.inputSchema:FlexibleSchema<unknown>— 툴이 기대하는 입력의 스키마입니다. 타입은 unknown이지만 검증을 위해 스키마가 여전히 필요합니다. 완전 동적 입력에는z.unknown()또는z.any()를 가진 Zod 스키마를 사용할 수 있습니다.execute:ToolExecuteFunction<unknown, unknown, Context>— 툴 호출의 인자로 호출되는 비동기 함수입니다. 입력은 unknown으로 타입이 지정되며 런타임에 검증/캐스팅해야 합니다.toolCallId:string— 툴 호출의 ID입니다.messages:ModelMessage[]— 언어 모델로 전송된 메시지입니다.abortSignal:AbortSignal(선택) — 선택적 abort 신호입니다.context:Context— 툴 실행에 전달되는 툴별 컨텍스트입니다. 이 값은toolsContext의 일치 항목에서 옵니다.
outputSchema:Zod Schema | JSON Schema(선택) — 툴이 생성하는 출력의 스키마입니다. 검증과 타입 추론에 사용됩니다.toModelOutput:({toolCallId: string; input: unknown; output: unknown}) => ToolResultOutput | PromiseLike<ToolResultOutput>(선택) — 툴 결과를 언어 모델이 사용할 수 있는 출력으로 매핑하는 선택적 변환 함수입니다.onInputStart:(options: ToolExecutionOptions<Context>) => void | PromiseLike<void>(선택) — 모델이 툴 입력 생성을 시작할 때 호출되는 선택적 함수입니다. 비스트리밍 컨텍스트에서는onInputAvailable직전에 호출됩니다.onInputDelta:(options: { inputTextDelta: string } & ToolExecutionOptions<Context>) => void | PromiseLike<void>(선택) — 인자 스트리밍 델타가 준비될 때 호출되는 선택적 함수입니다. 툴이 스트리밍 컨텍스트에서 사용될 때만 호출됩니다.onInputAvailable:(options: { input: unknown } & ToolExecutionOptions<Context>) => void | PromiseLike<void>(선택) —execute함수가 제공되지 않아도 툴 호출을 시작할 수 있을 때 호출되는 선택적 함수입니다.providerOptions:ProviderOptions(선택) — 추가 프로바이더별 메타데이터입니다.metadata:JSONObject(선택) — 툴 자체에 대한 선택적 메타데이터입니다 (예: 소스). 결과 툴 호출의toolMetadata로 전파되어 소비자가 툴 호출/결과 파트와 UI 메시지 파트에서 읽을 수 있습니다. 동적 툴의 소스(예: MCP 서버)가 스스로를 식별하는 데 유용합니다.
Returns (반환값)
generateText, streamText 및 기타 AI SDK 함수와 함께 사용할 수 있는 type: 'dynamic'의 Tool<unknown, unknown>을 반환합니다.
Type-Safe Usage (타입 안전 사용법)
정적 툴과 함께 동적 툴을 사용할 때는 올바른 타입 좁히기(type narrowing)를 위해 dynamic 플래그를 확인해야 합니다.
const result = await generateText({
model: __MODEL__,
tools: {
// Static tool with known types
weather: weatherTool,
// Dynamic tool with unknown types
custom: dynamicTool({
/* ... */
}),
},
onStepEnd: ({ toolCalls, toolResults }) => {
for (const toolCall of toolCalls) {
if (toolCall.dynamic) {
// Dynamic tool: input/output are 'unknown'
console.log('Dynamic tool:', toolCall.toolName);
console.log('Input:', toolCall.input);
continue;
}
// Static tools have full type inference
switch (toolCall.toolName) {
case 'weather':
// TypeScript knows the exact types
console.log(toolCall.input.location); // string
break;
}
}
},
});
Usage with useChat (useChat와 함께 사용)
useChat(UIMessage 형식)와 함께 사용하면 동적 툴은 dynamic-tool 파트로 나타납니다.
{
message.parts.map(part => {
switch (part.type) {
case 'dynamic-tool':
return (
<div>
<h4>Tool: {part.toolName}</h4>
<pre>{JSON.stringify(part.input, null, 2)}</pre>
</div>
);
// ... handle other part types
}
});
}