# 快速接入

# 简介

该 SDK 为 **协同服务SDK**（以下简称 SDK）， SDK 提供了 **协同工具注册** 和 **触发 Michael** 两种能力。

为了快速让集成方融入 EdgeOS 生态，为两种能力提供了以下两种 API：

1.  **Tools API：**该 API 提供了 `tools` 注册和执行的能力。`Michael`在运行期间将自主调用使用通过该 API 注册的 `tools`。
    
2.  **Michael** **API**：该 API 提供了触发`Michael`执行的能力。并提供了回调接收响应。
    

根据在 EdgeOS 中的身份选择使用哪种 API：

*   **业务 APP 作为用户交互入口**：则使用`**Michael API**`，向 Michael 发送命令，并接收结果。
    
*   **仅作为能力提供者**：用户不直接和您提供的 APP 做交互，则使用`**Tools API**`，可以把能力注册成 `tools`，`Michael` 将自主调用该能力。
    
*   如果业务 APP 既作为用户交互入口，又提供能力给 `Michael` 调用。那么两种 API 都需要集成。
    

---

# 环境准备

在开始接入 SDK 之前，请确保已准备好以下环境：

| **组件** | **版本** |
| --- | --- |
| Android Gradle Plugin | 8.9.1+ |
| Kotlin | 2.0.21 |
| Gradle | 8.11.1+ |
| KSP | 2.0.21-1.0.28 |
| Java | 17 |

## 依赖引入

1.  **配置 maven 仓库**
    

在项目根目录的 `settings.gradle.kts` 中添加：

```gradle
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        // 添加 SDK 仓库（根据实际情况配置）
        maven { url = uri("http://10.10.92.38:8081/repository/maven-releases")
                isAllowInsecureProtocol = true  
             }
        // 或使用本地 Maven
        mavenLocal()
    }
}
```

2.  **添加依赖项**
    
    在 APP 模块的 `build.gradle.kts` 中：
    
    ```json
    dependencies {
        // MCP SDK - APP 端
        implementation("com.xctech.collaboration:collaboration-sdk:1.0.0")
    }
    ```
    
3.  **同步项目**
    

点击 Android Studio 的 `Sync Now` 按钮同步 Gradle。

---

# 第一部分：使用 Michael API

业务 APP 如果作为用户交互入口，可以接入SDK 发送命令给 Michael 并接收结果。

##  初始化

### 在 Application 中初始化

创建或修改你的 Application 类：

```kotlin
import android.app.Application
import android.util.Log
import com.xctech.collaboration.sdk.CollaborationSDK
import com.xctech.collaboration.core.SdkInitResult

class MyApplication : Application() {

    companion object {
        // SDK 实例（初始化成功后可用）
        var collaborationSDK: CollaborationSDK? = null
            private set
    }

    override fun onCreate() {
        super.onCreate()
        initCollaborationSDK()
    }

    private fun initCollaborationSDK() {
        // 使用 init() 方法初始化，返回 SdkInitResult（不会抛异常）
        val result = CollaborationSDK.init(
            context = this,
            name = "MyApp",      // 你的 APP 名称
            version = "1.0.0"    // 你的 APP 版本
        )

        when (result) {
            is SdkInitResult.Success -> {
                collaborationSDK = result.sdk
                Log.i("MyApp", "SDK 初始化成功")
            }
            is SdkInitResult.Failure -> {
                Log.e("MyApp", "SDK 初始化失败: ${result.error.message}")
                // 可以选择稍后重试或提示用户
            }
        }
    }
}
```

### 在 AndroidManifest.xml 中注册

```xml
<application
    android:name=".MyApplication"
    ... >
    <!-- 其他配置 -->
</application>
```

---

## 触发 Michael 执行

Michael 具备 `Agent` 模块和 `runtime` 模块

*   `runtime`：一种工作流策略的实现，如果您的业务需要按照严格的流程执行，您应该选择 `runtime` 模块
    
