Skill.md
Query Loop Implementation
很多 AI 产品一开始只有一次模型调用。只要加入工具调用,一次调用就不够了:模型需要请求工具、读取工具结果、基于 observation 继续判断,然后选择继续调用工具或输出最终答案。
这个 skill 把这套模式整理成可上线的产品基础设施。
核心架构
使用三个边界:
ConversationManager
负责持久状态:session id、已保存 messages、用户设置、权限上下文、用量和预算。
QueryLoop
负责单次任务回合:调用模型、检测 tool call、执行工具、追加 tool result,并决定继续还是停止。
ToolRuntime
负责工具注册表:schema、校验、权限检查、执行、错误格式化和结果大小限制。
最小可用 Loop
第一版生产实现应该保持克制:
for (let turn = 1; turn <= maxTurns; turn++) {
const response = await model.generate({ messages, tools })
messages.push(response.message)
const toolCalls = extractToolCalls(response.message)
if (toolCalls.length === 0) {
return { status: "completed", finalMessage: response.message, messages }
}
for (const call of toolCalls) {
const result = await tools.execute(call, { signal, messages })
messages.push(makeToolResultMessage(call.id, result))
}
}
return { status: "max_turns", messages }
模型之所以能在工具调用后继续判断,是因为 loop 把 tool_result message 追加进去后再次调用模型。
安全要求
- 必须有
maxTurns。 - 支持 abort signal 和请求超时。
- 对所有模型生成的工具参数做 schema 校验。
- 任何副作用发生前先做权限检查。
- 跟踪 token、成本和运行时预算。
- 工具输出追加到历史前必须限制大小。
- 可恢复工具错误以 tool result 形式返回。
- 权限拒绝、预算耗尽、重复失败或 fatal tool error 时终止。
适用场景
当你要实现或审查这些能力时使用:
- 聊天或 workflow 产品里的工具调用
- function calling loop
- ReAct 风格的 reasoning-action-observation 循环
- query engine 或 agent runtime
- 类 Claude Code 的 agent loop
- tool result 回传和继续判断逻辑
- 最大轮次、超时、预算和权限 guardrail
刻意不处理什么
这个 skill 不负责上下文窗口管理。裁剪、检索、摘要和压缩应该放在单独的 context management 层。Query loop 接收 messages,返回更新后的 messages,专注于确定性的控制流。