Files
2026-06-01 13:54:52 +08:00

413 lines
18 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 附件模型
<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.rsrcoder](file://crates/rcoder/src/handler/chat_handler.rs)
- [chat_handler.rsagent_runner](file://crates/agent_runner/src/handler/chat_handler.rs)
- [lib.rsshared_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.rsrcoder](file://crates/rcoder/src/handler/chat_handler.rs#L17-L53)
- [chat_handler.rsagent_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.rsrcoder](file://crates/rcoder/src/handler/chat_handler.rs#L17-L53)
- [chat_handler.rsagent_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.rsrcoder](file://crates/rcoder/src/handler/chat_handler.rs#L17-L53)
- [chat_handler.rsagent_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.rsrcoder](file://crates/rcoder/src/handler/chat_handler.rs#L17-L53)
- [chat_handler.rsagent_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.rsrcoder](file://crates/rcoder/src/handler/chat_handler.rs#L17-L53)
- [chat_handler.rsagent_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二进制走 BlobResourceContentsURL 走 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.rsrcoder](file://crates/rcoder/src/handler/chat_handler.rs#L17-L53)
- [chat_handler.rsagent_runner](file://crates/agent_runner/src/handler/chat_handler.rs#L1-L275)
- [agent.proto](file://crates/shared_types/proto/agent.proto#L1-L43)
章节来源
- [lib.rsshared_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.rsrcoder](file://crates/rcoder/src/handler/chat_handler.rs#L17-L53)
- [chat_handler.rsagent_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 的上下文理解能力。建议在生产环境中合理设置大小阈值与扩展名白名单,并持续监控清理任务与日志,确保系统稳定高效运行。