← 返回 AI Agent 课程

【中文精读】Executable Code Actions Elicit Better LLM Agents(CodeAct)

原文:https://arxiv.org/abs/2402.01030 · 本文为中文精读版(忠实转述+关键段落翻译),非逐句全译 · 生成于 2026-07-03 · 精读整理:
导读:这篇 UIUC 等机构 2024 年发表于 ICML 的论文,是「让 agent 用代码而非 JSON 工具调用来行动」这条技术路线的代表作。它回答的问题极其根本:LLM agent 每一步到底应该以什么格式输出动作?主流做法(OpenAI function calling、绝大多数框架)让模型生成 JSON 或固定文本格式的工具调用,而本文系统论证并实证了第三种选择——直接生成可执行 Python 代码作为动作——在复杂任务上成功率最高可拉开约 20 个百分点。它同时贡献了框架(CodeAct)、基准(M3ToolEval)、数据集(CodeActInstruct 7k 轨迹)和开源模型(CodeActAgent),形成完整闭环。后来的 OpenDevin/OpenHands 等开源 agent 直接以它为思想源头(OpenHands 的核心 agent 至今叫 CodeActAgent),Claude Code、各类「code interpreter」式 agent 的设计也都可视为这一路线的延伸。读懂这篇,你就理解了「工具调用 agent」与「写代码 agent」两大流派分野的原点。

一、动机:JSON / 文本格式动作的两大枷锁

LLM agent 的标准工作方式是:感知环境 → 生成动作 → 观察结果,循环往复。问题在于动作的表达格式。此前几乎所有工作都让 LLM 以预定义格式(pre-defined format)生成动作——要么是 JSON(如 function calling),要么是约定的文本模板(如 Action: tool_name, Args: ...)。论文开篇即指出这类做法的两个核心局限:

论文还点名了另一条相关路线的不足:此前用代码控制机器人的工作(如 Code-as-Policies)是单轮生成整段程序,"难以根据新的环境观察动态调整或发出动作"(struggle to dynamically adjust or emit actions based on new environmental observation),依赖预设控制原语和精心手写的提示词。CodeAct 的关键区别是把代码生成放进多轮交互(multi-turn interaction)循环里。

论文图 1 上半部分给出一个直观例子:任务要求对一批输入逐个调用工具并汇总。text/JSON 格式的 agent 必须"对每个输入都单独执行一次动作"(have to take action for every input),一轮一个;而 CodeAct 用一个 for 循环(控制流)加上把工具 A 的输出直接传入工具 B(数据流),一个动作就处理完全部输入

二、方法:CodeAct 框架机制

2.1 核心设计:代码即动作

