欢迎光临
我们一直在努力

如何确保Agent在复杂任务链中的每一步行动都可审计?

在复杂的AI Agent应用中,如多步骤决策、工具调用和长链推理,一个核心挑战是缺乏透明度(即“黑箱”问题)。当Agent的最终输出不符合预期时,我们很难知道它在哪一步做出了错误的决策、调用了错误的工具,或是接收到了不正确的中间输入。为了解决这个问题,我们需要在基础设施层面建立强大的可审计性(Auditability)

本文将聚焦于如何通过结构化日志(Structured Logging)事件溯源(Event Sourcing)的理念,确保Agent在执行复杂任务链的每一步行动都清晰、可追踪、可回溯。

一、为什么Agent需要严格的审计?

  1. 调试与可解释性: 审计日志是理解Agent内部决策逻辑的唯一途径。它们帮助开发者定位失败的步骤、评估工具调用的效果。
  2. 合规性与治理(Governance): 在金融、医疗等受监管行业,Agent必须证明其决策过程符合特定规范。完整的审计路径是满足合规要求的基石。
  3. 性能优化: 通过分析不同步骤的耗时,可以识别任务链中的瓶颈,从而针对性地优化LLM调用或外部工具接口。

二、核心技术方案:审计日志的结构化设计

传统的纯文本日志难以查询和分析。为了实现高效审计,我们必须使用JSON或其他结构化格式,并确保每个日志事件(Audit Event)包含以下关键字段:

字段名 描述 示例值
timestamp 事件发生时间 2024-05-30T10:00:00.123Z
trace_id 贯穿整个任务链的唯一ID a1b2c3d4e5f6
step_id 当前步骤的唯一ID step_003
agent_name 执行动作的Agent或模块名称 PlanningAgent
action_type 动作类型(Plan/ToolCall/LLMInference/FinalAnswer) ToolCall
tool_name 如果是工具调用,工具的名称 FileSearchTool
inputs 当前步骤接收到的输入(或Prompt) {“query”: “最新的市场报告”}
outputs 当前步骤产生的输出或结果 {“status”: “success”, “result_len”: 1024}
status 步骤执行状态 SUCCESS / FAILURE

三、实操示例:构建可审计的Agent执行器

我们将使用Python的logging模块,并集成一个自定义的JSON Formatter来确保输出的结构化。

步骤 1: 定义结构化日志格式器

为了将Python的logging输出为标准的JSON格式,我们定义一个JsonAuditFormatter

import logging
import json
import time
import uuid

class JsonAuditFormatter(logging.Formatter):
    def format(self, record):
        # 基础结构
        log_record = {
            "timestamp": time.strftime("%Y-%m-%dT%H:%M:%S.000Z", time.gmtime(record.created)),
            "level": record.levelname,
            "message": record.getMessage(),
            "service": "AgentExecutor",
            # 附加的审计数据(来自extra参数)
        }

        # 合并通过 extra={...} 传递的自定义字段
        if hasattr(record, 'audit_data'):
            log_record.update(record.audit_data)

        return json.dumps(log_record, ensure_ascii=False)

# 配置Logger
def setup_audit_logger(name='AgentAuditor'):
    logger = logging.getLogger(name)
    logger.setLevel(logging.INFO)

    # 避免重复添加Handler
    if not logger.handlers:
        handler = logging.StreamHandler()
        handler.setFormatter(JsonAuditFormatter())
        logger.addHandler(handler)

    return logger

AUDIT_LOGGER = setup_audit_logger()

步骤 2: 实现可审计的Agent步骤

我们定义一个简化的Agent类,它在执行任何核心逻辑(如规划或工具调用)之前和之后,都会调用审计日志。

