Solon v4.0.4

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

</> markdown
2026年7月30日 下午3:58:34

这部分内容比较多,专门做了一个分组:

详见:《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 用于携带才能的元信息,支持链式构建:

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

2、自定义 Talent 开发步骤

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

方式一:继承 AbsTalent(推荐,工程化程度高)

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

@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 进行函数式定义:

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

两种方式对比

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

注册到 ChatModel

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 类名工具权限名主要能力
TerminalTalentread / write / edit / glob / grep / ls / bash终端交互、文件读写、内容搜索、Shell 命令执行
CodeTalentcode代码项目分析,自动识别技术栈并向 System Message 注入工程规约
TodoTalenttodo / todoread / todowrite任务清单管理(主代理文件持久化模式,子代理内存模式)
TaskTalenttask / subagent复杂任务拆解与子 Agent 委派(需启用 subagent 能力)
GenerateTalentgenerate调用子 Agent 执行内容生成任务(需启用 subagent 能力)
ClockTalent—(始终注册)提供当前时间感知,任意工具注册后自动添加,无需显式指定
WebfetchTalentwebfetch抓取指定 URL 的网页内容并转换为 Markdown 格式返回
WebsearchTalentwebsearch执行实时 Web 搜索并返回摘要结果
CodeSearchTalentcodesearch编程相关知识检索,针对 API、库与代码模式查询优化
LspTalentlsp语言服务协议(LSP)集成,提供代码补全、跳转定义、诊断等
McpGatewayTalentmcpMCP 协议服务端工具聚合网关,动态代理已注册的 MCP 工具集
OpenApiGatewayTalentopenapi / restapiOpenAPI/REST 服务工具聚合网关,根据 OpenAPI 描述文件暴露工具
MemoryTalentmemory对话记忆持久化与语义检索,支持跨会话长期记忆
SkillTalentskill技能库发现与动态加载,从 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 可包含多个 ToolgetTools() 返回多个 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。

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 已通过
典型用途资源控制、运维开关按场景/内容智能感知