14.4 Agent 注册与发现
`AgentRegistry` 是宿主服务的 Agent 注册中心,负责管理所有可用的 Agent 实例,并提供注册、查找、子 Agent 发现和声明式加载功能。
架构
graph TB
subgraph "Agent 来源"
BUILTIN[内置 Agent 工厂]
DECL[声明式 Agent 文件]
CUSTOM[自定义 Agent]
end
subgraph "AgentRegistry"
REG[agents: HashMap<AgentId, Arc<dyn IAgent>>]
DEF[default_id]
SEARCH[子 Agent 树遍历]
end
subgraph "客户端 API"
LIST[_raf/agent_list]
SUBL[_raf/subagent_list]
TREE[_raf/subagent_tree]
RESOLVE[resolve_agent]
end
BUILTIN --> REG
DECL --> REG
CUSTOM --> REG
REG --> LIST
REG --> SUBL
REG --> TREE
REG --> RESOLVE
AgentRegistry 核心 API
pub struct AgentRegistry {
agents: HashMap<AgentId, Arc<dyn IAgent>>,
default_id: Option<AgentId>,
}
impl AgentRegistry {
pub fn new() -> Self;
pub fn register(&mut self, agent: Arc<dyn IAgent>);
pub fn get(&self, id: &AgentId) -> Option<&Arc<dyn IAgent>>;
pub fn get_default(&self) -> Option<&Arc<dyn IAgent>>;
pub fn resolve_agent(&self, agent_id_override: Option<&str>) -> Option<Arc<dyn IAgent>>;
pub fn build_agent_list(&self) -> Vec<AgentInfo>;
pub fn get_subagent_list(&self, agent_id: &AgentId) -> Vec<SubAgentInfo>;
pub fn get_subagent_tree(&self, agent_id: &AgentId) -> Option<SubAgentNode>;
}
AgentInfo — 注册信息
pub struct AgentInfo {
pub id: String, // Agent 唯一标识符
pub agent_type: String, // Agent 类型标签
pub name: String, // 人类可读名称
pub description: String, // 功能描述
pub tool_names: Vec<String>, // 注册的工具列表
pub model_id: Option<String>, // 使用的模型 ID
pub capability_tags: Vec<String>, // 能力标签
pub has_subagents: bool, // 是否有子 Agent
pub is_default: bool, // 是否为默认 Agent
}
SubAgentInfo — 子 Agent 信息
pub struct SubAgentInfo {
pub id: String,
pub name: String,
pub agent_type: String,
pub description: String,
pub capability_tags: Vec<String>,
pub depth: usize, // 在 Agent 树中的深度
pub has_subagents: bool,
}
SubAgentNode — 树节点
pub struct SubAgentNode {
pub id: String,
pub name: String,
pub agent_type: String,
pub description: String,
pub capability_tags: Vec<String>,
pub children: Vec<SubAgentNode>, // 递归子节点
}
内置 Agent 工厂
`AgentFactory` 创建三种预设 Agent:
pub struct AgentFactory<'a> {
config: &'a HostConfig,
}
impl AgentFactory<'_> {
pub async fn create_all(&self) -> Result<Vec<Arc<dyn IAgent>>>;
fn create_coding_agent(&self) -> Result<Arc<dyn IAgent>>;
fn create_general_agent(&self) -> Result<Arc<dyn IAgent>>;
fn create_analysis_agent(&self) -> Result<Arc<dyn IAgent>>;
}
CodingAgent — 代码专家
fn create_coding_agent(&self) -> Result<Arc<dyn IAgent>> {
let agent = AgentBuilder::new("coding")
.chat_client(client)
.instructions("你是资深软件工程师...")
.with_description("代码专家智能体")
.with_tool(ReadFile::default())
.with_tool(WriteFile::default())
.with_tool(EditFile::default())
.with_tool(ListFiles::default())
.with_tool(SearchFile::default())
.with_tool(FindFiles::default())
.with_tool(RunCommand::default())
.max_tool_rounds(15)
.build()?;
Ok(agent)
}
GeneralAgent — 通用助手
fn create_general_agent(&self) -> Result<Arc<dyn IAgent>> {
let agent = AgentBuilder::new("general")
.chat_client(client)
.instructions("你是通用 AI 助手...")
.with_description("通用 AI 助手")
.max_tool_rounds(5)
.build()?;
Ok(agent)
}
AnalysisAgent — 数据分析师
fn create_analysis_agent(&self) -> Result<Arc<dyn IAgent>> {
let agent = AgentBuilder::new("analysis")
.chat_client(client)
.instructions("你是数据分析师...")
.with_description("数据分析师")
.with_tool(ReadFile::default())
.max_tool_rounds(10)
.build()?;
Ok(agent)
}
声明式 Agent 加载
从 JSON/YAML/TOML 文件加载 Agent:
use rust_agent_decl::DeclAgentBuilder;
async fn load_declarative_agents(
agents_dir: &str,
) -> anyhow::Result<Vec<Arc<dyn IAgent>>> {
let mut agents = Vec::new();
for entry in walkdir::WalkDir::new(agents_dir) {
let entry = entry?;
if entry.file_type().is_file() {
let path = entry.path();
let agent = DeclAgentBuilder::from_file(path).build().await?;
agents.push(agent);
}
}
Ok(agents)
}
配置 Agent 预设
通过配置文件控制哪些内置 Agent 被创建:
[agents]
coding = true
general = true
analysis = false # 禁用分析 Agent
子 Agent 树发现
树遍历算法
fn build_subagent_node(&self, agent: &Arc<dyn IAgent>) -> SubAgentNode {
let meta = agent.metadata();
let mut children = Vec::new();
// 遍历所有已注册 Agent,检查是否为当前 Agent 的子 Agent
for (child_id, child_agent) in &self.agents {
if agent.get_subagent(child_id).is_some() {
children.push(self.build_subagent_node(child_agent));
}
}
SubAgentNode {
id: agent.id().to_string(),
name: meta.key.clone(),
agent_type: meta.agent_type.clone(),
description: meta.description.clone(),
capability_tags: meta.capability_tags.clone(),
children,
}
}
Agent 解析策略
`resolve_agent()` 的查找顺序:
1. **直接查找**:通过 `AgentId` 直接匹配 2. **子 Agent 遍历**:在所有父 Agent 上调用 `get_subagent()` 3. **默认回退**:返回第一个注册的默认 Agent
pub fn resolve_agent(&self, agent_id_override: Option<&str>) -> Option<Arc<dyn IAgent>> {
if let Some(id_str) = agent_id_override {
let id = AgentId::new(id_str);
// 1. 直接查找
if let Some(agent) = self.agents.get(&id) {
return Some(agent.clone());
}
// 2. 子 Agent 遍历
for parent in self.agents.values() {
if let Some(sub) = parent.get_subagent(&id) {
return Some(sub);
}
}
}
// 3. 默认回退
self.get_default().cloned()
}
ACP 集成
Initialize 响应
// 构建 _meta.raf.agents 列表
let agent_list = registry.build_agent_list_meta();
// 注入到 initialize 响应
let mut resp = InitializeResponse::new(req.protocol_version)
.agent_capabilities(caps);
resp.meta = Some(agent_list);
响应格式:
{
"_meta": {
"raf": {
"version": "0.1.0",
"agents": [
{
"id": "coding",
"agent_type": "CodingAgent",
"name": "coding",
"description": "代码专家智能体",
"tool_names": ["read_file", "write_file", "run_command"],
"has_subagents": true,
"is_default": true
}
]
}
}
}
Session 创建时的 Agent 选择
// 从 NewSessionRequest._meta.raf.agent_id 获取目标 Agent
let target_agent = req.meta.as_ref()
.and_then(|m| m.get("raf.agent_id"))
.and_then(|v| v.as_str());
let sid = uuid::Uuid::new_v4().to_string();
session_bridge.create_session(&sid, target_agent).await;