附录:AgentBuilder 到 DeclAgentBuilder 迁移指南
本文档提供从手写 `AgentBuilder` 代码到声明式 `DeclAgentBuilder` 配置的迁移对照。适合已经用 `AgentBuilder` 构建了 Agent,希望将其配置外部化以便于维护和部署的场景。
迁移步骤概览
flowchart LR
A["现有代码<br/>(AgentBuilder)"] --> B[提取配置<br/>→ agent.yaml]
A --> C[保留 Rust 代码<br/>→ DeclAgentBuilder]
B --> D["一行加载<br/>DeclAgentBuilder::new()<br/>.from_yaml_file(...)<br/>.build()"]
C --> D
详细对照
模型配置
**AgentBuilder(手写)**:
use rust_agent_client::OpenAiChatClient;
let client = OpenAiChatClient::from_key(
&std::env::var("AGNES_API_KEY").unwrap(),
"agnes-2.0-flash",
)?;
let agent = AgentBuilder::new("my-agent")
.chat_client(client)
.instructions("你是一个助手。")
.build()?;
**DeclAgentBuilder(声明式 YAML)**:
# agent.yaml
kind: prompt
name: my-agent
model:
id: agnes-2.0-flash
provider: openai
connection:
kind: key
api_key: $AGNES_API_KEY
endpoint: https://apihub.agnes-ai.com/v1
instructions: 你是一个助手。
let agent = DeclAgentBuilder::new()
.from_yaml_file("agent.yaml")
.build()
.await?;
工具注册:内置工具
**AgentBuilder**:
use rust_agent_framework::tools::{ReadFile, WriteFile, RunCommand};
let agent = AgentBuilder::new("file-agent")
.chat_client(client)
.with_tool(ReadFile { scope: None })
.with_tool(WriteFile { scope: None })
.with_tool(RunCommand { scope: None, timeout_secs: Some(30) })
.build()?;
**DeclAgentBuilder**:
tools:
- kind: file
name: read_file
- kind: file
name: write_file
- kind: file
name: run_command
工具注册:自定义工具
**AgentBuilder**:
#[tool(description = "Echoes back the input text")]
struct Echo;
impl Echo {
async fn call(&self, arguments: serde_json::Value) -> Result<ToolResult> {
// ...
}
}
let agent = AgentBuilder::new("echo-agent")
.chat_client(client)
.with_tool(Echo)
.build()?;
**DeclAgentBuilder**:
tools:
- kind: function
name: echo
description: Echoes back the input text
let agent = DeclAgentBuilder::new()
.from_yaml_file("agent.yaml")
.with_tool("echo", |_| Ok(Arc::new(Echo)))
.build()
.await?;
工作区管理
**AgentBuilder**:
use rust_agent_core::{WorkspaceScope, ScopePolicy};
let scope = Arc::new(WorkspaceScope::new("/project", "my-project")
.with_policy(ScopePolicy::ApproveOutside));
let workspace = WorkspaceContextProvider::new(scope)
.add_tool(ReadFile::default())
.add_tool(WriteFile::default())
.add_tool(RunCommand::default());
let agent = AgentBuilder::new("workspace-agent")
.chat_client(client)
.add_context_provider(workspace)
.build()?;
**DeclAgentBuilder**:
contexts:
- kind: workspace
name: my-project
config:
root: /project
policy: approve
tools:
- kind: file
name: read_file
- kind: file
name: write_file
- kind: file
name: run_command
上下文提供器
**AgentBuilder**:
use rust_agent_framework::AgentSkillsProvider;
let skills = AgentSkillsProvider::scan("skills/code-review")?;
let agent = AgentBuilder::new("skills-agent")
.chat_client(client)
.add_context_provider(skills)
.build()?;
**DeclAgentBuilder**:
contexts:
- kind: skills
name: code-review
config:
directory: skills/code-review
压缩策略 & Token 计数
**AgentBuilder**:
let agent = AgentBuilder::new("agent")
.chat_client(client)
.with_compression_strategy(Arc::new(SlidingWindowStrategy::new(20)))
.with_token_counter(Arc::new(EstimateCounter))
.build()?;
**DeclAgentBuilder**:
压缩策略和 Token 计数器目前需通过混合模式注入(`with_context()` 传入自定义 Provider 实现压缩,或直接使用 `AgentBuilder` 构建后再手动设置)。声明式纯 YAML 支持将在后续版本中添加。
复合示例:多 Provider 合并
**AgentBuilder**:
let scope = Arc::new(WorkspaceScope::new("/project", "prod")
.with_policy(ScopePolicy::ApproveOutside));
let skills = AgentSkillsProvider::scan("skills/code-review")?;
let workspace = WorkspaceContextProvider::new(scope)
.add_tool(ReadFile::default());
let agent = AgentBuilder::new("full-agent")
.chat_client(client)
.add_context_provider(skills) // 顺序 1
.add_context_provider(workspace) // 顺序 2
.build()?;
**DeclAgentBuilder**:
contexts:
- kind: skills
name: code-review
config:
directory: skills/code-review
- kind: workspace
name: prod
config:
root: /project
policy: approve
> 声明式 `contexts` 数组中的顺序即 Provider 执行顺序。YAML 先声明的先执行。
运行模型切换
**AgentBuilder**:
// 切换模型需要重建 ChatClient 和 AgentBuilder
let client = OpenAiChatClient::from_key(&key, "agnes-2.0-flash")?;
let agent = AgentBuilder::new("agent")
.chat_client(client)
.build()?;
**DeclAgentBuilder**:
// 覆盖 YAML 中的模型,无需修改配置文件
let agent = DeclAgentBuilder::new()
.from_yaml_file("agent.yaml")
.with_model("agnes-2.0-flash")
.build()
.await?;
混合模式:YAML + 代码注入
不是所有配置都能/应放在 YAML 中。以下场景更适合混合模式:
let agent = DeclAgentBuilder::new()
.from_yaml_file("agent.yaml") // YAML 基础配置
.with_api_key(&env_key) // 运行时注入 API Key
.with_model("agnes-2.0-flash") // 运行时切换模型
.with_context(Arc::new(custom_prov)) // 注入 YAML 不支持的 Provider
.with_tool("my_tool", factory) // 注册自定义工具工厂
.max_tool_rounds(20) // 覆盖 YAML 中的 maxToolRounds
.build()
.await?;
**优先级规则**:`DeclAgentBuilder` 的运行时覆盖(`with_*` 方法)优先于 YAML 中的值。
常见迁移陷阱
| 陷阱 | 说明 | 解决方案 | |------|------|---------| | `function` 工具忘记 description | YAML 中内置工具无需 description,但 `function` 必须提供 | 添加 `description: ...` | | `maxToolRounds` 大小写 | YAML 用 camelCase,TOML 用 snake_case | JSON: `maxToolRounds` / TOML: `max_tool_rounds` | | ctx 种类不生效 | `mcp`/`knowledge`/`wiki` 在声明式路径需代码注入 | 使用 `with_context()` | | YAML 缩进错误 | YAML 对缩进敏感 | 使用 yamllint 检查 | | `$ENV_VAR` 未解析 | 运行时未设置环境变量 | 用 `with_api_key()` 覆盖 |