10.3 声明式 Agent/Workflow 配置
`rust-agent-decl` crate 提供了基于 JSON、YAML 和 TOML 格式的声明式 Agent 与 Workflow 定义系统,与 Microsoft Agent Framework (MAF) AgentSchema v1.0 完全兼容。
核心类型体系
classDiagram
class AgentDocument {
+Manifest(AgentManifest)
+Definition(AgentDefinition)
+from_json_str()
+from_yaml_str()
+from_toml_str()
+inner_definition() AgentDefinition
}
class AgentManifest {
+String name
+String display_name
+String description
+HashMap metadata
+AgentDefinition template
+PropertySchema parameters
+Vec~ManifestResource~ resources
}
class AgentDefinition {
+String name
+String display_name
+String description
+HashMap metadata
+PropertySchema input_schema
+PropertySchema output_schema
+AgentKindData kind_data
}
class AgentKindData {
<<enumeration>>
Prompt(PromptAgentData)
Workflow(WorkflowAgentData)
Container(ContainerAgentData)
}
class PromptAgentData {
+Model model
+Vec~ToolDecl~ tools
+Template template
+String instructions
+String additional_instructions
+usize max_tool_rounds
+Vec~AgentDefinition~ sub_agents
+Vec~ContextProviderDecl~ contexts
+CompressionDecl compression
+TokenCounterDecl token_counter
+HashMap sandbox
}
AgentDocument *-- AgentManifest
AgentDocument *-- AgentDefinition
AgentManifest *-- AgentDefinition
AgentDefinition *-- AgentKindData
AgentKindData *-- PromptAgentData
AgentKindData *-- WorkflowAgentData
AgentKindData *-- ContainerAgentData
AgentDocument — 顶层文档类型
`AgentDocument` 是一个 `#[serde(untagged)]` 枚举,可以接受两种形式:
- **Manifest**:完整的部署清单,包含模板和参数 - **Definition**:裸 Agent 定义,无 Manifest 包装
pub enum AgentDocument {
Manifest(AgentManifest),
Definition(AgentDefinition),
}
解析时,先检测是否存在 `template` 字段来判断是否为 Manifest,否则回退为 Definition。
AgentDefinition — Agent 统一定义
`AgentDefinition` 是所有 Agent 类型的统一载体,通过 `kind` 字段区分具体类型:
- `"prompt"` → `PromptAgentData`:基于 LLM 提示词的智能体 - `"workflow"` → `WorkflowAgentData`:工作流编排智能体 - `"hosted"` → `ContainerAgentData`:托管/容器化智能体
PromptAgentData — 提示词 Agent
这是最常用的 Agent 类型,包含:
- **model**:LLM 模型配置(Model 结构体,包含 id、connection、options) - **tools**:工具声明列表(ToolDecl,支持 7 种 MAF 工具类型) - **template**:提示词模板配置(Template 结构体) - **instructions**:系统指令文本 - **max_tool_rounds**:最大工具调用轮数(默认 10) - **contexts**:声明式上下文提供器(memory/skills/workspace/knowledge/wiki 等) - **compression** / **tokenCounter**:消息压缩策略(框架扩展,见 [3.5 压缩策略](../03-agent-engine/compression-strategies.md)) - **sandbox**:Agent 级代码沙箱默认(`kind: code` 工具继承)
多格式支持
通过 Cargo feature flags 控制格式支持:
[dependencies]
rust-agent-decl = { version = "0.1", features = ["json", "yaml", "toml"] }
| Feature | 格式 | 依赖 | |---------|------|------| | `json` (默认) | JSON | serde_json | | `yaml` | YAML | serde_yaml | | `toml` | TOML | toml | | `rhai` | Rhai 工作流/条件表达式 | rust-agent-rhai | | `web` | Web 搜索工具 | rust-agent-websearch | | `rag` | RAG 知识库上下文 | rust-agent-rag | | `wiki` | Wiki 知识库上下文 | rust-agent-wiki | | `openapi` | OpenAPI HTTP 工具 | rust-agent-openapi | | `openapi-validate` | OpenAPI 响应 JSON Schema 校验 | rust-agent-openapi/validate | | `sandbox` | 内置 code_interpreter 沙箱 | rust-agent-sandbox | | `sandbox-docker` | Docker/Podman 沙箱后端 | rust-agent-sandbox/docker | | `sandbox-wasm` | WASM 沙箱后端 | rust-agent-sandbox/wasm | | `mustache` | Mustache 模板 | mustache |
代码沙箱(`kind: code` / `ExecuteCode`)
# Agent 工具
tools:
- kind: code
name: code_interpreter
config:
backend: docker # process | container | docker | podman | wasm
timeout_secs: 60
memory_limit: 512m
cpus: "1.0"
pids_limit: 128
default_language: python
# Workflow 级默认 + ExecuteCode 动作
sandbox:
backend: process
timeout_secs: 30
trigger:
kind: OnConversationStart
id: start
actions:
- kind: ExecuteCode
code: print("hello")
language: python
output:
result: Local.stdout
解析示例
**JSON 格式**:
use rust_agent_decl::AgentDocument;
let doc = AgentDocument::from_json_file("agents/coding-agent.json")?;
let def = doc.inner_definition();
**YAML 格式**(需启用 `yaml` feature):
let yaml = r#"
kind: prompt
name: coding-agent
model:
id: agnes-2.0-flash
connection:
kind: key
api_key: $AGNES_API_KEY
instructions: 你是一个资深软件工程师。
tools:
- kind: function
name: read_file
description: 读取文件内容
"#;
let doc = AgentDocument::from_yaml_str(yaml)?;
**TOML 格式**(需启用 `toml` feature):
let doc = AgentDocument::from_toml_file("agents/agent.toml")?;
ToolResolver — 工具解析器
`ToolResolver` 负责将声明式工具定义解析为运行时的 `Arc<dyn ITool>` 实例。
支持的 MAF 工具类型(ToolResolver)
| 工具类型 | 状态 | 说明 | |---------|------|------| | `function` / `file` / `shell` / `web` | ✅ 已实现 | 内置框架工具 | | `code` | ✅ 已实现 | `code_interpreter`(需 `sandbox` feature,见 [13.9 代码沙箱](../13-extensions/sandbox.md)) | | `custom` | ✅ 需注册工厂 | `with_tool()` / `register_factory()` | | `mcp` | ✅ 已实现 | `rust-agent-mcp`,需预先 `register_mcp_server()` | | `openapi` | ✅ 已实现 | OpenAPI 3.x → HTTP 工具(需 `openapi` feature,见 [13.10](../13-extensions/openapi.md)) | | `file_search` | ❌ 未实现 | 需向量存储集成 |
使用示例
use rust_agent_decl::{ToolResolver, ToolDecl};
let mut resolver = ToolResolver::new();
// 注册自定义工具工厂
resolver.register_factory("my_tool", |config| {
// 从配置创建自定义工具
let param = config.get("param").and_then(|v| v.as_str());
Ok(Arc::new(MyCustomTool::new(param)))
});
// 解析工具声明
let tools = resolver.resolve_all(&agent_def.tools).await?;
MCP 工具解析
对于 `kind: mcp` 类型的工具声明,需要先注册 MCP 服务器:
use rust_agent_mcp::{McpServerClient, McpConnectionOptions};
// 连接并注册 MCP 服务器
let server = McpServerClient::connect(
McpConnectionOptions::stdio("mcp-filesystem-server", vec!["/work"]),
).await?;
resolver.register_mcp_server("stdio://filesystem-server", server);
// 现在 YAML 中声明的 mcp 工具可以正常解析
// tools:
// - kind: mcp
// name: read_file
// server_url: "stdio://filesystem-server"
// tool_name: read_file
let tools = resolver.resolve_all(&agent_def.tools).await?;
kind 字段溯源:声明式与运行时的双向映射
声明式配置中的 `kind` 字段并非凭空定义,而是与 RAF 运行时的 trait 方法**双向绑定**:
tools 节点的 kind 映射
`tools` 列表中每个工具的 `kind` 值**来源于 `ITool::kind()` 的返回值**。由 `#[tool(kind = "xxx")]` 宏属性在编译期注入:
| YAML/JSON `kind` | `ITool::kind()` 返回值 | 来源 | 说明 | |---|---|---|---| | `function` | `"function"` | `#[tool(kind = "function")]` | 用户注册的函数工具,**description 必须在 YAML 中提供** | | `custom` | `"custom"` | `#[tool(kind = "custom")]` | 工厂注册的自定义工具,**description 必须在 YAML 中提供** | | `web` | `"web"` | `#[tool(kind = "web")]` | 网络搜索/抓取工具,description 由宏内置 | | `file` | `"file"` | `#[tool(kind = "file")]` | 文件系统工具(11 个),description 由宏内置 | | `shell` | `"shell"` | `#[tool(kind = "shell")]` | Shell 命令执行,description 由宏内置 | | `skills` | `"skills"` | `#[tool(kind = "skills")]` | 技能加载和资源工具,description 由宏内置 | | `code` | `"code"` | `#[tool(kind = "code")]` | 代码解释器/沙箱,description 由宏内置 | | `mcp` | `"mcp"` | MCP 工具实现 | MCP 远程工具,description 由 MCP 服务器提供 | | `openapi` | `"openapi"` | OpenAPI 工具实现 | OpenAPI 规范工具 |
关键规则:何时需要写 description
| 工具类别 | `description` 字段 | 原因 | |---|---|---| | `web` / `file` / `shell` / `skills` / `code` | **无需配置** | `#[tool]` 宏在编译期硬编码了 description,`ToolResolver` 创建的实例自带描述 | | `function` / `custom` | **必须在 YAML 中提供** | 这两个类别由用户定义,没有内建描述 | | `mcp` | **无需配置** | 描述由远程 MCP 服务器的 `tools/list` 响应提供 |
# 正确:内置工具只需 name,description 由代码内建
tools:
- kind: file
name: read_file # ✅ 无需 description
- kind: web
name: web_search # ✅ 无需 description
# 正确:自定义工具必须提供 description
tools:
- kind: function
name: echo
description: 将输入文本原样返回 # ✅ 必须提供
- kind: custom
name: weather_lookup
description: 查询指定城市的天气 # ✅ 必须提供
contexts 节点的 kind 映射
`contexts` 列表中每个提供器的 `kind` 值**来源于 `IContextProvider::kind()` 的返回值**:
| YAML/JSON `kind` | `IContextProvider::kind()` 返回值 | 运行时 Provider | |---|---|---| | `memory` | `"memory"` | `SkillMemoryContextProvider` | | `skills` | `"skills"` | `AgentSkillsProvider` | | `mcp` | `"mcp"` | MCP Context Provider | | `workspace` | `"workspace"` | `WorkspaceContextProvider` | | `knowledge` | `"knowledge"` | RAG Knowledge Provider | | `wiki` | `"wiki"` | Wiki Knowledge Provider |
> **注意**:`history`(对话历史管理)由 `AgentBuilder` 内置自动注入 `InMemoryHistoryProvider`(kind = `"history"`),无需在 `contexts` 中声明。`websearch` 属于工具(`tools → kind: web`),不在此处配置。
扩展自定义 kind
如果你实现了 `IContextProvider` 并覆写了 `kind()` 返回自定义值,可以在 YAML 中通过 `with_context()` 注入:
struct MyCustomProvider;
impl IContextProvider for MyCustomProvider {
fn kind(&self) -> &str { "my_custom_kind" } // 自定义 kind
// ...
}
// 声明式构建时注入
let agent = DeclAgentBuilder::new()
.from_yaml_file("agent.yaml")
.with_context(Arc::new(MyCustomProvider))
.build().await?;
便捷函数
`DeclAgentBuilder` — 推荐入口
从 YAML/JSON/TOML 加载并构建 Agent,支持运行时覆盖、命名连接注册和沙箱默认:
use rust_agent_decl::DeclAgentBuilder;
let agent = DeclAgentBuilder::new()
.from_yaml_file("agents/my-agent.yaml")
.with_api_key(&std::env::var("OPENAI_API_KEY")?)
.with_connection("shared-openai", /* Connection */)
.build()
.await?;
等价的一行快捷方式:
let agent = DeclAgentBuilder::quick("agents/my-agent.yaml").await?;
> **`AgentResolver` / `quick_agent()`** 仍可用但已标记 `deprecated`,新代码请使用 `DeclAgentBuilder`。
完整的声明式配置示例
JSON 配置
{
"kind": "prompt",
"name": "coding-assistant",
"description": "代码助手智能体",
"model": {
"id": "agnes-2.0-flash",
"connection": {
"kind": "key",
"api_key": "$AGNES_API_KEY"
},
"options": {
"temperature": 0.3,
"maxTokens": 4096
}
},
"instructions": "你是资深软件工程师,专注于代码生成和审查。",
"tools": [
{
"kind": "function",
"name": "read_file",
"description": "读取文件内容"
},
{
"kind": "function",
"name": "write_file",
"description": "写入文件内容"
},
{
"kind": "function",
"name": "run_command",
"description": "执行 Shell 命令"
},
{
"kind": "web_search"
}
],
"maxToolRounds": 15,
"subAgents": [
{
"kind": "prompt",
"name": "code-reviewer",
"model": {
"id": "agnes-2.0-flash",
"connection": {
"kind": "key",
"api_key": "$AGNES_API_KEY"
}
},
"instructions": "你是代码审查专家。",
"tools": []
}
]
}
通过 DeclAgentBuilder 加载
use rust_agent_decl::{AgentDocument, DeclAgentBuilder};
async fn bootstrap() -> anyhow::Result<Arc<dyn IAgent>> {
DeclAgentBuilder::from_file("config/agent.json")
.build()
.await
.map_err(Into::into)
}
架构设计
flowchart LR
A[JSON/YAML/TOML 文件] --> B[AgentDocument]
B --> C[AgentDefinition]
C --> D[DeclAgentBuilder]
C --> E[compile_workflow]
C --> F[ToolResolver]
D --> G[Arc<dyn IAgent>]
E --> H[WorkflowGraph]
F --> I[Arc<dyn ITool>]
G --> J[AgentBuilder]
I --> J
J --> K[可运行的 Agent]
声明式配置系统的设计使得 RF 框架既能通过 Rust 代码进行强类型配置,也能通过外部配置文件实现热加载和动态部署。