package com.yunhai.agent.config; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * 智能体配置:大模型 + 各业务模块基地址 + 角色权限映射。 * *
全部落在 {@code application.yml} 的 {@code agent.*} 下,便于运维按环境改配置而不动代码。 */ @Data @Component @ConfigurationProperties(prefix = "agent") public class AgentSettings { /** 大模型配置 */ private Llm llm = new Llm(); /** 编排参数 */ private Loop loop = new Loop(); /** 角色权限映射(学生 / 教师 / 管理员 的角色号) */ private Roles roles = new Roles(); /** * 业务模块基地址表:key = 模块标识(工具定义里引用),value = 该模块的根地址(不含 /api)。 *
例:{@code homeleave: http://base.yunhaixingtong.com/home-leave} *
本地联调把 value 改成 {@code http://localhost:8106} 之类即可。
*/
private Map ★ 深链兜底(2026-10 新增):业务模块的用户态接口 {@code /<模块>/api/*} 只认
* 浏览器 CAS 会话,服务端调用拿不到,必然回 {@code code=302}(详见 README 第 11 节)。
* 此时智能体不再只丢一句报错,而是把模块页面地址随轨迹回传前端,
* 让用户用自己的浏览器登录态一键打开真实页面看数据 —— 这比"死等打通"务实得多。
*
* 取值已按各模块前端 {@code src/router/routes.ts} 的真实路由核对(2026-10-10):
* 默认 false:不向模型隐藏工具,越权与否由各业务模块按透传身份自行裁决。
* 置 true 时:用平台 GetUserMod 的 modId 与 {@code ToolDef.moduleId} 比对,未授权模块的工具不暴露。
*/
private boolean filterToolsByAuthorizedModule = false;
/**
* 是否开启「角色强校验」。
* 默认 true:模型若调用了当前角色无权使用的工具,服务端直接拒绝执行(不发真实请求),
* 并在轨迹里留下 FORBIDDEN 记录 —— 这是「分学生、教师权限」的硬约束。
* 置 false 可临时放开(排障用),此时仅按角色过滤列表,不做执行拦截。
*/
private boolean enforceRolePermission = true;
/**
* 浏览器代执行(方案 A,2026-10-12 新增)。
*
* 业务模块的用户态接口只认浏览器 CAS 会话,服务端调用必然 {@code code=302}
* (README 第 11 节的四条实测证据)。开启后,模块类工具不再由服务端发请求,而是:
* ★ 上线前必须按本校 UserBase 的角色体系校准:
* 平台 {@code BoaUser.getType() == 1} 恒为超管/校管;其余按 {@code roleIds} 命中下面的集合判定。
* 一个用户可同时命中多个(如既是教师又是管理员),能力取并集。
*/
@Data
public static class Roles {
/** 学生角色号(默认 1;请按 UserBase 校准) */
private List
* homeleave → /my 我的请假
* campusnotice → / 我的公告(收件箱)
* dormnotice → /par/notices 宿舍通知箱
* familyactivity → /par/activities 活动广场
* coursehomework → /stu/today 今日作业
* resourcelibrary → /resource 资源管理
* profession → /home 发展首页
*
* 运维可在 {@code application.yml} 用 {@code agent.module-landing.<模块>=<路由>} 覆盖单个模块;
* 工具自身声明的 {@code landingPath}({@code write(...)} / {@code readAt(...)})优先级更高。
*/
private Map
*
* 本地 dev(localhost:8081)因跨域取不到 base 域会话,代执行会失败并自动落回
* 「去系统里查看」的深链兜底;同站部署后即真实生效。
*/
private BrowserExec browserExec = new BrowserExec();
@Data
public static class BrowserExec {
/** 是否启用浏览器代执行(false = 维持服务端直调的旧行为) */
private boolean enabled = true;
}
@Data
public static class Llm {
/** OpenAI 兼容的 chat/completions 地址(DeepSeek 官方:https://api.deepseek.com/chat/completions) */
private String host = "https://api.deepseek.com/chat/completions";
/** 多模态/推理兼用的兜底地址(可选,默认同上) */
private String fallbackHost;
private String apiKey;
/** 默认模型:deepseek-flash(DeepSeek-V4.1-Flash,支持 function calling)。
* 以官方实时清单为准:GET https://api.deepseek.com/models(2026-10-10:deepseek-flash / deepseek-v4-pro) */
private String model = "deepseek-flash";
private int maxTokens = 2048;
private double temperature = 0.3;
/** 单次 HTTP 超时(毫秒)。⚠️ 实际出站超时已由平台统一客户端接管,见 {@code yh.http.read-timeout-ms};本字段保留仅作文档参考 */
private int timeout = 60000;
/** 是否开启深度思考(旧的 deepseek-reasoner 独立模型已下线;V4 系列改为在请求里带 effort 档位,本开关暂未接线) */
private boolean thinking = false;
}
@Data
public static class Loop {
/** 单轮对话内最多允许的「模型思考 → 调工具」循环次数,防死循环 */
private int maxRounds = 6;
/** 每个工具调用结果塞回模型时的最大字符数(防撑爆上下文) */
private int toolResultMaxChars = 6000;
/** 会话上下文最多保留的历史消息条数 */
private int historyMaxMessages = 20;
/** 会话空闲过期时间(分钟) */
private int sessionTtlMinutes = 120;
}
/**
* 角色映射:UserBase 的角色号(roleId)→ 智能体角色。
*