端到端 Agent 完整链路:从输入到证据化交付

前面的章节分别介绍了循环、工具和上下文,现在把它们放回一次完整任务里。从收到用户目标开始,一直跟到结果交付,看看各部分如何连接,也检查失败后由谁接手处理。

一个可用的 Agent 不是单次模型请求,也不是只有 while + tool call。完整系统需要把用户目标、上下文、计划、调度、模型决策、解析、执行、验证、恢复和交付连接成一条可观测链路。

1. 总体链路

flowchart TB I["1. Input / Identity"] --> C["2. Success Contract"] C --> S["3. Load Session / Checkpoint"] S --> X["4. Context Assembly"] X --> R["5. Route / Capability Selection"] R --> P["6. Plan / Task Graph"] P --> Q["7. Schedule Ready Tasks"] Q --> M["8. Model Decision"] M --> O["9. Output Parser"] O --> G{"10. Decision"} G -->|ToolCall| E["11. Policy / Executor"] E --> B["12. Observation / Evidence"] B --> U["13. Progress Update / Replan"] U --> Q G -->|Final candidate| F["14. Finalizer / Validation"] F -->|需修正且预算允许| U F -->|验收通过| A["15. Artifact / Trace / Memory Commit"] A --> Z["16. Stream / Return Result"]

这张图里有三种不同性质的组件:

  • 模型决策:理解目标、提出计划、选择下一动作、综合结果;
  • 确定性运行时:身份、schema、调度、权限、执行、预算、状态提交和验证;
  • 持久化边界:session、checkpoint、event、artifact、Memory 与最终交付。

把三者分开,才能判断错误来自模型、协议、工具、环境还是状态管理。

2. 1~4:建立可执行输入

2.1 Input / Identity

入口把 Web、CLI、API 或消息平台输入规范化为:

Python
from dataclasses import dataclass @dataclass(frozen=True) class RunInput: run_id: str user_id: str workspace_id: str locale: str request: tuple["MessageBlock", ...] attachments: tuple["ArtifactRef", ...] deadline: int budget: "Budget"
Rust
struct RunInput { run_id: String, user_id: String, workspace_id: String, locale: String, request: Vec<MessageBlock>, attachments: Vec<ArtifactRef>, deadline: u64, budget: Budget, }
JavaScript
/** * @typedef {{ * runId: string, * userId: string, * workspaceId: string, * locale: string, * request: MessageBlock[], * attachments: ArtifactRef[], * deadline: number, * budget: Budget * }} RunInput */
TypeScript
type RunInput = { runId: string userId: string workspaceId: string locale: string request: MessageBlock[] attachments: ArtifactRef[] deadline: number budget: Budget }

身份和 workspace 决定数据范围与工具权限。附件先成为受控 artifact,不直接把任意字节拼入 prompt。

2.2 Success Contract

把自然语言目标转成可检查契约:

yaml
goal: 修复创建文件夹失败并补齐 Agent 学习内容 deliverables: - code changes - markdown documents - cloud data sync acceptance: - folder create test passes - typecheck and unit tests pass - deployed page exposes new content evidence: - git diff - test reports - database counts and hashes - deployment status and browser check non_goals: - unrelated redesign

成功契约不一定全由模型生成。用户明确要求、仓库规则和 CI gate 具有更高确定性,应由运行时合并并保留来源。

2.3 Load Session / Checkpoint

新 run 建立初始 state;恢复 run 读取:

  • 最近 committed event;
  • 当前计划版本;
  • ready/running/waiting task;
  • pending tool call 和 side effect;
  • artifact 与 EvidenceItem;
  • 预算消耗;
  • compaction summary;
  • cancellation/approval 状态。

先 reconcile 未确认副作用,再继续调用模型,避免恢复后重复执行。

2.4 Context Assembly

Context Builder 从 policy、目标、计划、历史、工具、检索、Memory 和最新观察选择本轮最小充分集合,输出 provider request 和 ContextManifest。它不等于把数据库里的全部消息读出来。

3. 5~7:路线、计划与调度

3.1 Route / Capability Selection

Router 决定本轮使用:

  • 普通确定性 workflow;
  • 单 Agent loop;
  • 专用模型/多模态模型;
  • 某个 Skill 或 tool bundle;
  • Agent-as-tool / specialist;
  • 人工审批节点。