*   `Agent`：一种 Agent 策略的实现，如果您的业务需要让 AI 作为决策中枢，AI 自主选择工具完成您的任务目标。您应该选择 `Agent` 模块
    

### 2.1 运行 Agent 模块

#### 基本用法

```kotlin
import com.xctech.collaboration.core.TaskCallback
import com.xctech.collaboration.core.TaskError
import com.xctech.collaboration.core.TaskConfig
import com.xctech.collaboration.core.CommandResult
import com.xctech.collaboration.spec.TextContent

class MainActivity : AppCompatActivity() {

    private val sdk get() = MyApplication.collaborationSDK

    fun sendCommand(text: String) {
        val sdk = this.sdk
        if (sdk == null) {
            showError("SDK 未初始化")
            return
        }

        // 发送命令
        sdk.command(
            text = text,                              // 命令文本
            config = TaskConfig(timeout = 60_000L),   // 超时配置（可选）
            callback = object : TaskCallback<CommandResult> {

                override fun onStart(taskId: String) {
                    // 任务开始，显示加载状态
                    showLoading("正在处理...")
                }

                override fun onProgress(taskId: String, chunk: CommandResult) {
                    // 收到流式进度更新
                    chunk.content.filterIsInstance<TextContent>().forEach {
                        appendText(it.text)
                    }
                }

                override fun onComplete(taskId: String, result: CommandResult) {
                    // 任务完成
                    hideLoading()
                    showResult(result)
                }

                override fun onError(taskId: String, error: TaskError) {
                    // 发生错误
                    hideLoading()
                    showError("错误: ${error.message}")
                }

                override fun onTimeout(taskId: String) {
                    // 任务超时
                    hideLoading()
                    showError("请求超时，请重试")
                }

                override fun onCancelled(taskId: String) {
                    // 任务被取消
                    hideLoading()
                    showMessage("已取消")
                }
            }
        )
    }
}
```

#### 取消任务

```kotlin
// command() 返回 taskId
val taskId = sdk.command(text, callback = myCallback)

// 稍后可以取消
val cancelled = sdk.cancelTask(taskId)
```

### 2.2 运行 runtime 模块

（暂无开放，敬请期待）

---

## 连接状态监听

```kotlin
import com.xctech.collaboration.sdk.connection.ConnectionManager
import com.xctech.collaboration.sdk.connection.ConnectionState

// 设置连接监听
sdk.setConnectionListener(object : ConnectionManager.ConnectionListener {

    override fun onStateChanged(state: ConnectionState) {
        when (state) {
            is ConnectionState.Connected -> {
                // 已连接
                updateUI("已连接")
            }
            is ConnectionState.Disconnected -> {
                // 已断开
                updateUI("已断开")
            }
            is ConnectionState.Reconnecting -> {
                // 重连中
                updateUI("重连中... 第 ${state.attempt} 次")
            }
            is ConnectionState.Failed -> {
                // 连接失败
                updateUI("连接失败: ${state.error.message}")
            }
        }
    }

    override fun onConnected() {
        Log.i("SDK", "已连接到 Michael")
    }

    override fun onDisconnected(reason: ConnectionManager.DisconnectReason) {
        Log.w("SDK", "与 Michael 断开连接: $reason")
    }

    override fun onReconnecting(attempt: Int, delayMs: Long) {
        Log.i("SDK", "正在重连... 第 $attempt 次")
    }

    override fun onReconnectFailed(error: TaskError) {
        Log.e("SDK", "重连失败: ${error.message}")
    }
})

// 获取当前连接状态
val state = sdk.getConnectionState()

// 手动重连
sdk.reconnect()

// 手动断开
sdk.disconnect()
```

---

## 完整示例

