文件上传与异步任务
文件上传把页面能力、用户隐私和异步状态绑在一起。Agent 不应读取本地文件系统,也不能凭空生成文件内容。安全做法是让真人选择并确认文件,页面把业务文件 id 暴露给动作,后台完成处理,再把可验证的进度和结果返回。
可运行页面
下面的页面执行一次真实文件上传,并显示服务端任务从排队、处理到完成的状态。文件名含 virus 时会进入失败路径,再用取消与重试验证异步边界。
可运行方案
方案06:上传与异步任务
真实文件字节创建服务端任务,包含进度、取消、失败与重试。模型看到任务元数据,而不是文件内容。
pnpm dev:examples源码 examples/demos/recipe-upload-async/后端/桥 examples/recipe-backends/access-service/页面 https://plingjs.dev/demos/recipe-upload-async/?lang=zh从仓库根目录运行:
pnpm dev:examples打开 http://localhost:5191/demos/recipe-upload-async/?lang=zh。页面源码在 examples/demos/recipe-upload-async/;上传与任务后端在 examples/recipe-backends/access-service/,路由、内存语义与生产替换要求见其 README.md。
责任边界
| 环节 | 负责方 |
|---|---|
| 选择本地文件 | 真人浏览器 |
| 病毒扫描、类型与大小限制 | 上传服务或后端 |
| 创建业务附件记录 | 应用后端 |
| 触发解析 / 转码 / 导入 | 后台任务 |
| 告知进度、错误与取消 | 页面与传输 |
| 判断业务成功 | 执行器与后端查询 |
Pling 不把文件字节放进模型上下文,也不让 Agent 指定本地路径。能力参数应是 attachmentId、fileId 或业务批次 id。若确实需要用户选择文件,应由页面提供人工步骤,Agent 看到的是 handoff 与状态,而不是文件系统接口。
推荐流程
用户点选文件 → 前端上传到受鉴权端点
→ 后端返回附件 id(不返回本地路径)
→ Agent 调用 import_file({ attachmentId })
→ 页面显示任务已创建
→ Agent 等待进度状态或 receive result
→ 成功判据验证业务对象,而不仅是“上传完成”toast“上传完成”不等于“业务导入成功”。成功判据应指向可读取的业务结果,例如导入行数、生成的文档 id 或可查询的批次状态。
验收标准
- Agent 输入中不能出现本地文件路径或原始文件内容。
- 只有已登录用户可以上传到自己的租户空间。
- 上传接口限制 MIME、扩展名、大小与数量,并验证真实内容。
- 附件 id 绑定用户与租户,不能跨账户引用。
invoke返回任务 id 或明确状态,不使用虚假等待。- 取消、超时、部分成功与重试都有结构化错误。
- 重试不会创建重复附件或重复导入。
- 审计记录附件 id 与结果,不记录文件名中的敏感信息或文件内容。
异步状态
页面应暴露一个只读状态或查询动作:
{ "jobId": "job_42", "state": "processing", "completed": 120, "total": 300 }Agent 可以每隔固定时间查询,受轮询和步骤限额约束。不要用无限循环等待;describe 与状态查询应可被取消。后台任务完成但页面尚未刷新时,应明确提示需要同步,不要假设数据已经出现在当前记录窗口。
常见失败
把 base64 放进工具参数。 会破坏上下文限额、日志和审计。文件传输走业务上传端点。
用文件名判断安全性。 文件名可伪造。检测内容类型与大小,并在后台扫描。
重试生成第二个导入。 使用幂等键、批次 id 或后端唯一约束。协议 request id 不等于业务幂等键。
看到“上传成功”就报告完成。 必须验证业务结果或明确的终态。
取消只停前端。 后端任务也要收到取消或在结果写入前检查取消标志。
框架入口
Vue 3 的异步声明见 复合动作、异步与失败续跑,React 见 异步工作与恢复。函数级工具适合把“开始导入”“查询批次”拆成两个稳定动作。测试应包含大文件拒绝、恶意 MIME、跨租户附件、任务超时与重复提交。
本地验证
先上传一个小文件并观察进度;再上传名称含 virus 的文件,任务应失败而不是显示成功记录。取消一个运行中的任务,再重试失败任务,确认前端状态与服务端终态一致。
后端只在内存中保存任务元数据,不持久化文件,也不做真实病毒扫描。它用于观察传输、进度和失败语义,不能作为生产上传服务。

