测试视角做AI Agent可观测:权限、日志、证据全补齐

聊《做过测试的人学大模型,哪些经验可以直接迁移?》之前,先说一句实在的:别急着背概念,先看它在真实项目里到底解决什么问题。

摘要

目录

  • 真实案例:我带的一个AI测试项目
  • 权限:被很多人忽略的"第一道墙"
  • 日志与可观测:Agent决策链追踪
  • 失败原因:三类错误的区分方式
  • 质量评估:从"能不能跑"到"跑得好不好"
  • 简历表达建议
  • 总结

真实案例:我带的一个AI测试项目

文章插图 1

去年我接手了一个电商Agent的项目,做的是智能客服问答。系统用RAG架构,接入公司内部的订单数据库和产品知识库。产品侧要求的是"用户问什么答什么",但作为测试,我拿到需求后第一时间不是想怎么测通过率,而是先问了一句话:"它的权限边界在哪里?"

这个项目当时踩过的坑,我觉得很有代表性,也直接对应了我后来写进简历里的几个核心模块。

先说整体背景:这是一个基于LangChain的Agent,底层用的是OpenAI的API,知识库是通过Milvus向量数据库管理的。测试目标包括:功能正确性、权限合规性、可观测性、稳定性。其中前两个,传统测试同学容易上手;后两个,才是这次转型真正拉开差距的地方。

我做的第一件事,是搭了一个简化的本地测试环境——用一个开源模型加一个小型向量库,模拟真实RAG Agent的核心链路:用户输入 → 意图路由 → 工具调用 → 结果生成。这个环境的好处是,可以在权限配置上灵活调整,便于做各种边界测试。

权限:被很多人忽略的"第一道墙"

文章插图 2

面试过程中我发现一个问题:很多候选人做的项目,能跑通Demo就算完事,但真到企业级应用,权限往往是最先暴露问题的地方。

我的项目中,有一个很典型的case:知识库的某些数据是有访问权限控制的——比如订单金额、用户联系方式这类敏感字段,只有特定角色才能查询。但Agent在做检索时,没有做权限过滤,直接把所有数据都返回给了用户。

这属于典型的"数据平权"问题。解决思路是把权限检查放在检索层之前,而不是靠后期的人工审核。具体来说,就是让Agent在执行查询前,先获取当前用户的角色权限信息,然后根据权限白名单过滤知识库的返回结果。

代码层面,我是在ChatOpenAI之前加了一个中间件,专门做权限校验:

from typing import List, Dict

class PermissionFilter:
    def __init__(self, user_role: str):
        self.user_role = user_role
        self.access_levels = self._load_access_config()

    def _load_access_config(self) -> Dict:
        # 从配置文件加载角色权限表
        return {
            "customer_service": ["public_info"],
            "order_manager": ["order_info", "public_info"],
            "admin": ["all"]
        }

    def filter_documents(
        self,
        docs: List[Dict],
        user_role: str
    ) -> List[Dict]:
        allowed = self.access_levels.get(user_role, ["public_info"])
        if "all" in allowed:
            return docs

        filtered = []
        for doc in docs:
            if doc.get("access_level") in allowed:
                filtered.append(doc)
        return filtered

# 使用示例
filter = PermissionFilter(user_role="customer_service")
filtered_docs = filter.filter_documents(raw_docs, "customer_service")

这个代码的核心逻辑是先过滤再给模型,而不是让模型自行判断。输出是所有文档中符合当前角色权限的部分,异常处理方面,如果用户角色不在配置表里,默认只返回public_info级别的数据。

我在这个模块上花的时间不少,主要是调试不同角色的权限交叉访问问题。有一次发现某个manager角色的权限配置少了一个level,导致订单查询返回了空结果,排查了很久才发现是配置表的key拼错了。

日志与可观测:Agent决策链追踪

这是测试转AI最核心需要补的一个能力。传统测试只需要看接口返回对不对,但Agent的决策过程是多步的,每一步都可能出问题。

我做了一个工具调用链的日志追踪方案,核心思路是:每次工具调用都要记录输入参数、输出结果、耗时,并关联到同一个request_id。这样排查问题时,可以从最终回答反推整个决策过程。

排查过程是这样的:有一次发现Agent对同一个问题,有时候回答准确,有时候回答错误。通过日志追踪发现,问题出在tool选择上——模型在某些情况下选择了错误的工具,而且错误选择后没有重试机制。这个case让我深刻体会到,Agent的"随机性"在测试阶段就必须被充分覆盖。

具体实现上,我用了一个自定义的Callback类,继承LangChain的BaseCallbackHandler:

