自定义子图
创建与配置子图
以下章节提供了在创建智能体工作流子图时的代码模板和常见模式。
基本子图创建
自定义子图通常使用以下模式创建:
- 具有指定工具选择策略的子图:
kotlin
strategy<StrategyInput, StrategyOutput>("strategy-name") {
val subgraphIdentifier by subgraph<Input, Output>(
name = "subgraph-name",
toolSelectionStrategy = ToolSelectionStrategy.ALL
) {
// 为此子图定义节点和边
}
nodeStart then subgraphIdentifier then nodeFinish
}java
var strategyBuilder = AIAgentGraphStrategy.builder("strategy-name")
.withInput(String.class)
.withOutput(String.class);
var subgraphIdentifier = AIAgentSubgraph.builder("subgraph-name")
.withToolSelectionStrategy(ToolSelectionStrategy.ALL.INSTANCE)
.withInput(String.class)
.withOutput(String.class)
.define(subgraph -> {
// 为此子图定义节点和边
})
.build();
var strategy = strategyBuilder
.edge(strategyBuilder.nodeStart, subgraphIdentifier)
.edge(subgraphIdentifier, strategyBuilder.nodeFinish)
.build();- 具有指定工具列表的子图(定义工具库中的工具子集):
kotlin
strategy<StrategyInput, StrategyOutput>("strategy-name") {
val subgraphIdentifier by subgraph<Input, Output>(
name = "subgraph-name",
tools = listOf(firstTool, secondTool)
) {
// 为此子图定义节点和边
}
}java
var strategyBuilder = AIAgentGraphStrategy.builder("strategy-name")
.withInput(String.class)
.withOutput(String.class);
var subgraphIdentifier = AIAgentSubgraph.builder("subgraph-name")
.limitedTools(List.of(firstTool, secondTool))
.withInput(String.class)
.withOutput(String.class)
.define(subgraph -> {
// 为此子图定义节点和边
})
.build();
var strategy = strategyBuilder
.edge(strategyBuilder.nodeStart, subgraphIdentifier)
.edge(subgraphIdentifier, strategyBuilder.nodeFinish)
.build();有关参数和参数值的更多信息,请参阅 subgraph API 参考。有关工具的更多信息,请参阅工具。
以下代码示例展示了自定义子图的实际实现:
kotlin
strategy<String, String>("my-strategy") {
val mySubgraph by subgraph<String, String>(
tools = listOf(firstTool, secondTool)
) {
// 为此子图定义节点和边
val sendInput by nodeLLMRequest()
val executeToolCall by nodeExecuteTools()
val sendToolResult by nodeLLMSendToolResults()
edge(nodeStart forwardTo sendInput)
edge(sendInput forwardTo executeToolCall onToolCalls { true })
edge(executeToolCall forwardTo sendToolResult)
edge(sendToolResult forwardTo nodeFinish onTextMessage { true })
}
}java
var strategyBuilder = AIAgentGraphStrategy.builder("my-strategy")
.withInput(String.class)
.withOutput(String.class);
var sendInput = AIAgentNode.llmRequest(null);
var executeToolCall = AIAgentNode.executeTools(null);
var sendToolResult = AIAgentNode.llmSendToolResults(null);
var mySubgraph = AIAgentSubgraph.builder()
.limitedTools(List.of(firstTool, secondTool))
.withInput(String.class)
.withOutput(String.class)
.define(subgraph -> {
// 为此子图定义节点和边
subgraph
.edge(AIAgentEdge.builder()
.from(subgraph.nodeStart)
.to(sendInput)
.build()
)
.edge(AIAgentEdge.builder()
.from(sendInput)
.to(executeToolCall)
.onToolCalls()
.build()
)
.edge(executeToolCall, sendToolResult)
.edge(AIAgentEdge.builder()
.from(sendToolResult)
.to(subgraph.nodeFinish)
.onTextMessage()
.build()
)
.build();
})
.build();
var strategy = strategyBuilder
.edge(strategyBuilder.nodeStart, mySubgraph)
.edge(mySubgraph, strategyBuilder.nodeFinish)
.build();在子图中配置工具
可以通过多种方式为子图配置工具:
- 直接在子图定义中配置:
kotlin
val mySubgraph by subgraph<String, String>(
tools = listOf(AskUser)
) {
// 子图定义
}java
var mySubgraph = AIAgentSubgraph.builder()
.limitedTools(List.of(AskUser.INSTANCE))
.withInput(String.class)
.withOutput(String.class)
.define(subgraph -> {
// 子图定义
})
.build();- 从工具库中配置:
kotlin
val mySubgraph by subgraph<String, String>(
tools = listOf(toolRegistry.getTool("AskUser"))
) {
// 子图定义
}java
var mySubgraph = AIAgentSubgraph.builder()
.limitedTools(List.of(toolRegistry.getTool("AskUser")))
.withInput(String.class)
.withOutput(String.class)
.define(subgraph -> {
// 子图定义
})
.build();- 在执行期间动态配置:
kotlin
// 创建一组工具
this.llm.writeSession {
tools = tools.filter { it.name in listOf("first_tool_name", "second_tool_name") }
}java
var node = AIAgentNode.builder("node_name")
.withInput(String.class)
.withOutput(String.class)
.withAction((input, ctx) -> {
// 创建一组工具
ctx.getLlm().writeSession(session -> {
session.setTools(session.getTools().stream()
.filter(t -> List.of("first_tool_name", "second_tool_name").contains(t.getName()))
.collect(Collectors.toList()));
return null;
});
return input;
})
.build();高级子图技巧
多部分策略
复杂的工作流可以分解为多个子图,每个子图处理过程中的特定部分:
kotlin
strategy("complex-workflow") {
val inputProcessing by subgraph<String, A>(
) {
// 处理初始输入
}
val reasoning by subgraph<A, B>(
) {
// 根据处理后的输入进行推理
}
val toolRun by subgraph<B, C>(
// 来自工具库的可选工具子集
tools = listOf(firstTool, secondTool)
) {
// 根据推理运行工具
}
val responseGeneration by subgraph<C, String>(
) {
// 根据工具结果生成响应
}
nodeStart then inputProcessing then reasoning then toolRun then responseGeneration then nodeFinish
}java
var strategyBuilder = AIAgentGraphStrategy.builder("complex-workflow")
.withInput(String.class)
.withOutput(String.class);
var inputProcessing = AIAgentSubgraph.builder()
.withInput(String.class)
.withOutput(String.class)
.define(subgraph -> {
// 处理初始输入
})
.build();
var reasoning = AIAgentSubgraph.builder()
.withInput(String.class)
.withOutput(String.class)
.define(subgraph -> {
// 根据处理后的输入进行推理
})
.build();
var toolRun = AIAgentSubgraph.builder()
// 来自工具库的可选工具子集
.limitedTools(List.of(firstTool, secondTool))
.withInput(String.class)
.withOutput(String.class)
.define(subgraph -> {
// 根据推理运行工具
})
.build();
var responseGeneration = AIAgentSubgraph.builder()
.withInput(String.class)
.withOutput(String.class)
.define(subgraph -> {
// 根据工具结果生成响应
})
.build();
var strategy = strategyBuilder
.edge(strategyBuilder.nodeStart, inputProcessing)
.edge(inputProcessing, reasoning)
.edge(reasoning, toolRun)
.edge(toolRun, responseGeneration)
.edge(responseGeneration, strategyBuilder.nodeFinish)
.build();最佳做法
使用子图时,请遵循以下最佳做法:
将复杂工作流分解为子图:每个子图应具有清晰、集中的职责。
仅传递必要的上下文:仅传递后续子图正常运行所需的信息。
记录子图依赖关系:清晰地记录每个子图对前序子图的预期以及它为后续子图提供的内容。
孤立测试子图:在将子图集成到策略中之前,确保每个子图在各种输入下都能正确工作。
考虑 Token 使用情况:注意 Token 使用情况,尤其是在子图之间传递大量历史记录时。
故障排除
工具不可用
如果子图中工具不可用:
- 检查工具是否已在工具库中正确注册。
子图未按定义和预期的顺序运行
如果子图未按定义的顺序执行:
- 检查策略定义,确保子图按正确的顺序排列。
- 验证每个子图是否正确地将其输出传递给下一个子图。
- 确保您的子图与子图的其余部分相连,并且可以从开始(和结束)节点到达。注意条件边,确保它们涵盖了所有可能的继续执行条件,以免在子图或节点中阻塞。
示例
以下示例展示了如何在实际场景中使用子图创建智能体策略。 该代码示例包含三个定义的子图:researchSubgraph、planSubgraph 和 executeSubgraph,其中每个子图在助手流程中都有明确且不同的目的。
kotlin
// 定义智能体策略
val strategy = strategy<String, String>("assistant") {
// 包含工具调用的子图
val researchSubgraph by subgraph<String, String>(
"research_subgraph",
tools = listOf(WebSearchTool())
) {
val nodeCallLLM by nodeLLMRequest("call_llm")
val nodeExecuteTool by nodeExecuteTools()
val nodeSendToolResult by nodeLLMSendToolResults()
edge(nodeStart forwardTo nodeCallLLM)
edge(nodeCallLLM forwardTo nodeExecuteTool onToolCalls { true })
edge(nodeExecuteTool forwardTo nodeSendToolResult)
edge(nodeSendToolResult forwardTo nodeExecuteTool onToolCalls { true })
edge(nodeCallLLM forwardTo nodeFinish onTextMessage { true })
}
val planSubgraph by subgraph(
"plan_subgraph",
tools = listOf()
) {
val nodeUpdatePrompt by node<String, Unit> { research ->
llm.writeSession {
rewritePrompt {
prompt("research_prompt") {
system(
"You are given a problem and some research on how it can be solved." +
"Make step by step a plan on how to solve given task."
)
user("Research: $research")
}
}
}
}
val nodeCallLLM by nodeLLMRequest("call_llm")
edge(nodeStart forwardTo nodeUpdatePrompt)
edge(nodeUpdatePrompt forwardTo nodeCallLLM transformed { "Task: $agentInput" })
edge(nodeCallLLM forwardTo nodeFinish onTextMessage { true })
}
val executeSubgraph by subgraph<String, String>(
"execute_subgraph",
tools = listOf(DoAction(), DoAnotherAction()),
) {
val nodeUpdatePrompt by node<String, Unit> { plan ->
llm.writeSession {
rewritePrompt {
prompt("execute_prompt") {
system(
"You are given a task and detailed plan how to execute it." +
"Perform execution by calling relevant tools."
)
user("Execute: $plan")
user("Plan: $plan")
}
}
}
}
val nodeCallLLM by nodeLLMRequest("call_llm")
val nodeExecuteTool by nodeExecuteTools()
val nodeSendToolResult by nodeLLMSendToolResults()
edge(nodeStart forwardTo nodeUpdatePrompt)
edge(nodeUpdatePrompt forwardTo nodeCallLLM transformed { "Task: $agentInput" })
edge(nodeCallLLM forwardTo nodeExecuteTool onToolCalls { true })
edge(nodeExecuteTool forwardTo nodeSendToolResult)
edge(nodeSendToolResult forwardTo nodeExecuteTool onToolCalls { true })
edge(nodeCallLLM forwardTo nodeFinish onTextMessage { true })
}
nodeStart then researchSubgraph then planSubgraph then executeSubgraph then nodeFinish
}java
// 定义智能体策略
var strategyBuilder = AIAgentGraphStrategy.builder("assistant")
.withInput(String.class)
.withOutput(String.class);
// 包含工具调用的子图
var nodeCallLLM = AIAgentNode.llmRequest(null);
var nodeExecuteTool = AIAgentNode.executeTools(null);
var nodeSendToolResult = AIAgentNode.llmSendToolResults(null);
var researchSubgraph = AIAgentSubgraph.builder("research_subgraph")
.limitedTools(new WebSearchToolSet())
.withInput(String.class)
.withOutput(String.class)
.define(subgraph -> {
subgraph
.edge(AIAgentEdge.builder()
.from(subgraph.nodeStart)
.to(nodeCallLLM)
.build()
)
.edge(AIAgentEdge.builder()
.from(nodeCallLLM)
.to(nodeExecuteTool)
.onToolCalls()
.build()
)
.edge(nodeExecuteTool, nodeSendToolResult)
.edge(AIAgentEdge.builder()
.from(nodeSendToolResult)
.to(nodeExecuteTool)
.onToolCalls()
.build()
)
.edge(AIAgentEdge.builder()
.from(nodeCallLLM)
.to(subgraph.nodeFinish)
.onTextMessage()
.build()
)
.build();
})
.build();
var nodeUpdatePrompt = AIAgentNode.builder()
.withInput(String.class)
.withOutput(String.class)
.withAction((research, ctx) -> {
ctx.getLlm().writeSession(session -> {
session.setPrompt(Prompt.builder("research_prompt")
.system(
"You are given a problem and some research on how it can be solved." +
"Make step by step a plan on how to solve given task."
)
.user("Research: " + research)
.build());
return null;
});
return "Task: " + ctx.getAgentInput();
})
.build();
var nodeCallLLMPlan = AIAgentNode.llmRequest(null);
var planSubgraph = AIAgentSubgraph.builder("plan_subgraph")
.limitedTools(Collections.emptyList())
.withInput(String.class)
.withOutput(String.class)
.define(subgraph -> {
subgraph
.edge(subgraph.nodeStart, nodeUpdatePrompt)
.edge(AIAgentEdge.builder()
.from(nodeUpdatePrompt)
.to(nodeCallLLMPlan)
.build()
)
.edge(AIAgentEdge.builder()
.from(nodeCallLLMPlan)
.to(subgraph.nodeFinish)
.onTextMessage()
.build()
)
.build();
})
.build();
var nodeUpdatePromptExecute = AIAgentNode.builder()
.withInput(String.class)
.withOutput(String.class)
.withAction((plan, ctx) -> {
ctx.getLlm().writeSession(session -> {
session.setPrompt(Prompt.builder("execute_prompt")
.system(
"You are given a task and detailed plan how to execute it." +
"Perform execution by calling relevant tools."
)
.user("Execute: " + plan)
.user("Plan: " + plan)
.build());
return null;
});
return "Task: " + ctx.getAgentInput();
})
.build();
var nodeCallLLMExecute = AIAgentNode.llmRequest(null);
var nodeExecuteToolExecute = AIAgentNode.executeTools(null);
var nodeSendToolResultExecute = AIAgentNode.llmSendToolResults(null);
var executeSubgraph = AIAgentSubgraph.builder("execute_subgraph")
.limitedTools(new ActionToolSet())
.withInput(String.class)
.withOutput(String.class)
.define(subgraph -> {
subgraph
.edge(subgraph.nodeStart, nodeUpdatePromptExecute)
.edge(AIAgentEdge.builder()
.from(nodeUpdatePromptExecute)
.to(nodeCallLLMExecute)
.build()
)
.edge(AIAgentEdge.builder()
.from(nodeCallLLMExecute)
.to(nodeExecuteToolExecute)
.onToolCalls()
.build()
)
.edge(nodeExecuteToolExecute, nodeSendToolResultExecute)
.edge(AIAgentEdge.builder()
.from(nodeSendToolResultExecute)
.to(nodeExecuteToolExecute)
.onToolCalls()
.build()
)
.edge(AIAgentEdge.builder()
.from(nodeCallLLMExecute)
.to(subgraph.nodeFinish)
.onIsInstance(Message.Assistant.class)
.onTextMessage()
.build()
)
.build();
})
.build();
var strategy = strategyBuilder
.edge(strategyBuilder.nodeStart, researchSubgraph)
.edge(researchSubgraph, planSubgraph)
.edge(planSubgraph, executeSubgraph)
.edge(executeSubgraph, strategyBuilder.nodeFinish)
.build();