L6 · 如何将 Agent 能力提供给用户和其他系统? - Application
所属知识库:Agent 全栈技术地图
所属领域:03 · Agent System
所属章节:02 · Agent System 是如何构建和运行的? - Technical Architecture
文档类型:应用架构、交互协议与工程实践研究
版本:v1.1
更新日期:2026 年 10 月 28 日
核心问题:Agent System 如何将 L1 - L5 的模型、执行、编排和治理能力封装为稳定、可理解、可操作的应用接口,使用户与外部系统能够安全地提交任务、查看进度、接收增量反馈、参与审批、控制执行、获取结果,并在异步运行、断线重连、重复请求、权限变化与故障条件下保持交互和交付的一致性?
专题导读
本篇属 Technical Architecture。Agent System 的技术能力并不会自动转化为可使用的产品。即使 L4 Agent Engine 能够驱动模型与工具、L5 Orchestration 能够协调复杂任务,用户仍需要一种稳定方式表达意图、了解执行过程、干预关键操作、确认最终成果;其他软件也需要可靠的 API、事件和数据契约。L6 Application(应用层)研究的就是系统能力如何对外呈现、如何被调用,以及用户与业务系统如何在任务的整个生命周期中持续参与。
传统同步 API 往往以一次请求和一次响应为中心;Agent 任务可能运行数分钟乃至更久,期间会调用工具、生成中间产物、请求审批、等待外部事件、失败重试或被用户取消。因此,L6 不能只设计一个“聊天输入框”,也不能把内部 Token 流直接当成产品协议。它需要同时解决命令提交、任务资源、状态查询、事件订阅、人工决策、权限验证、产物管理、失败解释和版本兼容等问题。
本篇承接 L1 Infrastructure、L2 Platform Services、L3 Model Services、L4 Agent Engine、L5 Orchestration & Collaboration 的研究成果,以“技术研究报告 Studio”为贯穿案例,建立应用层的边界、接口模型、用户交互状态、异步通信、审批与取消、产物交付、外部集成和可验证的工程设计。重点区分内部执行事件与对外应用事件、命令接受与任务完成、界面显示状态与服务端权威状态、用户身份与 Agent 执行权限。文中 API 和事件 Schema 属于中立参考设计,不是任何框架的标准接口;资料来源与实际验证范围在文末说明。
一、研究定位:L6 的职责、边界与交付对象
1.1 L6 在六层技术架构中的位置
用户 / 浏览器 / 移动 App / 企业系统 / 外部 API 客户端
│
L6 Application
┌────────────┼────────────┐
任务 API 实时事件接口 审批与产物接口
└────────────┼────────────┘
│ 受控命令与查询
L5 Orchestration & Collaboration
│ 子任务 / 协作 / 汇总
L4 Agent Engine
│ 决策循环 / 工具执行
L3 Model Services
│
L2 Platform Services / L1 Infrastructure这里的分层是职责划分,不是要求部署六个服务。小型 Agent 应用完全可以将 API、执行器与数据库放在一个进程中;大型系统则可以拆分 API Gateway、Application Backend、事件推送服务和异步 Worker。L6 的边界在于对外契约:它不应把模型供应商协议、内部状态机实现、消息队列拓扑直接暴露为长期稳定的客户端接口。
| 层次 | 核心责任 | 对 L6 的主要供给 |
|---|---|---|
| L1 基础设施 | 计算、网络、隔离 | 应用服务的运行条件 |
| L2 平台服务 | 数据、消息、身份、存储 | 任务索引、事件、鉴权、产物 |
| L3 模型服务 | 模型协议、路由、计量 | 模型能力与成本信息 |
| L4 Agent Engine | 单个 Run 的执行 | 运行状态、工具事件、终态 |
| L5 编排协作 | 跨任务协调 | 工作流状态、审批节点、成果 |
| L6 应用 | 外部访问与交互契约 | 用户可操作的产品能力 |
1.2 L6 应提供的六类对外能力
- 任务入口:接收目标、输入材料、配置选择、预算与执行约束;验证请求并返回可追踪标识。
- 任务控制:允许查看、取消、暂停、恢复或重试,但操作是否可用取决于系统状态与权限。
- 状态与反馈:提供快照、进度、结构化事件和必要的实时更新。
- 人工参与:将审批、补充信息、修改要求和最终确认建模为有审计记录的操作。
- 产物交付:管理报告、数据、文件、引用、版本及下载权限。
- 外部集成:提供稳定 API、Webhook 或事件订阅,并处理重试、签名、版本与限流。
这六类能力不要求每个最小 Agent System 都具备。例如本地 CLI 只需任务输入和结果输出;若产品承诺长任务、审批和恢复,就必须提供相应契约。应用层的完整程度应由用户任务和风险决定,不由界面复杂程度决定。
1.3 应用层不等于 Agent Platform
L6 负责某个 Agent System 的能力如何被消费;Agent Platform 则研究多个 Agent 或 Agent System 如何被统一创建、注册、配置、治理和运营。一个研究报告 Studio 的任务页、审批页和结果页属于 L6;跨团队的 Agent 注册中心、租户管理、构建器和平台运营控制台则更接近 Agent Platform。两者可能共享 UI 组件和 API,但研究对象不同。
二、从用户意图到任务资源:应用契约的基本模型
2.1 命令、查询、事件与产物必须区分
**命令(Command)**请求系统改变状态,例如提交、取消、批准;**查询(Query)**读取当前权威状态;**事件(Event)**描述已经发生的事实;**产物(Artifact)**是可以独立访问、版本化和验收的输出。它们不能互相替代。收到 run.accepted 不意味着执行成功;看到 progress=90% 不意味着报告可交付;客户端发送 cancel 不意味着所有外部操作立即停止。
建议的外部资源模型:
Workspace / Project
└── Task 用户目标与输入契约
├── Run 一次实际执行实例
│ ├── Events 对外可见的状态与进度事件
│ └── Approvals 待处理的人类决策
├── Artifacts 版本化输出
└── Feedback 用户评价与修订请求Task 与 Run 分离具有实际意义:用户可以对同一 Task 重新运行或比较不同配置,保留每次运行的结果与成本。若系统只支持单次运行,可以在实现中合并,但 API 最好不要让“任务定义”和“执行尝试”概念永久混淆。
2.2 创建任务的参考接口
POST /v1/tasks
Authorization: Bearer <access_token>
Idempotency-Key: client-generated-unique-key
Content-Type: application/json{
"workspace_id": "ws-17",
"task_type": "research_report",
"input": {
"question": "比较两种 Agent 工作流的恢复机制",
"source_refs": ["artifact://input-17"]
},
"constraints": {
"max_cost_usd": 5,
"deadline_seconds": 1800,
"require_publish_approval": true
},
"config_version": "research-studio@3"
}参考响应:
HTTP/1.1 202 Accepted
Location: /v1/tasks/task-203{
"task_id": "task-203",
"run_id": "run-001",
"status": "QUEUED",
"status_url": "/v1/runs/run-001",
"events_url": "/v1/runs/run-001/events"
}202 Accepted 表示服务器接受了异步处理请求,不承诺最终成功。对非法输入应返回明确的 4xx;对于已经存在的幂等键,服务器应根据其契约返回原请求结果或冲突,而不是默默创建第二个 Run。请求幂等键需要绑定调用身份、操作和请求摘要,设置保留期,并由可信存储原子保证去重。仅在内存里维护字典不具备跨实例可靠性。
2.3 API 资源与最小操作集合
| 资源 | 操作 | 目的 |
|---|---|---|
/tasks | POST | 创建任务 |
/tasks/{id} | GET | 查看任务定义 |
/runs/{id} | GET | 查看运行快照 |
/runs/{id}/cancel | POST | 请求取消 |
/runs/{id}/events | GET | 查询或订阅事件 |
/approvals/{id} | GET/POST | 查看并提交审批决定 |
/artifacts/{id} | GET | 查看产物元数据 |
/artifacts/{id}/download | GET | 获取授权下载入口 |
这是教学用资源划分,不是必须采用的 REST 路由。实际设计可以使用 RPC、GraphQL 或其他协议,但必须保留等价的身份、资源、状态与错误语义。对重试、恢复、审批和产物版本的约束比 URL 命名更重要。
三、应用层状态模型:用户看到什么、系统实际处于什么状态
3.1 不要将内部 Step 状态直接暴露为产品状态
L4 可能拥有 MODEL_REQUESTED、TOOL_RUNNING、WAITING_TOOL_RESULT 等细粒度状态;L5 可能管理多个节点的 PENDING、BLOCKED 和 READY。如果前端直接依赖所有内部枚举,内部执行器一旦升级就会破坏 UI。因此应设计稳定的对外状态投影(Public State Projection)。
| 对外状态 | 含义 | 用户可执行动作 |
|---|---|---|
QUEUED | 已接受,等待执行 | 查看、请求取消 |
RUNNING | 正在执行 | 查看、请求取消 |
WAITING_INPUT | 需要补充信息 | 提交信息、取消 |
WAITING_APPROVAL | 等待授权决定 | 审批、拒绝、取消 |
PAUSED | 已暂停,等待恢复 | 恢复或取消(按权限) |
SUCCEEDED | 达到约定成功条件 | 查看产物、反馈 |
FAILED | 无法按约定完成 | 查看原因、重试 |
CANCELLED | 取消已生效 | 查看历史 |
状态集由产品契约决定,不能机械套用;例如不支持暂停的系统不应暴露 PAUSED。取消请求应与取消完成分离:可以使用 CANCELLING 中间状态,或 cancel_requested=true 与当前运行状态组合表达。不能在用户点击取消的瞬间就声称外部副作用全部停止。
3.2 任务进度不一定可以量化为百分比
Agent 任务会动态发现新子任务,分母可能变化。随意把工具调用次数映射为“完成 73%”容易误导。更稳妥的进度表示包括:当前阶段、已完成/总计的已知工作单元、最近活动时间、待处理阻塞、预计等待范围及不确定性。只有当工作量基准稳定且计算口径明确时才展示百分比。
{
"run_id": "run-001",
"status": "WAITING_APPROVAL",
"phase": "evidence_review",
"completed_nodes": 3,
"known_nodes": 5,
"progress_is_estimate": true,
"pending_approval_ids": ["approval-4"],
"updated_at": "2026-10-28T14:00:00Z",
"version": 19
}3.3 版本与并发控制
应用快照应带 version 或 ETag。审批、编辑和恢复操作可以通过 If-Match 或请求中的 expected_version 做乐观并发检查:如果用户依据旧状态提交决定,服务器返回冲突并要求刷新,而不是覆盖后来发生的状态。客户端显示的状态是投影,服务端持久化状态才是授权与状态转换的依据。
四、实时反馈:轮询、SSE、WebSocket 与事件重放
4.1 三种通信方式的适用条件
| 方式 | 优点 | 局限与注意事项 |
|---|---|---|
| 轮询 | 简单,兼容性好 | 延迟与请求开销的权衡 |
| SSE | 单向事件流,浏览器友好 | 连接中断后需补齐事件 |
| WebSocket | 双向、低延迟交互 | 会话、鉴权、重连更复杂 |
对于研究报告生成、阶段进度、工具活动和审批提示,HTTP 命令 + GET 快照 + SSE 事件流通常是值得优先评估的组合。实时协同编辑、语音双向流或高频控制才更可能需要 WebSocket。SSE 并不保证业务事件恰好处理一次;WebSocket 连接成功也不意味着消息已经持久化。
4.2 外部事件必须是稳定的产品协议
内部追踪事件可能包含 Prompt、工具参数、凭据、原始检索内容和模型中间信息,不能直接广播。应先经过权限检查、脱敏、归一化和可见性过滤,生成Public Event:
{
"event_id": "evt-00042",
"run_id": "run-001",
"sequence": 42,
"type": "run.phase_changed",
"occurred_at": "2026-10-28T14:00:00Z",
"schema_version": 1,
"payload": {
"phase": "drafting",
"message": "已进入报告撰写阶段"
}
}对外事件应具备可排序的游标或序列号,但不应假设跨多个 Run 存在全局严格顺序。生产环境还要定义事件保留期、重复投递行为、缺失事件处理、快照同步和敏感字段过滤。
4.3 断线重连与快照校准
推荐流程:客户端先读取权威快照和当前游标;再订阅后续事件;若服务端支持从游标恢复,则重放遗漏事件;如游标过期或出现序列缺口,重新读取快照。要避免“先读快照、后建立订阅”之间丢失事件,可采用服务端提供的一致性游标,或在订阅后进行二次快照校准。
GET /runs/{id} ─────► status + cursor=41
GET /runs/{id}/events?after=41
├─ evt 42
├─ evt 43
网络中断 ─────────────┤
重新连接 after=43 ────► evt 44, 45...
若游标过期 ──────────► 410/专用错误 → 重新拉取快照SSE 的 Last-Event-ID 是传递恢复游标的一种机制;是否支持重放、重放多长时间由服务端应用实现决定。客户端需要以 event_id 去重,并且不能把消息到达顺序自动等同于任务因果顺序。
4.4 流式模型输出与最终交付
模型 Token 流可以改善交互感受,但流式文本是过程性内容,不一定是最终产物。在工具调用、证据审查或报告修订中,前面显示的草稿可能被推翻。应区分 draft.delta、draft.replaced、artifact.ready 和 run.succeeded;对于需要引用和审查的报告,正式下载入口只应指向经过相应验收的版本。
五、人类参与:审批、澄清、修改与发布
5.1 审批是持久化的业务对象
不能只在前端弹出一个“允许/拒绝”按钮。审批应拥有独立 ID、关联的 Run/Step、请求操作、风险摘要、有效期、允许决策人、版本、状态与审计记录。L4/L5 进入等待态;L6 展示审批对象;用户提交决定;可信服务层验证身份与当前状态;执行器再恢复。
{
"approval_id": "approval-4",
"run_id": "run-001",
"action": "publish_report",
"target": "workspace:ws-17",
"risk_summary": "将研究报告发布到团队共享空间",
"request_digest": "sha256:...",
"status": "PENDING",
"expires_at": "2026-10-28T15:00:00Z",
"version": 2
}审批提交示例:
POST /v1/approvals/approval-4/decisions
If-Match: "2"
Content-Type: application/json{
"decision": "APPROVE",
"comment": "仅允许发布已审核的 v3 报告",
"artifact_version": "v3"
}审批必须绑定具体操作与内容版本,否则“批准发布 v3”可能被错误地复用为“发布 v4”。高风险操作需要执行前再次验证审批、目标资源和权限。审批界面提供的是人的决策入口,真正的授权必须由服务端执行。
5.2 人类输入的不同语义
- 澄清(Clarification):补足任务必要信息,不应默认修改原始目标。
- 审批(Approval):对某项明确操作授权或拒绝,必须绑定范围。
- 修订(Revision):要求重新处理某个成果,通常创建新版本或新执行尝试。
- 取消(Cancellation):请求终止后续工作,不能自动回滚已经发生的外部操作。
- 最终确认(Acceptance):对交付物进行业务验收,不等同于执行器的技术成功状态。
在研究报告 Studio 中,“审核 Agent 通过”是自动质量门禁,“用户确认选题”是人类业务决策,“允许公开发布”是具有外部副作用的授权,三者不应合并成一个布尔字段。
5.3 审批失效与竞态
审批请求可能在用户打开页面后已被撤销、过期、替换或执行。服务器应对重复决定返回幂等结果或冲突,并记录操作者、时间、目标版本及授权依据。客户端可以禁用按钮改善体验,但不能用按钮禁用替代后端检查。对等待时间很长的任务,还应定义超时后的默认行为,通常不应把“未响应”解释为自动批准。
六、任务控制:取消、暂停、恢复与重试
6.1 取消是请求,不是瞬时事实
取消可能跨越 API、编排器、Worker、模型服务和外部工具。典型流程是:L6 记录取消意图;L5 停止分配新子任务并传播取消;L4 尝试中断当前操作;工具网关处理可中断操作;系统最终记录 CANCELLED、FAILED 或其他合法终态。外部已经提交的邮件、付款或发布行为不能因为用户点击取消就自动撤销。
应明确取消的传播范围:仅当前 Run、当前子任务、整个 Workflow,还是所有子孙任务。取消必须检查权限、记录审计事件,并防止旧 Worker 在取消后继续提交结果。
6.2 暂停与恢复的前提
暂停能力依赖 L4/L5 的可持久化状态与安全检查点;不是 UI 增加按钮就能获得。恢复时应重新检查任务配置、工具权限、审批有效性、输入资料可用性与执行版本。对模型调用中途的暂停,可能只能在下一个安全点生效,而不能从任意 Token 位置精确恢复。
6.3 重试与重新运行不是同一个操作
内部重试处理同一执行尝试中的暂时性故障,必须有预算和副作用控制;用户重新运行通常创建新的 Run,允许使用新配置或新输入,并保留历史对照。对 FAILED 的 Run 不应简单把状态改回 RUNNING,否则事件历史、费用和版本难以审计。需要区分“从检查点恢复”与“从头创建新 Run”。
七、产物交付:从临时输出到可验收的结果
7.1 Artifact 是独立资源,不是聊天文本的附件
研究报告、数据集、代码文件、图像、引用清单和测试记录,应拥有可独立访问的元数据:artifact_id、task_id、run_id、version、content_type、size、checksum、status、provenance、created_at、retention_policy。文件内容通常放在对象存储或文件系统,数据库保存索引和访问控制信息。
{
"artifact_id": "report-203",
"run_id": "run-001",
"version": 3,
"content_type": "text/markdown",
"status": "READY_FOR_REVIEW",
"checksum_sha256": "...",
"source_manifest_id": "sources-11",
"created_at": "2026-10-28T14:20:00Z"
}7.2 产物状态与运行状态分离
run.succeeded 表示执行契约完成,但产物可能处于 DRAFT、READY_FOR_REVIEW、APPROVED 或 PUBLISHED。例如研究助理完成报告草稿后,Run 可以成功结束,但发布仍需要用户审批。反过来,某个 Run 失败时也可能保留有价值的中间资料;应允许按权限访问部分成果,并明确其未验收状态。
7.3 下载、安全与生命周期
下载应由应用服务授权,可使用短期签名 URL 或代理流;签名 URL 是临时访问凭证,需要控制有效期、对象范围与泄露风险。不能因为客户端知道对象存储路径就允许任意下载。上传材料应进行大小、类型、内容与恶意文件风险检查;HTML、Markdown、脚本和富文本预览需要防止 XSS 与内容注入。数据删除、版本保留、法律保留与审计要求应与 H9 Data Governance 对齐。
7.4 来源可追溯性
研究类 Agent 的最终报告应将关键结论映射到来源记录。来源至少包含原始地址或文档标识、访问时间、版本/摘要、引用片段定位及使用许可信息。引用链接存在不等于证据支持主张;L6 可以提供证据面板和来源跳转,但证据正确性仍需由相应的评估与审查机制判断。
八、面向外部系统的 API 与 Webhook 集成
8.1 外部集成的典型模式
- 同步请求:适合短小、确定性、响应时间可控的操作;不应无限延长 HTTP 连接等待复杂任务。
- 异步任务 API:创建任务返回 ID,客户端轮询或订阅状态,适合长任务。
- Webhook:服务端主动通知外部系统任务状态变化;接收方需验证签名和处理重复事件。
- 事件总线集成:适合内部多服务协作,但不应把内部消息格式直接当成公共 API。
8.2 Webhook 的安全与可靠性
Webhook 应采用 HTTPS、端点验证、签名与时间戳、重放窗口、超时、重试上限、失败记录和必要的死信处理。至少一次通知是常见的工程选择,因此消费者必须按 event_id 幂等处理;发送端不能把 HTTP 200 自动解释为对方已经完成业务动作。签名验证需要使用原始请求体,不能在 JSON 重新序列化后直接比较摘要。
{
"event_id": "evt-00046",
"event_type": "artifact.approved",
"schema_version": 1,
"occurred_at": "2026-10-28T14:25:00Z",
"resource": {
"task_id": "task-203",
"artifact_id": "report-203",
"version": 3
}
}8.3 API 版本与兼容性
公开 API 应明确版本策略、字段可选性、错误码、废弃周期和兼容窗口。新增枚举值可能破坏采用穷举匹配的客户端;应为未知状态提供安全回退。内部工作流可以频繁演进,但对外事件 Schema 和资源标识不宜随内部实现同步频繁变动。重大破坏性修改应采用新版本并提供迁移说明。
九、身份、权限与信任边界
9.1 四种身份不可混同
- 终端用户身份:谁提交任务、查看成果或批准操作。
- 工作空间/租户身份:资源归属与数据隔离范围。
- 服务身份:哪个 API、Worker 或后台服务正在调用其他服务。
- Agent 执行身份:某个 Run 被授予哪些工具与资源权限。
用户登录成功不意味着 Agent 可以继承用户所有权限。尤其是浏览器侧的 Access Token 不应被原样注入模型上下文。服务端应将用户授权转换为最小权限、可撤销、可审计的执行能力,并在实际工具调用前重新检查。
9.2 资源级授权
访问 /runs/{id}、/artifacts/{id}、/approvals/{id} 时必须校验资源归属,而不是只验证 Token 是否有效。顺序 ID、可猜测 URL、跨租户任务引用都是典型风险。审批还需要额外校验角色、操作范围和目标版本。L6 的前端隐藏按钮不构成安全边界。
9.3 不可信内容进入应用层的风险
Agent 输出可能包含恶意 Markdown、HTML、外链或诱导操作文本;工具返回可能夹带提示注入。应用层应把模型生成内容视为数据而非可信 UI 指令,使用安全渲染、URL 协议白名单、内容安全策略和必要的人工确认。任何会触发发布、支付、删除等高风险动作的交互,都必须走可信 API 的授权与审批流程。
十、可靠性与用户体验:应用层的故障模型
10.1 区分四类失败
| 失败类别 | 例子 | 对外处理 |
|---|---|---|
| 请求失败 | 输入非法、未授权 | 明确 4xx 与修正建议 |
| 受理失败 | 服务暂不可用 | 有界重试与幂等 |
| 执行失败 | 工具超时、预算耗尽 | Run 终态、原因与可恢复性 |
| 展示失败 | 事件断线、UI 崩溃 | 重连、快照校准 |
前端断线不意味着 Agent 停止运行;API 返回 500 也不一定意味着任务没有创建。当创建请求的响应丢失时,客户端应使用同一个幂等键重试,而不是直接提交一个新任务。
10.2 对外错误结构
{
"error": {
"code": "APPROVAL_VERSION_CONFLICT",
"message": "审批对象已发生变化,请刷新后重试",
"retryable": false,
"request_id": "req-98",
"resource_id": "approval-4"
}
}错误码应稳定、可文档化,避免向用户泄露内部堆栈、供应商密钥或敏感工具参数。对外错误要区分可重试、需人工处理、权限拒绝、预算终止和证据不足等语义。FAILED 不应被笼统翻译成“模型出了问题”。
10.3 超时、限流与背压
应用层应有请求体大小限制、认证速率限制、并发任务配额、事件连接数限制、上传/下载带宽控制和排队反馈。队列拥堵时,明确返回排队状态、预计等待范围或 429/503 与 Retry-After(按具体语义),比静默接受无限任务更可靠。预算硬限制需要由服务端执行,不能只在前端显示预估费用。
10.4 可观测性与隐私
应用层应为每个请求分配 request_id,并关联 task_id、run_id、workflow_id 和必要的 trace_id。建议观察创建成功率、任务受理延迟、事件推送延迟、审批等待时间、用户取消率、产物下载成功率、前端重连率及授权拒绝事件。日志不应默认保存完整 Prompt、用户文件和审批敏感内容;保留与访问策略需与 H1/H9 对齐。
十一、贯穿案例:技术研究报告 Studio 的应用架构
11.1 用户旅程与后端契约
创建 Studio / 选择研究模板
│
填写研究问题、材料、预算、发布约束
│ POST /tasks + Idempotency-Key
▼
任务已接受(QUEUED)
│
选题 Agent → 审核 Agent
│ 事件:phase_changed / approval_requested
▼
用户确认选题
│ POST /approvals/{id}/decisions
▼
研究 → 分析 → 写作 → 审核
│
产物 v1 / v2 / v3 + 来源清单
│
用户验收与发布审批(可选)
▼
已批准产物 / 下载 / 分享用户在一个界面中可以看到:左侧阶段进度、中间 Agent 工作记录和审批、右侧产物版本、底部任务控制。但这些 UI 区域不应直接读写内部 Worker 数据库;它们消费的是 L6 提供的快照、事件、审批与产物 API。
11.2 关键时序:审批后恢复
浏览器 L6 API L5 Orchestrator L4 Engine / L2
│ │ │ │
│ GET run │ │ │
│◄─ WAITING_APPROVAL + approval_id ───│ │
│ POST decision │ │ │
│───────────────►│ 校验身份/版本/范围 │ │
│ │──持久化决定────────►│ │
│◄─ 202/200 ────│ │──恢复被阻塞节点─────►│
│◄─ event: RUNNING ──────────────────│ │
│◄─ artifact.ready ──────────────────│◄──执行结果─────────│应避免审批 API 直接同步执行耗时模型任务。更稳妥的方式是先原子提交审批决定,再通过可靠事件或任务队列恢复编排;浏览器随后观察状态变化。若 API 在决定提交后断线,重复请求应返回同一审批结果,而不是重复触发发布。
11.3 前后端职责划分
前端:表单校验、状态展示、可访问性、重连提示、草稿与正式产物区分、确认操作、错误提示。L6 后端:身份与资源授权、命令校验、幂等、状态投影、事件过滤、审批记录、下载签发。L5/L4:真正的任务编排与执行。L2:可靠存储、消息、身份与产物底座。
前端可用乐观 UI 表示“取消请求已发送”,但最终状态必须由服务端事件或快照确认。不要让客户端自行推导“审核通过即可发布”等跨权限规则。
11.4 最小可行版本与演进
阶段 A:个人原型。 单用户、单机执行、POST /tasks + GET /runs + 文件下载;简单轮询即可,重点先保证任务标识、终态和结果可追溯。
阶段 B:可交付 Studio。 增加持久化、审批对象、产物版本、SSE 事件、幂等创建、取消、权限校验和可诊断错误。
阶段 C:团队协作。 增加工作空间隔离、角色授权、共享审查、Webhook、审计、配额、任务历史和跨用户通知。
阶段 D:规模化运行。 在真实负载和风险要求下评估多实例 API、事件分发、租户配额、数据保留、灾难恢复与协议兼容。并非所有项目都需要走到 D。
十二、技术选型:协议、前端与后端如何组合
12.1 不要从框架品牌开始选型
应先回答:任务是否超过单次 HTTP 超时?是否需要双向实时通信?是否需要人工审批?用户是否会跨设备恢复?产物是否需要版本与审计?是否存在多租户?这些问题决定 API、存储、事件和 UI 的基本架构,然后再选择实现框架。
| 需求 | 优先考虑 | 额外成本 |
|---|---|---|
| 简单短任务 | 同步 HTTP | 超时与阻塞 |
| 长任务 | 异步 Task/Run API | 状态与持久化 |
| 阶段实时反馈 | SSE + 快照 | 游标与重连 |
| 双向实时交互 | WebSocket | 会话管理 |
| 企业集成 | Webhook / API | 签名、重试、版本 |
| 高风险操作 | 持久审批资源 | 权限与审计 |
12.2 代表性技术的定位
- FastAPI / Starlette:可用于 Python HTTP API、异步处理和流式响应;是否具备可靠长任务执行取决于外部任务系统与持久化设计,不能把 Web 框架的后台任务功能当成生产级工作流引擎。
- Next.js / React:可用于研究 Studio 的交互界面、表单、状态视图与产物展示;不能依赖浏览器作为权威任务状态存储。
- OpenAPI:适合描述 HTTP API 契约、Schema 和客户端生成;不自动定义业务幂等、审批语义和异步任务生命周期。
- CloudEvents:可作为事件封装的参考规范,但具体 Agent 事件类型、授权和交付保证仍需自行定义。
- OpenTelemetry:适合跨请求与执行链路的观测关联;Trace 不是可直接供用户重放的持久业务事件日志。
上述属于技术定位而非最新版本兼容性认证;真实实现需核对框架文档、版本和部署环境。
十三、工程实践:最小应用契约实验与验证计划
13.1 实验目标与范围
本篇提供一个纯 Python 标准库的可运行契约实验,用于说明任务创建幂等、状态转换、事件游标、审批版本冲突和产物就绪判定。它是内存中的确定性模型,不包含 HTTP 服务器、真实 Agent、数据库、身份服务或分布式 Worker。实验结果只能支持这些模拟不变量,不能证明生产安全性。
配套文件 L6-Agent-System-Application-v1.1-demo.py,Python 3 标准库(含 3.9)。运行:python3 L6-Agent-System-Application-v1.1-demo.py。
from __future__ import annotations
from dataclasses import dataclass, field
@dataclass
class Run:
run_id: str
status: str = "QUEUED"
version: int = 0
events: list = field(default_factory=list)
def change(self, new_status):
allowed = {
"QUEUED": {"RUNNING", "CANCELLED"},
"RUNNING": {"WAITING_APPROVAL", "FAILED", "SUCCEEDED", "CANCELLED"},
"WAITING_APPROVAL": {"RUNNING", "CANCELLED"},
"FAILED": set(), "SUCCEEDED": set(), "CANCELLED": set(),
}
if new_status not in allowed[self.status]:
raise ValueError("illegal transition")
self.status = new_status
self.version += 1
self.events.append((self.version, "run.status_changed", new_status))
def after(self, cursor):
return [event for event in self.events if event[0] > cursor]
class App:
def __init__(self):
self.requests = {}
self.runs = {}
def create(self, principal, key, digest):
identity = (principal, key)
if identity in self.requests:
old_digest, run_id = self.requests[identity]
if old_digest != digest:
raise ValueError("idempotency key reused with different request")
return self.runs[run_id]
run_id = f"run-{len(self.runs) + 1}"
run = Run(run_id)
self.runs[run_id] = run
self.requests[identity] = (digest, run_id)
return run
def decide_approval(run, expected_version, approve):
if run.version != expected_version:
raise ValueError("approval version conflict")
if run.status != "WAITING_APPROVAL":
raise ValueError("approval not pending")
run.change("RUNNING" if approve else "CANCELLED")
def test_contract():
app = App()
run = app.create("user-a", "key-1", "digest-1")
assert app.create("user-a", "key-1", "digest-1") is run
assert len(app.runs) == 1
try:
app.create("user-a", "key-1", "different")
assert False
except ValueError:
pass
run.change("RUNNING")
run.change("WAITING_APPROVAL")
assert len(run.after(1)) == 1
try:
decide_approval(run, expected_version=1, approve=True)
assert False
except ValueError:
pass
decide_approval(run, expected_version=2, approve=True)
run.change("SUCCEEDED")
assert run.status == "SUCCEEDED"
assert len(run.after(0)) == 4
print("PASS: idempotency, conflict, cursor, approval, terminal state")
if __name__ == "__main__":
test_contract()本地执行通过:输出 PASS: idempotency, conflict, cursor, approval, terminal state。
13.2 实验不覆盖的关键生产条件
内存字典无法在进程崩溃后保留幂等记录;没有并发锁就不能保证跨线程/实例原子性;Run.version 不是数据库事务;示例没有鉴权、审批对象签名、事件持久化、真实网络断线或外部副作用。因此不能直接将其用作生产 API。真实系统需要把幂等表、任务状态、审批决定和事件 Outbox 置于明确的事务与一致性策略之下。
13.3 建议的集成验收矩阵
| 场景 | 故障注入 | 必须验证的结果 |
|---|---|---|
| 创建请求重试 | 丢失响应 | 同一幂等键不重复创建 |
| 并发审批 | 两人同时决定 | 至多一个有效状态变更 |
| SSE 断线 | 断网后恢复 | 不丢关键状态、可校准 |
| 取消传播 | Worker 正在调用工具 | 终态与副作用如实记录 |
| 越权下载 | 跨租户对象 ID | 服务端拒绝 |
| Webhook 重试 | 接收方超时 | 重复通知可去重 |
| 产物覆盖 | 并发生成 v2/v3 | 版本与校验和不混乱 |
| 发布审批 | 审批后替换产物 | 旧批准不能授权新版本 |
13.4 实施步骤
首先明确 Task/Run/Artifact/Approval 的资源契约与状态机;其次定义身份和资源授权;再实现幂等创建、快照查询、事件游标与产物元数据;随后接入 L5/L4 的真实执行结果;最后加入审批、取消、Webhook、限流、观测和故障测试。建议从单体应用开始,只有在并发、组织边界或独立扩缩容需求明确时再拆分服务。
十四、常见设计误区与修正
| 误区 | 风险 | 修正 |
|---|---|---|
| 聊天流就是任务状态 | 断线后无法恢复 | 独立 Run 快照与事件 |
202 等于任务成功 | 过早交付 | 明确受理与终态 |
| 取消按钮可立即终止一切 | 外部副作用仍存在 | 取消请求与生效分离 |
| 模型输出可以直接驱动 UI 操作 | 注入与越权 | 可信命令 API |
| 前端角色判断就是授权 | 可被绕过 | 服务端资源级鉴权 |
| 审批一个布尔值就够 | 版本错配与重放 | 持久审批对象 |
| SSE 自动保证不丢事件 | 断线缺口 | 游标、重放与快照 |
| 产物就是最后一条消息 | 无版本与证据 | 独立 Artifact 资源 |
| Webhook 只会投递一次 | 重复业务动作 | 事件 ID 幂等 |
| Trace 可以直接展示给用户 | 泄露敏感数据 | 事件投影与脱敏 |
十五、研究结论与下一专题
L6 Application 的核心职责,是把 Agent System 内部复杂、异步且可能不确定的执行过程,转化为稳定、可信、可恢复、可理解的外部交互契约。它不只是用户界面,也包括 API、任务资源、事件协议、审批、控制操作、产物版本、身份权限和外部系统集成。
本篇形成五项关键工程判断。第一,任务接受、执行状态、审批状态与产物交付必须分别建模,不能由聊天消息推断;第二,长任务优先考虑异步资源模型,实时流是体验增强而非唯一事实来源;第三,取消、审批和重试都是需要持久化与权限校验的状态转换;第四,外部产物应版本化、可追溯、可独立授权;第五,应用层的稳定协议应隔离内部 Agent Engine、编排框架和模型供应商的变化。
至此,「02 · Agent System 是如何构建和运行的? - Technical Architecture」 的 L1 - L6 六层技术研究形成完整闭环:从基础设施、基础软件、模型服务、Agent 执行、任务编排到应用交付。下一章节应先研究 「03 · 如何让 Agent System 稳定、安全、可控地运行? - Engineering & Governance」 的章节概述与研究导读,再进入 H1 Observability 等专题,而不直接跳过章节总纲。
附录 A:参考文献与原始资料入口
以下为本篇涉及的官方规范和技术文档入口。它们用于说明协议语义和工程实践的来源;本篇未实时逐页核验各资料在 2026 年 10 月 28 日的最新版本,也未开展外部框架源码审计。实施时需确认所用规范版本、供应商部署环境和具体 API 行为。
- HTTP Semantics - RFC 9110:www.rfc-editor.org/rfc/rfc9110。HTTP 状态码、方法和条件请求语义。
- HTTP Conditional Requests - RFC 9110:同上,ETag 与
If-Match的条件请求机制。 - Server-Sent Events - WHATWG HTML Living Standard:html.spec.whatwg.org/multipage/server-sent-events.html。EventSource、事件 ID 和重连机制。
- WebSocket Protocol - RFC 6455:www.rfc-editor.org/rfc/rfc6455。双向连接与协议基础。
- OpenAPI Specification:spec.openapis.org/oas/latest.html。HTTP API 描述与契约。
- CloudEvents Specification:cloudevents.io。事件封装格式与上下文属性。
- OAuth 2.0 Authorization Framework - RFC 6749:www.rfc-editor.org/rfc/rfc6749。授权框架基础;实际部署还需核对后续安全最佳实践。
- OWASP API Security Top 10:owasp.org/API-Security。对象级授权、认证与 API 风险。
- OWASP Cross Site Scripting Prevention Cheat Sheet:cheatsheetseries.owasp.org/cheatshee...n_Cheat_Sheet.html。不可信内容安全渲染。
- OpenTelemetry Documentation:opentelemetry.io/docs。请求追踪、日志与指标关联。
- FastAPI Documentation:fastapi.tiangolo.com。Python Web API 与流式响应实现参考。
- Next.js Documentation:nextjs.org/docs。React 应用与服务端能力参考。
- PostgreSQL Documentation - Transactions:www.postgresql.org/docs/current/tutorial-transactions.html。状态与审批事务实现参考。
- Amazon S3 - Presigned URLs:docs.aws.amazon.com/AmazonS3/latest/...tPreSignedURL.html。临时授权对象访问的典型机制。
- LangGraph - Persistence:docs.langchain.com/oss/python/langgraph/persistence。Agent 执行状态与检查点的衔接。
- OpenAI Agents SDK - Running Agents:openai.github.io/openai-agents-python/running_agents。执行循环与运行控制参考。
附录 B:研究证据、实现与验证声明
研究定位。 本篇是 Agent System L6 应用层的技术架构研究。Task、Run、Approval、Artifact、Public Event 等数据结构、路由、状态枚举、Studio 时序和工程检查表属于中立参考设计,并非某个官方 Agent 协议或行业统一规范。具体产品可按任务范围调整,但应保持状态、权限、事件和产物语义清晰。
资料边界。 HTTP、SSE、WebSocket、OpenAPI、CloudEvents、OAuth、对象存储和 Agent 框架的技术定位参照公开规范与官方资料。文中关于“优先考虑 HTTP + 快照 + SSE”的表述是条件化的工程建议,不是对所有应用的性能基准结论。未实时核验最新文档版本或特定产品的兼容性。
实验边界。 第十三节的 Python 示例是内存中的确定性契约实验,不使用真实 Agent、数据库、HTTP 服务、SSE、Webhook 或权限系统。它只能检查有限的状态与幂等不变量。即使本地运行通过,也不证明生产级并发安全、跨进程恢复、网络重连、越权隔离或实际审批可靠性。
尚待验证。 多实例幂等创建、审批事务竞态、事件持久化与重放、SSE 断线恢复、Webhook 签名与重复投递、跨租户授权、对象存储下载权限、取消传播和发布副作用,需要在具体技术栈中进行集成测试、故障注入和安全审查。所有上线结论都必须附带环境、版本、任务分布、权限模型和验收证据。