在做 LLM Agent 应用时,很多团队把精力集中在 Prompt 调优、工具调用格式和上下文管理上,却很少认真设计“评估层”。最常见的评估方式是:让 Agent 跑完整个任务,把完整轨迹存下来,再到离线数据集上统一算准确率。这种做法的最大问题是,评估结果来得太晚,任务已经执行完,错误已经发生,成本已经花掉,你只能在下一轮迭代里修复,无法在运行过程中干预。
ParEvalLayer 提供了一种不同的思路:在任务执行过程中,使用部分评估信号来支撑实时决策。它不追求每一步都做全量、深度的评估,而是根据当前决策点的需求,只评估最关键的几个维度,然后快速给出“继续、重试、切换、终止、求助人工”等动作建议。本文会从概念拆解开始,带你一步步实现一个最小可运行的 ParEvalLayer,并给出接入 Agent 主循环的完整代码示例。
这篇文章适合正在开发 LLM Agent 应用的后端工程师、算法工程师,也适合对 Agent 可观测性和评估体系感兴趣的同学。读完你会理解:为什么全量评估在生产环境不可行、部分评估的维度应该如何选取、评估结果如何转成决策动作,以及这套机制在工程落地时常见的坑。
1. 背景与核心概念
1.1 为什么 LLM-Agent 需要评估层
LLM-Agent 的本质是一个循环:大模型根据当前状态生成下一步动作,动作触发工具调用,工具返回结果,模型再把结果纳入上下文继续推理。这个过程会持续多轮,直到任务完成或达到终止条件。
在这个循环里,错误的代价是累积的。第一步如果选错了工具,后面的所有步骤都会基于错误的结果继续推导,最后输出的答案可能看起来完整,实际上完全不可用。更麻烦的是,LLM 本身具有很强的“自洽”能力,它会把错误过程包装得逻辑通顺,人工事后审查往往要花费比执行任务更长的时间。
评估层要解决的核心问题就是:如何判断 Agent 当前的状态是否健康。这里的“健康”包括几个方面:当前动作是否偏离用户目标、工具调用是否合法、模型输出是否有幻觉风险、任务是否在推进、最终答案格式是否满足要求。没有评估层,Agent 就像一个没有仪表盘的飞行器,只有落地之后你才知道飞偏了。
1.2 什么是 ParEvalLayer:部分评估而不是全量评估
ParEvalLayer 的核心含义在 “Partial” 这个词上。它强调的是一种有选择的、按需的评估方式,而不是每一步都对所有维度做完整打分。
为什么需要“部分”评估?原因很实际。如果每个步骤都调用一个大模型充当 Judge,对轨迹做全面评估,Token 消耗会成倍增加,响应延迟也会显著拉长。假设一个 Agent 要执行 10 步,每步评估需要 2000 Token,那么评估本身的成本就相当于多跑了两三个 Agent。这在离线评测中可以接受,但在生产环境的实时请求链路里是完全不可行的。
另一个原因是,不同决策点需要的信息粒度不同。Agent 在调用完一个工具之后,我们最关心的是“这次工具调用是否合理”;在准备输出最终答案之前,我们最关心的是“答案是否完整、是否有幻觉风险”。如果用一个固定的全量评估模板去覆盖所有场景,既浪费资源,又容易因为关注点分散而降低判断准确率。
所以 ParEvalLayer 的设计哲学是:评估维度和评估深度都跟随决策点动态变化。在关键节点做关键评估,用最小成本支撑当前最重要的决策。
1.3 典型应用场景
ParEvalLayer 适合用在所有需要“执行中干预”的 Agent 场景。这里举几个典型的例子。
第一个是智能客服 Agent。用户的问题可能超出 Agent 能力范围,如果不做评估,Agent 会硬着头皮生成一个看似合理的错误答案。接入评估层后,系统可以在模型生成回复前检测“是否有足够信息支撑回答”,如果信心不足,就触发转人工决策,避免错误信息直接触达用户。
第二个是代码生成与执行 Agent。Agent 生成 SQL 后,不能直接丢给数据库执行。评估层可以先检查 SQL 是否包含 DELETE、DROP 等危险操作,是否缺少 WHERE 条件,是否引用了不存在的表名。只有通过安全评估的 SQL 才会被放行执行。
第三个是多 Agent 协作系统。任务需要在多个子 Agent 之间路由,评估层可以判断当前子 Agent 是否卡住,如果连续多步没有进展,就切换到另一个更合适的子 Agent。
第四个是数据分析 Agent。Agent 生成结论之前,评估层可以对比结论和中间数据,检查是否存在明显的数字不一致或推断过度,及时拦截幻觉输出。
这些场景的共同点是:都需要在运行过程中做出决策,而且决策的正确性直接影响最终结果质量。
2. 环境准备与技术选型
2.1 运行环境
ParEvalLayer 本质上是一套评估逻辑的抽象设计,不依赖特定的 Agent 框架,所以实现起来很轻量。本文示例采用以下环境:
- 操作系统:Linux / macOS / Windows 均可
- 编程语言:Python 3.10 及以上
- 依赖库:仅使用标准库,不引入额外第三方框架
- LLM 接口:示例使用 OpenAI 风格的 Chat Completion 接口,实际项目中可按需替换
这里要说明一下,ParEvalLayer 并不是一个可以直接 pip install 的官方库,而是一种评估层设计模式。不同项目里的 Agent 框架、模型接口、工具系统差异很大,所以本文的重点是教会你实现这套模式,而不是提供一个绑定特定框架的黑盒组件。
2.2 版本说明
示例代码中会用到dataclasses和enum,这两个都是 Python 标准库,从 Python 3.7 开始稳定可用。如果你使用的是 Python 3.8 以下版本,建议先升级,因为from __future__ import annotations等类型注解特性在低版本下支持不完整。
LLM 模型方面,评估器既可以调用 GPT 系列模型,也可以调用开源模型。由于不同模型的指令遵循能力差异较大,评估提示词需要根据模型微调,这一点在后面的示例中会体现。
2.3 项目结构
为了让代码清晰易读,我们把示例拆成多个模块。整体结构如下:
pareval_demo/ ├── pareval/ │ ├── __init__.py │ ├── signal.py # 评估信号数据结构 │ ├── evaluator.py # 评估器抽象与实现 │ ├── policy.py # 决策策略 │ └── layer.py # ParEvalLayer 主类 ├── agent/ │ ├── __init__.py │ └── loop.py # Agent 主循环 ├── examples/ │ └── demo_agent.py # 完整示例运行入口 └── README.md后面我们按照这个结构逐个文件实现。先不要急着写代码,下一节先理解几个核心概念,这比代码本身更重要。
3. 核心设计:评估维度、信号与决策规则
3.1 评估维度拆解
在实现之前,需要先定义清楚“评估什么”。根据大量 Agent 生产环境的实践,评估维度通常可以拆解为以下几类。
任务相关性(Task Relevance),用于判断 Agent 的当前动作是否仍然围绕用户目标展开。Agent 经常会出现“跑偏”的情况,比如用户问的是数据统计,Agent 却开始介绍方法论,这就是相关性出了问题。
工具正确性(Tool Correctness),用于判断工具名称、参数、调用时机是否合法。例如一个天气查询 Agent 把城市参数写成了日期格式,这种错误需要在调用前拦截。
幻觉风险(Hallucination Risk),用于判断生成内容是否有事实性错误或逻辑矛盾。这个维度通常需要在模型输出之后,结合上下文和工具返回结果进行交叉验证。
进度有效性(Progress),用于判断任务是否在持续推进。如果连续多轮动作都一样,或者每次都在重复同一个失败的工具调用,说明 Agent 卡住了。
格式合法性(Format Validity),用于判断输出是否符合预期结构。比如要求输出 JSON,结果模型输出了 Markdown,这种问题虽然低级,但会直接破坏下游解析。
这五个维度不是全部,实际项目中可能还会增加安全合规、成本控制、隐私保护等维度。关键是要明白:维度越多,评估越准确,但成本越高。ParEvalLayer 的做法是,让不同决策点只启用其中一部分维度。
3.2 部分评估信号的设计
评估的原始结果,我们定义为“信号”(Signal)。一个信号应该包含足够的信息,让决策层能够理解评估结论,同时保留可观测性数据,方便后续排查问题。
信号的设计有几个要点。第一,严重级别要简单清晰,建议使用三个级别:PASS、WARN、FAIL。PASS 代表当前维度正常;WARN 代表有风险但可以继续,需要留意;FAIL 代表明确异常,需要触发干预。
第二,分数要连续化。布尔值在实际使用中过于武断,很多评估场景是模糊的,比如“这个回答有一点答非所问,但整体还能用”,用 0.7 分表达比直接给 True/False 更准确。分数范围建议固定在 0 到 1 之间。
第三,必须携带原因说明。分数只能告诉决策层“有问题”,但无法告诉运维人员“什么问题”。原因字段会用自然语言描述评估结论,方便后续人工审查和日志分析。
第四,保留元信息。模型评估可能有多次调用,元信息里可以存评估模型名、Token 消耗、评估耗时,这些数据对成本和性能分析非常关键。
3.3 决策点与决策规则
有了信号,还需要定义“在什么时机评估”以及“评估完做什么”。
我们把 Agent 执行流程中需要评估的时机称为决策点(Decision Point)。常见的决策点包括:
- 工具调用的前置校验点:Agent 准备调用工具之前
- 工具调用的后置校验点:工具返回结果之后
- 最终答案生成之前的输出校验点
- 每执行 N 步之后的进度检查点
每个决策点需要明确两件事:启用哪些评估维度,以及当信号组合成什么样时执行什么动作。
决策动作建议定义五个:CONTINUE(继续执行)、RETRY(重试当前动作)、SWITCH(切换到其他策略或子 Agent)、TERMINATE(终止任务并输出当前结果)、ASK_HUMAN(请求人工介入)。
决策规则的实现可以采用简单的阈值判断,也可以做加权打分。对于第一版实现,建议先用透明、可解释的规则,不要一上来就上复杂的机器学习排序模型,否则出了问题很难排查。
4. 完整实战案例:从零实现 ParEvalLayer
4.1 定义评估信号数据结构
先创建pareval/signal.py,定义评估维度、严重级别、信号和评估结果的数据结构。
# 文件路径:pareval/signal.py from dataclasses import dataclass, field from enum import Enum from typing import Any, Dict, List, Optional class EvalDimension(str, Enum): """评估维度""" TASK_RELEVANCE = "task_relevance" TOOL_CORRECTNESS = "tool_correctness" HALLUCINATION_RISK = "hallucination_risk" PROGRESS = "progress" FORMAT_VALIDITY = "format_validity" class EvalSeverity(str, Enum): """评估严重级别""" PASS = "pass" WARN = "warn" FAIL = "fail" @dataclass class EvalSignal: """单个维度的评估信号""" dimension: EvalDimension severity: EvalSeverity score: float # 0.0 ~ 1.0 reason: str meta: Dict[str, Any] = field(default_factory=dict) @dataclass class EvalResult: """一次部分评估的完整结果""" decision_point: str signals: List[EvalSignal] decision: str summary: str meta: Dict[str, Any] = field(default_factory=dict) def to_dict(self) -> Dict[str, Any]: return { "decision_point": self.decision_point, "decision": self.decision, "summary": self.summary, "signals": [ { "dimension": s.dimension.value, "severity": s.severity.value, "score": s.score, "reason": s.reason, } for s in self.signals ], }这里把信号设计成不可变的数据描述对象,方便在评估器、决策策略和日志模块之间传递。meta字段用于携带临时信息,比如评估模型名、耗时等。
4.2 实现评估器
接下来创建pareval/evaluator.py,定义评估器抽象基类和两个具体实现:进度评估器和工具调用合法性评估器。
# 文件路径:pareval/evaluator.py from abc import ABC, abstractmethod from typing import Any, Dict, List from .signal import EvalDimension, EvalSeverity, EvalSignal class BaseEvaluator(ABC): """评估器抽象基类""" def __init__(self, dimension: EvalDimension): self.dimension = dimension @abstractmethod def evaluate(self, trace: List[Dict[str, Any]]) -> EvalSignal: """对 Agent 轨迹执行评估,返回信号""" raise NotImplementedError class ProgressEvaluator(BaseEvaluator): """进度评估器:判断任务是否持续推进""" def __init__(self, max_stale_steps: int = 2): super().__init__(EvalDimension.PROGRESS) self.max_stale_steps = max_stale_steps def evaluate(self, trace: List[Dict[str, Any]]) -> EvalSignal: recent = trace[-self.max_stale_steps:] if trace else [] repeated_actions = 0 for i in range(1, len(recent)): if recent[i].get("action_name") == recent[i - 1].get("action_name"): repeated_actions += 1 if len(recent) >= self.max_stale_steps and repeated_actions >= self.max_stale_steps - 1: return EvalSignal( dimension=self.dimension, severity=EvalSeverity.FAIL, score=0.2, reason="连续多次执行相同动作,任务可能陷入循环", ) if repeated_actions >= 1: return EvalSignal( dimension=self.dimension, severity=EvalSeverity.WARN, score=0.6, reason="检测到重复动作,需要留意", ) return EvalSignal( dimension=self.dimension, severity=EvalSeverity.PASS, score=0.95, reason="任务持续有新动作产生", ) class ToolCorrectnessEvaluator(BaseEvaluator): """工具正确性评估器:检查工具调用是否合法""" def __init__(self): super().__init__(EvalDimension.TOOL_CORRECTNESS) def evaluate(self, trace: List[Dict[str, Any]]) -> EvalSignal: if not trace: return EvalSignal( dimension=self.dimension, severity=EvalSeverity.PASS, score=1.0, reason="没有工具调用记录", ) last_action = trace[-1] if last_action.get("type") != "tool_call": return EvalSignal( dimension=self.dimension, severity=EvalSeverity.PASS, score=1.0, reason="当前步骤不是工具调用,跳过工具校验", ) tool_name = last_action.get("tool_name", "") params = last_action.get("params", {}) errors = [] # 示例规则:name 不能为空,params 必须是字典 if not tool_name: errors.append("tool_name 为空") if not isinstance(params, dict): errors.append("params 必须是 JSON 对象") if errors: return EvalSignal( dimension=self.dimension, severity=EvalSeverity.FAIL, score=0.1, reason="; ".join(errors), meta={"tool_name": tool_name, "params": params}, ) return EvalSignal( dimension=self.dimension, severity=EvalSeverity.PASS, score=0.9, reason="工具调用结构合法", )这两个评估器都是基于规则的,没有调用大模型。这么做的好处是:基础校验成本为零,速度快,适合放在每个决策点都执行的场景。而像幻觉风险这类需要语义理解的维度,才会考虑使用 LLM 评估器。实际项目中,建议把基于规则的评估器作为第一道防线,LLM 评估器只用在关键节点。
4.3 实现决策策略
创建pareval/policy.py,定义决策动作枚举和决策策略类。
# 文件路径:pareval/policy.py from dataclasses import dataclass from typing import Callable, Dict, List from .signal import EvalResult, EvalSeverity, EvalSignal class AgentDecision: """Agent 决策动作""" CONTINUE = "continue" RETRY = "retry" SWITCH = "switch" TERMINATE = "terminate" ASK_HUMAN = "ask_human" @dataclass class DecisionRule: """决策规则:根据信号的严重级别组合决定动作""" on_any_fail: str = AgentDecision.RETRY on_any_warn: str = AgentDecision.CONTINUE on_all_pass: str = AgentDecision.CONTINUE max_warn_count: int = 2 class DecisionPolicy: """决策策略:把一组信号转换为一个决策动作""" def __init__(self, rules: Dict[str, DecisionRule]): self.rules = rules def decide( self, decision_point: str, signals: List[EvalSignal], ) -> EvalResult: rule = self.rules.get(decision_point, DecisionRule()) fail_count = sum(1 for s in signals if s.severity == EvalSeverity.FAIL) warn_count = sum(1 for s in signals if s.severity == EvalSeverity.WARN) if fail_count > 0: if fail_count >= 2: decision = AgentDecision.ASK_HUMAN else: decision = rule.on_any_fail elif warn_count > rule.max_warn_count: decision = AgentDecision.SWITCH elif warn_count > 0: decision = rule.on_any_warn else: decision = rule.on_all_pass summary = self._build_summary(signals, decision) return EvalResult( decision_point=decision_point, signals=signals, decision=decision, summary=summary, ) @staticmethod def _build_summary(signals: List[EvalSignal], decision: str) -> str: parts = [s.reason for s in signals if s.severity != EvalSeverity.PASS] if not parts: return f"所有检查通过,决策:{decision}" return f"发现 {len(parts)} 个关注点;决策:{decision};原因:{';'.join(parts)}"这个策略类采用透明的规则判断,而不是隐藏的加权公式。每个决策点的规则可以单独配置,例如前置校验点遇到工具错误就重试,而最终输出校验点遇到幻觉风险就必须转人工。
4.4 实现 ParEvalLayer 主类
创建pareval/layer.py,把评估器和决策策略组合起来。ParEvalLayer 的核心方法是evaluate_partial,它接收当前轨迹和决策点,只执行该决策点启用的评估维度。
# 文件路径:pareval/layer.py from typing import Callable, Dict, List, Optional from .evaluator import BaseEvaluator from .policy import DecisionPolicy from .signal import EvalResult class ParEvalLayer: """部分评估层:在指定决策点按需评估部分维度""" def __init__( self, evaluators: Dict[str, BaseEvaluator], policy: DecisionPolicy, logger: Optional[Callable[[EvalResult], None]] = None, ): self.evaluators = evaluators self.policy = policy self.logger = logger def evaluate_partial( self, trace: List[dict], decision_point: str, enabled_dims: List[str], ) -> EvalResult: """执行部分评估 Args: trace: Agent 执行轨迹 decision_point: 当前决策点名称 enabled_dims: 当前决策点启用的评估维度列表 Returns: EvalResult 评估结果 """ signals = [] for dim in enabled_dims: evaluator = self.evaluators.get(dim) if evaluator is None: continue signal = evaluator.evaluate(trace) signals.append(signal) result = self.policy.decide(decision_point, signals) if self.logger: self.logger(result) return result这个类的设计有几个优点。第一,评估器是插拔式的,新增维度不需要修改主类;第二,决策点通过enabled_dims控制评估范围,实现真正的“部分评估”;第三,通过注入 logger 回调,可以在不侵入业务代码的前提下实现日志和监控。
4.5 接入 Agent 主循环
创建agent/loop.py,演示 ParEvalLayer 如何嵌入 Agent 主循环。
# 文件路径:agent/loop.py from typing import Dict, List, Optional from pareval.layer import ParEvalLayer from pareval.policy import AgentDecision class DemoAgent: """简化版 Demo Agent,模拟工具调用""" def __init__(self): self.step_count = 0 def step(self, task: str, trace: List[dict]) -> dict: """执行一步动作,这里用固定逻辑模拟""" self.step_count += 1 if self.step_count == 1: return {"type": "tool_call", "tool_name": "query_data", "params": {"id": 1}} if self.step_count == 2: return {"type": "tool_call", "tool_name": "query_data", "params": {"id": 1}} return {"type": "final_answer", "content": "任务完成"} def run_agent_with_eval( task: str, agent: DemoAgent, eval_layer: ParEvalLayer, max_steps: int = 5, ) -> List[dict]: """带评估层的 Agent 主循环""" trace: List[dict] = [] final_decision = AgentDecision.CONTINUE for step_index in range(max_steps): action = agent.step(task, trace) trace.append(action) print(f"\n[Step {step_index + 1}] action={action.get('action_name', action.get('type'))}") # 根据动作类型选择决策点 if action.get("type") == "tool_call": decision_point = "before_tool_call" enabled_dims = ["tool_correctness", "progress"] else: decision_point = "before_final_answer" enabled_dims = ["progress"] result = eval_layer.evaluate_partial( trace=trace, decision_point=decision_point, enabled_dims=enabled_dims, ) print(f" 评估结果: decision={result.decision}, summary={result.summary}") final_decision = result.decision if result.decision == AgentDecision.TERMINATE: print(" 终止执行") break if result.decision == AgentDecision.RETRY: print(" 触发重试,回退一步") trace = trace[:-1] continue if result.decision == AgentDecision.ASK_HUMAN: print(" 转人工处理") break return trace4.6 运行与验证
最后创建examples/demo_agent.py,组装所有组件并运行。
# 文件路径:examples/demo_agent.py from agent.loop import DemoAgent, run_agent_with_eval from pareval.evaluator import ProgressEvaluator, ToolCorrectnessEvaluator from pareval.layer import ParEvalLayer from pareval.policy import DecisionPolicy, DecisionRule def build_default_rules(): return { "before_tool_call": DecisionRule( on_any_fail="retry", on_any_warn="continue", max_warn_count=1, ), "before_final_answer": DecisionRule( on_any_fail="ask_human", on_any_warn="continue", max_warn_count=2, ), } def main(): evaluators = { "progress": ProgressEvaluator(max_stale_steps=2), "tool_correctness": ToolCorrectnessEvaluator(), } eval_layer = ParEvalLayer( evaluators=evaluators, policy=DecisionPolicy(build_default_rules()), logger=lambda result: print(f" [log] {result.to_dict()}"), ) agent = DemoAgent() run_agent_with_eval( task="查询数据并输出结论", agent=agent, eval_layer=eval_layer, max_steps=5, ) if __name__ == "__main__": main()运行命令:
cd pareval_demo python examples/demo_agent.py预期输出大致如下:
[Step 1] action=tool_call [log] {'decision_point': 'before_tool_call', 'decision': 'continue', 'summary': '所有检查通过,决策:continue', 'signals': [...]} 评估结果: decision=continue, summary=所有检查通过,决策:continue [Step 2] action=tool_call [log] {'decision_point': 'before_tool_call', 'decision': 'retry', 'summary': '发现 1 个关注点;决策:retry;原因:检测到重复动作,需要留意', 'signals': [...]} 评估结果: decision=retry, summary=发现 1 个关注点;决策:retry;原因:检测到重复动作,需要留意 触发重试,回退一步由于 DemoAgent 的第二步和第一步动作相同,ProgressEvaluator 检测到重复动作,触发了重试,轨迹回退到第一步。这就验证了 ParEvalLayer 能在运行过程中及时干预 Agent 行为,而不是等到任务结束再复盘。
5. 常见问题与排查思路
ParEvalLayer 在落地过程中,会遇到一些典型的工程问题。这里整理了一份排查对照表。
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| 评估层频繁触发重试,Agent 无法推进 | 进度评估器对“重复动作”的判断过于敏感 | 调大max_stale_steps,或只在固定步数间隔做进度检查 |
| 关键错误没有被拦截 | 启用维度与决策点不匹配,漏掉了关键维度 | 检查enabled_dims配置,确认决策点覆盖所有风险点 |
| 评估本身消耗太多 Token | 所有决策点都启用了 LLM 评估器 | 将基础校验改为规则评估器,LLM 评估器只放在最终输出之前 |
| 决策结果不稳定,同样的输入时而是 retry 时而是 continue | LLM 评估器存在随机性,或 Prompt 指令不够明确 | 设置 temperature=0,给出更明确的评分标准和示例 |
| 评估日志不完整,事后无法定位问题 | logger 回调里只记录了 summary,没有记录原始信号 | 记录完整的to_dict()结果,包含每个维度的 score 和 reason |
| Agent 陷入重试死循环 | RETRY 决策没有次数上限 | 在run_agent_with_eval中增加重试计数,超过上限改为 ASK_HUMAN 或 TERMINATE |
在实际排查时,建议先看评估日志里的原始信号,确认是哪一个维度触发了决策,然后再定位是评估器逻辑问题还是 Agent 行为问题。不要一上来就调阈值,先看原因字段。
6. 最佳实践与工程建议
6.1 评估维度按决策点裁剪
这是 ParEvalLayer 最核心的工程原则。前置工具校验不需要评估最终答案的格式,输出前检查也不需要重新校验每个工具调用的合法性。把评估放在它最有效的决策点上,能同时降低成本和误报率。
建议每个决策点启用 1 到 3 个维度。超过 3 个维度时,不仅成本上升,不同维度之间的信号还可能相互干扰,导致决策策略复杂化,反而不利于维护。
6.2 先规则后模型,分层评估
评估器不一定都要用大模型。工具参数类型、JSON 格式、SQL 关键词黑名单、基础进度判断,这些规则就能搞定,而且零成本、低延迟、结果确定。
建议把评估器分成两层:L1 规则评估器,用于高频、确定性强的检查;L2 模型评估器,用于需要语义理解的场景,比如幻觉风险、最终答案质量。ParEvalLayer 的结构天然支持这种分层,因为评估器本身就是可替换的。
6.3 阈值校准要有离线依据
决策规则里的阈值和严重级别不能拍脑袋定。建议先跑一批离线样本,统计每个评估维度的分数分布,再根据误报率和漏报率来确定阈值。
例如,如果 ProgressEvaluator 对正常 Agent 也会给出 0.6 分,那把 0.6 设为 WARN 阈值就会造成大量误报。正确的做法是收集正常轨迹和异常轨迹的分数,找到两者的分界点,再留出安全余量。
6.4 防抖与冷却机制
Agent 在执行过程中,某些失败可能是暂时的。比如外部 API 超时导致的工具调用失败,立刻重试可能仍然失败。建议在决策层加入冷却机制:同一个决策点短时间内只允许触发一次 RETRY,后续失败直接升级为 SWITCH 或 ASK_HUMAN。
另外,连续多次 WARN 信号累积后触发 SWITCH,这个累积计数器也需要注意重置时机。建议以每个任务为单位重置,避免跨任务的状态污染。
6.5 可观测性与日志审计
评估层本身是一个需要被观测的系统。每次评估都应该记录:决策点名称、启用的维度、各维度分数、最终决策、评估耗时、Token 消耗、被评估的轨迹片段。
生产环境中,这些日志应该进入独立的评估指标看板。重点关注三个指标:评估覆盖率、决策动作分布、人工介入率。如果 ASK_HUMAN 的比例持续偏高,说明 Agent 自身能力不足,需要优化 Prompt 或增加工具;如果 CONTINUE 比例异常偏高,要警惕评估层形同虚设。
6.6 安全边界与最小权限
如果评估层用于控制工具调用权限,必须遵循最小权限原则。比如 SQL 执行场景,评估层判定“安全”只代表结构合法,不能替代数据库权限控制。评估层的拦截是纵深防御的一环,数据库连接本身仍然应该使用只读账号、限制执行超时、开启审计日志。
任何涉及删除、更新操作的场景,评估层都不应该成为唯一的防线。建议在工具层再做一次硬校验,比如危险操作需要二次确认参数,形成多层保护。
7. 总结与学习路线
本文围绕 ParEvalLayer 这个概念,完整拆解了 LLM Agent 评估层的设计思路和落地方法。核心要点可以总结为四条:评估维度要跟随决策点动态裁剪,评估器要按“先规则后模型”的原则分层实现,决策规则要保持透明可解释,评估结果必须完整记录用于观测和迭代。
文中给出的代码是一个最小可运行的骨架,你可以在此基础上扩展出更完整的评估体系。建议的下一步是:把五个评估维度都实现一遍,设计一个真实的小 Agent 任务,采集一批评估日志,用离线数据校准你的决策阈值。只有当你开始统计“评估层到底拦住了哪些错误,又误伤了多少正常请求”时,这套机制才能真正发挥价值。
如果你正在开发自己的 Agent 应用,不要等到线上出了问题才补评估层。即使从两个评估维度起步,也比完全没有评估要好。先把决策点梳理清楚,再逐步增加维度和评估深度,这条路比一次性追求完美的全量评估要稳妥得多。