1. 项目概述:当大模型遇上自动化测试

最近在折腾一个挺有意思的项目,叫OpenClaw。简单来说,它是一个开源的AI智能体框架,你可以把它理解为一个“大脑”,能够接收指令,然后调用各种工具去完成任务。而我这次的目标,是让这个“大脑”去执行一个非常具体的动作:运行一个Python脚本,并自动校验脚本的执行结果是否正确。听起来是不是有点像让一个刚学会走路的孩子去参加编程竞赛?但这就是AI智能体当前最吸引人的地方——将复杂指令拆解为可执行的原子操作。

我选择的核心“大脑”是Qwen3.5-9B,通义千问的一个开源模型。为什么是它?首先,9B的参数量在本地部署和推理速度上找到了一个不错的平衡点,既不像70B模型那样对硬件要求苛刻,又比一些更小的模型在代码理解和逻辑推理上更靠谱。其次,它的工具调用(Function Calling)能力经过实测,在开源模型中属于第一梯队,这对于让AI去执行“运行脚本”这种外部命令至关重要。

这个项目的核心价值在于验证一个工作流: 能否用一个大语言模型(LLM)作为决策中枢,可靠地驱动一个完整的、包含外部系统交互的自动化测试流程? 这不仅仅是跑个 python script.py 那么简单,它涉及到指令理解、环境感知、命令生成、执行监控、结果解析和逻辑判断等一系列环节。任何一个环节掉链子,整个流程就失败了。接下来,我就把自己从环境搭建到最终跑通整个流程中踩过的坑、总结的经验,毫无保留地分享出来。

2. 核心思路与架构设计

2.1 为什么是OpenClaw + Qwen3.5-9B?

在开始动手之前,得先想清楚技术选型。市面上能和OpenClaw对标的框架还有LangChain、LlamaIndex等。我选择OpenClaw,主要是看中它的“轻量”和“直接”。它没有过度封装,架构清晰,让你能清楚地知道指令是怎么流转的,工具是怎么被调用的,这对于调试一个以“执行外部命令”为核心的项目来说,简直是福音。你不会被一堆抽象层搞得晕头转向,出了问题能快速定位。

而选择Qwen3.5-9B模型,则是性能与成本的权衡。全参数微调(Fine-tuning)一个模型来专门做这件事成本太高,且容易过拟合。我们更需要的是模型的“零样本”或“少样本”工具调用能力。Qwen3.5-9B在工具调用格式的遵循、对指令的理解上表现稳定。我曾对比过在相同提示词下,它和某些同类尺寸模型的输出,Qwen给出的JSON格式更规范,命令生成的逻辑也更合理,减少了后续解析的麻烦。

整个系统的架构可以这样理解:

  1. 用户层 :我提供自然语言指令,例如:“请运行项目根目录下的 test_calculator.py 脚本,并验证其输出是否包含‘所有测试通过’字样。”
  2. 智能体层(OpenClaw + Qwen3.5-9B) :OpenClaw框架将我的指令传递给Qwen模型。模型理解指令后,决定需要调用“执行Shell命令”这个工具,并生成具体的命令参数,比如 cd /project && python test_calculator.py
  3. 工具执行层 :OpenClaw接收到模型返回的工具调用请求,在安全的沙箱或子进程中实际执行这条Shell命令。
  4. 反馈与校验层 :命令执行后,OpenClaw会捕获标准输出(stdout)、标准错误(stderr)和退出码(exit code),将这些信息作为上下文再次传给模型。模型需要根据这些反馈,判断任务是否成功,并给出结论,例如:“脚本执行成功,退出码为0,输出中包含‘所有测试通过’,因此校验通过。”

这个流程的关键在于“循环”:模型根据执行结果决定下一步动作,直到任务完成或失败。我们的目标就是让这个循环稳定、可靠地运转起来。

2.2 环境准备与关键配置

工欲善其事,必先利其器。环境的搭建是第一步,也是最容易出问题的一步。

