首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >AI 智能体开发实战:把"会调用工具"升级为"可交付的受控系统"

AI 智能体开发实战:把"会调用工具"升级为"可交付的受控系统"

原创
作者头像
资源大佬 jzit-top
发布于 2026-10-24 14:49:57
发布于 2026-10-24 14:49:57
650
举报

智能体开发的常见误区是把"能跑通 demo"当成完成——接个 LLM、给几个工具、跑出一条链路,看起来就成。专业视角下,智能体是一个带状态、带权限、带失败语义、带可观测性的分布式系统,其难点全部在"出错时怎么办"。本文按四个工程层拆解,并给出可复用代码。

一、工具层:schema 即契约,权限在代码里强制

工具定义不是给模型看的说明文字,而是有类型、有副作用标记、有审批要求的契约。权限绝不能交给 prompt 约束。

代码语言:javascript
复制
from enum import Enum
from pydantic import BaseModel, Field

class Risk(str, Enum):
    READ = "read"; WRITE = "write"; IRREVERSIBLE = "irreversible"

class Tool(BaseModel):
    name: str
    args_schema: type[BaseModel]
    risk: Risk
    fn: callable

class RefundArgs(BaseModel):
    order_id: str
    amount: int = Field(gt=0, le=500_00)   # 单位:分,硬性上限

TOOLS = {
    "get_order": Tool(name="get_order", args_schema=OrderArgs, risk=Risk.READ, fn=query_order),
    "refund":    Tool(name="refund",    args_schema=RefundArgs, risk=Risk.IRREVERSIBLE, fn=do_refund),
}

def invoke(name: str, raw_args: dict, approved: set[str]) -> dict:
    tool = TOOLS[name]
    args = tool.args_schema(**raw_args)          # 类型与范围校验,失败即抛错
    if tool.risk is Risk.IRREVERSIBLE and name not in approved:
        raise PermissionError(f"{name} 需人工审批")
    return tool.fn(**args.model_dump())

要点:Field(gt=0, le=...) 把业务边界写进 schema,模型输出越界会在解析阶段被拒;approved 集合由审批系统注入,而非模型自报。这是智能体与"自动化脚本"的分界线。

二、状态机层:显式状态,而非靠对话历史兜底

多轮智能体最常见的 bug 是"状态藏在消息数组里"。专业做法是用显式状态机定义合法迁移,对话历史只作为上下文,不作为控制流。

代码语言:javascript
复制
from enum import Enum

class State(str, Enum):
    COLLECT = "collect"; CONFIRM = "confirm"; EXECUTE = "execute"; DONE = "done"; FAILED = "failed"

TRANSITIONS = {
    State.COLLECT: {State.CONFIRM, State.FAILED},
    State.CONFIRM: {State.EXECUTE, State.COLLECT, State.FAILED},  # 用户可改单
    State.EXECUTE: {State.DONE, State.FAILED},
}

class Agent:
    def __init__(self, llm): self.llm, self.state, self.slots = llm, State.COLLECT, {}

    def step(self, user_msg: str) -> str:
        nxt, reply = self._decide(user_msg)          # LLM 只产出"建议迁移 + 回复"
        if nxt not in TRANSITIONS[self.state]:
            raise RuntimeError(f"非法迁移 {self.state} -> {nxt}")
        self.state = nxt
        return reply

    def _decide(self, msg: str) -> tuple[State, str]:
        out = self.llm.json(
            f"当前状态:{self.state} 槽位:{self.slots} 用户:{msg}\n"
            f"输出 {{next_state, reply, slots_patch}},next_state 只能是 {list(State)}")
        self.slots.update(out.get("slots_patch", {}))
        return State(out["next_state"]), out["reply"]

要点:LLM 的职责被压缩为"填槽 + 建议迁移",是否合法由代码判定;slots 与 state 可序列化落库,服务重启后会话可恢复——这是智能体能否上生产的关键。

三、执行层:幂等、超时与补偿

智能体调用外部系统必然遇到超时与重复。没有幂等键的执行层,会在重试时重复退款、重复下单。

代码语言:javascript
复制
import hashlib, time

def execute_idempotent(tool_name: str, args: dict, store) -> dict:
    key = hashlib.sha256(f"{tool_name}:{sorted(args.items())}".encode()).hexdigest()
    if (cached := store.get(key)) is not None:
        return cached                              # 命中即返回,不重复执行
    store.set(key, {"status": "running"}, ttl=3600)  # 先占位,防并发
    try:
        res = invoke(tool_name, args, approved=store.approved)
        store.set(key, {"status": "ok", "res": res}, ttl=86400)
        return res
    except TimeoutError:
        store.set(key, {"status": "unknown"}, ttl=86400)
        raise RuntimeError("结果未知,需对账,不得盲目重试")  # 关键:区分未知与失败

要点:running 占位锁防并发双写;超时归类为"未知"而非"失败",因为外部系统可能已执行。未知状态必须走对账而非重试,否则就是重复扣款事故。

四、观测层:每一步都要能回放

线上 badcase 无法复现,等于无法修复。智能体必须记录 state + slots + prompt 版本 + 模型 + 工具调用与结果。

代码语言:javascript
复制
import json, time

def trace(step_no: int, state: str, payload: dict, log="agent.jsonl"):
    with open(log, "a") as f:
        f.write(json.dumps({"ts": time.time(), "step": step_no,
                            "state": state, **payload}, ensure_ascii=False) + "\n")

配合指标:单任务步数分布(突增说明模型陷入循环)、工具失败率、人工审批拦截率、未知状态对账队列长度。这四项分别对应"绕圈""外部依赖""权限设计""一致性问题",覆盖了智能体绝大多数生产故障。

五、评测与发布

没有评测集的智能体不能上线。最小可行方案是 100–300 条黄金轨迹(输入 + 期望终态 + 期望工具序列),发布前跑回归:终态正确率、工具调用精确率、平均步数。指标不达标即阻断发布,与普通服务遵循同一套门禁纪律。

结语

智能体开发的成熟度,可以用一句话检验:当模型调用了一个不可逆工具但结果未知时,你的系统能否说清"接下来该怎么办"。能,说明工具契约、状态机、幂等执行与观测四层都立住了;不能,那它只是一个更花哨的脚本。专业智能体工程的全部努力,都花在这句追问的答案上。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 一、工具层:schema 即契约,权限在代码里强制
  • 二、状态机层:显式状态,而非靠对话历史兜底
  • 三、执行层:幂等、超时与补偿
  • 四、观测层:每一步都要能回放
  • 五、评测与发布
  • 结语
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档