- 工具循环:capture_image / get_robot_status / spawn_subagent - 子代理:技能超集(run_command 带超时截断、read_file / write_file) - V4L2 摄像头抓帧:MJPEG 优先零转码,YUYV+libjpeg 回退,/dev/video* 自动探测 - 时间戳注入:system prompt 会话级当前时间 + 工具结果执行时间 - CLI:--prompt-file / --camera / --camera-device / --model / --max-turns
79 lines
4.0 KiB
Markdown
79 lines
4.0 KiB
Markdown
# robot_agent — 基于 libhttp 的 DeepSeek 视觉机器人 Agent
|
||
|
||
C++20 机器人智能体骨架:命令行输入任务,调用 DeepSeek 视觉大模型(`deepseek-v4-flash-vision-exp`),通过**工具循环**驱动摄像头识图、状态查询、命令行执行与文件读写,后续可扩展硬件控制。
|
||
|
||
## 架构
|
||
|
||
```
|
||
用户任务(CLI 参数或 --prompt-file 文件)
|
||
└─ 主代理(run_chat_loop 工具循环)
|
||
├─ capture_image 拍照识图(真实摄像头 / 模拟图片)
|
||
├─ get_robot_status 查询机器人状态
|
||
└─ spawn_subagent 委派任务给子代理
|
||
└─ 子代理(技能超集,独立工具循环)
|
||
├─ run_command 执行 shell 命令(超时 + 输出截断)
|
||
├─ read_file / write_file
|
||
├─ capture_image / get_robot_status
|
||
└─ 返回结论 → 主代理综合回答
|
||
```
|
||
|
||
- **工具循环**:模型返回 `tool_calls` → agent 执行工具 → 结果回传 → 继续,直到模型给出最终回答(`--max-turns` 限轮)。
|
||
- **图片注入**:OpenAI 协议的 tool 消息只允许文本,工具返回的图片由主循环作为 `image_url` 注入下一轮。
|
||
- **时间戳**:会话开始时向 system prompt 注入一次当前时间(会话内不变);每个工具结果附 `工具执行时间`,供模型判断数据新旧。
|
||
- **摄像头**:V4L2 直采,优先 MJPEG(硬件编码零转码,最快),回退 YUYV + libjpeg 编码;设备常开复用;`/dev/video*` 自动探测。
|
||
|
||
## 依赖与构建
|
||
|
||
- g++(C++20)、libhttp(`libus_httpclient.so`)、Boost.JSON、libcurl、OpenSSL、libjpeg、pthread
|
||
- libhttp 需先编译:`cd ../libhttp && make`
|
||
|
||
```bash
|
||
make # 生成 ./robot_agent
|
||
make clean
|
||
```
|
||
|
||
## 使用
|
||
|
||
```bash
|
||
export DEEPSEEK_API_KEY=sk-xxx # 或用 --key
|
||
|
||
./robot_agent "看看环境里有什么" # 真实摄像头识图
|
||
./robot_agent "报告状态" # 状态查询
|
||
./robot_agent "列出当前目录文件" # 自动委派子代理执行命令
|
||
./robot_agent --prompt-file /tmp/task.txt # 从文件读取任务
|
||
./robot_agent "描述图片" --camera ./test.png # 模拟摄像头(读文件,便于离线测试)
|
||
```
|
||
|
||
| 参数 | 说明 | 默认 |
|
||
|---|---|---|
|
||
| `--prompt-file <文件>` | 从文件读取任务(与位置参数互斥) | — |
|
||
| `--camera <文件>` | 模拟摄像头:拍照工具读该图片 | 空 = 真实摄像头 |
|
||
| `--camera-device <设备>` | 摄像头设备 | 自动探测 `/dev/video*` |
|
||
| `--model <名称>` | 模型名 | `deepseek-v4-flash-vision-exp` |
|
||
| `--key <API_KEY>` | API key | 环境变量 `DEEPSEEK_API_KEY` |
|
||
| `--endpoint <URL>` | 接口地址 | `https://api.deepseek.com/chat/completions` |
|
||
| `--max-turns <N>` | 最大工具轮次 | 8 |
|
||
|
||
工具日志输出到 stderr(`[主代理][工具]` / `[子代理][工具]`),stdout 只输出最终回答,便于脚本管道。
|
||
|
||
## 代码结构
|
||
|
||
| 文件 | 职责 |
|
||
|---|---|
|
||
| `main.cpp` | CLI 解析、主代理工具注册 |
|
||
| `agent.hpp/cpp` | `run_chat_loop` 工具循环(主/子代理共用)、消息构造、时间戳注入 |
|
||
| `subagent.hpp/cpp` | 子代理:技能超集 + 独立提示词 |
|
||
| `tools.hpp/cpp` | `Tool`/`ToolRegistry` 与全部工具实现 |
|
||
| `camera.hpp/cpp` | V4L2 抓帧(MJPEG/YUYV、mmap、超时保护) |
|
||
|
||
## 扩展
|
||
|
||
- **加工具**:实现 `Tool{name, description, parameters(JSON Schema), execute}` 后 `registry.add(...)`。
|
||
- **工具返回图片**:`ToolResult.image_data_url` 填 data URL,主循环自动注入下一轮。
|
||
- **加子代理类型**:仿照 `subagent.cpp` 组装不同工具集与提示词。
|
||
- **接真实硬件**:把 `capture_image`/`get_robot_status` 的实现换成设备驱动调用即可,接口不变。
|
||
|
||
## 安全注意
|
||
|
||
`run_command` 会执行任意 shell 命令且无白名单/审批,仅建议在可信环境(你自己的机器人主机)运行;后续如需对外暴露,应先加命令审批或沙箱。
|