基础环境:

  • 操作系统 :推荐Ubuntu 22.04 LTS或Windows WSL2。我是在WSL2(Ubuntu)下完成的,兼顾了Windows的便利和Linux环境的一致性。纯Windows环境可能会在路径、权限和某些依赖上遇到诡异问题。
  • Python :版本必须>=3.9,建议3.10或3.11。用 python --version 确认。别用系统自带的Python2,那会是一场灾难。
  • CUDA(可选但强烈推荐) :如果你有NVIDIA显卡,安装对应版本的CUDA和cuDNN能极大加速Qwen模型的推理。用 nvidia-smi 查看驱动和CUDA版本。Qwen3.5-9B的量化版本(如GPTQ、AWQ)在8G显存的卡上就能流畅运行。

安装OpenClaw: 最稳妥的方式是从源码安装,便于调试和修改。

git clone https://github.com/openclaw/openclaw.git
cd openclaw
pip install -e . # 使用可编辑模式安装,后续修改代码立即生效

安装后,运行 openclaw --version 检查是否成功。这里有个坑:如果提示“无法将‘openclaw’识别为命令”,通常是因为Python的Scripts目录(Windows)或bin目录(Linux)没加到系统PATH里。你需要找到pip安装包的位置,或者直接用 python -m openclaw 来调用。

部署Qwen3.5-9B模型: 本地部署推荐使用Ollama,它简化了模型下载、加载和服务的全过程。

# 安装Ollama
curl -fsSL https://ollama.com/install.sh | sh
# 拉取并运行Qwen3.5-9B模型(这是一个约6G的4位量化版本,速度和质量平衡得很好)
ollama pull qwen2.5:9b
ollama run qwen2.5:9b

运行后,Ollama会在本地11434端口启动一个API服务。你可以用curl测试一下:

curl http://localhost:11434/api/generate -d '{
  "model": "qwen2.5:9b",
  "prompt": "Hello",
  "stream": false
}'

如果看到返回的JSON里有文本内容,说明模型服务正常。 特别注意 :网络上的“qwen3.5-9b”和Ollama中的“qwen2.5:9b”可能是命名差异,以Ollama官方库为准。如果遇到回复慢的问题,首先检查CPU/内存占用,其次可以尝试Ollama的 num_ctx (上下文长度)和 num_gpu (GPU层数)参数进行调整,对于9B模型, num_gpu 设置为40(即全部放GPU)通常能获得最佳速度。

配置OpenClaw连接Ollama: OpenClaw需要知道去哪里找你的“大脑”。修改OpenClaw的配置文件(通常位于 ~/.openclaw/config.yaml 或项目目录下的 config.yaml )。

model:
  provider: "ollama" # 指定使用Ollama
  name: "qwen2.5:9b" # 模型名称
  base_url: "http://localhost:11434" # Ollama API地址
  api_key: "none" # Ollama无需API Key

配置完成后,一个基础的、由大模型驱动的智能体环境就准备好了。接下来,我们要赋予它“动手”的能力。

3. 核心工具:让AI学会执行Shell命令

OpenClaw本身提供了一些基础工具,但“执行任意Shell命令”这种高风险高灵活度的工具,往往需要我们自己定义。这是整个项目的技术核心。

3.1 自定义Shell工具的实现

在OpenClaw中,一个工具本质上是一个Python函数,加上一些描述信息(元数据)。我们需要创建一个能安全执行命令并返回结果的工具。

# 文件:custom_tools.py
import subprocess
import shlex
from typing import Dict, Any
from openclaw.tools import tool

@tool
def execute_shell_command(command: str, timeout: int = 30) -> Dict[str, Any]:
    """
    在安全的环境中执行一条Shell命令,并返回结果。
    
    Args:
        command (str): 要执行的Shell命令字符串。
        timeout (int): 命令执行超时时间,单位秒,默认为30秒。
        
    Returns:
        Dict: 包含执行状态、输出、错误和退出码的字典。
    """
    result = {
        "success": False,
        "stdout": "",
        "stderr": "",
        "exit_code": None,
        "error": None
    }
    
    try:
        # 使用shlex.split可以安全地分割命令参数,避免shell注入攻击
        # 设置text=True以获取字符串而非字节
        # 设置timeout防止命令长时间挂起
        completed_process = subprocess.run(
            shlex.split(command),
            capture_output=True,
            text=True,
            timeout=timeout,
            # 可以在这里设置cwd(工作目录)或env(环境变量)
            # cwd="/specified/path"
        )
        
        result["stdout"] = completed_process.stdout
        result["stderr"] = completed_process.stderr
        result["exit_code"] = completed_process.returncode
        # 通常,退出码为0表示成功
        result["success"] = (completed_process.returncode == 0)
        
    except subprocess.TimeoutExpired:
        result["error"] = f"命令执行超时({timeout}秒)"
        result["success"] = False
    except FileNotFoundError:
        result["error"] = "未找到命令或可执行文件。请检查命令拼写和系统PATH。"
        result["success"] = False
    except Exception as e:
        result["error"] = f"执行过程中发生未知错误:{str(e)}"
        result["success"] = False
    
    return result

