14 KiB
代理服务
**本文档引用的文件** - [agent_service.rs](file://crates/agent_runner/src/proxy_agent/agent_service.rs) - [mod.rs](file://crates/agent_runner/src/proxy_agent/mod.rs) - [claude_code_agent.rs](file://crates/agent_runner/src/proxy_agent/claude_code_agent.rs) - [codex_agent.rs](file://crates/agent_runner/src/proxy_agent/codex_agent.rs) - [agent_stop_handle.rs](file://crates/agent_runner/src/proxy_agent/agent_stop_handle.rs) - [channel_utils.rs](file://crates/agent_runner/src/proxy_agent/channel_utils.rs) - [cleanup_task.rs](file://crates/agent_runner/src/proxy_agent/cleanup_task.rs) - [session_cache.rs](file://crates/agent_runner/src/service/session_cache.rs) - [docker_manager.rs](file://crates/docker_manager/src/manager.rs) - [docker_container_agent.rs](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs) - [main.rs](file://crates/agent_runner/src/main.rs) - [agent-abstraction-layer-design.md](file://specs/agent-abstraction-layer-design.md)目录
介绍
代理服务是AI开发平台的核心组件,负责管理AI代理的整个生命周期。该服务通过统一的接口抽象,支持多种AI代理类型(如Codex、Claude Code),并利用容器化技术实现资源隔离和高效管理。本文档详细阐述了代理服务的设计与实现,重点分析了AgentService结构体的核心作用、与Docker管理器的集成方式、异步任务调度机制以及错误恢复策略。
核心组件
代理服务的核心组件包括AgentService结构体、Docker管理器、会话缓存和清理任务。这些组件协同工作,确保AI代理的高效、稳定运行。AgentService结构体作为统一接口,封装了不同代理类型的启动和管理逻辑。Docker管理器负责容器的创建、启动和销毁,实现资源的动态分配和隔离。会话缓存用于存储和管理会话状态,支持SSE(Server-Sent Events)实时消息推送。清理任务则定期检查并清理闲置的代理实例,优化资源利用率。
代理服务设计与实现
代理服务的设计遵循模块化和可扩展的原则,通过定义清晰的接口和抽象,实现了不同代理类型的统一管理。核心是AcpAgentService trait,它定义了启动和管理ACP代理服务的统一接口。该trait的实现通过为AgentType枚举类型提供async_trait,实现了对不同代理类型的统一处理。
classDiagram
class AcpAgentService {
<<trait>>
+start_agent_service(chat_prompt : ChatPrompt, model_provider : Option~ModelProviderConfig~) Result~AcpConnectionInfo~
+agent_type_name() &'static str
}
class AgentType {
+Claude
+Codex
}
AcpAgentService <|-- AgentType
图源
AcpConnectionInfo结构体封装了与代理通信所需的关键信息,包括会话ID、用于发送提示的通道、用于发送取消通知的通道以及代理停止句柄。这种设计使得外部组件可以通过这些通道与代理进行异步通信,实现了非阻塞的消息传递。
本节源码
与Docker管理器的集成
代理服务通过docker_manager crate与Docker守护进程进行交互,实现了AI代理的容器化运行。DockerManager结构体作为核心管理器,封装了Docker客户端和配置信息,提供了创建、启动、停止和清理容器的高级接口。
sequenceDiagram
participant 代理服务
participant Docker管理器
participant Docker守护进程
代理服务->>Docker管理器 : create_container(config)
Docker管理器->>Docker守护进程 : 检查镜像是否存在
alt 镜像不存在
Docker守护进程-->>Docker管理器 : 返回不存在
Docker管理器->>Docker守护进程 : pull_image(image)
end
Docker管理器->>Docker守护进程 : create_container(options, config)
Docker守护进程-->>Docker管理器 : container_id
Docker管理器->>Docker守护进程 : start_container(container_id)
Docker守护进程-->>Docker管理器 : 启动成功
Docker管理器-->>代理服务 : DockerContainerInfo
图源
DockerManager的create_container方法是容器化运行AI代理实例的关键。该方法首先检查指定的镜像是否存在于本地,如果不存在则从远程仓库拉取。然后,它使用提供的配置创建容器,包括挂载点、环境变量、端口映射和资源限制。最后,启动容器并返回包含容器信息的DockerContainerInfo结构体。这种设计确保了每个AI代理实例都在独立的容器环境中运行,实现了资源隔离和安全防护。
本节源码
异步任务调度与会话管理
代理服务采用异步任务调度机制,通过tokio运行时和mpsc通道实现高效的并发处理。AcpAgentClient结构体实现了agent_client_protocol::Client trait,处理来自代理的会话通知。当收到session_notification时,它会解析通知内容,提取request_id,并将其与session_id关联,然后将更新推送到全局会话缓存。
flowchart TD
Start([收到session_notification]) --> ExtractSessionId["提取session_id"]
ExtractSessionId --> CheckMeta["检查meta中是否有request_id"]
CheckMeta --> |有| UseMetaId["使用meta中的request_id"]
CheckMeta --> |无| FindProjectId["通过session_id查找project_id"]
FindProjectId --> GetRequestId["从SESSION_REQUEST_CONTEXT获取request_id"]
GetRequestId --> |获取成功| UseContextId["使用context中的request_id"]
GetRequestId --> |获取失败| NoRequestId["未找到request_id"]
UseMetaId --> PushUpdate["推送AgentSessionUpdate"]
UseContextId --> PushUpdate
NoRequestId --> PushUpdate
PushUpdate --> End([完成])
图源
会话管理通过SESSION_CACHE和PROJECT_SESSION_MAP两个全局DashMap实现。SESSION_CACHE以session_id为键,存储SessionData,后者包含用于SSE消息推送的通道和取消令牌。PROJECT_SESSION_MAP则维护project_id到session_id的映射,确保一个项目只对应一个活跃的会话。push_session_update_with_project函数在推送消息时,会自动检查并清理旧的会话数据,保证了会话状态的一致性。
本节源码
错误恢复与生命周期管理
代理服务通过AgentLifecycleGuard结构体实现基于RAII(Resource Acquisition Is Initialization)原则的生命周期管理。当AgentLifecycleGuard被drop时,其内部的Drop实现会自动清理代理资源,如停止子进程和取消异步任务。这种设计简化了资源管理,避免了资源泄漏。
classDiagram
class AgentLifecycleGuard {
+new_claude(...) AgentLifecycleGuard
+new_codex(...) AgentLifecycleGuard
+graceful_stop() Result~()~
+cancel()
+is_stopped() bool
}
class AgentResources {
<<enumeration>>
+Claude
+CodexSubProcess
+CodexEmbedded
}
AgentLifecycleGuard --> AgentLifecycleInner : 包含
AgentLifecycleInner --> AgentResources : 包含
图源
AgentLifecycleGuard的graceful_stop方法实现了优雅停止代理的逻辑。它首先发送取消信号,然后根据代理类型执行相应的清理操作,如等待子进程退出或取消异步任务。cancel方法则用于非阻塞地发送取消信号。is_stopped方法检查代理是否已停止。这些方法共同构成了一个健壮的错误恢复机制,确保在各种异常情况下都能正确清理资源。
本节源码
与ACP适配器的交互模式
代理服务通过AcpAgentClient与ACP(Agent Client Protocol)适配器进行交互。AcpAgentClient实现了agent_client_protocol::Client trait,处理来自代理的各种请求,如权限请求、文件读写和会话通知。当代理需要执行文件操作时,AcpAgentClient会调用相应的tokio::fs函数,并将结果返回给代理。
sequenceDiagram
participant 代理
participant AcpAgentClient
participant 文件系统
代理->>AcpAgentClient : write_text_file(args)
AcpAgentClient->>文件系统 : create_dir_all(parent)
文件系统-->>AcpAgentClient : 创建成功
AcpAgentClient->>文件系统 : create_file(path)
文件系统-->>AcpAgentClient : 文件句柄
AcpAgentClient->>文件系统 : write_all(content)
文件系统-->>AcpAgentClient : 写入成功
AcpAgentClient-->>代理 : WriteTextFileResponse
图源
AcpAgentClient还负责处理会话通知,如AgentMessageChunk和AgentMessageComplete。它将这些通知转换为UnifiedSessionMessage,并通过push_session_update函数推送到会话缓存,最终通过SSE推送给前端客户端。这种交互模式实现了代理与外部系统的松耦合,提高了系统的可维护性和可扩展性。
本节源码
多代理类型支持
代理服务通过AgentType枚举和AcpAgentService trait的实现,支持多种代理类型,如Codex和Claude Code。AgentType枚举定义了不同的代理类型,而AcpAgentService trait的实现则为每种类型提供了具体的启动逻辑。
classDiagram
class AcpAgentService {
<<trait>>
+start_agent_service(...) Result~AcpConnectionInfo~
}
class AgentType {
+Claude
+Codex
}
AcpAgentService <|-- AgentType
class start_claude_code_acp_agent_service {
+command_path : &str
+command_args : Vec~String~
+spawn_args : Vec~String~
+merged_envs : HashMap~String, String~
}
class start_codex_acp_agent_service {
+command_path : &str
+cli_args : Vec~String~
+merged_envs : HashMap~String, String~
}
AgentType --> start_claude_code_acp_agent_service : 启动
AgentType --> start_codex_acp_agent_service : 启动
图源
start_claude_code_acp_agent_service和start_codex_acp_agent_service函数分别负责启动Claude Code和Codex代理。它们通过tokio::process::Command启动子进程,并建立ClientSideConnection进行通信。这些函数还处理环境变量和CLI参数的配置,确保代理能够正确初始化。这种设计实现了多代理类型的统一接口抽象,使得添加新的代理类型变得简单而直观。
本节源码
服务初始化与关闭逻辑
代理服务的初始化在main.rs文件的main函数中完成。它首先初始化遥测系统,然后解析命令行参数和配置文件。接着,它创建项目工作目录,并启动清理任务。最后,它创建HTTP服务器并监听指定端口。
flowchart TD
Start([main函数开始]) --> InitTelemetry["初始化遥测系统"]
InitTelemetry --> ParseArgs["解析命令行参数"]
ParseArgs --> LoadConfig["加载配置文件"]
LoadConfig --> CreateDir["创建项目工作目录"]
CreateDir --> StartCleanup["启动清理任务"]
StartCleanup --> SpawnWorker["启动agent_worker线程"]
SpawnWorker --> StartProxy["启动Pingora代理服务"]
StartProxy --> CreateRouter["创建HTTP路由"]
CreateRouter --> BindListener["绑定TCP监听器"]
BindListener --> Serve["启动HTTP服务器"]
Serve --> AwaitProxy["等待代理服务完成"]
AwaitProxy --> End([main函数结束])
图源
服务的关闭逻辑由tokio运行时的正常退出机制处理。当HTTP服务器停止时,main函数会等待代理服务完成,然后正常退出。清理任务和agent_worker线程也会随之停止。init_telemetry函数设置了全局的文本传播器,确保了trace_id的生成和传播,便于后续的性能分析和故障排查。
本节源码
结论
代理服务通过精心设计的架构和实现,成功地管理了AI代理的整个生命周期。它利用Rust的异步特性和类型系统,实现了高效、安全和可扩展的代理管理。与Docker管理器的集成确保了资源的隔离和安全,而异步任务调度和会话管理机制则保证了系统的高性能和实时性。错误恢复和生命周期管理策略进一步增强了系统的健壮性。通过统一的接口抽象,代理服务支持多种代理类型,为未来的扩展奠定了坚实的基础。整体而言,该服务是AI开发平台中不可或缺的核心组件,为用户提供了一个稳定、高效的AI代理运行环境。