gogo-agent

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

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

TL;DR

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

我们在代码中提供了很多工具,这些工具需要去做数据库的CRUD操作,比如查询行程单、取消行程单、查询用户的API KEY等。 这些工具,我们可以通过提供参数的方式,让LLM传入上下文中的用户ID,但是实际运行时会发现,有的时候LLM回传错,多数情况会传入一些默认值,比如prompt中的示例值会被传进来,这种情况一旦发生,轻则导致流程失败,重则会导致水平权限漏洞,导致数据泄露等。 这个问题在 gogo-agent 里其实是用「架构上根本不让模型碰 userId」来解决的,而不是靠提示词去约束模型别传错。核心思路一句话:userId 永远不进入 LLM 的可见范围,所以模型没有机会去"填"它,也就无从幻觉。 具体分三层来看。 第一层是透明注入,绕开 function schema。工具方法需要的 userId/sessionId 不是声明成 LLM 可见的工具参数,而是通过 AgentScope 的 ToolExecutionContext 旁路注入的。你在 BaseSubAgent.createToolCtx() 里把 AgentSessionContext 注册进去:

public static ToolExecutionContext createToolCtx() {
    AgentSessionContext sessionCtx = AgentSessionContextHolder.get();
    return sessionCtx != null
            ? ToolExecutionContext.builder().register(sessionCtx).build()
            : ToolExecutionContext.empty();
}

AgentSessionContext 的 Javadoc 也写得很明确——这些参数「无需标注 @ToolParam,对 LLM 完全透明」。也就是说模型在做 function-calling 时,看到的工具签名里压根没有 userId 这个字段,它既看不到、也无法在生成的 tool_call 参数里塞一个 userId。框架在真正反射调用工具方法时,才把上下文里的 userId 填进去。模型能幻觉的前提是"这个坑要它来填",而这个坑从来没暴露给它。 第二层是身份的唯一可信来源是 sa-token,不是对话内容。userId 在 Controller 入口就由登录态确定并种进 TTL:

String userId = StpUtil.getLoginIdAsString();   // 来自鉴权,不是用户输入
AgentSessionContextHolder.set(new AgentSessionContext(userId, sessionId));

这条链从头到尾 userId 都由 AgentSessionContextHolder.get() 读出,全程没有任何一处从模型的输出里去解析 userId。哪怕用户在对话里说"我是工号 12345,帮我查 67890 的差旅单",模型转述的这些数字也进不了 AgentSessionContext——落库、调 CLI、隔离目录时用的 userId 始终是鉴权得到的那个。 第三层是不可变 + 断言兜底。AgentSessionContext 里 userId 是 final 且构造时 Assert.notNull,一旦设定就不能被中途改写。而像 RghUserIsolationHook 这类真正用 userId 做用户级隔离(按 userId 建本地目录、从 Redis 取 Token)的地方,也是直接 AgentSessionContextHolder.get().getUserId(),与模型输出完全隔离。 所以本质上这是一个"最小暴露面"的设计:凡是安全敏感、且有唯一可信来源的字段(身份、会话),就不要交给 LLM 生成,用旁路上下文注入;只把真正需要模型推理的业务语义(目的地、日期、方案编号)留在工具参数里。这样即便模型产生幻觉,也只可能在业务字段上出错(这些还能靠校验和用户确认兜底),而不会污染到"你是谁"这种越权风险最高的维度。

版本提示

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

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

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