一个 Agent 能写出漂亮的工具调用序列,和它能被放心放进生产环境,中间隔着整层工程。可靠的 Agent Harness 需要同时覆盖状态管理、运行时、控制面、推理、工具、接口与语言选择七个方面,而 4sapi(https://4sapi.com)负责其中模型接入与计费这一段。

一、开篇痛点:Agent 项目为什么总是"跑着跑着就坏了"

Demo 阶段的 Agent 风光无限:一个 prompt 下去,模型自己规划、自己调工具、自己把结果拼成答案。一旦进入生产,问题接踵而至——任务跑到一半进程崩溃,重跑一遍什么状态都没有;工具调用了两次,数据库里写进两条重复记录;模型突然返回非法格式,解析直接抛异常;一次误操作删了不该删的数据,事后连是谁、什么时候、为什么都查不到。

这些事故的根源不是模型不够聪明,而是承载 Agent 的外壳太薄。外壳只负责"把 prompt 发给模型、把工具结果拼回去",状态存在内存里、权限靠自觉、错误靠重试、动作不留痕。可靠 Agent Harness 要解决的,正是这一整层工程问题。

二、原理速览:Agent Harness 的七层骨架

业界公认的可靠 Agent Harness 至少覆盖七个能力域。缺了任何一块,Agent 都只能在"能跑"和"能可靠地跑"之间隔着一道坎:

能力域 回答的问题 典型实现
状态管理 Agent 现在处于哪个阶段、做过什么 显式状态机 + 持久化检查点
运行时 Agent 的代码在哪里执行、怎么隔离 沙箱、容器、动态调度机器池
控制面 谁有权让 Agent 做什么、怎么审批 权限模型、审批流、策略引擎
推理 模型怎么调用、怎么重试、怎么计费 统一 API 接入、重试与预算控制
工具 工具怎么声明、怎么校验、怎么执行 结构化工具协议、白名单
接口 外部系统怎么和 Agent 对话 HTTP/SSE/webhook、会话恢复
语言选择 用哪种语言承载 Agent 逻辑 生态、类型系统与团队能力

三、核心观点:不可避免的复杂度应由核心抽象吸收

设计 Agent Harness 时,一个反复出现的错误是把复杂度推给扩展和用户:状态持久化让每个 Agent 自己写、错误处理让每个工具自己实现、权限检查让每个调用者自己操心。结果就是 10 个 Agent 有 10 套不兼容的约定,每加一个 Agent 都要重新踩一遍坑。

正确做法正相反:状态管理、重试、审计、预算这类所有 Agent 都逃不掉的复杂度,应该被核心抽象吸收,做成 Harness 的默认行为。工具作者只声明"这个工具做什么、参数是什么",模型调用者只负责"给输入拿输出",治理规则由控制面统一注入。复杂度的位置越靠近核心,整个系统就越容易扩展。

四、状态层:显式状态机

Agent 的执行过程必须落成显式状态机,而不是一堆散落在对话历史里的文字。每个状态表示一个确定语义的阶段,状态迁移由 Harness 控制,而不是由模型自由发挥:

+------------------+       +------------------+
|  IDLE / PENDING  |------>|    PLANNING      |
+------------------+       +------------------+
                                 |    |
                      (需要工具) |    | (直接作答)
                                 v    v
              +------------------+    +------------------+
              |   TOOL_CALL      |    |  FINISH / ANSWER  |
              +------------------+    +------------------+
                     |   ^                  |
              (等待审批)|   |(通过/重试)      |
                     v   |                  v
              +------------------+    +------------------+
              | AWAIT_APPROVAL   |    |   DONE / FAILED  |
              +------------------+    +------------------+

状态机的好处是每个状态都有明确的持久化策略:进入 TOOL_CALL 之前先写检查点,进程崩溃后从最近的检查点恢复,而不是让用户从头再来。恢复时要记录已完成的工具结果,避免同一动作执行两次。

五、运行时层:动态调度机器池

Agent 的代码在哪里执行,决定了它能碰什么、不能碰什么。把 Agent 直接跑在开发机上,等于把整个开发环境的权限交给了模型;把 Agent 关进死板的静态沙箱,又常常装不下真实的构建管线。

现在更主流的做法是让云端 Agent 运行在团队自己管理的动态调度机器池上。机器池靠近内部服务和源码,Agent 访问内网服务时延迟低、凭据分发可控;遇到自定义硬件(GPU、特殊加速卡)或难以打包的构建管线(大型编译任务、私有依赖),可以直接调度到对应机器上执行。机器按任务动态申请、用后回收,Agent 和内部资源的边界由调度器统一管理,而不是散落在每个人的笔记本里。

六、控制面层:治理链

控制面是可靠 Harness 和"能跑的 Demo"之间最本质的区别。一次 Agent 请求从进入到落地的完整治理链如下:

请求进入
   |
   v
① 身份与权限校验(谁在调用、能调什么模型和工具)
   |
   v
② 策略判断(任务类型、模型路由、成本预算、合规标签)
   |
   v
③ 推理层(模型 API 调用,经 4sapi 统一接入与计费)
   |
   v
④ 工具调用(白名单校验、参数校验、沙箱执行)
   |
   v
⑤ 结果校验与状态提交(幂等键、结果格式检查)
   |
   v
⑥ 审计日志(请求、决策、动作、成本、结果全量留痕)

关键设计:模型只负责"提议",决策权在控制面。模型说"我要删除数据库",Harness 检查权限、询问审批、记录日志,批准了才执行。这样即使模型被 prompt injection 诱导,越权动作也会在治理链上被拦下。

七、推理层:模型接入与重试

推理层是把 Agent 逻辑接到大模型 API 的胶水层,也是 4sapi(https://4sapi.com)的用武之地:统一 OpenAI 兼容接入、多模型路由、用量统计与计费对账,都不需要每个 Agent 各自实现一套。

一个可靠的推理层至少要处理三件事:超时、限流、非法返回。Python 接入示例:

import os
import time
import json
from openai import OpenAI

client = OpenAI(
    api_key=os.getenv("4SAPI_KEY"),
    base_url="https://4sapi.com/v1",   # 4sapi 统一接入地址
)

def llm_call(messages, model="gpt-4o-mini", max_tokens=1024, timeout=30):
    """带超时与退避重试的模型调用。"""
    deadline = time.time() + timeout
    backoff = 1.0
    while True:
        try:
            resp = client.chat.completions.create(
                model=model,
                messages=messages,
                max_tokens=max_tokens,
            )
            return resp.choices[0].message.content
        except Exception as e:
            if time.time() >= deadline:
                raise TimeoutError(f"llm_call timeout after {timeout}s: {e}")
            time.sleep(backoff)
            backoff = min(backoff * 2, 8.0)

def parse_tool_call(text: str) -> dict:
    """解析模型返回的工具调用 JSON,失败时返回空结构而不是抛异常。"""
    try:
        return json.loads(text)
    except json.JSONDecodeError:
        return {"error": "invalid_json", "raw": text[:200]}

重试要配合预算:模型调用有次数上限和 token 预算,超出后 Harness 主动进入 FAILED 或降级路径,而不是无限重试烧钱。4sapi 的用量统计可以直接对账到具体任务和 Agent。

八、工具层:结构化工具协议

工具是 Agent 改变世界的唯一通道,工具层越规范,治理就越容易。每个工具必须声明三件事:名称、参数 Schema、副作用等级(只读 / 可回滚写入 / 不可回滚写入)。

TOOLS = [
    {
        "type": "function",
        "function": {
            "name": "query_orders",
            "description": "按条件查询订单列表,只读操作",
            "parameters": {
                "type": "object",
                "properties": {
                    "status": {"type": "string", "enum": ["pending", "paid", "shipped"]},
                    "limit": {"type": "integer", "maximum": 100},
                },
                "required": ["status"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "refund_order",
            "description": "为订单发起退款,不可回滚写入,需要审批",
            "parameters": {
                "type": "object",
                "properties": {"order_id": {"type": "string"}},
                "required": ["order_id"],
            },
        },
    },
]

工具执行前 Harness 做参数校验、白名单校验和幂等检查;副作用等级高的工具自动进入 AWAIT_APPROVAL 状态。这样工具作者不需要自己实现权限,权限由控制面统一注入。

九、接口层:让外部系统安全调用

Agent 不是只能活在聊天窗口里。接口层让 Agent 变成可编程服务:外部系统通过 HTTP 创建任务、查询状态、接收结果。接口层的核心要求是幂等与恢复——调用方重试同一个请求时,不能产生两个任务。

import uuid
import requests

def submit_task(prompt: str, agent_url: str = "https://agent.example.com/tasks"):
    """提交 Agent 任务,携带幂等键,重复调用不会重复创建。"""
    idem_key = uuid.uuid4().hex
    resp = requests.post(
        agent_url,
        json={"prompt": prompt, "idempotency_key": idem_key},
        timeout=10,
    )
    resp.raise_for_status()
    return resp.json()["task_id"]

def wait_result(task_id: str, agent_url: str = "https://agent.example.com"):
    resp = requests.get(f"{agent_url}/tasks/{task_id}", timeout=10)
    resp.raise_for_status()
    return resp.json()  # {"state": "DONE", "result": ..., "cost": ...}

接口层还可以用 SSE 流式推送 Agent 的中间状态,让前端实时展示"正在规划 / 正在调用工具 / 等待审批",而不是干等一个最终结果。

十、知识架构:组织第二大脑

更高阶的实践是给 Agent 配一个"组织第二大脑":一套结构化、可审计的知识架构,把知识与推理分离。知识(事实、规则、经验、决策记录)放在知识库里,推理(模型调用)只负责检索和运用知识,两者不混在一起。

任务执行
   |
   v
结果与专家反馈(人工纠错、评审)
   |
   v
结构化知识条目(来源、时间、验证状态)
   |
   v
知识库(版本化、可审计、可回滚)
   |
   v
下一次推理引用知识,模型不重训、能力持续增长

这套循环的价值在于:模型不需要重训,系统却在变聪明。专家的一次纠错被沉淀成结构化知识条目,后续任务自动复用;每次知识变更都有来源和时间戳,出问题可以追溯回滚。知识与推理分离,还避免了把公司机密反复塞进 prompt 导致的泄露风险——敏感知识留在受控知识库,模型只拿到检索结果。

十一、错误处理与状态恢复

可靠的 Harness 对错误有一套统一策略,而不是遇到异常就整段重跑。错误按来源分类处理:

错误类型 示例 处理策略
模型层 超时、限流、非法返回 退避重试 + 预算上限
工具层 参数非法、执行失败 重试或降级为只读路径
状态层 进程崩溃、检查点损坏 从最近检查点恢复
治理层 审批拒绝、预算超支 进入 CANCELLED 并记录原因

每个错误都要落到状态机里:可重试的错误回到原状态重来,不可重试的错误进入 FAILED,用户拒绝审批则进入 CANCELLED。恢复的核心是检查点里记录了"已经做过什么",重跑时跳过已完成步骤,保证幂等。

十二、成本与风险清单

把可靠 Harness 上线前要确认的事项列成清单:

  1. 状态是否全部落到显式状态机,检查点是否持久化;
  2. 运行时是否隔离(沙箱 / 容器 / 动态机器池),Agent 能访问的最小权限集是什么;
  3. 治理链是否完整:身份校验、策略判断、审批、审计四段是否都接通;
  4. 模型接入是否统一(建议走 4sapi),是否有超时、重试、预算三重保护;
  5. 工具协议是否结构化,副作用等级是否标注,写操作是否幂等;
  6. 接口层是否支持幂等提交与断线恢复;
  7. 知识库是否有来源、时间戳、验证状态,能否回滚;
  8. 全链路是否留审计日志,成本是否可对账到任务粒度;
  9. 是否做过故障演练:进程崩溃、模型限流、审批拒绝、工具重复调用。

总结

可靠 Agent Harness 的骨架是七层:状态管理、运行时、控制面、推理、工具、接口与语言选择。显式状态机让执行可恢复,动态调度机器池让运行时可控,治理链让每次动作都有审批和留痕,结构化工具协议与幂等设计让错误可重试而副作用不重复,知识架构让组织经验可持续沉淀。不可避免的复杂度应由核心抽象吸收,而不是推给每个 Agent 自己实现。模型接入与计费这一段,可以直接复用 4sapi(https://4sapi.com)的统一网关能力,把精力留给状态、治理与工具本身。欢迎在评论区发表想法,聊聊各自踩过的 Agent 生产事故。