---
title: "chat - Talent 开发详解与预置封装"
---

这部分内容比较多，专门做了一个分组：

详见：[《Solon AI Talents 开发》](/article/learn-solon-ai-talents)

---



### 1、Talent 接口方法一览

`Talent` 是 Solon AI 中领域能力的顶层接口，定义于 `org.noear.solon.ai.chat.talent.Talent`，自 `3.8.4` 起提供。接口所有方法均提供 `default` 实现，子类按需覆盖。

| 方法签名 | 默认值 | 说明 |
|---|---|---|
| `boolean isEnabled()` | `true` | 是否启用该才能 |
| `void setEnabled(Boolean enabled)` | — | 动态启用或禁用（@since 4.0.4） |
| `String name()` | 类名 | 才能名称，用于标识与 System Message 注入 |
| `String description()` | `null` | 才能描述 |
| `TalentMetadata metadata()` | `name + description` | 才能元信息（含 name / description / category / tags / sensitive） |
| `boolean isSupported(Prompt prompt)` | `true` | 准入检查，决定本才能是否对当前请求生效 |
| `void onAttach(Prompt prompt)` | 空实现 | 激活钩子，才能被激活时调用，可用于初始化或审计 |
| `String getInstruction(Prompt prompt)` | `null` | 动态指令注入，返回值追加至 System Message |
| `Collection<FunctionTool> getTools(Prompt prompt)` | `null` | 动态工具注入，返回本才能提供的工具集合 |

**TalentMetadata** 用于携带才能的元信息，支持链式构建：

```java
new TalentMetadata("weather", "提供天气查询能力")
    .category("tools")
    .tags("weather", "query")
    .sensitive(false);
```


### 2、自定义 Talent 开发步骤

自定义 Talent 有两种构建方式，视场景选择。

#### 方式一：继承 AbsTalent（推荐，工程化程度高）

继承 `AbsTalent` 基类，通过 `@ToolMapping` 注解定义工具方法。基类会在构造时通过 `MethodToolProvider` 自动扫描并注册所有带注解的方法，无需手动维护工具列表。

```java
@Component
public class WeatherTalent extends AbsTalent {

    @Override
    public String name() {
        return "weather";
    }

    @Override
    public String description() {
        return "提供天气查询能力";
    }

    @Override
    public boolean isSupported(Prompt prompt) {
        // 根据 Prompt 内容决定是否激活，此处对所有请求生效
        return true;
    }

    @Override
    public String getInstruction(Prompt prompt) {
        return "当用户询问天气时，使用 get_weather 工具查询实时天气数据。";
    }

    @ToolMapping(description = "查询指定城市的天气")
    public String get_weather(@Param(description = "城市名称") String city) {
        // 调用天气 API 或本地逻辑
        return city + "：晴天，25°C";
    }
}
```

> `@Component` 场景下，可通过 `@Inject` 在 Talent 内注入其他 Bean，实现与业务服务的解耦。

#### 方式二：通过 TalentDesc 声明式构建（轻量场景）

适合不需要独立类文件的简单或临时才能，使用 Lambda 进行函数式定义：

```java
Talent weatherTalent = new TalentDesc("weather")
    .description("提供天气查询能力")
    .isSupported(prompt -> true)
    .instruction(prompt -> "当用户询问天气时，使用 get_weather 工具查询实时天气数据。")
    .toolAdd(/* 通过 FunctionTool 工厂方法或 @ToolMapping 扫描结果添加工具 */)
    .build();
```

#### 两种方式对比

| 特性 | TalentDesc 声明式 | AbsTalent 继承式 |
|---|---|---|
| 构建风格 | 函数式 / 链式调用 | 面向对象 / Override |
| 工具定义 | Lambda / 手动添加 | `@ToolMapping` 自动扫描 |
| 依赖注入 | 需手动从上下文获取 | 可通过容器 `@Inject` 注入 |
| 状态维护 | 不易持有复杂成员状态 | 支持成员变量与生命周期管理 |
| 推荐用途 | 快速定义、局部动态逻辑 | 复杂业务、多工具协作、深度工程化 |

#### 注册到 ChatModel

```java
ChatModel chatModel = ChatModel.of("https://...")
        .apiKey("...")
        .model("...")
        .build();

// 全局默认注册（对该 ChatModel 的所有请求生效）
chatModel.defaultTalentAdd(new WeatherTalent());

// 单次请求临时注册
chatModel.prompt("明天上海天气如何？")
        .options(o -> o.talentAdd(new WeatherTalent()))
        .call();
```


### 3、内置预置 Talent 列表

#### HarnessEngine 内置 Talent（14 个）

`HarnessEngine` 是 Solon AI 的运行时编排中心，通过工具权限名（ToolName）按需激活对应 Talent。以下为全部 14 个内置 Talent：