```kotlin
class MainActivity : AppCompatActivity() {

    private val sdk get() = MyApplication.collaborationSDK

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        setupConnectionListener()
        setupUI()
    }

    private fun setupConnectionListener() {
        sdk?.setConnectionListener(object : ConnectionManager.ConnectionListener {
            override fun onConnected() {
                runOnUiThread {
                    statusView.text = "已连接"
                    statusView.setTextColor(Color.GREEN)
                    btnSend.isEnabled = true
                }
            }

            override fun onDisconnected(reason: ConnectionManager.DisconnectReason) {
                runOnUiThread {
                    statusView.text = "已断开: $reason"
                    statusView.setTextColor(Color.RED)
                    btnSend.isEnabled = false
                }
            }

            override fun onReconnecting(attempt: Int, delayMs: Long) {
                runOnUiThread {
                    statusView.text = "重连中... ($attempt)"
                    statusView.setTextColor(Color.YELLOW)
                }
            }
        })
    }

    private fun setupUI() {
        btnSend.setOnClickListener {
            val text = editText.text.toString()
            if (text.isNotBlank()) {
                sendCommand(text)
            }
        }
    }

    private fun sendCommand(text: String) {
        sdk?.command(text, callback = object : TaskCallback<CommandResult> {
            override fun onStart(taskId: String) {
                runOnUiThread {
                    progressBar.visibility = View.VISIBLE
                    resultView.text = ""
                }
            }

            override fun onProgress(taskId: String, chunk: CommandResult) {
                runOnUiThread {
                    chunk.content.filterIsInstance<TextContent>().forEach {
                        resultView.append(it.text)
                    }
                }
            }

            override fun onComplete(taskId: String, result: CommandResult) {
                runOnUiThread {
                    progressBar.visibility = View.GONE
                }
            }

            override fun onError(taskId: String, error: TaskError) {
                runOnUiThread {
                    progressBar.visibility = View.GONE
                    Toast.makeText(this@MainActivity, error.message, Toast.LENGTH_SHORT).show()
                }
            }

            override fun onTimeout(taskId: String) {
                runOnUiThread {
                    progressBar.visibility = View.GONE
                    Toast.makeText(this@MainActivity, "请求超时", Toast.LENGTH_SHORT).show()
                }
            }

            override fun onCancelled(taskId: String) {
                runOnUiThread {
                    progressBar.visibility = View.GONE
                }
            }
        })
    }

    override fun onDestroy() {
        super.onDestroy()
        // 可选：释放 SDK 资源
        // sdk?.release()
    }
}

```

---

## API 参考

### CollaborationSDK

| **方法** | **说明** |
| --- | --- |
| `init(context, name, version, config?)` | 初始化 SDK（静态方法） |
| `getInstance()` | 获取实例（未初始化会抛异常） |
| `getInstanceOrNull()` | 获取实例或 null |
| `isSdkInitialized()` | 检查是否已初始化 |
| `command(text, config?, callback)` | 发送命令 |
| `cancelTask(taskId)` | 取消任务 |
| `getTaskStatus(taskId)` | 获取任务状态 |
| `setConnectionListener(listener)` | 设置连接监听 |
| `getConnectionState()` | 获取当前连接状态 |
| `reconnect()` | 手动重连 |
| `disconnect()` | 断开连接 |
| `release()` | 释放资源 |
| `getClientId()` | 获取客户端 ID |
| `getClientName()` | 获取客户端名称 |
| `getClientVersion()` | 获取客户端版本 |

# 第二部分：使用 Tools API

Tool 是具体的功能提供者，可以通过注解方式快速定义工具。

## 添加依赖

### 配置 Gradle Wrapper

确保 `gradle/wrapper/gradle-wrapper.properties` 中使用正确的 Gradle 版本：

```properties
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
```

### 配置项目级 Gradle 插件

在项目根目录的 `build.gradle` 或 `build.gradle.kts` 中：

**Groovy (build.gradle)**:

