Agent 工程基础底座:从 Python 服务到可演进的 Runtime 骨架
本文是 精英 Agent 工程师学习路线:从范式理解到生产级落地 阶段 0 的配套学习笔记。 核心目标:先搭出一个不依赖特定模型与 Agent 框架、能够测试和替换组件的工程底座,再进入 Prompt、Harness、RAG 与多 Agent。本文不会把“装好一堆中间件”误写成“具备生产能力”。
0. 学完后要交付什么
阶段 0 不是 Python、Docker、Redis 的百科全书。它只要求把后续文章反复使用的工程边界一次建立正确。
完成后,你应该能交付一个最小但完整的 OrderFlow-Agent 骨架,并回答下面的问题:
- HTTP 请求、Agent Run、模型调用和工具调用分别有什么 ID?
- Pydantic Schema 在 API 边界、模型边界和工具边界各校验什么?
- 哪些状态写 PostgreSQL,哪些状态放 Redis,哪些内容进入向量库?
- 模型超时、限流、格式错误、工具失败时,系统如何重试、降级或转人工?
- 为什么“模型返回成功”不等于“退款已经成功”?
- 如何在不启动真实模型的情况下测试主要业务路径?
- 如何从一条失败请求追到 Prompt 版本、模型、工具参数、状态变更和最终响应?
- 如何替换模型、向量库或编排框架,而不重写业务核心?
最终交付物不是一个聊天 Demo,而是下面这组可验证资产:
agent-system/ app/ tests/ migrations/ docs/ docker-compose.yml pyproject.toml .env.example README.md验收命令至少包括:
pytestruff check .mypy appdocker compose configdocker compose up -dcurl http://localhost:8000/health/livecurl http://localhost:8000/health/ready1. 先建立正确心智模型:Agent 是有副作用的分布式系统
一次普通模型调用大致是:
input -> model -> output一个真实 Agent Run 更接近:
request -> authentication -> input normalization -> context assembly -> model/router -> tool selection -> remote service call -> state transition -> verification -> response -> trace/evaluation/audit它同时具有四类复杂性:
| 复杂性 | 典型问题 | 工程响应 |
|---|---|---|
| 概率性 | 相同输入可能产生不同计划 | Schema、评估集、版本冻结 |
| 分布式 | 模型、工具、数据库跨网络 | 超时、重试、熔断、追踪 |
| 有状态 | 多轮会话与长任务需要恢复 | Checkpoint、状态机、幂等 |
| 有副作用 | 退款、发信、改数据不可随意重放 | 授权、确认、事务、审计、验证 |
Anthropic 在 Building effective agents 中把可预定义路径的 workflow 与由模型动态决定过程的 agent 区分开;OpenAI 的 Agents SDK、Google ADK、Microsoft AutoGen/Agent Framework 与 AWS Bedrock Agents 虽然抽象不同,但都在解决“模型、工具、状态、交接和追踪如何被 Runtime 管理”的问题。[S1] [S2] [S3] [S4] [S5]
这给阶段 0 一个非常重要的结论:
先建设普通后端工程能力,再叠加 Agent 能力。模型不应该绕过身份、权限、事务、审计和业务不变量。
1.1 三个平面
建议从一开始把系统分成三个平面:
Control Plane 配置、版本、策略、权限、模型路由、发布
Execution Plane Run、节点、模型调用、工具执行、状态迁移
Evidence Plane Trace、Audit、Eval、Failure Sample、成本与延迟很多 Demo 只有 Execution Plane,所以“能跑”;生产系统还需要 Control Plane 决定“允许怎样跑”,Evidence Plane 证明“刚才究竟怎样跑”。
1.2 四种真相源
不要把所有状态都塞进一段对话历史。至少区分:
| 真相源 | 例子 | 权威性 |
|---|---|---|
| 业务数据库 | 订单状态、实付金额、退款流水 | 业务事实真相 |
| Agent State | 当前意图、已完成步骤、下一节点 | 本次 Run 的流程真相 |
| Trace | 模型、工具、耗时、错误 | 执行过程证据 |
| Memory / RAG | 用户偏好、历史案例、规则文档 | 可检索上下文,不自动等于事实 |
模型生成的文字不是第五种真相源。它只能提出结构化判断或动作建议。
2. 能力边界:学到“可组合”,不要学成技术清单
路线中列出 FastAPI、Pydantic、Redis、PostgreSQL、向量库和 Docker,不代表项目必须同时深度依赖全部组件。阶段 0 的达标尺度如下。
| 能力 | 必须掌握 | 暂时不必深挖 |
|---|---|---|
| Python | 类型、异步、异常、包结构、测试 | 元类与解释器内部 |
| FastAPI | 生命周期、依赖注入、流式响应、错误映射 | 自研 Web 框架 |
| Pydantic | 输入/输出 Schema、判别联合、严格校验 | 复杂代码生成 |
| PostgreSQL | 事务、约束、索引、迁移、JSONB 边界 | 提前分库分表 |
| Redis | TTL、幂等键、限流、短期状态 | 把 Redis 当永久真相源 |
| 向量检索 | chunk、metadata filter、召回与评估 | 一开始追求超大规模 |
| Docker Compose | 本地一致环境、健康检查、持久卷 | 把 Compose 当生产编排器 |
| LLM API | 结构化输出、工具调用、流式事件、错误分类 | 绑定某一家私有响应对象 |
| Observability | trace/span、结构化日志、关键指标 | 只做漂亮 Dashboard |
2.1 成熟度阶梯
L0 脚本:一次模型调用,结果打印到终端L1 服务:HTTP API + Schema + 错误处理L2 Runtime:状态、工具注册、超时、幂等、追踪L3 可恢复:Checkpoint、队列、重放、人工接管L4 可治理:版本、评估门禁、灰度、审计、成本预算阶段 0 的目标是稳定达到 L2,并为 L3/L4 留出接口。
3. 推荐工程目录:按责任边界,而不是按框架教程
agent-system/ app/ api/ routes/ dependencies.py errors.py agents/ state.py runtime.py workflow.py core/ config.py logging.py ids.py clock.py domain/ orders.py refunds.py policies.py llm/ protocol.py gateway.py models.py errors.py tools/ schemas.py registry.py executor.py order_tools.py refund_tools.py rag/ documents.py retriever.py citations.py memory/ repository.py policy.py persistence/ database.py models.py repositories.py observability/ tracing.py metrics.py audit.py security/ identity.py authorization.py secrets.py main.py tests/ unit/ contract/ integration/ scenario/ migrations/ docs/ architecture.md runbook.md docker-compose.yml pyproject.toml .env.example目录的核心规则是依赖方向:
API / Runtime / Adapter ↓Application Service ↓Domain Contract
Domain 不反向依赖 FastAPI、OpenAI SDK、Redis Client 或向量库 SDK。这样做不是为了追求形式上的“整洁架构”,而是为了获得三个直接收益:
- 单元测试可用 Fake Model、Fake Tool、Fake Repository;
- 模型供应商和框架可替换;
- 业务规则不被 Prompt 或 SDK 响应类型吞没。
4. 配置与依赖:可复现比“在我机器上能跑”更重要
4.1 pyproject.toml 的最小分组
[project]name = "orderflow-agent"version = "0.1.0"requires-python = ">=3.12"dependencies = [ "fastapi>=0.115,<1", "pydantic>=2.10,<3", "pydantic-settings>=2.7,<3", "uvicorn[standard]>=0.34,<1", "httpx>=0.28,<1", "sqlalchemy[asyncio]>=2.0,<3", "asyncpg>=0.30,<1", "redis>=5,<7", "opentelemetry-api>=1.30,<2",]
[dependency-groups]dev = [ "pytest>=8,<9", "pytest-asyncio>=0.25,<1", "mypy>=1.14,<2", "ruff>=0.9,<1",]示例版本范围表达的是策略,不是本文替你锁定的最新版本。真实项目必须提交 lockfile,并通过依赖更新 PR 验证回归集。
4.2 配置必须有来源与敏感级别
from pydantic import SecretStrfrom pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings): model_config = SettingsConfigDict( env_file=".env", env_nested_delimiter="__", extra="ignore", )
environment: str = "local" database_url: SecretStr redis_url: SecretStr model_provider: str = "openai" model_name: str model_api_key: SecretStr request_timeout_seconds: float = 30.0 max_agent_steps: int = 12 max_run_cost_usd: float = 0.25配置治理至少包含:
.env.example只放键名和非敏感示例;- 生产 Secret 进入云密钥服务,不进入镜像、日志或 Trace;
- 启动时检查必填项与组合约束,失败就拒绝 Ready;
- Prompt、模型、工具 Schema 和策略使用独立版本号;
- 配置变更能够关联部署版本和评估报告。
5. 用 Pydantic 建立三层契约
Pydantic 不只是把 JSON 转成 Python 对象。Agent 系统至少需要三类不同契约。
5.1 API 契约
from typing import Annotated, Literalfrom pydantic import BaseModel, Field, StringConstraints
OrderId = Annotated[ str, StringConstraints(pattern=r"^ORD-[A-Z0-9]{8}$"),]
class AgentRequest(BaseModel): request_id: str user_id: str message: Annotated[str, Field(min_length=1, max_length=8000)] order_id: OrderId | None = None response_mode: Literal["sync", "stream"] = "stream"API Schema 保护服务免受非法输入影响,但不能替代认证与资源归属检查。
5.2 模型输出契约
class RefundIntent(BaseModel): intent: Literal["refund_request"] order_id: OrderId | None reason: str | None confidence: Annotated[float, Field(ge=0, le=1)] needs_clarification: bool
class OtherIntent(BaseModel): intent: Literal["logistics_query", "complaint", "unknown"] confidence: Annotated[float, Field(ge=0, le=1)]
IntentResult = Annotated[ RefundIntent | OtherIntent, Field(discriminator="intent"),]OpenAI Structured Outputs、Google Gemini structured output、Anthropic tool use 等方案都在把自由文本转为可校验数据。[S6] [S7] [S8] 但 Schema 只能约束“形状”,不能证明字段事实正确:一个格式合法的订单号仍可能属于其他用户。
5.3 工具契约
class CreateRefundArgs(BaseModel): order_id: OrderId amount_cents: Annotated[int, Field(gt=0)] reason_code: Literal[ "merchant_not_shipped", "logistics_lost", "quality_issue", ] idempotency_key: str
class RefundCreated(BaseModel): status: Literal["created"] refund_id: str order_id: OrderId
class RefundRejected(BaseModel): status: Literal["rejected"] code: Literal[ "permission_denied", "state_conflict", "amount_exceeded", "duplicate_request", ] retryable: bool = False工具契约还必须在 Schema 之外声明:
| 元数据 | 示例 |
|---|---|
| 副作用 | write |
| 权限 | refund:create |
| 风险级别 | high |
| 幂等要求 | required |
| 确认策略 | 金额超过阈值需人工 |
| 超时 | 3 秒 |
| 可重试 | 仅连接失败且服务未受理 |
| 数据分类 | 包含订单与支付数据 |
6. 模型网关:把厂商 SDK 隔离在适配器中
模型提供商正在快速增加 Responses、tool use、context caching、reasoning、computer use 等能力。直接让业务代码遍布某个 SDK 类型,会让模型升级变成全项目迁移。
6.1 内部协议
from collections.abc import AsyncIteratorfrom dataclasses import dataclassfrom typing import Any, Protocol
@dataclass(frozen=True)class ModelRequest: run_id: str messages: list[dict[str, Any]] tools: list[dict[str, Any]] output_schema: dict[str, Any] | None timeout_seconds: float
@dataclass(frozen=True)class ModelEvent: kind: str payload: dict[str, Any]
class ModelGateway(Protocol): async def stream( self, request: ModelRequest, ) -> AsyncIterator[ModelEvent]: ...适配器负责把 OpenAI、Anthropic、Gemini、Azure 或 Bedrock 的事件归一化为内部事件:
response.startedtext.deltatool_call.startedtool_call.arguments.deltatool_call.completedusage.completedresponse.failed6.2 错误不能只剩一个 Exception
class ModelError(Exception): retryable: bool = False
class ModelRateLimited(ModelError): retryable = True
class ModelTimeout(ModelError): retryable = True
class ModelInvalidOutput(ModelError): retryable = False
class ModelSafetyBlocked(ModelError): retryable = False
class ModelContextExceeded(ModelError): retryable = False重试策略必须基于错误语义,而不是“失败就再请求一次”。无条件重试会放大限流、成本和重复副作用。
6.3 路由依据
模型路由可以参考各大云平台的 Model Gateway / AI Gateway 思路,但路由条件应该由业务 SLO 驱动,而不是模型排行榜驱动:[S9] [S10] [S11]
任务类型+ 数据敏感级别+ 结构化输出能力+ 工具调用能力+ 延迟预算+ 单 Run 成本预算+ 区域与合规要求+ 当前错误率/限流状态= provider + model + fallback chain一个明确的反模式是:强模型失败后自动换弱模型继续执行高风险写操作。降级必须同时降低权限,例如退化为只读查询或转人工。
7. HTTP 与流式事件:传输进度,不传输未经确认的事实
7.1 Run API
from fastapi import APIRouter, Depends, status
router = APIRouter(prefix="/v1/agent-runs")
@router.post("", status_code=status.HTTP_202_ACCEPTED)async def create_run( body: AgentRequest, service: "AgentRunService" = Depends(),) -> dict[str, str]: run = await service.create(body) return { "run_id": run.id, "status": run.status, "events_url": f"/v1/agent-runs/{run.id}/events", }对于可能超过普通 HTTP 超时的任务,推荐创建 Run 后通过 SSE/WebSocket/轮询读取事件,而不是让一个连接承担所有恢复语义。
7.2 事件信封
{ "event_id": "evt_01J...", "run_id": "run_01J...", "sequence": 17, "type": "tool.completed", "occurred_at": "2026-03-21T08:12:03.421Z", "data": { "tool_call_id": "tc_01J...", "tool_name": "query_order", "result_ref": "result://tc_01J..." }}关键约束:
sequence让客户端检测丢帧与重连;event_id支持去重;- 大型或敏感结果使用引用,不直接塞进事件;
- “正在检查退款资格”是进度,“退款已完成”必须等写工具与状态验证成功;
- 客户端断线不能取消服务端 Run,除非显式调用取消接口。
8. 工具执行器:模型提议,系统裁决,适配器执行
Meta 的 Toolformer、Gorilla、ToolLLM 等工作说明模型可以学习何时以及如何使用外部 API;ReAct 则把推理与行动后的观察组织成循环。[P1] [P2] [P3] [P4] 工程系统需要在这些思想上增加权限、事务和验证。
8.1 安全调用管线
Model Tool Proposal -> Parse -> Schema Validate -> Resolve Identity -> Authorize -> Policy Check -> Risk / Confirmation Check -> Idempotency Reservation -> Execute with Timeout -> Normalize Result -> Verify Business State -> Audit -> Return Observation8.2 注册信息
from dataclasses import dataclassfrom enum import StrEnumfrom typing import typefrom pydantic import BaseModel
class SideEffect(StrEnum): NONE = "none" READ = "read" WRITE = "write" EXTERNAL = "external"
@dataclass(frozen=True)class ToolSpec: name: str version: str input_model: type[BaseModel] output_model: type[BaseModel] side_effect: SideEffect permission: str timeout_seconds: float confirmation_required: bool不要把工具描述当权限系统。即使描述写着“仅管理员可用”,执行器仍必须根据已认证身份做授权。
8.3 幂等不是简单的缓存
写操作建议使用:
idempotency_key = hash( tenant_id, user_id, operation, business_resource_id, normalized_arguments, confirmation_version)服务端记录:
reserved -> executing -> succeeded | failed_unknown | rejectedfailed_unknown 不能盲目重试,因为远端可能已经成功但响应丢失。此时应先调用查询工具对账。
9. 数据层:按一致性与访问模式选存储
9.1 PostgreSQL:业务与审计真相
适合保存:
- Agent Run 元数据与状态迁移;
- 工具调用记录与幂等记录;
- 业务事务引用;
- Prompt/Tool/Policy 版本引用;
- Evaluation Case 与结果;
- 可长期保留的审计事件。
最小表关系:
agent_runs 1---n run_stepsagent_runs 1---n tool_callsagent_runs 1---n model_callsagent_runs 1---n state_transitionsagent_runs 1---n eval_resultstool_calls 1---0..1 idempotency_records状态迁移应使用乐观锁或条件更新:
UPDATE agent_runsSET status = :next_status, version = version + 1, updated_at = now()WHERE id = :run_id AND status = :expected_status AND version = :expected_version;受影响行数为 0,说明有并发更新或非法迁移,不能静默覆盖。
9.2 Redis:有 TTL 的协调数据
适合保存:
- 限流计数;
- 短生命周期缓存;
- 分布式锁或租约;
- SSE 最近事件窗口;
- 任务队列;
- 幂等预留的快速索引。
不适合把唯一一份退款状态或审计记录只放 Redis。缓存失效、淘汰与主从切换必须是设计前提。
9.3 向量库:候选证据索引
向量检索保存的是“可能相关的候选”,不是业务判断结果。最小 metadata 至少包含:
{ "document_id": "policy-refund-v7", "chunk_id": "R001-C03", "tenant_id": "tenant-a", "acl": ["support", "risk"], "effective_from": "2026-01-01", "effective_to": null, "source_uri": "policy://refund/v7#R001", "content_hash": "sha256:..."}检索必须先做租户和权限过滤,再做语义相关性排序。论文 Retrieval-Augmented Generation 奠定了“参数记忆 + 外部非参数记忆”的基本范式;后续工程实践进一步要求版本、ACL、引用和评估。[P5]
10. 可靠性:每一步都要有预算和终止条件
10.1 Run Budget
from pydantic import BaseModel, Field
class RunBudget(BaseModel): max_steps: int = Field(default=12, ge=1, le=50) max_model_calls: int = Field(default=8, ge=1) max_tool_calls: int = Field(default=12, ge=0) max_elapsed_seconds: float = Field(default=90, gt=0) max_cost_usd: float = Field(default=0.25, gt=0)每次循环前检查预算。预算耗尽的正常输出应该是结构化终止原因,而不是进程崩溃:
{ "status": "needs_human", "reason": "run_budget_exhausted", "completed_steps": ["intent", "order_lookup"], "pending_steps": ["policy_check", "refund_decision"]}10.2 超时分层
HTTP request timeout >= Agent Run sync budget >= node timeout >= model/tool attempt timeout不要让底层 SDK 的默认超时决定整个系统命运。
10.3 重试矩阵
| 失败 | 自动重试 | 条件 |
|---|---|---|
| 模型 429/暂时 5xx | 是 | 指数退避 + jitter + 总预算 |
| 模型输出 Schema 错误 | 有限 | 最多一次修复,记录原输出 |
| 只读工具网络失败 | 是 | 工具声明可重试 |
| 写工具连接中断 | 否 | 先查询远端最终状态 |
| 权限拒绝 | 否 | 不能通过重试绕过权限 |
| 业务状态冲突 | 否 | 刷新状态并重规划或人工 |
| 上下文超限 | 否 | 压缩/重建上下文,不原样重试 |
10.4 Backpressure
长 Run 应进入有界队列。队列满时返回 429/503 + Retry-After,而不是无限接收后让数据库、模型配额和工具服务一起雪崩。Little’s Law 提醒我们:在稳定系统中,并发量约等于吞吐乘以停留时间;Agent 延迟变长会直接放大在途任务数。
11. 可观测性:Trace 是 Agent 的可执行病历
OpenTelemetry 正在定义 GenAI semantic conventions,用统一属性描述模型请求、响应、token、工具与 Agent 操作。该规范已迁入独立仓库且仍处 Development,内部事件不能绑定未固定版本的实验属性。[S12] 阶段 0 不要求追齐所有字段,但必须先建立父子关系。
HTTP span└── agent.run ├── context.build ├── model.call ├── tool.query_order ├── rag.retrieve_policy ├── model.decide ├── tool.create_refund └── state.verify11.1 每个 Span 至少记录
trace_id / run_id / tenant_idoperation_name / node_name / attemptmodel_provider / model_name / model_config_versionprompt_version / tool_name / tool_versioninput_size / output_size / token_usagelatency / error_type / retryablestate_before_hash / state_after_hash11.2 三条红线
- 不默认记录完整 Prompt、用户隐私、API Key 与工具敏感返回;
- Trace 用于诊断,不替代不可篡改的 Audit Log;
- 指标聚合不能丢掉失败样本引用,否则只能看到错误率,不能复现错误。
11.3 最小指标集
agent_runs_total{status}agent_run_duration_secondsmodel_calls_total{provider,model,status}model_tokens_total{direction}tool_calls_total{tool,status}tool_call_duration_seconds{tool}agent_retries_total{reason}agent_budget_exhausted_total{budget_type}human_handoffs_total{reason}12. 安全基线:模型之外必须仍然安全
阶段 0 的安全目标可以用一句话表达:
假设模型会被误导、会输出错误参数、会重复调用,系统仍不应越权、泄露或造成不可恢复副作用。
12.1 身份传播
End User Identity -> API Authentication -> Agent Principal -> Delegated Tool Scope -> Resource-level AuthorizationAgent 使用服务账号并不意味着它可以代表任意用户访问所有订单。每次工具调用都应同时带主体、租户、授权范围和业务资源。
12.2 最小权限
query_order: order:read:selfsearch_policy: policy:read:publishedcreate_refund: refund:create:eligible_ordercreate_compensation: compensation:create:approved_limit只读工具与写工具使用不同凭据;高风险写工具可以部署在独立服务或网络边界中。
12.3 输入不是指令
用户、网页、邮件、RAG 文档和工具返回都视为不可信数据。OWASP LLM Top 10 与 NIST AI RMF 的共同启发是:威胁建模、权限控制、数据治理、人工监督和持续监测必须覆盖完整生命周期,而不是只靠 System Prompt。[S13] [S14]
13. Docker Compose:构造开发环境,不伪装生产平台
services: api: build: . command: uvicorn app.main:app --host 0.0.0.0 --port 8000 env_file: .env depends_on: postgres: condition: service_healthy redis: condition: service_healthy ports: - "8000:8000"
postgres: image: postgres:17 environment: POSTGRES_DB: orderflow POSTGRES_USER: orderflow POSTGRES_PASSWORD: local-only healthcheck: test: ["CMD-SHELL", "pg_isready -U orderflow -d orderflow"] interval: 5s timeout: 3s retries: 10 volumes: - pgdata:/var/lib/postgresql/data
redis: image: redis:7-alpine command: redis-server --appendonly yes healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 5s timeout: 3s retries: 10
volumes: pgdata:注意:
depends_on的健康条件只解决启动顺序的一部分,应用仍要处理运行期断连;- 数据库迁移使用独立 Job,不让每个 API 实例同时迁移;
- 镜像使用非 root 用户、多阶段构建和明确版本;
- Compose 中的明文密码只用于本地,不能复制到生产;
- Liveness 只判断进程是否活着,Readiness 才检查是否具备接收流量的条件。
Docker 官方文档强调 Compose 用声明式 YAML 管理多容器应用;Kubernetes 等生产编排平台还会补充滚动发布、调度、弹性、网络策略和 Secret 等能力。[S15]
14. 测试金字塔:先让模型退出测试,再测试模型
14.1 纯函数单元测试
优先覆盖:
- Schema 校验;
- 状态迁移;
- 权限与金额规则;
- 幂等键生成;
- 错误分类;
- Context 选择与脱敏;
- 路由和预算判断。
def test_refund_cannot_exceed_paid_amount() -> None: decision = decide_refund( paid_amount_cents=10_000, requested_amount_cents=12_000, policy_limit_cents=10_000, )
assert decision.allowed is False assert decision.reason == "amount_exceeded"14.2 契约测试
固定厂商响应 fixture,验证适配器归一化:
provider event -> internal ModelEvent -> tool arguments -> validated domain commandSDK 升级时,契约测试应优先暴露流式事件名、usage 字段或工具参数格式变化。
14.3 集成测试
用真实 PostgreSQL/Redis 容器测试:
- 事务回滚;
- 并发状态更新;
- TTL 与幂等;
- 断线重连;
- 迁移向前/向后兼容;
- Outbox 或事件发布。
14.4 Scenario Test
{ "case_id": "foundation-refund-001", "input": { "message": "订单三天没发货,我要退款", "order_id": "ORD-A1B2C3D4" }, "fixtures": { "order_status": "paid", "paid_amount_cents": 12900, "logistics_status": "not_shipped" }, "expected": { "tool_sequence": [ "query_order", "query_logistics", "search_policy" ], "forbidden_tools": ["create_compensation"], "terminal_status": "awaiting_confirmation" }}14.5 在线模型评估
最后才接真实模型,比较:
Schema ValidityTool Selection AccuracyArgument AccuracyTask SuccessUnsafe Action RateLatency p50/p95/p99Tokens / Cost per Successful RunAgentBench、τ-bench、SWE-bench 等基准的核心启发不是直接拿排行榜当业务结论,而是把 Agent 放进可交互环境,按任务完成、轨迹和状态变化评估。[P6] [P7] [P8]
15. OrderFlow-Agent 的最小闭环
15.1 主路径
POST /v1/agent-runs -> authenticate user -> create run -> classify intent -> query order -> verify ownership -> query logistics -> retrieve effective policy -> produce structured decision -> policy engine validates decision -> request confirmation when required -> execute refund with idempotency key -> query refund state -> persist evidence and audit -> emit final response15.2 状态对象
from typing import Literalfrom pydantic import BaseModel, Field
class AgentState(BaseModel): schema_version: Literal["1"] = "1" run_id: str user_id: str tenant_id: str status: Literal[ "created", "running", "awaiting_input", "awaiting_confirmation", "succeeded", "failed", "needs_human", ] current_node: str completed_nodes: list[str] = Field(default_factory=list) order_id: OrderId | None = None evidence_refs: list[str] = Field(default_factory=list) pending_action: dict | None = None version: int = 0状态只保存恢复流程所需的信息。大型工具结果、文档全文和隐私数据应存到有访问控制的对象或记录中,以引用连接。
15.3 终止状态
succeededfailed_retryablefailed_terminalawaiting_inputawaiting_confirmationneeds_humancancelledbudget_exhausted“模型没有继续调用工具”不是可靠终止条件。
16. 大厂方案怎么借鉴,而不是怎么照抄
| 方案 | 可借鉴思想 | 不应直接推导 |
|---|---|---|
| OpenAI Agents SDK / Responses API | Run、tool、handoff、guardrail、trace 的 Runtime 抽象 | 使用 SDK 就自动生产可用 |
| Anthropic Building Effective Agents | 从简单组合开始,workflow 与 agent 分治 | 所有复杂任务都需要自治 Agent |
| Google ADK / Vertex AI Agent Engine | Agent 开发包与托管 Runtime 分层,session/eval/deploy 配套 | 托管后不再需要业务级审计 |
| Microsoft AutoGen / Agent Framework | 消息驱动、多 Agent、工作流与状态管理 | 多 Agent 一定优于单 Agent |
| AWS Bedrock Agents | Action Group、Knowledge Base、Guardrail 与云服务集成 | 云 IAM 能替代业务资源授权 |
| LangGraph | 显式状态图、checkpoint、interrupt、durable execution | 图框架能修复错误业务建模 |
| OpenTelemetry GenAI | 跨组件 Trace 语义与供应商中立观测 | 采集越多原始 Prompt 越好 |
判断一个厂商方案是否适合项目,至少问:
它解决的是 SDK、Runtime、Control Plane 还是 Observability?状态和数据存在哪里,退出厂商平台能否迁移?权限在模型、工具、云 IAM、还是业务服务哪一层执行?能否固定 Prompt、模型、工具和策略版本复现一次 Run?能否导出 trace、usage、evaluation 与 audit evidence?失败时能否人工接管、恢复和回放?17. 论文思想如何进入工程,而不是停在名词
| 论文/基准 | 技术思想 | 阶段 0 的工程落点 |
|---|---|---|
| ReAct [P1] | 推理、行动、观察交替 | 显式 action/observation 事件和步数预算 |
| Toolformer [P2] | 模型学习何时调用 API | 工具候选与调用评估,不取消执行层校验 |
| Gorilla [P3] | 面向大量 API 的可靠调用 | 工具文档版本、检索与参数契约 |
| ToolLLM [P4] | 大规模真实 API 学习与规划 | 工具轨迹数据模型与分层评估 |
| RAG [P5] | 参数模型结合外部检索 | 独立检索接口、来源引用和版本化证据 |
| AgentBench [P6] | 多环境交互式 Agent 评测 | Scenario 环境、成功条件与过程指标 |
| τ-bench [P7] | 工具-用户交互与策略遵循 | 状态数据库、策略约束、工具轨迹评估 |
| SWE-bench [P8] | 在真实环境验证任务解决 | 最终环境状态比语言自评更可信 |
| Lost in the Middle [P9] | 长上下文中的位置信息损失 | 不把所有历史粗暴拼接,建设 Context Builder |
论文给的是问题定义、方法和特定实验条件下的结果。落地时必须重新测量自己的数据、模型、工具和失败成本。
18. 常见失败与诊断顺序
18.1 “本地能跑,容器起不来”
检查:
工作目录与模块路径依赖是否锁定环境变量是否完整容器内 DNS 是否使用 service name数据库迁移是否执行健康检查是否把启动慢误判为死亡18.2 “模型明明选对工具,业务仍失败”
检查:
参数是否通过业务校验用户是否拥有订单订单状态是否在调用前已变化幂等键是否冲突远端是否成功但响应丢失是否执行了 final-state verification18.3 “加 Redis 后反而出现幽灵状态”
检查:
Redis 是否被误当真相源TTL 是否短于 Run 生命周期缓存键是否缺 tenant/user/version写数据库与删缓存是否存在竞态消费是否具备幂等与重放能力18.4 “Trace 很全,但不能复现”
检查:
Prompt / model / tool / policy 版本是否记录随机性参数是否记录外部工具结果是否有不可变引用或 hash状态迁移前后是否可定位敏感原文被脱敏后是否保留受控证据引用18.5 “成本突然上升”
按顺序检查:
Run 数量每 Run 模型调用数每次输入 token重试率检索 chunk 数模型路由分布未终止循环缓存命中率成功 Run 的单位成本19. 分阶段实践任务
19.1 第一轮:纯内存、无真实模型
1. 建 API Schema2. 建 AgentState3. 用 FakeModel 返回固定结构4. 用 FakeTool 模拟订单与物流5. 完成状态迁移单元测试6. 输出结构化事件19.2 第二轮:接基础设施
1. PostgreSQL 持久化 Run 与 Tool Call2. Redis 做 TTL 缓存和限流3. Docker Compose 启动依赖4. 增加迁移、Readiness 和集成测试19.3 第三轮:接真实模型
1. 实现一个 Provider Adapter2. 结构化输出解析与错误分类3. 接入只读工具4. 记录 token、延迟和成本5. 跑固定 Scenario Dataset19.4 第四轮:开放写操作
1. 身份和资源授权2. Policy Check3. Human Confirmation4. Idempotency Record5. Final-state Verification6. Audit Log 与故障演练每轮都要能单独演示和回归。不要在基础状态机尚不可测试时同时引入 RAG、长期记忆、多 Agent 与微调。
20. 达标检查清单
工程结构
- 业务领域不直接依赖模型 SDK;
- 配置有类型、默认值、必填校验和 Secret 边界;
- 依赖有 lockfile,开发/测试/生产构建可复现;
- 数据库迁移可自动验证;
- Liveness 与 Readiness 分离。
模型与工具
- 模型输出经过 Schema 校验;
- Provider 错误被归一化并标记是否可重试;
- 工具注册包含版本、权限、副作用、超时和确认策略;
- 写工具有幂等机制;
- 写工具成功后查询业务最终状态。
状态与可靠性
- Run 有显式状态机和非法迁移保护;
- 每个 Run 有步数、时间、模型调用和成本预算;
- 只对明确可重试操作重试;
- 进程重启后可读取未完成 Run;
- 队列、缓存与数据库的真相边界清楚。
安全与观测
- 用户身份和租户信息传播到每次工具授权;
- Prompt、日志和 Trace 默认不记录 Secret/PII;
- Trace 能关联 Prompt、模型、工具和策略版本;
- Audit Log 能说明谁在何时批准和执行了什么;
- 失败样本能进入回归集。
测试
- 无真实模型也能跑通核心 Scenario;
- 有 Provider Adapter 契约测试;
- 有 PostgreSQL/Redis 集成测试;
- 有正常、边界、并发、超时和权限失败样例;
- 能输出任务成功率、工具准确率、p95 延迟和单成功 Run 成本。
达到这些条件,阶段 1 的 Prompt、阶段 3 的 Harness 和后续 RAG/Memory 才有可靠承载面。
21. 面试与复盘问题
- 为什么结构化输出不能替代业务校验?
- Agent State、Conversation History、Trace 和 Audit Log 有什么区别?
- 为什么写工具网络超时后不能直接重试?
- 如何设计跨模型供应商的事件协议?
- Redis 适合保存哪些 Agent 数据,不适合保存哪些?
- 如何保证两个 Worker 不会重复执行同一笔退款?
- 为什么模型降级时通常也应该降低动作权限?
- 如何在不记录敏感 Prompt 原文的情况下支持问题复现?
- Agent 的 Liveness、Readiness 和业务可用性分别是什么?
- 一个 Benchmark 分数为什么不能直接证明业务系统可上线?
22. 参考资料与延伸阅读
资料按“厂商官方方案”“工程标准”“论文与基准”分组。链接用于核对公开行为与原始论述;本文中的架构组合、风险判断和 OrderFlow-Agent 设计属于工程推导,不代表对应厂商的唯一推荐架构。
厂商官方方案
[S1] Anthropic
- Building effective agents:workflow 与 agent 的边界、组合模式、工具设计原则。
- Tool use with Claude:Tool Schema、工具调用与工具结果交互。
[S2] OpenAI
- Agents SDK:Agent、handoff、guardrail、session 与 tracing 的 SDK 抽象。
- A practical guide to building agents:模型、工具、指令与编排的工程划分。
[S3] Google
- Agent Development Kit:模型无关的 Agent 开发、工具、session、workflow 与评估。
- Vertex AI Agent Engine overview:托管 Agent Runtime 的部署与运维边界。
[S4] Microsoft
- AutoGen documentation:Core、AgentChat 与扩展层的消息驱动 Agent 抽象。
- Azure AI Foundry Agent Service:托管 Agent、工具、身份与企业集成。
[S5] AWS
- Agents for Amazon Bedrock:Action Group、Knowledge Base、编排与 Guardrail 集成。
- Amazon Bedrock Guardrails:输入输出策略控制与安全配置。
[S6] OpenAI Structured Outputs
- Structured Outputs guide:基于 JSON Schema 约束模型输出。
- Function Calling guide:工具定义、调用与结果回传。
[S7] Google Gemini
- Structured output:Gemini 的 JSON Schema 输出能力。
- Function calling:函数声明与组合调用。
[S8] Anthropic Structured Tool Use
- Tool use implementation:客户端工具执行循环与结果返回。
[S9] Cloudflare AI Gateway
- AI Gateway:模型代理、分析、缓存、限流与可观测性。
[S10] Microsoft AI Gateway
- AI gateway in Azure API Management:多后端、token 限流、语义缓存与治理能力。
[S11] Google Cloud Model Armor
- Model Armor:模型输入输出安全检查与云端集成边界。
工程标准与基础设施
[S12] OpenTelemetry
- Semantic Conventions for Generative AI Systems:GenAI、Agent、工具与 metrics 的独立规范仓库,当前仍处 Development。
[S13] OWASP
- OWASP Top 10 for LLM Applications:Prompt Injection、敏感信息泄露、过度代理等风险分类。
- AI Agent Security Cheat Sheet:身份、工具、记忆、权限和审计的 Agent 安全建议。
[S14] NIST
- Artificial Intelligence Risk Management Framework: Generative Artificial Intelligence Profile:NIST AI 600-1 的治理、测量与风险管理框架。
[S15] 基础组件
论文与基准
[P1] ReAct
- Yao et al., ReAct: Synergizing Reasoning and Acting in Language Models, ICLR 2023。
[P2] Toolformer
- Schick et al., Toolformer: Language Models Can Teach Themselves to Use Tools, NeurIPS 2023。
[P3] Gorilla
- Patil et al., Gorilla: Large Language Model Connected with Massive APIs, 2023。
[P4] ToolLLM
- Qin et al., ToolLLM: Facilitating Large Language Models to Master 16000+ Real-world APIs, ICLR 2024。
[P5] RAG
- Lewis et al., Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks, NeurIPS 2020。
[P6] AgentBench
- Liu et al., AgentBench: Evaluating LLMs as Agents, ICLR 2024。
[P7] τ-bench
- Yao et al., τ-bench: A Benchmark for Tool-Agent-User Interaction in Real-World Domains, 2024。
[P8] SWE-bench
- Jimenez et al., SWE-bench: Can Language Models Resolve Real-World GitHub Issues?, ICLR 2024。
[P9] Long-context position effects
- Liu et al., Lost in the Middle: How Language Models Use Long Contexts, TACL 2024。
23. 阶段总结
阶段 0 真正要建立的不是“会用 FastAPI + Redis + Docker”的简历关键词,而是一套稳定的工程判断:
模型输出是提议,不是事实;工具调用是受控命令,不是字符串;状态变化要持久化、校验和审计;网络失败必须按副作用语义处理;上下文、业务数据、Trace 和 Memory 各有边界;没有测试、预算、终止条件和版本信息的 Agent 不可维护。有了这套底座,后续 Prompt Engineering 才能成为可测试的模型接口,Agent Harness 才能成为可恢复的 Runtime,RAG、Memory 与 Multi-Agent 也才不会变成堆叠复杂度。