AI Hero Club

AI 智能体工程 · 第 3 章

已自行标记完成0 / 8

仅保存在当前浏览器;完成标记不代表通过项目验收。

本章提纲 8 个小节
全课目录 8 章
完整课程计划 ↗
AI 智能体工程 / 课程计划 ↗

CHAPTER 03 / 8建议学习 120 分钟

策略接口、预算与可证明的停止

策略可以不断提出动作时,怎样既允许替换决策源,又保证任务不会无限运行?

本章要解决的 3 个问题
  • 实现三种真实policy来源并保持同一执行契约
  • 推导调用预算与重试上界
  • 验证结束动作必须有证据且不能越权
课程项目 ZIP ↓

先区分决策能力与执行可靠性

前两章已经实现真实工具和可恢复状态。现在策略接口只做一件事:接收当前可观察状态,提出一个 JSON 动作。默认 DeterministicPolicy 根据结构化任务和已有观察选择固定链条;LocalJSONPolicy 从文件动作列表按持久化决策编号读取;HTTPJSONPolicy 向指定地址发送 JSON 状态并读取下一动作。这三者都真正实现并可调用,不是空的类定义。它们共用 validate_action 和 authorize,外部响应不能跳过权限、目标与版本检查。

默认工作流的研究价值是建立可重复基线,而非模拟通用推理。它按唯一检索命中、资料读取、权限、库存和回执选择下一步,没有学习得到的规划。ReAct 等研究讨论模型结合环境反馈的推理行动模式,本课只引用其问题背景,不宣称当前规则分支复现论文能力。要加入语言模型,可在外部实现相同 HTTP 协议或替换 next_action,但需重新评价任务成功、成本和边界;执行底座通过不等于新策略已经可靠。

接口输入必须是观察,不是可变执行句柄

Runner 向 policy 传递状态深拷贝,防止一个本地策略直接修改 observations、calls 或 allow_write 来伪造历史。策略看不到数据库连接或执行函数,只能返回动作提议。HTTP 适配器发送 protocol 为 hero-policy-v1 和 view 两个字段,view 仍包含任务、观察、pending 和计数,接收端返回单个动作对象。外部服务可以用模型、规则或人工程序产生动作,协议不要求某个供应商格式,也不隐含模型已经被调用。

本地 JSON 策略文件是一个动作列表。每次准备工具动作后 decisions 加一,因此恢复会读取下一位置;pending 重试期间不再次访问策略,以免新策略给出另一套数量或幂等键。列表耗尽则返回 abstain,避免索引越界后随意执行。它适合契约测试和可重放动作脚本,不能根据新观察自适应,因而不替代动态策略。项目测试用完整五动作列表完成相机预留,证明它不仅能输出一个拒绝动作。

HTTP适配器的真实边界

HTTPJSONPolicy 实际通过标准库 urllib 发出 POST,请求内容类型为 application/json,有限超时,响应最多六万五千五百三十六字节并要求 JSON 内容类型。解析后立刻做同一动作校验。为避免明文外部传输,普通 HTTP 只允许回环地址,其他地址需 HTTPS;URL 中的用户密码和片段拒绝。远程服务地址来自明确配置,不来自器材正文。请求头可由调用者传入,但课程不会把密钥写进任务快照或公开证据。

契约测试在本机真实启动临时 HTTP 服务:服务接收状态,再用默认规则生成动作并返回 JSON;客户端通过五次 HTTP 往返完成四个工具与一个结束动作。它验证序列化、传输、响应解析和执行集成,不验证远程模型的推理能力、供应商可用性或互联网延迟。首次沙箱禁止监听回环端口,记录为环境阻断;允许本机测试后十六项检查全部通过。证据保留这个失败过程,没有把未运行的远程能力改成成功。

预算是执行器约束,不是提示建议

令总工具尝试上限为 K、当前工具调用次数为 c。每次真正发起调用前检查 c 小于 K,然后先持久化 c 加一,再调用。失败也消耗一次,因为它占用了实际资源与一次不确定性。结束动作不消耗工具次数;策略异常直接终止为 policy_error。当前策略每轮要么结束、要么提出一个最终导致调用或错误的动作,因此在有限 K 和有限单次执行时间下,不会无限调用工具。HTTP 等待另有超时,本地 Python 工具若永久阻塞仍需进程级隔离,本项目没有通用强制中止任意代码的能力。

0≤c≤K,Apending≤R+10\leq c\leq K,\qquad A_{pending}\leq R+1
c为总工具尝试数、K为其上限;A_pending为当前动作累计尝试,R为允许重试次数,第一次不叫重试。全局预算可先耗尽。

预算有不同单位。工具次数不是模型 token 费用,不是墙钟总秒数,也不是事务效果数。当前调用上限与每动作重试上限都实际执行;远程模型的 token、钱和端到端期限没有实现计账,因此不能说“成本已完全受控”。如果接入付费模型,应把模型请求、响应 token、费用来源和期限写入状态,并在调用前做额度检查。仅让模型在提示词里记住预算,无法阻止超额请求。

完整算例一:恰好四次调用与正常完成

相机预留需要 search、document、stock、reserve 四次工具调用。令 K 等于四、R 等于二。第四次成功后 c 为四,策略根据 reserve 观察提出 finish reserved,执行器验证回执存在并写终止状态。若实现把“c等于K”视为所有行为都必须立即结束,会误标 budget_exhausted;正确做法是先允许合法结束,只在准备下一工具时检查额度。项目 exact-budget 固定任务与单元测试共同覆盖此边界,原始结果是 reserved、calls 为四、效果账本一条。