```groovy
plugins {
    id 'com.android.application' version '8.9.1' apply false
    id 'org.jetbrains.kotlin.android' version '2.0.21' apply false
    id 'com.google.devtools.ksp' version '2.0.21-1.0.28' apply false
}
```

**Kotlin DSL (build.gradle.kts)**:

```kotlin
plugins {
    id("com.android.application") version "8.9.1" apply false
    id("org.jetbrains.kotlin.android") version "2.0.21" apply false
    id("com.google.devtools.ksp") version "2.0.21-1.0.28" apply false
}
```

### 添加模块依赖

在 Tool 模块的 `build.gradle` 或 `build.gradle.kts` 中：

**Groovy (build.gradle)**:

```groovy
plugins {
    id 'com.android.application'  // 或 'com.android.library'
    id 'org.jetbrains.kotlin.android'
    id 'com.google.devtools.ksp'

    // MCP Tool 插件（自动合并 Manifest）
    id 'com.xctech.collaboration.tool' version '1.0.0'
}

dependencies {
    // MCP SDK - Tool 端
    implementation 'com.xctech.collaboration:collaboration-sdk:1.0.0'

    // 注解
    implementation 'com.xctech.collaboration:collaboration-tool-annotations:1.0.0'

    // KSP 编译器
    ksp 'com.xctech.collaboration:collaboration-tool-compiler:1.0.0'
}
```

**Kotlin DSL (build.gradle.kts)**:

```kotlin
plugins {
    id("com.android.application")  // 或 library
    id("org.jetbrains.kotlin.android")
    id("com.google.devtools.ksp")

    // MCP Tool 插件（自动合并 Manifest）
    id("com.xctech.collaboration.tool") version "1.0.0"
}

dependencies {
    // MCP SDK - Tool 端
    implementation("com.xctech.collaboration:collaboration-sdk:1.0.0")

    // 注解
    implementation("com.xctech.collaboration:collaboration-tool-annotations:1.0.0")

    // KSP 编译器
    ksp("com.xctech.collaboration:collaboration-tool-compiler:1.0.0")
}
```

## 定义 Tool 服务

### 使用注解定义工具

创建你的 Tool 服务类：

```kotlin
import com.xctech.collaboration.tool.annotation.ToolService
import com.xctech.collaboration.tool.annotation.ToolMethod
import com.xctech.collaboration.tool.annotation.Param
import com.xctech.collaboration.tool.ToolCallCallback

@ToolService(
    name = "计算器",
    version = "1.0.0",
    description = "提供数学计算能力"
)
class CalculatorToolService {

    /**
     * 加法运算
     */
    @ToolMethod(
        name = "add",
        description = "计算两个数的和"
    )
    fun add(
        @Param(name = "a", description = "第一个数字") a: String,
        @Param(name = "b", description = "第二个数字") b: String,
        callback: ToolCallCallback
    ) {
        val numA = a.toDoubleOrNull()
        val numB = b.toDoubleOrNull()

        if (numA == null || numB == null) {
            callback.onError("参数必须是有效数字")
            return
        }

        val result = numA + numB
        callback.successText(result.toString())
    }

    /**
     * 乘法运算
     */
    @ToolMethod(
        name = "multiply",
        description = "计算两个数的乘积"
    )
    fun multiply(
        @Param(name = "a", description = "第一个数字") a: String,
        @Param(name = "b", description = "第二个数字") b: String,
        callback: ToolCallCallback
    ) {
        val numA = a.toDoubleOrNull()
        val numB = b.toDoubleOrNull()

        if (numA == null || numB == null) {
            callback.onError("参数必须是有效数字")
            return
        }

        val result = numA * numB
        callback.successText(result.toString())
    }
}
```

## 自动生成工具元数据

### 运行 KSP 生成代码

**重要**：每次增加、删除或修改 `@ToolService`、`@ToolMethod` 注解后，必须先运行 KSP 编译任务生成代码。

