Agent 人机协作闭环:AI 做事,人做决策,别把 Loop 写成死循环
Agent 人机协作闭环:AI 做事,人做决策,别把 Loop 写成死循环
一、Agent 替你写完了代码,然后直接 git push 到了 master
自动化的诱惑让工程师不断给 Agent 开放权限。
先是读取文件,然后是修改文件。
接着是执行命令,最后是 git push。
每一步都合理,直到某天 Agent 执行了 rm -rf /tmp/* 而路径变量恰好为空。
这不是虚构场景。
AutoGPT 和 BabyAGI 等自主 Agent 的早期用户,都经历过类似事故。
Agent 的 Loop 机制让模型可以不断调用工具、获取反馈、再调用工具。
这个循环里缺少一个关键环节——人的决策。
自主 Agent 和辅助 Agent 有本质区别。
前者追求闭环,后者追求人机协作。
工程落地中,辅助 Agent 远比自主 Agent 有价值。
二、人机协作 Loop 的设计模式
Agent 的标准 Loop 是"思考-行动-观察-再思考"。
人机协作模式在关键节点插入人工确认。
flowchart TB
A[用户输入任务] --> B[LLM 分析并生成计划]
B --> C{计划是否需要人工确认?}
C -->|高风险操作| D[展示计划给用户]
D --> E{用户批准?}
E -->|是| F[执行工具调用]
E -->|否| G[重新规划]
G --> B
C -->|低风险操作| F
F --> H[获取工具结果]
H --> I[LLM 分析结果]
I --> J{任务完成?}
J -->|是| K[汇总输出给用户]
J -->|否| L{是否超过最大轮次?}
L -->|是| M[请求用户干预]
L -->|否| C
三个关键的人机协作点:
第一,高风险操作前的人工确认。
第二,超过 N 轮推理后的人工介入。
第三,置信度低于阈值时的降级处理。
三、带人工确认的 Agent Loop 实现
package agent
import (
"context"
"fmt"
"log"
"time"
)
// RiskLevel 操作风险等级
type RiskLevel int
const (
RiskRead RiskLevel = 0 // 只读操作
RiskWrite RiskLevel = 1 // 数据写入
RiskExec RiskLevel = 2 // 命令执行
RiskDeploy RiskLevel = 3 // 部署操作
)
// Action 单步操作
type Action struct {
Tool string `json:"tool"`
Params map[string]any `json:"params"`
RiskLevel RiskLevel `json:"risk_level"`
Reason string `json:"reason"`
}
// HumanConfirmCallback 人工确认回调
type HumanConfirmCallback func(action Action) (bool, error)
// AgentLoop Agent 执行循环
type AgentLoop struct {
llmClient LLMClient
toolRegistry *ToolRegistry
maxSteps int
confirmThreshold RiskLevel // 超过此等级需要人工确认
humanConfirm HumanConfirmCallback
stepTimeout time.Duration
}
// Config Agent 配置
type Config struct {
MaxSteps int
ConfirmThreshold RiskLevel
StepTimeout time.Duration
}
// DefaultConfig 默认配置:10 步限制,写入以上需确认
func DefaultConfig() Config {
return Config{
MaxSteps: 10,
ConfirmThreshold: RiskWrite,
StepTimeout: 30 * time.Second,
}
}
// NewAgentLoop 创建 Agent 循环
func NewAgentLoop(
llm LLMClient,
registry *ToolRegistry,
confirm HumanConfirmCallback,
cfg Config,
) *AgentLoop {
return &AgentLoop{
llmClient: llm,
toolRegistry: registry,
maxSteps: cfg.MaxSteps,
confirmThreshold: cfg.ConfirmThreshold,
humanConfirm: confirm,
stepTimeout: cfg.StepTimeout,
}
}
// Run 执行 Agent 任务
func (a *AgentLoop) Run(ctx context.Context, task string) (string, error) {
messages := []Message{
{Role: "system", Content: systemPrompt()},
{Role: "user", Content: task},
}
for step := 0; step < a.maxSteps; step++ {
// 超时保护
stepCtx, cancel := context.WithTimeout(ctx, a.stepTimeout)
defer cancel()
resp, err := a.llmClient.Chat(stepCtx, messages)
if err != nil {
return "", fmt.Errorf("第 %d 步 LLM 调用失败: %w", step+1, err)
}
// 模型决定不再调用工具,输出最终结果
if resp.ToolCall == nil {
log.Printf("[Step %d] 任务完成,输出最终结果", step+1)
return resp.Content, nil
}
action := Action{
Tool: resp.ToolCall.Name,
Params: resp.ToolCall.Args,
RiskLevel: a.assessRisk(resp.ToolCall),
Reason: resp.Content,
}
log.Printf("[Step %d] 计划执行: %s (风险: %d)",
step+1, action.Tool, action.RiskLevel)
// 🔑 高风险操作需要人工确认
if action.RiskLevel >= a.confirmThreshold {
log.Printf("[Step %d] 需要人工确认: %s", step+1, action.Tool)
approved, err := a.humanConfirm(action)
if err != nil {
return "", fmt.Errorf("人工确认异常: %w", err)
}
if !approved {
messages = append(messages, Message{
Role: "user",
Content: fmt.Sprintf("操作被拒绝。请换一种方式完成任务。被拒原因:用户不同意执行 %s。", action.Tool),
})
continue
}
log.Printf("[Step %d] 人工已批准", step+1)
}
// 执行工具调用
result, toolErr := a.toolRegistry.Execute(ctx, resp.ToolCall)
if toolErr != nil {
// 工具执行失败,告知模型
messages = append(messages, Message{
Role: "tool",
Content: fmt.Sprintf("工具 %s 执行失败: %v", action.Tool, toolErr),
})
continue
}
// 将工具结果注入对话
messages = append(messages,
Message{Role: "assistant", Content: resp.Content, ToolCall: resp.ToolCall},
Message{Role: "tool", Content: result},
)
}
return "", fmt.Errorf("超过最大执行步骤 (%d),任务未完成", a.maxSteps)
}
// assessRisk 评估操作风险
func (a *AgentLoop) assessRisk(tc *ToolCall) RiskLevel {
switch tc.Name {
case "read_file", "search", "list_directory":
return RiskRead
case "write_file", "update_database", "send_email":
return RiskWrite
case "run_command", "execute_sql":
return RiskExec
case "git_push", "deploy", "restart_service":
return RiskDeploy
default:
return RiskRead
}
}
func systemPrompt() string {
return `你是一个 AI 助手。请逐步完成任务。
每一步你可以调用一个工具。
高风险操作会需要人工确认。`
}
四、人机协作的代价与适用边界
人工确认引入等待延迟。
用户可能不在电脑前,任务会卡住。
建议在确认机制中加入超时策略。
超时后降级为只读模式或暂停任务。
确认频率过高会导致"弹窗疲劳"。
用户最终会机械地点击"同意"。
需要根据历史行为动态调整确认阈值。
用户一贯批准的操作,可以降低确认等级。
不适合人机协作的场景:
批量处理成千上万条数据的任务(每步确认不可行);
用户提供明确授权脚本的自动化运维;
非交互式的后台定时任务。
五、总结
Agent 的 Loop 必须有退出机制,不能无限循环。
人机协作闭环在高风险操作前插入人工确认。
风险分级机制让确认策略可配置。
确认超时和频率控制防止弹窗疲劳。
目标是让 AI 有效率地做事,关键决策保留在人手里。
更多推荐
所有评论(0)