基于Qwen3.5-9B与OpenClaw的AI智能体自动化测试实践
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格式更规范,命令生成的逻辑也更合理,减少了后续解析的麻烦。
整个系统的架构可以这样理解:
- 用户层 :我提供自然语言指令,例如:“请运行项目根目录下的
test_calculator.py脚本,并验证其输出是否包含‘所有测试通过’字样。” - 智能体层(OpenClaw + Qwen3.5-9B) :OpenClaw框架将我的指令传递给Qwen模型。模型理解指令后,决定需要调用“执行Shell命令”这个工具,并生成具体的命令参数,比如
cd /project && python test_calculator.py。 - 工具执行层 :OpenClaw接收到模型返回的工具调用请求,在安全的沙箱或子进程中实际执行这条Shell命令。
- 反馈与校验层 :命令执行后,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
代码解读与注意事项:
-
@tool装饰器 :这是OpenClaw框架的魔法,它把这个普通函数注册为一个AI可调用的工具。框架会自动提取函数的参数描述和文档字符串,用于构建给模型的提示词。 - 参数设计 :
command参数是必须的,timeout参数给了模型一个控制执行时间的开关。你还可以增加cwd(工作目录)参数,让模型能更精确地控制执行环境。 - 安全第一 :使用
shlex.split(command)而不是shell=True来执行命令。shell=True虽然方便,但存在严重的命令注入风险。如果用户输入是rm -rf / && echo hello,shell=True会直接执行删除操作!而shlex.split会将其安全地解析为参数列表。 - 超时处理 :
timeout参数至关重要。没有它,一个死循环命令会让你的智能体线程永远卡住。 - 丰富的返回信息 :我们不仅返回成功与否,还返回标准输出、标准错误和退出码。这些信息对于后续的结果校验是必不可少的原材料。
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,则告诉我‘测试套件完全通过’;否则,分析输出和错误,告诉我哪些测试失败了。”
这条指令包含了:
- 上下文 :切换工作目录。
- 动作 :执行指定脚本。
- 校验逻辑 :基于输出内容 和 退出码进行双重判断。
- 交付物 :明确的结论报告。
4.3 观察智能体的思考与执行过程
当我们发出指令后,可以在OpenClaw的日志或对话界面中观察模型的“思考链”(Chain-of-Thought)。一个理想的执行过程如下:
- 规划 :模型会先理解任务,它可能会“想”:“用户要我运行一个测试脚本并检查结果。我需要先进入那个目录,然后运行Python脚本,最后检查输出。”
- 工具调用1 :模型决定调用
execute_shell_command,参数为command: “cd /home/user/projects/test_arena”。执行成功,返回success: true, stdout: “”, exit_code: 0。 - 工具调用2 :模型再次调用工具,参数为
command: “python test_demo.py”。工具执行我们的脚本。 - 接收反馈 :工具返回执行结果。假设这次随机测试成功了,返回信息可能是:
{ "success": true, "stdout": "开始运行测试套件...\n✓ 加法测试通过\n✓ 减法测试通过\n✓ 随机测试通过\n\n🎉 所有测试通过!", "stderr": "", "exit_code": 0 } - 分析与决策 :模型收到这些信息后,开始分析:“退出码是0,表示程序正常结束。输出中包含‘所有测试通过’字样。这符合用户设定的成功条件。”
- 最终回复 :模型生成最终答案:“测试套件完全通过。脚本执行成功,退出码为0,并且输出中包含了‘所有测试通过’的总结信息。”
如果随机测试失败了,模型收到的 stdout 末尾会是“❌ 部分测试失败”,且 exit_code 为1。模型就需要根据指令,给出“测试失败”的结论,并可能从输出中提取出“随机测试失败”这一信息。
这个过程完美展示了智能体的自动化能力: 理解复杂指令 -> 拆解为原子操作 -> 安全执行 -> 基于结果进行逻辑推理 -> 生成最终报告 。
5. 避坑指南与性能优化
在实际操作中,不可能一帆风顺。下面是我踩过的一些坑和对应的解决方案。
5.1 常见问题与排查
问题1:模型不调用工具,而是“空想”或直接输出命令文本。
- 现象 :模型回复“你应该执行
cd /path && python script.py”,但它并没有实际调用execute_shell_command工具。 - 原因 :提示词不够清晰,或者工具的描述(name, description, parameters)没有很好地嵌入到模型的上下文中。也可能是模型本身对工具调用的格式遵循不好。
- 解决 :
- 强化系统提示 :在系统提示中明确强调“你必须通过调用
execute_shell_command工具来执行命令”。 - 检查工具注册 :确保你的自定义工具已经正确注册到OpenClaw的智能体实例中。
- 更换模型或调整参数 :尝试Qwen2.5-9B的不同量化版本(如Q4_K_M),或者微调模型的
temperature参数(调低,如0.1,使其更确定性)和top_p参数。
- 强化系统提示 :在系统提示中明确强调“你必须通过调用
问题2:命令执行成功,但模型无法正确解析输出进行校验。
- 现象 :脚本明明输出“所有测试通过”,模型却得出结论“未找到成功标志”。
- 原因 :模型的上下文理解可能出现偏差,或者输出文本格式复杂(如包含大量日志、特殊字符),干扰了模型的判断。
- 解决 :
- 简化输出 :让测试脚本的输出格式尽量简洁、规范。使用明确的成功/失败关键词。
- 在指令中明确校验规则 :指令可以写得更具体,如“请检查 最后一行 是否包含‘所有测试通过’”。
- 分步引导 :对于复杂校验,可以设计多轮对话。先让模型执行命令并返回原始输出,再发起一轮新的对话,专门让模型分析上一轮的输出结果。
问题3:执行长时间脚本时超时。
- 现象 :
execute_shell_command工具返回超时错误。 - 原因 :默认的30秒超时对于某些耗时操作(如下载、编译)可能不够。
- 解决 :
- 调整超时参数 :在工具调用时,让模型传递一个更大的
timeout值。这需要你在工具描述中明确说明timeout参数的作用。 - 异步执行与状态检查 :对于超长任务,更高级的方案是设计“启动任务”和“查询任务状态”两个工具。但这需要额外的后台任务管理机制。
- 调整超时参数 :在工具调用时,让模型传递一个更大的
问题4:路径或环境问题导致命令执行失败。
- 现象 :
FileNotFoundError或ModuleNotFoundError。 - 原因 :智能体执行命令的环境可能与你的开发环境不同(PATH, Python环境等)。
- 解决 :
- 使用绝对路径 :在指令和模型生成的命令中,尽量使用绝对路径。
- 指定Python解释器 :使用
/usr/bin/python3或/home/user/.virtualenvs/project/bin/python这样的绝对路径。 - 在工具中预设环境 :在
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的“手脚”上好枷锁,比让它力大无穷更重要。
更多推荐
所有评论(0)