```bash

# 直接执行完整构建（会自动触发 KSP）
./gradlew :app:assembleDebug

# 生成 Debug 版本的代码
./gradlew :app:kspDebugKotlin

# 或生成 Release 版本的代码
./gradlew :app:kspReleaseKotlin

```
> **注意**：如果你修改了注解但没有运行 KSP，生成的代码和 Manifest 不会更新，会导致：

*   新增的工具方法无法被发现
    
*   删除的工具方法仍然被注册
    
*   参数变更不生效
    

KSP 会自动生成：

1.  **服务实现类**：`{YourClassName}_Generated.kt`（如 `CalculatorToolService_Generated.kt`）
    
2.  **Manifest 片段**：自动合并到最终 Manifest
    
3.  **工具方法映射**：自动生成参数解析和方法分发代码
    

### 生成的 Manifest

```xml
<!-- 自动生成并合并 -->
<service
    android:name="com.yourpackage.CalculatorToolService_Generated"
    android:exported="true">
    <intent-filter>
        <action android:name="com.xctech.collaboration.TOOLS" />
    </intent-filter>
    <meta-data android:name="collaboration_role" android:value="tool" />
    <meta-data android:name="tool_name" android:value="计算器" />
    <meta-data android:name="tool_version" android:value="1.0.0" />
    <meta-data android:name="tool_description" android:value="提供数学计算能力" />
    <!-- 工具方法列表（静态发现） -->
    <meta-data android:name="collaboration_tools" android:value="add,multiply" />
</service>
```
> **静态发现**：`collaboration_tools` 包含所有工具方法名称，Uril 无需绑定服务即可知道该 Tool 提供哪些能力。

### 生成的服务类

KSP 会生成一个继承自 `ToolServerService` 的实现类，自动处理：

*   MCP 协议通信
    
*   参数解析和验证
    
*   结果序列化
    
*   方法分发
    

## 高级用法

### 异步工具方法

对于耗时操作，使用 `ToolCallCallback` 进行异步响应：

```kotlin
@ToolService(
    name = "ASR语音识别",
    version = "1.0.0",
    description = "语音转文字服务"
)
class AsrToolService {

    @ToolMethod(
        name = "startAsr",
        description = "开始语音识别"
    )
    fun startAsr(
        @Param(name = "language", description = "识别语言", required = false) language: String?,
        callback: ToolCallCallback
    ) {
        // 启动异步任务
        AsrEngine.start(language ?: "zh-CN") { result ->
            when (result) {
                is AsrResult.Partial -> {
                    // 报告进度（可多次调用）
                    callback.onProgress(listOf(TextContent(text = result.text)))
                }
                is AsrResult.Final -> {
                    // 返回最终结果
                    callback.onSuccess(listOf(TextContent(text = result.text)))
                }
                is AsrResult.Error -> {
                    // 返回错误
                    callback.onError(result.message)
                }
            }
        }
    }

    @ToolMethod(
        name = "stopAsr",
        description = "停止语音识别"
    )
    fun stopAsr(callback: ToolCallCallback) {
        AsrEngine.stop()
        callback.successText("已停止识别")
    }
}
```

### 返回多种内容类型

```kotlin
import com.xctech.collaboration.spec.TextContent
import com.xctech.collaboration.spec.ImageContent

@ToolMethod(
    name = "captureScreen",
    description = "截取屏幕"
)
fun captureScreen(callback: ToolCallCallback) {
    val bitmap = takeScreenshot()
    val base64 = bitmap.toBase64()

    // 返回图片和文字说明
    callback.onSuccess(listOf(
        ImageContent(data = base64, mimeType = "image/png"),
        TextContent(text = "截图完成，分辨率: ${bitmap.width}x${bitmap.height}")
    ))
}
```

### 可选参数