import time
import logging
from langchain.callbacks.base import BaseCallbackHandler
from typing import Any, Dict, List

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class TraceCallback(BaseCallbackHandler):
    def __init__(self, request_id: str):
        self.request_id = request_id
        self.tool_calls = []

    def on_tool_start(
        self,
        serialized: Dict,
        input_str: str,
        **kwargs
    ) -> Any:
        tool_name = serialized.get("name", "unknown")
        self.tool_calls.append({
            "tool": tool_name,
            "input": input_str,
            "start_time": time.time(),
            "request_id": self.request_id
        })
        logger.info(
            f"[{self.request_id}] Tool start: {tool_name}, "
            f"input: {input_str[:100]}"
        )

    def on_tool_end(self, output: str, **kwargs) -> None:
        last_call = self.tool_calls[-1]
        last_call["output"] = output
        last_call["end_time"] = time.time()
        last_call["duration"] = (
            last_call["end_time"] - last_call["start_time"]
        )
        logger.info(
            f"[{self.request_id}] Tool end: {last_call['tool']}, "
            f"duration: {last_call['duration']:.2f}s"
        )

    def on_llm_end(self, response: Any, **kwargs) -> None:
        logger.info(
            f"[{self.request_id}] LLM response received"
        )

代码解释:输入是requestid,用于关联同一次请求的所有日志;核心逻辑是在工具调用开始和结束时记录时间戳和参数;输出是结构化的日志信息,方便后续查询和回溯;异常处理方面,如果工具调用失败,会在ontool_end里记录错误信息。

CSDN资料领取方式

失败原因:三类错误的区分方式

在做这个项目期间,我遇到很多看似奇怪的问题,后来总结成三类:业务错误、配置错误、环境错误。

业务错误是最难定位的。比如模型返回了错误的工具名,这不是代码bug,而是prompt设计的问题。有一次我在prompt里写"根据用户问题选择合适的工具",结果模型在某些边界case下会误判。排查思路是:先把模型输出的raw response打印出来,看它到底看到了什么、想了什么,再针对性地调整prompt。

配置错误相对好排查。有一次向量库的embedding模型和检索用的模型不一致,导致检索效果很差。排查动作是对比两边的配置项,发现embedding模型版本号不一致,统一后问题解决。这类错误的特征是:配置项之间有不一致,通过diff配置表可以快速定位。

环境错误一般出现在部署阶段。比如某个依赖包的版本在本地能跑但在服务器上不行。这类问题的排查思路是:先在开发环境复现,再看线上环境的docker镜像和依赖配置,找出差异点。

区分这三类错误的方法很简单:业务错误改prompt,配置错误改配置,环境错误改部署。但真正难的是在问题发生时,快速判断它属于哪一类。我后来的习惯是,遇到问题先问自己:是模型"想错了",还是配置"设错了",还是环境"装错了"。

质量评估:从"能不能跑"到"跑得好不好"

这是测试转AI最容易忽视的一环。Demo能跑通,只能证明功能可用,不能证明质量达标。

我在这个项目里建立了一套轻量级的质量评估指标,包括:回答准确率、权限覆盖率、工具调用成功率、平均响应时间、错误率。这些指标不是拍脑袋定的,而是根据业务场景和业务方的真实需求来的。

比如权限覆盖率,我的目标是99%以上,因为任何一条越权返回都可能是严重的合规问题。工具调用成功率是95%,因为这个指标直接关系用户体验。

评估方法是用一批标准测试集,每轮迭代都跑一遍,看指标变化趋势。这样做的好处是可以量化改进效果,也能在出问题时有据可查。

简历表达建议

如果你要做类似的项目,简历上不要只写"做了RAG Agent",要把权限、日志、评估这些维度写出来。比如:

  • "设计并实现了基于角色的权限过滤中间件,覆盖3类用户角色,权限覆盖率提升至99%"
  • "构建工具调用链追踪系统,实现单请求全链路日志记录,平均问题定位时间从2小时缩短至15分钟"
  • "建立Agent质量评估体系,定义5项核心指标,支持A/B测试和版本对比"

这些表达的关键是:有场景、有做法、有结果。面试官问起来的时候,能讲清楚为什么这么做、怎么做、做得怎么样。

适用边界

该方案适合可观测的小规模实践;当规模、实时性或合规要求变化时,需要重新评估限制和兜底。

总结

测试转AI测试,最大的门槛不是技术栈,而是思维方式的转换。传统测试关注功能是否正确,AI测试还要关注决策链是否可观测、权限边界是否清晰、质量指标是否可量化。

这个转型过程中,我走了不少弯路,但也积累了一些可以复用的经验。希望这篇文章能给你一些参考,少走一些我已经踩过的坑。

资料展示

下面是我整理的AI大模型学习资料和工具包预览,适合收藏后按主题逐步学习。

AI大模型资料展示 1

AI大模型资料展示 2

AI大模型资料展示 3

需要这份AI大模型资料清单的话,在评论区回复「清单」即可;我会根据大家的问题继续补充对应的实战内容。

CSDN官方大礼包

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值