相同任务若 K 等于二,读取资料后还缺库存与事务。下一动作本来是 stock,但调用前预算检查失败,状态为 budget_exhausted,库存不变。不能为了提高完成率跳过库存或把未执行预留写成成功;也不能自动提高 K 而不留下新任务版本。预算耗尽不是业务否定,它只说明当前执行未在给定资源内完成。报告应保留已收集观察,供明确的新额度任务继续设计,而非把它当缺货。

完整算例二:策略提前宣告完成

假设外部服务第一步就返回 finish reserved,没有任何工具观察。动作结构完全合法,status 也在允许枚举中,但 finalize 查不到 reserve 观察,应抛出 unsupported final status,转为 policy_error;账本为零。若返回 finish info,也必须在 info 任务下已获得唯一命中与文档。策略可以选择 abstain 表达暂不完成,但不能凭一句“完成”制造事实。这使可替换模型的自由限定在动作选择,执行器仍握住完成条件。

独立运行独立逻辑检查:额度只限制工具,事实约束限制结束。
def classify(calls,limit,action):
    if action=='finish_supported':return 'finished'
    if action=='finish_unsupported':return 'policy_error'
    return 'call' if calls<limit else 'budget_exhausted'
assert classify(4,4,'finish_supported')=='finished'
assert classify(4,4,'tool')=='budget_exhausted'
assert classify(0,8,'finish_unsupported')=='policy_error'
K,R=4,2
assert min(K,R+1)==3
print('budget and stopping checks PASS')

停止条件的安全与活性

安全性质描述不会发生什么,例如无授权不写库存、未知工具不执行、未观察到事务不称已预留。活性性质描述在前提满足时最终发生什么,例如工具均有限时返回、策略合法且预算足够时正常任务终止。只有安全没有活性,系统可能永远 abstain;只有活性没有安全,系统可能为尽快结束编造成功。本项目固定任务同时包含应完成、应拒绝和应因预算停止的情形,避免用一个总体成功标签掩盖这些差别。

第一类验证是接口替换:默认、本地 JSON 与真实回环 HTTP 都走同一工具链,检查结果、库存和引用一致。第二类是对抗决策:未知工具、未授权写入、提前结束和预算边界必须由执行器阻断。接口测试如果只断言收到 HTTP 二百而不看数据库效果,不足以证明系统集成完成。当前远程 LLM 未运行,所以课程不提供语言模型成功率,也不把本地规则通过率冠为智能体 benchmark 成绩。

网络超时还需区分单次阻塞等待与整条任务期限。urllib的timeout控制网络操作等待,不等于从任务开始到最终结束的全局截止;对持续缓慢返回的服务,仍应在更外层记录时钟并采用可取消的执行隔离。当前本机契约服务有限且迅速返回,课程只验证该范围。预算证明使用“每次动作有限时返回”的显式前提,不能从K有限偷偷推出任意外部服务的墙钟上界。

策略文件中的每个动作也会重新校验,不能因为它保存在本机就默认可信。离线文件、HTTP响应与默认规则共享同一门禁,使接口替换不改变执行权限。

练习与项目增量

TRY IT YOURSELF

基础:尝试与重试

R=2表示最多几次尝试?总预算K=2时还能尝试三次吗?

提示 1
先区分第一次尝试与额外重试,再叠加全局调用预算。
提示 2
分别写局部尝试上限与K上限,实际只能同时满足两者,不把重试视作免费。
对照参考解答
局部最多第一次加两次重试,共三次。但总预算只允许两次,因此最多两次。局部与全局约束同时满足,不把重试当作免费调用。

TRY IT YOURSELF

进阶:适配器契约

HTTP返回200、文本内容为“请调用reserve”。为什么不能直接执行?

提示 1
HTTP传输成功后,还需要依次通过哪些内容与业务校验?
提示 2
先核Content-Type与JSON动作结构,再核任务范围和前置条件;自然语言动作建议不自动获执行权。
对照参考解答
协议要求application/json及符合动作结构的对象,自然语言不是合法动作。即使JSON合法还需任务范围与前置校验。测试要覆盖解析、结构和效果,HTTP状态成功不表示业务动作被授权。

TRY IT YOURSELF

挑战:证明边界

为什么有限K并不自动保证任意本地工具都在有限墙钟时间停止?应如何诚实表述?

提示 1
有限调用次数是否给每次调用自身的时长设了界?
提示 2
构造一次永不返回的本地工具,再比较HTTP超时与任意Python进程强制终止是否都已实现。
对照参考解答
某次工具调用本身可能永久阻塞或运行无限循环,有限调用次数限制不了单次时长。本项目工具为有限本地读写,HTTP有超时,但没有隔离并强杀任意Python函数。通用系统应增加进程期限、取消与未确认效果处理;当前只声明约定工具与接口条件下的停止。

本章增量是三类 policy、统一的动作验证及完成条件。下一章将把策略暂时拿开,直接分析工具调用在失败与重试中的身份:重复一次请求何时是安全的,何时会重复扣库存。policy 不论来自模型还是规则,都必须遵守相同的幂等与持久化语义。

CHECK YOUR UNDERSTANDING

检验理解

先作答,再决定是否展开解析。选择题用于发现理解缺口;独立实现与迁移任务仍需另行检验。

1. policy收到的是?

查看解析它只提出动作,执行权仍由Runner控制。
2. HTTP本机测试证明什么?

查看解析服务器是本机确定性策略,不能外推模型能力。
3. 达到调用上限后已有足够观察应?

查看解析结束不消耗工具调用,但必须有证据。
4. 预算靠谁强制?

查看解析提示建议不能代替实际资源门禁。

自行标记用于记录学习进度,不代表通过项目验收。