```kotlin
@ToolMethod(
    name = "search",
    description = "搜索内容"
)
fun search(
    @Param(name = "keyword", description = "搜索关键词") keyword: String,
    @Param(name = "limit", description = "返回数量", required = false) limit: String?,
    callback: ToolCallCallback
) {
    val maxResults = limit?.toIntOrNull() ?: 10  // 默认 10 条
    val results = doSearch(keyword, maxResults)
    callback.successText(results.joinToString("\n"))
}
```

### 错误处理

```kotlin
@ToolMethod(name = "divide", description = "除法运算")
fun divide(
    @Param(name = "a", description = "被除数") a: String,
    @Param(name = "b", description = "除数") b: String,
    callback: ToolCallCallback
) {
    val numA = a.toDoubleOrNull()
    val numB = b.toDoubleOrNull()

    when {
        numA == null || numB == null -> {
            // 工具级别错误（返回 isError=true 的结果）
            callback.onError("参数必须是有效数字")
        }
        numB == 0.0 -> {
            // 协议级别错误（返回错误码）
            callback.onError(ErrorCodes.INVALID_PARAMS, "除数不能为零")
        }
        else -> {
            callback.successText((numA / numB).toString())
        }
    }
}
```

## 手动实现（不使用注解）

如果需要更精细的控制，可以直接继承 `ToolServerService`：

```kotlin
import com.xctech.collaboration.tool.ToolServerService
import com.xctech.collaboration.tool.ToolCallCallback
import com.xctech.collaboration.spec.*
import com.xctech.collaboration.core.ErrorCodes

class MyManualToolService : ToolServerService() {

    override fun getToolServerInfo(): Implementation {
        return Implementation(name = "手动Tool", version = "1.0.0")
    }

    override fun getServerCapabilities(): ServerCapabilities {
        return ServerCapabilities(
            tools = ToolServerCapability(listChanged = true)
        )
    }

    override fun onRegisterTools(): List<Tool> {
        return listOf(
            Tool(
                name = "myTool",
                description = "自定义工具",
                inputSchema = ToolInputSchema(
                    properties = mapOf(
                        "input" to mapOf(
                            "type" to "string",
                            "description" to "输入参数"
                        )
                    ),
                    required = listOf("input")
                )
            )
        )
    }

    override fun onToolCall(
        name: String,
        arguments: Map<String, String>?,
        callback: ToolCallCallback
    ) {
        when (name) {
            "myTool" -> {
                val input = arguments?.get("input") ?: ""
                val result = processInput(input)
                callback.successText(result)
            }
            else -> {
                callback.onError(ErrorCodes.METHOD_NOT_FOUND, "未知工具: $name")
            }
        }
    }
}
```

手动实现时需要在 `AndroidManifest.xml` 中声明服务：

```xml
<service
    android:name=".MyManualToolService"
    android:exported="true">
    <intent-filter>
        <action android:name="com.xctech.collaboration.TOOLS" />
    </intent-filter>
    <meta-data android:name="collaboration_role" android:value="tool" />
    <meta-data android:name="tool_version" android:value="1.0.0" />
    <meta-data android:name="tool_name" android:value="xx工具" />
    <meta-data android:name="tool_description" android:value="xx工具" />
    <meta-data android:name="collaboration_tools" android:value="myTool" />
</service>
```

## ToolCallCallback API

### 方法说明

| **方法** | **说明** |
| --- | --- |
| `onProgress(content)` | 报告进度，可多次调用 |
| `onSuccess(content)` | 成功完成，返回结果内容 |
| `onError(code, message)` | 协议级别错误（AIDL onError） |
| `onError(message)` | 工具级别错误（isError=true） |

### 扩展方法

```kotlin
// 快捷返回文本
callback.successText("结果文本")

// 快捷返回图片
callback.successImage(base64Data, "image/png")

// 返回多内容
callback.successContents(
    TextContent(text = "说明"),
    ImageContent(data = base64, mimeType = "image/jpeg")
)
```

## 调试

### 启用协议拦截器

```kotlin
import com.xctech.collaboration.core.ProtocolInterceptor

// 在 Application 或 Service 中启用
ProtocolInterceptor.enable(pretty = true)
```

