
清空记录
历史记录
取消
清空记录
历史记录

一句话讲清这个功能
不用Function Calling,只靠"一条协议+一个中断",就能让不支持工具调用的模型在RK3576 Debian12设备上自主执行shell命令:
本功能实现"模型自主调用设备shell工具"的agent循环:用户用自然语言提问,模型按ReAct 协议输出
实测视频演示:
它想解决什么问题?
在触觉智能RK3576开发板部署运行DeepSeek-R1-Distill-1.5B轻量化模型时,我们遇到明显落地痛点:模型原生不支持Function Calling(R1蒸馏版本未针对工具调用场景专项微调),同时配套RKLLM 旧版SDK缺少回调暂停、推理续跑这类高级原生能力。
常规实现方案是上层程序预先封装、主动替模型查询设备信息,智能化程度很低。我们期望达成自主交互效果:
用户:当前内存占用多少? |
这是标准ReAct工具调用Agent循环。阻碍在于:RKLLM同步推理接口rkllm_run为阻塞式调用,推理一旦启动,无法在流式生成中途插入shell命令执行逻辑。因此核心目标明确:在RK3576 Debian12端侧流式推理过程中截获工具调用指令,执行系统命令后回填结果,继续完成推理作答。
整体流程:一条"截流-执行-回喂"的循环
用户提问 │ ▼┌─ 第1轮 rkllm_run ───────────────────────────┐│ 模型流式输出,回调逐 token 累积 ││ 检测到free -h (完整闭合标签) ││ ↓ 调用 rkllm_abort 中断本轮生成 │└─────────────────────────────────────────────┘ │ 提取命令:free -h ▼posix_spawn 执行(15s 超时 / 4KB 限长 / 去重)→ 得到Debian12系统真实数据 │ ▼┌─ 第2轮 rkllm_run ───────────────────────────┐│ 全新"作答任务"prompt: ││ 用户原始问题 + [free -h Debian系统输出] ││ "严禁再调用工具,直接给出最终答案" ││ → 模型基于硬件真实数据作答 │└─────────────────────────────────────────────┘ │ ▼向客户端输出答案 + token 统计
流程关键节点在首轮推理末尾:调用rkllm_abort在完整工具标签解析完成瞬间中断生成,完成推理截流;模型刚输出需要执行的系统命令,程序立刻接管调度Debian12系统shell。
核心设计逐段拆解
模型本身无原生工具调用能力,通过系统提示词统一约定交互协议:需要查询RK3576板卡硬件、系统信息时,输出成对闭合专用标签。
static const char *SYSTEM_PROMPT = "你是RK3576 Debian12设备上的智能助手,通过执行 shell 命令查看设备状态后作答。\n" "需要查询硬件/系统信息时,严格输出且成对闭合(命令单行):\n" "COMMAND \n" "你可以执行Debian系统任意 shell 命令来获取所需设备信息。\n" "输出标签后必须立即停止,等待系统返回结果,禁止自行编造内容。\n";
程序侧配套解析逻辑,仅识别完整闭合、内容长度合规的标签文本,正文内偶然出现tool字符不会误触发工具逻辑:
// 在整段 cur 里找第一个【完整闭合】的... static bool extract_tool_tag(const std::string &cur, std::string &cmd, size_t &tag_start){ size_t open = cur.find(""); if (open == std::string::npos) return false; size_t close = cur.find(" ", open + 6); if (close == std::string::npos) return false; if (close - open > MAX_TAG_LEN) return false; // 标签内容过长,视为普通正文 tag_start = open; cmd = trim(cur.substr(open + 6, close - open - 6)); return true;}
模型输出以逐Token流式回调推送,每次触发RKLLM_RUN_NORMAL回调时,拼接新增文本至全局缓存,同步执行标签解析;一旦捕获完整工具调用标签,设置原子标记并调用rkllm_abort终止当前推理流程:
case RKLLM_RUN_NORMAL: if (ctx->tool_pending.load()) return; // abort后延迟到达的回调直接丢弃 ctx->run_tokens++; ctx->cur += result->text; // 累积本轮回调全部输出文本 if (extract_tool_tag(ctx->cur, found_cmd, found_start)) { ctx->pending_cmd = found_cmd; // 缓存待执行shell命令 ctx->tool_pending.store(true); // 标记存在待执行工具任务 rkllm_abort(llmHandle); // ★ 中断RKLLM推理,回到主循环调度Debian shell break; } // ... 无标签的普通文本正常流式下发客户端工程容错设计:不依赖rkllm_abort 返回值做业务判断(RKLLM SDK 未明确定义 abort 后标准行为),以原子变量 tool_pending 作为唯一业务裁决依据;即使 abort 未即时终止生成、模型输出达到 Token 上限,本轮推理结束后全量文本兜底扫描,仍能正确识别工具调用标签,适配 RK3576 Debian12 端侧不稳定推理场景。
RK3576板卡内存仅4GB,早期使用popen()(底层fork实现)执行Debian shell命令时,频繁出现OOM内存溢出崩溃。根源:fork会完整复制父进程全部地址空间,而父进程常驻1.5B模型权重与大量缓存,内存占用接近2GB。
替换为posix_spawn彻底解决内存问题,glibc下该接口基于clone(CLONE_VM)实现,子进程与父进程共享虚拟内存,不做全量拷贝,适配低内存端侧设备:
// fork会复制LLM进程巨大地址空间 → RK3576 Debian环境极易OOM;posix_spawn共享内存无拷贝posix_spawn_file_actions_t fa;posix_spawn_file_actions_init(&fa);posix_spawn_file_actions_adddup2(&fa, fds[1], STDOUT_FILENO); // 子进程标准输出重定向管道posix_spawn_file_actions_adddup2(&fa, fds[1], STDERR_FILENO);posix_spawn(&pid, "/bin/sh", &fa, &attr, argv, environ);
两层安全防护规避Debian系统风险:
(1)15秒执行超时:拦截top、持续输出类长耗时命令,防止板卡卡死;
(2)4KB输出长度限制:避免dmesg打印GB级系统日志占用内存;
通过select轮询读取管道,超时 / 超限直接发送 SIGKILL 销毁子进程。
1.5B小模型存在逻辑缺陷:获取系统返回数据后仍重复发起相同shell调用,造成无效循环。配套三层限制机制适配RK3576 Debian部署:
(1)命令去重:标准化空格格式(free -h与free -h判定为同一条),记录单次请求已执行命令,重复调用直接返回提示文本,不再二次调度 shell;
// fork会复制LLM进程巨大地址空间 → RK3576 Debian环境极易OOM;posix_spawn共享内存无拷贝posix_spawn_file_actions_t fa;posix_spawn_file_actions_init(&fa);posix_spawn_file_actions_adddup2(&fa, fds[1], STDOUT_FILENO); // 子进程标准输出重定向管道posix_spawn_file_actions_adddup2(&fa, fds[1], STDERR_FILENO);posix_spawn(&pid, "/bin/sh", &fa, &attr, argv, environ);
(2)调用次数硬上限:单次提问最多允许3次工具调用,杜绝无限循环推理;
(3)执行失败重试:检测shell命令退出码,区分执行成功 / 失败;存在至少一条成功命令则进入最终作答流程;若全部命令执行报错,构造重试 Prompt 引导模型更换适配Debian12的查询指令。
初期方案直接拼接模型上一轮完整输出继续推理,R1蒸馏模型会重复复制自身历史文本,出现无限复读卡死。重构为独立作答Prompt,仅保留用户原始问题+Debian系统命令输出,剔除模型全部历史思考、标签文本,强制模型直接输出答案:
std::string norm = normalize_cmd(cmd); // 统一命令空格格式for (auto &ec : ctx.executed_cmds) if (ec == norm) { dup = true; break; }if (dup) result = "[提示: 命令 '" + cmd + "' 之前已在本请求执行过。请更换Debian shell命令或直接基于已有数据作答。]";主循环根据任务状态自动切换三类Prompt模板:
static std::string build_answer_prompt(const AgentCtx &ctx){ std::string p = BOS; p += U_OP; p += SYSTEM_PROMPT; p += "\n\n用户问题:"; p += ctx.question; p += "\n\n以下shell命令已在RK3576 Debian12设备执行,下方为系统真实输出数据:\n"; for (auto &r : ctx.tool_results) { p += "结果:" + r + "\n"; } p += "\n请根据以上Debian硬件数据直接、简洁地用中文回答用户问题。\n"; p += "严禁再调用工具,禁止输出 标签,直接给出最终答案。"; p += A_MK; return p;} DeepSeek-R1系列模型推理前会输出大量长文本思考内容,直接推送给客户端会刷屏,用户容易误以为RK3576程序卡死。增加前端显示过滤逻辑:完全屏蔽内部文本,进入思考区块时仅下发[思考中...]占位提示,提升 Debian 端侧交互体验:
if (ctx.tool_results.empty()) prompt = build_prompt_round0(ctx); // 首轮推理:允许发起shell工具调用else if (ctx.have_good_result) prompt = build_answer_prompt(ctx); // 存在有效Debian系统数据:进入纯作答流程else prompt = build_retry_prompt(ctx); // 所有命令执行失败:引导模型更换查询命令重试
占位提示仅做展示层过滤,模型完整思考文本仍会在程序内部缓存,不影响工具标签识别与推理逻辑。
可以怎么拓展
•多工具接入:除Debian原生shell外,可拓展文件读写、HTTP网络请求、外设传感器采集、GPIO硬件控制等工具,让模型从查询板卡状态升级为自主操控RK3576硬件;
•升级新版RKLLM SDK:新版SDK原生支持Function Calling、KV缓存续推理,省去每轮推理完整Prefill开销,大幅提升RK3576 Debian设备推理速度;
•Prompt缓存+多模型切换:缓存固定系统提示词降低预处理耗时;简单任务使用小尺寸快速模型,复杂设备任务使用1.5B推理模型,平衡端侧性能与效果;
•定时巡检Agent:后台定时器常驻运行,模型定期自动执行Debian系统监控命令,主动上报RK3576内存、温度、负载异常,实现无人值守设备运维。
值得借鉴的设计范式
设计 | 解决什么问题 |
在 RK3576 无原生 Function Calling 的模型上实现工具调用,仅依赖 Prompt 约定,无模型改造成本 | |
tool_pending 状态机 + 兜底扫描 | 不依赖 RKLLM SDK 未标准化的 abort 接口,端侧推理流程稳定可控 |
全新独立 "作答任务"Prompt(不回喂历史) | 根治R1小模型复读、无限循环问题,适配RK3576 Debian推理场景 |
posix_spawn 替代fork 创建子进程 | 解决4GB内存RK3576开发板执行shell时OOM崩溃问题,低内存端侧通用 |
命令去重 / 调用次数上限 / 失败重试 | 约束1.5B小模型逻辑缺陷,保证Debian端侧Agent流程收敛 |
思考内容隐藏 + 占位提示 | 优化 RK3576 设备人机交互,消除用户程序假死误判 |
这套截流式工具调用+中断续跑方案通用性极强:无需模型原生工具微调、不依赖高端SDK特性,完全依靠应用层自定义协议与状态机实现。其中posix_spawn规避fork内存溢出、输出长度限流防日志雪崩等设计,对所有RK系列、内存受限Linux/Debian端侧LLM工程落地均具备参考价值。
结语
RK3576端侧硬件资源有限,大模型工具调用落地处处受限,但本套落地方案证明:即便仅使用1.5B蒸馏推理模型、老旧同步RKLLM SDK、4GB内存嵌入式开发板,依靠分层协议、内存优化、状态机容错的工程设计,依然可以搭建一套能够自主调用Debian 系统shell、操控本地硬件的完整 Agent。端侧大模型发展不只追求更大参数量,更要依靠精细化工程方案,让模型真正能够读懂、使用身边嵌入式设备。
触觉智能Purple Pi OH2开发板,基于触觉智能RK3576核心板SOM7609系列+底板架构,搭载4核A72+4 核A53+M0多核异构处理器,主频2.2GHz,集成 6Tops NPU,轻松应对 AI 推理、边缘计算与轻量级深度学习。配套完善 SDK、丰富资料与Demo,适用于嵌入式工程师项目选型、创客开发科研。
触觉智能SOM7609系列核心板仅40.5×40.5mm 超小尺寸,专为空间受限场景打造。基于 RK3576/RK3576J SoC,集成高性能GPU与VPU,支持4K视频编解码与多屏异显;提供PCIe、USB3.2、双路千兆以太网、MIPI-DSI/CSI、eDP、CAN、SPI、I2C 等丰富接口,灵活扩展。支持Linux、Android、开源鸿蒙OpenHarmony等丰富系统,配套硬件设计指南、驱动源码与技术支持,助力产品快速落地。