代码解读与注意事项:

  1. @tool 装饰器 :这是OpenClaw框架的魔法,它把这个普通函数注册为一个AI可调用的工具。框架会自动提取函数的参数描述和文档字符串,用于构建给模型的提示词。
  2. 参数设计 command 参数是必须的, timeout 参数给了模型一个控制执行时间的开关。你还可以增加 cwd (工作目录)参数,让模型能更精确地控制执行环境。
  3. 安全第一 :使用 shlex.split(command) 而不是 shell=True 来执行命令。 shell=True 虽然方便,但存在严重的命令注入风险。如果用户输入是 rm -rf / && echo hello shell=True 会直接执行删除操作!而 shlex.split 会将其安全地解析为参数列表。
  4. 超时处理 timeout 参数至关重要。没有它,一个死循环命令会让你的智能体线程永远卡住。
  5. 丰富的返回信息 :我们不仅返回成功与否,还返回标准输出、标准错误和退出码。这些信息对于后续的结果校验是必不可少的原材料。

3.2 工具的描述与提示工程

写好工具函数只是第一步,更重要的是如何让Qwen模型“理解”并“用好”这个工具。这全靠我们给工具的“描述”。

@tool 装饰器自动生成的元数据基础上,我们可以在系统提示词(System Prompt)中对工具的使用进行强调和规范。这是提示工程的关键部分。

我们需要在启动OpenClaw智能体时,传入一个清晰的系统指令:

你是一个擅长自动化任务和系统操作的AI助手。你可以调用`execute_shell_command`工具来执行系统命令。
请遵循以下准则:
1.  在决定执行命令前,先思考命令的必要性和安全性。
2.  命令应尽可能具体。例如,要运行Python脚本,应使用`python /full/path/to/script.py`或先`cd`到目录再执行`python script.py`。
3.  执行命令后,仔细分析工具返回的`stdout`、`stderr`和`exit_code`。
4.  对于需要校验结果的任务,你需要根据返回的输出内容,自行判断任务是否成功,并给出最终结论。

这个系统提示做了几件事:明确了角色、指明了核心工具、规定了安全性和具体性准则、最重要的是, 把结果校验的逻辑判断责任交给了模型本身 。我们并不预先写死“如果输出包含A就算成功”,而是让模型根据任务指令(如“验证输出是否包含‘通过’”)和实际输出来做推理。这更符合智能体“自主决策”的定位。

4. 实战:Python脚本执行与智能校验

理论铺垫完毕,现在进入实战环节。我们设计一个简单的测试脚本,然后让OpenClaw智能体去运行并校验它。

4.1 准备测试用例

创建一个简单的Python脚本 test_demo.py ,它模拟一个测试场景:

# test_demo.py
import sys
import random

def test_addition():
    """测试加法"""
    assert 1 + 1 == 2, "加法测试失败"
    print("✓ 加法测试通过")
    return True

def test_subtraction():
    """测试减法"""
    assert 5 - 3 == 2, "减法测试失败"
    print("✓ 减法测试通过")
    return True

def test_random_failure():
    """模拟一个随机失败的测试(用于演示)"""
    value = random.randint(0, 1)
    if value == 0:
        print("✗ 随机测试失败")
        return False
    else:
        print("✓ 随机测试通过")
        return True

if __name__ == "__main__":
    print("开始运行测试套件...")
    results = []
    results.append(test_addition())
    results.append(test_subtraction())
    results.append(test_random_failure())
    
    if all(results):
        print("\n🎉 所有测试通过!")
        sys.exit(0) # 退出码 0 表示成功
    else:
        print("\n❌ 部分测试失败。")
        sys.exit(1) # 退出码非0 表示失败

