QCon San Francisco 2026 将邀请来自 Airbnb、OpenAI、Netflix、Honeycomb 等工程组织的实践者,讨论当 AI Agent 承担更多任务后,生产系统该如何构建、运行与持续演进。值得关注的并不只是模型能力,而是一个更现实的问题:当软件从“接收请求并返回结果”变成“理解目标、选择工具、执行动作并反复修正”时,原有的可靠性边界也随之改变。
来源摘要没有披露具体演讲内容或厂商方案,因此下面不预测各家公司会发布什么,而是围绕这一主题,整理一套可以直接用于工程评审的生产化框架。
从确定性调用,转向受约束的行动循环
传统服务通常有相对清晰的调用链:客户端发起请求,服务验证参数,执行业务逻辑,再返回响应。Agent 系统则可能包含多个动态步骤:
- 接收用户目标与上下文;
- 由模型生成计划;
- 选择并调用搜索、数据库、工单或支付工具;
- 根据工具结果修改计划;
- 达到目标、触发审批,或者因预算耗尽而停止。
这意味着生产系统不能只监控一次 HTTP 请求是否成功,还要回答更多问题:Agent 为什么选择了这个工具?读取了哪些数据?一次任务执行了多少步?是否重复触发了有副作用的操作?模型或提示词升级后,成功率和成本发生了什么变化?
一个实用的设计原则是:把模型当作不稳定的决策组件,而不是拥有完整权限的业务后端。 模型可以提出动作,但真正执行动作的代码仍应经过权限、参数、预算和业务策略检查。
生产架构通常需要明确分开以下几层:
- 规划层:模型把目标转化为下一步动作;
- 工具层:对数据库、内部 API 和第三方服务提供结构化接口;
- 策略层:判断动作是否允许,必要时要求人工确认;
- 执行层:处理超时、重试、幂等和补偿;
- 观测层:记录任务、模型调用、工具调用、成本与最终结果。
可观测性不能停留在日志和 Token 数量
Agent 任务可能返回了正确答案,却走了一条危险或昂贵的路径;也可能业务动作执行成功,但最终文本回复失败。因此,只统计状态码、延迟和 Token 消耗并不足够。
可以为每次任务建立一个 run_id,并把完整过程拆成多个 span:
agent.run
├── model.plan
├── policy.check
├── tool.get_order
├── model.replan
├── policy.check
└── tool.create_refund
每个 span 至少可以记录:
- 模型、提示词和工具定义的版本;
- 输入与输出的摘要或脱敏内容;
- 工具名称、参数、耗时和错误类型;
- 重试次数、Token 数量与估算成本;
- 策略判断结果和人工审批状态;
- 任务最终是成功、失败、中止还是部分完成。
敏感数据不能为了调试而无条件写入追踪系统。生产环境应对身份信息、支付数据和密钥进行脱敏,并配置保留周期与访问权限。对于高风险动作,审计记录还应与普通应用日志分开保存。
除了线上指标,还要建立固定评测集。每次修改模型、系统提示词、工具描述或检索逻辑时,重新运行同一批任务,比较任务完成率、错误工具调用率、平均步骤数、P95 延迟和单任务成本。这样才能把“模型感觉更聪明”转化为可回归的工程指标。
一个可运行的受限 Agent 工作流
下面是一个不依赖第三方库的最小示例。由于来源摘要没有提供具体 API,这段代码使用确定性的模拟规划器代替真实 LLM,重点展示工具白名单、步数限制、策略检查、幂等键、默认试运行和结构化审计。保存为 agent_demo.py 后即可运行。
import hashlib
import json
import sys
import time
import uuid
ORDERS = {
"ORD-100": {"status": "paid", "amount": 39.90}
}
ALLOWED_TOOLS = {"get_order", "create_refund"}
MAX_STEPS = 4
PROCESSED_KEYS = set()
SYSTEM_PROMPT = """
You are an order-support planner.
Return structured tool calls only.
Never invent an order ID or refund amount.
Refunds require a paid order and must not exceed 50 USD.
Stop when the objective is complete or when a tool returns an error.
""".strip()
def audit(run_id, event, **fields):
record = {
"timestamp": round(time.time(), 3),
"run_id": run_id,
"event": event,
**fields,
}
print(json.dumps(record, ensure_ascii=False))
def mock_plan(objective):
# 生产环境可在这里调用 LLM,并使用 JSON Schema 校验返回值。
# 本示例只支持一个固定订单,避免把模拟器误认为真实智能体。
if "ORD-100" not in objective:
return []
return [
{"tool": "get_order", "arguments": {"order_id": "ORD-100"}},
{
"tool": "create_refund",
"arguments": {"order_id": "ORD-100", "amount": 39.90},
},
]
def get_order(order_id):
order = ORDERS.get(order_id)
if not order:
raise ValueError("order not found")
return {"order_id": order_id, **order}
def create_refund(order_id, amount, idempotency_key, dry_run=True):
order = ORDERS.get(order_id)
if not order or order["status"] != "paid":
raise ValueError("only paid orders can be refunded")
if amount <= 0 or amount > order["amount"] or amount > 50:
raise ValueError("refund rejected by policy")
if idempotency_key in PROCESSED_KEYS:
return {"status": "duplicate_ignored", "order_id": order_id}
if dry_run:
return {"status": "would_refund", "order_id": order_id, "amount": amount}
PROCESSED_KEYS.add(idempotency_key)
return {"status": "refunded", "order_id": order_id, "amount": amount}
def run_agent(objective, dry_run=True):
run_id = str(uuid.uuid4())
audit(run_id, "run_started", objective=objective, dry_run=dry_run)
plan = mock_plan(objective)
if not plan:
audit(run_id, "run_stopped", reason="unsupported_objective")
return
for index, step in enumerate(plan, start=1):
if index > MAX_STEPS:
audit(run_id, "run_stopped", reason="step_budget_exceeded")
return
tool = step["tool"]
arguments = step["arguments"]
if tool not in ALLOWED_TOOLS:
audit(run_id, "tool_blocked", tool=tool)
return
key_source = json.dumps(
{"run_id": run_id, "tool": tool, "arguments": arguments},
sort_keys=True,
)
idempotency_key = hashlib.sha256(key_source.encode()).hexdigest()
audit(run_id, "tool_started", step=index, tool=tool, arguments=arguments)
try:
if tool == "get_order":
result = get_order(**arguments)
else:
result = create_refund(
**arguments,
idempotency_key=idempotency_key,
dry_run=dry_run,
)
audit(run_id, "tool_finished", step=index, tool=tool, result=result)
except Exception as exc:
audit(run_id, "tool_failed", step=index, tool=tool, error=str(exc))
return
audit(run_id, "run_finished", status="completed")
if __name__ == "__main__":
objective = " ".join(sys.argv[1:]) or "Check ORD-100 and refund it"
run_agent(objective, dry_run=True)
运行命令:
python agent_demo.py "Check ORD-100 and refund it"
默认的 dry_run=True 不会真正改变状态。接入真实系统时,应把 mock_plan() 替换为带结构化输出约束的模型调用,把订单和退款函数替换为内部 API,同时保留策略校验。还应将幂等键写入持久化存储,而不是进程内集合;否则服务重启或水平扩容后无法阻止重复操作。
上线前应重点审查的边界
Agent 获得的工具越多,潜在故障组合就越多。上线前可以逐项检查:
- 权限是否最小化:读取订单的工具不应自动获得退款权限;
- 高风险动作是否分级:付款、删除、发布和权限变更应要求人工确认;
- 是否限制循环:设置最大步骤数、总超时、Token 预算和工具调用预算;
- 是否默认幂等:所有写操作都携带稳定的幂等键;
- 是否防御提示注入:网页、邮件和文档中的文字只能作为数据,不能覆盖系统策略;
- 是否支持回放:保存版本号与结构化事件,使失败任务能够离线复现;
- 是否准备降级路径:模型不可用时转人工、返回只读结果,或使用确定性流程;
- 是否单独评估成本:除了平均值,还要关注长尾任务与失控循环。
采用策略:先让 Agent 建议,再让它执行
更稳妥的落地顺序不是一次性开放所有业务能力,而是逐步扩大自主范围。第一阶段让 Agent 只生成建议;第二阶段允许调用只读工具;第三阶段开放可撤销、低金额或低影响的写操作;只有在评测、审计和人工审批机制成熟后,才考虑更高风险的自动执行。
QCon San Francisco 2026 所聚焦的“构建、运行和演进”恰好揭示了 Agent 工程的核心:模型只是系统的一部分。真正决定它能否进入生产环境的,是权限边界、执行控制、可观测性、评测体系和故障恢复能力。把这些基础设施先搭起来,Agent 才能从演示中的聪明助手,变成可运营、可追责的生产组件。