拓冰建站拓冰建站
首页 / 资讯中心 / 正文

给 Agent 装上护栏——harness 层设计

给 Agent 装上护栏——harness 层设计这是「Agent 工程化」系列的第九篇。前面八篇把 Agent 的能力讲完了会动手、记性好、懂业务、有经验、还会拆任务。但能力越强越让人害怕——它跑飞了怎么办这篇讲护栏harness预算、白名单、重试、断点恢复让能干的 Agent 也听话。跑飞现场上线第一天钱花光了还在跑Agent 上线第一天的真实场景用户帮我查一下这个行业的最新动态 Agent调用搜索工具第 1 次搜到 10 条结果 Agent第 2 次嗯再搜下另一个关键词…… Agent第 30 次…… Agent第 200 次还没完再搜搜……用户早走了Agent 还在自己循环搜索工具被调了几百次token 费用哗哗涨但没人能叫停它。为什么会这样回看第二篇那个核心循环while任务未完成:# ← 问题在这llm 输出{思考,行动}执行工具循环的条件是任务未完成——谁来判断完成LLM 自己。而 LLM 可能陷入再搜一次也许有结果的死循环。循环是油门没有刹车。护栏要做的就是给这个循环装上刹车。专业点说在 Agent 循环外面包一层 harness缰绳它不管 Agent 怎么想只管不许越过这些线。护栏的整体结构循环外的一层壳是否用户提问harness 前置检查预算还有吗 工具在名单里吗Agent 循环思考 行动 观察harness 后置检查超预算了吗 死循环了吗一切正常强制收尾告知用户已达上限harness 不管怎么完成任务只管四件事预算、白名单、重试、断点。逐个拆。核心一三层预算——先定义多少钱算完跑飞的本质是没有成本上限。解法是给循环套三层预算任何一层超了都强制收尾层级管什么例子每次调用单次工具调用的开销上限单次返回最多 2000 token每轮循环单轮思考行动的 token单轮最多 1500 token整个会话总调用次数 / 总 token / 总费用最多 20 次工具调用总费用 0.5 元classBudget:def__init__(self):self.max_calls20# 整个会话最多调 20 次工具self.max_cost0.5# 最多花 0.5 元self.calls0self.cost0.0defcheck(self)-bool:循环每轮开始时检查超了就刹车returnself.callsself.max_callsandself.costself.max_cost循环每轮都问一句预算还够吗budgetBudget()whilenottask_doneandbudget.check():# 刹车在这里...# Agent 循环本体budget.calls1budget.costround_cost(...)else:ifnottask_done:finish_gracefully(已达本次会话上限先到这里)# 优雅收尾优雅收尾是关键预算耗尽不是硬中断而是告诉用户已达上限需要的话可以继续。核心二工具白名单——只允许它碰该碰的Agent 能力越强越要给它的工具划定范围方式说明风险黑名单默认都可用禁止某些漏一个就出事白名单默认都不可用只放行名单内的最安全写操作天然受限生产里两个原则白名单 按场景下发查资料任务只下发搜索工具订票任务才下发下单工具——每个 Agent 看到的工具是这个任务该有的写操作强制人工确认下单、付款、删数据这类工具执行前必须过人工确认闸第三篇讲过两道闸harness 在这里落地WHITELIST{research_task:[web_search,read_url],# 研究任务只给查询工具booking_task:[search_flight,book_ticket],# 订票任务才给下单工具}defallowed_tools(task_type:str)-list:return[tfortinALL_TOOLSift.nameinWHITELIST[task_type]]白名单 不给模型做坏事的机会比事后追责便宜得多。核心三重试——什么时候重来什么时候别重来工具调用会失败但失败要分类——有的值得重试有的重试等于烧钱失败类型例子重试网络抖动连接超时、服务 503重试退避重试限流429 请求过多重试等几秒参数错误4xx、必填参数缺失不重试重试也一样错逻辑错误业务校验不通过不重试改参数才行importtimedefcall_with_retry(fn,*args,max_retries3):foriinrange(max_retries):try:returnfn(*args)exceptNetworkErrorase:# 5xx/429退避重试time.sleep(2**i)# 1s, 2s, 4s 退避exceptParameterErrorase:# 4xx参数错了重试没用returnf参数错误:{e}# 把错误反馈给模型让它改return多次重试仍失败一条判断口诀网络层的问题重试业务层的问题反馈给模型改。把错误信息以工具结果形式喂回模型第三篇讲过反馈修正让模型自己改参数——这比重试高效得多。核心四断点恢复——聊到一半崩了能接着聊生产环境进程可能随时重启发布、OOM、宕机。用户聊到一半会话就没了这是最伤体验的事。断点恢复 会话状态持久化会话进行中每轮结束把状态落库messages 已完成步骤 预算剩余进程崩溃 / 用户离开重启后从库恢复重建上下文接着上一轮继续defsave_checkpoint(session_id,messages,budget):db.save(session_id,{messages:messages,budget:budget})defrestore(session_id):statedb.load(session_id)returnstate[messages],state[budget]# 重建上下文继续跑注意持久化的不只是 messages还有预算剩余和已完成步骤——恢复后不能白跑一遍那会重复扣费、重复下单。踩坑Agent 死循环怎么都停不下来最经典的护栏翻车场景场景工具返回了一个错误Agent 觉得我没调好再调一次结果同一个错误循环重试了几十次——步数没超限但轮次全部浪费在重试同一个注定失败的调用上。根因步数上限只防无限循环防不了低效循环。解法加一层连续失败检测——连续 N 次比如 3 次工具调用都失败或结果相同就认定卡住了CONSECUTIVE_FAIL_LIMIT3defshould_stop(history)-bool:fails0forhinhistory[-CONSECUTIVE_FAIL_LIMIT:]:ifh.is_errororh.resulthistory[-1].result:fails1returnfailsCONSECUTIVE_FAIL_LIMIT卡住后的收尾方式也有讲究不是沉默硬停而是强制提示一次 标记未解决助手抱歉我连续尝试了几次都未能完成标记为未解决 可能是接口暂时不可用。建议稍后再试或联系人工客服。把未解决状态记录下来——这是第 11 篇评测的数据来源哪些问题 Agent 搞不定比哪些问题它搞定了更有价值。小结护栏 循环外的壳不管怎么干只管不许越线三层预算每次 / 每轮 / 整个会话超了就优雅收尾工具白名单按场景下发写操作人工确认不给做坏事的机会重试分两类网络层问题重试退避业务层问题反馈给模型改断点恢复messages 预算 已完成步骤都持久化崩溃了接着聊死循环连续失败检测 强制提示一次 标记未解决下篇预告护栏装好了Agent 终于敢放心上线了。但上线只是开始——线上 Agent 出了岔子你怎么知道它调用了几次工具、花了多少钱、哪一步答错了这些必须有记录。下一篇讲生产部署与可观测日志、trace、指标、告警让线上 Agent 的一举一动都在掌握之中。本系列路线从 0 到 1Agent 是什么 → 手写最小 ReAct → Function Calling 与工具设计 → 上下文管理 → Memory 记忆系统 → RAG 知识库 → Skill 自学习 → 编排模式与多 Agent → 给 Agent 装护栏 → 生产部署与可观测 → 评测与回归
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门