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%。
相关推荐
JiaHao汤1 天前
MySQL SQL 性能优化实战指南
sql·mysql·性能优化
一只叫煤球的猫2 天前
ThreadForge v1.1.0 发布:让 Java 并发更接近 Go 的开发体验
java·后端·性能优化
PineappleCoder2 天前
告别“幻影坦克”:手把手教你丝滑规避布局抖动,让页面渲染快如闪电!
前端·性能优化
xcLeigh2 天前
IoTDB 性能优化双杀:查询分析与负载均衡实战指南
性能优化·负载均衡·时序数据库·iotdb
山峰哥2 天前
数据库工程中的SQL调优实践:从索引策略到查询优化的深度探索
服务器·数据库·sql·性能优化·编辑器
阿林来了2 天前
Flutter三方库适配OpenHarmony【flutter_speech】— 性能优化实践
flutter·性能优化
玩具猴_wjh3 天前
高并发系统性能优化
性能优化
码云数智-大飞3 天前
前端性能优化全链路实战:从加载速度到渲染效率的极致提速方案
前端·性能优化
叫我一声阿雷吧3 天前
JS实现无限滚动加载列表|适配多端+性能优化【附完整可复用源码】
开发语言·javascript·性能优化