---
title: "chat - Talent 的两种构建方式"
---

在 Solon AI 中，才能的构建遵循“由简入繁”的原则。和 Tool 一样，也提供了两种构建方式：

* 通过 TalentDesc 描述式构建
* 通过实现 Talent 接口 或 AbsTalent 基类扩展


无论是申明式还是接口式，开发者都能获得对才能生命周期的完整控制权。



### 1、通过 TalentDesc（才能描述） 描述式构建

TalentDesc 提供了一种轻量级的构建方式。它不仅支持静态属性设置，还允许通过 Lambda 注入动态谓词和逻辑。这使得开发者无需创建新的类文件，就能实现复杂的准入检查和指令生成。

适用场景：快速组合工具、逻辑相对集中的才能定义、偏好函数式风格的开发。

示例代码：

```java
TalentDesc talent = new TalentDesc("order_expert")
        .description("订单助手")
        // 动态准入：只有提到“订单”时才激活
        .isSupported(prompt -> prompt.getUserContent().contains("订单"))
        // 动态指令：根据用户是否是 VIP 注入不同 SOP
        .instruction(prompt -> {
            if ("VIP".equals(prompt.attr("user_level"))) {
                return "这是尊贵的 VIP 客户，请优先调用 fast_track_tool。";
            }
            return "按常规流程处理订单查询。";
        })
        .toolAdd(new OrderTools());
```


提示：此方式适合动态构建。

### 2、通过实现 Talent 接口（一般使用 AbsTalent 基类扩展）


通过实现 Talent 接口，开发者可以利用面向对象的特性（如继承、成员变量状态、复杂的依赖注入）来组织代码。这种方式在逻辑极其复杂、或者需要复用基础才能逻辑时最为合适。

**适用场景：**

* 高度工程化：需要利用容器组件的注入能力。
* 状态维护：需要在 onAttach 中计算并存储中间状态供后续接口使用。
* 逻辑复用：通过继承 AbsTalent 实现一套通用的安全审计或日志逻辑。

示例代码（使用 AbsTalent 作为基类，可以简化开发）：

```java
@Component
public class TechSupportTalent extends AbsTalent {
    @Inject
    private KbService kbService; 

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

    @Override
    public String description() {
        return "技术支持专家，支持故障排查与配置重置";
    }

    @Override
    public boolean isSupported(Prompt prompt) {
        String content = prompt.getUserContent();
        // 扩展意图识别：涵盖关键词、报错信息等特征
        return content != null && (content.contains("故障") || content.contains("报错") || content.contains("error"));
    }

    @Override
    public String getInstruction(Prompt prompt) {
        return "你现在是技术支持专家，请遵循以下 SOP：\n" +
                "1. 首先根据报错信息检索知识库（search_kb）。\n" +
                "2. 给出方案前，必须核实用户的环境版本（Solon 版本）。\n" +
                "3. 若需修改生产配置，必须明确告知风险。";
    }

    @ToolMapping(name = "search_kb", description = "搜索技术知识库，获取故障解决方案")
    public String searchKb(@Param("query") String query) {
        if (Utils.isEmpty(query)) {
            return "请输入搜索关键词";
        }
        return kbService.search(query);
    }

    @ToolMapping(
            name = "reset_config",
            description = "重置系统配置（高危操作）",
            meta = "{'danger': true, 'confirm_msg': '操作将导致服务重启，确定吗？'}"
    )
    public String resetConfig(@Param("serviceName") String serviceName) {
        // 执行具体的重置逻辑
        return "服务 [" + serviceName + "] 配置已重置，正在重启...";
    }
}
```

AbsTalent 基类（也可定义自己的快捷基类）：

```java
package org.noear.solon.ai.chat.talent;

import org.noear.solon.ai.chat.prompt.Prompt;
import org.noear.solon.ai.chat.tool.FunctionTool;
import org.noear.solon.ai.chat.tool.MethodToolProvider;
import org.noear.solon.lang.Preview;

import java.util.*;

/**
 * 才能定制基类
 */
public abstract class AbsTalent implements Talent {
    private volatile TalentMetadata metadata;
    private volatile boolean enabled = true;

    private final Map<String, FunctionTool> toolMap0;
    private final List<FunctionTool> tools0;

    private final Map<String, FunctionTool> toolMap;
    private final List<FunctionTool> tools;

    protected AbsTalent() {
        this(null);
    }

    /**
     * @since 3.10.2
     */
    protected AbsTalent(Map<String, Object> binding) {
        this.tools0 = new ArrayList<>();
        this.tools0.addAll(new MethodToolProvider(this)
                .binding(binding)
                .includeProvide(false)
                .getTools());

        this.toolMap0 = new LinkedHashMap<>();
        for (FunctionTool tool : tools0) {
            toolMap0.put(tool.name(), tool);
        }

        this.tools = Collections.unmodifiableList(tools0);
        this.toolMap = Collections.unmodifiableMap(toolMap0);
    }

    protected void internalAddTool(FunctionTool tool) {
        this.tools0.add(tool);
        this.toolMap0.put(tool.name(), tool);
    }

    public Map<String, FunctionTool> getToolMap() {
        return toolMap;
    }

    public Collection<FunctionTool> getToolAry() {
        return tools;
    }

    public Collection<FunctionTool> getToolAry(String... names) {
        return getToolAry(Arrays.asList(names));
    }

    public Collection<FunctionTool> getToolAry(Collection<String> names) {
        List<FunctionTool> list = new ArrayList<>();
        for (String key : names) {
            if (toolMap.containsKey(key)) {
                list.add(toolMap.get(key));
            }
        }
        return list;
    }

    public void setEnabled(Boolean enabled) {
        if (enabled != null) {
            this.enabled = enabled;
        }
    }

    @Override
    public boolean isEnabled() {
        return enabled;
    }

    @Override
    public TalentMetadata metadata() {
        if (this.metadata == null) {
            this.metadata = new TalentMetadata(this.name(), this.description());
        }

        return this.metadata;
    }

    @Override
    public Collection<FunctionTool> getTools(Prompt prompt) {
        return tools;
    }
}
```


## 3、构建方式对比




| 特性 | TalentDesc 申明式 | Talent 接口实现（或 AbsTalent 基类扩展） | 
| -------- | -------- | -------- |
| 构建风格     | 函数式 / 链式调用              | 面向对象 / 显式实现     |
| 控制力        | 完整控制 (通过 Lambda)     | 完整控制 (通过 Override)     |
| 代码组织     | 集中在一个代码块中           | 分散在独立的类文件中     |
| 依赖注入     | 需手动从上下文获取           | 可以通过容器注入     |
| 推荐用途     | 快速定义、局部动态逻辑     | 复杂业务领域、深度工程化项目     |


无论选择哪种方式，你都可以通过 prompt 参数感知输入，通过 onAttach 拦截生命周期，以及通过指令染色控制模型行为。选择的关键在于你希望如何组织你的代码结构。



