agent性能优化

先把问题摸透:4个核心瓶颈

优化前我先把整个流程拆开来测,发现问题就出在这四点:

  1. 向量检索(RAG)每次都重新查,光这一步就耗3-5秒,还重复执行,纯纯浪费资源;
  2. 外部数据文件每次调用都重新解析,文件不大但解析一次也要秒级,完全没必要;
  3. 工具调用链太碎,拿个用户ID和月份都要分两次调用,多一次调用就多一次网络和序列化开销;
  4. 依赖外部API,网络一波动就超时失败,测试时错误率都到7%了。

我的目标很明确:先把重复操作干掉,再简化流程,最后把稳定性提上来,不求一步到位,但要先解决高收益的问题。

第一步:给RAG检索加缓存,从3秒到0.1秒

向量检索是耗时大头,而且同一个查询会反复出现,最适合加缓存。我没搞复杂的分布式缓存,先从内存缓存入手,简单直接见效快。

核心思路就是:第一次查完把结果存起来,30分钟内再查同一个问题,直接拿缓存里的,还得定期清过期的,避免内存爆了。

python 复制代码
# 先初始化缓存和过期时间
rag_cache = {}
CACHE_EXPIRY_TIME = 30 * 60  # 30分钟过期

def get_cache_key(query: str) -> str:
    # 转小写去空格,避免大小写、空格导致缓存失效
    return f"rag_{query.lower().strip()}"

@tool(description="从向量存储中检索参考资料")
def rag_summarize(query: str) -> str:
    import time
    cache_key = get_cache_key(query)
    
    # 缓存命中直接返回
    if cache_key in rag_cache and time.time() - rag_cache[cache_key]['timestamp'] < CACHE_EXPIRY_TIME:
        logger.info(f"[缓存命中] 直接用{query}的检索结果")
        return rag_cache[cache_key]['result']
    
    # 没命中就执行检索,记个耗时
    start_time = time.time()
    result = rag.rag_summarize(query)
    logger.info(f"[检索完成] 这次查了{time.time()-start_time:.2f}秒")
    
    # 把结果存进缓存
    rag_cache[cache_key] = {
        'result': result,
        'timestamp': time.time()
    }
    # 顺手清过期缓存
    _clean_expired_cache()
    return result

def _clean_expired_cache():
    """定期清过期缓存,避免内存泄漏"""
    import time
    expired_keys = [k for k, v in rag_cache.items() if time.time() - v['timestamp'] >= CACHE_EXPIRY_TIME]
    for key in expired_keys:
        del rag_cache[key]

这么改完,只要是30分钟内查过的问题,响应时间直接从3-5秒降到0.1秒以内,重复检索的负载也少了一大半。我还加了日志,能看到缓存命中率,方便后续调整过期时间。

第二步:外部数据只加载一次,秒级变毫秒级

之前每次拿用户月度数据,都会重新读文件、解析,哪怕数据根本没变化。我就加了个全局标记,第一次调用时加载完存内存,之后直接用:

python 复制代码
_external_data_loaded = False  # 标记数据是否已加载

def generate_external_data():
    global _external_data_loaded
    if not _external_data_loaded:
        start_time = time.time()
        external_data_path = get_abs_path(agent_conf["external_data_path"])
        with open(external_data_path, "r", encoding="utf-8") as f:
            # 解析数据的逻辑...
        _external_data_loaded = True
        logger.info(f"外部数据加载完,耗时{time.time()-start_time:.2f}秒")

@tool(description="获取用户月度使用记录")
def fetch_external_data(user_id: str, month: str) -> str:
    generate_external_data()  # 确保数据已加载
    try:
        return external_data[user_id][month]
    except KeyError:
        logger.warning(f"没找到{user_id} {month}的记录")
        return ""

就加了一个布尔标记,数据加载从每次秒级变成只有第一次加载耗几秒,后续都是毫秒级访问,这个改动成本最低,收益却最明显。

第三步:合并工具调用,少走弯路

之前拿用户ID和月份要调两个工具,我直接合了一个get_user_info,一次返回JSON格式的用户ID+月份:

python 复制代码
@tool(description="获取用户ID和当前月份")
def get_user_info() -> str:
    import json
    user_info = {
        "user_id": random.choice(user_ids),
        "month": random.choice(month_arr)
    }
    return json.dumps(user_info)

工具调用链从"拿ID→拿月份→拿数据→生成报告"简化成"拿用户信息→拿数据→生成报告",调用次数少了30%左右,少一次调用就少一次网络往返和数据处理,积少成多,稳定性也跟着提了。

最后看看效果:没花大成本,却解决了大问题

优化完测了几组用例,虽然平均耗时从42.3秒降到38.92秒(个别用例因为网络波动略涨),但核心环节的提升是实打实的:

  • 向量检索缓存命中时<0.1秒,比之前快98%;
  • 外部数据加载从秒级变毫秒级,快99%;
  • 工具调用次数少了30%,网络错误率从7.14%降到0;
  • 测试通过率从92.86%涨到100%。
相关推荐
无心水9 小时前
【OpenClaw:应用与协同】23、OpenClaw生产环境安全指南——Token管理/沙箱隔离/权限最小化
大数据·人工智能·安全·ai·性能优化·openclaw
一个天蝎座 白勺 程序猿11 小时前
KingbaseES融合数据库:一库多能,企业数据管理新思路
数据库·性能优化·kingbasees·金仓数据库
一起搞IT吧15 小时前
Android功耗系列专题理论之十四:Sensor功耗问题分析方法
android·c++·智能手机·性能优化
学编程的小程18 小时前
当JOIN条件"下潜"到子查询深处:一场关于查询优化器代价决策的深度实践
性能优化
Gauss松鼠会20 小时前
openGauss数据库源码解析系列文章——存储引擎源码解析(一)
数据库·oracle·性能优化·database·opengauss
所谓伊人,在水一方33320 小时前
【Python数据可视化精通】第8讲 | 大规模数据可视化与性能优化
开发语言·python·信息可视化·性能优化·数据分析
weixin1997010801620 小时前
南网商城商品详情页前端性能优化实战
java·前端·性能优化
一起搞IT吧20 小时前
Android功耗系列专题理论之十五:相机camera功耗问题分析方法
android·c++·数码相机·智能手机·性能优化
weixin1997010801620 小时前
网易考拉商品详情页前端性能优化实战
java·前端·python·性能优化
笨手笨脚の21 小时前
Java 性能优化
java·jvm·数据库·性能优化·分布式锁·分布式事务·并发容器