> ## Documentation Index
> Fetch the complete documentation index at: https://java.agentscope.io/llms.txt
> Use this file to discover all available pages before exploring further.

# 可观测与调试

AgentScope Java 提供了多种机制来观测和调试智能体的执行过程：

* **Studio（可视化调试）**：通过 Web 界面实时可视化和交互式调试
* **OpenTelemetry 链路追踪**：通过 OTLP 协议将 Trace 数据导出到外部可观测性平台（如 Langfuse、Jaeger）

***

## Studio（可视化调试）

Studio 提供 Web 界面实时可视化 Agent 执行过程，支持交互式调试和消息追踪。

***

### 核心特性

* **实时可视化**：Web 界面展示 Agent 推理和执行过程
* **交互式输入**：通过 Web UI 与 Agent 对话
* **消息追踪**：查看完整的消息流和Trace
* **多 Run 管理**：支持多个实验运行的组织和比较

***

### 快速开始

#### 1. 启动 Studio Server

从源码启动

```bash theme={null}
git clone https://github.com/agentscope-ai/agentscope-studio
cd agentscope-studio
npm install
npm run dev
```

npm安装

```bash theme={null}
npm install -g @agentscope/studio  # or npm install @agentscope/studio
as_studio
```

Studio 将运行在 `http://localhost:5173`（前端开发服务器）

<img src="https://mintcdn.com/agent-scope/A3NLCDIERICd7rWS/imgs/studioServer.png?fit=max&auto=format&n=A3NLCDIERICd7rWS&q=85&s=80593866840b666e3e16e9fe5e302b19" alt="Studio Server 页面" width="2924" height="1710" data-path="imgs/studioServer.png" />

#### 2. Java 应用集成

```java theme={null}
import io.agentscope.core.studio.StudioManager;
import io.agentscope.core.studio.StudioMessageHook;
import io.agentscope.core.studio.StudioUserAgent;

// 初始化 Studio 连接
StudioManager.init()
    .studioUrl("http://localhost:3000")
    .project("MyProject")
    .runName("demo_" + System.currentTimeMillis())
    .initialize()
    .block();

// 创建带 Hook 的 Agent
ReActAgent agent = ReActAgent.builder()
    .name("Assistant")
    .model(model)
    .hook(new StudioMessageHook(StudioManager.getClient()))
    .build();

// Agent 消息自动发送到 Studio
agent.call(msg).block();

// 清理资源
StudioManager.shutdown();
```

#### 3. 在AgentScope Studio 查看Trace信息

<img src="https://mintcdn.com/agent-scope/A3NLCDIERICd7rWS/imgs/studioServer-trace.png?fit=max&auto=format&n=A3NLCDIERICd7rWS&q=85&s=5e184f00184d2a2db3c50917410e15ec" alt="Trace信息" width="2916" height="1702" data-path="imgs/studioServer-trace.png" />

### StudioUserAgent

通过 Web UI 接收用户输入。

```java theme={null}
import io.agentscope.core.studio.StudioUserAgent;

// 创建用户 Agent
StudioUserAgent user = StudioUserAgent.builder()
    .name("User")
    .studioClient(StudioManager.getClient())
    .webSocketClient(StudioManager.getWebSocketClient())
    .build();

// 等待 Web UI 用户输入
Msg userInput = user.call(null).block();
```

您可以在Studio中的Projects中找到该Project，通过WebUI的方式进行调试

<img src="https://mintcdn.com/agent-scope/A3NLCDIERICd7rWS/imgs/studioServer-webUI.png?fit=max&auto=format&n=A3NLCDIERICd7rWS&q=85&s=31f16b40a382f4d8a6a781fbc677a43d" alt="Studio Server Web UI 输入界面" width="2914" height="1710" data-path="imgs/studioServer-webUI.png" />

#### 对话循环

```java theme={null}
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();
}
```

***

### 完整示例

```java theme={null}
package io.agentscope.examples;

import io.agentscope.core.ReActAgent;
import io.agentscope.core.message.Msg;
import io.agentscope.extensions.model.dashscope.DashScopeChatModel;
import io.agentscope.core.studio.StudioManager;
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")
            .project("JavaExamples")
            .runName("studio_demo_" + System.currentTimeMillis())
            .initialize()
            .block();
        System.out.println("Connected to Studio\n");

        try {
            // 创建 Agent（带 Studio Hook）
            ReActAgent agent = ReActAgent.builder()
                .name("Assistant")
                .sysPrompt("You are a helpful AI assistant.")
                .model(DashScopeChatModel.builder()
                    .apiKey(apiKey)
                    .modelName("qwen3-max")
                    .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: "
                        + msg.getTextContent() + "\n");
                }
                turn++;
            }

        } finally {
            System.out.println("\nShutting down...");
            StudioManager.shutdown();
            System.out.println("Done\n");
        }
    }
}
```

***

### 高级用法

#### 手动推送消息

```java theme={null}
StudioClient client = StudioManager.getClient();

Msg customMsg = Msg.builder()
    .role(MsgRole.ASSISTANT)
    .content(TextBlock.builder().text("自定义消息").build())
    .build();

client.pushMessage(customMsg).block();
```

#### 多 Agent 可视化

```java theme={null}
// 为每个 Agent 添加 Hook
ReActAgent agent1 = ReActAgent.builder()
    .name("Agent1")
    .hook(new StudioMessageHook(client))
    .build();

ReActAgent agent2 = ReActAgent.builder()
    .name("Agent2")
    .hook(new StudioMessageHook(client))
    .build();

// Studio 将分别显示两个 Agent 的消息
```

***

## OpenTelemetry 链路追踪

AgentScope Java 集成了 OpenTelemetry，提供分布式链路追踪能力。你可以将 Trace 导出到任何支持 OTLP 协议的平台，如 Langfuse。

### 快速开始

使用 `TelemetryTracer` 并通过 `TracerRegistry` 注册，即可自动追踪所有智能体调用、模型调用和工具执行：

```java theme={null}
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 theme={null}
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 theme={null}
TracerRegistry.register(
    TelemetryTracer.builder()
        .endpoint("http://localhost:4317")
        .build()
);
```

***

## 更多资源

* **Studio 完整示例**: [StudioExample.java](https://github.com/agentscope-ai/agentscope-java/blob/main/agentscope-examples/documentation/advanced/src/main/java/io/agentscope/examples/advanced/StudioExample.java)
* **Studio 仓库**: [https://github.com/agentscope-ai/agentscope-studio](https://github.com/agentscope-ai/agentscope-studio)
* **Hook 文档**: [hook.md](/v1/zh/docs/task/hook)
