Agent 可解释性:让模型在执行每一步时输出理由和置信度

📅 2026/7/12 15:42:32
Agent 可解释性:让模型在执行每一步时输出理由和置信度
Agent 可解释性让模型在执行每一步时输出理由和置信度一、深度引言与场景痛点大家好我是赵咕咕。一个周五下午产品经理跑来问我咱们的 Agent 为什么给用户推荐了 B 方案而不是 A 方案我翻了半天日志只找到一串工具调用记录——search(产品B价格)、compare(A vs B)、recommend(B)——但完全看不出它为什么做了这些选择。Agent 不像传统程序你没法打断点进去看if 条件是怎么判断的。它的每一步决策都在 LLM 的黑箱里完成而 LLM 的输出往往只有一个动作指令没有推理过程。这就是可解释性的问题。当 Agent 出错了我们需要知道它错在哪一步、为什么错。当 Agent 表现好我们也需要知道它做对了什么以便复制成功。今天聊聊怎么让 Agent 在执行每一步时输出理由和置信度。二、底层机制与原理深度剖析2.1 Agent 决策的透明性需求Agent 的可解释性需要覆盖两个层面步骤级解释每一步为什么选择这个工具为什么用这个参数全局级追溯从输入到输出的完整决策链路包括每一步的置信度变化。flowchart LR A[用户输入] -- B[步骤1: 意图识别] B -- B1[理由: 用户询问价格对比br/置信度: 0.92] B1 -- C[步骤2: 选择检索工具] C -- C1[理由: 需要查询产品B价格br/置信度: 0.88] C1 -- D[步骤3: 生成最终回答] D -- D1[理由: 综合A和B的价格分析br/置信度: 0.85] D1 -- E[输出 决策追溯]每一条理由和置信度都可以作为结构化数据存储下来。出问题时直接查询置信度低于 0.6 的步骤快速定位问题环节。2.2 置信度的计算方式LLM 本身不直接输出置信度。但有几种方式可以间接获取方法一让 LLM 自己打分。在 Prompt 中要求模型在输出动作的同时输出一个 0-1 的置信度分数。这是最简单的方式但模型的自我评估不一定准确。方法二Token 概率。LLM 在生成每个 token 时都有一个概率分布。可以取输出的关键 token如工具名的对数概率作为置信度。方法三多模型投票。用两个模型同时推理如果一致则置信度高否则低。sequenceDiagram participant U as 用户 participant A as Agent participant L as LLM participant E as 解释器 participant S as 存储 U-A: 提交问题 A-L: 发送 Prompt (要求输出理由置信度) L--A: {action: search, input: 价格, reason: ..., confidence: 0.9} A-E: 解析解释信息 E-S: 存储决策追溯 A-A: 执行工具调用 A-S: 存储工具结果 A-U: 返回答案 透明化说明三、生产级代码实现3.1 带可解释性的 Agent 步骤import asyncio import json import time import uuid from dataclasses import dataclass, field from typing import Any dataclass class AgentStep: Agent 单步执行记录包含可解释性字段。 step_id: str field(default_factorylambda: uuid.uuid4().hex[:8]) step_index: int 0 action: str action_input: str reason: str # 为什么要做这一步 confidence: float 0.0 # 模型对这一步的置信度 tool_output: str # 工具返回结果 latency_ms: float 0.0 error: str | None None timestamp: float field(default_factorytime.time) dataclass class AgentTrace: 完整的一次 Agent 执行追溯。 trace_id: str field(default_factorylambda: uuid.uuid4().hex[:12]) user_input: str steps: list[AgentStep] field(default_factorylist) final_answer: str total_latency_ms: float 0.0 overall_confidence: float 0.0 def get_low_confidence_steps( self, threshold: float 0.6 ) - list[AgentStep]: 找出所有置信度低于阈值的步骤。 return [s for s in self.steps if s.confidence threshold] def summary(self) - str: parts [fTrace {self.trace_id}: {len(self.steps)} 步] for s in self.steps: parts.append( f 步骤 {s.step_index}: {s.action}({s.action_input}) f置信度{s.confidence:.2f} 理由{s.reason[:60]} ) parts.append(f 最终置信度: {self.overall_confidence:.2f}) return \n.join(parts) class ExplainableAgent: 支持可解释性的 ReAct Agent。 EXPLAINABLE_PROMPT 你是一个带可解释性的任务助手。 根据对话历史决定下一步动作。你必须以严格 JSON 格式回复 {{ action: 工具名或 finish, action_input: 工具参数, reason: 为什么选择这个动作的简短理由, confidence: 0.0~1.0 之间的浮点数表示你对这个决定的信心 }} 可用工具: {tools} 对话历史: {history} 请回复: def __init__(self, llm, tools: dict, max_steps: int 10): self.llm llm self.tools tools self.max_steps max_steps async def run( self, user_input: str, session_id: str | None None ) - tuple[str, AgentTrace]: trace AgentTrace(user_inputuser_input) if session_id: trace.trace_id f{session_id}-{uuid.uuid4().hex[:6]} history: list[dict] [{role: user, content: user_input}] t_start time.monotonic() for step_idx in range(self.max_steps): step AgentStep(step_indexstep_idx 1) try: # Think step thought await self._think(history) step.action thought.get(action, unknown) step.action_input thought.get(action_input, ) step.reason thought.get(reason, 无理由) step.confidence float(thought.get(confidence, 0.5)) if step.action finish: trace.final_answer thought.get(action_input, ) trace.steps.append(step) break # Act step t_act time.monotonic() result await self._act(step.action, step.action_input) step.latency_ms (time.monotonic() - t_act) * 1000 step.tool_output result.output if result.error: step.error result.error history.append({ role: system, content: f工具 {step.action} 返回: {result.output} }) except Exception as e: step.error str(e) step.confidence 0.0 trace.steps.append(step) trace.total_latency_ms (time.monotonic() - t_start) * 1000 trace.overall_confidence self._calc_overall_confidence(trace.steps) return trace.final_answer, trace async def _think(self, history: list[dict]) - dict[str, Any]: history_text \n.join( f{h[role]}: {h[content]} for h in history ) prompt self.EXPLAINABLE_PROMPT.format( toolslist(self.tools.keys()), historyhistory_text, ) response await self.llm.generate(prompt) return self._parse_json(response) async def _act(self, action: str, action_input: str): from dataclasses import dataclass as dc dc class Result: output: str error: str | None None if action not in self.tools: return Result(errorf未知工具: {action}) try: output await self.tools[action](action_input) return Result(outputstr(output)) except Exception as e: return Result(errorstr(e)) def _parse_json(self, text: str) - dict[str, Any]: import re match re.search(r\{[\s\S]*\}, text) if not match: raise ValueError(f无法解析 JSON: {text[:200]}) return json.loads(match.group()) staticmethod def _calc_overall_confidence( steps: list[AgentStep] ) - float: if not steps: return 0.0 confidences [s.confidence for s in steps if s.confidence 0] return sum(confidences) / len(confidences) if confidences else 0.03.2 追溯数据的使用class TraceAnalyzer: 分析 Agent 执行追溯发现模式。 staticmethod async def find_weak_steps( traces: list[AgentTrace], threshold: float 0.6 ) - dict[str, list]: 找出所有低置信度步骤按动作类型聚合。 by_action: dict[str, list[AgentStep]] {} for trace in traces: for step in trace.steps: if step.confidence threshold: by_action.setdefault(step.action, []).append(step) return by_action staticmethod async def analyze_failures( traces: list[AgentTrace], ) - dict[str, Any]: 分析失败案例的模式。 failed [t for t in traces if not t.final_answer] patterns { total_failures: len(failed), avg_confidence: sum( t.overall_confidence for t in failed ) / max(len(failed), 1), common_first_action: {}, } for t in failed: if t.steps: first t.steps[0].action patterns[common_first_action][first] ( patterns[common_first_action].get(first, 0) 1 ) return patterns四、边界分析与架构权衡4.1 解释 vs 性能让 LLM 输出理由和置信度会增加输出 token 的数量约 20-50%从而增加延迟和成本。在延迟敏感的实时场景如语音助手这可能不可接受。折中方案生产环境只输出置信度不输出理由节省 token。Debug 模式输出完整理由只在需要排查时开启。异步存储追溯不阻塞主流程。4.2 LLM 的自我评估可信吗研究表明确实不完美。模型在简单任务上自我评估较准在复杂推理任务上容易过度自信。所以置信度更适合做相对比较这一步比那一步更不确定而非绝对值。如果需要更准确的置信度可以考虑 Token 概率方案——虽然实现更复杂但信号更客观。4.3 追溯数据的存储成本每条 Agent 执行记录包含多个步骤、每个步骤都有理由原文。如果 QPS 高存储量会很大。建议按比例采样如 10% 完整记录90% 只记录置信度。设置 TTL如 7 天自动清理。对理由文本做压缩或摘要。五、总结可解释性不是独立功能而是 Agent 系统的基础设施。没有它你的 Agent 就是一个黑箱——能干活但你不知道它为什么这么干。构建可解释性的三个层次步骤级追溯每一步输出动作 理由 置信度。全局决策链路从输入到输出的完整路径标注每一环的置信度。模式分析从大量追溯中发现系统性弱点和优化方向。我目前的 Agent 项目都强制要求输出可解释性字段。这多出来的几十个 token 成本换来的是产品经理不再追问我为什么出了 bug 我能在 5 分钟内定位到具体步骤而团队新人也能通过读追溯日志快速理解 Agent 的行为逻辑。Agent 的短期目标是完成任务长期目标是值得信任。而可解释性就是信任的基石。0712 第2周收官。下周见