添加qiming-rcoder模块
This commit is contained in:
299
qiming-rcoder/.qoder/repowiki/zh/content/数据模型与类型/HTTP结果模型.md
Normal file
299
qiming-rcoder/.qoder/repowiki/zh/content/数据模型与类型/HTTP结果模型.md
Normal file
@@ -0,0 +1,299 @@
|
||||
# HTTP结果模型
|
||||
|
||||
<cite>
|
||||
**本文引用的文件**
|
||||
- [http_result.rs](file://crates/shared_types/src/model/http_result.rs)
|
||||
- [app_error.rs](file://crates/shared_types/src/model/app_error.rs)
|
||||
- [lib.rs](file://crates/shared_types/src/lib.rs)
|
||||
- [agent_status_handler.rs(rcoder)](file://crates/rcoder/src/handler/agent_status_handler.rs)
|
||||
- [router.rs(rcoder)](file://crates/rcoder/src/router.rs)
|
||||
- [agent_status_handler.rs(agent_runner)](file://crates/agent_runner/src/handler/agent_status_handler.rs)
|
||||
- [router.rs(agent_runner)](file://crates/agent_runner/src/router.rs)
|
||||
- [chat_response.rs](file://crates/shared_types/src/model/chat_response.rs)
|
||||
- [agent_model.rs](file://crates/shared_types/src/model/agent_model.rs)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [简介](#简介)
|
||||
2. [项目结构](#项目结构)
|
||||
3. [核心组件](#核心组件)
|
||||
4. [架构总览](#架构总览)
|
||||
5. [详细组件分析](#详细组件分析)
|
||||
6. [依赖关系分析](#依赖关系分析)
|
||||
7. [性能考量](#性能考量)
|
||||
8. [故障排查指南](#故障排查指南)
|
||||
9. [结论](#结论)
|
||||
10. [附录](#附录)
|
||||
|
||||
## 简介
|
||||
本文件围绕HTTP结果模型展开,重点说明统一响应格式的设计理念、成功与失败路径的处理逻辑,并结合Axum处理器的返回类型使用,系统性地介绍HttpResult<T>泛型结果类型与AppError错误体系。文档同时梳理错误码与触发条件、错误上下文信息收集机制、序列化输出示例以及客户端错误处理建议,帮助开发者在不同服务中一致地构建标准化API响应。
|
||||
|
||||
## 项目结构
|
||||
- 共享类型位于 crates/shared_types,其中定义了HttpResult<T>与AppError等跨服务通用模型。
|
||||
- rcoder与agent_runner两个服务各自实现了Axum路由与处理器,广泛采用HttpResult<T>作为成功响应,AppError作为错误响应。
|
||||
- 通过lib.rs统一导出共享类型,便于服务间复用。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "共享类型"
|
||||
SR["shared_types/lib.rs<br/>统一导出"]
|
||||
HR["model/http_result.rs<br/>HttpResult<T>"]
|
||||
AE["model/app_error.rs<br/>AppError 错误体系"]
|
||||
end
|
||||
subgraph "rcoder 服务"
|
||||
RR["rcoder/router.rs<br/>路由注册"]
|
||||
RH["rcoder/handler/agent_status_handler.rs<br/>处理器示例"]
|
||||
end
|
||||
subgraph "agent_runner 服务"
|
||||
AR["agent_runner/router.rs<br/>路由注册"]
|
||||
AH["agent_runner/handler/agent_status_handler.rs<br/>处理器示例"]
|
||||
end
|
||||
SR --> HR
|
||||
SR --> AE
|
||||
RR --> RH
|
||||
AR --> AH
|
||||
RH --> HR
|
||||
AH --> HR
|
||||
RH --> AE
|
||||
AH --> AE
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [lib.rs](file://crates/shared_types/src/lib.rs#L15-L53)
|
||||
- [http_result.rs](file://crates/shared_types/src/model/http_result.rs#L24-L103)
|
||||
- [app_error.rs](file://crates/shared_types/src/model/app_error.rs#L1-L65)
|
||||
- [router.rs(rcoder)](file://crates/rcoder/src/router.rs#L52-L84)
|
||||
- [agent_status_handler.rs(rcoder)](file://crates/rcoder/src/handler/agent_status_handler.rs#L72-L132)
|
||||
- [router.rs(agent_runner)](file://crates/agent_runner/src/router.rs#L41-L70)
|
||||
- [agent_status_handler.rs(agent_runner)](file://crates/agent_runner/src/handler/agent_status_handler.rs#L70-L122)
|
||||
|
||||
章节来源
|
||||
- [lib.rs](file://crates/shared_types/src/lib.rs#L15-L53)
|
||||
- [router.rs(rcoder)](file://crates/rcoder/src/router.rs#L52-L84)
|
||||
- [router.rs(agent_runner)](file://crates/agent_runner/src/router.rs#L41-L70)
|
||||
|
||||
## 核心组件
|
||||
- HttpResult<T>:统一的成功/失败响应载体,包含业务字段code、message、data、tid以及运行时计算的success布尔值。成功路径通过success(data)构造,失败路径通过error(code, message)或internal_error(message)构造。序列化时自动注入success字段,Axum IntoResponse实现负责HTTP状态码与Content-Type设置。
|
||||
- AppError:统一的错误类型,封装anyhow、IO与通用错误,提供generic、internal_server_error、validation_error等便捷构造方法。其IntoResponse实现将错误标准化为包含error.code与error.message的对象,状态码固定为500。
|
||||
|
||||
章节来源
|
||||
- [http_result.rs](file://crates/shared_types/src/model/http_result.rs#L24-L103)
|
||||
- [app_error.rs](file://crates/shared_types/src/model/app_error.rs#L1-L65)
|
||||
|
||||
## 架构总览
|
||||
下图展示了Axum处理器与统一响应模型之间的交互关系,以及错误路径与成功路径的分流。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant C as "客户端"
|
||||
participant R as "Axum 路由"
|
||||
participant H as "处理器"
|
||||
participant S as "业务逻辑"
|
||||
participant OK as "HttpResult<T>"
|
||||
participant ERR as "AppError"
|
||||
C->>R : "HTTP 请求"
|
||||
R->>H : "调用处理器"
|
||||
H->>S : "执行业务逻辑"
|
||||
alt "成功"
|
||||
S-->>H : "返回数据"
|
||||
H->>OK : "构造 HttpResult : : success(data)"
|
||||
OK-->>R : "IntoResponse"
|
||||
R-->>C : "200 OK + JSON"
|
||||
else "失败"
|
||||
S-->>H : "返回错误"
|
||||
H->>ERR : "构造 AppError 或返回错误"
|
||||
ERR-->>R : "IntoResponse"
|
||||
R-->>C : "500 Internal Server Error + JSON"
|
||||
end
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [agent_status_handler.rs(rcoder)](file://crates/rcoder/src/handler/agent_status_handler.rs#L72-L132)
|
||||
- [http_result.rs](file://crates/shared_types/src/model/http_result.rs#L77-L103)
|
||||
- [app_error.rs](file://crates/shared_types/src/model/app_error.rs#L33-L57)
|
||||
|
||||
## 详细组件分析
|
||||
|
||||
### HttpResult<T> 泛型结果类型
|
||||
- 设计理念
|
||||
- 统一响应格式:所有API响应均包含code、message、data、tid与success字段,便于前端统一解析与展示。
|
||||
- 成功路径:success(data)构造,code默认“0000”,success=true。
|
||||
- 失败路径:error(code, message)构造,success=false;internal_error(message)为内部错误的快捷方式。
|
||||
- 上下文追踪:自动从OpenTelemetry上下文提取trace_id,若无则置空,便于日志与链路追踪。
|
||||
- 序列化策略:自定义Serialize实现,显式写出5个字段,其中success根据code是否为“0000”动态计算。
|
||||
- 响应适配:实现IntoResponse,优先返回JSON,序列化失败时降级为500与纯文本。
|
||||
|
||||
- 关键行为与复杂度
|
||||
- 构造函数O(1),序列化O(n)(n为data序列化开销),IntoResponse序列化O(1)+序列化开销。
|
||||
- trace_id提取依赖当前span上下文,若无效则返回None,不影响响应正确性。
|
||||
|
||||
- 使用建议
|
||||
- 成功场景:优先使用success(data)返回结构化数据。
|
||||
- 失败场景:明确错误码与message,避免使用internal_error除非无法确定具体原因。
|
||||
- 数据为空:data字段可为None,但需保证业务语义清晰。
|
||||
|
||||
章节来源
|
||||
- [http_result.rs](file://crates/shared_types/src/model/http_result.rs#L24-L103)
|
||||
|
||||
### AppError 错误体系
|
||||
- 设计理念
|
||||
- 统一错误抽象:通过枚举封装常见错误来源,便于集中处理与上报。
|
||||
- 易于扩展:支持From实现,如tokio mpsc SendError的转换,便于在异步通道中传播错误。
|
||||
- 标准化输出:IntoResponse固定返回500状态码与包含error.code与error.message的对象,便于前端统一处理。
|
||||
|
||||
- 错误分类与构造
|
||||
- AnyhowError:包装底层异常,便于上抛。
|
||||
- IoError:包装IO错误。
|
||||
- Generic:通用错误,支持validation_error与internal_server_error等便捷方法。
|
||||
|
||||
- 使用建议
|
||||
- 业务层尽量将错误转换为明确的错误码与message,必要时使用AppError::Generic承载。
|
||||
- 对于可恢复的业务错误,优先返回HttpResult::error(...)而非抛出AppError,以便客户端区分业务错误与系统错误。
|
||||
|
||||
章节来源
|
||||
- [app_error.rs](file://crates/shared_types/src/model/app_error.rs#L1-L65)
|
||||
|
||||
### Axum处理器中的返回类型使用
|
||||
- 返回类型约定
|
||||
- 成功:Result<HttpResult<T>, AppError>,处理器返回Ok(HttpResult::success(...))或Ok(HttpResult::error(...))。
|
||||
- 失败:Result<HttpResult<T>, AppError>,处理器返回Err(AppError::...)或Ok(HttpResult::error(...))。
|
||||
- 示例:rcoder与agent_runner的agent_status处理器均采用该模式,先做参数校验,再构造AgentStatusResponse并返回HttpResult.success(...),或在参数非法时返回HttpResult.error(...)。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start(["进入处理器"]) --> Validate["校验输入参数"]
|
||||
Validate --> Valid{"参数有效?"}
|
||||
Valid --> |否| BuildErr["构造 HttpResult::error(code, message)"]
|
||||
BuildErr --> ReturnErr["返回 Ok(HttpResult::error)"]
|
||||
Valid --> |是| DoBiz["执行业务逻辑"]
|
||||
DoBiz --> BizOK{"业务成功?"}
|
||||
BizOK --> |否| BuildBizErr["构造 HttpResult::error(code, message)"]
|
||||
BuildBizErr --> ReturnBizErr["返回 Ok(HttpResult::error)"]
|
||||
BizOK --> |是| BuildData["构造响应数据"]
|
||||
BuildData --> ReturnOk["返回 Ok(HttpResult::success(data))"]
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [agent_status_handler.rs(rcoder)](file://crates/rcoder/src/handler/agent_status_handler.rs#L72-L132)
|
||||
- [agent_status_handler.rs(agent_runner)](file://crates/agent_runner/src/handler/agent_status_handler.rs#L70-L122)
|
||||
|
||||
章节来源
|
||||
- [agent_status_handler.rs(rcoder)](file://crates/rcoder/src/handler/agent_status_handler.rs#L72-L132)
|
||||
- [agent_status_handler.rs(agent_runner)](file://crates/agent_runner/src/handler/agent_status_handler.rs#L70-L122)
|
||||
|
||||
### 错误码与触发条件
|
||||
- 内置错误码
|
||||
- “0000”:成功。
|
||||
- “5000”:内部错误(internal_error(message)构造)。
|
||||
- 业务错误码示例
|
||||
- “INVALID_PARAMS”:参数校验失败(例如agent_status处理器对project_id为空的处理)。
|
||||
- “INVALID_SESSION”:会话无效(OpenAPI示例中出现)。
|
||||
- “SESSION_NOT_FOUND”:会话不存在(OpenAPI示例中出现)。
|
||||
- 触发条件
|
||||
- 参数校验失败:处理器在进入业务逻辑前进行参数校验,不符合要求时返回HttpResult::error(...)。
|
||||
- 业务状态异常:如Agent不存在、会话不存在等,返回相应错误码与message。
|
||||
- 系统异常:无法预期的错误,使用AppError或HttpResult::internal_error(...)。
|
||||
|
||||
章节来源
|
||||
- [agent_status_handler.rs(rcoder)](file://crates/rcoder/src/handler/agent_status_handler.rs#L72-L132)
|
||||
- [agent_status_handler.rs(agent_runner)](file://crates/agent_runner/src/handler/agent_status_handler.rs#L70-L122)
|
||||
- [http_result.rs](file://crates/shared_types/src/model/http_result.rs#L36-L58)
|
||||
|
||||
### 错误上下文信息收集机制
|
||||
- trace_id采集
|
||||
- HttpResult<T>在构造时与IntoResponse阶段均可从OpenTelemetry上下文提取trace_id,若当前span无效则置空。
|
||||
- 该机制确保每个响应具备可追踪的链路标识,便于日志聚合与问题定位。
|
||||
- 请求ID(request_id)
|
||||
- 在聊天响应等结构中提供request_id字段,用于标识与追踪请求,便于跨服务关联。
|
||||
- 会话消息中的错误字段
|
||||
- 会话通知结构中包含错误信息字段,便于在SSE流中传递错误详情。
|
||||
|
||||
章节来源
|
||||
- [http_result.rs](file://crates/shared_types/src/model/http_result.rs#L8-L22)
|
||||
- [chat_response.rs](file://crates/shared_types/src/model/chat_response.rs#L1-L18)
|
||||
- [agent_model.rs](file://crates/shared_types/src/model/agent_model.rs#L71-L97)
|
||||
|
||||
### 序列化输出示例
|
||||
- 成功响应(示例结构)
|
||||
- 字段:code、message、data、tid、success
|
||||
- data为对象或数组时,success为true;data为null时,success仍为true
|
||||
- 失败响应(示例结构)
|
||||
- 字段:code、message、data为null、tid、success为false
|
||||
- 或AppError的标准化错误对象(error.code与error.message)
|
||||
|
||||
章节来源
|
||||
- [http_result.rs](file://crates/shared_types/src/model/http_result.rs#L61-L74)
|
||||
- [app_error.rs](file://crates/shared_types/src/model/app_error.rs#L33-L57)
|
||||
|
||||
### 客户端错误处理建议
|
||||
- 成功与失败路径区分
|
||||
- 优先依据success字段判断整体成功与否;若为false,读取error.code与error.message进行分支处理。
|
||||
- 错误码映射
|
||||
- 将“0000”视为成功;“5000”视为内部错误,提示用户稍后重试或上报工单。
|
||||
- “INVALID_PARAMS”、“INVALID_SESSION”、“SESSION_NOT_FOUND”等业务错误码用于提示用户修正输入或重新发起请求。
|
||||
- 上下文追踪
|
||||
- 记录并回传tid,便于服务端定位问题;在客户端日志中附带request_id,便于跨服务关联。
|
||||
- 降级与重试
|
||||
- 对瞬时性错误(如网络抖动)建议客户端进行指数退避重试;对参数类错误直接提示用户修正。
|
||||
|
||||
## 依赖关系分析
|
||||
- 组件耦合
|
||||
- HttpResult<T>与AppError均为共享类型,rcoder与agent_runner通过lib.rs统一导出使用,降低重复实现与耦合。
|
||||
- 处理器依赖共享类型,路由层仅负责注册与文档生成,职责清晰。
|
||||
- 外部依赖
|
||||
- OpenTelemetry与tracing用于trace_id采集与日志追踪。
|
||||
- serde、utoipa用于序列化与OpenAPI文档生成。
|
||||
- axum用于HTTP响应适配与IntoResponse实现。
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
HR["HttpResult<T>"] --> AX["axum::response::IntoResponse"]
|
||||
HR --> OT["opentelemetry/tracing"]
|
||||
HR --> SD["serde"]
|
||||
AE["AppError"] --> AX
|
||||
AE --> TH["thiserror"]
|
||||
RC["rcoder/handler/*"] --> HR
|
||||
RC --> AE
|
||||
AR["agent_runner/handler/*"] --> HR
|
||||
AR --> AE
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [http_result.rs](file://crates/shared_types/src/model/http_result.rs#L1-L103)
|
||||
- [app_error.rs](file://crates/shared_types/src/model/app_error.rs#L1-L65)
|
||||
- [lib.rs](file://crates/shared_types/src/lib.rs#L15-L53)
|
||||
|
||||
章节来源
|
||||
- [lib.rs](file://crates/shared_types/src/lib.rs#L15-L53)
|
||||
|
||||
## 性能考量
|
||||
- 序列化成本
|
||||
- HttpResult<T>的序列化为结构体序列化,主要开销取决于data的大小;建议在成功路径仅返回必要字段,避免冗余数据。
|
||||
- IntoResponse路径
|
||||
- 成功路径返回200+JSON,失败路径返回500+JSON;序列化失败时降级为500+纯文本,避免中间件异常。
|
||||
- trace_id采集
|
||||
- trace_id提取依赖当前span上下文,若无上下文则跳过,不会引入额外开销。
|
||||
|
||||
## 故障排查指南
|
||||
- 常见问题
|
||||
- 响应未携带success字段:确认使用HttpResult<T>而非自定义结构体。
|
||||
- 错误响应格式不一致:统一使用AppError或HttpResult::error(...),避免混合返回。
|
||||
- trace_id缺失:检查OpenTelemetry中间件是否正确注入span上下文。
|
||||
- 定位步骤
|
||||
- 根据tid在日志系统中检索对应链路。
|
||||
- 结合request_id在聊天/会话相关接口中定位具体请求。
|
||||
- 对业务错误码进行聚合统计,识别高频错误与潜在输入问题。
|
||||
|
||||
## 结论
|
||||
通过HttpResult<T>与AppError的组合,系统实现了统一、可观测、易维护的API响应模型。成功与失败路径清晰分离,错误码与上下文信息完整,配合Axum的IntoResponse实现,能够稳定地输出标准化响应。建议在所有新接口中遵循该模式,以提升客户端体验与运维效率。
|
||||
|
||||
## 附录
|
||||
- 统一导出入口
|
||||
- shared_types::lib.rs统一导出HttpResult与AppError,便于服务间复用。
|
||||
- OpenAPI示例
|
||||
- rcoder与agent_runner的OpenAPI文档中对HttpResult<T>进行了标注与示例展示,便于客户端理解响应结构。
|
||||
|
||||
章节来源
|
||||
- [lib.rs](file://crates/shared_types/src/lib.rs#L15-L53)
|
||||
- [router.rs(rcoder)](file://crates/rcoder/src/router.rs#L86-L151)
|
||||
- [router.rs(agent_runner)](file://crates/agent_runner/src/router.rs#L72-L128)
|
||||
393
qiming-rcoder/.qoder/repowiki/zh/content/数据模型与类型/gRPC数据模型.md
Normal file
393
qiming-rcoder/.qoder/repowiki/zh/content/数据模型与类型/gRPC数据模型.md
Normal file
@@ -0,0 +1,393 @@
|
||||
# gRPC数据模型
|
||||
|
||||
<cite>
|
||||
**本文引用的文件**
|
||||
- [agent.proto](file://crates/shared_types/proto/agent.proto)
|
||||
- [agent.rs](file://crates/shared_types/src/grpc/agent.rs)
|
||||
- [build.rs](file://crates/shared_types/build.rs)
|
||||
- [lib.rs](file://crates/shared_types/src/lib.rs)
|
||||
- [agent_service.rs](file://crates/agent_runner/src/proxy_agent/agent_service.rs)
|
||||
- [acp_agent.rs](file://crates/agent_runner/src/proxy_agent/acp_agent.rs)
|
||||
- [chat_handler.rs](file://crates/agent_runner/src/handler/chat_handler.rs)
|
||||
- [router.rs](file://crates/agent_runner/src/router.rs)
|
||||
- [Cargo.toml](file://Cargo.toml)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [简介](#简介)
|
||||
2. [项目结构](#项目结构)
|
||||
3. [核心组件](#核心组件)
|
||||
4. [架构总览](#架构总览)
|
||||
5. [详细组件分析](#详细组件分析)
|
||||
6. [依赖分析](#依赖分析)
|
||||
7. [性能考虑](#性能考虑)
|
||||
8. [故障排查指南](#故障排查指南)
|
||||
9. [结论](#结论)
|
||||
10. [附录](#附录)
|
||||
|
||||
## 简介
|
||||
本文件围绕 agent.proto 协议生成的 Rust gRPC 数据模型,系统性阐述 Protobuf 消息类型(如 AgentRequest、AgentResponse)的字段定义与语义;解释 gRPC 服务接口与 ACP 协议的映射关系,重点覆盖流式调用 SubscribeProgress 的实现细节;提供序列化性能分析、版本兼容性策略与协议扩展指南;并结合 agent_runner 的实际调用场景,展示客户端与服务端之间的数据交换模式。
|
||||
|
||||
## 项目结构
|
||||
- 协议定义位于 shared_types/proto/agent.proto,描述 gRPC 服务与消息类型。
|
||||
- 生成的 Rust gRPC 客户端与服务端代码位于 shared_types/src/grpc/agent.rs。
|
||||
- 构建脚本 build.rs 使用 tonic-prost-build 将 .proto 编译为 Rust。
|
||||
- agent_runner 通过 HTTP 路由与 ACP 代理协作,间接消费 gRPC 数据模型。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "shared_types"
|
||||
P["proto/agent.proto"]
|
||||
G["src/grpc/agent.rs"]
|
||||
L["src/lib.rs"]
|
||||
B["build.rs"]
|
||||
end
|
||||
subgraph "agent_runner"
|
||||
H["handler/chat_handler.rs"]
|
||||
R["router.rs"]
|
||||
A["proxy_agent/acp_agent.rs"]
|
||||
S["proxy_agent/agent_service.rs"]
|
||||
end
|
||||
P --> B --> G
|
||||
L --> G
|
||||
H --> A
|
||||
A --> S
|
||||
R --> H
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [agent.proto](file://crates/shared_types/proto/agent.proto#L1-L98)
|
||||
- [agent.rs](file://crates/shared_types/src/grpc/agent.rs#L1-L651)
|
||||
- [build.rs](file://crates/shared_types/build.rs#L1-L14)
|
||||
- [lib.rs](file://crates/shared_types/src/lib.rs#L1-L71)
|
||||
- [chat_handler.rs](file://crates/agent_runner/src/handler/chat_handler.rs#L1-L321)
|
||||
- [router.rs](file://crates/agent_runner/src/router.rs#L1-L200)
|
||||
- [acp_agent.rs](file://crates/agent_runner/src/proxy_agent/acp_agent.rs#L1-L392)
|
||||
- [agent_service.rs](file://crates/agent_runner/src/proxy_agent/agent_service.rs#L1-L62)
|
||||
|
||||
章节来源
|
||||
- [agent.proto](file://crates/shared_types/proto/agent.proto#L1-L98)
|
||||
- [agent.rs](file://crates/shared_types/src/grpc/agent.rs#L1-L651)
|
||||
- [build.rs](file://crates/shared_types/build.rs#L1-L14)
|
||||
- [lib.rs](file://crates/shared_types/src/lib.rs#L1-L71)
|
||||
- [chat_handler.rs](file://crates/agent_runner/src/handler/chat_handler.rs#L1-L321)
|
||||
- [router.rs](file://crates/agent_runner/src/router.rs#L1-L200)
|
||||
- [acp_agent.rs](file://crates/agent_runner/src/proxy_agent/acp_agent.rs#L1-L392)
|
||||
- [agent_service.rs](file://crates/agent_runner/src/proxy_agent/agent_service.rs#L1-L62)
|
||||
|
||||
## 核心组件
|
||||
- gRPC 服务与消息
|
||||
- 服务:AgentService,包含 Chat、SubscribeProgress(Server Streaming)、CancelSession、GetStatus 四个 RPC。
|
||||
- 消息:ChatRequest、ChatResponse、ProgressRequest、ProgressEvent、CancelRequest、CancelResponse、GetStatusRequest、GetStatusResponse、ModelProviderConfig、Attachment。
|
||||
- 生成代码
|
||||
- 通过 build.rs 调用 tonic-prost-build,生成客户端与服务端桩代码,位于 shared_types/src/grpc/agent.rs。
|
||||
- ACP 协议映射
|
||||
- agent_runner 通过 HTTP 路由与 ACP 代理协作,将 ChatRequest/Response 与 ACP 的 PromptRequest/PromptResponse 对接,实现会话进度的 SSE 通知与取消控制。
|
||||
|
||||
章节来源
|
||||
- [agent.proto](file://crates/shared_types/proto/agent.proto#L1-L98)
|
||||
- [agent.rs](file://crates/shared_types/src/grpc/agent.rs#L1-L651)
|
||||
- [build.rs](file://crates/shared_types/build.rs#L1-L14)
|
||||
- [chat_handler.rs](file://crates/agent_runner/src/handler/chat_handler.rs#L1-L321)
|
||||
- [acp_agent.rs](file://crates/agent_runner/src/proxy_agent/acp_agent.rs#L1-L392)
|
||||
|
||||
## 架构总览
|
||||
下图展示了 gRPC 数据模型在系统中的位置与交互关系,以及与 ACP 的对接路径。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "客户端"
|
||||
C1["HTTP 客户端"]
|
||||
end
|
||||
subgraph "agent_runner"
|
||||
R1["Axum 路由 /chat"]
|
||||
H1["聊天处理器 handle_chat"]
|
||||
A1["ACP 代理调度 agent_worker"]
|
||||
S1["AcpAgentService trait"]
|
||||
end
|
||||
subgraph "gRPC 层"
|
||||
G1["AgentServiceClient<br/>Chat/SubscribeProgress/CancelSession/GetStatus"]
|
||||
G2["AgentServiceServer<br/>实现 Chat/SubscribeProgress/CancelSession/GetStatus"]
|
||||
end
|
||||
subgraph "ACP 代理"
|
||||
P1["PromptRequest/PromptResponse"]
|
||||
N1["会话进度通知 SSE"]
|
||||
end
|
||||
C1 --> R1 --> H1 --> A1 --> S1
|
||||
H1 --> G1
|
||||
G1 --> G2
|
||||
G2 --> A1
|
||||
A1 --> P1
|
||||
A1 --> N1
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [agent.rs](file://crates/shared_types/src/grpc/agent.rs#L122-L650)
|
||||
- [chat_handler.rs](file://crates/agent_runner/src/handler/chat_handler.rs#L1-L321)
|
||||
- [acp_agent.rs](file://crates/agent_runner/src/proxy_agent/acp_agent.rs#L1-L392)
|
||||
- [agent_service.rs](file://crates/agent_runner/src/proxy_agent/agent_service.rs#L1-L62)
|
||||
- [router.rs](file://crates/agent_runner/src/router.rs#L1-L200)
|
||||
|
||||
## 详细组件分析
|
||||
|
||||
### Protobuf 消息类型与字段语义
|
||||
- AgentService
|
||||
- Chat:一元 RPC,请求 ChatRequest,返回 ChatResponse。
|
||||
- SubscribeProgress:服务端流式 RPC,请求 ProgressRequest,返回 ProgressEvent 流。
|
||||
- CancelSession:一元 RPC,请求 CancelRequest,返回 CancelResponse。
|
||||
- GetStatus:一元 RPC,请求 GetStatusRequest,返回 GetStatusResponse。
|
||||
- ChatRequest
|
||||
- project_id:项目标识。
|
||||
- session_id:会话标识。
|
||||
- prompt:用户提示词。
|
||||
- model_config:可选的模型提供商配置。
|
||||
- attachments:可选的附件列表。
|
||||
- request_id:可选的请求标识。
|
||||
- ChatResponse
|
||||
- request_id:请求标识。
|
||||
- success:是否成功。
|
||||
- error:可选的错误信息。
|
||||
- ProgressRequest
|
||||
- session_id:订阅进度的会话标识。
|
||||
- ProgressEvent
|
||||
- event:oneof,包含 log、thought、chunk、done、error 等事件类型。
|
||||
- json_payload:保留的原始 JSON,用于兼容过渡。
|
||||
- timestamp:Unix 时间戳。
|
||||
- CancelRequest
|
||||
- session_id:要取消的会话标识。
|
||||
- reason:取消原因。
|
||||
- CancelResponse
|
||||
- success:是否取消成功。
|
||||
- GetStatusRequest
|
||||
- project_id:项目标识。
|
||||
- GetStatusResponse
|
||||
- status:状态字符串,如 "idle"、"busy"、"error"。
|
||||
- ModelProviderConfig
|
||||
- provider:提供商名称。
|
||||
- model:模型名称。
|
||||
- api_key:可选的 API 密钥。
|
||||
- api_base:可选的 API 基地址。
|
||||
- Attachment
|
||||
- name:附件名称。
|
||||
- kind:附件类型(如 text、image、file)。
|
||||
- content:内容(文本、base64 或 URL)。
|
||||
- source:来源(如 local、upload、paste)。
|
||||
- language:可选的语言(仅文本)。
|
||||
|
||||
章节来源
|
||||
- [agent.proto](file://crates/shared_types/proto/agent.proto#L1-L98)
|
||||
|
||||
### 生成的 gRPC 客户端与服务端
|
||||
- 客户端
|
||||
- AgentServiceClient 提供 chat、subscribe_progress、cancel_session、get_status 方法,均基于 tonic+prost 编解码。
|
||||
- 支持压缩、最大消息大小、拦截器等配置。
|
||||
- 服务端
|
||||
- AgentServiceServer 实现 trait AgentService 的四个方法,并在内部将 HTTP 路径映射到具体 RPC。
|
||||
- 支持压缩、最大消息大小等配置。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class AgentServiceClient {
|
||||
+connect(dst) Result
|
||||
+send_compressed(encoding) Self
|
||||
+accept_compressed(encoding) Self
|
||||
+max_decoding_message_size(limit) Self
|
||||
+max_encoding_message_size(limit) Self
|
||||
+chat(request) -> Response~ChatResponse~
|
||||
+subscribe_progress(request) -> Response~Streaming~ProgressEvent~
|
||||
+cancel_session(request) -> Response~CancelResponse~
|
||||
+get_status(request) -> Response~GetStatusResponse~
|
||||
}
|
||||
class AgentServiceServer {
|
||||
+new(inner) Self
|
||||
+from_arc(inner) Self
|
||||
+with_interceptor(interceptor) Self
|
||||
+accept_compressed(encoding) Self
|
||||
+send_compressed(encoding) Self
|
||||
+max_decoding_message_size(limit) Self
|
||||
+max_encoding_message_size(limit) Self
|
||||
}
|
||||
class AgentService {
|
||||
<<trait>>
|
||||
+chat(request) -> Response~ChatResponse~
|
||||
+subscribe_progress(request) -> Stream~ProgressEvent~
|
||||
+cancel_session(request) -> Response~CancelResponse~
|
||||
+get_status(request) -> Response~GetStatusResponse~
|
||||
}
|
||||
AgentServiceServer --> AgentService : "实现"
|
||||
AgentServiceClient --> AgentServiceServer : "调用"
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [agent.rs](file://crates/shared_types/src/grpc/agent.rs#L122-L650)
|
||||
|
||||
章节来源
|
||||
- [agent.rs](file://crates/shared_types/src/grpc/agent.rs#L122-L650)
|
||||
|
||||
### 与 ACP 协议的映射关系
|
||||
- ChatRequest/Response 与 ACP 的 PromptRequest/PromptResponse 对接
|
||||
- agent_runner 的聊天处理器将 HTTP 请求转换为 ChatPrompt,并通过 ACP 代理发送 PromptRequest,接收 PromptResponse。
|
||||
- 会话进度通过 SSE 推送,与 gRPC 的 SubscribeProgress 语义一致(替代 /agent/progress/{session_id})。
|
||||
- 取消与状态
|
||||
- CancelSession 对应 ACP 的取消通知;GetStatus 对应查询代理状态。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as "HTTP 客户端"
|
||||
participant Handler as "handle_chat"
|
||||
participant Worker as "agent_worker"
|
||||
participant ACP as "AcpAgentService"
|
||||
participant Server as "AgentServiceServer"
|
||||
participant ClientG as "AgentServiceClient"
|
||||
Client->>Handler : POST /chat
|
||||
Handler->>Worker : LocalSetAgentRequest
|
||||
Worker->>ACP : start_agent_service(...)
|
||||
ACP-->>Worker : AcpConnectionInfo
|
||||
Worker->>ACP : 发送 PromptRequest
|
||||
ACP-->>Worker : PromptResponse
|
||||
Worker-->>Handler : ChatPromptResponse
|
||||
Handler-->>Client : ChatResponse
|
||||
Note over Client,Server : SubscribeProgress 通过 gRPC 客户端订阅 ProgressEvent 流
|
||||
Client->>ClientG : subscribe_progress(ProgressRequest)
|
||||
ClientG->>Server : /agent.AgentService/SubscribeProgress
|
||||
Server-->>ClientG : ProgressEvent stream
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [chat_handler.rs](file://crates/agent_runner/src/handler/chat_handler.rs#L1-L321)
|
||||
- [acp_agent.rs](file://crates/agent_runner/src/proxy_agent/acp_agent.rs#L1-L392)
|
||||
- [agent_service.rs](file://crates/agent_runner/src/proxy_agent/agent_service.rs#L1-L62)
|
||||
- [agent.rs](file://crates/shared_types/src/grpc/agent.rs#L232-L257)
|
||||
|
||||
章节来源
|
||||
- [chat_handler.rs](file://crates/agent_runner/src/handler/chat_handler.rs#L1-L321)
|
||||
- [acp_agent.rs](file://crates/agent_runner/src/proxy_agent/acp_agent.rs#L1-L392)
|
||||
- [agent_service.rs](file://crates/agent_runner/src/proxy_agent/agent_service.rs#L1-L62)
|
||||
- [agent.rs](file://crates/shared_types/src/grpc/agent.rs#L232-L257)
|
||||
|
||||
### 流式调用 SubscribeProgress 的实现细节
|
||||
- 客户端侧
|
||||
- AgentServiceClient.subscribe_progress 返回 Streaming<ProgressEvent>。
|
||||
- 可配置压缩与最大消息大小。
|
||||
- 服务端侧
|
||||
- AgentServiceServer 将 /agent.AgentService/SubscribeProgress 映射到 subscribe_progress 方法,返回实现者提供的流。
|
||||
- 实际使用
|
||||
- agent_runner 通过 HTTP SSE 提供 /agent/progress/{session_id},与 gRPC 流式接口语义一致,便于替换与统一。
|
||||
|
||||
章节来源
|
||||
- [agent.rs](file://crates/shared_types/src/grpc/agent.rs#L232-L257)
|
||||
- [router.rs](file://crates/agent_runner/src/router.rs#L1-L200)
|
||||
|
||||
### 序列化性能分析
|
||||
- 编解码器
|
||||
- 使用 prost+tonic 编解码,二进制序列化,开销低、吞吐高。
|
||||
- 压缩
|
||||
- 支持 send_compressed/accept_compressed,可在高延迟网络中降低带宽占用。
|
||||
- 消息大小限制
|
||||
- 提供 max_decoding_message_size/max_encoding_message_size,默认解码上限通常为 4MB,可根据业务调整。
|
||||
- oneof 与可选字段
|
||||
- ProgressEvent.event 使用 oneof,减少冗余字段存储;可选字段(如 ChatRequest.request_id、ModelProviderConfig.api_key)按需传输,降低体积。
|
||||
- 附件与 JSON 兼容
|
||||
- Attachment.content 支持多种格式;ProgressEvent.json_payload 保留原始 JSON,便于过渡期兼容。
|
||||
|
||||
章节来源
|
||||
- [agent.rs](file://crates/shared_types/src/grpc/agent.rs#L182-L212)
|
||||
- [agent.rs](file://crates/shared_types/src/grpc/agent.rs#L397-L412)
|
||||
- [agent.proto](file://crates/shared_types/proto/agent.proto#L1-L98)
|
||||
|
||||
### 版本兼容性策略与协议扩展指南
|
||||
- 向后兼容
|
||||
- 新增字段使用 optional,避免破坏已有客户端解析。
|
||||
- 保留 json_payload 等兼容字段,逐步迁移至强类型字段。
|
||||
- 扩展建议
|
||||
- 新增 RPC:在 AgentService 中添加新方法,同时在客户端/服务端生成代码中补充实现。
|
||||
- 新增消息:在 proto 中新增 message,并在 shared_types/src/grpc/agent.rs 中自动生成。
|
||||
- 迁移路径:先提供新接口,再逐步引导客户端切换,最后清理旧接口。
|
||||
- 构建与发布
|
||||
- 修改 proto 后,通过 build.rs 重新生成 agent.rs,确保客户端/服务端一致性。
|
||||
|
||||
章节来源
|
||||
- [agent.proto](file://crates/shared_types/proto/agent.proto#L1-L98)
|
||||
- [build.rs](file://crates/shared_types/build.rs#L1-L14)
|
||||
- [agent.rs](file://crates/shared_types/src/grpc/agent.rs#L1-L651)
|
||||
|
||||
### 客户端与服务端数据交换模式(结合 agent_runner 场景)
|
||||
- HTTP 到 gRPC 的桥接
|
||||
- HTTP 路由 /chat 由 handle_chat 处理,内部通过 ACP 代理发送 PromptRequest,接收 PromptResponse。
|
||||
- gRPC 的 Chat/SubscribeProgress/CancelSession/GetStatus 由 AgentServiceClient/Server 提供,可用于直接的 gRPC 客户端接入。
|
||||
- 会话与进度
|
||||
- 会话 ID 与项目 ID 在 ChatRequest/Response 中传递,服务端据此维护会话状态与进度推送。
|
||||
- 取消与状态
|
||||
- CancelSession 与 GetStatus 与 ACP 的取消与状态查询对齐,保证一致性。
|
||||
|
||||
章节来源
|
||||
- [chat_handler.rs](file://crates/agent_runner/src/handler/chat_handler.rs#L1-L321)
|
||||
- [agent.rs](file://crates/shared_types/src/grpc/agent.rs#L122-L650)
|
||||
- [router.rs](file://crates/agent_runner/src/router.rs#L1-L200)
|
||||
|
||||
## 依赖分析
|
||||
- 构建链路
|
||||
- build.rs 调用 tonic_prost_build::configure().build_server(true).build_client(true),输出到 src/grpc/agent.rs。
|
||||
- shared_types/src/lib.rs include!("grpc/agent.rs"),统一导出 gRPC 模块。
|
||||
- 运行时依赖
|
||||
- workspace.dependencies 中包含 agent-client-protocol(ACP 协议),用于与 ACP 代理交互。
|
||||
- tokio、tonic、prost 等异步与序列化依赖。
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
Build["build.rs"] --> Proto["agent.proto"]
|
||||
Proto --> Gen["src/grpc/agent.rs"]
|
||||
Lib["src/lib.rs"] --> Gen
|
||||
Cargo["Cargo.toml"] --> ACP["agent-client-protocol"]
|
||||
Runner["agent_runner"] --> ACP
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [build.rs](file://crates/shared_types/build.rs#L1-L14)
|
||||
- [agent.proto](file://crates/shared_types/proto/agent.proto#L1-L98)
|
||||
- [agent.rs](file://crates/shared_types/src/grpc/agent.rs#L1-L651)
|
||||
- [lib.rs](file://crates/shared_types/src/lib.rs#L1-L71)
|
||||
- [Cargo.toml](file://Cargo.toml#L1-L205)
|
||||
|
||||
章节来源
|
||||
- [build.rs](file://crates/shared_types/build.rs#L1-L14)
|
||||
- [lib.rs](file://crates/shared_types/src/lib.rs#L1-L71)
|
||||
- [Cargo.toml](file://Cargo.toml#L1-L205)
|
||||
|
||||
## 性能考虑
|
||||
- 序列化
|
||||
- prost 二进制编码,相比 JSON 更小更快;oneof 与可选字段减少冗余。
|
||||
- 压缩
|
||||
- 在高延迟网络中启用压缩,降低带宽;注意服务端需支持对应编码。
|
||||
- 消息大小
|
||||
- 合理设置 max_decoding_message_size/max_encoding_message_size,避免过大消息导致内存压力。
|
||||
- 流式传输
|
||||
- SubscribeProgress 使用服务端流,分片推送进度,降低一次性传输成本。
|
||||
- 并发与连接
|
||||
- gRPC 客户端连接池与重连策略需结合业务并发量评估;在 agent_runner 中可通过 ACP 代理连接管理策略优化。
|
||||
|
||||
## 故障排查指南
|
||||
- 常见问题
|
||||
- 服务未就绪:客户端 ready() 失败,检查服务端启动与网络可达性。
|
||||
- 消息过大:触发 max_decoding_message_size 限制,适当增大或拆分消息。
|
||||
- 压缩不匹配:客户端启用压缩但服务端不支持,需协商一致的压缩算法。
|
||||
- 会话状态异常:确认 project_id/session_id 传递正确,避免跨会话混淆。
|
||||
- 排查步骤
|
||||
- 检查 gRPC 客户端/服务端生成代码是否与 proto 一致。
|
||||
- 核对 ACP 代理连接与生命周期管理,确保连接可用且未超时。
|
||||
- 结合 agent_runner 的日志,定位 HTTP 到 ACP 的转换与进度推送环节。
|
||||
|
||||
章节来源
|
||||
- [agent.rs](file://crates/shared_types/src/grpc/agent.rs#L182-L212)
|
||||
- [agent.rs](file://crates/shared_types/src/grpc/agent.rs#L397-L412)
|
||||
- [acp_agent.rs](file://crates/agent_runner/src/proxy_agent/acp_agent.rs#L1-L392)
|
||||
- [chat_handler.rs](file://crates/agent_runner/src/handler/chat_handler.rs#L1-L321)
|
||||
|
||||
## 结论
|
||||
本文基于 agent.proto 生成的 Rust gRPC 数据模型,系统梳理了消息类型、服务接口与 ACP 协议的映射关系,给出了流式调用的实现要点、序列化性能分析、版本兼容与扩展策略,并结合 agent_runner 的实际调用场景展示了客户端与服务端的数据交换模式。遵循本文建议可确保在演进过程中保持协议稳定与性能最优。
|
||||
|
||||
## 附录
|
||||
- 相关文件清单
|
||||
- 协议与生成:agent.proto、agent.rs、build.rs、lib.rs
|
||||
- 业务集成:chat_handler.rs、acp_agent.rs、agent_service.rs、router.rs
|
||||
- 依赖声明:Cargo.toml
|
||||
391
qiming-rcoder/.qoder/repowiki/zh/content/数据模型与类型/代理状态模型.md
Normal file
391
qiming-rcoder/.qoder/repowiki/zh/content/数据模型与类型/代理状态模型.md
Normal file
@@ -0,0 +1,391 @@
|
||||
# 代理状态模型
|
||||
|
||||
<cite>
|
||||
**本文引用的文件**
|
||||
- [agent.proto](file://crates/shared_types/proto/agent.proto)
|
||||
- [agent.rs](file://crates/shared_types/src/grpc/agent.rs)
|
||||
- [agent_model.rs](file://crates/shared_types/src/model/agent_model.rs)
|
||||
- [agent_type.rs](file://crates/shared_types/src/model/agent_type.rs)
|
||||
- [model_provider.rs](file://crates/shared_types/src/model/model_provider.rs)
|
||||
- [http_result.rs](file://crates/shared_types/src/model/http_result.rs)
|
||||
- [app_error.rs](file://crates/shared_types/src/model/app_error.rs)
|
||||
- [agent_status_handler.rs(agent_runner)](file://crates/agent_runner/src/handler/agent_status_handler.rs)
|
||||
- [agent_status_handler.rs(rcoder)](file://crates/rcoder/src/handler/agent_status_handler.rs)
|
||||
- [mod.rs(proxy_agent)](file://crates/agent_runner/src/proxy_agent/mod.rs)
|
||||
- [agent_service.rs](file://crates/agent_runner/src/proxy_agent/agent_service.rs)
|
||||
- [agent-abstraction-layer-design.md](file://specs/agent-abstraction-layer-design.md)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [简介](#简介)
|
||||
2. [项目结构](#项目结构)
|
||||
3. [核心组件](#核心组件)
|
||||
4. [架构总览](#架构总览)
|
||||
5. [详细组件分析](#详细组件分析)
|
||||
6. [依赖关系分析](#依赖关系分析)
|
||||
7. [性能考量](#性能考量)
|
||||
8. [故障排查指南](#故障排查指南)
|
||||
9. [结论](#结论)
|
||||
|
||||
## 简介
|
||||
本文件系统化梳理代理状态模型,聚焦以下目标:
|
||||
- 解释 AgentStatusResponse、AgentType 等关键类型
|
||||
- 对比不同 AI 代理(Codex、Claude Code)的状态表示与统一抽象机制
|
||||
- 说明状态查询接口的数据输出格式、字段含义与扩展点
|
||||
- 结合 agent_status_handler 的实现,展示状态聚合逻辑与错误传播路径
|
||||
- 提供 gRPC 协议映射细节(来自 agent.proto)与 JSON 序列化示例
|
||||
|
||||
## 项目结构
|
||||
围绕“代理状态模型”的相关模块分布如下:
|
||||
- 协议与序列化:shared_types/proto/agent.proto 与生成的 gRPC 客户端/服务端代码
|
||||
- 数据模型:shared_types/src/model 下的 agent_model.rs、agent_type.rs、model_provider.rs、http_result.rs、app_error.rs
|
||||
- HTTP 状态查询处理器:agent_runner 与 rcoder 两处实现
|
||||
- 代理抽象与生命周期:agent_runner/proxy_agent 下的抽象层与生命周期管理
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "共享类型与协议"
|
||||
P["agent.proto<br/>gRPC 定义"]
|
||||
G["agent.rs<br/>生成的gRPC客户端/服务端"]
|
||||
M["agent_model.rs<br/>AgentStatusResponse/AgentStatus"]
|
||||
T["agent_type.rs<br/>AgentType/Claude/Codex"]
|
||||
MP["model_provider.rs<br/>ModelProviderConfig/SafeInfo"]
|
||||
HR["http_result.rs<br/>统一HTTP响应结构"]
|
||||
AE["app_error.rs<br/>应用错误类型"]
|
||||
end
|
||||
subgraph "HTTP状态查询"
|
||||
AR["agent_status_handler.rsagent_runner"]
|
||||
RC["agent_status_handler.rsrcoder"]
|
||||
end
|
||||
subgraph "代理抽象与生命周期"
|
||||
PA["proxy_agent/mod.rs<br/>PROJECT_AND_AGENT_INFO_MAP"]
|
||||
AS["agent_service.rs<br/>AcpAgentService"]
|
||||
end
|
||||
P --> G
|
||||
M --> AR
|
||||
M --> RC
|
||||
T --> AR
|
||||
T --> RC
|
||||
MP --> AR
|
||||
MP --> RC
|
||||
HR --> AR
|
||||
HR --> RC
|
||||
AE --> AR
|
||||
AE --> RC
|
||||
PA --> AR
|
||||
AS --> AR
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [agent.proto](file://crates/shared_types/proto/agent.proto#L1-L98)
|
||||
- [agent.rs](file://crates/shared_types/src/grpc/agent.rs#L1-L120)
|
||||
- [agent_model.rs](file://crates/shared_types/src/model/agent_model.rs#L32-L117)
|
||||
- [agent_type.rs](file://crates/shared_types/src/model/agent_type.rs#L16-L63)
|
||||
- [model_provider.rs](file://crates/shared_types/src/model/model_provider.rs#L43-L132)
|
||||
- [http_result.rs](file://crates/shared_types/src/model/http_result.rs#L24-L103)
|
||||
- [app_error.rs](file://crates/shared_types/src/model/app_error.rs#L1-L65)
|
||||
- [agent_status_handler.rs(agent_runner)](file://crates/agent_runner/src/handler/agent_status_handler.rs#L1-L122)
|
||||
- [agent_status_handler.rs(rcoder)](file://crates/rcoder/src/handler/agent_status_handler.rs#L1-L132)
|
||||
- [mod.rs(proxy_agent)](file://crates/agent_runner/src/proxy_agent/mod.rs#L1-L256)
|
||||
- [agent_service.rs](file://crates/agent_runner/src/proxy_agent/agent_service.rs#L1-L62)
|
||||
|
||||
章节来源
|
||||
- [agent.proto](file://crates/shared_types/proto/agent.proto#L1-L98)
|
||||
- [agent.rs](file://crates/shared_types/src/grpc/agent.rs#L1-L120)
|
||||
- [agent_model.rs](file://crates/shared_types/src/model/agent_model.rs#L32-L117)
|
||||
- [agent_type.rs](file://crates/shared_types/src/model/agent_type.rs#L16-L63)
|
||||
- [model_provider.rs](file://crates/shared_types/src/model/model_provider.rs#L43-L132)
|
||||
- [http_result.rs](file://crates/shared_types/src/model/http_result.rs#L24-L103)
|
||||
- [app_error.rs](file://crates/shared_types/src/model/app_error.rs#L1-L65)
|
||||
- [agent_status_handler.rs(agent_runner)](file://crates/agent_runner/src/handler/agent_status_handler.rs#L1-L122)
|
||||
- [agent_status_handler.rs(rcoder)](file://crates/rcoder/src/handler/agent_status_handler.rs#L1-L132)
|
||||
- [mod.rs(proxy_agent)](file://crates/agent_runner/src/proxy_agent/mod.rs#L1-L256)
|
||||
- [agent_service.rs](file://crates/agent_runner/src/proxy_agent/agent_service.rs#L1-L62)
|
||||
|
||||
## 核心组件
|
||||
- AgentStatusResponse:HTTP 状态查询的统一响应载体,包含项目标识、存活标记、会话ID、代理状态、时间戳与模型提供商安全信息。
|
||||
- AgentStatus:共享的代理服务状态枚举,抽象了 Active、Idle、Terminating 等状态。
|
||||
- AgentType:代理类型枚举,区分 Claude 与 Codex,并提供从模型提供商配置推断类型的能力。
|
||||
- ModelProviderConfig/SafeInfo:模型提供商配置与脱敏后的安全信息,用于在状态响应中安全暴露必要元数据。
|
||||
- gRPC GetStatus:agent.proto 中定义的 GetStatusRequest/GetStatusResponse,字段为字符串形式的状态码。
|
||||
- HTTP 层:agent_status_handler.rs(两套实现)负责参数校验、状态聚合与错误传播。
|
||||
|
||||
章节来源
|
||||
- [agent_model.rs](file://crates/shared_types/src/model/agent_model.rs#L32-L117)
|
||||
- [agent_type.rs](file://crates/shared_types/src/model/agent_type.rs#L16-L63)
|
||||
- [model_provider.rs](file://crates/shared_types/src/model/model_provider.rs#L43-L132)
|
||||
- [agent.proto](file://crates/shared_types/proto/agent.proto#L69-L76)
|
||||
- [agent.rs](file://crates/shared_types/src/grpc/agent.rs#L82-L91)
|
||||
- [agent_status_handler.rs(agent_runner)](file://crates/agent_runner/src/handler/agent_status_handler.rs#L70-L122)
|
||||
- [agent_status_handler.rs(rcoder)](file://crates/rcoder/src/handler/agent_status_handler.rs#L72-L132)
|
||||
|
||||
## 架构总览
|
||||
状态查询的端到端流程如下:
|
||||
- HTTP 层:接收 /agent/status/{project_id} 请求,进行参数校验与错误传播
|
||||
- 聚合层:从全局映射中读取项目对应的代理信息(含 AgentStatus、会话ID、时间戳、模型提供商)
|
||||
- 输出层:构造 AgentStatusResponse,按 is_alive 控制可选字段的序列化
|
||||
- gRPC 层:GetStatus 以字符串状态码返回,与 HTTP 层的 AgentStatus 枚举形成互补
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant C as "客户端"
|
||||
participant H as "HTTP处理器<br/>agent_status_handler.rs"
|
||||
participant M as "状态映射<br/>PROJECT_AND_AGENT_INFO_MAP"
|
||||
participant R as "响应构造<br/>AgentStatusResponse"
|
||||
C->>H : GET /agent/status/{project_id}
|
||||
H->>H : 校验project_id
|
||||
alt 有效
|
||||
H->>M : 读取项目代理信息
|
||||
M-->>H : 返回Agent信息(含AgentStatus/时间戳/模型提供商)
|
||||
H->>R : 构造AgentStatusResponse(is_alive=true)
|
||||
R-->>C : JSON响应(success=true,data=完整状态)
|
||||
else 无效
|
||||
H-->>C : JSON响应(success=false,error=INVALID_PARAMS)
|
||||
end
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [agent_status_handler.rs(agent_runner)](file://crates/agent_runner/src/handler/agent_status_handler.rs#L70-L122)
|
||||
- [agent_status_handler.rs(rcoder)](file://crates/rcoder/src/handler/agent_status_handler.rs#L72-L132)
|
||||
- [mod.rs(proxy_agent)](file://crates/agent_runner/src/proxy_agent/mod.rs#L1-L256)
|
||||
- [agent_model.rs](file://crates/shared_types/src/model/agent_model.rs#L32-L117)
|
||||
|
||||
## 详细组件分析
|
||||
|
||||
### AgentStatusResponse 与 AgentStatus
|
||||
- 字段与语义
|
||||
- project_id:项目唯一标识
|
||||
- is_alive:代理是否存活(true 表示存在且健康)
|
||||
- session_id:仅在 is_alive=true 时存在
|
||||
- status:仅在 is_alive=true 时存在,枚举值为 Active/Idle/Terminating
|
||||
- last_activity/created_at:仅在 is_alive=true 时存在
|
||||
- model_provider:仅在 is_alive=true 时存在,使用脱敏后的安全信息
|
||||
- 序列化策略
|
||||
- 使用 serde 的 skip_serializing_if 控制可选字段的输出
|
||||
- 通过 http_result.rs 的统一结构体包装 success、code、message、tid 与 data
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class AgentStatusResponse {
|
||||
+string project_id
|
||||
+bool is_alive
|
||||
+string session_id?
|
||||
+AgentStatus status?
|
||||
+datetime last_activity?
|
||||
+datetime created_at?
|
||||
+ModelProviderSafeInfo model_provider?
|
||||
}
|
||||
class AgentStatus {
|
||||
<<enum>>
|
||||
+Active
|
||||
+Idle
|
||||
+Terminating
|
||||
}
|
||||
class ModelProviderSafeInfo {
|
||||
+string id
|
||||
+string name
|
||||
+string api_protocol
|
||||
+string default_model
|
||||
}
|
||||
AgentStatusResponse --> AgentStatus : "包含"
|
||||
AgentStatusResponse --> ModelProviderSafeInfo : "包含"
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [agent_model.rs](file://crates/shared_types/src/model/agent_model.rs#L70-L117)
|
||||
- [model_provider.rs](file://crates/shared_types/src/model/model_provider.rs#L117-L132)
|
||||
|
||||
章节来源
|
||||
- [agent_model.rs](file://crates/shared_types/src/model/agent_model.rs#L70-L117)
|
||||
- [http_result.rs](file://crates/shared_types/src/model/http_result.rs#L24-L103)
|
||||
|
||||
### AgentType 抽象与多代理支持
|
||||
- AgentType 枚举:Claude 与 Codex(条件编译 feature)
|
||||
- 类型推断:根据 ModelProviderConfig 的 name 推断代理类型,默认 Claude
|
||||
- 环境注入:提供从环境变量构建 Claude/Codex 模型提供商配置的方法
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class AgentType {
|
||||
<<enum>>
|
||||
+Claude
|
||||
+Codex?
|
||||
}
|
||||
class ModelProviderConfig {
|
||||
+string id
|
||||
+string name
|
||||
+string base_url
|
||||
+string api_key
|
||||
+bool requires_openai_auth
|
||||
+string default_model
|
||||
+string api_protocol?
|
||||
+to_safe_info()
|
||||
}
|
||||
AgentType --> ModelProviderConfig : "推断/配置"
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [agent_type.rs](file://crates/shared_types/src/model/agent_type.rs#L16-L63)
|
||||
- [model_provider.rs](file://crates/shared_types/src/model/model_provider.rs#L43-L132)
|
||||
|
||||
章节来源
|
||||
- [agent_type.rs](file://crates/shared_types/src/model/agent_type.rs#L16-L63)
|
||||
- [model_provider.rs](file://crates/shared_types/src/model/model_provider.rs#L43-L132)
|
||||
|
||||
### gRPC GetStatus 协议映射
|
||||
- 定义位置:agent.proto 中的 GetStatusRequest/GetStatusResponse
|
||||
- 字段:GetStatusResponse.status 为字符串,取值为 "idle"、"busy"、"error"
|
||||
- 生成代码:agent.rs 中包含 GetStatus 的客户端与服务端方法签名
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start(["gRPC调用 GetStatus"]) --> Req["构造GetStatusRequest(project_id)"]
|
||||
Req --> Call["调用AgentService.get_status"]
|
||||
Call --> Resp["返回GetStatusResponse(status)"]
|
||||
Resp --> Map["映射到HTTP层AgentStatus枚举"]
|
||||
Map --> Out["HTTP层AgentStatusResponse输出"]
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [agent.proto](file://crates/shared_types/proto/agent.proto#L69-L76)
|
||||
- [agent.rs](file://crates/shared_types/src/grpc/agent.rs#L82-L91)
|
||||
|
||||
章节来源
|
||||
- [agent.proto](file://crates/shared_types/proto/agent.proto#L69-L76)
|
||||
- [agent.rs](file://crates/shared_types/src/grpc/agent.rs#L82-L91)
|
||||
|
||||
### HTTP 状态查询接口与聚合逻辑
|
||||
- 参数校验:project_id 必填且非空,否则返回 INVALID_PARAMS
|
||||
- 存在性判断:从 PROJECT_AND_AGENT_INFO_MAP 获取项目代理信息
|
||||
- 聚合策略:
|
||||
- 存在:填充完整 AgentStatusResponse(包含 session_id、status、时间戳、model_provider.safe)
|
||||
- 不存在:仅返回 project_id 与 is_alive=false
|
||||
- 错误传播:AppError 统一转为 HTTP 响应结构体,包含 success、code、message、tid
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["收到GET /agent/status/{project_id}"] --> B["trim并校验project_id"]
|
||||
B --> C{"project_id为空?"}
|
||||
C -- 是 --> E["返回HttpResult.error(INVALID_PARAMS)"]
|
||||
C -- 否 --> D["从PROJECT_AND_AGENT_INFO_MAP读取"]
|
||||
D --> F{"是否存在代理?"}
|
||||
F -- 是 --> G["构造完整AgentStatusResponse(is_alive=true)"]
|
||||
F -- 否 --> H["构造简化AgentStatusResponse(is_alive=false)"]
|
||||
G --> I["返回HttpResult.success"]
|
||||
H --> I
|
||||
E --> J["返回HttpResult.error"]
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [agent_status_handler.rs(agent_runner)](file://crates/agent_runner/src/handler/agent_status_handler.rs#L70-L122)
|
||||
- [agent_status_handler.rs(rcoder)](file://crates/rcoder/src/handler/agent_status_handler.rs#L72-L132)
|
||||
- [http_result.rs](file://crates/shared_types/src/model/http_result.rs#L24-L103)
|
||||
- [app_error.rs](file://crates/shared_types/src/model/app_error.rs#L1-L65)
|
||||
- [mod.rs(proxy_agent)](file://crates/agent_runner/src/proxy_agent/mod.rs#L1-L256)
|
||||
|
||||
章节来源
|
||||
- [agent_status_handler.rs(agent_runner)](file://crates/agent_runner/src/handler/agent_status_handler.rs#L70-L122)
|
||||
- [agent_status_handler.rs(rcoder)](file://crates/rcoder/src/handler/agent_status_handler.rs#L72-L132)
|
||||
- [http_result.rs](file://crates/shared_types/src/model/http_result.rs#L24-L103)
|
||||
- [app_error.rs](file://crates/shared_types/src/model/app_error.rs#L1-L65)
|
||||
- [mod.rs(proxy_agent)](file://crates/agent_runner/src/proxy_agent/mod.rs#L1-L256)
|
||||
|
||||
### 不同代理(Codex、Claude Code)的状态表示与统一抽象
|
||||
- HTTP 层:AgentStatusResponse 的 status 字段为 Active/Idle/Terminating 枚举,统一表达代理的运行态
|
||||
- gRPC 层:GetStatusResponse.status 为字符串,取值为 "idle"、"busy"、"error",与 HTTP 枚举形成互补
|
||||
- 类型抽象:AgentType 统一区分 Claude 与 Codex,便于在上层进行差异化配置与行为控制
|
||||
|
||||
章节来源
|
||||
- [agent_model.rs](file://crates/shared_types/src/model/agent_model.rs#L32-L61)
|
||||
- [agent_type.rs](file://crates/shared_types/src/model/agent_type.rs#L16-L63)
|
||||
- [agent.proto](file://crates/shared_types/proto/agent.proto#L69-L76)
|
||||
- [agent.rs](file://crates/shared_types/src/grpc/agent.rs#L82-L91)
|
||||
|
||||
### JSON 序列化示例与字段含义
|
||||
- 成功响应(代理存活)
|
||||
- success: true
|
||||
- data: 包含 project_id、is_alive(true)、session_id、status、last_activity、created_at、model_provider.safe
|
||||
- 成功响应(代理不存活)
|
||||
- success: true
|
||||
- data: 包含 project_id、is_alive(false)
|
||||
- 失败响应(参数错误)
|
||||
- success: false
|
||||
- error: 包含 code、message
|
||||
|
||||
章节来源
|
||||
- [agent_status_handler.rs(agent_runner)](file://crates/agent_runner/src/handler/agent_status_handler.rs#L12-L69)
|
||||
- [agent_status_handler.rs(rcoder)](file://crates/rcoder/src/handler/agent_status_handler.rs#L12-L67)
|
||||
- [http_result.rs](file://crates/shared_types/src/model/http_result.rs#L24-L103)
|
||||
|
||||
## 依赖关系分析
|
||||
- 低耦合与高内聚
|
||||
- HTTP 层仅依赖共享模型(AgentStatusResponse、AgentStatus、ModelProviderSafeInfo),不直接依赖具体代理实现
|
||||
- gRPC 层独立于 HTTP 层,二者通过共享的模型与协议文件解耦
|
||||
- 关键依赖链
|
||||
- HTTP 处理器依赖:PROJECT_AND_AGENT_INFO_MAP、AgentStatusResponse、HttpResult、AppError
|
||||
- 代理抽象依赖:AgentType、AcpAgentService、生命周期管理(AgentLifecycle)
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
AR["agent_status_handler.rsagent_runner"] --> MAP["PROJECT_AND_AGENT_INFO_MAP"]
|
||||
AR --> RESP["AgentStatusResponse"]
|
||||
AR --> HTTP["HttpResult"]
|
||||
AR --> ERR["AppError"]
|
||||
RC["agent_status_handler.rsrcoder"] --> MAP
|
||||
RC --> RESP
|
||||
RC --> HTTP
|
||||
RC --> ERR
|
||||
RESP --> STAT["AgentStatus"]
|
||||
RESP --> MP["ModelProviderSafeInfo"]
|
||||
AS["agent_service.rs"] --> AT["AgentType"]
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [agent_status_handler.rs(agent_runner)](file://crates/agent_runner/src/handler/agent_status_handler.rs#L1-L122)
|
||||
- [agent_status_handler.rs(rcoder)](file://crates/rcoder/src/handler/agent_status_handler.rs#L1-L132)
|
||||
- [agent_model.rs](file://crates/shared_types/src/model/agent_model.rs#L32-L117)
|
||||
- [agent_service.rs](file://crates/agent_runner/src/proxy_agent/agent_service.rs#L1-L62)
|
||||
- [agent_type.rs](file://crates/shared_types/src/model/agent_type.rs#L16-L63)
|
||||
- [mod.rs(proxy_agent)](file://crates/agent_runner/src/proxy_agent/mod.rs#L1-L256)
|
||||
|
||||
章节来源
|
||||
- [agent_status_handler.rs(agent_runner)](file://crates/agent_runner/src/handler/agent_status_handler.rs#L1-L122)
|
||||
- [agent_status_handler.rs(rcoder)](file://crates/rcoder/src/handler/agent_status_handler.rs#L1-L132)
|
||||
- [agent_model.rs](file://crates/shared_types/src/model/agent_model.rs#L32-L117)
|
||||
- [agent_service.rs](file://crates/agent_runner/src/proxy_agent/agent_service.rs#L1-L62)
|
||||
- [agent_type.rs](file://crates/shared_types/src/model/agent_type.rs#L16-L63)
|
||||
- [mod.rs(proxy_agent)](file://crates/agent_runner/src/proxy_agent/mod.rs#L1-L256)
|
||||
|
||||
## 性能考量
|
||||
- 读取开销:状态查询仅访问内存映射表(DashMap),读操作为 O(1) 量级
|
||||
- 序列化成本:AgentStatusResponse 采用 serde,skip_serializing_if 减少冗余字段输出
|
||||
- 错误路径短路:参数校验失败立即返回,避免不必要的映射查找
|
||||
- 并发安全:代理信息结构体通过 Arc/Mutex 等并发原语保护(生命周期管理),状态查询不持有写锁
|
||||
|
||||
[本节为通用性能讨论,不直接分析具体文件]
|
||||
|
||||
## 故障排查指南
|
||||
- 参数错误
|
||||
- 现象:返回 INVALID_PARAMS
|
||||
- 排查:确认 project_id 非空且去除前后空白
|
||||
- 代理不存在
|
||||
- 现象:is_alive=false,其余字段省略
|
||||
- 排查:确认项目是否已创建代理服务;检查生命周期管理与清理逻辑
|
||||
- 错误传播
|
||||
- AppError 统一转为 HTTP 响应结构体,包含 success、code、message、tid
|
||||
- gRPC 层的 GetStatus 返回字符串状态码,注意与 HTTP 枚举的映射关系
|
||||
|
||||
章节来源
|
||||
- [agent_status_handler.rs(agent_runner)](file://crates/agent_runner/src/handler/agent_status_handler.rs#L70-L122)
|
||||
- [agent_status_handler.rs(rcoder)](file://crates/rcoder/src/handler/agent_status_handler.rs#L72-L132)
|
||||
- [app_error.rs](file://crates/shared_types/src/model/app_error.rs#L1-L65)
|
||||
- [http_result.rs](file://crates/shared_types/src/model/http_result.rs#L24-L103)
|
||||
|
||||
## 结论
|
||||
- AgentStatusResponse 与 AgentStatus 提供了跨代理的一致状态视图,满足 HTTP 与 gRPC 双栈需求
|
||||
- AgentType 抽象确保 Claude 与 Codex 在配置与行为层面的统一入口
|
||||
- 状态查询接口通过最小化参数校验与内存映射读取,实现高效稳定的可观测性
|
||||
- 扩展建议
|
||||
- 在 gRPC 层引入更丰富的状态枚举(如 error 详情),并与 HTTP 层对齐
|
||||
- 在 AgentStatusResponse 中增加健康检查指标(如最近一次错误时间、重启次数)以增强可观测性
|
||||
- 在生命周期管理中补充 Termination 阶段的细化状态,以便更精确地反映代理终止过程
|
||||
334
qiming-rcoder/.qoder/repowiki/zh/content/数据模型与类型/容器模型.md
Normal file
334
qiming-rcoder/.qoder/repowiki/zh/content/数据模型与类型/容器模型.md
Normal file
@@ -0,0 +1,334 @@
|
||||
# 容器模型
|
||||
|
||||
<cite>
|
||||
**本文引用的文件**
|
||||
- [crates/rcoder/src/proxy_agent/docker_container_agent.rs](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs)
|
||||
- [crates/rcoder/src/service/container_manager.rs](file://crates/rcoder/src/service/container_manager.rs)
|
||||
- [crates/docker_manager/src/types.rs](file://crates/docker_manager/src/types.rs)
|
||||
- [crates/docker_manager/src/lib.rs](file://crates/docker_manager/src/lib.rs)
|
||||
- [crates/shared_types/src/model/agent_project_runner_model.rs](file://crates/shared_types/src/model/agent_project_runner_model.rs)
|
||||
- [crates/shared_types/src/lib.rs](file://crates/shared_types/src/lib.rs)
|
||||
- [crates/rcoder/src/proxy_agent/port_manager.rs](file://crates/rcoder/src/proxy_agent/port_manager.rs)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [简介](#简介)
|
||||
2. [项目结构](#项目结构)
|
||||
3. [核心组件](#核心组件)
|
||||
4. [架构总览](#架构总览)
|
||||
5. [详细组件分析](#详细组件分析)
|
||||
6. [依赖关系分析](#依赖关系分析)
|
||||
7. [性能考量](#性能考量)
|
||||
8. [故障排查指南](#故障排查指南)
|
||||
9. [结论](#结论)
|
||||
10. [附录](#附录)
|
||||
|
||||
## 简介
|
||||
本文件聚焦于 RCoder 项目中的“容器模型”,系统性梳理容器相关数据结构(尤其是 ContainerBasicInfo)、状态转换与生命周期管理、以及与 docker_manager 的交互关系。文档还涵盖序列化/反序列化行为、验证约束、性能优化策略,并说明该模型在代理运行时与容器管理中的作用。
|
||||
|
||||
## 项目结构
|
||||
围绕容器模型的关键文件分布如下:
|
||||
- rcoder 侧:
|
||||
- 容器生命周期编排与服务 URL 构建:[crates/rcoder/src/service/container_manager.rs](file://crates/rcoder/src/service/container_manager.rs)
|
||||
- 容器创建与健康检查:[crates/rcoder/src/proxy_agent/docker_container_agent.rs](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs)
|
||||
- 端口管理(历史/兼容):[crates/rcoder/src/proxy_agent/port_manager.rs](file://crates/rcoder/src/proxy_agent/port_manager.rs)
|
||||
- docker_manager 侧:
|
||||
- 容器配置与信息、状态枚举、清理工具等:[crates/docker_manager/src/types.rs](file://crates/docker_manager/src/types.rs)
|
||||
- 默认镜像、网络常量、全局管理器等:[crates/docker_manager/src/lib.rs](file://crates/docker_manager/src/lib.rs)
|
||||
- shared_types 侧:
|
||||
- 容器基本信息结构体定义与导出:[crates/shared_types/src/model/agent_project_runner_model.rs](file://crates/shared_types/src/model/agent_project_runner_model.rs)
|
||||
- 类型导出入口:[crates/shared_types/src/lib.rs](file://crates/shared_types/src/lib.rs)
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "rcoder"
|
||||
CM["容器管理服务<br/>container_manager.rs"]
|
||||
DCA["Docker容器代理<br/>docker_container_agent.rs"]
|
||||
PM["端口管理器<br/>port_manager.rs"]
|
||||
end
|
||||
subgraph "docker_manager"
|
||||
DMTypes["类型定义<br/>types.rs"]
|
||||
DMLib["默认常量/全局管理器<br/>lib.rs"]
|
||||
end
|
||||
subgraph "shared_types"
|
||||
SModel["容器模型定义<br/>agent_project_runner_model.rs"]
|
||||
SExport["类型导出入口<br/>lib.rs"]
|
||||
end
|
||||
CM --> DCA
|
||||
CM --> DMTypes
|
||||
CM --> SModel
|
||||
DCA --> DMTypes
|
||||
DCA --> DMLib
|
||||
PM -.-> CM
|
||||
SExport --> SModel
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [crates/rcoder/src/service/container_manager.rs](file://crates/rcoder/src/service/container_manager.rs#L1-L200)
|
||||
- [crates/rcoder/src/proxy_agent/docker_container_agent.rs](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs#L1-L120)
|
||||
- [crates/docker_manager/src/types.rs](file://crates/docker_manager/src/types.rs#L1-L120)
|
||||
- [crates/docker_manager/src/lib.rs](file://crates/docker_manager/src/lib.rs#L1-L120)
|
||||
- [crates/shared_types/src/model/agent_project_runner_model.rs](file://crates/shared_types/src/model/agent_project_runner_model.rs#L1-L60)
|
||||
- [crates/shared_types/src/lib.rs](file://crates/shared_types/src/lib.rs#L1-L71)
|
||||
|
||||
章节来源
|
||||
- [crates/rcoder/src/service/container_manager.rs](file://crates/rcoder/src/service/container_manager.rs#L1-L120)
|
||||
- [crates/rcoder/src/proxy_agent/docker_container_agent.rs](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs#L1-L120)
|
||||
- [crates/docker_manager/src/types.rs](file://crates/docker_manager/src/types.rs#L1-L120)
|
||||
- [crates/shared_types/src/model/agent_project_runner_model.rs](file://crates/shared_types/src/model/agent_project_runner_model.rs#L1-L60)
|
||||
|
||||
## 核心组件
|
||||
- ContainerBasicInfo:跨模块共享的容器基本信息,包含容器 ID、名称、IP、内外端口、项目 ID、状态、创建时间、服务 URL 等字段,用于对外暴露与持久化。
|
||||
- DockerContainerConfig/DockerContainerInfo:docker_manager 提供的容器配置与运行期信息,前者用于创建容器,后者用于描述已存在容器。
|
||||
- ContainerStatus:容器状态枚举,支持从字符串转换与序列化。
|
||||
- 全局 DockerManager:提供容器生命周期操作、网络信息查询、镜像选择、清理等能力。
|
||||
- 容器管理服务 ContainerManager:在 rcoder 侧协调容器创建、复用、网络检测与服务 URL 构建。
|
||||
|
||||
章节来源
|
||||
- [crates/shared_types/src/model/agent_project_runner_model.rs](file://crates/shared_types/src/model/agent_project_runner_model.rs#L1-L60)
|
||||
- [crates/docker_manager/src/types.rs](file://crates/docker_manager/src/types.rs#L85-L174)
|
||||
- [crates/docker_manager/src/lib.rs](file://crates/docker_manager/src/lib.rs#L130-L211)
|
||||
- [crates/rcoder/src/service/container_manager.rs](file://crates/rcoder/src/service/container_manager.rs#L1-L120)
|
||||
|
||||
## 架构总览
|
||||
容器模型在 RCoder 中的职责链路:
|
||||
- rcoder 的容器管理服务负责按需创建/复用容器,并基于动态网络名称与容器 IP 构建服务 URL。
|
||||
- docker_container_agent 负责具体创建容器、注入环境变量与挂载、等待 agent_runner 就绪。
|
||||
- docker_manager 提供底层 Docker 操作、镜像选择、资源限制、网络与清理工具。
|
||||
- shared_types 统一导出容器模型,保证跨模块一致性。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Caller as "调用方"
|
||||
participant CM as "ContainerManager"
|
||||
participant DCA as "DockerContainerAgent"
|
||||
participant DM as "DockerManager"
|
||||
participant Agent as "agent_runner(容器内)"
|
||||
Caller->>CM : 请求容器(project_id, service_type)
|
||||
CM->>DM : 查询容器是否存在
|
||||
alt 已存在
|
||||
CM->>DM : 获取网络信息(IP)
|
||||
CM-->>Caller : 返回ContainerBasicInfo(service_url)
|
||||
else 不存在
|
||||
CM->>DCA : start_docker_container_agent_service(...)
|
||||
DCA->>DM : select_image()/get_service_config()
|
||||
DCA->>DM : create_container(DockerContainerConfig)
|
||||
DM-->>DCA : DockerContainerInfo
|
||||
DCA->>DCA : 等待Agent就绪(get_container_ip/wait_for_agent_server_ready)
|
||||
DCA-->>CM : (DockerContainerInfo, server_url)
|
||||
CM->>DM : 获取网络信息(IP)
|
||||
CM-->>Caller : 返回ContainerBasicInfo(service_url)
|
||||
end
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [crates/rcoder/src/service/container_manager.rs](file://crates/rcoder/src/service/container_manager.rs#L153-L274)
|
||||
- [crates/rcoder/src/proxy_agent/docker_container_agent.rs](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs#L19-L130)
|
||||
- [crates/docker_manager/src/types.rs](file://crates/docker_manager/src/types.rs#L1-L120)
|
||||
|
||||
## 详细组件分析
|
||||
|
||||
### 数据结构:ContainerBasicInfo
|
||||
- 字段定义与业务含义
|
||||
- container_id:容器唯一标识,用于定位与日志追踪。
|
||||
- container_name:容器名称,便于可视化与调试。
|
||||
- container_ip:容器在动态网络中的 IP,用于内部通信。
|
||||
- internal_port:容器内服务监听端口(固定为代理容器默认端口)。
|
||||
- external_port:外部映射端口(当前实现为 0,表示无宿主机端口映射)。
|
||||
- project_id:项目标识,用于多租户隔离与容器复用。
|
||||
- status:容器状态字符串,便于对外展示与持久化。
|
||||
- created_at:容器创建时间,UTC 时间戳。
|
||||
- service_url:服务访问 URL,由容器 IP 与固定端口拼接而成。
|
||||
- 序列化/反序列化
|
||||
- 采用标准的 serde Serialize/Deserialize,支持 JSON 序列化,便于 API 返回与日志输出。
|
||||
- 验证约束
|
||||
- 字段均为简单标量或时间类型,无复杂校验;业务层通过 DockerManager 返回的网络信息与端口常量保证 service_url 有效性。
|
||||
- 性能优化
|
||||
- 作为轻量结构体,拷贝成本低;对外仅暴露必要字段,减少冗余数据传输。
|
||||
|
||||
章节来源
|
||||
- [crates/shared_types/src/model/agent_project_runner_model.rs](file://crates/shared_types/src/model/agent_project_runner_model.rs#L1-L60)
|
||||
- [crates/rcoder/src/service/container_manager.rs](file://crates/rcoder/src/service/container_manager.rs#L242-L269)
|
||||
|
||||
### 数据结构:DockerContainerConfig 与 DockerContainerInfo
|
||||
- DockerContainerConfig
|
||||
- 用途:创建容器时的配置载体,包含镜像、名称前缀、宿主机/容器路径、工作目录、环境变量、端口映射、网络模式、资源限制、额外挂载、命令/入口点、网络名称等。
|
||||
- 关键点:当前实现中端口映射为空,网络模式与工作目录来自服务配置;资源限制来自配置;容器路径通过变量替换与宿主机路径解析。
|
||||
- DockerContainerInfo
|
||||
- 用途:描述已存在容器的运行期信息,包含 ID、名称、项目 ID、镜像、状态、创建/启动时间、主机/容器路径、端口映射、分配端口、健康状态、内部服务端口、网络名称等。
|
||||
- 序列化/反序列化
|
||||
- 均实现 serde Serialize/Deserialize,便于与 Docker API 返回结构互通。
|
||||
- 验证约束
|
||||
- 通过服务配置与镜像选择策略保证镜像与网络模式的有效性;端口映射为空时,内部通信不依赖宿主机端口映射。
|
||||
|
||||
章节来源
|
||||
- [crates/docker_manager/src/types.rs](file://crates/docker_manager/src/types.rs#L1-L120)
|
||||
- [crates/docker_manager/src/types.rs](file://crates/docker_manager/src/types.rs#L85-L174)
|
||||
|
||||
### 状态转换与生命周期管理
|
||||
- 状态来源
|
||||
- ContainerStatus 枚举支持从字符串转换与序列化,覆盖常见容器状态(创建中、运行中、已停止、已暂停、重启中、移除中、已退出、已死亡、未知)。
|
||||
- 生命周期流程
|
||||
- 容器创建:由 docker_container_agent 基于服务配置与镜像选择策略创建容器。
|
||||
- 就绪等待:等待容器内 agent_runner 健康检查通过,超时则清理失败容器。
|
||||
- 复用与查询:ContainerManager 在后续请求中复用已存在容器,动态获取网络 IP 并构建服务 URL。
|
||||
- 清理:docker_manager 提供清理工具与过滤条件,支持按状态/标签/名称模式筛选并批量删除。
|
||||
- 端口策略
|
||||
- 当前实现采用内部网络通信,无需宿主机端口映射;external_port 字段为 0,端口管理器主要用于历史/兼容场景。
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> 创建中
|
||||
创建中 --> 运行中 : "启动成功"
|
||||
创建中 --> 已停止 : "启动失败/清理"
|
||||
运行中 --> 已停止 : "停止/异常"
|
||||
已停止 --> 运行中 : "重启"
|
||||
运行中 --> 移除中 : "清理"
|
||||
移除中 --> [*]
|
||||
运行中 --> 已退出 : "优雅退出"
|
||||
已退出 --> [*]
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [crates/docker_manager/src/types.rs](file://crates/docker_manager/src/types.rs#L120-L174)
|
||||
|
||||
章节来源
|
||||
- [crates/docker_manager/src/types.rs](file://crates/docker_manager/src/types.rs#L120-L174)
|
||||
- [crates/rcoder/src/proxy_agent/docker_container_agent.rs](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs#L111-L130)
|
||||
- [crates/rcoder/src/service/container_manager.rs](file://crates/rcoder/src/service/container_manager.rs#L277-L472)
|
||||
|
||||
### 与 docker_manager 的交互关系
|
||||
- 配置与镜像选择
|
||||
- docker_container_agent 通过 docker_manager 的镜像选择与服务配置接口获取镜像与运行参数。
|
||||
- 容器创建与查询
|
||||
- docker_container_agent 调用 create_container 获取 DockerContainerInfo;ContainerManager 通过 get_container_info 与 get_container_network_info 获取网络 IP 与状态。
|
||||
- 网络与端口
|
||||
- 使用动态网络名称(由 docker_manager 检测),容器内部服务端口固定为代理容器默认端口;当前实现不进行宿主机端口映射。
|
||||
- 默认常量与全局管理器
|
||||
- docker_manager 提供默认工作目录、网络模式、镜像选择策略与全局 DockerManager 单例,rcoder 侧通过全局实例获取管理器并执行操作。
|
||||
|
||||
章节来源
|
||||
- [crates/rcoder/src/proxy_agent/docker_container_agent.rs](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs#L58-L130)
|
||||
- [crates/rcoder/src/service/container_manager.rs](file://crates/rcoder/src/service/container_manager.rs#L142-L274)
|
||||
- [crates/docker_manager/src/lib.rs](file://crates/docker_manager/src/lib.rs#L130-L211)
|
||||
|
||||
### 实际使用模式与示例路径
|
||||
- 容器创建与就绪等待
|
||||
- 示例路径:[start_docker_container_agent_service](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs#L19-L130)
|
||||
- 该函数负责检查已有容器、选择镜像与服务配置、创建容器、等待 agent_runner 就绪并返回容器信息与服务 URL。
|
||||
- 容器复用与服务 URL 构建
|
||||
- 示例路径:[get_or_create_container](file://crates/rcoder/src/service/container_manager.rs#L153-L208)、[ensure_container_exists](file://crates/rcoder/src/service/container_manager.rs#L277-L360)、[create_container_for_request](file://crates/rcoder/src/service/container_manager.rs#L361-L472)
|
||||
- 该流程在容器存在时直接复用,不存在时创建并获取网络 IP,最终构造服务 URL。
|
||||
- 网络 IP 获取与健康检查
|
||||
- 示例路径:[get_container_ip](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs#L375-L417)、[wait_for_agent_server_ready](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs#L348-L374)
|
||||
- 通过 docker_manager 的网络信息查询与健康检查端点轮询确认容器内服务可用。
|
||||
|
||||
章节来源
|
||||
- [crates/rcoder/src/proxy_agent/docker_container_agent.rs](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs#L19-L130)
|
||||
- [crates/rcoder/src/service/container_manager.rs](file://crates/rcoder/src/service/container_manager.rs#L153-L208)
|
||||
|
||||
### 序列化/反序列化行为与验证约束
|
||||
- 序列化
|
||||
- ContainerBasicInfo、DockerContainerConfig、DockerContainerInfo、ContainerStatus 均实现 serde Serialize/Deserialize,支持 JSON 输出与 API 交互。
|
||||
- 反序列化
|
||||
- ContainerStatus 支持从字符串转换,便于从 Docker API 返回的状态字符串映射到枚举。
|
||||
- 验证约束
|
||||
- 服务配置与镜像选择在 docker_manager 层保证有效;rcoder 侧通过固定端口与动态网络名称确保 service_url 有效性;容器状态字符串映射为枚举,避免非法状态传播。
|
||||
|
||||
章节来源
|
||||
- [crates/shared_types/src/model/agent_project_runner_model.rs](file://crates/shared_types/src/model/agent_project_runner_model.rs#L1-L60)
|
||||
- [crates/docker_manager/src/types.rs](file://crates/docker_manager/src/types.rs#L1-L120)
|
||||
- [crates/docker_manager/src/types.rs](file://crates/docker_manager/src/types.rs#L120-L174)
|
||||
|
||||
### 性能优化策略
|
||||
- 端口映射优化
|
||||
- 采用内部网络通信,避免端口分配与释放开销,external_port 设为 0,简化网络管理。
|
||||
- 路径解析与挂载
|
||||
- 通过容器路径解析器将容器内路径转换为宿主机绝对路径,减少挂载错误与重复 IO。
|
||||
- 写时复制与共享
|
||||
- shared_types 中的 ProjectState 使用 Arc 实现高效共享与写时复制,降低频繁更新带来的内存复制成本。
|
||||
- 超时与重试
|
||||
- 健康检查采用 1 秒间隔与 30 次上限,避免长时间阻塞;失败时快速清理失败容器,降低资源占用。
|
||||
|
||||
章节来源
|
||||
- [crates/rcoder/src/proxy_agent/docker_container_agent.rs](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs#L111-L130)
|
||||
- [crates/rcoder/src/service/container_manager.rs](file://crates/rcoder/src/service/container_manager.rs#L474-L521)
|
||||
- [crates/shared_types/src/model/agent_project_runner_model.rs](file://crates/shared_types/src/model/agent_project_runner_model.rs#L106-L160)
|
||||
|
||||
## 依赖关系分析
|
||||
- 模块耦合
|
||||
- rcoder 的容器管理服务依赖 docker_manager 的容器信息与网络查询能力;docker_container_agent 依赖 docker_manager 的镜像选择与容器创建能力。
|
||||
- shared_types 统一导出 ContainerBasicInfo,避免跨模块重复定义。
|
||||
- 外部依赖
|
||||
- Docker API(bollard)用于容器查询与网络信息获取。
|
||||
- serde 用于结构体序列化/反序列化。
|
||||
- 循环依赖
|
||||
- 通过 shared_types 导出类型,避免 rcoder 与 docker_manager 之间的循环导入。
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
CM["rcoder/service/container_manager.rs"] --> DMT["docker_manager/types.rs"]
|
||||
DCA["rcoder/proxy_agent/docker_container_agent.rs"] --> DMT
|
||||
DCA --> DML["docker_manager/lib.rs"]
|
||||
CM --> SModel["shared_types/model/agent_project_runner_model.rs"]
|
||||
DMT --> SModel
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [crates/rcoder/src/service/container_manager.rs](file://crates/rcoder/src/service/container_manager.rs#L1-L120)
|
||||
- [crates/rcoder/src/proxy_agent/docker_container_agent.rs](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs#L1-L120)
|
||||
- [crates/docker_manager/src/types.rs](file://crates/docker_manager/src/types.rs#L1-L120)
|
||||
- [crates/docker_manager/src/lib.rs](file://crates/docker_manager/src/lib.rs#L1-L120)
|
||||
- [crates/shared_types/src/model/agent_project_runner_model.rs](file://crates/shared_types/src/model/agent_project_runner_model.rs#L1-L60)
|
||||
|
||||
章节来源
|
||||
- [crates/rcoder/src/service/container_manager.rs](file://crates/rcoder/src/service/container_manager.rs#L1-L120)
|
||||
- [crates/rcoder/src/proxy_agent/docker_container_agent.rs](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs#L1-L120)
|
||||
- [crates/docker_manager/src/types.rs](file://crates/docker_manager/src/types.rs#L1-L120)
|
||||
- [crates/shared_types/src/model/agent_project_runner_model.rs](file://crates/shared_types/src/model/agent_project_runner_model.rs#L1-L60)
|
||||
|
||||
## 性能考量
|
||||
- 端口管理
|
||||
- 当前实现不使用宿主机端口映射,external_port 为 0;端口管理器仍可用于历史/兼容场景,避免不必要的端口占用。
|
||||
- 路径解析
|
||||
- 宿主机路径解析与容器内路径标准化减少挂载错误与 IO 重试,提升稳定性。
|
||||
- 状态与网络查询
|
||||
- 通过 docker_manager 的网络信息查询与固定端口,避免多次网络探测与端口冲突。
|
||||
- 资源限制
|
||||
- 服务配置提供资源限制,结合 docker_manager 的资源限制结构,控制容器资源占用,避免资源争用。
|
||||
|
||||
章节来源
|
||||
- [crates/rcoder/src/proxy_agent/port_manager.rs](file://crates/rcoder/src/proxy_agent/port_manager.rs#L1-L96)
|
||||
- [crates/rcoder/src/proxy_agent/docker_container_agent.rs](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs#L192-L242)
|
||||
- [crates/docker_manager/src/types.rs](file://crates/docker_manager/src/types.rs#L51-L61)
|
||||
|
||||
## 故障排查指南
|
||||
- 容器创建失败
|
||||
- 检查镜像选择与服务配置是否正确;查看 docker_manager 的错误日志与镜像拉取状态。
|
||||
- 参考路径:[start_docker_container_agent_service](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs#L88-L130)
|
||||
- 容器内服务未就绪
|
||||
- 观察健康检查轮询与超时设置;确认容器内 agent_runner 启动日志与端口监听情况。
|
||||
- 参考路径:[wait_for_agent_server_ready](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs#L348-L374)
|
||||
- 网络连接问题
|
||||
- 确认动态网络名称与容器网络映射;检查容器是否连接到预期网络。
|
||||
- 参考路径:[get_container_ip](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs#L375-L417)、[get_dynamic_network_name](file://crates/rcoder/src/service/container_manager.rs#L142-L151)
|
||||
- 端口冲突(历史/兼容)
|
||||
- 若使用宿主机端口映射,检查端口管理器分配与释放逻辑。
|
||||
- 参考路径:[PortManager](file://crates/rcoder/src/proxy_agent/port_manager.rs#L1-L96)
|
||||
|
||||
章节来源
|
||||
- [crates/rcoder/src/proxy_agent/docker_container_agent.rs](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs#L88-L130)
|
||||
- [crates/rcoder/src/proxy_agent/docker_container_agent.rs](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs#L348-L417)
|
||||
- [crates/rcoder/src/service/container_manager.rs](file://crates/rcoder/src/service/container_manager.rs#L142-L151)
|
||||
- [crates/rcoder/src/proxy_agent/port_manager.rs](file://crates/rcoder/src/proxy_agent/port_manager.rs#L1-L96)
|
||||
|
||||
## 结论
|
||||
RCoder 的容器模型以 ContainerBasicInfo 为核心,结合 docker_manager 的配置与生命周期能力,在 rcoder 侧实现了按需创建、复用与健康检查的容器管理流程。通过内部网络通信与固定端口策略,显著降低了端口管理复杂度与资源占用;shared_types 的统一导出保证了跨模块一致性。整体设计在可维护性、性能与可扩展性之间取得良好平衡。
|
||||
|
||||
## 附录
|
||||
- 关键实现路径参考
|
||||
- 容器创建与就绪等待:[start_docker_container_agent_service](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs#L19-L130)
|
||||
- 容器复用与服务 URL 构建:[get_or_create_container](file://crates/rcoder/src/service/container_manager.rs#L153-L208)
|
||||
- 网络 IP 获取与健康检查:[get_container_ip](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs#L375-L417)、[wait_for_agent_server_ready](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs#L348-L374)
|
||||
- 容器状态与序列化:[ContainerStatus](file://crates/docker_manager/src/types.rs#L120-L174)
|
||||
- 容器模型定义:[ContainerBasicInfo](file://crates/shared_types/src/model/agent_project_runner_model.rs#L1-L60)
|
||||
524
qiming-rcoder/.qoder/repowiki/zh/content/数据模型与类型/数据模型与类型.md
Normal file
524
qiming-rcoder/.qoder/repowiki/zh/content/数据模型与类型/数据模型与类型.md
Normal file
@@ -0,0 +1,524 @@
|
||||
# 数据模型与类型
|
||||
|
||||
<cite>
|
||||
**本文档引用的文件**
|
||||
- [agent_model.rs](file://crates/shared_types/src/model/agent_model.rs)
|
||||
- [chat_prompt.rs](file://crates/shared_types/src/model/chat_prompt.rs)
|
||||
- [chat_response.rs](file://crates/shared_types/src/model/chat_response.rs)
|
||||
- [attachment.rs](file://crates/shared_types/src/model/attachment.rs)
|
||||
- [model_provider.rs](file://crates/shared_types/src/model/model_provider.rs)
|
||||
- [agent_session_notify.rs](file://crates/shared_types/src/model/agent_session_notify.rs)
|
||||
- [agent_type.rs](file://crates/shared_types/src/model/agent_type.rs)
|
||||
- [http_result.rs](file://crates/shared_types/src/model/http_result.rs)
|
||||
- [agent_project_runner_model.rs](file://crates/shared_types/src/model/agent_project_runner_model.rs)
|
||||
- [agent.proto](file://crates/shared_types/proto/agent.proto)
|
||||
- [config.yml](file://config.yml)
|
||||
- [rcoder_default.yml](file://crates/rcoder/src/rcoder_default.yml)
|
||||
- [agent-abstraction-layer-design.md](file://specs/agent-abstraction-layer-design.md)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [引言](#引言)
|
||||
2. [核心实体与关系](#核心实体与关系)
|
||||
3. [字段定义与数据类型](#字段定义与数据类型)
|
||||
4. [主键/外键、索引与约束](#主键外键索引与约束)
|
||||
5. [数据验证规则与业务规则](#数据验证规则与业务规则)
|
||||
6. [数据库模式图](#数据库模式图)
|
||||
7. [示例数据](#示例数据)
|
||||
8. [数据访问模式、缓存策略与性能考虑](#数据访问模式缓存策略与性能考虑)
|
||||
9. [数据生命周期、保留策略与归档规则](#数据生命周期保留策略与归档规则)
|
||||
10. [数据迁移路径与版本管理](#数据迁移路径与版本管理)
|
||||
|
||||
## 引言
|
||||
RCoder项目是一个基于AI代理的开发辅助系统,其数据模型设计围绕AI代理服务、会话管理、项目状态和用户交互等核心功能构建。本数据模型文档旨在全面介绍RCoder项目的数据结构、类型定义、实体关系以及相关的业务规则和性能策略。通过分析`shared_types` crate中的Rust结构体和`proto`文件中的gRPC消息定义,我们能够理解系统中数据的组织方式和流转过程。该模型支持多代理类型(如Claude和Codex)、灵活的模型提供商配置、丰富的附件类型,并通过gRPC协议实现服务间的通信。此外,系统的配置文件(YAML)定义了服务部署和运行时的参数,这些参数也构成了系统数据模型的一部分。
|
||||
|
||||
## 核心实体与关系
|
||||
RCoder项目的数据模型围绕几个核心实体构建,这些实体通过明确的关系相互连接,形成了一个支持AI代理服务生命周期管理的系统。主要实体包括`Agent`(代理)、`Project`(项目)、`Session`(会话)、`ModelProvider`(模型提供商)和`Attachment`(附件)。
|
||||
|
||||
`Project`(项目)是用户工作的核心单元,每个项目由唯一的`project_id`标识。一个项目可以关联一个正在运行的`Agent`实例。这种关系通过`ProjectAndAgentInfo`结构体体现,其中`project_id`作为关键字段将项目与代理实例绑定。`Agent`实例的生命周期由`AgentLifecycleGuard`管理,当代理被创建时,它会与一个`Session`(会话)相关联,会话ID(`session_id`)是代理与用户交互过程中的唯一标识。
|
||||
|
||||
`ModelProvider`(模型提供商)为`Agent`提供AI模型能力。`Agent`通过`model_provider`字段引用一个`ModelProviderConfig`对象,该对象包含了访问AI模型API所需的所有信息,如API密钥、基础URL和默认模型名称。一个`ModelProvider`可以被多个`Agent`实例共享,但一个`Agent`在同一时间只能使用一个`ModelProvider`。
|
||||
|
||||
`Attachment`(附件)是用户在与AI代理交互时可以附加到提示(prompt)中的数据。一个`ChatPrompt`请求可以包含多个`Attachment`,形成一对多的关系。`Attachment`是一个枚举类型,支持多种媒体类型,如文本、图像、音频和文档,这使得用户可以提供丰富的上下文信息给AI代理。
|
||||
|
||||
最后,`Session`(会话)不仅是代理运行的上下文,也是状态更新和消息通知的载体。`AgentSessionUpdate`、`SessionPromptStart`和`SessionPromptEnd`等结构体都包含`session_id`,用于将状态更新与特定的会话关联起来。这些更新通过`SessionNotify`枚举被统一处理,并最终转换为`UnifiedSessionMessage`发送给前端,实现服务端到客户端的实时通信。
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
PROJECT {
|
||||
string project_id PK
|
||||
datetime created_at
|
||||
datetime last_activity
|
||||
}
|
||||
SESSION {
|
||||
string session_id PK
|
||||
string project_id FK
|
||||
string request_id
|
||||
datetime created_at
|
||||
datetime last_activity
|
||||
string status
|
||||
}
|
||||
AGENT {
|
||||
string agent_type
|
||||
string status
|
||||
string session_id FK
|
||||
string model_provider_id FK
|
||||
}
|
||||
MODEL_PROVIDER {
|
||||
string id PK
|
||||
string name
|
||||
string base_url
|
||||
string api_key
|
||||
string default_model
|
||||
string api_protocol
|
||||
}
|
||||
ATTACHMENT {
|
||||
string id PK
|
||||
string session_id FK
|
||||
string source_type
|
||||
string mime_type
|
||||
string filename
|
||||
text description
|
||||
}
|
||||
CHAT_PROMPT {
|
||||
string project_id FK
|
||||
string session_id FK
|
||||
string prompt
|
||||
string request_id
|
||||
string agent_type
|
||||
string service_type
|
||||
}
|
||||
CHAT_RESPONSE {
|
||||
string project_id FK
|
||||
string session_id FK
|
||||
string request_id
|
||||
string error
|
||||
}
|
||||
PROJECT ||--o{ SESSION : "1 to many"
|
||||
SESSION ||--|| AGENT : "1 to 1"
|
||||
SESSION ||--o{ ATTACHMENT : "1 to many"
|
||||
AGENT }|--|| MODEL_PROVIDER : "uses"
|
||||
CHAT_PROMPT }|--|| SESSION : "references"
|
||||
CHAT_RESPONSE }|--|| SESSION : "references"
|
||||
```
|
||||
|
||||
**图源**
|
||||
- [agent_model.rs](file://crates/shared_types/src/model/agent_model.rs#L47-L68)
|
||||
- [chat_prompt.rs](file://crates/shared_types/src/model/chat_prompt.rs#L8-L29)
|
||||
- [chat_response.rs](file://crates/shared_types/src/model/chat_response.rs#L5-L17)
|
||||
- [attachment.rs](file://crates/shared_types/src/model/attachment.rs#L93-L104)
|
||||
- [model_provider.rs](file://crates/shared_types/src/model/model_provider.rs#L45-L67)
|
||||
|
||||
**本节来源**
|
||||
- [agent_model.rs](file://crates/shared_types/src/model/agent_model.rs)
|
||||
- [chat_prompt.rs](file://crates/shared_types/src/model/chat_prompt.rs)
|
||||
- [attachment.rs](file://crates/shared_types/src/model/attachment.rs)
|
||||
- [model_provider.rs](file://crates/shared_types/src/model/model_provider.rs)
|
||||
|
||||
## 字段定义与数据类型
|
||||
本节详细定义RCoder数据模型中各核心实体的字段及其数据类型。所有类型均基于Rust语言定义,并通过`serde`和`utoipa`等库支持序列化、反序列化和API文档生成。
|
||||
|
||||
### ProjectAndAgentInfo (项目与代理信息)
|
||||
该结构体是`rcoder`和`agent_runner`共用的核心结构,代表一个项目与其实例化代理的关联。
|
||||
- `project_id` (`String`): 项目的唯一标识符。
|
||||
- `session_id` (`SessionId`): 代理服务的会话ID,由代理启动时创建。
|
||||
- `prompt_tx` (`mpsc::UnboundedSender<PromptRequest>`): 用于向代理发送提示请求的异步通道。
|
||||
- `cancel_tx` (`mpsc::UnboundedSender<CancelNotificationRequest>`): 用于向代理发送取消通知的异步通道。
|
||||
- `model_provider` (`Option<ModelProviderConfig>`): 可选的模型提供商配置,为代理提供AI模型能力。
|
||||
- `request_id` (`Option<String>`): 当前活跃的用户请求ID,用于追踪单个请求。
|
||||
- `status` (`AgentStatus`): 代理的当前服务状态(`Active`, `Idle`, `Terminating`)。
|
||||
- `last_activity` (`DateTime<Utc>`): 代理最后一次活动的时间戳。
|
||||
- `created_at` (`DateTime<Utc>`): 代理实例的创建时间戳。
|
||||
- `stop_handle` (`Option<Arc<dyn AgentLifecycle>>`): 代理生命周期管理的句柄,用于优雅停止代理。
|
||||
|
||||
### ChatPrompt (聊天提示)
|
||||
该结构体定义了用户向AI代理发送的请求。
|
||||
- `project_id` (`String`): 关联的项目ID。
|
||||
- `project_path` (`PathBuf`): 项目在文件系统中的路径。
|
||||
- `session_id` (`Option<String>`): 可选的会话ID。如果未提供,代理将自动创建一个新会话。
|
||||
- `prompt` (`String`): 用户输入的提示内容。
|
||||
- `attachments` (`Vec<Attachment>`): 可选的附件列表,`Builder`模式下默认为空。
|
||||
- `data_source_attachments` (`Vec<String>`): 用于AI开发的外部数据源信息,以JSON字符串数组形式传递。
|
||||
- `agent_type` (`AgentType`): 指定使用的代理类型(`Claude`或`Codex`),`Builder`模式下默认值。
|
||||
- `service_type` (`ServiceType`): 必填字段,指定使用的服务类型(`rcoder`或`agent-runner`)。
|
||||
- `request_id` (`Option<String>`): 可选的请求ID,用于标识和追踪。
|
||||
- `model_provider` (`Option<ModelProviderConfig>`): 可选的模型提供商配置,用于覆盖默认配置。
|
||||
|
||||
### ChatResponse (聊天响应)
|
||||
该结构体定义了AI代理对用户请求的响应。
|
||||
- `project_id` (`String`): 关联的项目ID。
|
||||
- `session_id` (`String`): 代理的会话ID。
|
||||
- `error` (`Option<String>`): 可选的错误信息,如果请求失败则填充。
|
||||
- `request_id` (`Option<String>`): 请求ID,用于标识和追踪。
|
||||
- `service_type` (`ServiceType`): 使用的服务类型。
|
||||
|
||||
### Attachment (附件)
|
||||
`Attachment`是一个枚举类型,支持多种媒体格式。
|
||||
- **通用字段**:
|
||||
- `id` (`String`): 附件的唯一标识符,使用UUID生成。
|
||||
- `source` (`AttachmentSource`): 附件数据源,枚举类型,包含`FilePath`、`Base64`和`Url`。
|
||||
- `filename` (`Option<String>`): 可选的文件名。
|
||||
- `description` (`Option<String>`): 可选的描述。
|
||||
- **TextAttachment (文本附件)**: 无额外字段。
|
||||
- **ImageAttachment (图像附件)**:
|
||||
- `mime_type` (`String`): MIME类型(如`image/jpeg`)。
|
||||
- `dimensions` (`Option<ImageDimensions>`): 可选的图像尺寸信息。
|
||||
- **AudioAttachment (音频附件)**:
|
||||
- `mime_type` (`String`): MIME类型(如`audio/mp3`)。
|
||||
- `duration` (`Option<f64>`): 可选的音频时长(秒)。
|
||||
- **DocumentAttachment (文档附件)**:
|
||||
- `mime_type` (`String`): MIME类型(如`application/pdf`)。
|
||||
- `size` (`Option<u64>`): 可选的文件大小(字节)。
|
||||
|
||||
### ModelProviderConfig (模型提供商配置)
|
||||
该结构体封装了访问AI模型API所需的所有凭证和配置。
|
||||
- `id` (`String`): 模型提供商的唯一ID。
|
||||
- `name` (`String`): 提供商名称(如`openai`, `anthropic`)。
|
||||
- `base_url` (`String`): API的基础URL。
|
||||
- `api_key` (`String`): 访问API的密钥。
|
||||
- `requires_openai_auth` (`bool`): 是否需要OpenAI兼容的认证头。
|
||||
- `default_model` (`String`): 默认使用的模型名称。
|
||||
- `api_protocol` (`Option<String>`): 模型接口协议类型(`anthropic`或`openai`),可选。
|
||||
|
||||
### AgentSessionUpdate (代理会话更新)
|
||||
该结构体封装了代理在执行任务过程中产生的各种更新事件。
|
||||
- `session_id` (`String`): 关联的会话ID。
|
||||
- `session_update` (`SessionUpdate`): 具体的更新内容,为枚举类型,包含`UserMessageChunk`、`AgentMessageChunk`、`ToolCall`等。
|
||||
- `request_id` (`Option<String>`): 可选的请求ID。
|
||||
|
||||
**本节来源**
|
||||
- [agent_model.rs](file://crates/shared_types/src/model/agent_model.rs#L47-L68)
|
||||
- [chat_prompt.rs](file://crates/shared_types/src/model/chat_prompt.rs#L8-L29)
|
||||
- [chat_response.rs](file://crates/shared_types/src/model/chat_response.rs#L5-L17)
|
||||
- [attachment.rs](file://crates/shared_types/src/model/attachment.rs#L23-L90)
|
||||
- [model_provider.rs](file://crates/shared_types/src/model/model_provider.rs#L45-L67)
|
||||
- [agent_session_notify.rs](file://crates/shared_types/src/model/agent_session_notify.rs#L61-L65)
|
||||
|
||||
## 主键外键索引与约束
|
||||
RCoder的数据模型主要在内存和进程间通信层面运作,其“主键”和“外键”概念更多地体现在数据结构的逻辑关联和唯一性保证上,而非传统的关系型数据库约束。
|
||||
|
||||
### 主键 (Primary Keys)
|
||||
- **`project_id`**: 在`ProjectAndAgentInfo`和`ChatPrompt`等结构体中,`project_id`是项目实体的逻辑主键。它确保了每个项目在系统中的唯一性,并作为查找和管理项目相关资源(如代理、会话)的主要依据。
|
||||
- **`session_id`**: 在`ProjectAndAgentInfo`和`AgentSessionUpdate`等结构体中,`session_id`是会话实体的逻辑主键。它唯一标识一个代理的运行实例,所有与该代理的交互(如发送提示、接收更新、取消任务)都通过此ID进行。
|
||||
- **`id`**: 在`Attachment`结构体中,`id`字段(由`Uuid::new_v4()`生成)是每个附件的唯一标识符,作为附件的主键。
|
||||
|
||||
### 外键 (Foreign Keys)
|
||||
- **`project_id` in `ProjectAndAgentInfo`**: 该字段作为外键,将`ProjectAndAgentInfo`记录与一个具体的`Project`实体关联起来。它确保了代理实例的归属。
|
||||
- **`session_id` in `ProjectAndAgentInfo`**: 该字段作为外键,将`ProjectAndAgentInfo`记录与一个具体的`Session`实体关联起来。它建立了项目、代理和会话三者之间的联系。
|
||||
- **`session_id` in `AgentSessionUpdate`**: 该字段作为外键,将状态更新事件与一个具体的会话关联,确保前端能够正确地将更新渲染到对应的会话流中。
|
||||
- **`request_id` in `ChatPrompt` and `ChatResponse`**: 虽然`request_id`不是严格的外键,但它起到了关联请求和响应的作用,是实现请求-响应追踪的关键。
|
||||
|
||||
### 索引与约束
|
||||
由于数据主要存储在内存数据结构(如`DashMap`)中,索引是隐式存在的。
|
||||
- **内存索引**: `ProjectAndAgentInfo`通常被存储在以`project_id`为键的`DashMap<String, ProjectAndAgentInfo>`中。这使得通过`project_id`查找代理信息的操作具有接近O(1)的时间复杂度,相当于在`project_id`上创建了一个哈希索引。
|
||||
- **业务约束**:
|
||||
1. **唯一性约束**: 系统设计上保证一个`project_id`在同一时间只能关联一个活跃的`Agent`实例。当为一个已有代理的项目创建新会话时,旧的代理实例会被终止。
|
||||
2. **非空约束**: `ChatPrompt`中的`project_id`、`prompt`和`service_type`字段是必填的,由`Builder`模式和业务逻辑保证。
|
||||
3. **枚举约束**: `AgentType`和`AgentStatus`等字段的值被限制在预定义的枚举范围内,由Rust的类型系统强制执行。
|
||||
4. **格式约束**: `model_provider.api_key`等敏感字段在日志中会被脱敏(如显示为`sk-***abc`),通过`Display` trait的实现来保证。
|
||||
|
||||
**本节来源**
|
||||
- [agent_model.rs](file://crates/shared_types/src/model/agent_model.rs#L47-L68)
|
||||
- [chat_prompt.rs](file://crates/shared_types/src/model/chat_prompt.rs#L10-L29)
|
||||
- [agent_session_notify.rs](file://crates/shared_types/src/model/agent_session_notify.rs#L61-L65)
|
||||
|
||||
## 数据验证规则与业务规则
|
||||
RCoder项目通过Rust的强类型系统、`derive_builder`宏和自定义验证逻辑来实施数据验证和业务规则。
|
||||
|
||||
### 数据验证规则
|
||||
- **类型安全**: Rust的编译时类型检查确保了字段的数据类型正确,例如`last_activity`必须是`DateTime<Utc>`,`status`必须是`AgentStatus`枚举的成员。
|
||||
- **必填字段验证**: `ChatPrompt`结构体使用`derive_builder`宏。`project_id`、`prompt`和`service_type`没有`#[builder(default)]`属性,因此在构建时必须显式提供,否则编译失败。
|
||||
- **枚举值验证**: `AgentType`实现了`FromStr` trait,当从字符串解析时,会检查输入是否为有效的类型(`"claude"`或`"codex"`),否则返回错误。
|
||||
- **附件处理验证**: `Attachment`模块定义了`AttachmentError`枚举,用于处理文件读取、Base64解码、URL访问等操作中可能出现的错误,确保附件数据的完整性和可用性。
|
||||
|
||||
### 业务规则
|
||||
- **代理生命周期管理**: 代理的创建、运行和销毁遵循严格的业务流程。`AgentLifecycleGuard`实现了RAII(资源获取即初始化)原则,当其被`drop`时会自动触发资源清理。`graceful_stop`方法首先发送取消信号,等待任务自然退出,最后强制清理资源,确保了代理的优雅关闭。
|
||||
- **会话与项目绑定**: 一个`project_id`在同一时间只能有一个活跃的代理会话。当收到新的`ChatPrompt`请求时,如果该项目已有代理在运行,系统会先取消旧的会话,再启动新的会话,避免资源冲突。
|
||||
- **模型提供商推断**: `AgentType::from_model_provider`方法根据`ModelProviderConfig`的`name`字段自动推断应使用的代理类型(`anthropic` -> `Claude`),简化了用户配置。
|
||||
- **环境变量注入**: `AgentType`提供了`claude_from_env`和`codex_from_env`等方法,能够从进程环境变量中读取配置,并自动注入必要的启动参数(如`--dangerously-skip-permissions`),确保代理能够正确启动。
|
||||
- **状态更新的统一处理**: 所有的会话状态更新(开始、结束、错误、进度)都通过`SessionNotify`枚举被转换为统一的`UnifiedSessionMessage`格式。这保证了前端接收到的消息格式一致,简化了前端的处理逻辑。
|
||||
- **配置优先级**: 当`ChatPrompt`中提供了`model_provider`时,它会覆盖系统默认的模型提供商配置,实现了按请求级别的配置覆盖。
|
||||
|
||||
**本节来源**
|
||||
- [agent_model.rs](file://crates/shared_types/src/model/agent_model.rs#L339-L403)
|
||||
- [chat_prompt.rs](file://crates/shared_types/src/model/chat_prompt.rs#L6-L29)
|
||||
- [agent_type.rs](file://crates/shared_types/src/model/agent_type.rs#L115-L124)
|
||||
- [agent_session_notify.rs](file://crates/shared_types/src/model/agent_session_notify.rs#L77-L162)
|
||||
|
||||
## 数据库模式图
|
||||
RCoder项目并未使用传统的关系型数据库,其数据主要存储在内存中,并通过gRPC进行服务间通信。因此,其“数据库”模式更准确地描述为**数据结构与通信协议模式**。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class ProjectAndAgentInfo {
|
||||
+project_id : String
|
||||
+session_id : SessionId
|
||||
+prompt_tx : mpsc : : UnboundedSender<PromptRequest>
|
||||
+cancel_tx : mpsc : : UnboundedSender<CancelNotificationRequest>
|
||||
+model_provider : Option<ModelProviderConfig>
|
||||
+request_id : Option<String>
|
||||
+status : AgentStatus
|
||||
+last_activity : DateTime<Utc>
|
||||
+created_at : DateTime<Utc>
|
||||
+stop_handle : Option<Arc<dyn AgentLifecycle>>
|
||||
}
|
||||
class ChatPrompt {
|
||||
+project_id : String
|
||||
+project_path : PathBuf
|
||||
+session_id : Option<String>
|
||||
+prompt : String
|
||||
+attachments : Vec<Attachment>
|
||||
+data_source_attachments : Vec<String>
|
||||
+agent_type : AgentType
|
||||
+service_type : ServiceType
|
||||
+request_id : Option<String>
|
||||
+model_provider : Option<ModelProviderConfig>
|
||||
}
|
||||
class ChatResponse {
|
||||
+project_id : String
|
||||
+session_id : String
|
||||
+error : Option<String>
|
||||
+request_id : Option<String>
|
||||
+service_type : ServiceType
|
||||
}
|
||||
class Attachment {
|
||||
+id : String
|
||||
+source : AttachmentSource
|
||||
+filename : Option<String>
|
||||
+description : Option<String>
|
||||
}
|
||||
class AttachmentSource {
|
||||
<<enumeration>>
|
||||
+FilePath{ path : String }
|
||||
+Base64{ data : String, mime_type : String }
|
||||
+Url{ url : String }
|
||||
}
|
||||
class ModelProviderConfig {
|
||||
+id : String
|
||||
+name : String
|
||||
+base_url : String
|
||||
+api_key : String
|
||||
+requires_openai_auth : bool
|
||||
+default_model : String
|
||||
+api_protocol : Option<String>
|
||||
}
|
||||
class AgentSessionUpdate {
|
||||
+session_id : String
|
||||
+session_update : SessionUpdate
|
||||
+request_id : Option<String>
|
||||
}
|
||||
class SessionUpdate {
|
||||
<<enumeration>>
|
||||
+UserMessageChunk
|
||||
+AgentMessageChunk
|
||||
+ToolCall
|
||||
+Plan
|
||||
+AvailableCommandsUpdate
|
||||
+CurrentModeUpdate
|
||||
}
|
||||
class UnifiedSessionMessage {
|
||||
+session_id : String
|
||||
+message_type : SessionMessageType
|
||||
+sub_type : String
|
||||
+data : serde_json : : Value
|
||||
+timestamp : DateTime<Utc>
|
||||
}
|
||||
class HttpResult~T~ {
|
||||
+code : String
|
||||
+message : String
|
||||
+data : Option~T~
|
||||
+tid : Option<String>
|
||||
+success : bool
|
||||
}
|
||||
ProjectAndAgentInfo --> ModelProviderConfig : "uses"
|
||||
ChatPrompt --> Attachment : "has many"
|
||||
ChatPrompt --> ModelProviderConfig : "can override"
|
||||
AgentSessionUpdate --> SessionUpdate : "contains"
|
||||
AgentSessionUpdate --> UnifiedSessionMessage : "converts to"
|
||||
HttpResult --> ChatResponse : "wraps"
|
||||
HttpResult --> AgentStatusResponse : "wraps"
|
||||
```
|
||||
|
||||
**图源**
|
||||
- [agent_model.rs](file://crates/shared_types/src/model/agent_model.rs)
|
||||
- [chat_prompt.rs](file://crates/shared_types/src/model/chat_prompt.rs)
|
||||
- [chat_response.rs](file://crates/shared_types/src/model/chat_response.rs)
|
||||
- [attachment.rs](file://crates/shared_types/src/model/attachment.rs)
|
||||
- [model_provider.rs](file://crates/shared_types/src/model/model_provider.rs)
|
||||
- [agent_session_notify.rs](file://crates/shared_types/src/model/agent_session_notify.rs)
|
||||
- [http_result.rs](file://crates/shared_types/src/model/http_result.rs)
|
||||
|
||||
## 示例数据
|
||||
以下是根据数据模型生成的JSON格式示例数据,展示了API请求和响应的典型结构。
|
||||
|
||||
### ChatPrompt 请求示例
|
||||
```json
|
||||
{
|
||||
"project_id": "my-web-app",
|
||||
"project_path": "/home/user/project_workspace/my-web-app",
|
||||
"session_id": null,
|
||||
"prompt": "请帮我创建一个React组件,实现一个带有搜索功能的用户列表。",
|
||||
"attachments": [
|
||||
{
|
||||
"type": "text",
|
||||
"content": {
|
||||
"id": "att-123",
|
||||
"source": {
|
||||
"source_type": "FilePath",
|
||||
"data": {
|
||||
"path": "src/components/UserList.js"
|
||||
}
|
||||
},
|
||||
"filename": "UserList.js",
|
||||
"description": "现有用户列表组件"
|
||||
}
|
||||
}
|
||||
],
|
||||
"data_source_attachments": [],
|
||||
"agent_type": "Claude",
|
||||
"service_type": "rcoder",
|
||||
"request_id": "req-abc123",
|
||||
"model_provider": {
|
||||
"id": "openai-gpt4",
|
||||
"name": "openai",
|
||||
"base_url": "https://api.openai.com/v1",
|
||||
"api_key": "sk-very-long-secret-key",
|
||||
"requires_openai_auth": true,
|
||||
"default_model": "gpt-4-turbo",
|
||||
"api_protocol": "openai"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ChatResponse 响应示例
|
||||
```json
|
||||
{
|
||||
"project_id": "my-web-app",
|
||||
"session_id": "sess-456def",
|
||||
"error": null,
|
||||
"request_id": "req-abc123",
|
||||
"service_type": "rcoder"
|
||||
}
|
||||
```
|
||||
|
||||
### AgentStatusResponse 响应示例
|
||||
```json
|
||||
{
|
||||
"project_id": "my-web-app",
|
||||
"is_alive": true,
|
||||
"session_id": "sess-456def",
|
||||
"status": "Active",
|
||||
"last_activity": "2024-01-01T12:05:30Z",
|
||||
"created_at": "2024-01-01T12:00:00Z",
|
||||
"model_provider": {
|
||||
"id": "openai-gpt4",
|
||||
"name": "openai",
|
||||
"api_protocol": "openai",
|
||||
"default_model": "gpt-4-turbo"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### UnifiedSessionMessage (SSE流) 示例
|
||||
```json
|
||||
{
|
||||
"session_id": "sess-456def",
|
||||
"message_type": "AgentSessionUpdate",
|
||||
"sub_type": "agent_message_chunk",
|
||||
"data": {
|
||||
"content": {
|
||||
"text": "好的,我将为您创建一个React组件...",
|
||||
"type": "text"
|
||||
},
|
||||
"request_id": "req-abc123"
|
||||
},
|
||||
"timestamp": "2024-01-01T12:05:35Z"
|
||||
}
|
||||
```
|
||||
|
||||
**本节来源**
|
||||
- [chat_prompt.rs](file://crates/shared_types/src/model/chat_prompt.rs)
|
||||
- [chat_response.rs](file://crates/shared_types/src/model/chat_response.rs)
|
||||
- [agent_model.rs](file://crates/shared_types/src/model/agent_model.rs#L71-L97)
|
||||
- [agent_session_notify.rs](file://crates/shared_types/src/model/agent_session_notify.rs#L17-L30)
|
||||
|
||||
## 数据访问模式缓存策略与性能考虑
|
||||
RCoder项目的数据访问模式、缓存策略和性能优化紧密围绕其高并发、低延迟的实时交互需求设计。
|
||||
|
||||
### 数据访问模式
|
||||
- **内存优先**: 核心状态(如`ProjectAndAgentInfo`)存储在全局的`DashMap`或`RwLock<HashMap>`中,提供极快的读写速度。通过`project_id`作为键进行哈希查找,实现O(1)的平均时间复杂度。
|
||||
- **异步通道通信**: `rcoder`主服务与`agent_runner`代理服务之间通过`tokio`的`mpsc`(多生产者单消费者)无界通道进行通信。`prompt_tx`用于发送提示,`cancel_tx`用于发送取消指令。这种模式避免了直接的函数调用开销,实现了服务间的解耦和非阻塞通信。
|
||||
- **gRPC流式传输**: 代理的执行进度通过gRPC的服务器流式RPC(`SubscribeProgress`)或SSE(Server-Sent Events)实时推送给前端。`UnifiedSessionMessage`被序列化为JSON并通过流发送,确保了低延迟的用户体验。
|
||||
- **原子操作与锁优化**: `ProjectState`结构体使用`Arc<ProjectCoreState>`和`Arc<ProjectExtendedState>`,结合`Arc::make_mut`实现写时复制(Copy-on-Write),在读多写少的场景下极大减少了锁竞争。`AtomicBool`用于`AgentLifecycleGuard`的状态标记,避免了对整个结构体的加锁。
|
||||
|
||||
### 缓存策略
|
||||
- **配置缓存**: `MultiImageConfig`中的`cache_config`允许缓存Docker镜像选择的结果,避免重复的镜像解析和选择计算,提高容器启动速度。
|
||||
- **内存缓存**: 整个`ProjectAndAgentInfo`映射本身就是一种内存缓存,避免了每次请求都重新创建或查询代理实例。
|
||||
- **无持久化缓存**: 项目未使用Redis等外部缓存系统,所有缓存均为进程内内存缓存,简化了架构,但依赖于单个进程的可用性。
|
||||
|
||||
### 性能考虑
|
||||
- **零拷贝与高效克隆**: 广泛使用`Arc`(原子引用计数)来共享数据,避免了不必要的数据复制。`ProjectState`的设计确保了核心状态的高效克隆。
|
||||
- **异步非阻塞I/O**: 整个系统基于`tokio`异步运行时构建,所有I/O操作(文件读写、网络通信、进程管理)都是非阻塞的,能够高效处理大量并发连接。
|
||||
- **资源限制**: 通过`docker_config`中的`resource_limits`(如`memory_limit`, `cpu_limit`)对Docker容器施加资源限制,防止单个代理消耗过多系统资源,影响整体稳定性。
|
||||
- **连接池与复用**: 虽然未明确提及,但`reqwest`客户端等HTTP库通常会内部维护连接池,复用TCP连接,减少握手开销。
|
||||
- **批处理与合并**: `ProjectAndContainerInfo`的`update_extended_from_request`方法允许一次性批量更新多个字段,减少状态更新的次数。
|
||||
|
||||
**本节来源**
|
||||
- [agent_model.rs](file://crates/shared_types/src/model/agent_model.rs#L47-L68)
|
||||
- [agent_project_runner_model.rs](file://crates/shared_types/src/model/agent_project_runner_model.rs)
|
||||
- [config.yml](file://config.yml#L144-L147)
|
||||
- [agent.proto](file://crates/shared_types/proto/agent.proto#L9-L11)
|
||||
|
||||
## 数据生命周期保留策略与归档规则
|
||||
RCoder项目的数据生命周期管理主要通过自动化和配置驱动的策略来实现,侧重于临时性和运行时数据的管理。
|
||||
|
||||
### 数据生命周期
|
||||
1. **创建 (Creation)**:
|
||||
- 当用户发起`ChatPrompt`请求时,系统检查`project_id`。
|
||||
- 如果该项目没有活跃的代理,则创建一个新的`ProjectAndAgentInfo`实例,启动`agent_runner`进程,并生成新的`session_id`。
|
||||
- 代理的生命周期由`AgentLifecycleGuard`管理,其创建标志着代理生命周期的开始。
|
||||
|
||||
2. **活跃 (Active)**:
|
||||
- 代理处于`Active`状态,通过`prompt_tx`接收用户提示,并通过`SessionNotify`发送状态更新。
|
||||
- `last_activity`字段在每次交互时被更新,用于判断代理的活跃度。
|
||||
|
||||
3. **终止 (Termination)**:
|
||||
- **正常终止**: 当代理完成任务或用户主动取消时,调用`AgentLifecycleGuard::graceful_stop`。该方法发送取消信号,等待任务退出,然后清理资源(终止子进程、关闭通道)。
|
||||
- **超时终止**: 配置文件中的`container_ttl_seconds`(默认3600秒)定义了容器的存活时间。后台任务会定期检查超过TTL的代理并自动终止。
|
||||
- **错误终止**: 如果代理进程崩溃或发生严重错误,`Drop`实现会确保资源被清理。
|
||||
|
||||
4. **销毁 (Destruction)**:
|
||||
- `AgentLifecycleGuard`被`drop`时,其`Drop`实现会执行最终的清理工作,确保子进程被杀死,通道被关闭。
|
||||
- `ProjectAndAgentInfo`记录从`DashMap`中被移除,相关内存被回收。
|
||||
|
||||
### 保留策略与归档规则
|
||||
- **临时性数据**: 会话(`Session`)和代理(`Agent`)实例被视为临时工作负载。它们的生命周期与用户的开发会话绑定,一旦任务完成或超时,就会被销毁。
|
||||
- **无长期归档**: 项目当前的设计中,没有明确的机制将聊天记录、生成的代码或会话日志归档到持久化存储(如数据库或文件系统)。所有数据在代理终止后即丢失。
|
||||
- **配置驱动的保留**: `container_ttl_seconds`是主要的保留策略配置,它强制性地保留了代理实例的最长时间。
|
||||
- **自动清理**: `docker_config.auto_cleanup`设置为`true`,表明系统会在代理终止后自动清理Docker容器,释放系统资源。
|
||||
|
||||
**本节来源**
|
||||
- [agent_model.rs](file://crates/shared_types/src/model/agent_model.rs#L218-L249)
|
||||
- [agent_model.rs](file://crates/shared_types/src/model/agent_model.rs#L348-L403)
|
||||
- [config.yml](file://config.yml#L160-L161)
|
||||
- [rcoder_default.yml](file://crates/rcoder/src/rcoder_default.yml#L173-L174)
|
||||
|
||||
## 数据迁移路径与版本管理
|
||||
RCoder项目的数据迁移和版本管理主要体现在配置文件和gRPC协议的演进上。
|
||||
|
||||
### 数据迁移路径
|
||||
- **配置文件迁移**: 从`config.yml`到`rcoder_default.yml`的演变,以及`multi_image_config`的引入,代表了系统配置的演进。迁移路径通常由代码中的默认值和向后兼容逻辑处理。例如,`create_legacy_multi_image_config`函数可以将旧的简单配置转换为新的多镜像配置格式。
|
||||
- **gRPC协议迁移**: `agent.proto`文件定义了服务间的通信协议。当需要添加新功能(如新的`ProgressEvent`类型)时,会通过添加新的字段或消息来实现,遵循gRPC的向后兼容原则(如使用`optional`关键字)。
|
||||
- **数据结构演进**: Rust结构体通过添加新字段(通常为`Option<T>`类型)来实现向后兼容。例如,`ChatPrompt`中的`data_source_attachments`是一个后来添加的字段,旧的客户端可以忽略它,而新的服务器可以安全地处理缺失的字段。
|
||||
|
||||
### 版本管理
|
||||
- **语义化版本控制**: 项目使用`Cargo.toml`进行依赖管理,遵循语义化版本控制(SemVer)。`crates/shared_types`等内部crate的版本号变化反映了API的稳定性。
|
||||
- **配置版本**: 配置文件本身没有明确的`version`字段,但其结构的变化(如`docker_config`的复杂化)隐式地代表了版本迭代。代码通过检查字段是否存在来处理不同版本的配置。
|
||||
- **gRPC服务版本**: `agent.proto`中的`package agent;`和`service AgentService`定义了服务的命名空间。未来可以通过创建新的`AgentServiceV2`服务来实现不兼容的API变更。
|
||||
- **环境变量映射**: `agent-abstraction-layer-design.md`中的JSON配置展示了如何通过模板(如`{MODEL_PROVIDER_API_KEY}`)将不同模型提供商的环境变量映射到代理的启动参数中,这是一种灵活的配置版本管理方式。
|
||||
|
||||
**本节来源**
|
||||
- [config.yml](file://config.yml)
|
||||
- [rcoder_default.yml](file://crates/rcoder/src/rcoder_default.yml)
|
||||
- [agent.proto](file://crates/shared_types/proto/agent.proto)
|
||||
- [agent-abstraction-layer-design.md](file://specs/agent-abstraction-layer-design.md#L545-L610)
|
||||
336
qiming-rcoder/.qoder/repowiki/zh/content/数据模型与类型/聊天数据模型.md
Normal file
336
qiming-rcoder/.qoder/repowiki/zh/content/数据模型与类型/聊天数据模型.md
Normal file
@@ -0,0 +1,336 @@
|
||||
# 聊天数据模型
|
||||
|
||||
<cite>
|
||||
**本文引用的文件**
|
||||
- [chat_prompt.rs](file://crates/shared_types/src/model/chat_prompt.rs)
|
||||
- [chat_response.rs](file://crates/shared_types/src/model/chat_response.rs)
|
||||
- [attachment.rs](file://crates/shared_types/src/model/attachment.rs)
|
||||
- [model_provider.rs](file://crates/shared_types/src/model/model_provider.rs)
|
||||
- [http_result.rs](file://crates/shared_types/src/model/http_result.rs)
|
||||
- [app_error.rs](file://crates/shared_types/src/model/app_error.rs)
|
||||
- [chat_handler.rs](file://crates/agent_runner/src/handler/chat_handler.rs)
|
||||
- [agent_session_notification.rs](file://crates/agent_runner/src/handler/agent_session_notification.rs)
|
||||
- [session_cache.rs](file://crates/agent_runner/src/service/session_cache.rs)
|
||||
- [agent_service.rs](file://crates/agent_runner/src/proxy_agent/agent_service.rs)
|
||||
- [channel_utils.rs](file://crates/agent_runner/src/proxy_agent/channel_utils.rs)
|
||||
- [agent_session_notify.rs](file://crates/shared_types/src/model/agent_session_notify.rs)
|
||||
- [router.rs](file://crates/agent_runner/src/router.rs)
|
||||
- [http_test.rest](file://http_test.rest)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [简介](#简介)
|
||||
2. [项目结构](#项目结构)
|
||||
3. [核心组件](#核心组件)
|
||||
4. [架构总览](#架构总览)
|
||||
5. [详细组件分析](#详细组件分析)
|
||||
6. [依赖关系分析](#依赖关系分析)
|
||||
7. [性能考量](#性能考量)
|
||||
8. [故障排查指南](#故障排查指南)
|
||||
9. [结论](#结论)
|
||||
10. [附录](#附录)
|
||||
|
||||
## 简介
|
||||
本文件聚焦于聊天数据模型,系统性阐述 ChatPrompt 与 ChatResponse 的结构定义、提示词构造规则、上下文管理机制与附件处理方式;同时结合 chat_handler 的实现逻辑,完整描述从请求到响应的数据转换流程,并给出流式响应(SSE)的数据分块格式、进度更新机制与终止条件。最后提供 HTTP 请求/响应示例与边界情况、错误处理模式,帮助开发者快速理解并正确使用该系统。
|
||||
|
||||
## 项目结构
|
||||
围绕聊天数据模型的关键文件分布如下:
|
||||
- 共享类型层:定义 ChatPrompt、ChatResponse、附件与模型提供商配置等核心数据结构
|
||||
- 业务处理器层:chat_handler 负责接收请求、构建 ChatPrompt、调度代理并返回统一响应
|
||||
- 实时通知层:SSE 通道 agent_session_notification 将会话消息以事件形式推送给客户端
|
||||
- 会话缓存层:session_cache 提供会话级消息缓冲与推送,支持心跳、取消与清理
|
||||
- 代理服务层:根据模型提供商选择具体代理类型并启动 ACP 代理服务
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "共享类型层"
|
||||
A["ChatPrompt<br/>ChatResponse<br/>Attachment<br/>ModelProviderConfig"]
|
||||
end
|
||||
subgraph "业务处理器层"
|
||||
B["chat_handler.handle_chat"]
|
||||
end
|
||||
subgraph "代理服务层"
|
||||
C["agent_service.AcpAgentService"]
|
||||
end
|
||||
subgraph "实时通知层"
|
||||
D["agent_session_notification.SSE"]
|
||||
E["session_cache.SessionData<br/>SessionWorker"]
|
||||
end
|
||||
B --> A
|
||||
B --> C
|
||||
C --> E
|
||||
E --> D
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [chat_handler.rs](file://crates/agent_runner/src/handler/chat_handler.rs#L176-L320)
|
||||
- [agent_service.rs](file://crates/agent_runner/src/proxy_agent/agent_service.rs#L1-L62)
|
||||
- [session_cache.rs](file://crates/agent_runner/src/service/session_cache.rs#L1-L140)
|
||||
- [agent_session_notification.rs](file://crates/agent_runner/src/handler/agent_session_notification.rs#L355-L483)
|
||||
|
||||
章节来源
|
||||
- [router.rs](file://crates/agent_runner/src/router.rs#L41-L70)
|
||||
|
||||
## 核心组件
|
||||
- ChatPrompt:承载一次聊天请求的全部上下文,包括项目ID、工作目录、会话ID、提示词、附件、数据源附件、代理类型、服务类型、请求ID与模型提供商配置
|
||||
- ChatResponse:统一的聊天响应载体,包含项目ID、会话ID、可选错误信息与请求ID
|
||||
- Attachment:多形态附件抽象,支持文本、图像、音频、文档,统一通过 AttachmentSource 表达数据来源(文件路径、Base64、URL)
|
||||
- ModelProviderConfig:模型提供商配置,决定代理类型与 API 协议
|
||||
- HttpResult:统一的 HTTP 响应包装,包含 code、message、data、tid 与 success 字段
|
||||
- AppError:应用级错误封装,统一映射为 HTTP 响应
|
||||
|
||||
章节来源
|
||||
- [chat_prompt.rs](file://crates/shared_types/src/model/chat_prompt.rs#L1-L52)
|
||||
- [chat_response.rs](file://crates/shared_types/src/model/chat_response.rs#L1-L18)
|
||||
- [attachment.rs](file://crates/shared_types/src/model/attachment.rs#L1-L216)
|
||||
- [model_provider.rs](file://crates/shared_types/src/model/model_provider.rs#L1-L132)
|
||||
- [http_result.rs](file://crates/shared_types/src/model/http_result.rs#L1-L103)
|
||||
- [app_error.rs](file://crates/shared_types/src/model/app_error.rs#L1-L65)
|
||||
|
||||
## 架构总览
|
||||
下图展示从 HTTP 请求到 SSE 实时推送的整体流程,涵盖提示词构造、代理调度、会话管理与事件分发。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as "客户端"
|
||||
participant Handler as "chat_handler.handle_chat"
|
||||
participant Builder as "ChatPromptBuilder"
|
||||
participant Agent as "AcpAgentService"
|
||||
participant Worker as "LocalSetAgentRequest"
|
||||
participant Cache as "SessionData/SessionWorker"
|
||||
participant SSE as "agent_session_notification.SSE"
|
||||
Client->>Handler : POST /chat {prompt, attachments, ...}
|
||||
Handler->>Handler : 校验参数/生成project_id/request_id
|
||||
Handler->>Builder : 构建ChatPrompt
|
||||
Builder-->>Handler : ChatPrompt
|
||||
Handler->>Worker : 发送LocalSetAgentRequest
|
||||
Worker->>Agent : 启动代理服务并执行
|
||||
Agent->>Cache : 推送SessionNotify消息
|
||||
Cache-->>SSE : 通过mpsc通道分发消息
|
||||
SSE-->>Client : 事件流prompt_start/prompt_end/agent_message_chunk/heartbeat
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [chat_handler.rs](file://crates/agent_runner/src/handler/chat_handler.rs#L176-L320)
|
||||
- [agent_service.rs](file://crates/agent_runner/src/proxy_agent/agent_service.rs#L1-L62)
|
||||
- [session_cache.rs](file://crates/agent_runner/src/service/session_cache.rs#L140-L222)
|
||||
- [agent_session_notification.rs](file://crates/agent_runner/src/handler/agent_session_notification.rs#L355-L483)
|
||||
|
||||
## 详细组件分析
|
||||
|
||||
### ChatPrompt 与 ChatResponse 数据模型
|
||||
- ChatPrompt 字段要点
|
||||
- project_id:项目唯一标识,用于隔离工作空间
|
||||
- project_path:项目工作目录路径
|
||||
- session_id:会话标识,可选;若未提供则由代理自动创建并返回
|
||||
- prompt:用户提示词
|
||||
- attachments:附件列表,支持文本、图像、音频、文档
|
||||
- data_source_attachments:数据源附件(JSON 字符串数组),用于外部数据源信息传递
|
||||
- agent_type:代理类型(由模型提供商配置推导)
|
||||
- service_type:服务类型(固定为 RCoder)
|
||||
- request_id:请求追踪ID,可选
|
||||
- model_provider:模型提供商配置,决定代理与协议
|
||||
- ChatResponse 字段要点
|
||||
- project_id:项目ID
|
||||
- session_id:会话ID
|
||||
- error:可选错误信息
|
||||
- request_id:可选请求追踪ID
|
||||
|
||||
提示词构造规则
|
||||
- 若未提供 project_id,处理器会自动生成 UUID 并移除连字符,随后创建项目工作目录
|
||||
- 若未提供 session_id,处理器会清理该项目下的所有旧会话,确保全新开始
|
||||
- 若未提供 request_id,处理器会自动生成 UUID 并移除连字符
|
||||
- 代理类型由模型提供商配置推导,服务类型固定为 RCoder
|
||||
|
||||
附件处理方式
|
||||
- 附件通过统一的 Attachment 抽象表达,支持三种数据源:
|
||||
- FilePath:相对项目目录的文件路径
|
||||
- Base64:包含数据与 MIME 类型
|
||||
- Url:远程链接
|
||||
- 附件类型包括 Text、Image、Audio、Document,均包含可选的元数据(如文件名、尺寸、时长、大小)
|
||||
|
||||
章节来源
|
||||
- [chat_prompt.rs](file://crates/shared_types/src/model/chat_prompt.rs#L1-L52)
|
||||
- [chat_response.rs](file://crates/shared_types/src/model/chat_response.rs#L1-L18)
|
||||
- [attachment.rs](file://crates/shared_types/src/model/attachment.rs#L1-L216)
|
||||
- [model_provider.rs](file://crates/shared_types/src/model/model_provider.rs#L1-L132)
|
||||
- [chat_handler.rs](file://crates/agent_runner/src/handler/chat_handler.rs#L198-L210)
|
||||
- [chat_handler.rs](file://crates/agent_runner/src/handler/chat_handler.rs#L225-L258)
|
||||
- [chat_handler.rs](file://crates/agent_runner/src/handler/chat_handler.rs#L266-L283)
|
||||
|
||||
### 上下文管理机制
|
||||
- 项目与会话映射
|
||||
- 通过 PROJECT_SESSION_MAP 确保同一 project_id 仅对应一个活跃 session_id
|
||||
- 当 session_id 变化时,自动清理旧 session 的数据并更新映射
|
||||
- 会话缓存与推送
|
||||
- SessionData 维护当前连接与取消令牌,支持即时推送与环形缓冲
|
||||
- SessionWorker 负责将消息写入环形缓冲并实时推送到当前连接
|
||||
- 心跳消息定期发送,保持连接活性
|
||||
- 会话清理策略
|
||||
- 处理器在收到请求时,若指定 session_id 则移除该会话;否则清理该项目下所有会话
|
||||
- 取消任务时,主动触发 CancellationToken 并关闭发送端,确保连接及时断开
|
||||
|
||||
章节来源
|
||||
- [session_cache.rs](file://crates/agent_runner/src/service/session_cache.rs#L1-L140)
|
||||
- [session_cache.rs](file://crates/agent_runner/src/service/session_cache.rs#L140-L222)
|
||||
- [session_cache.rs](file://crates/agent_runner/src/service/session_cache.rs#L224-L355)
|
||||
- [chat_handler.rs](file://crates/agent_runner/src/handler/chat_handler.rs#L225-L258)
|
||||
|
||||
### 流式响应(SSE)数据分块格式与终止条件
|
||||
SSE 事件格式
|
||||
- 事件名称与消息类型映射
|
||||
- prompt_start:会话开始
|
||||
- prompt_end:会话结束(包含停止原因与可选错误信息)
|
||||
- agent_message_chunk:代理输出片段
|
||||
- user_message_chunk:用户输入片段
|
||||
- agent_thought_chunk:代理思考片段
|
||||
- tool_call/tool_call_update:工具调用与更新
|
||||
- plan/available_commands_update/current_mode_update:计划、可用命令与当前模式更新
|
||||
- heartbeat:心跳事件
|
||||
- 数据内容
|
||||
- 统一以 UnifiedSessionMessage 形式推送,包含 session_id、message_type、sub_type、data 与时间戳
|
||||
- data 内容根据子类型不同而异,例如 agent_message_chunk 的 data.content 包含文本内容与类型
|
||||
|
||||
进度更新机制
|
||||
- SSE 连接建立后立即发送 heartbeat,随后持续推送实时更新
|
||||
- 心跳定时器每 30 秒发送一次,用于维持连接活性
|
||||
- 当取消令牌被触发或发送端被关闭时,SSE 自然断开
|
||||
|
||||
终止条件
|
||||
- 会话结束事件(prompt_end)携带停止原因(如 EndTurn、MaxTokens、MaxTurnRequests、Refusal、Cancelled)
|
||||
- 取消任务时,主动关闭连接并清理旧消息
|
||||
- 容器连接失败或读取 SSE 流失败时,发送 error 事件并断开连接
|
||||
|
||||
章节来源
|
||||
- [agent_session_notification.rs](file://crates/agent_runner/src/handler/agent_session_notification.rs#L36-L57)
|
||||
- [agent_session_notification.rs](file://crates/agent_runner/src/handler/agent_session_notification.rs#L355-L483)
|
||||
- [agent_session_notify.rs](file://crates/shared_types/src/model/agent_session_notify.rs#L1-L180)
|
||||
- [session_cache.rs](file://crates/agent_runner/src/service/session_cache.rs#L140-L222)
|
||||
|
||||
### 请求到响应的完整数据转换流程
|
||||
- 输入:HTTP 请求体包含 prompt、可选 project_id、session_id、attachments、data_source_attachments、model_provider、request_id
|
||||
- 处理:
|
||||
- 参数校验(prompt 非空)
|
||||
- 自动生成 project_id 与 request_id(如缺失)
|
||||
- 清理旧会话(按 session_id 或项目维度)
|
||||
- 构建 ChatPrompt 并发送到本地任务通道
|
||||
- 等待 ChatPromptResponse,若包含错误则返回统一错误响应
|
||||
- 输出:HttpResult<ChatResponse>,包含项目ID、会话ID与可选错误信息
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start(["进入 handle_chat"]) --> Validate["校验 prompt 非空"]
|
||||
Validate --> GenIds{"是否提供 project_id/request_id?"}
|
||||
GenIds --> |否| GenPid["生成 project_id 并创建工作目录"]
|
||||
GenIds --> |是| UseProvided["使用提供的 project_id/request_id"]
|
||||
GenPid --> CleanSessions["清理旧会话按 session_id 或项目"]
|
||||
UseProvided --> CleanSessions
|
||||
CleanSessions --> BuildPrompt["构建 ChatPrompt"]
|
||||
BuildPrompt --> SendTask["发送 LocalSetAgentRequest"]
|
||||
SendTask --> AwaitResp{"收到 ChatPromptResponse?"}
|
||||
AwaitResp --> |是且有错误| ReturnErr["返回统一错误响应"]
|
||||
AwaitResp --> |是且无错误| ReturnOk["返回 HttpResult.success(ChatResponse)"]
|
||||
AwaitResp --> |否| ReturnLocalErr["返回本地发送错误"]
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [chat_handler.rs](file://crates/agent_runner/src/handler/chat_handler.rs#L176-L320)
|
||||
- [http_result.rs](file://crates/shared_types/src/model/http_result.rs#L1-L103)
|
||||
|
||||
章节来源
|
||||
- [chat_handler.rs](file://crates/agent_runner/src/handler/chat_handler.rs#L176-L320)
|
||||
- [http_result.rs](file://crates/shared_types/src/model/http_result.rs#L1-L103)
|
||||
|
||||
### 代理类型与模型提供商配置
|
||||
- 代理类型选择
|
||||
- 根据模型提供商配置推导代理类型(Claude、Codex 等)
|
||||
- 通过 AcpAgentService trait 启动对应代理服务
|
||||
- 模型提供商配置
|
||||
- 包含 id、name、base_url、api_key、requires_openai_auth、default_model、api_protocol
|
||||
- api_protocol 默认 OpenAI,支持 Anthropic 与 OpenAI
|
||||
|
||||
章节来源
|
||||
- [agent_service.rs](file://crates/agent_runner/src/proxy_agent/agent_service.rs#L1-L62)
|
||||
- [model_provider.rs](file://crates/shared_types/src/model/model_provider.rs#L1-L132)
|
||||
|
||||
## 依赖关系分析
|
||||
- 组件耦合与内聚
|
||||
- chat_handler 与 shared_types 的 ChatPrompt/ChatResponse 强耦合,但通过 Builder 模式降低复杂度
|
||||
- 代理服务通过 trait 解耦,便于扩展新代理类型
|
||||
- SSE 层通过 SessionData/SessionWorker 与处理器解耦,实现高内聚低耦合
|
||||
- 外部依赖
|
||||
- Axum 路由与响应封装
|
||||
- Tokio mpsc 通道用于异步消息传递
|
||||
- DashMap 用于全局会话缓存
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
chat_handler["chat_handler.handle_chat"] --> shared_types["shared_types.ChatPrompt/ChatResponse"]
|
||||
chat_handler --> agent_service["AcpAgentService"]
|
||||
agent_service --> session_cache["SessionData/SessionWorker"]
|
||||
session_cache --> agent_session_notification["SSE 事件推送"]
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [chat_handler.rs](file://crates/agent_runner/src/handler/chat_handler.rs#L176-L320)
|
||||
- [agent_service.rs](file://crates/agent_runner/src/proxy_agent/agent_service.rs#L1-L62)
|
||||
- [session_cache.rs](file://crates/agent_runner/src/service/session_cache.rs#L1-L140)
|
||||
- [agent_session_notification.rs](file://crates/agent_runner/src/handler/agent_session_notification.rs#L355-L483)
|
||||
|
||||
章节来源
|
||||
- [router.rs](file://crates/agent_runner/src/router.rs#L41-L70)
|
||||
|
||||
## 性能考量
|
||||
- 会话消息缓冲
|
||||
- 使用环形缓冲(ringbuf)提升消息吞吐,避免阻塞
|
||||
- 心跳消息不入环形缓冲,确保实时性
|
||||
- 连接管理
|
||||
- 通过 CancellationToken 主动关闭旧连接,避免资源泄漏
|
||||
- 即时推送失败时自动降级为丢弃,保证系统稳定性
|
||||
- 并发控制
|
||||
- 项目级并发限制:同一项目仅允许一个活跃代理任务
|
||||
- 会话级清理:确保新会话不会混入旧消息
|
||||
|
||||
章节来源
|
||||
- [session_cache.rs](file://crates/agent_runner/src/service/session_cache.rs#L140-L222)
|
||||
- [chat_handler.rs](file://crates/agent_runner/src/handler/chat_handler.rs#L211-L224)
|
||||
|
||||
## 故障排查指南
|
||||
常见错误与处理
|
||||
- 参数校验失败
|
||||
- prompt 为空:返回统一错误响应
|
||||
- 并发请求限制
|
||||
- 项目存在活跃代理任务:返回“Agent正在执行任务,请等待当前任务完成后再发送新请求”
|
||||
- 本地发送错误
|
||||
- 任务通道发送失败:返回本地发送错误
|
||||
- SSE 连接问题
|
||||
- 容器连接失败或读取流失败:发送 error 事件并断开连接
|
||||
- 未找到对应容器:返回“未找到 session_id 对应的活跃容器”
|
||||
|
||||
章节来源
|
||||
- [chat_handler.rs](file://crates/agent_runner/src/handler/chat_handler.rs#L137-L168)
|
||||
- [chat_handler.rs](file://crates/agent_runner/src/handler/chat_handler.rs#L211-L224)
|
||||
- [agent_session_notification.rs](file://crates/agent_runner/src/handler/agent_session_notification.rs#L135-L153)
|
||||
- [agent_session_notification.rs](file://crates/agent_runner/src/handler/agent_session_notification.rs#L231-L244)
|
||||
|
||||
## 结论
|
||||
本文系统梳理了聊天数据模型的核心结构与处理流程,明确了提示词构造规则、上下文管理机制与附件处理方式,并深入解析了 SSE 的事件格式、进度更新与终止条件。结合 chat_handler 的实现逻辑,读者可以准确把握从请求到响应的全链路数据转换过程,并据此编写正确的 HTTP 请求与客户端消费逻辑。
|
||||
|
||||
## 附录
|
||||
|
||||
### HTTP 请求/响应示例
|
||||
- 创建聊天会话(POST /chat)
|
||||
- 请求体字段:prompt、project_id(可选)、session_id(可选)、attachments(可选)、data_source_attachments(可选)、model_provider(可选)、request_id(可选)
|
||||
- 成功响应:HttpResult.success(ChatResponse),包含 project_id、session_id、request_id
|
||||
- 错误响应:HttpResult.error(code, message)
|
||||
- 建立 SSE 连接(GET /agent/progress/{session_id})
|
||||
- 事件类型:prompt_start、prompt_end、agent_message_chunk、user_message_chunk、agent_thought_chunk、tool_call、tool_call_update、plan、available_commands_update、current_mode_update、heartbeat
|
||||
- 断开条件:取消令牌触发、发送端关闭、容器连接失败
|
||||
- 取消会话(POST /agent/session/cancel)
|
||||
- 参数:project_id、session_id
|
||||
- 行为:主动关闭 SSE 连接并清理旧消息
|
||||
|
||||
章节来源
|
||||
- [http_test.rest](file://http_test.rest#L1-L109)
|
||||
- [chat_handler.rs](file://crates/agent_runner/src/handler/chat_handler.rs#L102-L173)
|
||||
- [agent_session_notification.rs](file://crates/agent_runner/src/handler/agent_session_notification.rs#L355-L483)
|
||||
413
qiming-rcoder/.qoder/repowiki/zh/content/数据模型与类型/附件模型.md
Normal file
413
qiming-rcoder/.qoder/repowiki/zh/content/数据模型与类型/附件模型.md
Normal file
@@ -0,0 +1,413 @@
|
||||
# 附件模型
|
||||
|
||||
<cite>
|
||||
**本文引用的文件**
|
||||
- [attachment.rs](file://crates/shared_types/src/model/attachment.rs)
|
||||
- [chat_prompt.rs](file://crates/shared_types/src/model/chat_prompt.rs)
|
||||
- [chat_response.rs](file://crates/shared_types/src/model/chat_response.rs)
|
||||
- [content_builder.rs](file://crates/agent_runner/src/utils/content_builder.rs)
|
||||
- [file_utils.rs](file://crates/agent_runner/src/utils/file_utils.rs)
|
||||
- [acp_agent.rs](file://crates/agent_runner/src/proxy_agent/acp_agent.rs)
|
||||
- [chat_handler.rs(rcoder)](file://crates/rcoder/src/handler/chat_handler.rs)
|
||||
- [chat_handler.rs(agent_runner)](file://crates/agent_runner/src/handler/chat_handler.rs)
|
||||
- [lib.rs(shared_types)](file://crates/shared_types/src/lib.rs)
|
||||
- [agent.proto](file://crates/shared_types/proto/agent.proto)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [简介](#简介)
|
||||
2. [项目结构](#项目结构)
|
||||
3. [核心组件](#核心组件)
|
||||
4. [架构总览](#架构总览)
|
||||
5. [详细组件分析](#详细组件分析)
|
||||
6. [依赖分析](#依赖分析)
|
||||
7. [性能考虑](#性能考虑)
|
||||
8. [故障排查指南](#故障排查指南)
|
||||
9. [结论](#结论)
|
||||
|
||||
## 简介
|
||||
本文件系统化阐述附件模型的设计与用途,覆盖以下方面:
|
||||
- Attachment 结构体族的组成与职责边界
|
||||
- 文件元数据(路径、大小、MIME 类型)的存储方式与来源
|
||||
- 附件在聊天上下文中的引用机制、与提示词构造的关系
|
||||
- 安全检查策略(文件扩展名、大小限制、来源类型)
|
||||
- 资源清理流程(临时文件、会话与代理资源)
|
||||
- 实际用例:附件如何参与 AI 代理交互并影响提示词构造
|
||||
|
||||
## 项目结构
|
||||
附件模型位于共享类型模块中,围绕该模型构建了聊天提示、内容转换、文件工具与代理交互链路。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "共享类型"
|
||||
A["attachment.rs<br/>定义 Attachment/AttachmentSource 及错误"]
|
||||
B["chat_prompt.rs<br/>ChatPrompt 含 attachments 字段"]
|
||||
C["chat_response.rs<br/>通用聊天响应结构"]
|
||||
D["agent.proto<br/>gRPC ChatRequest 含 attachments 字段"]
|
||||
end
|
||||
subgraph "代理运行时"
|
||||
E["content_builder.rs<br/>将 Attachment 转为 ContentBlock"]
|
||||
F["file_utils.rs<br/>文件校验/读取/创建附件"]
|
||||
G["acp_agent.rs<br/>构建 Prompt 并发送给代理"]
|
||||
H["chat_handler.rsrcoder<br/>接收请求并转发"]
|
||||
I["chat_handler.rsagent_runner<br/>接收请求并构建 ChatPrompt"]
|
||||
end
|
||||
A --> B
|
||||
B --> G
|
||||
E --> G
|
||||
F --> E
|
||||
H --> I
|
||||
I --> G
|
||||
D --> H
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [attachment.rs](file://crates/shared_types/src/model/attachment.rs#L1-L216)
|
||||
- [chat_prompt.rs](file://crates/shared_types/src/model/chat_prompt.rs#L1-L52)
|
||||
- [chat_response.rs](file://crates/shared_types/src/model/chat_response.rs#L1-L18)
|
||||
- [content_builder.rs](file://crates/agent_runner/src/utils/content_builder.rs#L1-L418)
|
||||
- [file_utils.rs](file://crates/agent_runner/src/utils/file_utils.rs#L1-L339)
|
||||
- [acp_agent.rs](file://crates/agent_runner/src/proxy_agent/acp_agent.rs#L343-L391)
|
||||
- [chat_handler.rs(rcoder)](file://crates/rcoder/src/handler/chat_handler.rs#L17-L53)
|
||||
- [chat_handler.rs(agent_runner)](file://crates/agent_runner/src/handler/chat_handler.rs#L1-L275)
|
||||
- [agent.proto](file://crates/shared_types/proto/agent.proto#L1-L43)
|
||||
|
||||
章节来源
|
||||
- [attachment.rs](file://crates/shared_types/src/model/attachment.rs#L1-L216)
|
||||
- [chat_prompt.rs](file://crates/shared_types/src/model/chat_prompt.rs#L1-L52)
|
||||
- [content_builder.rs](file://crates/agent_runner/src/utils/content_builder.rs#L1-L418)
|
||||
- [file_utils.rs](file://crates/agent_runner/src/utils/file_utils.rs#L1-L339)
|
||||
- [acp_agent.rs](file://crates/agent_runner/src/proxy_agent/acp_agent.rs#L343-L391)
|
||||
- [chat_handler.rs(rcoder)](file://crates/rcoder/src/handler/chat_handler.rs#L17-L53)
|
||||
- [chat_handler.rs(agent_runner)](file://crates/agent_runner/src/handler/chat_handler.rs#L1-L275)
|
||||
- [agent.proto](file://crates/shared_types/proto/agent.proto#L1-L43)
|
||||
|
||||
## 核心组件
|
||||
- 附件数据源类型:支持文件路径、Base64、URL 三种来源,统一通过枚举承载
|
||||
- 附件类型:文本、图像、音频、文档四类,均包含 id、source、可选元数据(如 filename、description、size、mime_type、dimensions、duration)
|
||||
- 附件错误:集中定义文件读取、类型不支持、Base64 解码、大小超限、URL 访问等错误
|
||||
- 聊天提示:ChatPrompt 携带 attachments 与 data_source_attachments,驱动代理侧提示词构建
|
||||
- 内容构建:将附件转换为 ACP ContentBlock,支撑多模态提示词
|
||||
- 文件工具:校验扩展名、大小限制、读取与创建附件、清理临时文件
|
||||
- 代理交互:构建 PromptRequest,将附件内容块注入提示词,并携带 request_id 等元信息
|
||||
|
||||
章节来源
|
||||
- [attachment.rs](file://crates/shared_types/src/model/attachment.rs#L1-L216)
|
||||
- [chat_prompt.rs](file://crates/shared_types/src/model/chat_prompt.rs#L1-L52)
|
||||
- [content_builder.rs](file://crates/agent_runner/src/utils/content_builder.rs#L1-L418)
|
||||
- [file_utils.rs](file://crates/agent_runner/src/utils/file_utils.rs#L1-L339)
|
||||
- [acp_agent.rs](file://crates/agent_runner/src/proxy_agent/acp_agent.rs#L343-L391)
|
||||
|
||||
## 架构总览
|
||||
附件在系统中的流转路径如下:
|
||||
- 客户端/上游服务通过 gRPC/HTTP 请求携带附件
|
||||
- 服务端解析请求,构建 ChatPrompt(含 attachments 与 data_source_attachments)
|
||||
- 代理侧将附件转换为 ContentBlock,拼接到提示词中
|
||||
- 代理执行推理,返回结果;同时进行资源清理
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as "客户端"
|
||||
participant Handler as "聊天处理器"
|
||||
participant Prompt as "ChatPrompt"
|
||||
participant Builder as "ContentBuilder"
|
||||
participant Agent as "代理ACPI"
|
||||
participant Resp as "响应"
|
||||
Client->>Handler : "提交聊天请求含附件"
|
||||
Handler->>Prompt : "构建 ChatPrompt包含 attachments"
|
||||
Prompt->>Builder : "将附件转换为 ContentBlock"
|
||||
Builder-->>Prompt : "返回内容块列表"
|
||||
Prompt->>Agent : "构建 PromptRequest含附件内容块"
|
||||
Agent-->>Resp : "返回聊天响应"
|
||||
Resp-->>Client : "返回结果"
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [chat_handler.rs(rcoder)](file://crates/rcoder/src/handler/chat_handler.rs#L17-L53)
|
||||
- [chat_handler.rs(agent_runner)](file://crates/agent_runner/src/handler/chat_handler.rs#L1-L275)
|
||||
- [chat_prompt.rs](file://crates/shared_types/src/model/chat_prompt.rs#L1-L52)
|
||||
- [content_builder.rs](file://crates/agent_runner/src/utils/content_builder.rs#L1-L418)
|
||||
- [acp_agent.rs](file://crates/agent_runner/src/proxy_agent/acp_agent.rs#L343-L391)
|
||||
- [agent.proto](file://crates/shared_types/proto/agent.proto#L1-L43)
|
||||
|
||||
## 详细组件分析
|
||||
|
||||
### 附件数据模型与元数据
|
||||
- 数据源类型
|
||||
- 文件路径:相对项目路径,便于在工作区定位
|
||||
- Base64:携带数据与 MIME 类型,适合内联传输
|
||||
- URL:远程资源,需网络访问
|
||||
- 附件类型与元数据
|
||||
- 文本附件:id、source、filename、description
|
||||
- 图像附件:id、source、mime_type、filename、description、dimensions
|
||||
- 音频附件:id、source、mime_type、filename、description、duration
|
||||
- 文档附件:id、source、mime_type、filename、description、size
|
||||
- 元数据来源
|
||||
- MIME 类型:由创建时指定或从扩展名推断
|
||||
- 大小:文档附件可选 size 字段
|
||||
- 尺寸/时长:图像/音频附件可选 dimensions/duration
|
||||
- 访问与查询
|
||||
- 提供 id()、mime_type()、source() 等便捷方法
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class AttachmentSource {
|
||||
<<enum>>
|
||||
+FilePath(path)
|
||||
+Base64(data,mime_type)
|
||||
+Url(url)
|
||||
}
|
||||
class TextAttachment {
|
||||
+string id
|
||||
+AttachmentSource source
|
||||
+string? filename
|
||||
+string? description
|
||||
}
|
||||
class ImageAttachment {
|
||||
+string id
|
||||
+AttachmentSource source
|
||||
+string mime_type
|
||||
+string? filename
|
||||
+string? description
|
||||
+ImageDimensions? dimensions
|
||||
}
|
||||
class AudioAttachment {
|
||||
+string id
|
||||
+AttachmentSource source
|
||||
+string mime_type
|
||||
+string? filename
|
||||
+string? description
|
||||
+f64? duration
|
||||
}
|
||||
class DocumentAttachment {
|
||||
+string id
|
||||
+AttachmentSource source
|
||||
+string mime_type
|
||||
+string? filename
|
||||
+string? description
|
||||
+u64? size
|
||||
}
|
||||
class Attachment {
|
||||
<<enum>>
|
||||
+Text(TextAttachment)
|
||||
+Image(ImageAttachment)
|
||||
+Audio(AudioAttachment)
|
||||
+Document(DocumentAttachment)
|
||||
+id() &str
|
||||
+mime_type() &str?
|
||||
+source() &AttachmentSource
|
||||
}
|
||||
Attachment --> AttachmentSource : "包含"
|
||||
Attachment --> TextAttachment : "分支"
|
||||
Attachment --> ImageAttachment : "分支"
|
||||
Attachment --> AudioAttachment : "分支"
|
||||
Attachment --> DocumentAttachment : "分支"
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [attachment.rs](file://crates/shared_types/src/model/attachment.rs#L1-L216)
|
||||
|
||||
章节来源
|
||||
- [attachment.rs](file://crates/shared_types/src/model/attachment.rs#L1-L216)
|
||||
|
||||
### 文件元数据存储与验证规则
|
||||
- 存储方式
|
||||
- MIME 类型:显式传入或通过扩展名推断
|
||||
- 大小:文档附件可选 size 字段;文件工具在读取时校验大小
|
||||
- 尺寸/时长:图像/音频附件可选 dimensions/duration 字段
|
||||
- 验证规则
|
||||
- 扩展名白名单:仅允许预设扩展名集合
|
||||
- 文件大小上限:默认 50MB,可通过配置调整
|
||||
- 来源类型约束:
|
||||
- 文本附件:禁止压缩文件作为文本附件
|
||||
- 图像/音频/文档:按来源类型分别读取或下载
|
||||
- 错误类型
|
||||
- 文件读取失败、不支持的文件类型、Base64 解码失败、文件大小超限、URL 访问失败
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start(["开始"]) --> Ext["校验扩展名"]
|
||||
Ext --> ExtOK{"扩展名合法?"}
|
||||
ExtOK -- 否 --> ErrExt["返回不支持的文件类型错误"]
|
||||
ExtOK -- 是 --> Size["校验文件大小"]
|
||||
Size --> SizeOK{"未超限?"}
|
||||
SizeOK -- 否 --> ErrSize["返回文件大小超限错误"]
|
||||
SizeOK -- 是 --> Read["按来源类型读取/解码"]
|
||||
Read --> Done(["结束"])
|
||||
ErrExt --> Done
|
||||
ErrSize --> Done
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [file_utils.rs](file://crates/agent_runner/src/utils/file_utils.rs#L1-L339)
|
||||
- [attachment.rs](file://crates/shared_types/src/model/attachment.rs#L184-L216)
|
||||
|
||||
章节来源
|
||||
- [file_utils.rs](file://crates/agent_runner/src/utils/file_utils.rs#L1-L339)
|
||||
- [attachment.rs](file://crates/shared_types/src/model/attachment.rs#L184-L216)
|
||||
|
||||
### 附件在聊天上下文中的引用机制
|
||||
- 请求结构
|
||||
- rcoder 与 agent_runner 的聊天处理器均支持 attachments 字段
|
||||
- ChatPromptBuilder 用于组装 ChatPrompt,包含 attachments 与 data_source_attachments
|
||||
- 引用与传递
|
||||
- ChatRequest/ChatPrompt 持有附件列表
|
||||
- gRPC ChatRequest 也包含 attachments 字段,便于跨服务传递
|
||||
- 会话与请求追踪
|
||||
- request_id 可选,若未提供则自动生成
|
||||
- 构建 PromptRequest 时将 request_id 放入 meta,便于后续追踪
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant RC as "rcoder 聊天处理器"
|
||||
participant AR as "agent_runner 聊天处理器"
|
||||
participant CP as "ChatPromptBuilder"
|
||||
participant PR as "PromptRequest"
|
||||
RC->>AR : "转发聊天请求含 attachments"
|
||||
AR->>CP : "构建 ChatPromptproject_id/session_id/prompt/attachments"
|
||||
CP-->>AR : "返回 ChatPrompt"
|
||||
AR->>PR : "构建 PromptRequest附加附件内容块"
|
||||
PR-->>AR : "返回 PromptRequest"
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [chat_handler.rs(rcoder)](file://crates/rcoder/src/handler/chat_handler.rs#L17-L53)
|
||||
- [chat_handler.rs(agent_runner)](file://crates/agent_runner/src/handler/chat_handler.rs#L1-L275)
|
||||
- [chat_prompt.rs](file://crates/shared_types/src/model/chat_prompt.rs#L1-L52)
|
||||
- [acp_agent.rs](file://crates/agent_runner/src/proxy_agent/acp_agent.rs#L343-L391)
|
||||
- [agent.proto](file://crates/shared_types/proto/agent.proto#L1-L43)
|
||||
|
||||
章节来源
|
||||
- [chat_handler.rs(rcoder)](file://crates/rcoder/src/handler/chat_handler.rs#L17-L53)
|
||||
- [chat_handler.rs(agent_runner)](file://crates/agent_runner/src/handler/chat_handler.rs#L1-L275)
|
||||
- [chat_prompt.rs](file://crates/shared_types/src/model/chat_prompt.rs#L1-L52)
|
||||
- [agent.proto](file://crates/shared_types/proto/agent.proto#L1-L43)
|
||||
|
||||
### 安全检查策略
|
||||
- 文件扩展名校验:仅允许白名单扩展名,避免恶意文件
|
||||
- 文件大小限制:防止过大附件导致内存压力与网络开销
|
||||
- 来源类型安全:
|
||||
- 文本附件禁止压缩文件
|
||||
- URL 读取采用网络客户端,失败即忽略并记录告警
|
||||
- 附件转换容错:读取失败或网络异常时静默忽略,不影响主流程
|
||||
|
||||
章节来源
|
||||
- [file_utils.rs](file://crates/agent_runner/src/utils/file_utils.rs#L1-L339)
|
||||
- [content_builder.rs](file://crates/agent_runner/src/utils/content_builder.rs#L1-L418)
|
||||
|
||||
### 资源清理流程
|
||||
- 临时文件清理:文件工具提供批量清理临时文件的能力
|
||||
- 代理与会话资源:代理侧通过生命周期守卫与连接池管理,结合定时清理任务,确保代理进程、会话与 SSE 消息得到回收
|
||||
- 清理策略要点:
|
||||
- 基于 RAII 的自动清理:移除映射后由生命周期守卫触发资源回收
|
||||
- 超时保护:清理过程设置超时,避免阻塞
|
||||
- 统计与日志:记录清理统计,便于运维监控
|
||||
|
||||
章节来源
|
||||
- [file_utils.rs](file://crates/agent_runner/src/utils/file_utils.rs#L312-L322)
|
||||
- [acp_agent.rs](file://crates/agent_runner/src/proxy_agent/acp_agent.rs#L343-L391)
|
||||
|
||||
### 附件与 AI 代理交互及提示词构造
|
||||
- 附件到内容块的转换
|
||||
- 文本:优先按文本读取,失败则忽略
|
||||
- 图像/音频:按来源读取为 Base64,附带 URI
|
||||
- 文档:按 MIME 类型区分文本/二进制,文本走 TextResourceContents,二进制走 BlobResourceContents,URL 走 ResourceLink
|
||||
- 提示词构造
|
||||
- 将最终提示词与附件内容块合并为 ContentBlocks
|
||||
- 若存在 data_source_attachments,则在构建时加入数据源信息
|
||||
- 将 request_id 放入 meta,便于通道层追踪
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
P["ChatPrompt.attachments"] --> CB["ContentBuilder.attachments_to_content_blocks"]
|
||||
CB --> Blocks{"每种附件类型?"}
|
||||
Blocks --> |文本| T["TextContent"]
|
||||
Blocks --> |图像| I["ImageContent(Base64)"]
|
||||
Blocks --> |音频| A["AudioContent(Base64)"]
|
||||
Blocks --> |文档| D{"MIME 类型为 text/* ?"}
|
||||
D --> |是| DT["TextResourceContents"]
|
||||
D --> |否| DB["BlobResourceContents"]
|
||||
T --> Merge["合并为 ContentBlocks"]
|
||||
I --> Merge
|
||||
A --> Merge
|
||||
DT --> Merge
|
||||
DB --> Merge
|
||||
Merge --> PR["PromptRequest含附件内容块"]
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [content_builder.rs](file://crates/agent_runner/src/utils/content_builder.rs#L1-L418)
|
||||
- [acp_agent.rs](file://crates/agent_runner/src/proxy_agent/acp_agent.rs#L343-L391)
|
||||
|
||||
章节来源
|
||||
- [content_builder.rs](file://crates/agent_runner/src/utils/content_builder.rs#L1-L418)
|
||||
- [acp_agent.rs](file://crates/agent_runner/src/proxy_agent/acp_agent.rs#L343-L391)
|
||||
|
||||
## 依赖分析
|
||||
- 低耦合高内聚
|
||||
- shared_types 的附件模型独立于具体实现,便于跨服务复用
|
||||
- 代理侧通过 ContentBuilder 与 file_utils 解耦附件读取与转换
|
||||
- 关键依赖关系
|
||||
- ChatPrompt 依赖 Attachment/AttachmentSource
|
||||
- ContentBuilder 依赖 agent_client_protocol 的 ContentBlock 类型
|
||||
- file_utils 依赖 base64、tokio fs、reqwest
|
||||
- 聊天处理器依赖 ChatPromptBuilder 与模型提供商配置
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
Shared["shared_types: attachment.rs"] --> Prompt["chat_prompt.rs"]
|
||||
Prompt --> Builder["content_builder.rs"]
|
||||
Builder --> Utils["file_utils.rs"]
|
||||
HandlerR["chat_handler.rsrcoder"] --> HandlerA["chat_handler.rsagent_runner"]
|
||||
HandlerA --> Prompt
|
||||
Proto["agent.proto"] --> HandlerR
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [attachment.rs](file://crates/shared_types/src/model/attachment.rs#L1-L216)
|
||||
- [chat_prompt.rs](file://crates/shared_types/src/model/chat_prompt.rs#L1-L52)
|
||||
- [content_builder.rs](file://crates/agent_runner/src/utils/content_builder.rs#L1-L418)
|
||||
- [file_utils.rs](file://crates/agent_runner/src/utils/file_utils.rs#L1-L339)
|
||||
- [chat_handler.rs(rcoder)](file://crates/rcoder/src/handler/chat_handler.rs#L17-L53)
|
||||
- [chat_handler.rs(agent_runner)](file://crates/agent_runner/src/handler/chat_handler.rs#L1-L275)
|
||||
- [agent.proto](file://crates/shared_types/proto/agent.proto#L1-L43)
|
||||
|
||||
章节来源
|
||||
- [lib.rs(shared_types)](file://crates/shared_types/src/lib.rs#L1-L71)
|
||||
- [attachment.rs](file://crates/shared_types/src/model/attachment.rs#L1-L216)
|
||||
- [chat_prompt.rs](file://crates/shared_types/src/model/chat_prompt.rs#L1-L52)
|
||||
- [content_builder.rs](file://crates/agent_runner/src/utils/content_builder.rs#L1-L418)
|
||||
- [file_utils.rs](file://crates/agent_runner/src/utils/file_utils.rs#L1-L339)
|
||||
- [chat_handler.rs(rcoder)](file://crates/rcoder/src/handler/chat_handler.rs#L17-L53)
|
||||
- [chat_handler.rs(agent_runner)](file://crates/agent_runner/src/handler/chat_handler.rs#L1-L275)
|
||||
- [agent.proto](file://crates/shared_types/proto/agent.proto#L1-L43)
|
||||
|
||||
## 性能考虑
|
||||
- 附件读取与转换
|
||||
- 优先使用 Base64 内联传输,减少磁盘 IO;对大文件建议使用 URL 或文件路径
|
||||
- 文档附件优先按文本读取,失败再降级为二进制,避免不必要的解码
|
||||
- 网络访问
|
||||
- URL 读取采用异步客户端,失败即短路,避免阻塞
|
||||
- 大小限制
|
||||
- 默认 50MB 上限,可根据部署环境调优,平衡吞吐与稳定性
|
||||
- 清理与回收
|
||||
- 定时清理代理与会话资源,避免长期运行导致资源泄漏
|
||||
|
||||
## 故障排查指南
|
||||
- 常见错误与定位
|
||||
- 文件读取失败:检查路径是否存在、权限是否足够
|
||||
- 不支持的文件类型:确认扩展名在白名单中
|
||||
- Base64 解码失败:确认数据格式正确且未被截断
|
||||
- 文件大小超限:调整上传策略或增大阈值
|
||||
- URL 访问失败:检查网络连通性与目标可达性
|
||||
- 日志与追踪
|
||||
- 附件转换失败会记录告警日志,建议结合 request_id 追踪
|
||||
- 清理任务输出统计信息,便于发现异常增长
|
||||
|
||||
章节来源
|
||||
- [attachment.rs](file://crates/shared_types/src/model/attachment.rs#L184-L216)
|
||||
- [file_utils.rs](file://crates/agent_runner/src/utils/file_utils.rs#L1-L339)
|
||||
- [content_builder.rs](file://crates/agent_runner/src/utils/content_builder.rs#L1-L418)
|
||||
|
||||
## 结论
|
||||
附件模型通过统一的数据源与类型抽象,为多模态聊天提供了清晰的扩展点。配合严格的验证规则与容错转换,既保证了安全性,又提升了可用性。在代理交互层面,附件被无缝注入提示词,显著增强了 AI 的上下文理解能力。建议在生产环境中合理设置大小阈值与扩展名白名单,并持续监控清理任务与日志,确保系统稳定高效运行。
|
||||
328
qiming-rcoder/.qoder/repowiki/zh/content/数据模型与类型/项目状态模型.md
Normal file
328
qiming-rcoder/.qoder/repowiki/zh/content/数据模型与类型/项目状态模型.md
Normal file
@@ -0,0 +1,328 @@
|
||||
# 项目状态模型
|
||||
|
||||
<cite>
|
||||
**本文引用的文件**
|
||||
- [agent_project_runner_model.rs](file://crates/shared_types/src/model/agent_project_runner_model.rs)
|
||||
- [agent_model.rs](file://crates/shared_types/src/model/agent_model.rs)
|
||||
- [session_cache.rs](file://crates/agent_runner/src/service/session_cache.rs)
|
||||
- [docker_container_agent.rs](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs)
|
||||
- [chat_handler.rs](file://crates/rcoder/src/handler/chat_handler.rs)
|
||||
- [cleanup_task.rs](file://crates/rcoder/src/proxy_agent/cleanup_task.rs)
|
||||
- [agent-abstraction-layer-design.md](file://specs/agent-abstraction-layer-design.md)
|
||||
</cite>
|
||||
|
||||
## 目录
|
||||
1. [简介](#简介)
|
||||
2. [项目结构](#项目结构)
|
||||
3. [核心组件](#核心组件)
|
||||
4. [架构总览](#架构总览)
|
||||
5. [详细组件分析](#详细组件分析)
|
||||
6. [依赖关系分析](#依赖关系分析)
|
||||
7. [性能考量](#性能考量)
|
||||
8. [故障排查指南](#故障排查指南)
|
||||
9. [结论](#结论)
|
||||
|
||||
## 简介
|
||||
本文件围绕“项目状态模型”展开,重点解析 ProjectCoreState、ProjectExtendedState、ProjectState 以及 ProjectAndAgentInfo 等核心状态结构,阐明其字段语义、变更触发条件与同步机制;结合 agent_runner 与 rcoder 模块的实际用例,说明状态在 AI 代理生命周期中的流转;提供状态图示例与典型场景下的数据快照;解释线程安全处理方式(如 Arc、DashMap、Arc::make_mut、CancellationToken 等)与并发访问模式,并给出一致性保障措施。
|
||||
|
||||
## 项目结构
|
||||
本仓库采用多 crate 分层组织,其中与“项目状态模型”直接相关的模块包括:
|
||||
- shared_types:跨模块共享的模型定义,包含 ProjectCoreState、ProjectExtendedState、ProjectState、ProjectAndAgentInfo、AgentStatus 等。
|
||||
- agent_runner:会话缓存与消息推送,涉及 session_id 与 Project 的映射管理。
|
||||
- rcoder:代理容器化启动、状态清理与生命周期管理,涉及 Docker 容器生命周期与状态清理。
|
||||
- specs:抽象层设计文档,描述 AgentStatus 的状态机与生命周期管理。
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "共享类型"
|
||||
A["ProjectCoreState<br/>ProjectExtendedState<br/>ProjectState<br/>ProjectAndAgentInfo<br/>AgentStatus"]
|
||||
end
|
||||
subgraph "agent_runner"
|
||||
B["SessionData<br/>SESSION_CACHE<br/>PROJECT_SESSION_MAP"]
|
||||
C["push_session_update<br/>ensure_project_session"]
|
||||
end
|
||||
subgraph "rcoder"
|
||||
D["Docker 容器代理启动<br/>start_docker_container_agent_service"]
|
||||
E["清理任务<br/>cleanup_task"]
|
||||
F["聊天处理器<br/>chat_handler"]
|
||||
end
|
||||
A --> B
|
||||
B --> C
|
||||
D --> E
|
||||
F --> A
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [agent_project_runner_model.rs](file://crates/shared_types/src/model/agent_project_runner_model.rs#L30-L189)
|
||||
- [session_cache.rs](file://crates/agent_runner/src/service/session_cache.rs#L1-L120)
|
||||
- [docker_container_agent.rs](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs#L21-L130)
|
||||
- [chat_handler.rs](file://crates/rcoder/src/handler/chat_handler.rs#L245-L270)
|
||||
- [cleanup_task.rs](file://crates/rcoder/src/proxy_agent/cleanup_task.rs#L650-L720)
|
||||
|
||||
章节来源
|
||||
- [agent_project_runner_model.rs](file://crates/shared_types/src/model/agent_project_runner_model.rs#L30-L189)
|
||||
- [session_cache.rs](file://crates/agent_runner/src/service/session_cache.rs#L1-L120)
|
||||
- [docker_container_agent.rs](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs#L21-L130)
|
||||
- [chat_handler.rs](file://crates/rcoder/src/handler/chat_handler.rs#L245-L270)
|
||||
- [cleanup_task.rs](file://crates/rcoder/src/proxy_agent/cleanup_task.rs#L650-L720)
|
||||
|
||||
## 核心组件
|
||||
本节聚焦“项目状态模型”的核心结构及其职责边界。
|
||||
|
||||
- ProjectCoreState
|
||||
- 字段语义:project_id(项目唯一标识)、session_id(会话标识,可选)、last_activity(最后活动时间)、created_at(创建时间)。
|
||||
- 变更触发:update_session 在创建会话时设置 session_id 并刷新 last_activity;update_activity 仅刷新 last_activity。
|
||||
- 访问模式:高频读写,适合通过 Arc 共享与写时复制更新。
|
||||
|
||||
- ProjectExtendedState
|
||||
- 字段语义:model_provider(模型提供商配置,可选)、container(容器信息,可选)、request_id(当前活跃请求ID,可选)、status(Agent 服务状态,可选)。
|
||||
- 变更触发:update_from_request 批量更新容器、模型提供商与请求ID;也可通过可变访问器逐项更新。
|
||||
- 访问模式:相对稳定的扩展字段,适合 Arc 共享与写时复制更新。
|
||||
|
||||
- ProjectState
|
||||
- 设计要点:将 core 与 extended 分离,分别使用 Arc 共享,提供 update_core/update_extended 方法,内部通过 Arc::make_mut 实现写时复制,避免不必要的深拷贝。
|
||||
- 便捷访问器:project_id、session_id、last_activity。
|
||||
|
||||
- ProjectAndAgentInfo
|
||||
- 字段语义:在共享类型中提供向后兼容的结构,内部持有 ProjectState,暴露与 ProjectState 对应的更新与访问方法。
|
||||
- 变更触发:update_session、update_activity、set_* 系列方法触发状态更新。
|
||||
|
||||
- AgentStatus
|
||||
- 枚举值:Active(活跃)、Idle(空闲)、Terminating(正在终止)。
|
||||
- 用途:表示 Agent 服务的运行状态,配合 last_activity、request_id 等字段共同反映代理生命周期。
|
||||
|
||||
章节来源
|
||||
- [agent_project_runner_model.rs](file://crates/shared_types/src/model/agent_project_runner_model.rs#L30-L189)
|
||||
- [agent_model.rs](file://crates/shared_types/src/model/agent_model.rs#L32-L41)
|
||||
|
||||
## 架构总览
|
||||
下图展示“项目状态模型”在 rcoder 与 agent_runner 之间的交互,以及状态在代理生命周期中的流转。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Client as "客户端"
|
||||
participant RC as "rcoder 聊天处理器(chat_handler)"
|
||||
participant PS as "ProjectAndAgentInfo(ProjectState)"
|
||||
participant AR as "agent_runner 会话缓存(session_cache)"
|
||||
participant DC as "Docker 容器代理(docker_container_agent)"
|
||||
Client->>RC : "发起聊天/会话请求"
|
||||
RC->>PS : "update_session(session_id)"
|
||||
RC->>PS : "update_activity()"
|
||||
RC->>AR : "push_session_update_with_project(project_id, session_id, notify)"
|
||||
AR->>AR : "ensure_project_session(project_id, session_id)"
|
||||
AR-->>RC : "推送消息到 SessionData"
|
||||
RC->>DC : "启动容器化 Agent 服务(若需要)"
|
||||
DC-->>RC : "返回容器信息与服务URL"
|
||||
RC-->>Client : "返回会话状态与服务信息"
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [chat_handler.rs](file://crates/rcoder/src/handler/chat_handler.rs#L245-L270)
|
||||
- [session_cache.rs](file://crates/agent_runner/src/service/session_cache.rs#L259-L355)
|
||||
- [docker_container_agent.rs](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs#L21-L130)
|
||||
- [agent_project_runner_model.rs](file://crates/shared_types/src/model/agent_project_runner_model.rs#L170-L202)
|
||||
|
||||
## 详细组件分析
|
||||
|
||||
### ProjectCoreState 与 ProjectExtendedState 的字段语义与更新流程
|
||||
- 字段语义
|
||||
- project_id:项目唯一标识,贯穿整个生命周期。
|
||||
- session_id:会话标识,首次创建会话时设置,用于区分不同会话。
|
||||
- last_activity:最近一次活动时间,用于空闲检测与清理策略。
|
||||
- created_at:创建时间,用于统计与审计。
|
||||
- model_provider/container/request_id/status:扩展状态,承载容器、模型提供商、请求ID与服务状态等信息。
|
||||
|
||||
- 更新流程
|
||||
- update_session:设置 session_id 并刷新 last_activity。
|
||||
- update_activity:仅刷新 last_activity。
|
||||
- update_from_request:批量更新容器、模型提供商与请求ID。
|
||||
|
||||
- 写时复制更新
|
||||
- ProjectState.update_core/update_extended 内部使用 Arc::make_mut,在需要修改时才触发写时复制,避免不必要的深拷贝。
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
Start(["进入更新流程"]) --> CheckCore["是否更新核心状态?"]
|
||||
CheckCore --> |是| MakeMutCore["Arc::make_mut(core)"]
|
||||
MakeMutCore --> ApplyCore["应用更新: update_session/update_activity"]
|
||||
CheckCore --> |否| CheckExtended["是否更新扩展状态?"]
|
||||
CheckExtended --> |是| MakeMutExtended["Arc::make_mut(extended)"]
|
||||
MakeMutExtended --> ApplyExtended["应用更新: update_from_request/set_*"]
|
||||
CheckExtended --> |否| End(["结束"])
|
||||
ApplyCore --> End
|
||||
ApplyExtended --> End
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [agent_project_runner_model.rs](file://crates/shared_types/src/model/agent_project_runner_model.rs#L117-L159)
|
||||
|
||||
章节来源
|
||||
- [agent_project_runner_model.rs](file://crates/shared_types/src/model/agent_project_runner_model.rs#L30-L189)
|
||||
|
||||
### 会话映射与消息推送(agent_runner)
|
||||
- SESSION_CACHE:按 session_id 分组缓存会话消息,使用环形缓冲区与实时推送相结合的方式,减少内存占用并保证消息及时送达。
|
||||
- PROJECT_SESSION_MAP:确保一个 project_id 只对应一个活跃的 session_id。当 session_id 变化时,自动清理旧 session 的缓存数据。
|
||||
- push_session_update/push_session_update_with_project:将通知转换为统一消息并推送到 SessionData;ensure_project_session 负责维护映射关系与清理旧数据。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant AR as "agent_runner"
|
||||
participant PC as "PROJECT_SESSION_MAP"
|
||||
participant SC as "SESSION_CACHE"
|
||||
participant SD as "SessionData"
|
||||
AR->>PC : "ensure_project_session(project_id, session_id)"
|
||||
alt session_id 变化
|
||||
PC-->>SC : "移除旧 session_id 对应的缓存"
|
||||
end
|
||||
AR->>SC : "push_session_update(session_id, notify)"
|
||||
SC->>SD : "实时推送消息"
|
||||
SD-->>AR : "推送完成"
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [session_cache.rs](file://crates/agent_runner/src/service/session_cache.rs#L259-L355)
|
||||
|
||||
章节来源
|
||||
- [session_cache.rs](file://crates/agent_runner/src/service/session_cache.rs#L1-L120)
|
||||
- [session_cache.rs](file://crates/agent_runner/src/service/session_cache.rs#L259-L355)
|
||||
|
||||
### rcoder 中的状态更新与生命周期清理
|
||||
- 聊天处理器(chat_handler)
|
||||
- 在收到请求时,检查并更新项目会话状态:若 session_id 不同则更新会话并刷新 last_activity;若相同则仅更新活动时间。
|
||||
- 使用 Arc::make_mut 与写时复制更新,避免不必要的深拷贝。
|
||||
|
||||
- 清理任务(cleanup_task)
|
||||
- 通过 DashMap 的 Entry API 原子性地移除项目到代理的映射,触发 AgentLifecycleGuard 的 Drop,从而自动清理资源。
|
||||
- 清理顺序:销毁 Docker 容器 -> 原子性移除项目映射 -> 原子性清理 sessions 映射 -> 输出清理完成日志。
|
||||
- 超时保护:清理过程整体超时控制,防止阻塞。
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant RT as "清理任务(cleanup_task)"
|
||||
participant PM as "PROJECT_AND_AGENT_INFO_MAP"
|
||||
participant SM as "sessions 映射"
|
||||
participant DM as "DockerManager"
|
||||
RT->>DM : "destroy_docker_container(project_id)"
|
||||
DM-->>RT : "容器销毁完成"
|
||||
RT->>PM : "原子性移除项目映射"
|
||||
PM-->>RT : "返回 session_id"
|
||||
RT->>SM : "原子性清理 sessions 映射(session_id)"
|
||||
SM-->>RT : "清理完成"
|
||||
RT-->>RT : "输出清理完成日志"
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [cleanup_task.rs](file://crates/rcoder/src/proxy_agent/cleanup_task.rs#L650-L720)
|
||||
- [docker_container_agent.rs](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs#L733-L785)
|
||||
|
||||
章节来源
|
||||
- [chat_handler.rs](file://crates/rcoder/src/handler/chat_handler.rs#L245-L270)
|
||||
- [cleanup_task.rs](file://crates/rcoder/src/proxy_agent/cleanup_task.rs#L650-L720)
|
||||
- [docker_container_agent.rs](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs#L733-L785)
|
||||
|
||||
### AgentStatus 状态机与生命周期
|
||||
- AgentStatus 枚举:Active、Idle、Terminating。
|
||||
- 状态切换时机(基于现有实现抽象):
|
||||
- Active:收到 Prompt 请求时。
|
||||
- Idle:Prompt 处理完成或被取消时。
|
||||
- Terminating:Agent 停止过程中。
|
||||
- AgentLifecycleGuard:遵循 RAII 原则,当守卫被 drop 时自动清理资源;提供 graceful_stop、cancel、is_stopped、cancellation_token 等接口。
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> Idle
|
||||
Idle --> Active : "收到 Prompt 请求"
|
||||
Active --> Idle : "任务完成/取消"
|
||||
Active --> Terminating : "停止中"
|
||||
Terminating --> [*]
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [agent_model.rs](file://crates/shared_types/src/model/agent_model.rs#L32-L41)
|
||||
- [agent-abstraction-layer-design.md](file://specs/agent-abstraction-layer-design.md#L1157-L1225)
|
||||
|
||||
章节来源
|
||||
- [agent_model.rs](file://crates/shared_types/src/model/agent_model.rs#L32-L41)
|
||||
- [agent-abstraction-layer-design.md](file://specs/agent-abstraction-layer-design.md#L1157-L1225)
|
||||
|
||||
### 线程安全与并发访问模式
|
||||
- Arc 共享与写时复制
|
||||
- ProjectState 将 core 与 extended 分离,分别使用 Arc 共享,通过 Arc::make_mut 在需要修改时才触发写时复制,降低锁竞争与内存拷贝成本。
|
||||
- DashMap 原子性操作
|
||||
- cleanup_task 使用 DashMap::entry API 原子性地移除映射,避免读写锁竞争,确保清理过程的一致性。
|
||||
- CancellationToken
|
||||
- AgentLifecycleGuard 使用 CancellationToken 实现非阻塞取消,优雅停止时先 cancel 再强制清理,保证资源释放与一致性。
|
||||
- 会话连接管理
|
||||
- SessionData 直接共享当前连接与取消令牌,避免命令传递带来的额外开销;close_current_connection 主动触发取消令牌并显式关闭发送端,确保接收端能及时感知连接关闭。
|
||||
|
||||
章节来源
|
||||
- [agent_project_runner_model.rs](file://crates/shared_types/src/model/agent_project_runner_model.rs#L117-L159)
|
||||
- [cleanup_task.rs](file://crates/rcoder/src/proxy_agent/cleanup_task.rs#L661-L704)
|
||||
- [agent_model.rs](file://crates/shared_types/src/model/agent_model.rs#L218-L338)
|
||||
- [session_cache.rs](file://crates/agent_runner/src/service/session_cache.rs#L1-L120)
|
||||
|
||||
## 依赖关系分析
|
||||
- ProjectState 依赖于 chrono 时间类型与 serde 序列化能力,用于时间戳与持久化。
|
||||
- ProjectAndAgentInfo 依赖于 shared_types 中的 AgentStatus、ModelProviderConfig 等类型,用于承载代理状态与模型配置。
|
||||
- agent_runner 的 session_cache 依赖 DashMap、ringbuf、tokio channels 等并发与缓冲机制。
|
||||
- rcoder 的清理任务依赖 DockerManager、DashMap、Tokio 定时器与超时控制。
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
Shared["shared_types 模型"] --> Runner["agent_runner 会话缓存"]
|
||||
Shared --> RC["rcoder 聊天处理器"]
|
||||
Runner --> RC
|
||||
RC --> Docker["DockerManager"]
|
||||
RC --> Cleaner["清理任务"]
|
||||
```
|
||||
|
||||
图表来源
|
||||
- [agent_project_runner_model.rs](file://crates/shared_types/src/model/agent_project_runner_model.rs#L30-L189)
|
||||
- [session_cache.rs](file://crates/agent_runner/src/service/session_cache.rs#L1-L120)
|
||||
- [chat_handler.rs](file://crates/rcoder/src/handler/chat_handler.rs#L245-L270)
|
||||
- [docker_container_agent.rs](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs#L21-L130)
|
||||
- [cleanup_task.rs](file://crates/rcoder/src/proxy_agent/cleanup_task.rs#L650-L720)
|
||||
|
||||
章节来源
|
||||
- [agent_project_runner_model.rs](file://crates/shared_types/src/model/agent_project_runner_model.rs#L30-L189)
|
||||
- [session_cache.rs](file://crates/agent_runner/src/service/session_cache.rs#L1-L120)
|
||||
- [chat_handler.rs](file://crates/rcoder/src/handler/chat_handler.rs#L245-L270)
|
||||
- [docker_container_agent.rs](file://crates/rcoder/src/proxy_agent/docker_container_agent.rs#L21-L130)
|
||||
- [cleanup_task.rs](file://crates/rcoder/src/proxy_agent/cleanup_task.rs#L650-L720)
|
||||
|
||||
## 性能考量
|
||||
- 写时复制(Arc::make_mut):在频繁读取、偶发更新的场景下显著降低锁竞争与内存拷贝成本。
|
||||
- 会话缓存优化:RingBuffer 缓冲与实时推送结合,既能保证消息及时性,又能控制内存占用。
|
||||
- 原子性操作:DashMap::entry API 在清理映射时避免读写锁竞争,提升清理吞吐。
|
||||
- 取消令牌:CancellationToken 非阻塞取消,配合优雅停止流程,减少资源泄漏与阻塞风险。
|
||||
- 端口与网络优化:容器内部网络通信,避免宿主机端口映射与释放带来的额外开销。
|
||||
|
||||
## 故障排查指南
|
||||
- 会话映射异常
|
||||
- 现象:同一 project_id 出现多个活跃 session。
|
||||
- 排查:确认 ensure_project_session 是否正确清理旧 session;检查 PROJECT_SESSION_MAP 的原子性插入与移除。
|
||||
- 参考路径:[session_cache.rs](file://crates/agent_runner/src/service/session_cache.rs#L282-L355)
|
||||
|
||||
- 清理任务超时或阻塞
|
||||
- 现象:清理任务超时或长时间不结束。
|
||||
- 排查:检查 destroy_docker_container 是否成功;确认清理流程中的超时保护与日志输出。
|
||||
- 参考路径:[cleanup_task.rs](file://crates/rcoder/src/proxy_agent/cleanup_task.rs#L787-L836)
|
||||
|
||||
- 代理资源未释放
|
||||
- 现象:Agent 停止后仍占用资源。
|
||||
- 排查:确认 AgentLifecycleGuard 的 Drop 是否触发;检查 cancellation_token 是否正确 cancel。
|
||||
- 参考路径:[agent_model.rs](file://crates/shared_types/src/model/agent_model.rs#L340-L404)
|
||||
|
||||
- 会话连接无法断开
|
||||
- 现象:SSE 连接长时间不关闭。
|
||||
- 排查:确认 close_current_connection 是否被调用;检查 CancellationToken 与发送端的显式关闭。
|
||||
- 参考路径:[session_cache.rs](file://crates/agent_runner/src/service/session_cache.rs#L115-L140)
|
||||
|
||||
章节来源
|
||||
- [session_cache.rs](file://crates/agent_runner/src/service/session_cache.rs#L282-L355)
|
||||
- [cleanup_task.rs](file://crates/rcoder/src/proxy_agent/cleanup_task.rs#L787-L836)
|
||||
- [agent_model.rs](file://crates/shared_types/src/model/agent_model.rs#L340-L404)
|
||||
- [session_cache.rs](file://crates/agent_runner/src/service/session_cache.rs#L115-L140)
|
||||
|
||||
## 结论
|
||||
本项目通过 ProjectCoreState/ProjectExtendedState/ProjectState 的分层设计,结合 Arc 共享与写时复制,实现了高性能、低锁争用的状态管理;借助 DashMap 原子性操作与 CancellationToken,确保在高并发场景下的一致性与可靠性。agent_runner 的会话缓存与 rcoder 的清理任务共同构成了完整的生命周期管理闭环,覆盖从会话创建、消息推送、状态更新到资源清理的全链路。建议在新增状态字段时,遵循“核心小字段高频更新、扩展大字段低频更新”的设计原则,并优先使用写时复制与原子性操作,以获得最佳的性能与一致性表现。
|
||||
Reference in New Issue
Block a user