클래스 기반 도구
원문: Koog Documentation — class-based-tools 이 글은 Koog 공식 문서의 class-based-tools 페이지를 한국어로 옮긴 번역본입니다. 문서 구조와 링크 의미를 유지하되, MkDocs 전용 UI 문법은 블로그에서 읽기 좋도록 정리했습니다.
클래스 기반 도구
이 섹션에서는 향상된 유연성과 사용자 정의된 동작이 필요한 시나리오를 위해 설계된 API에 대해 설명합니다. Kotlin에서 이 접근 방식을 사용하면 매개변수, 메타데이터, 실행 로직, 도구 등록 및 호출 방법을 포함하여 도구를 완전히 제어할 수 있습니다. Java에서는 리플렉션 기반 등록과 함께 주석 기반 메서드를 사용하여 도구가 생성됩니다.
이러한 제어 수준은 기본 사용 사례를 확장하여 상담원 세션 및 워크플로에 원활하게 통합할 수 있는 정교한 도구를 만드는 데 이상적입니다.
이 페이지에서는 Kotlin과 Java 모두에서 도구를 구현하고, 레지스트리를 통해 도구를 관리하고, 호출하고, 노드 기반 에이전트 아키텍처 내에서 사용하는 방법을 설명합니다.
참고 API는 Kotlin용 다중 플랫폼입니다. Java 도구는 주석 기반 메서드를 사용하여 구현되고 리플렉션을 통해 등록됩니다. 이를 통해 Kotlin의 다양한 플랫폼에서 동일한 도구를 사용할 수 있으며 Java는 완전한 JVM 상호 운용성을 제공합니다.
도구 구현
Koog 프레임워크는 도구 구현을 위해 다음과 같은 접근 방식을 제공합니다.
코틀린의 경우:
- 모든 도구에 기본 클래스
Tool를 사용합니다. 텍스트가 아닌 결과를 반환해야 하거나 도구 동작을 완전히 제어해야 하는 경우 이 클래스를 사용해야 합니다. - 기본
Tool클래스를 확장하고 텍스트 결과를 반환하는 도구 생성을 단순화하는SimpleTool클래스를 사용합니다. 다음과 같은 시나리오에 이 접근 방식을 사용해야 합니다. 도구는 텍스트만 반환하면 됩니다.
두 접근 방식 모두 동일한 핵심 구성 요소를 사용하지만 구현과 반환되는 결과가 다릅니다.
자바의 경우:
- 리플렉션 기반 등록과 함께 주석 기반 방법(
@Tool및@LLMDescription)을 사용합니다. 일시 중지 기능 제한으로 인해 Java에서 Kotlin의Tool또는SimpleTool서브클래싱이 지원되지 않으므로 이는 Java 상호 운용성을 위해 권장되는 접근 방식입니다.
도구 클래스(Kotlin)
Tool<Args, Result> 추상 클래스는 Kotlin에서 도구를 생성하기 위한 기본 클래스입니다.
이를 통해 특정 인수 유형(Args)을 허용하고 다양한 유형(Result)의 결과를 반환하는 도구를 만들 수 있습니다.
각 도구는 다음 구성 요소로 구성됩니다.
| 구성 요소 | 설명 |
|---|---|
Args |
도구에 필요한 인수를 정의하는 직렬화 가능한 데이터 클래스입니다. |
Result |
도구가 반환하는 직렬화 가능한 결과 유형입니다. 도구 결과를 사용자 정의 형식으로 표시하려면 ToolResult.TextSerializable 클래스를 상속하고 textForLLM(): String 메서드를 구현하세요. |
argsSerializer |
도구에 대한 인수가 역직렬화되는 방식을 정의하는 재정의된 변수입니다. argsSerializer도 참조하세요. |
resultSerializer |
도구 결과가 역직렬화되는 방식을 정의하는 재정의된 변수입니다. resultSerializer도 참조하세요. ToolResult.TextSerializable을 상속하기로 선택한 경우 ToolResultUtils.toTextSerializer() 사용을 고려하세요. |
descriptor |
도구 메타데이터를 지정하는 재정의된 변수: - name- description§TOK7§§- requiredParameters(기본적으로 비어 있음)- optionalParameters(기본적으로 비어 있음)descriptor도 참조하세요. |
execute() |
도구의 논리를 구현하는 함수입니다. Args 유형의 인수를 사용하고 Result 유형의 결과를 반환합니다. execute()도 참조하세요. |
참고: Java Implementation Java에서는
Tool<Args, Result>을 서브클래싱하는 대신@Tool및@LLMDescription와 함께 주석 기반 메서드를 사용합니다. 프레임워크는 리플렉션을 통해 자동으로 직렬화 및 등록을 처리합니다. 더 알아보기 자세한 내용은 아래 Annotation-based methods을 참조하세요.
참고 LLM이 도구를 더 쉽게 이해하고 적절하게 사용할 수 있도록 도구에 명확한 설명과 잘 정의된 매개변수 이름이 있는지 확인하세요. Kotlin에서는
descriptor속성을 사용하세요. Java에서는@LLMDescription주석을 사용합니다.
사용예
다음은 숫자 결과를 반환하는 Tool 클래스를 사용하는 사용자 정의 도구 구현의 예입니다.
코틀린
1// Implement a simple calculator tool that adds two digits2object CalculatorTool : Tool<CalculatorTool.Args, Int>(3 argsType = typeToken<Args>(),4 resultType = typeToken<Int>(),5 name = "calculator",6 description = "A simple calculator that can add two digits (0-9)."7) {89 // Arguments for the calculator tool10 @Serializable11 data class Args(12 @property:LLMDescription("The first digit to add (0-9)")13 val digit1: Int,14 @property:LLMDescription("The second digit to add (0-9)")15 val digit2: Int16 ) {17 init {18 require(digit1 in 0..9) { "digit1 must be a single digit (0-9)" }19 require(digit2 in 0..9) { "digit2 must be a single digit (0-9)" }20 }21 }2223 // Function to add two digits24 override suspend fun execute(args: Args): Int = args.digit1 + args.digit225}도구를 구현한 후에는 도구 레지스트리에 도구를 추가한 다음 에이전트와 함께 사용해야 합니다. 자세한 내용은 Tool registry을 참조하세요.
자세한 내용은 API reference을 참조하세요.
SimpleTool 클래스(Kotlin)
SimpleTool<Args> 추상 클래스는 Tool<Args, ToolResult.Text>을 확장하고 텍스트 결과를 반환하는 도구 생성을 단순화합니다.
각각의 간단한 도구는 다음 구성 요소로 구성됩니다.
| 구성 요소 | 설명 |
|---|---|
Args |
사용자 정의 도구에 필요한 인수를 정의하는 직렬화 가능한 데이터 클래스입니다. |
argsSerializer |
도구에 대한 인수가 직렬화되는 방식을 정의하는 재정의된 변수입니다. argsSerializer도 참조하세요. |
descriptor |
도구 메타데이터를 지정하는 재정의된 변수: - name- description- requiredParameters(기본적으로 비어 있음)- optionalParameters(기본적으로 비어 있음)descriptor도 참조하세요. |
doExecute() |
도구에서 수행되는 기본 작업을 설명하는 재정의된 함수입니다. Args 유형의 인수를 사용하고 String를 반환합니다. doExecute()도 참조하세요. |
참고: Java Implementation Java에서 동등한 접근 방식은
String을 반환하는 주석 기반 메서드를 사용하는 것입니다. 프레임워크는 텍스트 결과 래핑을 자동으로 처리합니다. 자세한 내용은 아래 Annotation-based methods을 참조하세요.
참고 LLM이 도구를 더 쉽게 이해하고 적절하게 사용할 수 있도록 도구에 명확한 설명과 잘 정의된 매개변수 이름이 있는지 확인하세요. Kotlin에서는
descriptor및 생성자 매개변수를 사용합니다. Java에서는@Tool및@LLMDescription주석을 사용합니다.
사용예
다음은 Kotlin에서 SimpleTool를 사용하는 사용자 정의 도구 구현의 예입니다.
코틀린
1// Create a tool that casts a string expression to a double value2object CastToDoubleTool : SimpleTool<CastToDoubleTool.Args>(3 argsType = typeToken<Args>(),4 name = "cast_to_double",5 description = "casts the passed expression to double or returns 0.0 if the expression is not castable"6) {7 // Define tool arguments8 @Serializable9 data class Args(10 @property:LLMDescription("An expression to case to double")11 val expression: String,12 @property:LLMDescription("A comment on how to process the expression")13 val comment: String14 )1516 // Function that executes the tool with the provided arguments17 override suspend fun execute(args: Args): String {18 return "Result: ${castToDouble(args.expression)}, " + "the comment was: ${args.comment}"19 }2021 // Function to cast a string expression to a double value22 private fun castToDouble(expression: String): Double {23 return expression.toDoubleOrNull() ?: 0.024 }25}주석 기반 메서드(Java)
Java에서 도구를 구현하려면 Tool 또는 SimpleTool을 서브클래싱하는 대신 @Tool 및 @Tool와 함께 주석 기반 메서드를 사용하세요.
@LLMDescription. Koog는 리플렉션을 통해 자동으로 직렬화 및 등록을 처리합니다. 자세히 알아보려면
구현에 대해서는 아래 Java 예제를 참조하세요.
사용 예
이는 Kotlin에서 Tool 클래스를 사용하는 것과 동일한 Java 도구 구현의 예입니다.
자바
1// Java equivalent: implement the tool as a Java method and register it via ToolRegistry.builder().2// This is the recommended Java interop path instead of subclassing the Kotlin Tool base class.3public final class CalculatorTool {4 private CalculatorTool() {}56 @Tool(customName = "calculator")7 @LLMDescription(description = "A simple calculator that can add two digits (0-9).")8 public static int calculator(9 @LLMDescription(description = "The first digit to add (0-9)") int digit1,10 @LLMDescription(description = "The second digit to add (0-9)") int digit211 ) {12 if (digit1 < 0 || digit1 > 9) throw new IllegalArgumentException("digit1 must be a single digit (0-9)");13 if (digit2 < 0 || digit2 > 9) throw new IllegalArgumentException("digit2 must be a single digit (0-9)");14 return digit1 + digit2;15 }1617 public static ToolRegistry registry() throws NoSuchMethodException {18 return ToolRegistry.builder()19 .tool(CalculatorTool.class.getMethod("calculator", int.class, int.class))20 .build();21 }22}23// Note: Subclassing the Kotlin Tool<TArgs, TResult> and overriding a suspend execute(...) from Java is not supported.24// The Java interop uses reflection-based registration of Java methods as tools.다음은 Kotlin에서 SimpleTool 클래스를 사용하는 것과 동일한 Java 도구 구현의 예입니다. 이 예
텍스트 결과를 반환하는 간단한 도구를 구현합니다.
자바
1// Java equivalent of SimpleTool: provide a Java method and register it as a tool.2public final class CastToDoubleTool {3 private CastToDoubleTool() {}45 @Tool(customName = "cast_to_double")6 @LLMDescription(description = "casts the passed expression to double or returns 0.0 if the expression is not castable")7 public static String castToDouble(8 @LLMDescription(description = "An expression to case to double") String expression,9 @LLMDescription(description = "A comment on how to process the expression") String comment10 ) {11 double value;12 try {13 value = Double.parseDouble(expression);14 } catch (Exception e) {15 value = 0.0;16 }17 return "Result: " + value + ", the comment was: " + comment;18 }1920 public static ToolRegistry registry() throws NoSuchMethodException {21 return ToolRegistry.builder()22 .tool(CastToDoubleTool.class.getMethod("castToDouble", String.class, String.class))23 .build();24 }25}26// Note: Extending Kotlin SimpleTool<TArgs> from Java is not required; registering a Java method is the idiomatic approach.도구 결과를 사용자 정의 형식으로 LLM에 보내기
코틀린의 경우:
LLM으로 전송된 JSON 결과가 만족스럽지 않은 경우(예를 들어 도구 출력이 Markdown으로 구성된 경우 LLM이 더 잘 작동할 수 있는 경우도 있음) 다음 단계를 따라야 합니다.
ToolResult.TextSerializable인터페이스를 구현하고textForLLM()메서드를 재정의합니다.ToolResultUtils.toTextSerializer<T>()을 사용하여resultSerializer재정의
자바의 경우:
주석이 달린 메서드에서 서식이 지정된 텍스트(예: Markdown)를 String으로 직접 반환합니다. 프레임워크는 이를 자동으로 처리합니다.
예
다음은 Kotlin과 Java 모두에서 사용자 지정 형식의 출력을 보여주는 예입니다.
코틀린
1// A tool that edits file2object EditFile : Tool<EditFile.Args, EditFile.Result>(3 argsType = typeToken<Args>(),4 resultType = typeToken<Result>(),5 name = "edit_file",6 description = "Edits the given file"7) {8 // Define tool arguments9 @Serializable10 public data class Args(11 val path: String,12 val original: String,13 val replacement: String14 )1516 @Serializable17 public data class Result(18 private val patchApplyResult: PatchApplyResult19 ) {2021 @Serializable22 public sealed interface PatchApplyResult {23 @Serializable24 public data class Success(val updatedContent: String) : PatchApplyResult2526 @Serializable27 public sealed class Failure(public val reason: String) : PatchApplyResult28 }2930 // Textual output (in Markdown format) that will be visible to the LLM after the tool finishes.31 fun textForLLM(): String = markdown {32 if (patchApplyResult is PatchApplyResult.Success) {33 line {34 bold("Successfully").text(" edited file (patch applied)")35 }36 } else {37 line {38 text("File was ")39 .bold("not")40 .text(" modified (patch application failed: ${(patchApplyResult as PatchApplyResult.Failure).reason})")41 }42 }43 }4445 override fun toString(): String = textForLLM()46 }4748 // Function that executes the tool with the provided arguments49 override suspend fun execute(args: Args): Result {50 return TODO("Implement file edit")51 }52}자바
1import ai.koog.agents.core.tools.ToolRegistry;2import ai.koog.agents.core.tools.annotations.LLMDescription;3import ai.koog.agents.core.tools.annotations.Tool;45// Java equivalent: return Markdown text directly to the LLM from a Java method and register it as a tool.6// This avoids needing a custom serializable Result type (which would require Kotlin serialization support).7public final class EditFile {8 private EditFile() {}910 @Tool(customName = "edit_file")11 @LLMDescription(description = "Edits the given file")12 public static String editFile(13 String path,14 String original,15 String replacement16 ) {17 // TODO: Implement file edit logic; below is a placeholder illustrating Markdown output18 boolean success = false;19 if (success) {20 return "**Successfully** edited file (patch applied)";21 } else {22 return "File was **not** modified (patch application failed: reason)";23 }24 }2526 public static ToolRegistry registry() throws NoSuchMethodException {27 return ToolRegistry.builder()28 .tool(EditFile.class.getMethod("editFile", String.class, String.class, String.class))29 .build();30 }31}32// Note: If you need a structured custom Result object from Java, you must expose a Kotlin @Serializable type33// or another serializer-aware type. Returning String works out-of-the-box with Koog's Java interop.Kotlin 또는 Java로 도구를 구현한 후 이를 도구 레지스트리에 추가한 다음 에이전트와 함께 사용해야 합니다. 자세한 내용은 Tool registry을 참조하세요.