文章目录
- [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 的职责:
- 存储认证信息(
apiKey/baseUrl/host) - 通过
listModels()获取可用模型列表 - 通过
getChatModelClass()告知应创建哪种ChatModel
Model 的职责:
- 接收
Messages+ToolSchema→ 返回ChatResponse - 处理
HTTP/gRPC通信 - 管理
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();