这个脚本有两个必然成功的测试,一个随机成功或失败的测试。最终会打印总结信息并以不同的退出码结束。

4.2 构造智能体任务指令

现在,我们启动配置好的OpenClaw智能体,并向它发出任务指令。指令需要清晰、无歧义:

“请切换到 /home/user/projects/test_arena 目录,执行其中的Python脚本 test_demo.py 。执行完成后,请检查脚本的输出结果。如果输出中包含‘所有测试通过’字样,并且脚本的退出码为0,则告诉我‘测试套件完全通过’;否则,分析输出和错误,告诉我哪些测试失败了。”

这条指令包含了:

  1. 上下文 :切换工作目录。
  2. 动作 :执行指定脚本。
  3. 校验逻辑 :基于输出内容 退出码进行双重判断。
  4. 交付物 :明确的结论报告。

4.3 观察智能体的思考与执行过程

当我们发出指令后,可以在OpenClaw的日志或对话界面中观察模型的“思考链”(Chain-of-Thought)。一个理想的执行过程如下:

  1. 规划 :模型会先理解任务,它可能会“想”:“用户要我运行一个测试脚本并检查结果。我需要先进入那个目录,然后运行Python脚本,最后检查输出。”
  2. 工具调用1 :模型决定调用 execute_shell_command ,参数为 command: “cd /home/user/projects/test_arena” 。执行成功,返回 success: true, stdout: “”, exit_code: 0
  3. 工具调用2 :模型再次调用工具,参数为 command: “python test_demo.py” 。工具执行我们的脚本。
  4. 接收反馈 :工具返回执行结果。假设这次随机测试成功了,返回信息可能是:
    {
      "success": true,
      "stdout": "开始运行测试套件...\n✓ 加法测试通过\n✓ 减法测试通过\n✓ 随机测试通过\n\n🎉 所有测试通过!",
      "stderr": "",
      "exit_code": 0
    }
    
  5. 分析与决策 :模型收到这些信息后,开始分析:“退出码是0,表示程序正常结束。输出中包含‘所有测试通过’字样。这符合用户设定的成功条件。”
  6. 最终回复 :模型生成最终答案:“测试套件完全通过。脚本执行成功,退出码为0,并且输出中包含了‘所有测试通过’的总结信息。”

如果随机测试失败了,模型收到的 stdout 末尾会是“❌ 部分测试失败”,且 exit_code 为1。模型就需要根据指令,给出“测试失败”的结论,并可能从输出中提取出“随机测试失败”这一信息。

这个过程完美展示了智能体的自动化能力: 理解复杂指令 -> 拆解为原子操作 -> 安全执行 -> 基于结果进行逻辑推理 -> 生成最终报告

5. 避坑指南与性能优化

在实际操作中,不可能一帆风顺。下面是我踩过的一些坑和对应的解决方案。

5.1 常见问题与排查

问题1:模型不调用工具,而是“空想”或直接输出命令文本。

  • 现象 :模型回复“你应该执行 cd /path && python script.py ”,但它并没有实际调用 execute_shell_command 工具。
  • 原因 :提示词不够清晰,或者工具的描述(name, description, parameters)没有很好地嵌入到模型的上下文中。也可能是模型本身对工具调用的格式遵循不好。
  • 解决
    1. 强化系统提示 :在系统提示中明确强调“你必须通过调用 execute_shell_command 工具来执行命令”。
    2. 检查工具注册 :确保你的自定义工具已经正确注册到OpenClaw的智能体实例中。
    3. 更换模型或调整参数 :尝试Qwen2.5-9B的不同量化版本(如Q4_K_M),或者微调模型的 temperature 参数(调低,如0.1,使其更确定性)和 top_p 参数。

问题2:命令执行成功,但模型无法正确解析输出进行校验。

  • 现象 :脚本明明输出“所有测试通过”,模型却得出结论“未找到成功标志”。
  • 原因 :模型的上下文理解可能出现偏差,或者输出文本格式复杂(如包含大量日志、特殊字符),干扰了模型的判断。
  • 解决
    1. 简化输出 :让测试脚本的输出格式尽量简洁、规范。使用明确的成功/失败关键词。
    2. 在指令中明确校验规则 :指令可以写得更具体,如“请检查 最后一行 是否包含‘所有测试通过’”。
    3. 分步引导 :对于复杂校验,可以设计多轮对话。先让模型执行命令并返回原始输出,再发起一轮新的对话,专门让模型分析上一轮的输出结果。

