Agentic AI验证框架:从规则引擎到可观测性的Python实现
发布时间:2026/9/1 11:52:25来源:尧图网络
当把带工具调用的 Agent 从 Demo 推向生产环境时会遇到一类非常现实的问题模型明明只有两个内部工具可用某些 Prompt 下却会拼接出不存在的工具名工具已经返回了结构化结果模型却没有基于返回值作答而是开始自由发挥编造出看似合理的订单状态。更麻烦的是这类问题很难在开发阶段被传统测试用例覆盖因为模型的每一步决策都是动态的。如果你也在做 Agentic AI 的应用落地大概率会陷入同一种困境为了一个低频但高危的错误不敢把 Agent 真正交给用户。这篇文章会围绕 “Only believe what you can validate” 这一原则拆解 Agentic AI 验证框架的设计思路并给出一套轻量级、可直接运行的 Python 实现。读完你可以掌握验证框架的核心模块、规则引擎的写法以及如何在代码层面追踪和校验 Agent 的每一步行为。1. 为什么 Agentic AI 需要一套验证框架1.1 Agentic AI 到底是什么Agentic AI 通常指具备自主决策、任务规划和工具调用能力的 AI 系统。它和传统 Chatbot 的关键区别在于对话型模型只负责“生成文本”而 Agent 会在一次任务中自主决定调用哪些工具、传入什么参数、如何处理工具返回值进而决定下一步动作。一个最简单的 Agent 执行链路通常包含四类步骤接收用户输入并形成推理或计划。根据计划选择一个工具。用拼接好的参数调用工具并获取返回值。基于工具返回值生成最终回复或继续下一轮决策。在这个过程里模型既承担了“意图理解”的角色又承担了“决策执行”的角色。换句话说Agent 不再只是回答“你说得对”而是真的会去操作订单、修改数据、读取文件、触发工作流。1.2 传统测试为什么失效传统软件测试的核心假设是“代码路径可以枚举”。一个函数有多少分支、多少个输入参数、边界条件是什么开发者可以在编码阶段想清楚然后写单元测试、集成测试去覆盖。但 Agent 的逻辑由模型权重驱动不是由明确的 if-else 驱动。同样的用户问题在不同模型版本、不同 Prompt 措辞、不同历史上下文下可能产生完全不同的工具参数。这就导致很难提前枚举所有错误路径。工具调用参数是否符合预期只能在运行时判断。模型的“幻觉”可能出现在工具返回之后而不是之前。一个错误决策可能被后续多步执行放大最终造成数据污染或权限越界。你会发现传统测试只能保证“代码本身没有 bug”但无法保证“模型这次没有乱来”。因此我们需要一套运行时的验证框架对 Agent 的每一步行为进行校验、记录和干预。1.3 验证框架要解决的核心问题把 “Only believe what you can validate” 落到工程上核心是回答三个问题Agent 每一步做了什么这一步是否符合预期规则如果不符合应该如何响应要让以上问题可回答验证框架至少要提供三部分能力可观测、可校验、可追溯。可观测记录 Agent 的推理、工具调用、工具返回、最终回复。可校验对每一步执行规则断言例如工具名是否合法、参数是否完整、返回值是否符合 schema、最终回复是否包含敏感信息。可追溯保留完整执行日志出现问题时能定位到具体是哪一步、哪个规则失败。下一节我们围绕这三个能力拆解一个通用验证框架的层次结构。2. 验证框架的整体设计四个层次2.1 第一层输入校验与工具参数校验这一层最直观也最容易实现。在 Agent 调用工具之前我们要对两件事做校验工具名是否在允许的白名单内。工具参数是否满足最小必填要求以及参数类型是否合法。例如一个订单查询工具要求order_id是字符串并且不能为空。如果模型传入了空的order_id或者传了数字类型验证框架应该在真正执行工具之前拦截下来。很多 Agent 框架内置了函数调用Function Calling能力模型输出本身是 JSON 结构。但 JSON 结构合法不代表业务语义合法。比如模型可能传{order_id: }JSON 是合法的但业务上毫无意义。因此输入校验必须包含业务规则不能只依赖 JSON Schema。2.2 第二层过程追踪与中间状态校验这一层解决“Agent 到底做了什么”的问题。建议在 Agent 执行的每个关键节点都埋点模型生成的一段思考或计划。每次工具调用的工具名、入参。每个工具的原始返回值。每次工具调用产生的异常。最终回复内容。把这些节点统一记录成结构化日志而不是简单地打print。结构化日志可以直接喂给规则引擎执行断言也可以在事后导出来做人工审计。这一层还应该支持“中间状态校验”。例如某个 Agent 被设计了业务规则只有用户是管理员角色时才允许调用删除类工具。如果模型在中间步骤尝试调用该工具即使最终回复没有透出任何异常验证框架也应该判定这次执行为失败。2.3 第三层输出结果校验输出结果校验是对 Agent 最终回复的检查也是防止幻觉扩散的最后一道防线。常见校验项包括最终回复是否包含敏感信息例如身份证号、手机号、内部 token。最终回复是否与工具返回值矛盾。最终回复是否包含明确的拒绝措辞当不应该有权限时。最终回复长度是否合理是否明显啰嗦或截断。实际操作中输出校验既可以基于正则、关键词等传统规则也可以基于另一个 LLM 做评估即 LLM-as-a-judge 的方式。后者的判断能力更强但要注意评估模型本身的稳定性和成本。2.4 第四层审计与异常决策回溯最后一层是长期价值所在。验证框架应该把所有步骤记录和验证结果保存下来形成可供检索的审计事件。这一点在生产环境中尤其重要。当用户投诉 Agent 执行了错误操作时我们需要快速回答这个 Agent 当时调用了哪些工具传入的参数是谁给出的触发失败的是哪条规则是否有同类问题在多个会话中反复出现把验证结果和 Agent 的决策日志放到一起就能做非常有效的回归分析。后续如果调整 Prompt 或模型版本也可以先用历史会话数据重放一遍观察验证失败率是否上升。3. 环境准备与项目结构3.1 运行环境在动手写代码之前先说明运行环境。为了让你能直接复制运行本文示例只使用 Python 标准库不依赖额外的第三方包。版本建议Python 3.10 及以上因为示例使用了dataclass、Enum和tuple[bool, str]类型注解。操作系统不限Windows、macOS、Linux 均可。IDE 推荐使用 VS Code 或 PyCharm主要是有类型提示支持。如果你的项目里已经使用了 Pydantic、LangChain 或其他 Agent 框架不影响本文思路。把本文的验证器作为独立模块接入即可。3.2 项目结构为了方便管理我们将示例组织成下面的目录结构demo-agent-verification/ ├── main.py └── verification_framework/ ├── __init__.py ├── agent/ │ ├── __init__.py │ └── demo_agent.py └── core/ ├── __init__.py ├── models.py ├── rules.py ├── tracker.py └── verifier.py各文件的职责如下文件职责core/models.py定义步骤记录的数据模型和步骤类型枚举。core/rules.py定义验证规则抽象类及常用规则实现。core/tracker.py定义会话追踪器记录 Agent 每一步行为。core/verifier.py定义验证执行器批量执行规则。agent/demo_agent.py模拟一个带工具调用的 Agent。main.py组装 Agent 和验证框架运行完整链路。4. 实现一个轻量级验证框架4.1 定义验证数据模型所有验证的基础是结构化记录。我们先定义StepRecord数据类它表示 Agent 执行过程中的一个步骤。# 文件路径verification_framework/core/models.py from dataclasses import dataclass, field from typing import Any, Optional from enum import Enum from datetime import datetime class StepType(str, Enum): REASONING reasoning TOOL_CALL tool_call TOOL_RESULT tool_result AGENT_REPLY agent_reply dataclass class StepRecord: session_id: str step_type: StepType content: str tool_name: Optional[str] None input_args: Optional[dict] None output: Any None error: Optional[str] None timestamp: str field(default_factorylambda: datetime.now().isoformat()) def to_dict(self): return { session_id: self.session_id, step_type: self.step_type.value, content: self.content, tool_name: self.tool_name, input_args: self.input_args, output: self.output, error: self.error, timestamp: self.timestamp, }这里的关键是step_type枚举。把 Agent 行为归一成四类步骤后规则引擎就能针对某一类步骤做特定校验而不是把推理文本和工具调用混在一起处理。to_dict()方法用于后续日志导出和审计。生产环境中这一步可以选择将记录写入 JSONL 文件、数据库或日志系统。4.2 编写验证规则规则引擎是验证框架的核心。我们定义一个抽象基类VerificationRule所有规则统一实现check()方法该方法接收一个StepRecord返回(是否通过, 失败信息)。# 文件路径verification_framework/core/rules.py from abc import ABC, abstractmethod from typing import List from .models import StepRecord, StepType class VerificationRule(ABC): 所有验证规则的基类。 name: str abstractmethod def check(self, record: StepRecord) - tuple[bool, str]: ... class AllowedToolRule(VerificationRule): 校验 Agent 调用的工具是否在白名单内。 name allowed_tool def __init__(self, allowed_tools: set): self._allowed_tools allowed_tools def check(self, record: StepRecord) - tuple[bool, str]: if record.step_type StepType.TOOL_CALL: if record.tool_name not in self._allowed_tools: return False, ftool {record.tool_name} 不在白名单中 return True, class RequiredArgRule(VerificationRule): 校验指定工具调用的必填参数是否存在且非空。 name required_arg def __init__(self, tool_name: str, required_args: List[str]): self._tool_name tool_name self._required_args required_args def check(self, record: StepRecord) - tuple[bool, str]: if record.step_type StepType.TOOL_CALL and record.tool_name self._tool_name: args record.input_args or {} for arg in self._required_args: if arg not in args or args[arg] is None or args[arg] : return False, ftool {self._tool_name} 缺少必填参数: {arg} return True, 在这个设计中规则只对与自己相关的步骤生效无关步骤默认通过。例如RequiredArgRule只校验指定工具名对应的TOOL_CALL记录并不会干扰其他工具的调用。通过继承抽象基类你可以不断扩展新规则。比如“金额必须大于 0”“地址必须属于允许的省份”“返回值必须包含 status 字段”等都可以用同样模式实现。4.3 实现验证执行器有了规则还需要一个执行器来批量运行规则并汇总结果。# 文件路径verification_framework/core/verifier.py from dataclasses import dataclass from typing import List from .models import StepRecord from .rules import VerificationRule dataclass class StepCheckResult: record: StepRecord rule_name: str passed: bool message: str class Verifier: def __init__(self, rules: List[VerificationRule]): self._rules rules def verify(self, records: List[StepRecord]) - List[StepCheckResult]: results [] for record in records: for rule in self._rules: passed, message rule.check(record) results.append(StepCheckResult( recordrecord, rule_namerule.name, passedpassed, messagemessage, )) return results def summary(self, results: List[StepCheckResult]) - None: total len(results) failed [r for r in results if not r.passed] print(f验证总条数: {total}, 失败条数: {len(failed)}) for r in failed: print(f [FAIL] rule{r.rule_name} fstep{r.record.step_type.value} fcontent{r.record.content[:40]!r} fmessage{r.message}) if not failed: print( [PASS] 所有规则均通过)verify()方法沿“记录 × 规则”的维度做笛卡尔积遍历结果量级通常很小不会成为性能瓶颈。每个StepCheckResult都保留了对应的record方便定位失败的具体步骤。summary()方法只是辅助输出。生产环境建议把失败结果序列化为结构化日志并推动告警而不是只打印在控制台。4.4 实现 Agent 调用追踪追踪器的作用是让 Agent 在执行过程中把每一步记录下来。为了减少 Agent 逻辑的改动我们把SessionTracker传入 Agent 构造函数。# 文件路径verification_framework/core/tracker.py from typing import List from .models import StepRecord class SessionTracker: 记录一次 Agent 会话中的所有关键步骤。 def __init__(self, session_id: str): self.session_id session_id self.records: List[StepRecord] [] def add_record(self, record: StepRecord) - None: self.records.append(record) def export(self) - List[dict]: return [r.to_dict() for r in self.records]add_record()统一收口所有步骤的写入。这样我们还可以在中间加上一些副作用操作例如实时上报、缓存、按阈值告警等。5. 完整实战验证一次带工具调用的 Agent 流程5.1 模拟一个订单查询 Agent为了方便演示下面实现一个极简 Agent。它包含两个模拟工具一个是查询订单状态一个是发起退款。Agent 会按照“接收问题 → 调用查询工具 → 生成回复”的顺序执行。# 文件路径verification_framework/agent/demo_agent.py import json from ..core.models import StepRecord, StepType from ..core.tracker import SessionTracker def get_order_status(order_id: str) - dict: 查询订单状态模拟实现。 if order_id A001: return {order_id: order_id, status: shipped, amount: 199.0} return {order_id: order_id, status: unknown, amount: 0.0} def send_refund(order_id: str, reason: str) - dict: 发起退款模拟实现。 return {order_id: order_id, reason: reason, status: refund_created} TOOL_MAP { get_order_status: get_order_status, send_refund: send_refund, } class DemoAgent: def __init__(self, tracker: SessionTracker): self.tracker tracker def run(self, user_request: str, session_id: str) - str: # 1. 记录用户输入 self.tracker.add_record(StepRecord( session_idsession_id, step_typeStepType.REASONING, contentfuser_request: {user_request}, )) # 2. 模拟模型决策调用订单查询工具 order_id A001 tool_name get_order_status args {order_id: order_id} self.tracker.add_record(StepRecord( session_idsession_id, step_typeStepType.TOOL_CALL, content模型决定查询订单状态, tool_nametool_name, input_argsargs, )) result TOOL_MAP[tool_name](**args) self.tracker.add_record(StepRecord( session_idsession_id, step_typeStepType.TOOL_RESULT, contentf工具返回: {json.dumps(result, ensure_asciiFalse)}, tool_nametool_name, outputresult, )) # 3. 模拟模型基于结果生成回复 if result.get(status) shipped: final_reply 您的订单已发货。 else: final_reply 抱歉暂时无法查询到该订单。 self.tracker.add_record(StepRecord( session_idsession_id, step_typeStepType.AGENT_REPLY, contentfinal_reply, )) return final_reply这个示例把“模型决策”简化成了固定逻辑。真实项目中你会在第二步接入 LLM 的 Function Calling 或 ReAct 循环此时只要保证每一次工具调用前后都写入StepRecord追踪器就能正常工作。5.2 配置验证规则并运行有了 Agent 和验证框架后我们在main.py中把它们串起来。# 文件路径main.py from verification_framework.agent.demo_agent import DemoAgent from verification_framework.core.rules import AllowedToolRule, RequiredArgRule from verification_framework.core.tracker import SessionTracker from verification_framework.core.verifier import Verifier def main(): session_id session-001 tracker SessionTracker(session_id) agent DemoAgent(tracker) # 1. 让 Agent 执行一次任务 reply agent.run(查询我的订单状态, session_id) print(Agent 回复:, reply) print() # 2. 导出完整记录 records tracker.records # 3. 配置验证规则 rules [ AllowedToolRule(allowed_tools{get_order_status, send_refund}), RequiredArgRule(tool_nameget_order_status, required_args[order_id]), RequiredArgRule(tool_namesend_refund, required_args[order_id, reason]), ] verifier Verifier(rules) # 4. 执行验证 results verifier.verify(records) verifier.summary(results) if __name__ __main__: main()在项目根目录执行python main.py预期输出如下Agent 回复: 您的订单已发货。 验证总条数: 8, 失败条数: 0 [PASS] 所有规则均通过这里的 8 条验证结果来自 4 个StepRecord乘以 2 个规则。当前 Agent 行为符合预期所以全部通过。5.3 构造一个会失败的场景为了让验证框架体现出价值我们把 Agent 的调用改成“越权行为”在DemoAgent.run()中模拟模型错误地调用了send_refund工具并且在参数中省略reason。修改demo_agent.py中对应片段# 模拟模型错误决策跳过查询直接发起退款 tool_name send_refund args {order_id: A001}再次运行main.py输出会变成Agent 回复: 您的订单已发货。 验证总条数: 8, 失败条数: 2 [FAIL] rulerequired_arg steptool_call content模型决定查询订单状态 messagetool send_refund 缺少必填参数: reason注意输出中只列出reason参数缺失。原因是send_refund工具本身在白名单中所以AllowedToolRule并不拦截。如果我们把业务规则改为“退款工具需要管理员权限”还需要再新增一条权限规则才能捕获越权调用。这恰恰说明验证规则需要结合具体业务场景逐步沉淀。6. 常见问题与排查思路在实际使用中验证框架本身也会遇到一些常见问题。这里整理成表格方便你直接对照排查。问题现象常见原因解决思路Agent 调用了不存在的工具模型在 Function Calling 中拼接了错误的工具名检查工具定义是否清晰验证白名单规则是否覆盖所有工具工具参数缺失或为空模型没有从上下文中提取到关键实体在 Prompt 中强化必填参数要求并在验证规则里增加 RequiredArgRule工具返回后模型仍然幻觉模型没有严格基于工具返回值作答在输出校验中加入“回复是否包含工具返回值关键信息”的规则验证规则误报太多规则条件过严或未区分步骤类型检查规则是否只对特定 step_type 生效优先用白名单而非黑名单一条步骤触发大量规则日志爆炸规则设计粒度过细合并同类规则只保留影响业务结论的高价值规则验证失败但业务仍继续缺少失败阻断机制在验证器返回失败后由上层决定是重试、降级还是人工介入追踪记录太多影响性能在循环内部记录了所有中间变量只记录关键决策节点避免记录完整 Prompt 或超大上下文快速排查时建议先看两样东西第一是StepRecord中的step_type和tool_name确认失败发生在哪一步第二是失败规则本身的条件确认是否覆盖了当前场景。大部分问题都能靠这两步缩小范围。7. 最佳实践与工程建议7.1 把验证规则当作产品代码维护验证规则不是一次性写死的脚本它应该像业务代码一样被管理。推荐做法是规则单独建目录按业务模块拆分文件。每条规则都有明确的name和失败信息模板。新增工具时必须同时新增对应规则。变更规则必须走 Code Review。如果 Agent 的决策逻辑比较丰富可以考虑把规则描述抽成 JSON/YAML 配置方便非开发人员参与维护。但要注意配置化会带来一定的动态加载复杂度建议先从代码模式开始。7.2 验证失败后的响应策略要分层设计验证失败并不意味着一定要终止整个流程。通常可以分为三层软失败记录警告继续执行。适合低风险场景例如回复语气不够友好。硬失败中断当前步骤返回预设错误信息。适合高风险场景例如参数非法或调用越权。人工介入进入审批队列。适合无法自动判断的复杂场景例如退款金额超过阈值。一个容易踩坑的地方是不要在 Agent 内部用 try-except 把所有异常都吞掉。验证失败信息要透出到上层由调度系统决定响应策略。7.3 权限与安全边界必须前置Agent 的权限边界是安全性最高的一环。建议遵循最小权限原则每个 Agent 只挂载业务必需的工具。工具白名单在配置中心维护不要在代码中硬编码。涉及删除、退款、发送消息等高风险操作必须增加二次确认或人工审批。不能在 Agent 的 Prompt 或工具描述中暴露内部敏感信息。验证框架只能检测“是否越权”并不能替代权限系统本身。底层的工具执行仍然需要独立的鉴权和审计。7.4 结构化日志是可观测性的基础生产环境的 Agent 日志不能只输出人类可读文本建议统一输出 JSON 结构。至少包含{ session_id: session-001, step_type: tool_call, tool_name: get_order_status, input_args: {order_id: A001}, output: null, error: null, timestamp: 2025-01-15T10:00:00.000Z }结构化的好处是能直接被日志平台检索、聚合和告警。当验证失败率上升时我们可以按rule_name聚合快速发现是哪条规则在被大量触发。7.5 用历史会话做回归评测验证框架沉淀下来的数据是 Agent 评测集的重要来源。建议定期做这么一件事把过去一段时间的真实会话固定成测试集每次修改 Prompt、升级模型、调整工具定义后重新跑一遍验证观察失败率变化。这才是 “Only believe what you can validate” 的真正实践不是上线前测一次就结束而是每一次改动都要有可验证的回归结论。8. 总结与进一步学习本文从一个容易踩坑的场景出发介绍了为什么 Agentic AI 不能只依赖传统测试并围绕 “Only believe what you can validate” 设计了一套轻量级验证框架。完整代码中包含四个核心部分数据模型、规则引擎、追踪器、验证执行器。这套结构可以直接复用到真实项目也可以作为你自研 Agent 平台的起点。如果你希望继续深入建议关注以下方向把StepRecord接入主流日志或追踪系统让验证日志和链路追踪打通。研究基于评估模型的输出校验方案用于判断回复是否与工具结果矛盾。在历史会话上批量重放验证规则建立 Agent 回归评测集。将验证失败率指标纳入监控告警例如失败率超过阈值时自动通知。落地的过程中最重要的不是想象 Agent 能有多智能而是先把每一步行为记录清楚、校验严格。你能验证的部分越多可以信任的部分就越大。
网站建设高端定制企业官网