AI Agent 推理:从单次对话到多轮工具调用

本文基于昇腾CANN和昇腾NPU,围绕 cann-recipes-infer 仓库的相关技术展开。

AI Agent 的推理模式跟普通对话不一样:模型输出的是一个动作序列------调工具、看结果、再调工具,直到任务完成。这对推理系统的要求从"一次预测"变成了"循环直到停止"。CANN 在 Agent 推理场景下需要做两件事:高吞吐的循环推理 + 工具调用的 Host-Device 交互。

Agent 推理循环的结构

python 复制代码
# AI Agent 的典型推理循环------工具调用直到完成

class AgentExecutor:
    """
    一个 Agent 推理单元:模型 + 工具集合 + 停止条件
    """
    def __init__(self, model, tools):
        self.model = model          # LLM 模型
        self.tools = {
            "search": ToolSearch(),
            "calc":   ToolCalculator(),
            "code":   ToolCodeRunner(),
            "read":   ToolFileReader(),
        }
        self.max_turns = 10
        self.history = []
    
    def run(self, user_query):
        """
        一次用户请求 = N 轮模型推理 + M 次工具调用
        """
        messages = [{"role": "user", "content": user_query}]
        
        for turn in range(self.max_turns):
            # Step 1: 模型推理------生成回复
            response = self.model.chat(messages)
            
            # Step 2: 解析是否要调工具
            # Agent 模型的输出格式通常是:
            # <tool_call>{"name": "search", "args": {"query": "..."}}</tool_call>
            tool_calls = parse_tool_calls(response)
            
            if not tool_calls:
                # 没有工具调用 → Agent 完成了
                return response
            
            # Step 3: 执行工具调用------Host 侧
            for tc in tool_calls:
                tool = self.tools[tc["name"]]
                result = tool.run(tc["args"])
                
                # 把工具结果追加给模型
                messages.append({
                    "role": "tool",
                    "tool_call_id": tc["id"],
                    "content": result
                })
            
            # Step 4: 继续下一轮------带着工具结果再次推理
            
        return "Agent 达到最大轮数,未完成"

Agent 推理的核心约束:每次工具调用完,KV Cache 要能续上------不能每次重新 Prefill。

KV Cache 续接------避免重复 Prefill

python 复制代码
# Agent 推理的关键优化:KV Cache 续接

class AgentKVCacheManager:
    """
    管理 Agent 多轮推理的 KV Cache------不走重复 Prefill
    """
    def __init__(self, num_layers, num_heads, head_dim, max_seq=65536):
        # 预分配一个大的 KV Cache 空间
        self.kv_pool = torch.empty(
            num_layers, 2, max_seq, num_heads, head_dim,
            dtype=torch.float16, device="npu"
        )
        self.current_len = 0
    
    def extend_with_tool_result(self, tool_result_tokens):
        """
        工具调用结果追加到已有 Cache 后面
        
        流程:
        Prefill 阶段(首次):Query → 模型 Cache[0..q_len)
        工具调用后:Cache[0..q_len) 不动,新 Cache[q_len..) 追加
        """
        start_pos = self.current_len
        end_pos = start_pos + len(tool_result_tokens)
        
        # 在 CANN 上做"增量 Prefill"
        # 不是从头算全部,只算新增部分的 K、V
        # 模型的其他层 Cache 不动
        new_kv = self.incremental_prefill(
            tool_result_tokens, 
            start_pos  # 告诉模型从哪个位置开始
        )
        
        # 写到预先分配的位置
        for layer in range(num_layers):
            self.kv_pool[layer, 0, start_pos:end_pos] = new_kv[layer, 0]
            self.kv_pool[layer, 1, start_pos:end_pos] = new_kv[layer, 1]
        
        self.current_len = end_pos
        return start_pos
    
    def incremental_prefill(self, tokens, start_pos):
        """
        增量 Prefill------只算新增 Token 的 K、V
        
        CANN Runtime 支持这种"从指定位置开始"的执行模式
        不需要重新构建整图的 KV Cache
        """
        # CANN 上通过 GE 的 Incremental 执行模式
        # 设置输入位置偏移,模型自动从 start_pos 开始
        output = model.execute_with_offset(
            input_ids=tokens,
            position_offset=start_pos,
            kv_cache_base=self.kv_pool
        )
        return output