论文提出的可执行代码动作(executable code actions,CodeAct)框架,一句话概括:"用可执行 Python 代码把 LLM agent 的动作整合到统一的动作空间"(use executable Python code to consolidate LLM agents' actions into a unified action space)。选择 Python 的理由很务实:它是最流行的语言(TIOBE 排名第一),预训练语料里代码占比极高,且拥有海量现成开源包。

框架含三个角色:agent、用户(user)、环境(environment)。每一轮交互中:

  1. agent 接收一个观察(observation)——要么是用户的自然语言指令,要么是上一轮代码的执行结果;
  2. agent 可选地先做思维链(chain-of-thought)式的推理规划;
  3. agent 发出一个动作(action)——"发给环境的每个动作都是一段 Python 代码"(each emitted action to the environment is a piece of Python code);
  4. 环境(Python 解释器)执行这段代码,把标准输出、返回值或报错信息(traceback)作为下一轮观察返回给 agent。

预定义工具在这个框架里并没有消失,而是降格为普通的 Python 函数/API:agent 可以像调用任何库函数一样调用它们,也可以把它们嵌进循环、条件、变量赋值中自由组合。

2.2 「代码即动作」相对 JSON/text 的优势论证

论文(§2 及表 1)系统列出了代码作为动作格式的几大优势,这是全文的理论骨架:

三、实验一:CodeAct 作为格式本身有多强(M3ToolEval 与 API-Bank)

论文用两个实验回答两个递进的问题:简单的单工具调用场景下 CodeAct 是否不吃亏(API-Bank),以及复杂多工具组合场景下 CodeAct 优势有多大(M3ToolEval)。共评测 17 个 LLM(8 个开源 + 9 个闭源),每个模型分别用 CodeAct / JSON / text 三种动作格式跑。

3.1 M3ToolEval:复杂任务上最高约 20 个百分点的绝对提升

由于现有基准没有覆盖"需要多轮、多工具组合"的场景,作者自建了 M3ToolEval:共 82 个人工策划的任务,覆盖网页浏览、金融、旅行行程规划、科学、信息处理五个领域,每个领域配独特的手工工具集;零样本评测(不给示范,考察模型开箱即用的指令跟随),最多 10 轮交互,最终答案与标准解精确匹配判分。指标是成功率和平均交互轮数。核心结果:

3.2 API-Bank:简单原子调用场景下 CodeAct 至少不输

API-Bank 测的是单步原子 API 调用的正确率,这里没有组合优势可言,是对 CodeAct 的"下限测试"。结果:CodeAct 在 17 个模型中 8 次成为最佳格式(开源 4、闭源 4),JSON 5 次、text 4 次。代表性数字(正确率 %,CodeAct/JSON/text):claude-2 为 76.7/59.4/73.7;gpt-4-1106-preview 为 76.7/82.7/73.4;Llama-2-13b-chat 为 38.1/8.5/37.3。一个有意思的观察:闭源模型 JSON 成绩不错(GPT-4 系列 JSON 反而最高),作者推测是因为它们专门针对 function calling 做过微调;而开源模型的 JSON 表现一致地差。结论:即便在 JSON 的主场(简单单工具调用、且对手被专门调优过),CodeAct 也大体打平或更好;一旦任务变复杂,优势立刻拉开。

四、CodeActInstruct:7k 条多轮交互轨迹的构造

格式的优势验证完,下一步是把它蒸馏进开源小模型。作者构造了指令微调数据集 CodeActInstruct:7,139 条多轮 agent-环境交互轨迹,共约 1,058 万 token(平均每条约 1,482 token)。图 2 的三角色框架在此起了设计指导作用:CodeActInstruct 专注 agent-环境交互,通用对话数据负责 agent-用户交互。数据来源覆盖四个任务族:

任务族数据源轨迹数Token 数
信息检索HotpotQA(提供 wikipedia_search API)1,664约 247 万
软件包(工具)使用MATH(数学推理,可用 sympy 等)1,732约 172 万
APPS(代码生成)647约 124 万
外部记忆WikiTableQuestion(SQL/sqlite3 与 Pandas 双变体)1,065约 132 万
机器人规划ALFWorld(机器人控制 API 包装成 Python 函数)2,031约 384 万

(注:任务提示里描述的"APIBank/M3ToolEval 相关任务族",指的正是这四类能力方向;M3ToolEval 本身留作 out-of-domain 测试,不进训练集。)构造与筛选上有三个值得复述的细节:

规模对比:相比同期的 AgentInstruct(1,866 条)和 FireAct(2,063 条),CodeActInstruct 轨迹数是其 3.8 倍 / 3.5 倍,token 数是 5 倍 / 19 倍。

五、CodeActAgent:训练与评测

5.1 训练细节

基座取 Mistral-7BLlama-2-7B,全参数 SFT。训练混合 = CodeActInstruct(7,139 条)+ 通用对话数据(共 69,230 条 / 约 5,515 万 token):OpenOrca CoT 子集下采样 50,000 条、ShareGPT 下采样 10,000 条(去掉单轮)、ShareGPT-GPT4 版 4,583 条、CapyBara 4,647 条。超参:序列长度 Llama-2 用 4,096、Mistral 用 16,384(Mistral 长上下文是它后来表现更好的因素之一);chatML 格式、只在 assistant 回复上算 loss、短样本打包 + flash attention;4×A100-40GB,学习率 1e-5(50 步 warmup、cosine 衰减到 1e-6),batch size 32,训 5 个 epoch 取第 3 个 epoch 的 checkpoint。

5.2 评测:in-domain 与 out-of-domain

评测分两块:agent 任务(MINT in-domain、MINT out-of-domain、M3ToolEval、MiniWob++ 网页操作、ScienceWorld 文本动作)+ 通用能力(MMLU、HumanEval、GSM8K、MT-Bench)。关键数字(MINT 成功率取 k=5 轮):

模型(7B)MINT-IDMINT-ODMiniWob++SciWorldMMLUHumanEvalGSM8KMT-Bench总平均
CodeActAgent (Mistral)57.432.446.215.959.134.758.08.242.5
CodeActAgent (Llama-2)51.320.425.517.650.618.138.37.530.7
Mistral-Instruct18.89.70.54.053.829.343.36.425.6
Llama-2-Chat3.211.00.05.948.013.927.76.321.1
AgentLM8.76.128.913.748.715.424.66.124.8
FireAct0.00.30.06.844.13.512.44.514.0

要点解读:

六、结论与局限

结论:CodeAct 用可执行 Python 代码统一了 LLM agent 的动作空间;在复杂多工具场景下比 text/JSON 格式最多高约 20% 成功率、少约 30% 交互轮数;配套的 CodeActInstruct(7k 轨迹)训出的 CodeActAgent 能与 Python 生态无缝集成——用现成库完成模型训练这类复杂任务,并通过 self-debug 自主纠错。框架、基准、数据、模型全部开源。

局限(论文 Impact Statement 部分,如实转述):

对开发者的启示