问题3:执行长时间脚本时超时。

  • 现象 execute_shell_command 工具返回超时错误。
  • 原因 :默认的30秒超时对于某些耗时操作(如下载、编译)可能不够。
  • 解决
    1. 调整超时参数 :在工具调用时,让模型传递一个更大的 timeout 值。这需要你在工具描述中明确说明 timeout 参数的作用。
    2. 异步执行与状态检查 :对于超长任务,更高级的方案是设计“启动任务”和“查询任务状态”两个工具。但这需要额外的后台任务管理机制。

问题4:路径或环境问题导致命令执行失败。

  • 现象 FileNotFoundError ModuleNotFoundError
  • 原因 :智能体执行命令的环境可能与你的开发环境不同(PATH, Python环境等)。
  • 解决
    1. 使用绝对路径 :在指令和模型生成的命令中,尽量使用绝对路径。
    2. 指定Python解释器 :使用 /usr/bin/python3 /home/user/.virtualenvs/project/bin/python 这样的绝对路径。
    3. 在工具中预设环境 :在 execute_shell_command 工具的实现中,通过 subprocess.run env 参数注入特定的环境变量。

5.2 性能优化与扩展思路

1. 结果校验的强化: 目前的校验依赖模型的自然语言理解能力。为了更可靠,可以设计一个专门的“结果分析工具”。这个工具接收脚本输出和一组“校验规则”(如正则表达式、关键词列表),返回结构化的校验结果。这样就把感性的“理解”变成了确定性的“规则匹配”,更适合对可靠性要求极高的生产场景。

2. 工具能力的扩展: execute_shell_command 是万能钥匙,但也是瑞士军刀。对于高频操作,可以封装更专用的工具,提升成功率和效率。

  • run_python_script(script_path, args) :专门用于运行Python脚本,自动处理Python解释器路径和参数传递。
  • check_file_contains(file_path, pattern) :专门检查文件内容是否匹配特定模式。
  • get_process_status(process_name) :检查某个进程是否在运行。 这些专用工具的描述更清晰,能引导模型生成更准确的调用参数。

3. 工作流(Workflow)固化: 对于固定的测试流程,比如“拉取代码 -> 安装依赖 -> 运行测试 -> 生成报告”,我们可以不依赖模型的每次规划,而是用OpenClaw的工作流功能将其固化为一个可重复执行的序列。模型可以作为这个工作流的触发器或决策节点(例如,判断代码更新后再触发)。

4. 多模态输入支持: 如果测试输出包含图表、截图(比如UI自动化测试),可以考虑使用多模态模型(如Qwen-VL)作为智能体的“大脑”,使其能“看到”执行结果并进行判断,这将极大扩展自动化测试的范围。

6. 总结与展望

通过这个项目,我们成功地将Qwen3.5-9B大模型通过OpenClaw框架,与真实的系统操作环境连接了起来,实现了一个从自然语言指令到自动化执行与校验的闭环。这不仅仅是“用AI跑了个脚本”,而是验证了一种范式:大模型可以作为复杂工作流的智能调度器和决策器。

我个人的体会是,现阶段的关键不在于让AI做多么惊天动地的事,而在于让它们 可靠地完成一件件小事 。把“运行并校验Python脚本”这样的小事做扎实,积累起可靠的工具调用、稳定的上下文管理和有效的错误处理机制,才是构建更复杂AI智能体应用的基石。过程中最大的挑战往往不是模型能力,而是如何设计清晰的任务边界、安全的工具接口以及鲁棒的交互流程。

这个demo只是一个起点。沿着这个思路,你可以将它扩展成一个真正的AI驱动的测试助手:让它定时巡检、分析日志、对比测试结果、甚至根据失败日志尝试定位代码问题。想象力有多大,舞台就有多大。不过,始终要记住一点:在任何涉及系统操作的自动化中, 安全是第一条铁律 ,给AI的“手脚”上好枷锁,比让它力大无穷更重要。

更多推荐