Agent Scope Java 2.x 系列【4】模型层

文章目录

  • [1. 概述](#1. 概述)
  • [2. 模型认证层](#2. 模型认证层)
    • [2.1 CredentialBase](#2.1 CredentialBase)
    • [2.2 ModelCard](#2.2 ModelCard)
    • [2.3 八种实现](#2.3 八种实现)
    • [2.4 Builder 示例](#2.4 Builder 示例)
    • [2.5 fromJson() :从配置反序列化](#2.5 fromJson() :从配置反序列化)
    • [2.6 与 Model 包的关系](#2.6 与 Model 包的关系)
    • [2.7 使用示例](#2.7 使用示例)
  • [3. 模型接入层](#3. 模型接入层)
    • [3.1 Model 接口](#3.1 Model 接口)
    • [3.2 ChatModelBase 抽象基类](#3.2 ChatModelBase 抽象基类)
    • [3.3 模型实现类](#3.3 模型实现类)
    • [3.4 GenerateOptions 生成参数](#3.4 GenerateOptions 生成参数)
    • [3.5 ExecutionConfig 执行策略](#3.5 ExecutionConfig 执行策略)
    • [3.6 ChatResponse 模型响应](#3.6 ChatResponse 模型响应)
    • [3.7 ChatUsage Token 用量](#3.7 ChatUsage Token 用量)
    • [3.8 ModelRegistry 模型注册中心](#3.8 ModelRegistry 模型注册中心)
    • [3.9 ToolSchema 工具 Schema](#3.9 ToolSchema 工具 Schema)
    • [3.10 EndpointType 端点类型](#3.10 EndpointType 端点类型)
    • [3.11 使用示例](#3.11 使用示例)

1. 概述

模型层采用两层结构:

  • 上层是 Credential(io.agentscope.core.credential),承载某个提供商的 API 鉴权字段
  • 下层是 Chat Model(io.agentscope.core.model),即在该凭证基础上对接的具体推理模型实现

2. 模型认证层

io.agentscope.core.credential 是模型层的上半部分 ------认证层。它与 model 包(推理层)共同构成 AgentScope 的两层模型架构:

text 复制代码
Credential(本包)              Model(model 包)
═══════════════════            ═══════════════════
"以什么身份调用"                "调用哪个模型做什么"

DashScopeCredential  ──关联──→ DashScopeChatModel
OpenAICredential     ──关联──→ OpenAIChatModel
AnthropicCredential  ──关联──→ AnthropicChatModel
...

核心设计 :先注册凭证 → 从凭证获取模型列表 → 选择模型创建 ChatModel。这样前端只需鉴权一次,就能展示该提供商支持的所有模型。

类图:

text 复制代码
CredentialBase (abstract)
    │  id: String
    │  listModels() → Mono<List<ModelCard>>
    │  getChatModelClass() → Class<? extends ChatModelBase>
    │
    ├── DashScopeCredential    ← 通义千问        apiKey + baseUrl
    ├── OpenAICredential       ← OpenAI 兼容      apiKey + baseUrl + organization
    ├── AnthropicCredential    ← Claude          apiKey + baseUrl
    ├── GeminiCredential       ← Google Gemini   apiKey
    ├── DeepSeekCredential     ← DeepSeek        apiKey + baseUrl
    ├── KimiCredential         ← Moonshot Kimi   apiKey + baseUrl
    ├── XAICredential          ← xAI Grok        apiKey
    └── OllamaCredential       ← 本地 Ollama      host

ModelCard (Record)
    modelName: String
    displayName: String
    contextSize: Integer

2.1 CredentialBase

抽象基类:

java 复制代码
public abstract class CredentialBase {
    private final String id;

    // 唯一标识
    public final String getId();

    // 关联的 ChatModel 类型
    public abstract Class<? extends ChatModelBase> getChatModelClass();

    // 列出此凭证下可用的模型(异步,部分提供商需 API 调用)
    public Mono<List<ModelCard>> listModels();
}

2.2 ModelCard

模型卡片:

java 复制代码
public record ModelCard(
    String modelName,       // API 名称,如 "qwen-max"
    String displayName,     // 展示名称,如 "Qwen Max"
    Integer contextSize     // 上下文窗口大小(token)
) {}

通过 credential.listModels() 获取,供前端渲染模型选择器。

2.3 八种实现

凭证 TYPE 常量 字段 关联 ChatModel
DashScopeCredential "dashscope" apiKey, baseUrl DashScopeChatModel
OpenAICredential "openai" apiKey, baseUrl, organization OpenAIChatModel
AnthropicCredential "anthropic" apiKey, baseUrl AnthropicChatModel
GeminiCredential "gemini" apiKey GeminiChatModel
DeepSeekCredential "deepseek" apiKey, baseUrl OpenAIChatModel
KimiCredential "kimi" apiKey, baseUrl OpenAIChatModel
XAICredential "xai" apiKey OpenAIChatModel
OllamaCredential "ollama" host OllamaChatModel

DeepSeek / Kimi / XAI 都是 OpenAI 兼容 API,因此复用 OpenAIChatModel,只凭证字段和默认地址不同。

2.4 Builder 示例

java 复制代码
// DashScope
DashScopeCredential dashscope = DashScopeCredential.builder()
    .id("my-dashscope")
    .apiKey(System.getenv("DASHSCOPE_API_KEY"))
    .build();

// OpenAI
OpenAICredential openai = OpenAICredential.builder()
    .id("my-openai")
    .apiKey("sk-xxx")
    .baseUrl("https://api.openai.com/v1")
    .organization("org-xxx")
    .build();

// DeepSeek
DeepSeekCredential deepseek = DeepSeekCredential.builder()
    .id("my-deepseek")
    .apiKey("sk-xxx")       // 默认 baseUrl: https://api.deepseek.com
    .build();

// Ollama(本地,无需 apiKey)
OllamaCredential ollama = OllamaCredential.builder()
    .id("local-ollama")
    .host("http://localhost:11434")
    .build();

2.5 fromJson() :从配置反序列化

每个凭证都有静态 fromJson() 方法,支持从 JSON 配置文件或数据库反序列化:

java 复制代码
// 通用格式:{ "type": "dashscope", "apiKey": "sk-xxx", ... }
DashScopeCredential cred = DashScopeCredential.fromJson(
    "my-dashscope",           // id
    "dashscope",              // type
    "{\"apiKey\":\"sk-xxx\"}" // config JSON
);

2.6 与 Model 包的关系

复制代码
┌─────────────────────────────────────────────────────────┐
│                    ModelRegistry                         │
│  resolve("dashscope:qwen-max")                          │
│      │                                                   │
│      ├── 1. 查找 ProviderEntry "dashscope:"              │
│      ├── 2. 调用 ModelFactory(modelName)                 │
│      │       ├── 读取环境变量 DASHSCOPE_API_KEY          │
│      │       └── 创建 DashScopeChatModel(apiKey, name)  │
│      └── 3. 返回 Model 实例                              │
└─────────────────────────────────────────────────────────┘

Credential 的职责:

  1. 存储认证信息(apiKey / baseUrl / host)
  2. 通过 listModels() 获取可用模型列表
  3. 通过 getChatModelClass() 告知应创建哪种 ChatModel

Model 的职责:

  1. 接收 Messages + ToolSchema → 返回 ChatResponse
  2. 处理 HTTP/gRPC 通信
  3. 管理 GenerateOptions(temperature / maxTokens 等)

2.7 使用示例

创建凭证并获取模型列表:

java 复制代码
DashScopeCredential credential = DashScopeCredential.builder()
    .id("prod-dashscope")
    .apiKey("sk-xxx")
    .build();

// 异步获取可用模型列表
credential.listModels().subscribe(models -> {
    for (ModelCard card : models) {
        System.out.printf("%s | %s | %d tokens%n",
            card.modelName(), card.displayName(), card.contextSize());
    }
});

从凭证创建 ChatModel:

java 复制代码
DashScopeCredential credential = DashScopeCredential.builder()
    .id("my-ds").apiKey("sk-xxx").build();

// 获取凭证的模型列表 → 选择第一个 → 创建 ChatModel
credential.listModels()
    .map(models -> models.get(0).modelName())
    .map(modelName -> DashScopeChatModel.builder()
        .apiKey(credential.getApiKey())
        .modelName(modelName)
        .build())
    .subscribe(model -> {
        // 用 model 调用 LLM
    });

大多数场景不需要手动管理凭证,ModelRegistry 内部自动处理:

java 复制代码
// 一行搞定:自动读取环境变量,自动创建凭证 + 模型
Model model = ModelRegistry.resolve("dashscope:qwen-max");

// 等价于手动:
// 1. DashScopeCredential.fromEnv() → apiKey
// 2. DashScopeChatModel.builder().apiKey(apiKey).modelName("qwen-max").build()

3. 模型接入层

io.agentscope.core.model 是 AgentScope 2.0 的模型接入层 ,提供统一的 LLM 调用抽象。

核心设计理念:

  • 接口统一 :所有模型通过 Model 接口接入,对上层 Agent 透明
  • 基类复用 :ChatModelBase 封装流式调用、错误处理等通用逻辑
  • Builder 模式 :每个模型提供 Builder,支持链式配置
  • 全局注册 :ModelRegistry 支持按名称解析模型(如 "dashscope:qwen-max")

类图:

text 复制代码
Model (interface)                     ModelRegistry (static)
    │ stream(msgs, tools, options)        │ register(name, model)
    │ getModelName()                      │ resolve("dashscope:qwen-max")
    │                                     │ registerFactory(...)
    ▼
ChatModelBase (abstract)
    │ stream() → Generator pipeline (retry/config merge)
    │ doStream() --- 子类实现
    │
    ├── DashScopeChatModel        ← 通义千问
    ├── OpenAIChatModel           ← OpenAI 兼容
    ├── AnthropicChatModel        ← Claude
    ├── GeminiChatModel           ← Google Gemini
    └── OllamaChatModel           ← 本地 Ollama

工具类:
    GenerateOptions     ← 生成参数(temperature/maxTokens/thinking...)
    ExecutionConfig     ← 执行策略(超时/重试/退避)
    ToolSchema          ← 工具 Schema(name/description/parameters)
    ToolChoice (interface)
    ChatResponse        ← 模型响应(content/usage/finishReason)
    ChatUsage           ← Token 用量(input/output/total)
    EndpointType        ← DashScope 端点类型(AUTO/TEXT/MULTIMODAL)

3.1 Model 接口

所有模型实现的唯一入口。Agent 调用 model.stream(messages, tools, options) 获取 Flux<ChatResponse> 流式响应。

java 复制代码
public interface Model {
    Flux<ChatResponse> stream(
        List<Msg> messages,
        List<ToolSchema> tools,
        GenerateOptions options
    );
    String getModelName();
    default boolean supportsNativeStructuredOutput() { return false; }
}

3.2 ChatModelBase 抽象基类

内置了 ExecutionConfig 驱动的重试/超时/退避管道,子类只需实现 doStream()。

java 复制代码
public abstract class ChatModelBase implements Model {
    // 模板方法:处理 GenerateOptions 合并 + ExecutionConfig 重试/超时
    public final Flux<ChatResponse> stream(...);

    // 子类实现:真正的 HTTP/gRPC 调用
    protected abstract Flux<ChatResponse> doStream(
        List<Msg> messages, List<ToolSchema> tools, GenerateOptions options);
}

3.3 模型实现类

类 模型 Builder 关键参数
DashScopeChatModel 通义千问(Qwen) apiKey, modelName, enableThinking, enableSearch, endpointType
OpenAIChatModel OpenAI / 兼容 API apiKey, baseUrl, modelName
AnthropicChatModel Claude apiKey, modelName
GeminiChatModel Google Gemini apiKey, modelName
OllamaChatModel 本地 Ollama baseUrl, modelName

构建 DashScopeChatModel 示例:

java 复制代码
DashScopeChatModel model = DashScopeChatModel.builder()
    .apiKey("sk-xxx")                    // 必填
    .modelName("qwen-max")               // 模型名
    .endpointType(EndpointType.AUTO)     // AUTO / TEXT / MULTIMODAL
    .enableThinking(true)                // 启用思考模式(qwen-plus/qwen-max)
    .enableSearch(false)                 // 启用联网搜索
    .stream(true)                        // 是否流式
    .defaultOptions(GenerateOptions.builder()
        .temperature(0.7)
        .maxTokens(2000)
        .build())
    .proxy(ProxyConfig.http("proxy:8080"))
    .build();

3.4 GenerateOptions 生成参数

每次模型调用可覆盖的参数,Builder 支持所有主流参数:

java 复制代码
GenerateOptions options = GenerateOptions.builder()
    .temperature(0.7)            // 温度
    .topP(1.0)                   // Top-P 采样
    .maxTokens(4096)             // 最大输出 token
    .maxCompletionTokens(2048)   // 最大完成 token(OpenAI 风格)
    .topK(50)                    // Top-K 采样
    .seed(42L)                   // 随机种子
    .thinkingBudget(1000)        // 思考预算(Claude/Qwen)
    .reasoningEffort("medium")   // 推理强度(OpenAI o1)
    .frequencyPenalty(0.1)       // 频率惩罚
    .presencePenalty(0.1)        // 存在惩罚
    .parallelToolCalls(true)     // 并行工具调用
    .cacheControl(true)          // Prompt 缓存
    .executionConfig(ExecutionConfig.builder()
        .timeout(Duration.ofSeconds(60))
        .maxAttempts(3)
        .build())
    .toolChoice(...)             // 工具选择策略
    .responseFormat(...)         // 结构化输出格式
    .build();

3.5 ExecutionConfig 执行策略

控制模型调用的超时、重试和退避:

java 复制代码
ExecutionConfig config = ExecutionConfig.builder()
    .timeout(Duration.ofSeconds(60))     // 单次调用超时
    .maxAttempts(3)                      // 最大重试次数(含首次)
    .initialBackoff(Duration.ofMillis(100))  // 初始退避
    .maxBackoff(Duration.ofSeconds(10))      // 最大退避
    .backoffMultiplier(2.0)              // 退避倍增因子
    .retryOn(e -> isRetryableError(e))   // 自定义重试判断
    .build();

内置常量:

  • MODEL_DEFAULTS:模型调用默认策略(3 次重试,60s 超时,指数退避)
  • TOOL_DEFAULTS:工具执行默认策略(1 次,30s 超时)
  • RETRYABLE_ERRORS:内置可重试错误判断(5xx、超时、限流等)

3.6 ChatResponse 模型响应

java 复制代码
ChatResponse response = ChatResponse.builder()
    .id("chatcmpl-xxx")               // 响应 ID
    .content(List.of(TextBlock...))    // ContentBlock 列表
    .usage(ChatUsage.builder()         // Token 用量
        .inputTokens(156)
        .outputTokens(89)
        .build())
    .finishReason("stop")             // stop / length / tool_calls
    .metadata(Map.of(...))            // 额外元数据
    .build();

3.7 ChatUsage Token 用量

java 复制代码
public class ChatUsage {
    int getInputTokens();     // 输入 token
    int getOutputTokens();    // 输出 token
    int getTotalTokens();     // 总 token = input + output
    double getTime();         // 耗时(秒)
}

3.8 ModelRegistry 模型注册中心

全局静态注册表,支持按字符串名称解析模型:

java 复制代码
// 手动注册
ModelRegistry.register("my-model", myModelInstance);

// 注册工厂(延迟创建)
ModelRegistry.registerFactory("provider:", modelName -> { ... });

// 按名称解析(自动识别 provider:model 格式)
Model model = ModelRegistry.resolve("dashscope:qwen-max");
// → 自动找到 DashScopeChatModel,从环境变量 DASHSCOPE_API_KEY 读取密钥

// 内置支持的 provider:
//   dashscope: → DashScopeChatModel       (DASHSCOPE_API_KEY)
//   openai:    → OpenAIChatModel          (OPENAI_API_KEY)
//   anthropic: → AnthropicChatModel       (ANTHROPIC_API_KEY)
//   gemini:    → GeminiChatModel          (GEMINI_API_KEY)
//   ollama:    → OllamaChatModel          (OLLAMA_BASE_URL)

在 HarnessAgent 中可以直接用字符串指定模型:

java 复制代码
HarnessAgent.builder()
    .model("dashscope:qwen-max")    // ModelRegistry 自动解析
    .build();

3.9 ToolSchema 工具 Schema

工具定义传给 LLM 的 JSON Schema:

java 复制代码
ToolSchema schema = ToolSchema.builder()
    .name("get_weather")
    .description("获取城市天气")
    .parameters(Map.of(
        "type", "object",
        "properties", Map.of(
            "city", Map.of("type", "string", "description", "城市名称")
        ),
        "required", List.of("city")
    ))
    .build();

3.10 EndpointType 端点类型

DashScope 有三种端点模式:

枚举值 说明
AUTO 自动选择(默认)
TEXT 纯文本端点
MULTIMODAL 多模态端点(支持图片/文件)

3.11 使用示例

直接使用 Model :

java 复制代码
DashScopeChatModel model = DashScopeChatModel.builder()
    .apiKey(System.getenv("DASHSCOPE_API_KEY"))
    .modelName("qwen-plus")
    .stream(true)
    .build();

List<Msg> messages = List.of(
    Msg.builder().role(MsgRole.USER)
        .content(List.of(TextBlock.builder().text("你好").build()))
        .build()
);

model.stream(messages, List.of(), GenerateOptions.builder()
        .temperature(0.7).maxTokens(1000).build())
    .subscribe(response -> {
        response.getContent().forEach(block -> {
            if (block instanceof TextBlock text) {
                System.out.print(text.getText());
            }
        });
    });

通过 ModelRegistry 使用:

java 复制代码
// 一行解析(自动读取环境变量)
Model model = ModelRegistry.resolve("dashscope:qwen-max");

// 或手动注册
ModelRegistry.register("my-qwen",
    DashScopeChatModel.builder().apiKey("sk-xxx").modelName("qwen-plus").build());
Model model = ModelRegistry.resolve("my-qwen");

在 HarnessAgent 中使用:

java 复制代码
// 方式 1:传字符串,ModelRegistry 自动解析
HarnessAgent.builder()
    .model("dashscope:qwen-max")
    .build();

// 方式 2:传 Model 实例
HarnessAgent.builder()
    .model(DashScopeChatModel.builder().apiKey("sk-xxx").modelName("qwen-plus").build())
    .build();

自定义重试策略:

java 复制代码
ExecutionConfig retryConfig = ExecutionConfig.builder()
    .maxAttempts(5)
    .initialBackoff(Duration.ofSeconds(1))
    .maxBackoff(Duration.ofSeconds(30))
    .backoffMultiplier(2.0)
    .retryOn(e -> e.getMessage().contains("rate_limit"))
    .build();

// 注入到 ReActAgent
ReActAgent.builder()
    .model(model)
    .modelExecutionConfig(retryConfig)
    .build();
相关推荐
阿里云云原生7 分钟前
阿里云 AgentCore 产品负责人解读产品全景
云原生·agent
SL_staff12 分钟前
当规则引擎开始‘懂业务’:JVS-Rules金融风控四大原生能力拆解
java·python·全栈
Shaoshing23 分钟前
前缀和与差分
java·数据结构·算法·前缀和·差分
独立开发者阿乐33 分钟前
豆包 AI 搜索收录站点的必要条件
人工智能·geo优化·ai爬虫·llms.txt·悬赏问答·豆包收录
dd聊技术42 分钟前
Prompt 从代码常量搬进数据库:改一句话,不用再发一次版
java·后端
ACP广源盛1392462567344 分钟前
硬件选型笔记|国产 PCIe4.0 交换芯片 IX8024@ACP,AI 边缘节点本地存储扩展方案探讨
人工智能·硬件架构·硬件工程·pcie·国产芯片
ly76891 小时前
Spring Data MongoDB 批量写入实践:BulkOperations 批大小与写关注权衡
java·mongodb·spring·批量写入·bulkoperations·写关注·mongotemplate
10年前端老司机1 小时前
我用 Vue3 + LangGraph 做了个心理咨询 AI,踩了 9 个坑后总结出来的实战经验
前端·langchain·agent
奈落241 小时前
规则引擎还是大模型?AI 工作流与传统自动化的分工边界:确定性流程照旧,‘每次都不太一样‘的知识型工作才交给 AI
运维·人工智能·自动化·大模型·工作流·ai 办公
TAKETODAY1 小时前
Netty 是怎么把 HTTP 请求交给 MVC 的?一个请求的完整链路
java·netty