하위 그래프 생성 및 구성

·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, planSubgraphexecuteSubgraph의 세 가지 정의된 하위 그래프가 포함되어 있습니다. 여기서 각 하위 그래프에는 보조 흐름 내에서 정의되고 고유한 목적이 있습니다.

코틀린

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();