harness — 自主对话
harness 是 niuma_code 的默认模式。无需命令——描述任务,LLM 在工具循环中自主探索完成。
工作原理
你输入任务 → LLM 读取文件 → 编辑代码 → 运行命令 → 检查结果 → 完成
模型在 tool-use 循环中自主决策:调用工具、评估结果、决定继续或停止。没有预先规划——初始输入越清晰,执行越精准。
架构
harness 采用三层架构:
ChatService (对话编排: 召回→对话→更新)
└── HarnessEngine (工具循环内核)
├── StreamEngine (单轮流式传输 + watchdog 重连)
└── ToolExecutor (工具权限检查 + 批量执行)
HarnessEngine 是核心引擎,负责:
- 构建请求(注入工具定义 + 系统 prompt)
- 调用 StreamEngine 发起流式请求
- 若 LLM 返回 tool_use → ToolExecutor 执行工具 → 将结果追加到消息 → 重复
- 若 LLM 返回纯文本 → 循环结束,输出最终回复
工具类别
| 类别 | 工具 | 说明 |
|---|---|---|
| 知识图谱 | kg_find_symbol, kg_list_classes, kg_get_callers |
代码结构查询 |
| Bash | execute_bash |
Shell 命令执行(含权限门) |
| 文件 | read_file, write_file, edit_file, glob_files, grep_content |
文件读写与搜索 |
| 联网搜索 | web_search |
联网搜索(中继 API 服务端执行) |
| 子代理 | spawn_subagent |
启动子代理处理独立子任务 |
首轮默认使用全量工具,LLM 自行决策调用哪些。
循环控制
自然停止
LLM 不返回 tool_use 块时,循环自然结束。
死循环检测
连续 3 轮工具调用签名(工具名+入参)完全相同 → 判定原地打转 → 自动停止,进入总结阶段。
用户取消
按 Esc 或 Ctrl+C 随时取消生成,保留已输出的部分回复。
错误处理
API 错误自动重试
| 故障类型 | 响应方式 |
|---|---|
| 网络停滞(无事件) | Watchdog 检测后自动重连 |
| 单轮超时 | Watchdog 检测后自动重连 |
| 瞬时错误 (429/5xx/连接失败) | 指数退避重试(封顶 120s) |
| 消息结构异常 | 清理消息后重试 |
| 用户中断 | 保留已输出部分 |
Watchdog 守护线程每 10s 检查心跳,双判据触发关流:
- 停滞:距上次事件超过
API_TIMEOUT(连接黑洞) - 超时:整轮耗时超过
API_ROUND_MAX(thinking-only 长响应)
空回复保护
LLM 返回空文本且无 tool_use 时,线性退避重试(3s → 6s → 9s 封顶),最多 10 次后询问用户是否继续。TUI 模式下自动继续。
记忆召回集成
当历史记忆命中时,harness 自动在最终回复首尾包裹记忆引用:
[根据我的记忆 (YYYY-MM-DD),结合工具调用结果:]
... LLM 回复 ...
[以上内容基于历史记忆和实时工具调用结果综合生成]
工具调用过程中的中间文本不受 recall 包裹,仅最终答案受控。
何时使用 harness
| 适合 | 不太适合 |
|---|---|
| 探索性任务 | 有硬性截止时间的任务 |
| 快速编辑和修复 | 多步骤验证 |
| 需求模糊 | 并行独立任务 |
| 单一目标工作 | 复杂编排 |
示例:修复 Bug
> login 函数在 auth.py 中,当 email 为空时会抛出 KeyError。修复它。
harness 会:
- 读取
auth.py找到 login 函数 - 定位缺失的 email 检查
- 添加输入验证
- 运行测试(如有)
- 报告修复结果
示例:代码生成
> 创建一个带 email 验证的用户注册 REST API 端点
harness 会:
- 检查现有项目结构
- 识别框架和模式
- 生成端点代码
- 添加验证逻辑
- 创建或更新测试
最佳实践
表述具体
# 好 — harness 精确知道要做什么
> 在 services/user.py 的 UserService 类中添加 delete_user 方法,
通过设置 is_active=False 进行软删除,并记录日志。
# 模糊 — harness 需要猜测
> 修复 user service
提供上下文
# 好 — 足够的上下文
> 项目使用 FastAPI + SQLAlchemy。为 GET /users 端点添加分页,
使用 limit/offset 参数。
# 缺少上下文 — harness 需要自行发现
> 添加分页
每次一个目标
harness 最适合单一明确目标。对于多个任务,可以:
- 合并为一个描述清晰的请求
- 使用
/loop进行结构化多步骤工作 - 分开发送消息
harness vs /loop
| 方面 | harness | /loop |
|---|---|---|
| 计划 | 模型内部决策 | 显式计划 + 用户确认 |
| 执行 | 自主流程 | 结构化轮次 + 逐步验证 |
| 验证 | 隐式(模型自检) | 每个任务显式验证命令 |
| 失败处理 | 死循环检测自动停止 | 单任务 3 次自纠重试 |
| 用户控制 | 仅取消 | 每步可确认/排除/修改 |
| 适合 | 模糊、探索性任务 | 可分解、可验证的任务 |
用 harness 让模型自己搞定。 用 /loop 获得结构化执行、验证和检查点。