路由依据包括任务类型、模型 capability、上下文长度、工具需求、延迟和预算。Route decision 进入 trace 并通过固定任务集评测。

3.2 Plan / Task Graph

Planner 把目标变成可验收步骤,显式记录 dependency、input、output、write scope、budget 和 acceptance criteria。计划是可变假设,不是已经发生的事实。

3.3 Schedule Ready Tasks

Scheduler 使用确定性规则选择依赖已满足的任务:

Text
ready(task) = task.status == queued AND every dependency succeeded AND resource lock available AND concurrency/budget available AND task belongs to current plan version

Planner 回答“做什么”,Scheduler 回答“何时可以做、由谁做”。并发、背压、资源锁、lease 和失败传播不应只交给 prompt。

4. 8~10:模型请求与 Output Parser

4.1 Model Decision

Model Adapter 发送已经装配的请求,接收流式或非流式 provider events,并记录:

  • model/provider 与 capability;
  • request/response ID;
  • token/缓存/延迟;
  • stop reason;
  • tool call content blocks;
  • provider error 与 retry attempt。

4.2 Output Parser

Parser 依次执行:

Text
raw provider events -> assemble content/tool deltas -> protocol completeness -> normalized ModelResponse -> JSON/schema validation -> domain/state validation -> ToolDecision | FinalCandidate

它区分 native structured output、tool calling、JSON mode 和自由文本兼容路径。结构可解析只代表格式成立,不代表事实和业务成功。

4.3 Decision

规范化输出常见分支:

  • 调用一个或多个工具;
  • handoff / specialist;
  • 请求必要输入;
  • 更新计划;
  • 给出 final candidate;
  • provider 或 model behavior error。

每个分支都有显式 event 和预算变化。

5. 11~13:执行、观察与重规划

5.1 Policy / Executor

Tool Executor:

  1. 解析工具版本;
  2. normalize arguments;
  3. schema/domain/state guard;
  4. policy 与 approval;
  5. idempotency、reservation 与 lock;
  6. adapter 执行;
  7. timeout/cancellation;
  8. ToolResult 规范化;
  9. evidence 抽取和独立验证;
  10. state/trace commit。

文件、terminal、浏览器、数据库等 adapter 有各自语义;统一外壳不应抹掉退出码、HTTP 状态、事务或部分成功。

5.2 Observation / Evidence

Observation 是给 Agent 的有界事实;Evidence 是可追溯的原始或结构化证明:

Text
Observation: "typecheck failed: 2 diagnostics; first at app/a.ts:42" Evidence: test-report://run_123/typecheck file://workspace/app/a.ts#L42-L48 process://proc_88 { exit_code: 2, stdout_hash: ... }

观察可以压缩,证据引用必须稳定。

5.3 Progress Update / Replan

Reducer 根据 ToolResult 更新 task state。Planner 只在以下情况重规划:

  • 原假设被环境观察推翻;
  • 依赖或接口改变;
  • 验收失败且原步骤不再合适;
  • 预算/权限使原路径不可行;
  • 新任务必须加入图。

计划变更产生新版本,并使依赖旧输出的下游任务失效。不要在每一轮无条件重写整份计划。

6. 14~16:Finalizer、持久化与返回

6.1 Finalizer / Validation

Final candidate 进入四层验证:

  1. 协议:所有 tool call 有结果,输出类型完整;
  2. 结构:必填字段、artifact 和格式;
  3. 任务:成功契约逐项满足;
  4. 外部状态:文件、数据库、部署或消息的真实状态。

可修复失败且预算允许时,ValidationResult 回到 Agent 成为 observation;deadline、硬失败或不可消解的 unknown 状态则以明确 stop reason 结束。

6.2 Artifact / Trace / Memory Commit

结束前提交:

  • 最终回答和结构化结果;
  • 文件、报告、diff、截图等 artifacts;
  • EvidenceItem / ValidationResult;
  • 完整 trace 与成本;
  • plan/task 最终状态;
  • 适合长期保存的 Memory 候选;
  • 未完成、部分成功或 unknown side effect。

Memory 写入是经过策略筛选的派生动作,不是把整个 trace 永久保存。

6.3 Stream / Return Result

用户可在运行中接收进度事件,但最终响应只声明已验证状态。建议结构:

