diff --git a/docs/_toc.yml b/docs/_toc.yml index d175b6c92..7278907ca 100644 --- a/docs/_toc.yml +++ b/docs/_toc.yml @@ -54,8 +54,8 @@ parts: title: Multimodal - file: en/task/structured-output title: Structured Output - - file: en/task/studio - title: Studio + - file: en/task/observability + title: Observability & Studio - file: en/task/agui title: AG-UI Protocol - file: en/task/a2a @@ -129,8 +129,8 @@ parts: title: 多模态 - file: zh/task/structured-output title: 结构化输出 - - file: zh/task/studio - title: Studio + - file: zh/task/observability + title: 可观测与调试 - file: zh/task/agui title: AG-UI 协议 - file: zh/task/a2a diff --git a/docs/en/task/studio.md b/docs/en/task/observability.md similarity index 58% rename from docs/en/task/studio.md rename to docs/en/task/observability.md index 09664b541..ed018b132 100644 --- a/docs/en/task/studio.md +++ b/docs/en/task/observability.md @@ -1,10 +1,19 @@ -# Studio (Visual Debugging) +# Observability & Studio + +AgentScope Java provides multiple mechanisms for observing and debugging agent execution: + +- **Studio (Visual Debugging)**: Real-time visualization and interactive debugging through a Web UI +- **OpenTelemetry Tracing**: Export trace data to external observability platforms (e.g., Langfuse, Jaeger) via the OTLP protocol + +--- + +## Studio (Visual Debugging) Studio provides a Web interface for real-time visualization of Agent execution processes, supporting interactive debugging and message tracing. --- -## Core Features +### Core Features - **Real-time Visualization**: Web interface displays Agent reasoning and execution processes - **Interactive Input**: Interact with Agent through Web UI @@ -13,9 +22,9 @@ Studio provides a Web interface for real-time visualization of Agent execution p --- -## Quick Start +### Quick Start -### 1. Start Studio Server +#### 1. Start Studio Server Start from source code ```bash @@ -34,7 +43,7 @@ Studio will run at http://localhost:5173 ![Studio Server Page](../../imgs/studioServer.png) -### 2. Java Application Integration +#### 2. Java Application Integration ```java import io.agentscope.core.studio.StudioManager; @@ -63,13 +72,13 @@ agent.call(msg).block(); StudioManager.shutdown(); ``` -### 3. View Trace Information in AgentScope Studio +#### 3. View Trace Information in AgentScope Studio ![Trace Information](../../imgs/studioServer-trace.png) -## StudioUserAgent +### StudioUserAgent Receive user input through Web UI. @@ -90,18 +99,18 @@ You can find the Project in Studio's Projects and debug through the WebUI ![Studio Server Web UI Input Interface](../../imgs/studioServer-webUI.png) -### Conversation Loop +#### Conversation Loop ```java Msg msg = null; while (true) { // Get user input from Web UI msg = user.call(msg).block(); - + if (msg == null || "exit".equalsIgnoreCase(msg.getTextContent())) { break; } - + // Agent processes msg = agent.call(msg).block(); } @@ -109,7 +118,7 @@ while (true) { --- -## Complete Example +### Complete Example ```java package io.agentscope.examples; @@ -122,12 +131,12 @@ import io.agentscope.core.studio.StudioMessageHook; import io.agentscope.core.studio.StudioUserAgent; public class StudioExample { - + public static void main(String[] args) throws Exception { String apiKey = System.getenv("DASHSCOPE_API_KEY"); - + System.out.println("Connecting to Studio at http://localhost:3000..."); - + // Initialize Studio StudioManager.init() .studioUrl("http://localhost:3000") @@ -136,7 +145,7 @@ public class StudioExample { .initialize() .block(); System.out.println("Connected to Studio\n"); - + try { // Create Agent (with Studio Hook) ReActAgent agent = ReActAgent.builder() @@ -148,39 +157,39 @@ public class StudioExample { .build()) .hook(new StudioMessageHook(StudioManager.getClient())) .build(); - + // Create user Agent StudioUserAgent user = StudioUserAgent.builder() .name("User") .studioClient(StudioManager.getClient()) .webSocketClient(StudioManager.getWebSocketClient()) .build(); - + // Conversation loop System.out.println("Starting conversation (type 'exit' to quit)"); System.out.println("Open http://localhost:3000 to interact\n"); - + Msg msg = null; int turn = 1; while (true) { System.out.println("[Turn " + turn + "] Waiting for user input..."); msg = user.call(msg).block(); - + if (msg == null || "exit".equalsIgnoreCase(msg.getTextContent())) { System.out.println("\nConversation ended"); break; } - + System.out.println("[Turn " + turn + "] User: " + msg.getTextContent()); msg = agent.call(msg).block(); - + if (msg != null) { - System.out.println("[Turn " + turn + "] Agent: " + System.out.println("[Turn " + turn + "] Agent: " + msg.getTextContent() + "\n"); } turn++; } - + } finally { System.out.println("\nShutting down..."); StudioManager.shutdown(); @@ -192,9 +201,9 @@ public class StudioExample { --- -## Advanced Usage +### Advanced Usage -### Manual Message Pushing +#### Manual Message Pushing ```java StudioClient client = StudioManager.getClient(); @@ -208,7 +217,7 @@ client.pushMessage(customMsg).block(); ``` -### Multi-Agent Visualization +#### Multi-Agent Visualization ```java // Add Hook to each Agent @@ -224,11 +233,98 @@ ReActAgent agent2 = ReActAgent.builder() // Studio will display messages from both Agents separately ``` + +--- + +## OpenTelemetry Tracing + +AgentScope Java integrates with OpenTelemetry to provide distributed tracing for agent execution. You can export traces to any platform that supports the OTLP protocol, such as Langfuse. + +### Quick Start + +Use `TelemetryTracer` and register it via `TracerRegistry` to enable automatic tracing for all agent calls, model calls, and tool executions: + +```java +import io.agentscope.core.tracing.TracerRegistry; +import io.agentscope.core.tracing.telemetry.TelemetryTracer; + +// Register a TelemetryTracer with an OTLP endpoint +TracerRegistry.register( + TelemetryTracer.builder() + .endpoint("https://your-otlp-endpoint/v1/traces") + .build() +); + +// After registration, all agent activities are automatically traced +ReActAgent agent = ReActAgent.builder() + .name("Assistant") + .model(model) + .build(); +``` + +Once registered, the tracer automatically captures: +- **Agent calls** — span for each `agent.call()` +- **Model calls** — span for each LLM invocation +- **Tool executions** — span for each tool call +- **Formatting** — span for message formatting + +No additional code is needed — tracing is applied globally. + +### Configuration + +`TelemetryTracer` supports the following builder options: + +| Option | Description | Default | +|----------------|---------------------------------------------------|---------| +| `endpoint` | OTLP endpoint URL | — | +| `addHeader` | Add a single HTTP header (e.g., for auth) | — | +| `headers` | Set all HTTP headers as a `Map` | — | +| `enabled` | Enable or disable tracing | `true` | +| `tracer` | Use a custom OpenTelemetry `Tracer` instance | — | + +### Integration with Langfuse + +[Langfuse](https://langfuse.com/) is an open-source observability platform that supports the OpenTelemetry protocol. You can send traces to Langfuse Cloud or a self-hosted instance. + +```java +import io.agentscope.core.tracing.TracerRegistry; +import io.agentscope.core.tracing.telemetry.TelemetryTracer; +import java.util.Base64; + +// Encode your Langfuse API key as Base64 +String publicKey = "pk-lf-xxxxxxxx"; +String secretKey = "sk-lf-xxxxxxxx"; +String encoded = Base64.getEncoder().encodeToString((publicKey + ":" + secretKey).getBytes()); + +TracerRegistry.register( + TelemetryTracer.builder() + .endpoint("https://cloud.langfuse.com/api/public/otel/v1/traces") + .addHeader("Authorization", "Basic " + encoded) + .addHeader("x-langfuse-ingestion-version", "4") + .build() +); +``` + +> **Note**: The `x-langfuse-ingestion-version` header is required by Langfuse when using the OTLP endpoint. Make sure to include it. + +After running your agent, you can view the traces in the Langfuse dashboard, including the full call chain, latency, and input/output of each step. + +### Integration with Other OTLP Backends + +Any platform that supports the OTLP protocol can be used. For example, to send traces to a local Jaeger instance: + +```java +TracerRegistry.register( + TelemetryTracer.builder() + .endpoint("http://localhost:4317") + .build() +); +``` + --- ## More Resources -- **Complete Example**: [StudioExample.java](https://github.com/agentscope-ai/agentscope-java/blob/main/agentscope-examples/advanced/src/main/java/io/agentscope/examples/advanced/StudioExample.java) +- **Studio Example**: [StudioExample.java](https://github.com/agentscope-ai/agentscope-java/blob/main/agentscope-examples/advanced/src/main/java/io/agentscope/examples/advanced/StudioExample.java) - **Studio Repository**: https://github.com/agentscope-ai/agentscope-studio - **Hook Documentation**: [hook.md](./hook.md) - diff --git a/docs/zh/task/studio.md b/docs/zh/task/observability.md similarity index 58% rename from docs/zh/task/studio.md rename to docs/zh/task/observability.md index b5034b677..3f3cdad47 100644 --- a/docs/zh/task/studio.md +++ b/docs/zh/task/observability.md @@ -1,10 +1,19 @@ -# Studio(可视化调试) +# 可观测与调试 + +AgentScope Java 提供了多种机制来观测和调试智能体的执行过程: + +- **Studio(可视化调试)**:通过 Web 界面实时可视化和交互式调试 +- **OpenTelemetry 链路追踪**:通过 OTLP 协议将 Trace 数据导出到外部可观测性平台(如 Langfuse、Jaeger) + +--- + +## Studio(可视化调试) Studio 提供 Web 界面实时可视化 Agent 执行过程,支持交互式调试和消息追踪。 --- -## 核心特性 +### 核心特性 - **实时可视化**:Web 界面展示 Agent 推理和执行过程 - **交互式输入**:通过 Web UI 与 Agent 对话 @@ -13,9 +22,9 @@ Studio 提供 Web 界面实时可视化 Agent 执行过程,支持交互式调 --- -## 快速开始 +### 快速开始 -### 1. 启动 Studio Server +#### 1. 启动 Studio Server 从源码启动 ```bash @@ -33,7 +42,7 @@ Studio 将运行在 http://localhost:5173 ![Studio Server 页面](../../imgs/studioServer.png) -### 2. Java 应用集成 +#### 2. Java 应用集成 ```java import io.agentscope.core.studio.StudioManager; @@ -62,13 +71,13 @@ agent.call(msg).block(); StudioManager.shutdown(); ``` -### 3. 在AgentScope Studio 查看Trace信息 +#### 3. 在AgentScope Studio 查看Trace信息 ![Trace信息](../../imgs/studioServer-trace.png) -## StudioUserAgent +### StudioUserAgent 通过 Web UI 接收用户输入。 @@ -88,18 +97,18 @@ Msg userInput = user.call(null).block(); 您可以在Studio中的Projects中找到该Project,通过WebUI的方式进行调试 ![Studio Server Web UI 输入界面](../../imgs/studioServer-webUI.png) -### 对话循环 +#### 对话循环 ```java Msg msg = null; while (true) { // 从 Web UI 获取用户输入 msg = user.call(msg).block(); - + if (msg == null || "exit".equalsIgnoreCase(msg.getTextContent())) { break; } - + // Agent 处理 msg = agent.call(msg).block(); } @@ -107,7 +116,7 @@ while (true) { --- -## 完整示例 +### 完整示例 ```java package io.agentscope.examples; @@ -120,12 +129,12 @@ import io.agentscope.core.studio.StudioMessageHook; import io.agentscope.core.studio.StudioUserAgent; public class StudioExample { - + public static void main(String[] args) throws Exception { String apiKey = System.getenv("DASHSCOPE_API_KEY"); - + System.out.println("Connecting to Studio at http://localhost:3000..."); - + // 初始化 Studio StudioManager.init() .studioUrl("http://localhost:3000") @@ -134,7 +143,7 @@ public class StudioExample { .initialize() .block(); System.out.println("Connected to Studio\n"); - + try { // 创建 Agent(带 Studio Hook) ReActAgent agent = ReActAgent.builder() @@ -146,39 +155,39 @@ public class StudioExample { .build()) .hook(new StudioMessageHook(StudioManager.getClient())) .build(); - + // 创建用户 Agent StudioUserAgent user = StudioUserAgent.builder() .name("User") .studioClient(StudioManager.getClient()) .webSocketClient(StudioManager.getWebSocketClient()) .build(); - + // 对话循环 System.out.println("Starting conversation (type 'exit' to quit)"); System.out.println("Open http://localhost:3000 to interact\n"); - + Msg msg = null; int turn = 1; while (true) { System.out.println("[Turn " + turn + "] Waiting for user input..."); msg = user.call(msg).block(); - + if (msg == null || "exit".equalsIgnoreCase(msg.getTextContent())) { System.out.println("\nConversation ended"); break; } - + System.out.println("[Turn " + turn + "] User: " + msg.getTextContent()); msg = agent.call(msg).block(); - + if (msg != null) { - System.out.println("[Turn " + turn + "] Agent: " + System.out.println("[Turn " + turn + "] Agent: " + msg.getTextContent() + "\n"); } turn++; } - + } finally { System.out.println("\nShutting down..."); StudioManager.shutdown(); @@ -190,9 +199,9 @@ public class StudioExample { --- -## 高级用法 +### 高级用法 -### 手动推送消息 +#### 手动推送消息 ```java StudioClient client = StudioManager.getClient(); @@ -206,7 +215,7 @@ client.pushMessage(customMsg).block(); ``` -### 多 Agent 可视化 +#### 多 Agent 可视化 ```java // 为每个 Agent 添加 Hook @@ -222,10 +231,98 @@ ReActAgent agent2 = ReActAgent.builder() // Studio 将分别显示两个 Agent 的消息 ``` + +--- + +## OpenTelemetry 链路追踪 + +AgentScope Java 集成了 OpenTelemetry,提供分布式链路追踪能力。你可以将 Trace 导出到任何支持 OTLP 协议的平台,如 Langfuse。 + +### 快速开始 + +使用 `TelemetryTracer` 并通过 `TracerRegistry` 注册,即可自动追踪所有智能体调用、模型调用和工具执行: + +```java +import io.agentscope.core.tracing.TracerRegistry; +import io.agentscope.core.tracing.telemetry.TelemetryTracer; + +// 注册 TelemetryTracer,配置 OTLP 端点 +TracerRegistry.register( + TelemetryTracer.builder() + .endpoint("https://your-otlp-endpoint/v1/traces") + .build() +); + +// 注册后,所有智能体活动将自动被追踪 +ReActAgent agent = ReActAgent.builder() + .name("Assistant") + .model(model) + .build(); +``` + +注册后,追踪器会自动捕获: +- **智能体调用** — 每次 `agent.call()` 生成一个 Span +- **模型调用** — 每次 LLM 调用生成一个 Span +- **工具执行** — 每次工具调用生成一个 Span +- **格式化** — 消息格式化生成一个 Span + +无需额外代码 — 追踪在全局范围内自动生效。 + +### 配置选项 + +`TelemetryTracer` 支持以下 Builder 选项: + +| 选项 | 描述 | 默认值 | +|---------------|-------------------------------------------|----------| +| `endpoint` | OTLP 端点 URL | — | +| `addHeader` | 添加单个 HTTP 请求头(如用于认证) | — | +| `headers` | 以 `Map` 形式设置所有 HTTP 请求头 | — | +| `enabled` | 启用或禁用追踪 | `true` | +| `tracer` | 使用自定义的 OpenTelemetry `Tracer` 实例 | — | + +### 接入 Langfuse + +[Langfuse](https://langfuse.com/) 是一个开源的可观测性平台,支持 OpenTelemetry 协议。你可以将 Trace 发送到 Langfuse Cloud 或自部署的实例。 + +```java +import io.agentscope.core.tracing.TracerRegistry; +import io.agentscope.core.tracing.telemetry.TelemetryTracer; +import java.util.Base64; + +// 将 Langfuse API Key 编码为 Base64 +String publicKey = "pk-lf-xxxxxxxx"; +String secretKey = "sk-lf-xxxxxxxx"; +String encoded = Base64.getEncoder().encodeToString((publicKey + ":" + secretKey).getBytes()); + +TracerRegistry.register( + TelemetryTracer.builder() + .endpoint("https://cloud.langfuse.com/api/public/otel/v1/traces") + .addHeader("Authorization", "Basic " + encoded) + .addHeader("x-langfuse-ingestion-version", "4") + .build() +); +``` + +> **注意**:使用 Langfuse 的 OTLP 端点时,`x-langfuse-ingestion-version` 请求头是必需的,请确保包含此头部。 + +运行智能体后,你可以在 Langfuse 控制台中查看 Trace,包括完整的调用链、延迟以及每一步的输入/输出。 + +### 接入其他 OTLP 后端 + +任何支持 OTLP 协议的平台都可以使用。例如,将 Trace 发送到本地 Jaeger 实例: + +```java +TracerRegistry.register( + TelemetryTracer.builder() + .endpoint("http://localhost:4317") + .build() +); +``` + --- ## 更多资源 -- **完整示例**: [StudioExample.java](https://github.com/agentscope-ai/agentscope-java/blob/main/agentscope-examples/advanced/src/main/java/io/agentscope/examples/advanced/StudioExample.java) +- **Studio 完整示例**: [StudioExample.java](https://github.com/agentscope-ai/agentscope-java/blob/main/agentscope-examples/advanced/src/main/java/io/agentscope/examples/advanced/StudioExample.java) - **Studio 仓库**: https://github.com/agentscope-ai/agentscope-studio - **Hook 文档**: [hook.md](./hook.md)