功能型代理 (Functional agents)
使用功能型代理 (functional agents) 時,您將邏輯實作為一個函式,用於處理使用者輸入、與 LLM 互動、在必要時呼叫工具並產生最終輸出。 與 圖形化代理 (graph-based agents) 相比,這通常意味著更快的原型製作 (prototyping),但具有以下缺點:
- 不易視覺化
- 無狀態持久化 (state persistence)
先決條件
確保您的環境與專案符合以下需求:
JDK 17+
Kotlin 2.2.0+
Gradle 8.0+ 或 Maven 3.8+ 將 Koog 軟件包 新增為相依性:
dependencies {
// 穩定版
implementation("ai.koog:koog-agents:1.2.0")
// Beta
implementation("ai.koog:koog-agents-additions:1.2.0-beta")
}
dependencies {
// 穩定版
implementation 'ai.koog:koog-agents:1.2.0'
// Beta
implementation 'ai.koog:koog-agents-additions:1.2.0-beta'
}
<dependency>
<!-- 穩定版 -->
<dependency>
<groupId>ai.koog</groupId>
<artifactId>koog-agents-jvm</artifactId>
<version>1.2.0</version>
</dependency>
<!-- Beta -->
<dependency>
<groupId>ai.koog</groupId>
<artifactId>koog-agents-additions-jvm</artifactId>
<version>1.2.0-beta</version>
</dependency>
</dependency>從 LLM 提供商獲取 API key,或透過 Ollama 執行本機 LLM。
若要了解更多資訊,請參閱 快速入門。 本頁面中的範例假設您正透過 Ollama 在本機執行 Llama 3.2。
本頁面說明如何實作功能型策略,以為您的代理快速製作某些自訂邏輯的原型。
建立最小化功能型代理
若要建立最小化功能型代理,請使用與 基本代理 相同的 AIAgent 介面,並將 AIAgentFunctionalStrategy 的執行個體傳遞給它。 您可以定義一個功能型策略,該策略預期一個輸入並傳回一個輸出,進行一次 LLM 呼叫,然後從回應中傳回助理訊息的內容。
在 Kotlin 中,最方便的方式是使用 functionalStrategy {...} DSL 方法。在 Java 中,您可以使用 AIAgent builder 上的 functionalStrategy 方法。
val strategy = functionalStrategy<String, String> { input ->
val response = requestLLM(input)
response.parts.filterIsInstance<MessagePart.Text>().joinToString("
") { it.text }
}
val mathAgent = AIAgent(
promptExecutor = simpleOllamaAIExecutor(),
llmModel = OllamaModels.Meta.LLAMA_3_2,
strategy = strategy
)
fun main() = runBlocking {
val result = mathAgent.run("What is 12 × 9?")
println(result)
}AIAgent<String, String> mathAgent = AIAgent.builder()
.promptExecutor(SimpleLLMExecutorsKt.simpleOllamaAIExecutor("http://localhost:11434"))
.llmModel(OllamaModels.Meta.LLAMA_3_2)
.functionalStrategy("mathStrategy", (AIAgentFunctionalContext context, String input) -> {
Message.Response response = context.requestLLM(input);
if (response instanceof Message.Assistant) {
return ((Message.Assistant) response).getContent();
}
return "";
})
.build();
String result = mathAgent.run("What is 12 × 9?");
System.out.println(result);代理可以產生以下輸出:
The answer to 12 × 9 is 108.進行循序的 LLM 呼叫
您可以擴充之前的策略以進行多次循序的 LLM 呼叫:
fun Message.Assistant.text(): String =
parts.filterIsInstance<MessagePart.Text>().joinToString("
") { it.text }
val strategy = functionalStrategy<String, String> { input ->
// 第一次 LLM 呼叫根據使用者輸入產生初步草案
val draft = requestLLM("Draft: $input").text()
// 第二次 LLM 呼叫改進初步草案
val improved = requestLLM("Improve and clarify.").text()
// 最後一次 LLM 呼叫將改進後的文字格式化並傳回結果
requestLLM("Format the result as bold.").text()
}AIAgent<String, String> mathAgent = AIAgent.builder()
.promptExecutor(simpleOllamaAIExecutor("http://localhost:11434"))
.systemPrompt("You are a precise math assistant.")
.llmModel(OllamaModels.Meta.LLAMA_3_2)
.functionalStrategy((AIAgentFunctionalContext context, String input) -> {
// 第一次 LLM 呼叫根據使用者輸入產生初步草案
Message.Response draftResponse = context.requestLLM("Draft: " + input);
String draft = "";
if (draftResponse instanceof Message.Assistant) {
draft = ((Message.Assistant) draftResponse).getContent();
}
// 第二次 LLM 呼叫改進初步草案
Message.Response improvedResponse = context.requestLLM("Improve and clarify.");
String improved = "";
if (improvedResponse instanceof Message.Assistant) {
improved = ((Message.Assistant) improvedResponse).getContent();
}
// 最後一次 LLM 呼叫將改進後的文字格式化並傳回結果
Message.Response finalResponse = context.requestLLM("Format the result as bold.");
if (finalResponse instanceof Message.Assistant) {
return ((Message.Assistant) finalResponse).getContent();
}
return "";
})
.build();代理可以產生以下輸出:
To calculate the product of 12 and 9, we multiply these two numbers together.
12 × 9 = **108**加入工具
在許多情況下,功能型代理需要完成特定任務,例如讀取和寫入資料、呼叫 API 或執行其他確定性操作。在 Koog 中,您可以將這些功能公開為 工具 並讓 LLM 決定何時呼叫它們。
以下是您需要執行的步驟:
- 建立 基於註解的工具。
- 將其加入工具註冊表 (tool registry) 並將註冊表傳遞給代理。
- 確保代理策略可以識別 LLM 回應中的工具呼叫、執行要求的工具、將其結果傳送回 LLM,並重複此程序直到沒有剩餘的工具呼叫。
@LLMDescription("Tools for performing math operations")
class MathTools : ToolSet {
@Tool
@LLMDescription("Multiplies two numbers and returns the result")
fun multiply(a: Int, b: Int): Int {
// 這不是必須的,但有助於在主控台輸出中看到工具呼叫
println("Multiplying $a and $b...")
return a * b
}
}
val toolRegistry = ToolRegistry {
tool(MathTools()::multiply)
}
val strategy = functionalStrategy<String, String> { input ->
// 將使用者輸入傳送至 LLM
var response = requestLLM(input)
// 僅在 LLM 要求工具時進行迴圈
var toolCalls = response.parts.filterIsInstance<MessagePart.Tool.Call>()
while (toolCalls.isNotEmpty()) {
// 執行工具並傳回結果
val results = executeTools(toolCalls)
// 將工具結果傳送回 LLM。LLM 可能會呼叫更多工具或傳回最終輸出
response = sendToolResults(results)
toolCalls = response.parts.filterIsInstance<MessagePart.Tool.Call>()
}
// 當沒有剩餘工具呼叫時,從回應中提取並傳回助理訊息內容
response.parts.filterIsInstance<MessagePart.Text>().joinToString("
") { it.text }
}
val mathAgentWithTools = AIAgent(
promptExecutor = simpleOllamaAIExecutor(),
llmModel = OllamaModels.Meta.LLAMA_3_2,
toolRegistry = toolRegistry,
strategy = strategy
)
fun main() = runBlocking {
val result = mathAgentWithTools.run("Multiply 3 by 4, then multiply the result by 5.")
println(result)
}@LLMDescription(description = "Tools for performing math operations")
public static class MathTools implements ToolSet {
@Tool
@LLMDescription(description = "Multiplies two numbers and returns the result")
public int multiply(int a, int b) {
// 這不是必須的,但有助於在主控台輸出中看到工具呼叫
System.out.println("Multiplying " + a + " and " + b + "...");
return a * b;
}
}
public static void main(String[] args) {
MathTools mathTools = new MathTools();
ToolRegistry toolRegistry = ToolRegistry.builder()
.tools(mathTools)
.build();
AIAgent<String, String> mathAgentWithTools = AIAgent.builder()
.promptExecutor(SimpleLLMExecutorsKt.simpleOllamaAIExecutor("http://localhost:11434"))
.llmModel(OllamaModels.Meta.LLAMA_3_2)
.toolRegistry(toolRegistry)
.functionalStrategy("mathWithTools", (AIAgentFunctionalContext context, String input) -> {
// 將使用者輸入傳送至 LLM
List<Message.Response> responses = context.requestLLMMultiple(input);
// 僅在 LLM 要求工具時進行迴圈
while (context.containsToolCalls(responses)) {
// 從回應中提取工具呼叫
List<MessagePart.Tool.Call> pendingCalls = context.extractToolCalls(responses);
// 執行工具並傳回結果
List<ReceivedToolResult> results = context.executeMultipleTools(pendingCalls, false);
// 將工具結果傳送回 LLM
responses = context.sendMultipleToolResults(results);
}
// 從回應中提取並傳回助理訊息內容
Message.Response finalResponse = responses.get(0);
if (finalResponse instanceof Message.Assistant) {
return ((Message.Assistant) finalResponse).getContent();
}
return "";
})
.build();
String result = mathAgentWithTools.run("Multiply 3 by 4, then multiply the result by 5.");
System.out.println(result);
}代理可以產生以下輸出:
Multiplying 3 and 4...
Multiplying 12 and 5...
The result of multiplying 3 by 4 is 12. Multiplying 12 by 5 gives us a final answer of 60.後續步驟
- 了解如何建立 圖形化代理 (graph-based agents)
