gogo-agent

我给 Agent 加了哪些关键配置

先看 MasterAgent 构建时的完整配置,后面逐项拆解:

TL;DR

先看 MasterAgent 构建时的完整配置,后面逐项拆解:

先看 MasterAgent 构建时的完整配置,后面逐项拆解:

// MasterAgent#build(节选)
ReActAgent agent = ReActAgent.builder()
 .name("MasterAgent")
 .description("智能差旅主智能体....")
 .model(xxModel)                    // ① 模型分层
 .toolkit(toolkit)                          // ⑧ 工具集(含子智能体)
 .toolExecutionContext(masterToolCtx)              // ⑨ 透明上下文注入
 .toolExecutionConfig(ExecutionConfig.builder()     // ③ 工具超时 + 重试
    .timeout(Duration.ofMinutes(TOOL_TIMEOUT_MINUTES))
    .maxAttempts(3)
    .build())
  .memory(AgentMemoryFactory.create(stableModel))     // ⑤ 自动压缩记忆
  .longTermMemory(longTermMemory)            // ⑥ 长期记忆
  .longTermMemoryMode(LongTermMemoryMode.AGENT_CONTROL)
  .hooks(List.of(xxx))   // ⑦ Hook 编排
  .sysPrompt(PromptLoader.load("master-agent-system.md"))// ⑩ 系统提示词
  .maxIters(MAX_ITERATIONS)                              // ② 迭代上限
  .generateOptions(xxx)                      // ④ 上下文缓存
        .build();

这些配置分四类目标:控成本(①④⑤)、保稳定(②③⑦)、管记忆(⑤⑥)、做扩展(⑧⑨⑩)。下面逐项展开。

1.模型分层:按「贵不贵」分角色

我们没有全局用一个模型,而是在 ModelConfig 里定义了4档,按任务价值挑模型:

✅用了哪几种模型,分别用在哪?

模型的分配我们是「按任务价值 + 是否需要慢思考」两个维度切的: 最强档 qwen3.7-max:留给核心决策链。其中主编排和行程单管理用不开思考的版本(要快、要能利用隐式缓存);而预订执行和行程规划这两个最复杂、最容易出错的环节,特意换成 LLMentor

2.maxIters:给 ReAct 循环上「保险丝」

ReActAgent 是「推理→调工具→再推理」的循环,不设上限,模型一旦陷入死循环会烧钱烧到超时。我按 Agent 复杂度给了不同上限:

.maxIters(MAX_ITERATIONS)   // MasterAgent=15, Plan=15, Manage/Booking=10, Info=5
Agent maxIters 依据
MasterAgent / ItineraryPlanAgent 15 要多轮协调子 Agent / 搜比价,步骤最多
ItineraryManageAgent / BookingAgent 10 单域内多步操作
InfoAgent 5 查完就答,无需长链

越靠近纯查询,上限越低——既是成本闸,也是「跑偏时尽早止损」的兜底。

3.工具执行:超时 + 自动重试(保稳定)

工具会调外部 API/CLI,网络抖动是常态。我给工具执行加了超时与重试策略。基类里沉淀了统一的默认配置:

// BaseSubAgent#getToolConfig —— 子 Agent 通用工具执行策略
public ExecutionConfig getToolConfig() {
    return ExecutionConfig.builder()
            .timeout(Duration.ofMinutes(1))                       // 单次工具最多等 1 分钟
            .maxAttempts(3)                                       // 最多 3 次(含首次)
            .initialBackoff(Duration.ofSeconds(3))                // 首次退避 3 秒
            .retryOn(error -> error instanceof java.io.IOException)// ★ 只对网络类错误重试
            .build();
}
✅工具并行执行&失败重试

在这套差旅助手里,Agent 每一轮 reasoning 之后往往要调用一批工具:查差旅政策、查订单、查目的地天气/资讯、调外部平台(tuniu / 签证 MCP)、甚至把子 Agent 当工具委托出去。这些调用有两个共同特征,直接决定了性 LLMentor

4.cacheControl(true):白嫖百炼隐式缓存

多轮对话里,system prompt 和历史前缀几乎不变,每轮重复计费很亏。开这个开关后,框架会自动给 system messages 与最后一条消息打上 cache_control,命中百炼的隐式缓存,重复前缀按缓存价计费:

.generateOptions(GenerateOptions.builder()
        .cacheControl(true)   // 框架自动对 system + 末条消息加 cache_control
        .build())
上下文工程——上下文缓存

... LLMentor

5.memory:自动压缩/卸载,抑制 token 膨胀

多智能体多轮对话,输入 token 会滚雪球。我没有用默认 memory,而是统一用 AgentMemoryFactory 产出一个调优过的 AutoContextMemory:

.memory(AgentMemoryFactory.create(stableModel))   // 用 stableModel 做压缩摘要(不用最贵模型)
上下文工程——记忆自动压缩

... LLMentor

6.长期记忆

跨会话记住用户的出行偏好,靠长期记忆。它按 userId 隔离(userId 从 TTL 上下文读出):

