Skip to content

Commit 1633b4a

Browse files
committed
JBRes-7677: langfuse example for mcp metrics in opentelemetry
1 parent f8341eb commit 1633b4a

File tree

5 files changed

+80
-7
lines changed

5 files changed

+80
-7
lines changed

agents/agents-features/agents-features-opentelemetry/src/jvmMain/kotlin/ai/koog/agents/features/opentelemetry/integration/langfuse/Langfuse.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ public fun OpenTelemetryConfig.addLangfuseExporter(
3333
timeout: Duration = 10.seconds,
3434
traceAttributes: List<CustomAttribute> = emptyList()
3535
) {
36-
val url = langfuseUrl ?: System.getenv()["LANGFUSE_HOST"] ?: "https://cloud.langfuse.com"
36+
val url = langfuseUrl
37+
?: System.getenv()["LANGFUSE_HOST"]
38+
?: System.getenv()["LANGFUSE_BASE_URL"]
39+
?: "https://cloud.langfuse.com"
3740

3841
logger.debug { "Configured endpoint for Langfuse telemetry: $url" }
3942

examples/simple-examples/build.gradle.kts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ plugins {
66

77
dependencies {
88
implementation(platform(libs.kotlin.bom))
9+
implementation(libs.mcp.server)
10+
implementation(libs.mcp.client)
911

1012
/*
1113
Koog dependencies from composite build.
@@ -14,6 +16,8 @@ dependencies {
1416
//noinspection UseTomlInstead
1517
implementation("ai.koog:koog-agents")
1618
//noinspection UseTomlInstead
19+
implementation("ai.koog:agents-mcp-server")
20+
//noinspection UseTomlInstead
1721
implementation("ai.koog:koog-ktor")
1822
//noinspection UseTomlInstead
1923
implementation("ai.koog:agents-features-sql")
@@ -137,3 +141,8 @@ registerRunExampleTask("runExampleAdvancedJokeAgentClient", "ai.koog.agents.exam
137141
ACP examples
138142
*/
139143
registerRunExampleTask("runExampleAcpApp", "ai.koog.agents.example.acp.KoogAcpAppKt")
144+
145+
/*
146+
Langfuse examples
147+
*/
148+
registerRunExampleTask("runExampleLangfuseApp", "ai.koog.agents.example.features.langfuse.LangfuseKt")

examples/simple-examples/env.template.properties

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,25 @@
44
# Or, if you want to integrate with 1password, you can put reference, e.g. op://foo/bar:
55
# FOO=op://foo/bar
66

7-
OPENAI_API_KEY=
7+
# https://platform.openai.com/api-keys
8+
OPENAI_API_KEY=sk-proj-...
89

910
ANTHROPIC_API_KEY=
1011

1112
AWS_ACCESS_KEY_ID=
1213
AWS_SECRET_ACCESS_KEY=
1314
AWS_BEDROCK_GUARDRAIL_ID=
1415
AWS_BEDROCK_GUARDRAIL_VERSION=
16+
17+
# Langfuse credentials https://langfuse.com/faq/all/where-are-langfuse-api-keys
18+
# To run locally, first install Langfuse:
19+
#
20+
# git clone https://github.com/langfuse/langfuse.git
21+
# cd langfuse
22+
# docker compose up
23+
#
24+
# then open http://localhost:3000
25+
#
26+
LANGFUSE_SECRET_KEY=sk-lf-...
27+
LANGFUSE_PUBLIC_KEY=pk-lf-...
28+
LANGFUSE_HOST=http://localhost:3000

examples/simple-examples/gradle/libs.versions.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ logback = "1.5.13"
88
mockk = "1.13.8"
99
opentelemetry = "1.51.0"
1010
oshai-logging = "7.0.7"
11+
mcp = "0.8.1"
1112

1213
[libraries]
1314
kotlin-bom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "kotlin" }
@@ -23,6 +24,8 @@ opentelemetry-exporter-logging = { module = "io.opentelemetry:opentelemetry-expo
2324
opentelemetry-exporter-otlp = { module = "io.opentelemetry:opentelemetry-exporter-otlp" }
2425
opentelemetry-sdk = { module = "io.opentelemetry:opentelemetry-sdk" }
2526
oshai-kotlin-logging = { module = "io.github.oshai:kotlin-logging", version.ref = "oshai-logging" }
27+
mcp-client = { module = "io.modelcontextprotocol:kotlin-sdk-client", version.ref = "mcp" }
28+
mcp-server = { module = "io.modelcontextprotocol:kotlin-sdk-server", version.ref = "mcp" }
2629

2730
[plugins]
2831
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
11
package ai.koog.agents.example.features.langfuse
22

33
import ai.koog.agents.core.agent.AIAgent
4+
import ai.koog.agents.core.tools.ToolRegistry
5+
import ai.koog.agents.core.tools.annotations.LLMDescription
6+
import ai.koog.agents.core.tools.annotations.Tool
7+
import ai.koog.agents.core.tools.reflect.tool
48
import ai.koog.agents.example.ApiKeyService
59
import ai.koog.agents.features.opentelemetry.feature.OpenTelemetry
610
import ai.koog.agents.features.opentelemetry.integration.langfuse.addLangfuseExporter
11+
import ai.koog.agents.mcp.McpToolRegistryProvider
12+
import ai.koog.agents.mcp.server.startSseMcpServer
713
import ai.koog.prompt.executor.clients.openai.OpenAIModels
814
import ai.koog.prompt.executor.llms.all.simpleOpenAIExecutor
15+
import io.ktor.server.cio.*
916
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter
17+
import kotlinx.coroutines.delay
18+
import kotlin.time.Duration.Companion.seconds
1019

1120
/**
1221
* Example of Koog agents tracing to [Langfuse](https://langfuse.com/)
@@ -18,15 +27,22 @@ import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter
1827
* 1. Set up a Langfuse project and credentials as described [here](https://langfuse.com/docs/get-started#create-new-project-in-langfuse)
1928
* 2. Get Langfuse credentials as described [here](https://langfuse.com/faq/all/where-are-langfuse-api-keys)
2029
* 3. Set `LANGFUSE_HOST`, `LANGFUSE_PUBLIC_KEY`, and `LANGFUSE_SECRET_KEY` environment variables
30+
* 4. Set `OPENAI_API_KEY` from [here](https://platform.openai.com/account/api-keys)
2131
*
2232
* @see <a href="https://langfuse.com/docs/opentelemetry/get-started#opentelemetry-endpoint">Langfuse OpenTelemetry Docs</a>
2333
*/
2434
suspend fun main() {
25-
simpleOpenAIExecutor(ApiKeyService.openAIApiKey).use { executor ->
35+
val server = startSseMcpServer(CIO, port = 30001, host = "localhost", ToolRegistry {
36+
tool(::applyArithmetic)
37+
})
38+
delay(1.seconds)
39+
try {
40+
val tools = McpToolRegistryProvider.fromSseUrl("http://localhost:30001")
2641
val agent = AIAgent(
27-
promptExecutor = executor,
28-
llmModel = OpenAIModels.Chat.GPT4oMini,
29-
systemPrompt = "You are a code assistant. Provide concise code examples."
42+
promptExecutor = simpleOpenAIExecutor(ApiKeyService.openAIApiKey),
43+
llmModel = OpenAIModels.Chat.GPT4_1Mini,
44+
systemPrompt = "You are a code assistant. Provide concise code examples.",
45+
toolRegistry = ToolRegistry { tool(::sin); tool(::cos) } + tools
3046
) {
3147
install(OpenTelemetry) {
3248
addLangfuseExporter()
@@ -35,8 +51,36 @@ suspend fun main() {
3551

3652
println("Running agent with Langfuse tracing")
3753

38-
val result = agent.run("Tell me a joke about programming")
54+
val result = agent.run("Compute (sin(1) + cos(2)) * 69 using available tools")
3955

4056
println("Result: $result\nSee traces on the Langfuse instance")
57+
} finally {
58+
server.close()
4159
}
4260
}
61+
62+
@Tool
63+
@LLMDescription("Calculates the result of an arithmetic expression")
64+
fun applyArithmetic(
65+
@LLMDescription("Arithmetic operation: +-*/") op: String,
66+
@LLMDescription("First operand") a: Double,
67+
@LLMDescription("Second operand") b: Double
68+
): Double = when (op) {
69+
"+" -> a + b
70+
"-" -> a - b
71+
"*" -> a * b
72+
"/" -> a / b
73+
else -> throw IllegalArgumentException("Unsupported operation: $op")
74+
}
75+
76+
@Tool
77+
@LLMDescription("sin")
78+
fun sin(
79+
@LLMDescription("Operand") x: Double
80+
): Double = kotlin.math.sin(x)
81+
82+
@Tool
83+
@LLMDescription("cos")
84+
fun cos(
85+
@LLMDescription("Operand") x: Double
86+
): Double = kotlin.math.cos(x)

0 commit comments

Comments
 (0)