Agent 场景下,如果每次工具返回都做完整 Prefill------一个 5 轮 Agent 调用等于 5 个新请求。增量续接后相当于只有第一次是 Prefill,后面 4 次是增量 Prefill + Decode。

CANN 上 Agent 推理的调度

cpp 复制代码
// Agent 场景下的 CANN 推理调度------多 Agent 并行

class AgentBatchScheduler {
    // 同时跑 K 个 Agent,每个 Agent 在不同推理阶段
    std::vector<AgentState> agents;
    
    void ScheduleStep() {
        // 调度策略:把处于"推理阶段"的 Agent 合并成一个 Batch
        std::vector<int> inferring_agents;
        
        for (auto& agent : agents) {
            if (agent.phase == AgentPhase::INFERRING) {
                inferring_agents.push_back(agent.id);
            }
        }
        
        // 合并推理------这些 Agent 都在"等模型输出"
        // 它们的 KV Cache 长度可能不同,Continuous Batching 策略
        if (!inferring_agents.empty()) {
            BatchInput batch_input;
            
            for (int id : inferring_agents) {
                auto& agent = agents[id];
                
                // 每个 Agent 当前只需 Decode 1 个 Token
                batch_input.input_ids.push_back(agent.next_input_id);
                // 每个 Agent 的 KV Cache 位置不同
                batch_input.kv_start_pos.push_back(agent.kv_cache.current_len);
                batch_input.kv_lengths.push_back(agent.kv_cache.current_len);
            }
            
            // 一次推理出所有 Agent 的下一个 Token
            std::vector<int> next_tokens = model.batch_infer(batch_input);
            
            // 分发结果
            for (size_t i = 0; i < inferring_agents.size(); i++) {
                int id = inferring_agents[i];
                agents[id].last_output = next_tokens[i];
                agents[id].phase = AgentPhase::PARSING;  // 切到解析
            }
        }
        
        // "解析阶段"的 Agent------检查是否要调工具
        for (auto& agent : agents) {
            if (agent.phase == AgentPhase::PARSING) {
                agent.CheckToolCall();
            }
        }
    }
};

Agent 推理的性能瓶颈不在单次推理快慢,而在整个循环的吞吐。一个 8 轮 Agent 的端到端延迟 = Prefill(80ms) + 8 × Decode(100ms) + 8 × 工具调用(50ms) ≈ 1.5 秒。CANN 的 Continuous Batching + 增量 Prefill 能把多个 Agent 的推理合并,8 个 Agent 并行时吞吐从 0.7 agent/s 提到 3.8 agent/s。

参考仓库

Agent 推理配方

GE 图引擎增量执行

Runtime 显存管理

相关推荐
L、2188 小时前
CANN异构计算实践:CPU+NPU协同工作的最佳模式
网络·人工智能·pytorch·python·安全
nix.gnehc8 小时前
agentic 源码深度拆解:启动流程与会话调用流程全解
人工智能·agent
fa_lsyk8 小时前
安装部署Claude Code及测试
人工智能
2601_957882248 小时前
一条视频如何自动适配5大平台的技术实现
人工智能·算法·机器学习
AI小百科8 小时前
目前开源AI编辑器面临的主要挑战是什么
人工智能·开源·编辑器
TDK村田muRata8 小时前
CUS200M-12 | TDK医疗电源|直流12V 16.7A |CUS200M-12/A
服务器·人工智能·3d·机器人·无人机
csdn小瓯8 小时前
日志规范化与结构化输出:构建可观测的 AI 后端系统
人工智能
Yuk丶8 小时前
厌倦了假AI对话?用本地大模型给UE注入真智能(已开源!)
c++·人工智能·开源·ue4·游戏程序·ue4客户端开发
udc小白8 小时前
Excel实现LSTM示例
人工智能·深度学习·神经网络·机器学习·excel·lstm