.longTermMemory(longTermMemory)                       // 按 userId 构建,跨会话保留偏好
.longTermMemoryMode(LongTermMemoryMode.AGENT_CONTROL) // 由 Agent 自主决定何时读写记忆
✅上下文工程——长期记忆

长期记忆让 Agent 跨会话记住"你是谁、你喜欢什么"——用户说过一次"我出差只坐高铁一等座、不订红眼航班",下个月再来规划时 Agent 自动带上这些偏好,无需重复交代。在 gogo-agent 里,它由 AgentScope 框架的 LLMentor

7. hooks:把横切能力插进生命周期(保稳定 + 可观测)

这是我配置最重的一块。Hook 是挂在 Agent 执行前后/工具前后的回调,我用它把大量横切逻辑从业务里剥离出来。以 BookingAgent 为例,挂了整整一串:

.hooks(List.of(
    dynamicTimeInjectionHook,    // 每轮注入当前时间(且保持 system 前缀稳定,利于缓存)
    new AutoContextHook(),       // 配合 AutoContextMemory 执行压缩/卸载
    cliResultCompressHook,       // CLI 结果去重压缩
    flightApiKeyHook, tuniuApiKeyHook,  // 第三方 API Key 注入
    rghUserIsolationHook,        // 酒店 CLI 按用户隔离本地目录/Token
    skillContentCollapseHook,    // 技能内容折叠
    sessionPersistenceHook,      // 会话持久化
    executionLoggerHook,         // 执行日志(可观测)
    toolCircuitBreakerHook,      // 工具熔断
    progressNotifierHook,        // 进度推送前端
    activeAgentPersistenceHook,  // 记录当前活跃 Agent(continuation 用)
    bookingPersistenceHook,      // 下单结果自动落库
    new PendingToolRecoveryHook()// 工具挂起恢复(Human-in-the-Loop)
))

几个关键 Hook 的价值:toolCircuitBreakerHook(熔断,防某个工具反复失败拖垮整体)、PendingToolRecoveryHook(支持工具挂起后等用户回复再续跑,跨节点恢复)、executionLoggerHook+progressNotifierHook(可观测 + 前端进度条)。不同 Agent 按需裁剪——InfoAgent 只挂了 8 个,没有预订相关的 Hook。

8. 工具与技能:并行、Shell 白名单、子智能体即工具

工具并行:预订/规划这类需要同时查多个数据源的 Agent 开了并行工具执行:

Toolkit toolkit = new Toolkit(ToolkitConfig.builder().parallel(true).build());

技能 + 受限 Shell:BookingAgent 挂载 tuniu-cli 技能,并且用白名单严格限制可执行命令,防止模型执行任意命令:

skillBox.registerSkill(skillRepository.getSkill("tuniu-cli"));
ShellCommandTool shellTool = new ShellCommandTool(
        null,
        Set.of("tuniu", "env", "bash", "cat", "grep", "date", "which", "ls"),  // ★ 命令白名单
        null);
skillBox.codeExecution().withShell(shellTool).withRead().withWrite().enable();

子智能体即工具:MasterAgent 把 4 个子 Agent 用 SubAgentProvider 注册成工具,让主模型像调工具一样调度子 Agent(详见「智能体清单」文档)。

9. toolExecutionContext:对 LLM 透明的上下文注入

把 userId/sessionId(从 TTL 读出)注入工具执行上下文,工具方法能直接拿到,但不出现在 LLM 的 function schema 里:

.toolExecutionContext(createToolCtx())   // BaseSubAgent: register(AgentSessionContext)

既省 token 又防止模型篡改用户身份

✅如何避免模型幻觉导致用户id传错?

我们在代码中提供了很多工具,这些工具需要去做数据库的CRUD操作,比如查询行程单、取消行程单、查询用户的API KEY等。 这些工具,我们可以通过提供参数的方式,让LLM传入上下文中的用户ID,但是实际运行时会发现,有的时候LLM回传错,多 LLMentor

10. RAG 知识库:knowledge + RAGMode.AGENTIC

InfoAgent 挂了三个向量知识库,并用「智能体自主检索」模式:

// InfoAgent#build(节选)
.model(stableModel)   // 信息查询用中档模型即可
.knowledge(attractionKnowledge)               // 景点
.knowledge(corporateTravelPolicyKnowledge)    // 差旅政策
.knowledge(corporateTravelGuidelinesKnowledge)// 差旅指南
.ragMode(RAGMode.AGENTIC)   // 由模型自行决定是否检索、检索什么

AGENTIC 模式让模型自主判断「这个问题要不要查知识库、查哪个」,而不是每次都盲目检索。

版本提示

模型、框架与接口会持续变化。涉及版本号、参数与生产配置时,请在实践前对照对应官方文档。

LLMentor系统化学习大模型应用工程

内容来自个人课程知识库备份,并经过结构化整理。技术版本持续演进,生产使用前请结合官方文档验证。