智能体(Agent)开发的最大误区是把重心放在提示词调优上。真实生产系统的失败原因几乎都集中在三处:工具调用参数不可靠(模型输出格式漂移)、规划循环无终止条件(无限反思、成本失控)、副作用不可回滚(重复下单、重复发信)。本文围绕这三点给出可落地的实现,而非框架使用教程。
让模型"输出 JSON"在演示里可行,在生产里必须用函数签名 + 参数校验 + 结构化输出三重约束。核心是:工具描述即契约,校验失败要能自愈重试。
import json
from dataclasses import dataclass
from typing import Callable, Any
from pydantic import BaseModel, ValidationError
class QueryOrder(BaseModel): # 参数契约
order_id: str
fields: list[str] = ["status", "amount"]
@dataclass
class Tool:
name: str
desc: str
schema: type[BaseModel]
fn: Callable[..., Any]
idempotent: bool = True # 是否可安全重试
REGISTRY: dict[str, Tool] = {}
def tool(schema: type[BaseModel], desc: str, idempotent=True):
def deco(fn):
REGISTRY[fn.__name__] = Tool(fn.__name__, desc, schema, fn, idempotent)
return fn
return deco
@tool(QueryOrder, "按订单号查询订单状态与金额")
def query_order(order_id: str, fields: list[str]) -> dict:
return {"order_id": order_id, **{f: "PAID" for f in fields}}
def dispatch(name: str, raw_args: str) -> tuple[bool, Any, str]:
"""返回 (成功, 结果, 错误信息)。错误信息回灌给模型用于自纠。"""
t = REGISTRY.get(name)
if not t:
return False, None, f"unknown tool {name}"
try:
args = t.schema.model_validate_json(raw_args) # 严格校验
except ValidationError as e:
# 关键:把校验错误原文返回,模型据此修正参数
return False, None, f"invalid args: {e.errors()[:2]}"
try:
return True, t.fn(**args.model_dump()), ""
except Exception as e:
return False, None, f"tool error: {type(e).__name__}"把校验错误结构化回灌给模型,是提升工具调用成功率最有效的手段,实测一次自愈可把格式错误率从 8% 降到 1% 以下。
ReAct 式循环最大的风险是发散。必须用步数预算 + 成本预算 + 收敛判定三重刹车,而不是靠模型自己说"完成":
MAX_STEPS, MAX_TOKENS = 8, 20000
def run_agent(llm, user_input: str, tools_spec: str) -> str:
history = [{"role": "user", "content": user_input}]
used_tokens = 0
for step in range(MAX_STEPS):
resp = llm.chat(history, tools=tools_spec)
used_tokens += resp.usage
if used_tokens > MAX_TOKENS: # 成本刹车
return "任务超预算,已中止,请缩小范围"
if resp.tool_call is None: # 无工具调用 = 收敛
return resp.content
ok, result, err = dispatch(resp.tool_call.name, resp.tool_call.args)
history.append({"role": "assistant", "tool_call": resp.tool_call})
history.append({"role": "tool",
"content": json.dumps(result if ok else {"error": err},
ensure_ascii=False)})
if not ok and step >= MAX_STEPS - 2: # 临近预算仍失败,降级
return "无法完成,请人工处理"
return "达到最大步数,未收敛"要点是:收敛判定基于"不再需要工具"这一客观信号,而不是解析模型的自我评价文本——后者不可靠且难以测试。
有副作用的工具(下单、支付、发信)必须区分 idempotent。非幂等工具的重试要么携带幂等键,要么直接禁止自动重试:
import uuid
def execute_safe(t: Tool, args: dict, attempt: int = 2):
for i in range(attempt if t.idempotent else 1):
try:
return t.fn(**args)
except TimeoutError:
if i == attempt - 1:
raise更强的做法是补偿事务:智能体每一步写"意图日志",失败时按逆序执行补偿动作(取消订单、回滚库存),保证多步操作的一致性。这与分布式事务的 Saga 模式同构,只是补偿决策由模型 + 规则共同完成。
没有评估的智能体无法迭代。最小可行的评估集应包含:单工具正确率、多步任务完成率、平均步数与 token 成本、越权与幻觉工具调用率。用回放式测试固定输入、断言工具调用序列,才能在改提示词或换模型时发现回归:
def test_refund_flow(agent, mock_llm):
mock_llm.stub(tool_seq=["query_order", "refund"], args_valid=True)
out = agent.run("帮我把 A1001 退款")
assert [c.name for c in mock_llm.calls] == ["query_order", "refund"]
assert "成功" in out智能体开发的专业性体现在把不确定性关进工程约束:工具层用 schema 与错误回灌保证参数正确,循环层用预算与客观收敛信号防止发散,副作用层用幂等键与补偿保证一致性,最终用回放测试锁定行为。框架可以换,但这四层约束缺一不可——它们决定了智能体是演示玩具还是可交付系统。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。