class AuditableAgent:
    def __init__(self, name, trace_id):
        self.name = name
        self.trace_id = trace_id

    def execute_planning(self, initial_query):
        step_id = str(uuid.uuid4())[:8]

        # --- 审计点 A: 步骤开始 --- 
        AUDIT_LOGGER.info(
            "Planning step started.",
            extra={
                'audit_data': {
                    'trace_id': self.trace_id,
                    'step_id': step_id,
                    'agent_name': self.name,
                    'action_type': 'Planning',
                    'inputs': {'query': initial_query},
                    'status': 'RUNNING'
                }
            }
        )

        # 模拟LLM推理和规划逻辑
        time.sleep(0.1)
        plan_result = f"Plan generated for query: {initial_query}. Requires search tool."

        # --- 审计点 B: 步骤结束 --- 
        AUDIT_LOGGER.info(
            "Planning step finished successfully.",
            extra={
                'audit_data': {
                    'trace_id': self.trace_id,
                    'step_id': step_id,
                    'agent_name': self.name,
                    'action_type': 'Planning',
                    'outputs': {'plan': plan_result},
                    'status': 'SUCCESS'
                }
            }
        )
        return plan_result

    def execute_tool_call(self, plan_output, tool_name='SearchTool'):
        step_id = str(uuid.uuid4())[:8]

        # --- 审计点 C: 工具调用开始 --- 
        AUDIT_LOGGER.info(
            "Tool call initiated.",
            extra={
                'audit_data': {
                    'trace_id': self.trace_id,
                    'step_id': step_id,
                    'agent_name': self.name,
                    'action_type': 'ToolCall',
                    'tool_name': tool_name,
                    'inputs': {'plan': plan_output},
                    'status': 'RUNNING'
                }
            }
        )

        # 模拟工具执行
        time.sleep(0.2)
        tool_result = "Found 5 relevant documents about the market."

        # --- 审计点 D: 工具调用结束 --- 
        AUDIT_LOGGER.info(
            "Tool call completed.",
            extra={
                'audit_data': {
                    'trace_id': self.trace_id,
                    'step_id': step_id,
                    'agent_name': self.name,
                    'action_type': 'ToolCall',
                    'tool_name': tool_name,
                    'outputs': {'result': tool_result},
                    'status': 'SUCCESS'
                }
            }
        )
        return tool_result

# 任务执行
def run_task(query):
    trace_id = str(uuid.uuid4())
    print(f"\n--- Starting Task Chain (Trace ID: {trace_id}) ---")
    agent = AuditableAgent("FinancialAgent", trace_id)

    plan = agent.execute_planning(query)
    result = agent.execute_tool_call(plan)

    print(f"\n--- Task Completed. Final Output: {result} ---")

# 运行示例
run_task("分析最新的全球经济走势")

步骤 3: 分析日志输出

运行上述代码后,控制台将输出一系列JSON格式的审计事件。这些事件包含了完整的上下文信息。例如,一个工具调用成功的记录可能如下所示(为清晰起见,此处已格式化):

{
  "timestamp": "2024-05-30T10:05:30.456Z",
  "level": "INFO",
  "message": "Tool call completed.",
  "service": "AgentExecutor",
  "trace_id": "3a1f2b4c-9d0e-4f7a-8b3c-5e6d7a8f9b0c",
  "step_id": "b8e2a3f9",
  "agent_name": "FinancialAgent",
  "action_type": "ToolCall",
  "tool_name": "SearchTool",
  "outputs": {
    "result": "Found 5 relevant documents about the market."
  },
  "status": "SUCCESS"
}

通过数据库或日志聚合系统(如Elasticsearch, Loki)存储这些日志,我们就可以:

  1. 根据trace_id重构整个任务链: 轻松查看Agent从开始到结束的所有中间决策。
  2. 根据status筛选失败步骤: 快速定位导致任务中断或结果异常的具体环节。
  3. 分析inputsoutputs 精确了解信息在Agent各步骤之间的流转和转换。

四、进阶:集成OpenTelemetry追踪

对于更复杂的微服务架构或需要跨服务追踪的情况,可以考虑将上述结构化审计事件映射为OpenTelemetry (OTel) 的 Span 事件。每个Agent步骤(如Planning, ToolCall)可以被视为一个Span。OTel提供了标准化的协议和采集器,使其能够无缝接入到 Jaeger 或 Zipkin 等分布式追踪系统,实现更强大的可视化和性能分析能力。

【本站文章皆为原创,未经允许不得转载】:汤不热吧 » 如何确保Agent在复杂任务链中的每一步行动都可审计?
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址