Python
from dataclasses import dataclass from typing import Literal @dataclass(frozen=True) class RunResult: outcome: Literal["completed", "partial", "failed", "cancelled"] final_output: tuple["MessageBlock", ...] deliverables: tuple["ArtifactRef", ...] validation: tuple["ValidationResult", ...] unresolved: tuple["UnresolvedItem", ...] usage: "UsageSummary" trace_ref: str
Rust
enum RunOutcome { Completed, Partial, Failed, Cancelled, } struct RunResult { outcome: RunOutcome, final_output: Vec<MessageBlock>, deliverables: Vec<ArtifactRef>, validation: Vec<ValidationResult>, unresolved: Vec<UnresolvedItem>, usage: UsageSummary, trace_ref: String, }
JavaScript
/** * @typedef {{ * outcome: 'completed'|'partial'|'failed'|'cancelled', * finalOutput: MessageBlock[], * deliverables: ArtifactRef[], * validation: ValidationResult[], * unresolved: UnresolvedItem[], * usage: UsageSummary, * traceRef: string * }} RunResult */
TypeScript
type RunResult = { outcome: 'completed' | 'partial' | 'failed' | 'cancelled' finalOutput: MessageBlock[] deliverables: ArtifactRef[] validation: ValidationResult[] unresolved: UnresolvedItem[] usage: UsageSummary traceRef: string }

7. 端到端示例:修复一个仓库 issue

sequenceDiagram participant U as User participant R as Runner participant M as Model participant E as Executor participant V as Validator U->>R: issue + repository R->>R: success contract + checkpoint R->>M: map + selected tools + task state M->>E: search_files / read_file E-->>M: code observations + evidence M->>E: run reproduction E-->>M: exit code + diagnostics M->>E: apply_patch(expected_hash) E-->>M: diff + new hash M->>E: target test + regression E-->>M: reports M->>R: final candidate R->>V: contract + artifacts + evidence V-->>R: accepted R-->>U: patch、测试与剩余事项

逐步解释:

  1. 先定位和复现,避免依据 issue 文本直接改代码;
  2. 文件读取带 hash;patch 在写者协调锁内核对并替换,单独的“比较 hash + rename”并非原子 compare-and-swap;
  3. Terminal 结果区分 stdout、stderr、退出码和 timeout;
  4. 目标测试验证修复,相关回归减少邻近破坏;
  5. Finalizer 还检查 diff 范围、产物和未提交文件;
  6. 最终“完成”来自 ValidationResult,不来自模型一句话。

8. 跨模块不变量

  1. 每个模型请求都有 ContextManifest;
  2. 每个 provider 响应保留 raw ref 和 normalized result;
  3. 每个 tool call 恰好对应一个 ToolResult;
  4. 每个副作用都有幂等身份和验证;
  5. Planner、Scheduler、Runner、Executor 分层;
  6. Observation 不伪装成 Evidence;
  7. 可修复验证失败回到 loop,而非立即丢弃;
  8. deadline、取消和预算由运行时强制;
  9. checkpoint 只在必要状态已持久化后前移;
  10. final output 的完成声明能映射到成功契约。

9. 每层最常见的失败

层 失败 诊断证据
Input 目标歧义、附件缺失 normalized input
Success Contract 验收过于主观 contract history
Context 约束丢失、噪声过多 ContextManifest
Route capability 不匹配 route decision
Plan 步骤不可验收、依赖缺失 plan versions
Scheduler 写冲突、饥饿、重复领取 queue/lease events
Model 选错工具、循环 response trace
Parser delta 不完整、schema mismatch raw response
Executor timeout、partial、unknown ToolResult
Observation 截断隐藏关键错误 artifact + truncation
Replan 旧结果未失效 task graph versions
Finalizer 把调用成功当任务完成 ValidationResult
Persistence checkpoint 与副作用错位 event log

10. 学习与实现顺序

  1. 先实现单 Agent model -> tool -> observation -> final;
  2. 加入结构化 ToolResult、终止和预算;
  3. 增加 ContextManifest 与 Output Parser;
  4. 用 Success Contract 和 Finalizer 验证;
  5. 加入 plan/task graph 与确定性 scheduler;
  6. 再做 checkpoint、worker、middleware 和多 Agent;
  7. 每增加一层,先加入 trace、故障注入和回归任务。

复杂框架替代不了清晰契约。最小可验证系统通常比一次加入所有组件更容易获得稳定成功率。

参考资料