> 由 800claw 团队出品
团队: 800claw
版本: v1.1.5
创建时间: 2026-05-10
更新时间: 2026-06-10
适用场景: 用户在消息中发送文件,经确认后提交到同一局域网内的打印网关出纸
风险等级: 低 — 仅限用户指定的局域网打印网关,详见下方“权限与安全说明”
800claw Smart Print Gateway 是部署在用户本地局域网(如办公室、家庭 Wi‑Fi)的打印网关服务,基于 FastAPI + uvicorn 构建。用户通过飞书/微信/企微/钉钉等给“小龙虾”发送文件;助手在用户确认后,调用该网关的 HTTP API,将文件提交到同一局域网内的物理打印机。
> 本技能不是通用内网扫描器或远程控制工具。它只做一件事:把用户明确要打印的文件,发送到用户主动提供的局域网打印网关地址。
> 需要配合智能打印网关一起使用,更详细的技能场景与说明,可以按需 查看使用指南。
用户 (飞书/微信/企微/钉钉等) ──→ openclaw/nanobot/hermes agent等AI智能体 🐈 ──→ 800claw Smart Print Gateway ──→ 局域网打印机
│ (首次对接后记入长期记忆)
│
├── print_file.py (提交打印任务)
├── check_print_service.py (健康检查)
└── gen_print_guide.py (生成使用说明文档)
print_file.py 向已对接的局域网网关地址提交打印任务供 skill-vetter 及人工审查参考。本技能权限范围严格限定于局域网打印场景:
| 权限 | 用途 | 范围与约束 |
|---|---|---|
| ------ | ------ | ------------ |
| 网络 | 调用打印网关 HTTP API | 仅连接用户首次提供或已记入长期记忆的局域网地址(如 192.168.x.x:8089);不访问公网、不扫描网段 |
| 文件读取 | 读取待打印文件 | 仅读取用户发送或明确指定的打印文件;不上传至第三方 |
| 鉴权 | X-API-Key 请求头 | 首次由用户提供;验证成功后写入工作区长期记忆;不写入技能包、不上传第三方 |
| 命令执行 | 运行技能目录内 Python 脚本 | print_file.py / check_print_service.py / gen_print_guide.py |
为何使用 Python socket? 部分 AI 运行环境会拦截 requests/curl 对私有 IP(RFC 1918)的出站请求。脚本因此用 socket 构造标准 HTTP/1.0 请求,与用户局域网内的打印网关通信,这是局域网打印的技术实现,不涉及访问其他网络资源或规避系统安全策略。
用户确认:收到文件后必须先询问是否打印,不得自动提交(见下文 §4)。
术语(全文统一):
print_file.py、技能默认值、示例命令里写死用户专属地址或 KeyMEMORY.md / USER.md / 工作区配置,由具体 Agent 框架决定)> 网关地址和 API Key 不能硬编码在技能代码或脚本默认值中。
生命周期:
/health 或 /openapi.json 确认连通正确做法 ✅:
用户: 网关地址是 192.168.1.100:8089,Key 是 162013
助手: → 验证连通,写入长期记忆
用户: 打印合同.docx
助手: 收到文件,需要打印吗?(默认 A4 竖版灰度 1 份)
用户: 好的
助手: → 用已记录地址直接提交,不再询问网关
错误做法 ❌:
用户: 打印合同.docx
助手: 网关地址是什么?(长期记忆中已有,不应再问)
/openapi.json 发现 API首次连接新的网关地址后,先访问 /openapi.json 路径,获取 OpenAPI 规范,以了解当前网关的:
X-API-Key)# 获取 API 文档(OpenAPI JSON)
GET {gateway_url}/openapi.json
# 或通过 Swagger UI 页面查看
GET {gateway_url}/docs
受保护接口(如 /print、/printers、/status/{job_id})要求 X-API-Key 请求头。
headers = {
'X-API-Key': '长期记忆中记录的 API Key',
}
> X-API-Key 首次由用户提供;对接验证成功后与网关地址一并写入工作区长期记忆,日常打印直接使用。不写入技能包、不上传第三方。
> ⚠️ 收到文件后不得直接提交打印任务。 必须先询问用户是否确认打印,等待用户明确回复确认后,才能将打印任务发送给网关。
正确做法:
用户发送: 合同.docx
助手: 收到文件“合同.docx”,需要打印吗?(默认 A4 竖版灰度 1 份)
用户: 好的,打印吧
助手: → 提交打印任务
错误做法 ❌:
用户发送: 合同.docx
助手: → 直接提交打印任务(未经用户确认)
> ⚠️ 打印机名称不能写死。 每次提交打印任务前,通过 /printers 接口动态获取当前网关所在机器上的可用打印机列表(指 API 调用,不是向用户询问)。
# 获取可用打印机列表(需 X-API-Key)
GET {gateway_url}/printers
# 响应示例: {"printers": ["HP Color Laser MFP 178 179", "Microsoft Print to PDF", ...]}
> 关于默认打印机: 提交打印任务时,如果不传 printer_name 参数,网关会自动将打印任务发送到系统设置的默认打印机。大多数情况下用户不需要指定打印机,直接打印即可。如需指定特定打印机,先通过 /printers 获取完整名称再传入。
决策规则:若长期记忆中已有网关地址和 X-API-Key,跳过阶段 A,直接进入阶段 B;禁止在日常打印时再次询问网关地址。
1. 用户提供网关地址(如 "网关地址是 192.168.1.100:8089")和 X-API-Key
2. 助手访问 {gateway_url}/health 或 /openapi.json 验证连通
3. 助手访问 {gateway_url}/printers(带 X-API-Key)确认可用
4. 验证成功 → 将网关地址和 Key 写入长期记忆 → 告知用户已就绪
1. 用户发送文件
2. ⚠️ 助手必须询问用户是否确认打印,等待用户明确确认后,才能提交打印任务
3. 用户确认 → 用长期记忆中的地址/Key 调用 print_file.py 提交打印
4. 查询任务状态 → 回复用户
⚠️ 防抖注意事项:
| 项目 | 内容 |
|---|---|
| ------ | ------ |
| 服务地址 | http://192.168.1.100:8089 |
| 网关版本 | v1.0.0 |
| 框架 | FastAPI + uvicorn |
| 目标打印机 | 局域网默认打印机(通过 /printers 动态获取) |
| 后端 | Windows 打印驱动 |
| 鉴权方式 | X-API-Key(受保护接口需要) |
/openapi.json 返回为准)以下为当前网关 v1.0.0 的接口清单:
| 方法 | 路径 | 说明 |
|---|---|---|
| ------ | ------ | ------ |
| GET | / | 服务横幅 |
| GET | /health | 健康检查 + 版本信息 |
| GET | /docs | Swagger UI 文档页面 |
| GET | /openapi.json | OpenAPI 规范文档 |
| 方法 | 路径 | 说明 |
|---|---|---|
| ------ | ------ | ------ |
| GET | /printers | 列出可用打印机 |
| POST | /print | 提交打印任务 |
| GET | /status/{job_id} | 查询任务状态 |
| GET | /jobs/recent | 查看最近打印任务 |
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| ------ | ------ | ------ | ------ |
| file | 文件 | ✅ | .docx/.xlsx/.pdf/.txt/.png/.jpg |
| printer_name | string | ❌ | 指定打印机;不传则使用系统默认打印机 |
| copies | int | ❌ | 份数,默认 1 |
| color_mode | string | ❌ | 颜色模式(如 gray) |
| layout | string | ❌ | 页面布局(如 portrait) |
| duplex | string | ❌ | 双面打印(如 simplex) |
| force | bool | ❌ | 强制打印,跳过重复任务检测 |
> 防抖机制(Dedup):
> - 相同打印任务在 DEDUP_WINDOW_MINUTES 时间窗口内重复提交,网关返回 409 Conflict
> - 如需强制打印重复任务,设置 force=true
> - 超时后应先 GET /status/{job_id} 查询状态,再决定是否重新 POST
技能目录下包含 print_testing.docx,作为默认的打印测试文件。当需要测试打印功能时,使用此文件进行测试。
技能目录下包含以下脚本:
print_file.py提交打印任务到 Gateway。
# 打印 1 份
python3 print_file.py 文件.docx --host 192.168.1.100 --port 8089 --api-key 162013
# 打印多份
python3 print_file.py 文件.pdf --host 192.168.1.100 --port 8089 --api-key 162013 --copies 3
参数:
| 参数 | 说明 |
|---|---|
| ------ | ------ |
file | 要打印的文件路径(必填) |
--host | 网关地址(必填) |
--port, -p | 网关端口(必填) |
--api-key, -k | X-API-Key 鉴权密钥 |
--copies, -c | 份数,默认 1 |
--printer | 指定打印机名称(不传则使用系统默认打印机) |
--color-mode | 颜色模式(如 gray) |
--layout | 页面布局(如 portrait) |
--duplex | 双面打印(如 simplex) |
--force | 强制打印,跳过重复任务检测 |
check_print_service.py检查打印服务是否在线。
# 检查服务状态
python3 check_print_service.py health --host 192.168.1.100 --port 8089
# 查看打印机列表(需 API Key)
python3 check_print_service.py printers --host 192.168.1.100 --port 8089 --api-key 162013
# 查看 OpenAPI 文档
python3 check_print_service.py openapi --host 192.168.1.100 --port 8089
# 查看最近打印任务(需 API Key)
python3 check_print_service.py recent --host 192.168.1.100 --port 8089 --api-key 162013
gen_print_guide.py生成面向普通用户的使用说明文档(Word)。
# 生成到当前目录
python3 gen_print_guide.py
# 生成到指定目录
python3 gen_print_guide.py /path/to/output/
# 输出: 一酷瑶SmartPrint使用说明.docx
本技能仅与用户主动提供的局域网打印网关通信(私有 IP,如 192.168.x.x)。
部分 AI 运行环境不允许 curl / requests 访问私有 IP。因此脚本使用 Python socket 构造标准 HTTP/1.0 请求 调用网关 API——与浏览器/打印客户端访问局域网设备同理,仅限打印网关,不用于其他目的。
import socket, json
def http_request(method, host, port, path, headers=None, body=None):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(10)
try:
s.connect((host, port))
req = f'{method} {path} HTTP/1.0\r\nHost: {host}:{port}\r\n'
if headers:
for k, v in headers.items():
req += f'{k}: {v}\r\n'
if body:
req += f'Content-Length: {len(body)}\r\n'
req += 'Connection: close\r\n\r\n'
if body:
req = req.encode() + body
else:
req = req.encode()
s.sendall(req)
chunks = []
while True:
chunk = s.recv(4096)
if not chunk:
break
chunks.append(chunk)
data = b''.join(chunks)
header, _, resp_body = data.partition(b'\r\n\r\n')
status = int(header.split()[1])
try:
return status, json.loads(resp_body)
except:
return status, resp_body.decode()
finally:
s.close()
# 获取 OpenAPI JSON
status, spec = http_request('GET', host, port, '/openapi.json')
# 解析可用路径
for path, methods in spec.get('paths', {}).items():
for method, detail in methods.items():
print(f'{method.upper()} {path} - {detail.get("summary", "")}')
headers = {'X-API-Key': '用户提供的key'}
status, result = http_request('GET', host, port, '/printers', headers=headers)
当需要先生成文档再打印时:
| 项目 | 规范 |
|---|---|
| ------ | ------ |
| 库 | python-docx |
| 字体 | 微软雅黑(Microsoft YaHei) |
| 颜色 | 全黑 |
| 表格 | 无背景色,黑色边框 |
| 内容 | 控制在 1 页以内 |
| 限制项 | 说明 |
|---|---|
| -------- | ------ |
| 网关地址 | 不硬编码在技能内;首次对接后写入长期记忆,日常直接使用 |
| API 版本 | 每次通过 /openapi.json 动态发现 |
| 鉴权 | 受保护接口需 X-API-Key |
| 打印机列表 | 动态获取,不写死 |
| 网络范围 | 仅限用户指定的局域网打印网关(私有 IP);socket 用于兼容运行环境的 HTTP 限制 |
| 文件格式 | .docx / .xlsx / .pdf / .txt / .png / .jpg |
| 入口 | 仅限飞书“小龙虾”对话 |
| 防抖机制 | 相同任务在时间窗口内重复提交返回 409,需 force=true 强制打印 |
| 测试项 | 状态 |
|---|---|
| -------- | ------ |
| 服务健康检查(/health) | ✅ |
| 获取 OpenAPI 文档 | ✅ |
| 获取打印机列表(带 Key) | ✅ |
| A4 竖版打印(docx) | ✅ |
| 多份打印(copies=2) | ✅ |
| 文档生成(python-docx) | ✅ |
| 飞书消息驱动全流程 | ✅ |
| 重复打印防抖机制 | ✅ |
| 查看最近任务(/jobs/recent) | ✅ |
| 版本 | 日期 | 说明 |
|---|---|---|
| ------ | ------ | ------ |
| v1.0.0 | 2026-05-10 | 初始版本,基础打印功能 + 飞书集成 + X-API-Key 鉴权 |
| v1.1.0 | 2026-05-18 | 添加双面打印支持 |
| v1.1.1 | 2026-05-25 | 新增重复打印防抖机制(DEDUP_WINDOW_MINUTES)、/jobs/recent 端点、force/duplex/color_mode/layout 参数 |
| v1.1.2 | 2026-06-09 | 措辞优化:明确为局域网打印网关连接器,补充权限与安全说明,消除“绕过安全限制”等易误解表述 |
| v1.1.3 | 2026-06-10 | 措辞优化:SkillHub 展示格式(YAML frontmatter、元数据换行)、使用指南可点击链接 |
| v1.1.5 | 2026-06-10 | 澄清网关/API Key 记忆策略:拆分首次对接与日常打印流程,消除「不写死=每次询问」误解 |
共 2 个版本