### 查看日志

```bash
# 查看 Tool 服务日志
adb logcat | grep "MCP_SDK_TOOL"

# 查看 MCP 协议请求/响应
adb logcat | grep "MCP_PROTOCOL"

# 查看服务发现
adb logcat | grep "MCP_SDK_DISCOVERY"
```

### 协议日志示例

```plaintext
D/MCP_PROTOCOL: [REQUEST] tools/call
D/MCP_PROTOCOL: {
D/MCP_PROTOCOL:   "jsonrpc": "2.0",
D/MCP_PROTOCOL:   "method": "tools/call",
D/MCP_PROTOCOL:   "params": {
D/MCP_PROTOCOL:     "name": "add",
D/MCP_PROTOCOL:     "arguments": { "a": "1", "b": "2" }
D/MCP_PROTOCOL:   }
D/MCP_PROTOCOL: }

D/MCP_PROTOCOL: [RESPONSE] tools/call
D/MCP_PROTOCOL: {
D/MCP_PROTOCOL:   "jsonrpc": "2.0",
D/MCP_PROTOCOL:   "result": {
D/MCP_PROTOCOL:     "content": [{ "type": "text", "text": "3.0" }],
D/MCP_PROTOCOL:     "isError": false
D/MCP_PROTOCOL:   }
D/MCP_PROTOCOL: }

```

# 注解参考

### @ToolService

| **属性** | **类型** | **必填** | **说明** |
| --- | --- | --- | --- |
| `name` | String | 是 | 工具服务名称 |
| `version` | String | 否 | 版本号（默认 "1.0.0"） |
| `description` | String | 否 | 服务描述 |

### @ToolMethod

| **属性** | **类型** | **必填** | **说明** |
| --- | --- | --- | --- |
| `name` | String | 是 | 方法名称（MCP 中的 tool name） |
| `description` | String | 否 | 方法描述 |

### @Param

| **属性** | **类型** | **必填** | **说明** |
| --- | --- | --- | --- |
| `name` | String | 否 | 参数名称（默认使用方法参数名） |
| `description` | String | 否 | 参数描述 |
| `required` | Boolean | 否 | 是否必填（默认 true） |

# 常见问题

### Q1: 编译后没有生成服务类？

**检查项**：

1.  确认已添加 KSP 插件和编译器依赖
    
2.  确认类上有 `@ToolService` 注解
    
3.  确认方法上有 `@ToolMethod` 注解
    
4.  确认方法最后一个参数是 `ToolCallCallback`
    
5.  **手动执行 KSP 编译**：`./gradlew :app:kspDebugKotlin`
    
6.  检查生成目录：`app/build/generated/ksp/debug/kotlin/`
    

### Q2: Uril 发现不到我的 Tool？

**检查项**：

1.  确认 `AndroidManifest.xml` 中有服务声明
    
2.  确认 `intent-filter` 的 action 是 `com.xctech.collaboration.TOOLS`
    
3.  确认 `android:exported="true"`
    
4.  确认 Tool 应用已安装到设备
    

### Q3: 工具调用返回 "Tool not found"？

**检查项**：

1.  确认工具名称（`@ToolMethod` 的 `name`）与调用时一致
    
2.  查看 Uril 日志中发现的工具列表
    
3.  确认 Tool 服务已正常启动
    

### Q4: 如何调试参数传递？

在工具方法中添加日志：

```kotlin
@ToolMethod(name = "myTool", description = "...")
fun myTool(
    @Param(name = "input", description = "...") input: String,
    callback: ToolCallCallback
) {
    Log.d("MyTool", "收到参数: input=$input")
    // ...
}
```

### Q5: 大数据传输失败？

SDK 内置了数据保护机制：

*   自动压缩大于 200KB 的数据
    
*   自动分片传输超大数据
    
*   如仍失败，考虑分批返回结果