하위 그래프 생성 및 구성

·3분 읽기

원문: Koog Documentation — custom-subgraphs 이 글은 Koog 공식 문서의 custom-subgraphs 페이지를 한국어로 옮긴 번역본입니다. 문서 구조와 링크 의미를 유지하되, MkDocs 전용 UI 문법은 블로그에서 읽기 좋도록 정리했습니다.

하위 그래프 생성 및 구성

다음 섹션에서는 에이전트 워크플로에 대한 하위 그래프 생성 시 코드 템플릿과 일반적인 패턴을 제공합니다.

기본 하위 그래프 생성

사용자 정의 하위 그래프는 일반적으로 다음 패턴을 사용하여 생성됩니다.

  • 지정된 도구 선택 전략이 포함된 하위 그래프:

코틀린

1strategy<StrategyInput, StrategyOutput>("strategy-name") {2    val subgraphIdentifier by subgraph<Input, Output>(3        name = "subgraph-name",4        toolSelectionStrategy = ToolSelectionStrategy.ALL5    ) {6        // Define nodes and edges for this subgraph7    }89    nodeStart then subgraphIdentifier then nodeFinish10}

자바

1var strategyBuilder = AIAgentGraphStrategy.builder("strategy-name")2    .withInput(String.class)3    .withOutput(String.class);45var subgraphIdentifier = AIAgentSubgraph.builder("subgraph-name")6    .withToolSelectionStrategy(ToolSelectionStrategy.ALL.INSTANCE)7    .withInput(String.class)8    .withOutput(String.class)9    .define(subgraph -> {10        // Define nodes and edges for this subgraph11    })12    .build();1314var strategy = strategyBuilder15    .edge(strategyBuilder.nodeStart, subgraphIdentifier)16    .edge(subgraphIdentifier, strategyBuilder.nodeFinish)17    .build();
  • 지정된 도구 목록(정의된 도구 레지스트리의 도구 하위 집합)이 포함된 하위 그래프:

코틀린

1strategy<StrategyInput, StrategyOutput>("strategy-name") {2   val subgraphIdentifier by subgraph<Input, Output>(3       name = "subgraph-name",4       tools = listOf(firstTool, secondTool)5   ) {6        // Define nodes and edges for this subgraph7    }8}

자바

1var strategyBuilder = AIAgentGraphStrategy.builder("strategy-name")2    .withInput(String.class)3    .withOutput(String.class);45var subgraphIdentifier = AIAgentSubgraph.builder("subgraph-name")6    .limitedTools(List.of(firstTool, secondTool))7    .withInput(String.class)8    .withOutput(String.class)9    .define(subgraph -> {10        // Define nodes and edges for this subgraph11    })12    .build();1314var strategy = strategyBuilder15    .edge(strategyBuilder.nodeStart, subgraphIdentifier)16    .edge(subgraphIdentifier, strategyBuilder.nodeFinish)17    .build();

매개변수 및 매개변수 값에 대한 자세한 내용은 subgraph API reference을 참조하세요. 더 알아보기 도구에 대한 자세한 내용은 Tools을 참조하세요.

다음 코드 샘플은 사용자 정의 하위 그래프의 실제 구현을 보여줍니다.

코틀린

1strategy<String, String>("my-strategy") {2   val mySubgraph by subgraph<String, String>(3      tools = listOf(firstTool, secondTool)4   ) {5        // Define nodes and edges for this subgraph6        val sendInput by nodeLLMRequest()7        val executeToolCall by nodeExecuteTool()8        val sendToolResult by nodeLLMSendToolResult()910        edge(nodeStart forwardTo sendInput)11        edge(sendInput forwardTo executeToolCall onToolCall { true })12        edge(executeToolCall forwardTo sendToolResult)13        edge(sendToolResult forwardTo nodeFinish onAssistantMessage { true })14    }15}

자바

1var strategyBuilder = AIAgentGraphStrategy.builder("my-strategy")2        .withInput(String.class)3        .withOutput(String.class);45var sendInput = AIAgentNode.llmRequest();6var executeToolCall = AIAgentNode.executeTool();7var sendToolResult = AIAgentNode.llmSendToolResult();89var mySubgraph = AIAgentSubgraph.builder()10    .limitedTools(List.of(firstTool, secondTool))11    .withInput(String.class)12    .withOutput(String.class)13    .define(subgraph -> {14        // Define nodes and edges for this subgraph15        subgraph16            .edge(subgraph.nodeStart, sendInput)17            .edge(AIAgentEdge.builder()18                .from(sendInput)19                .to(executeToolCall)20                .onIsInstance(Message.Tool.Call.class)21                .build()22            )23            .edge(executeToolCall, sendToolResult)24            .edge(AIAgentEdge.builder()25                .from(sendToolResult)26                .to(subgraph.nodeFinish)27                .onIsInstance(Message.Assistant.class)28                .transformed(Message.Assistant::getContent)29                .build()30            )31            .build();3233    })34    .build();3536var strategy = strategyBuilder37    .edge(strategyBuilder.nodeStart, mySubgraph)38    .edge(mySubgraph, strategyBuilder.nodeFinish)39    .build();

하위 그래프에서 도구 구성

여러 가지 방법으로 하위 그래프에 대한 도구를 구성할 수 있습니다.

  • 하위 그래프 정의에서 직접:

코틀린

1val mySubgraph by subgraph<String, String>(2   tools = listOf(AskUser)3 ) {4    // Subgraph definition5 }

자바

1var mySubgraph = AIAgentSubgraph.builder()2    .limitedTools(List.of(AskUser.INSTANCE))3    .withInput(String.class)4    .withOutput(String.class)5    .define(subgraph -> {6        // Subgraph definition7    })8    .build();
  • 도구 레지스트리에서:

코틀린

1val mySubgraph by subgraph<String, String>(2    tools = listOf(toolRegistry.getTool("AskUser"))3) {4    // Subgraph definition5}

자바

1var mySubgraph = AIAgentSubgraph.builder()2    .limitedTools(List.of(toolRegistry.getTool("AskUser")))3    .withInput(String.class)4    .withOutput(String.class)5    .define(subgraph -> {6        // Subgraph definition7    })8    .build();
  • 실행 중 동적으로:

코틀린

1// Make a set of tools2this.llm.writeSession {3    tools = tools.filter { it.name in listOf("first_tool_name", "second_tool_name") }4}

자바

1var node = AIAgentNode.builder("node_name")2    .withInput(String.class)3    .withOutput(String.class)4    .withAction((input, ctx) -> {5        // Make a set of tools6        ctx.getLlm().writeSession(session -> {7            session.setTools(session.getTools().stream()8                .filter(t -> List.of("first_tool_name", "second_tool_name").contains(t.getName()))9                .collect(Collectors.toList()));10            return null;11        });12        return input;13    })14    .build();

고급 하위 그래프 기술

다중 부분 전략

복잡한 워크플로는 각각 프로세스의 특정 부분을 처리하는 여러 하위 그래프로 나눌 수 있습니다.

코틀린

1strategy("complex-workflow") {2   val inputProcessing by subgraph<String, A>(3   ) {4      // Process the initial input5   }67   val reasoning by subgraph<A, B>(8   ) {9      // Perform reasoning based on the processed input10   }1112   val toolRun by subgraph<B, C>(13      // Optional subset of tools from the tool registry14      tools = listOf(firstTool, secondTool)15   ) {16      // Run tools based on the reasoning17   }1819   val responseGeneration by subgraph<C, String>(20   ) {21      // Generate a response based on the tool results22   }2324   nodeStart then inputProcessing then reasoning then toolRun then responseGeneration then nodeFinish2526}

자바

1var strategyBuilder = AIAgentGraphStrategy.builder("complex-workflow")2        .withInput(String.class)3        .withOutput(String.class);45var inputProcessing = AIAgentSubgraph.builder()6    .withInput(String.class)7    .withOutput(String.class)8    .define(subgraph -> {9        // Process the initial input10    })11    .build();1213var reasoning = AIAgentSubgraph.builder()14    .withInput(String.class)15    .withOutput(String.class)16    .define(subgraph -> {17        // Perform reasoning based on the processed input18    })19    .build();2021var toolRun = AIAgentSubgraph.builder()22    // Optional subset of tools from the tool registry23    .limitedTools(List.of(firstTool, secondTool))24    .withInput(String.class)25    .withOutput(String.class)26    .define(subgraph -> {27        // Run tools based on the reasoning28    })29    .build();3031var responseGeneration = AIAgentSubgraph.builder()32    .withInput(String.class)33    .withOutput(String.class)34    .define(subgraph -> {35        // Generate a response based on the tool results36    })37    .build();3839var strategy = strategyBuilder40    .edge(strategyBuilder.nodeStart, inputProcessing)41    .edge(inputProcessing, reasoning)42    .edge(reasoning, toolRun)43    .edge(toolRun, responseGeneration)44    .edge(responseGeneration, strategyBuilder.nodeFinish)45    .build();

모범 사례

하위 그래프로 작업할 때 다음 모범 사례를 따르십시오.

  1. 복잡한 워크플로를 하위 그래프로 나누기: 각 하위 그래프에는 명확하고 집중적인 책임이 있어야 합니다.

  2. 필요한 컨텍스트만 전달: 후속 하위 그래프가 올바르게 작동하는 데 필요한 정보만 전달합니다.

  3. 하위 그래프 종속성 문서화: 각 하위 그래프가 이전 하위 그래프에서 기대하는 것과 후속 하위 그래프에 무엇을 제공하는지 명확하게 문서화합니다.

  4. 하위 그래프를 별도로 테스트: 각 하위 그래프를 전략에 통합하기 전에 다양한 입력에서 올바르게 작동하는지 확인하세요.

  5. 토큰 사용 고려: 특히 하위 그래프 간에 대규모 기록을 전달할 때 토큰 사용에 주의하세요.

문제 해결

도구를 사용할 수 없음

하위 그래프에서 도구를 사용할 수 없는 경우:

  • 도구가 도구 레지스트리에 올바르게 등록되었는지 확인하십시오.

하위 그래프가 정의되고 예상된 순서로 실행되지 않습니다.

하위 그래프가 정의된 순서대로 실행되지 않는 경우:

  • 전략 정의를 확인하여 하위 그래프가 올바른 순서로 나열되어 있는지 확인하세요.
  • 각 하위 그래프가 출력을 다음 하위 그래프로 올바르게 전달하는지 확인하세요.
  • 하위 그래프가 하위 그래프의 나머지 부분과 연결되어 있고 처음부터 끝까지 도달할 수 있는지 확인하세요. 조건부 가장자리에 주의하세요. 하위 그래프나 노드에서 차단되지 않도록 계속하려면 가능한 모든 조건을 다루어야 합니다.

예

다음 예에서는 실제 시나리오에서 에이전트 전략을 생성하기 위해 하위 그래프를 사용하는 방법을 보여줍니다. 코드 샘플에는 researchSubgraph, planSubgraph 및 executeSubgraph의 세 가지 정의된 하위 그래프가 포함되어 있습니다. 여기서 각 하위 그래프에는 보조 흐름 내에서 정의되고 고유한 목적이 있습니다.

코틀린

1// Define the agent strategy2val strategy = strategy<String, String>("assistant") {34    // A subgraph that includes a tool call5    val researchSubgraph by subgraph<String, String>(6        "research_subgraph",7        tools = listOf(WebSearchTool())8    ) {9        val nodeCallLLM by nodeLLMRequest("call_llm")10        val nodeExecuteTool by nodeExecuteTool()11        val nodeSendToolResult by nodeLLMSendToolResult()1213        edge(nodeStart forwardTo nodeCallLLM)14        edge(nodeCallLLM forwardTo nodeExecuteTool onToolCall { true })15        edge(nodeExecuteTool forwardTo nodeSendToolResult)16        edge(nodeSendToolResult forwardTo nodeExecuteTool onToolCall { true })17        edge(nodeCallLLM forwardTo nodeFinish onAssistantMessage { true })18    }1920    val planSubgraph by subgraph(21        "plan_subgraph",22        tools = listOf()23    ) {24        val nodeUpdatePrompt by node<String, Unit> { research ->25            llm.writeSession {26                rewritePrompt {27                    prompt("research_prompt") {28                        system(29                            "You are given a problem and some research on how it can be solved." +30                                    "Make step by step a plan on how to solve given task."31                        )32                        user("Research: $research")33                    }34                }35            }36        }37        val nodeCallLLM by nodeLLMRequest("call_llm")3839        edge(nodeStart forwardTo nodeUpdatePrompt)40        edge(nodeUpdatePrompt forwardTo nodeCallLLM transformed { "Task: $agentInput" })41        edge(nodeCallLLM forwardTo nodeFinish onAssistantMessage { true })42    }4344    val executeSubgraph by subgraph<String, String>(45        "execute_subgraph",46        tools = listOf(DoAction(), DoAnotherAction()),47    ) {48        val nodeUpdatePrompt by node<String, Unit> { plan ->49            llm.writeSession {50                rewritePrompt {51                    prompt("execute_prompt") {52                        system(53                            "You are given a task and detailed plan how to execute it." +54                                    "Perform execution by calling relevant tools."55                        )56                        user("Execute: $plan")57                        user("Plan: $plan")58                    }59                }60            }61        }62        val nodeCallLLM by nodeLLMRequest("call_llm")63        val nodeExecuteTool by nodeExecuteTool()64        val nodeSendToolResult by nodeLLMSendToolResult()6566        edge(nodeStart forwardTo nodeUpdatePrompt)67        edge(nodeUpdatePrompt forwardTo nodeCallLLM transformed { "Task: $agentInput" })68        edge(nodeCallLLM forwardTo nodeExecuteTool onToolCall { true })69        edge(nodeExecuteTool forwardTo nodeSendToolResult)70        edge(nodeSendToolResult forwardTo nodeExecuteTool onToolCall { true })71        edge(nodeCallLLM forwardTo nodeFinish onAssistantMessage { true })72    }7374    nodeStart then researchSubgraph then planSubgraph then executeSubgraph then nodeFinish75}

자바

1// Define the agent strategy2var strategyBuilder = AIAgentGraphStrategy.builder("assistant")3    .withInput(String.class)4    .withOutput(String.class);56// A subgraph that includes a tool call7var nodeCallLLM = AIAgentNode.llmRequest();8var nodeExecuteTool = AIAgentNode.executeTool();9var nodeSendToolResult = AIAgentNode.llmSendToolResult();1011var researchSubgraph = AIAgentSubgraph.builder("research_subgraph")12    .limitedTools(new WebSearchToolSet())13    .withInput(String.class)14    .withOutput(String.class)15    .define(subgraph -> {16        subgraph17            .edge(subgraph.nodeStart, nodeCallLLM)18            .edge(AIAgentEdge.builder()19                .from(nodeCallLLM)20                .to(nodeExecuteTool)21                .onIsInstance(Message.Tool.Call.class)22                .build()23            )24            .edge(nodeExecuteTool, nodeSendToolResult)25            .edge(AIAgentEdge.builder()26                .from(nodeSendToolResult)27                .to(nodeExecuteTool)28                .onIsInstance(Message.Tool.Call.class)29                .build()30            )31            .edge(AIAgentEdge.builder()32                .from(nodeCallLLM)33                .to(subgraph.nodeFinish)34                .onIsInstance(Message.Assistant.class)35                .transformed(Message.Assistant::getContent)36                .build()37            )38            .build();39    })40    .build();4142var nodeUpdatePrompt = AIAgentNode.builder()43    .withInput(String.class)44    .withOutput(String.class)45    .withAction((research, ctx) -> {46        ctx.getLlm().writeSession(session -> {47            session.setPrompt(Prompt.builder("research_prompt")48                .system(49                    "You are given a problem and some research on how it can be solved." +50                    "Make step by step a plan on how to solve given task."51                )52                .user("Research: " + research)53                .build());54            return null;55        });56        return "Task: " + ctx.getAgentInput();57    })58    .build();59var nodeCallLLMPlan = AIAgentNode.llmRequest();6061var planSubgraph = AIAgentSubgraph.builder("plan_subgraph")62    .limitedTools(Collections.emptyList())63    .withInput(String.class)64    .withOutput(String.class)65    .define(subgraph -> {66        subgraph67            .edge(subgraph.nodeStart, nodeUpdatePrompt)68            .edge(nodeUpdatePrompt, nodeCallLLMPlan)69            .edge(AIAgentEdge.builder()70                .from(nodeCallLLMPlan)71                .to(subgraph.nodeFinish)72                .onIsInstance(Message.Assistant.class)73                .transformed(Message.Assistant::getContent)74                .build()75            )76            .build();77    })78    .build();7980var nodeUpdatePromptExecute = AIAgentNode.builder()81    .withInput(String.class)82    .withOutput(String.class)83    .withAction((plan, ctx) -> {84        ctx.getLlm().writeSession(session -> {85            session.setPrompt(Prompt.builder("execute_prompt")86                .system(87                    "You are given a task and detailed plan how to execute it." +88                    "Perform execution by calling relevant tools."89                )90                .user("Execute: " + plan)91                .user("Plan: " + plan)92                .build());93            return null;94        });95        return "Task: " + ctx.getAgentInput();96    })97    .build();9899var nodeCallLLMExecute = AIAgentNode.llmRequest();100var nodeExecuteToolExecute = AIAgentNode.executeTool();101var nodeSendToolResultExecute = AIAgentNode.llmSendToolResult();102103var executeSubgraph = AIAgentSubgraph.builder("execute_subgraph")104    .limitedTools(new ActionToolSet())105    .withInput(String.class)106    .withOutput(String.class)107    .define(subgraph -> {108        subgraph109            .edge(subgraph.nodeStart, nodeUpdatePromptExecute)110            .edge(nodeUpdatePromptExecute, nodeCallLLMExecute)111            .edge(AIAgentEdge.builder()112                .from(nodeCallLLMExecute)113                .to(nodeExecuteToolExecute)114                .onIsInstance(Message.Tool.Call.class)115                .build()116            )117            .edge(nodeExecuteToolExecute, nodeSendToolResultExecute)118            .edge(AIAgentEdge.builder()119                .from(nodeSendToolResultExecute)120                .to(nodeExecuteToolExecute)121                .onIsInstance(Message.Tool.Call.class)122                .build()123            )124            .edge(AIAgentEdge.builder()125                .from(nodeCallLLMExecute)126                .to(subgraph.nodeFinish)127                .onIsInstance(Message.Assistant.class)128                .transformed(Message.Assistant::getContent)129                .build()130            )131            .build();132    })133    .build();134135var strategy = strategyBuilder136    .edge(strategyBuilder.nodeStart, researchSubgraph)137    .edge(researchSubgraph, planSubgraph)138    .edge(planSubgraph, executeSubgraph)139    .edge(executeSubgraph, strategyBuilder.nodeFinish)140    .build();