文章
harness相关
2026-08-11 23:42
更新于 2026-08-11 23:44
不依赖 LangChain 的 harness,含上下⽂压缩 + 兜底 + 持久化记忆
1. 最小 Agent 循环(agent.ts)
ask() 一次请求 = 记忆检索 → 上下文压缩 → ReAct 循环 → 兜底终止。
循环内是标准的 Function Calling 链路:
组装请求(system + 历史 + 工具 schema)
→ 模型返回 tool_calls(JSON 字符串参数)
→ 解析 + 校验 → 执行工具 → 结果以 role:tool 回传
→ 再请求模型 → 直接回答则终止
终止条件有三个:模型直接回答 / 超过最大步数 / 连续工具失败超阈值。
2. 工具调用异常兜底(agent.ts 的 executeToolWithRetry)
五层兜底,分层背:
- 工具不存在 → 报错 + 列出可用工具(白名单校验);
- JSON 解析失败 → 错误回传,模型修正重发;
- Schema 校验失败 → 讲清"缺哪个参数、该是什么类型";
- 执行异常 / 超时 →
retryable工具指数退避重试(200ms → 400ms,最多 2 次); - 仍失败 → 错误作为 tool 消息喂回模型,下一轮自我纠错。
关键认知:错误不抛给程序,而是变成"观察结果"回传模型;业务错误(订单不存在)与工具错误分开,前者不触发重试。
3. 上下文压缩(context.ts)
两层策略 + 兜底:
- 滑动窗口:只保留最近 N 轮完整对话;
- 滚动摘要:窗口外的历史交给模型压成一条摘要消息(摘要标记
summary,不参与二次摘要); - 兜底:压缩后仍超预算 → 从最旧消息开始丢;摘要生成失败 → 占位文本,不影响主流程。
token 估算用"中文 1 字 ≈ 1 token、英文 4 字符 ≈ 1 token"的近似算法,生产可换 tiktoken。
4. 持久化记忆(memory.ts)
- 存储:JSON 文件(重启不丢),生产可换 SQLite / Redis / 向量库;
- 检索:零依赖的词重叠打分(CJK 二元组 + 英文词),生产换 embedding + ANN,思路一致;
- 读写入口:模型通过
remember_fact/recall_memory工具自主读写; - 注入:每次请求自动把 top-k 相关记忆拼进 system prompt(短期记忆 = 会话内 messages,长期记忆 = 这个文件)。