| Talent 类名 | 工具权限名 | 主要能力 |
|---|---|---|
| `TerminalTalent` | `read` / `write` / `edit` / `glob` / `grep` / `ls` / `bash` | 终端交互、文件读写、内容搜索、Shell 命令执行 |
| `CodeTalent` | `code` | 代码项目分析，自动识别技术栈并向 System Message 注入工程规约 |
| `TodoTalent` | `todo` / `todoread` / `todowrite` | 任务清单管理（主代理文件持久化模式，子代理内存模式） |
| `TaskTalent` | `task` / `subagent` | 复杂任务拆解与子 Agent 委派（需启用 subagent 能力） |
| `GenerateTalent` | `generate` | 调用子 Agent 执行内容生成任务（需启用 subagent 能力） |
| `ClockTalent` | —（始终注册） | 提供当前时间感知，任意工具注册后自动添加，无需显式指定 |
| `WebfetchTalent` | `webfetch` | 抓取指定 URL 的网页内容并转换为 Markdown 格式返回 |
| `WebsearchTalent` | `websearch` | 执行实时 Web 搜索并返回摘要结果 |
| `CodeSearchTalent` | `codesearch` | 编程相关知识检索，针对 API、库与代码模式查询优化 |
| `LspTalent` | `lsp` | 语言服务协议（LSP）集成，提供代码补全、跳转定义、诊断等 |
| `McpGatewayTalent` | `mcp` | MCP 协议服务端工具聚合网关，动态代理已注册的 MCP 工具集 |
| `OpenApiGatewayTalent` | `openapi` / `restapi` | OpenAPI/REST 服务工具聚合网关，根据 OpenAPI 描述文件暴露工具 |
| `MemoryTalent` | `memory` | 对话记忆持久化与语义检索，支持跨会话长期记忆 |
| `SkillTalent` | `skill` | 技能库发现与动态加载，从 SKILL.md 驱动 Agent 专项行为 |

#### 预定义权限组合

`HarnessEngine` 提供三组开箱即用的工具权限常量集合，通过 `toolsAdd(TOOL_ALL_PUBLIC)` 等方式使用：

| 常量名 | 说明 |
|---|---|
| `TOOL_ALL_FULL` | 全量工具（含高级工具：mcp / openapi / hitl / memory / lsp / generate 等） |
| `TOOL_ALL_PUBLIC` | 公有工具全集（主流场景推荐，不含高级网关与人机交互） |
| `TOOL_PI` | 编程交互精简集（仅 read / write / edit / bash 系列） |


### 4、Talent 与 Tool 的关系

Talent 是 Tool 的聚合载体，二者的核心关系：

- **一个 Talent 可包含多个 Tool**：`getTools()` 返回多个 `FunctionTool`，统一挂载到推理上下文，模型可在同一才能语境下按需调用。
- **Talent 额外提供 Instruction**：通过 `getInstruction()` 向 System Message 注入领域 SOP，裸 Tool 本身不具备此能力。
- **注册 Talent 自动注册其工具**：无需再单独调用 `toolAdd()`，Talent 注册后其内含的所有工具自动对本次推理可见。
- **工具染色**：借鉴 MCP 思想，Talent 的元信息（name / description）会注入到旗下工具的元数据中，模型可感知工具的才能归属。
- **整体开关**：`isEnabled / setEnabled` 对整个 Talent 及其内含工具做统一启用/禁用（@since 4.0.4）。

#### Talent 生命周期

每次推理调用时，Talent 框架按以下顺序驱动所有已注册才能：

```
注册阶段
  └─ chatModel.defaultTalentAdd(talent)  // 全局
     options.talentAdd(talent)            // 单次

触发阶段（每次推理）
  ├─ isEnabled()          → false 则跳过整个才能
  ├─ isSupported(prompt)  → false 则跳过（基于 Prompt 上下文感知）
  ├─ onAttach(prompt)     → 初始化 / 审计日志
  ├─ getInstruction(prompt) → 注入 System Message（独立 Talent 块）
  └─ getTools(prompt)     → 挂载并染色工具集合
```


### 5、Talent 的动态启用与禁用（@since 4.0.4）

`Talent` 接口提供 `setEnabled(Boolean enabled)` 方法，`AbsTalent` 基类已提供线程安全的 `volatile boolean` 默认实现。调用该方法可在不取消注册的前提下临时禁用某个 Talent。

```java
WeatherTalent weatherTalent = new WeatherTalent();
chatModel.defaultTalentAdd(weatherTalent);

// 临时禁用（不移除注册结构，不影响其他 Talent）
weatherTalent.setEnabled(false);

// 重新启用
weatherTalent.setEnabled(true);
```

**典型应用场景**：

- **A/B 测试**：对不同用户会话启用不同的 Talent 组合，无需重建 ChatModel 实例。
- **资源控制**：在高并发或资源受限时临时关闭消耗较大的 Talent（如 `WebsearchTalent`）。
- **权限管控**：根据用户角色或请求上下文动态开关敏感 Talent，无需维护多套注册配置。
- **调试隔离**：在排查问题时单独禁用某个 Talent，保持整体注册结构不变。

**与 `isSupported()` 的区别**：

| | `setEnabled(false)` | `isSupported()` 返回 false |
|---|---|---|
| 触发时机 | 一次性全局开关，持续生效 | 每次推理时动态评估 |
| 决策依据 | 外部主动调用 | 基于当前 Prompt 上下文 |
| 生命周期 | 跳过全部钩子（onAttach 等也不执行） | 跳过激活阶段，但 isEnabled 已通过 |
| 典型用途 | 资源控制、运维开关 | 按场景/内容智能感知 |
