用户的话会被整理成 spec。后面的校验、追问、确认和执行,交给本地脚本处理。
聊天机器人的命令格式越多,用户越容易忘。
提醒、值日、课程表、文件修改、脚本生成、仿真、部署,这些任务如果都要求用户记住精确命令,最后一定会变成两种失败:用户换一种说法就解析失败,开发者继续往正则里补例外。
chatbot-qq 里的自然语言任务代理,是我对这个问题的一次整理。我不想让模型直接接管机器人,只让它做一件事:把自然语言目标变成结构化 spec。
执行任务的,仍然是本地脚本。
固定命令不够覆盖创建任务
固定命令适合管理动作。
比如“列出提醒”“删除某条提醒”“查看状态”这类请求,本来就有清晰格式,用确定性解析器最快,也最容易测试。
但创建任务不一样。用户通常不会按模板说话。他可能说:
每周日晚上提醒大家轮值,顺序按洗手台、拖地、厕所、轮休走。也可能说:
帮我把刚才那个脚本改成只能处理本地文件,改完发回来。这些话里有明确目标,只是没有按命令模板来写。如果机器人只盯着前缀和参数位置,很容易把它判成格式错误。
所以自然语言任务代理先判断:这是不是一个要完成的任务。是的话就进入任务代理,别急着回一段“用法”。
模型只做结构化解析
我不希望模型直接执行任务。
模型适合理解一句话里隐含的任务类型、时间、对象、文件、检查方式和确认条件。不过模型不适合直接写状态、改文件、重启服务或决定哪些路径能碰。
所以 task-agent 这一层不能返回一段随意说明,而要给本地脚本一份固定格式的数据。
{ "task_type": "script_create_and_run", "title": "生成数据统计脚本", "description": "统计近期消息并输出摘要", "language": "python", "output_path": "local_files/generated/summary.py", "run_after_create": true, "checks": ["syntax", "dry_run"]}这个 spec 还不是执行许可。它只是候选计划。
下一步必须进入 schema 校验、本地路径准备、缺字段处理、重复任务检查和执行器选择。只有通过这些本地规则,任务才会真的落地。
schema 是执行前的闸
自然语言代理最麻烦的通常不是怎么让模型听懂,而是后面的 schema。
每种任务都有自己必须填的字段:
weekly_rota要有星期、时间、任务顺序和当前分配。scheduled_reminder要有提醒周期、时间和提醒内容。file_modify_and_return要有源文件、修改要求、输出路径和检查项。script_create_and_run要有脚本语言、输出路径、是否运行和检查项。deploy_or_restart必须带确认门控。
模型输出后,脚本会检查字段类型、枚举值、时间格式、数组长度和对象数量。缺字段就标出来,不让模型顺手猜一个。
这个设计让模型的职责很窄:理解并填表。表不合法,就不能执行。
缺字段只问一个问题
命令机器人常见的失败回复是整段用法说明。
这对用户并不友好。用户已经表达了目标,机器人应该接着把任务补完整,而不是把格式文档甩回来。
自然语言任务代理的失败策略更像这样:
我已经识别到这是定时提醒任务,但还缺提醒时间。你要几点提醒?或者:
我已经识别到这是文件修改任务,但还缺源文件。请上传文件,或给出当前工作区里的文件路径。一次只问一个最关键的字段,用户补完之后继续同一个任务上下文。这样比“重新按格式发一遍”更接近真实协作。
文件和脚本任务必须限制工作区
文件修改、脚本生成这类任务最容易出问题。
用户的自然语言可能很短:“帮我改这个文件”“写个脚本跑一下”。如果不限制目录,模型很容易把任务扩展得过大。
所以任务上下文里反复强调几条规则:
- 只读写当前聊天工作区。
- 输入文件只能来自允许的归档目录。
- 输出文件必须写到
local_files/下的指定子目录。 - 不覆盖原始文件。
- 不读取凭据类文件、环境配置或私有日志。
- 不删除、移动、改权限,也不修改工作区外文件。
这些规则光写在给模型的说明里不够,还得在本地路径检查里再拦一遍。比如文件修改任务会解析相对路径,再确认目标路径仍在当前工作区内;脚本生成任务默认写入 local_files/generated/;修改后的文件放到 local_files/modified/。
模型可以建议路径,但最后路径是否合法,由脚本决定。
dry-run 不是装饰
脚本任务里我保留了 checks 字段,例如:
["syntax", "dry_run"]语法检查比较直接:Python 可以编译检查,JavaScript 可以 --check,PowerShell 可以做语法解析,Shell 可以 bash -n。
dry-run 前面还要有安全筛查。脚本里如果出现高风险删除、网络访问、子进程调用、敏感环境读取等模式,就不进入 dry-run。
这类检查并不完美,但它把“模型写了一个脚本”与“机器人真的执行脚本”隔开了一层。对聊天机器人来说,这层隔离很值。
部署和重启必须确认
部署、重启、reload 这类操作不能静默执行。
在任务 spec 里,deploy_or_restart 明确带着:
{ "requires_confirmation": true}执行器看到这类任务后,不直接动服务,而是返回确认门控:动作是什么,目标是什么,原因是什么,如何确认,如何取消。
这能避免一句随口的“重启一下”变成真实线上动作。模型可以识别这是部署或重启意图,但执行前必须等管理员确认。
我最后还是补了 canary
自然语言入口很容易做出一个能跑通的 demo,但我不太敢只靠手试。
我更关心这些事有没有被自动验证:
- Responses 模式和 Chat Completions 模式都能拿到模型输出。
- 解析请求里包含工作区范围和禁止危险文件操作的规则。
- 模型只返回 JSON,不靠自由文本执行。
- 特定任务可以使用更低成本模型。
- 部署类任务会保留确认门控。
这些 canary 不需要连真实 QQ,也不需要真实模型长期在线。它们用 mock 请求验证桥接层构造的上下文、endpoint、模型参数和关键安全规则。
至少它能保证桥接层没有在关键规则上跑偏。
这次做完后的想法
这次我没有把目标放在“让机器人更会聊天”上。更实际的问题是:用户可以正常说话,系统内部仍然按 spec、schema、执行器和检查项来走。
我现在更倾向于把这类系统拆成五层:
用户目标-> 任务分类-> 结构化 spec-> 本地校验和执行器-> 回执、产物和检查结果模型站在中间,只负责把自然语言变成机器可检查的计划。
只要模型别越过这条线,机器人就可以听懂自然语言,同时把执行部分留在可检查、可撤回的流程里。
继续读