wei-py
|
e1ecc18223
|
perf(intent): doubao-seed-2.0 分类请求关闭深度思考
|
3 weeks ago |
wei-py
|
256362e34a
|
refactor(chat): 前置 FAQ 三级匹配并同步流程文档
|
3 weeks ago |
wanghanlin
|
d33cb56e8a
|
优化
|
3 weeks ago |
wanghanlin
|
0838dca61a
|
fix(auth): 修复后台会话长期不失效,JWT 时间配置改用可读单位
问题
- 关闭后台页面数天后重新打开,可跳过登录页直接进入后台
- 根因:refresh token 有效期 7 天且滚动续期无上限;refresh Cookie 为持久化 Cookie
(maxAge 硬编码 7 天)在浏览器关闭后不会删除,重开页面时 App.vue 启动自检发现
/auth/me 返回 401,静默调 /auth/refresh 换发新 token 并重置窗口 —— 只要 7 天内
来访一次即等效永久会话
会话有效期修复
- application.yml:refresh-expiration 由 7 天改为 8h,作为会话时长的唯一配置项,
所有环境统一生效(不在 dev/prod 覆盖)
- auth/AuthController:refresh Cookie 的 Max-Age 由硬编码 7*24*60*60 改为读
jwt.refresh-expiration,消除「改配置不改 Cookie」造成的有效期漂移
- App.vue:刷新 token 成功后二次校验 /auth/me,失败即登出;修复原先
.catch(() => {}) 丢弃返回值导致用户带着空 currentUser 进入后台、权限判断全部
失效、直到某个请求 401 才被踢出的漏洞
JWT 时间配置改用 Duration 可读格式
- expiration / refresh-expiration / sdk-expiration 均绑定为 java.time.Duration,
值写成 15m / 8h / 2h;纯数字仍按毫秒解析,向后兼容旧配置
- JwtTokenProvider 兜底默认值由 604800000(7 天,与 yml 的 8 小时并不一致)修正为 8h
- SdkJwtTokenProvider:默认有效期改 Duration,钳制边界 MIN/MAX_EXPIRATION 改为
Duration.ofMinutes(5) / Duration.ofDays(1),并公开 clampExpirationMillis 供控制器复用
SDK 配置接通
- controller/AuthController(SDK):默认 ttl 改读 jwt.sdk-expiration。此前硬编码
7200000L,而唯一读该配置的 3 参 generateToken 无任何调用方,属改了不生效的死配置
- 控制器内不再出现 300000L / 86400000L 等毫秒魔数,expiresIn 与 token 实际有效期
保持一致(对外的 ttl / expiresIn 单位仍为秒,契约不变)
验证
- 实测 Duration 绑定链路:15m→PT15M(900s)、8h→PT8H(28800s)、2h→PT2H(7200s),
纯数字 28800000→PT8H(28800s),确认向后兼容
- mvn clean package -P prod 构建通过(含前端构建)
文档
- CLAUDE.md 同步会话有效期约定、Duration 单位规范、SDK Token 有效期约定
已知残留
- 仍保留滚动续期,页面持续活跃的用户不会掉线;彻底杜绝需引入绝对过期上限或服务端
落库记录最后活动时间,本次未做
|
3 weeks ago |
wanghanlin
|
2001dc3a0f
|
fix(doc): 修复重新处理文档会按 2000 字截断预览重建导致内容丢失
问题
- knowledge_document.content 上传时被截断到 2000 字符(有意的预览设计),
但 reprocessDocument 把它当原文重建分块,而 DocumentProcessingService 以
cleanBeforeFirstAttempt=true 运行(先删光旧向量)——对超过 2000 字符的文档
执行 POST /document/batch/reprocess 会永久丢失其余内容
修复
- content 改存原文全文(列已是 TEXT,无需 DDL),并写 extra_config.contentComplete
作为完整性标记
- 实体 content 加 @JsonIgnore:全文任何接口都不返回(否则 GET /document/list
无字段投影,每行都会带上整篇正文);文档详情接口单独组装响应,返回 2000 字预览
(键名仍是 content)与 contentTruncated 标志,前端据此提示截断
- reprocessDocument 的数据源按优先级解析:
1) 有 contentComplete 标记 → 用库内全文(语义最忠实,JSON 的 fields/pointer
模式不受影响,也不依赖文件是否还在)
2) 历史遗留文档(无标记,content 是截断预览)→ 按 fileType 从原始文件重解析
(md → MarkdownDocumentLoader,json → JsonDocumentLoader,其余 → Tika),
成功后回填全文并打标记,此后不再依赖原始文件
3) 两者都不可用 → 明确报错拒绝,绝不静默按截断预览重建
无法完整还原时在标记 PROCESSING 之前抛错,事务回滚,文档状态与已有向量都不受影响
- contentTruncated 判据覆盖历史数据:长度恰好等于上限且无 contentComplete 标记时
同样判定为已截断,避免把截断预览误报成完整内容
- 同步 content 列注释(DatabaseInitConfig / init-database.sql / knowledge-base.sql),
该注释会在下次启动幂等刷新到库
验证(真实库 + 557 篇存量文档环境)
- 上传 4891 字符正文:库内存全文,详情接口返回 2000 字预览 + contentTruncated=true
- 重新处理:chunk_count 与首次完全一致(修复前会降为个位数),内容无丢失
- 模拟历史数据(截断 + 无标记):有文件时从文件重解析成功并回填全文;
文件也丢失时明确拒绝,且文档状态与 chunk_count 保持不变(向量未被破坏)
- 回填后再删文件重跑仍成功(已自愈);GET /document/list 不再含 content
- RAG 对话回归正常
已知降级
- JSON 的 basic/fields/pointer 解析模式上传时未持久化,历史 JSON 文档从文件重解析
只能按 basic 还原(不丢数据,仅抽取口径可能变化,日志有 WARN)
- 存量中疑似被截断的文档需重跑一次才能回填全文(均已保留原始文件,均可恢复)
|
3 weeks ago |
wanghanlin
|
94c1a074e7
|
优化
|
4 weeks ago |
wanghanlin
|
84eea7564f
|
refactor: 自造轮子改用 Spring AI 标准组件、清理死代码并修复既有缺陷
组件替换(改用 1.1.x 标准组件)
- 文档提取:删除自写 TikaDocumentReader(内部直接 new org.apache.tika.Tika()),
改用官方 org.springframework.ai.reader.tika.TikaDocumentReader。
pom 早已引入 spring-ai-tika-document-reader 却从未使用其类,属典型「引了标准依赖却手写实现」
- 意图识别:IntentRouter 的手写正则解析(含去 BOM/零宽字符/全角空格等约 60 行防御逻辑)
改用标准 BeanOutputConverter<IntentResult>,保留原有降级语义(空输入/解析失败 → RAG)
- 推荐问题:SuggestionGenerator 的哨兵字符串 + 代码块剥离 + 按行降级解析改用
ChatClient.entity(ParameterizedTypeReference<List<String>>),整体删除 SuggestionResponseParser
- 分块:删除 MyTokenTextSplitter 薄壳,新增 OverlapTokenTextSplitter
分块器 overlap 缺陷修复(本次验证中发现并修复)
- 旧实现把 knowledge.chunk.overlap 传进了 TokenTextSplitter 第 2 个形参 minChunkSizeChars 位,
overlap 从未生效(Spring AI 的 TokenTextSplitter 根本没有 overlap 形参)
- 新实现继承标准 TextSplitter,复刻 TokenTextSplitter 全部切分语义,仅把前进步长改为
chunkSize - overlap,使重叠真正生效
- 验证中发现:标点截断会缩短本块消耗的 token 数,与 overlap 叠加后可把前进步长压到
1 个 token,分块数膨胀 10 倍(实测 349 块 vs 修复后 44 块)。故仅当截断后仍能前进
至少 (chunkSize - overlap) / 2 个 token 时才采用该截断,否则宁可切断句子
- overlap=0 时与标准 TokenTextSplitter 逐块一致(已对比验证)
- ⚠️ 存量文档需重新分块 + 重新向量化(POST /document/batch/reprocess),否则新旧向量口径混杂
其他既有缺陷修复
- RerankerService:原用 new RestTemplate() 且无任何超时,慢 provider 会把检索线程拖到
TCP 超时;改用 RestClient + JdkClientHttpRequestFactory 显式设置 connect/read 超时(各 3s)
- McpServerConfigController:MCP Server 增删改/启停/全量刷新后未清 AssistantApp 的
ChatClient 缓存,导致继续使用旧工具集;现补调 clearCache()
死代码清理(均已 grep 确认零引用)
- 删除 FileBasedChatMemory、ReReadingAdvisor(零装配且 before() 逻辑为 no-op)、
SseEventBuilder(零引用)、SuggestionResponseParser
- McpToolCallback 删除 EVENTS ThreadLocal 与 drainEvents()/resetEvents()(零调用),
保留在用的 MCP_EVENTS_KEY/MCP_ROUNDS_KEY ToolContext 机制
文档
- 同步更新 CLAUDE.md / README.md / DEPLOY.md 的版本号、组件说明与架构描述
- 修正 CLAUDE.md 中与代码不符的既有描述:主启动类并未排除 PgVectorStoreAutoConfiguration
(项目用的是非 starter 坐标,classpath 上本就没有该自动配置);分类过滤实现已完成,
原「Spring AI filter 支持有限」的 TODO 已不成立
|
4 weeks ago |
wanghanlin
|
1731a3ca60
|
chore(deps): 升级 Spring Boot 3.5.8 / Spring AI 1.1.2 / Spring AI Alibaba 1.1.2.2
升级到官方兼容矩阵组合(SAA 1.1.2.2 的官方基线即 Boot 3.5.8 + SAI 1.1.2)。
编译适配
- SAA 1.1.2.2 将内部类 DashscopeChatOptionsBuilder 更名为 DashScopeChatOptionsBuilder
- Spring AI 1.1.x 起 AssistantMessage/ToolResponseMessage 带 metadata 的构造器改为
protected,MessageConverter 改用标准 builder
依赖增删
- MCP SDK 继续排除传递依赖并锁定 0.18.3:1.1.2 传递的是 0.17.0,其 JsonMapper 包名
为 json.jackson(无 jackson2),与本项目使用的 json.jackson2 不兼容,不锁版本会编译失败;
已核对 spring-ai-mcp 1.1.2 仅引用 McpSyncClient/McpAsyncClient/McpClient/
McpTransportContext/McpSchema/Assert,这些类 0.18.3 均存在,覆盖安全
- 删除 spring-security-oauth2-client:原为 Spring AI 1.0.x ToolCallingAutoConfiguration
的 ClassNotFound workaround,1.1.2 已无该耦合(已核对字节码常量池零 oauth2 引用)
- 删除显式 victools jsonschema-generator:改由 spring-ai-model 传递引入(4.38.0),
顺带消除原先 4.38.0/4.37.0 混用
- 删除 kryo:唯一使用者 FileBasedChatMemory 为死代码,本提交一并删除
- 新增 jtokkit 1.1.0(OverlapTokenTextSplitter 直接使用)
- 升 Knife4j 4.5.0、MyBatis-Plus 3.5.14、hutool 5.8.41、jjwt 0.12.7;
Lombok 版本交由 Boot 父 POM 托管(1.18.42)
刻意不采纳的升级建议
- 不导入 spring-ai-alibaba-bom:该 BOM 的 dependencyManagement 并不包含
spring-ai-alibaba-starter-dashscope,导入后仍需显式写版本号,无收益
- 保留 spring-ai-openai / spring-ai-pgvector-store 的非 starter 坐标:项目手动构建
ChatModel/EmbeddingModel/VectorStore,换 starter 会额外引入 model-openai、chat-client、
chat-memory 三个自动配置,可能生成与手写工厂、DatabaseChatMemory 冲突的 Bean
|
4 weeks ago |
wanghanlin
|
a1211e8c1b
|
chore(frontend): 更新 SDK 测试面板构建产物引用
|
4 weeks ago |
wanghanlin
|
90754d15b2
|
perf(rag): MULTI_QUERY 多路检索并行化并避免 FAQ 重复语义匹配
- 新增 ragRetrieveExecutor 有界线程池 + knowledge.rag.multiquery.parallel 开关:
多路检索默认并行执行(各路 embedding HTTP + PG 查询相互独立,可把 N 路串行降为 1 段最慢路),
按原查询顺序合并去重,结果与串行路径一致;单路异常降级为空不拖垮整次检索;
饱和时退回请求线程串行(CallerRuns),供高并发/embedding 侧限流时置 false 回退
- ChatPipeline/RagPipeline:FAQ 高置信已「干净跑完」完整三级匹配仍未命中时,进入 RAG 检索跳过
重复的 FAQ 匹配(FaqMatchOutcome 携带 completedCleanly 标记),避免同一请求两次 FAQ 语义 embedding;
异常降级的 miss 不跳过,防止误跳
- FaqMatchEngine:语义匹配前加 faq_embedding 门控,作用域内无向量候选时直接返回未命中,
省掉一次注定失败的语义 embedding HTTP
|
1 month ago |
wanghanlin
|
a7d0ad87c9
|
feat(doc): 文档列表目录树默认收起并移除标签筛选
- 目录树去除 expand-all,初始仅显示分类、子目录折叠,点击展开
- 移除工具栏「全部标签」下拉及其数据源链路:filterTag/tagOptions、
api 的 listDocuments tag 参数与 getTagList、store 的 tags/loadTags、
路由守卫预加载
- 后端删除 /document/list 的 tag 参数过滤与 /tag/list 聚合接口
(getTagList 实现一并移除)
- 文档自带 tags 属性、行内/详情展示、向量 metadata 均保留不变
|
1 month ago |
wanghanlin
|
06fbbaa41d
|
chore(frontend): 更新 SDK 测试面板构建产物引用
|
1 month ago |
wanghanlin
|
d0cd06f9fc
|
fix(document): 修复批量上传向量化只成功小文档问题并加固处理链路
- 移除逐 chunk 串行 AI 关键词提取(MyKeywordEnricher):产出 excerpt_keywords 全库无检索消费点,却将外部调用放大 chunkCount 倍且与在线对话共用模型抢限流
- 向量化改按批入库(默认 50 块/批, knowledge.vector.batch-size)逐批 try-catch 隔离:失败批只记录缺失区间继续,已入库块保留,error_message 聚合"已入库 x/y 块+缺失区间+原因",chunk_count 改为实际入库块数
- 新增文档级失败自动整体重试(≤2 次, 仅 timeout/429/5xx 等瞬时错误):重试前清残留向量防重复;处理期间删除文档即终止写入避免孤儿向量;外层兜底保证状态不悬挂 PROCESSING
- Embedding 客户端(DashScope/OpenAI 兼容/豆包多模态)补显式 connect 10s/read 60s 超时,避免慢响应无限挂起占死 documentExecutor 线程
- 文档同步 CLAUDE.md/README.md,新增 knowledge.vector.batch-size 配置说明
|
1 month ago |
wanghanlin
|
459cabb1bc
|
fix(mcp-server): 修复启用开关触发 toggle/refresh 请求死循环
- 前端 toggleMcpServer 补发 { active } 请求体,与后端 @RequestBody 契约一致(此前 active 拼在 query、无 body,每次点开关必 400)
- 后端 toggleActive 兼容 query 兜底,避免旧调用方仍 400
- axios 拦截器加重试上限(_retry),刷新改用裸 axios 发起,切断 401→refresh→重试 自激递归
- MCP 开关失败回滚 _active 状态并加 _toggling 防连点
|
1 month ago |
wanghanlin
|
2668b8e73b
|
feat(document): 文档列表支持移动到目录(统一分类根/目录)
- 后端 moveDocuments 统一移动:目标为目录时校验存在并强制采用目录所属分类,分类变更时同步 vector_store 的 categoryId metadata
- DocumentController 批量移动接口新增 folderId 参数(extractLong 兼容雪花 ID 字符串)
- 前端 DocList 新增单行/批量「移动」弹窗,复用目录树 t-tree 选目标,替换原「移动分类」
|
1 month ago |
wanghanlin
|
1ffd960377
|
feat(document): 目录树独立滚动与文件夹上传完善
- 文档列表目录树独立滚动
- 上传页目录选择器改为先选分类再选目录
- 文件夹上传标题剥离目录前缀(原样文件名)
- 部分文件失败时弹窗按原因分组展示失败明细
|
1 month ago |
wanghanlin
|
562370ece5
|
fix(backend): 数据库初始化幂等自愈与 vector_store 物理删除
- DatabaseInitConfig 改为全幂等自愈(ADD COLUMN IF NOT EXISTS + 回填 + 索引/触发器幂等)
- HybridSearchService 移除对 vector_store 的 is_delete 过滤(该表无此列,物理删除)
|
1 month ago |
wanghanlin
|
dc8aa7a9d1
|
refactor(backend): 列表排序字段白名单统一走 SortUtils 防 SQL 注入
- 新增 SortUtils.resolveColumn 统一排序字段白名单映射,未知字段回退默认列
- 各 Controller/Service 列表接口新增 sortField/sortOrder 参数并接入白名单
- 前端列表页列加 sorter 并透传服务端排序参数
|
1 month ago |
wanghanlin
|
367ec79401
|
fix(document): 修复文件夹上传连接池耗尽与目录树独立滚动
- 移除 DocumentProcessingService 异步方法上的跨方法事务,AI 关键词提取/向量化期间不再占用数据库连接,避免文件夹批量上传时连接池被占满超时
- 新增有界 documentExecutor 线程池,替代默认无界 SimpleAsyncTaskExecutor,防线程爆炸与大模型限流
- 文档列表页目录树与列表改为左右独立滚动
|
1 month ago |
wanghanlin
|
780917561b
|
feat(document): 新增知识库文档目录(文件夹)功能
- 新增 KnowledgeFolder 实体/Mapper、FolderService、FolderController,支持目录树增删改查
- 文档新增 folderId 字段,列表支持按目录筛选与服务端排序
- 新增文件夹批量上传(按相对路径自动创建子目录)
- 文档列表页新增左侧目录树面板,上传页新增目录选择与文件夹上传
|
1 month ago |
wanghanlin
|
8256e9ee85
|
fix(upload): 文档上传去重改为仅同分类内查重
去重范围从全局收窄为按分类:checkContentDuplicate 增加 category_id 条件,不同分类允许内容重复,未分类按 0 归并;修正误导文案并改用 selectList 规避多结果异常
|
1 month ago |
wanghanlin
|
9d5fe80fb3
|
fix(upload): 修复文档上传多文件失效与 401 跳登录
- 上传改走 axios 复用 401 自动刷新,显式 multipart/form-data 修复 MultipartException
- DocUpload 文件 Tab 加 multiple,上传 handler 按 TDesign requestMethod 契约重写
- AuthController 的 refresh cookie Secure 属性按请求 scheme 动态判断,HTTP 自动降级
- application.yml / application-dev.yml 统一 refresh-cookie-secure 配置
|
1 month ago |
wanghanlin
|
cbbb588c69
|
chore: 清理角色表误加的 sort_order 孤儿列
customer_service_role 无排序权重需求,按 id 排序即可;sort_order 列系误加且无代码引用,启动时 DROP COLUMN IF EXISTS 幂等清理
|
1 month ago |
wanghanlin
|
1e768a7409
|
fix(service): 修复角色创建主键获取异常
创建角色改用 RETURNING id 显式取回主键,避免 PostgreSQL JDBC 对 RETURN_GENERATED_KEYS 追加 RETURNING * 导致 GeneratedKeyHolder.getKey() 抛 multiple keys 异常
|
1 month ago |
wanghanlin
|
a2dff86923
|
feat(rag): FAQ 匹配支持分类隔离并在闲聊意图前精准匹配
FaqMatchEngine 三级匹配(精确/关键词/语义)新增 categoryIds 分类过滤,授权分类与未分类 FAQ 可见;ChatPipeline 闲聊(CHITCHAT)意图前先尝试 FAQ 精准匹配,命中则短路返回标准答案;同步更新 PipelineFlow 架构图
|
1 month ago |
wanghanlin
|
3038cd0387
|
fix(security): CORS 拆分为 SDK 开放与管理白名单双轨
修复 9338fcb 收紧 CORS 白名单后引发的线上 403 回归:
将 corsConfigurationSource 与 addCorsMappings 拆分为两套配置——SDK 第三方接入接口
(/ai/**、/category/tree、/category/list、/feedback、/attachment/upload)开放 allowedOriginPatterns("*"),
管理后台接口保持 allowed-origins 白名单防 CSRF;并在 application-prod.yml 白名单补上线上域名
https://aidoc.dgscdw.com:11300,同时记录 CORS 双轨制踩坑规范。
|
1 month ago |
wanghanlin
|
9fe3ee6828
|
fix(sdk): 修复历史会话不显示图片附件
- MessageConverter 落库时持久化多模态 Media 到 metadata._media
- ConversationService 历史消息接口提取 _media 为顶层 images 字段
- SDK 前端历史映射补齐 images,复用 renderUserBubble 附件渲染
|
1 month ago |
wanghanlin
|
081758128c
|
fix(app): 修复切换会话后用户提问被查询重写结果覆盖
RAG 查询重写(REWRITE 等策略)的润色产物被当作用户消息落库到
chat_message 会话记忆表,导致 ChatSDK 切换角色/对话后前端拉取
历史显示的是润色版而非原始提问。
ChatPipeline 在 RAG 分支将 finalMessage 由 rag.rewrittenQuery()
改为 ctx.message(),使查询重写仅服务于检索,用户消息(传给模型、
落库、前端展示)统一为原始提问。
|
1 month ago |
wanghanlin
|
377aad48db
|
fix(app): 修复切换推理模型后对话流式超时
chatStreamOpenAi 流开始时立即发出首片 chunk(role=assistant),确保 SSE 响应头及时 flush,避免推理模型思考阶段无输出导致前端等待首字节触发 60s 超时;AI_READ_TIMEOUT 由 120s 放宽到 300s,给推理模型思考+生成留足总时长
|
1 month ago |
wanghanlin
|
0aa11a5ec6
|
fix(app): 修复推荐问题显示哨兵标记异常
SuggestionResponseParser 剥离旧版 ___SUGGESTIONS___ 哨兵标记,避免按行降级解析成垃圾条目;同步更新 suggestion_prompt 种子默认值,移除与新架构"只输出 JSON 数组"要求矛盾的哨兵文案
|
1 month ago |
wanghanlin
|
d5d392aca4
|
feat(sdk): 支持图片上传与多模态对话
SDK 前端新增图片附件上传与多模态对话能力,输入区新增附件按钮与图片预览,新增 allowImageUpload 配置项;/attachment/upload 鉴权改由 SdkAuthFilter 承担(移除方法级 @PreAuthorize),JwtAuthFilter/SecurityConfig 同步放行
|
1 month ago |
wanghanlin
|
9338fcbd5f
|
feat(security): JWT token_version 服务端撤销与登录安全加固
- 新增 token_version 服务端撤销机制:改密/禁用/角色变更/登出时自增,使已签发 token 立即失效
- refresh token 从 localStorage 迁移到 httpOnly Cookie,access token 有效期缩短至 15 分钟
- 新增登录失败锁定(LoginAttemptService)与密码强度校验(PasswordValidator)
- SDK JWT 密钥支持环境变量注入,使用默认密钥时告警
修复:
- assignRoles 角色未变化仍自增 token_version,导致用户新建用户时 token 被误失效而跳转登录
- 角色 ID 解析兼容前端字符串传输,避免雪花 ID 精度丢失导致 ClassCastException
- updateFill 改用 setFieldValByName,修复 update_time 未自动填充的问题
|
1 month ago |
wanghanlin
|
f0325d8f2d
|
feat(frontend): AI 执行链页面新增导出图片功能
- PipelineFlow.vue 增加导出 PNG/SVG 按钮,支持将当前渲染的流程图导出为高清图片
- 同步更新 static/sdk/test.html 构建产物资源引用
|
1 month ago |
wanghanlin
|
d6a20f228a
|
feat: 支持图片/附件 SFTP 上传、多模态对话与 FAQ Markdown 编辑器
后端:
- 新增 SFTP 附件上传服务与 /attachment/upload 接口
- 新增 StorageProperties 集中化存储配置(支持 DataSize 50MB)
- ChatContext 新增 imageUrls,AI 调用链路透传多模态图片
- AssistantApp 构造 UserMessage(text, Media) 实现视觉输入
- ContentSafetyAdvisor MASK 脱敏时保留原消息图片 Media
- 配置拆分到 application-dev.yml / application-prod.yml(对齐参考项目)
前端:
- 对话面板支持图片/附件上传与缩略图/下载链接展示
- chat.ts 透传 imageUrls,chatAdapter 增加 Attachment 模型
- FAQ 编辑器替换为 md-editor-v3,支持粘贴图片自动上传
- FAQ 表格答案摘要去除 markdown 语法
- UI-DEV-GUIDE 补充 FormDrawer 使用规范
|
1 month ago |
wanghanlin
|
08fdc2e82d
|
修改样式
|
2 months ago |
wanghanlin
|
321bee93ff
|
fix(mcp): 修复 SSE 端点带路径前缀时连接 404
HttpClientSseClientTransport 内部用 URI.resolve 拼接端点,对以 / 开头的
sseEndpoint 会整体替换 path,导致 /mcp-cdw/sse 被解析成 /sse 丢失前缀。
改为显式拆分 origin 与 path,分别作为 baseUri 与 sseEndpoint 传入,
并兼容用户填 base 或完整 SSE URL 两种写法。
|
2 months ago |
wanghanlin
|
11572a7023
|
修改样式
|
2 months ago |
wanghanlin
|
a2971ba2c2
|
修改样式
|
2 months ago |
wanghanlin
|
a1328994a5
|
feat(mcp): MCP 服务配置支持自定义请求头鉴权
- mcp_server_config 新增 headers JSONB 字段,SSE 模式通过 customizeRequest 注入请求头
- 敏感头(Authorization 等)返回前脱敏,更新时未改动保留原值
- DatabaseInitConfig 与 init-database.sql 同步新增 headers 列迁移
- McpClientManager 增加 @DependsOn(databaseInitConfig) 保证列迁移先于客户端加载
- 前端 MCP 配置弹窗新增请求头输入框
|
2 months ago |
wanghanlin
|
97f8f1a8f0
|
回复内容自适应 SDK 弹窗宽度
|
2 months ago |
wanghanlin
|
e23b70ffca
|
feat(client): SDK 界面重构改用 TDesign Web Components 组件
- 聊天核心:消息气泡/输入框/操作栏/加载态改用 t-chat-message/t-chat-sender/t-chat-action/t-chat-loading
- 外围 UI:知识库下拉/推荐问题/离线横幅改用 t-select/t-tag/t-alert
- Markdown 渲染由 t-chat-item 内置 cherry-markdown 承担,移除自研 marked 渲染器与 marked.min.js
- 构建管线:引入 tdesign-web-components@1.2.10 按需打包,mermaid 用本地 stub 替换省约 1.2MB
- 清理重构后死代码与死样式(escapeHtml/getLocale/appendStreamingCaret/offlineBannerEl 等)
- 同步更新测试面板断言(T3/T6/T10 适配 t-chat-sender)与 README/CLAUDE.md
|
2 months ago |
wanghanlin
|
8132f26891
|
feat(sdk-test): 测试面板重构为 Vue 3 + TDesign Chat 应用
- 新增 Vite 多页入口 sdk-test.html 与 SdkTestPanel.vue,用 TDesign Chat(ChatList/ChatSender/ChatActionbar)渲染对话演示
- 对话演示直调 GET /ai/chat/stream(OpenAI 格式),复用 readSSEStream 解析 delta.content,支持同步/流式、RAG 开关与来源展示
- SDK 集成验证区精简为 10 个核心用例,接口统一迁到新路径 /ai/chat*
- cp-to-static.mjs 构建后将 sdk-test.html 移动到 static/sdk/test.html
|
2 months ago |
wanghanlin
|
940caedea8
|
feat(部署): 前端静态资源免认证访问与打包配置
- pom.xml 将 static/** 单独作为资源目录,关闭 filtering 并指定 targetPath 避免平铺到 classes 根目录
- JwtAuthFilter 跳过首页与静态资源路径,避免管理后台密钥误校验产生 WARN 日志
- SecurityConfig 放行 /、/index.html、/assets/**、/sdk/** 等静态资源与首页
|
2 months ago |
wanghanlin
|
1cd8ed1248
|
feat(chat): 流式对话输出对齐 OpenAI Chat Completions 标准 SSE 格式
- 新增 AssistantApp.chatStreamOpenAi,复用 chatStream 编排逻辑,将流式文本分片包装为 data: {"choices":[{"delta":{"content":"..."}}]} 标准 JSON chunk
- 首片 delta 携带 role=assistant,流结束时追加 finish_reason=stop chunk 与 data: [DONE];熔断降级、FAQ 命中、错误兜底统一走 openAiFallbackStream
- AiController、OpenApiController 的流式接口改调 chatStreamOpenAi,旧路径保留纯文本输出向后兼容
|
2 months ago |
wanghanlin
|
23f195326d
|
feat(llm-trace): 提示词追踪增强与缺陷修复
新增追踪字段与落库链路:
- FAQ 命中详情(faqId/faqQuestion/faqMatchType/faqScore)
- 错误分类(errorType/errorMessage)与 Token 用量三档
- MCP 工具调用事件(toolCallsJson)、多轮历史(historyMessagesJson/historyTurns)
- RAG 命中片段(ragHitsJson)、检索模式(searchMode)、账户/API Key
- 数据库迁移新增 13 列 + 3 索引,同步 init-database.sql
前端增强:
- 筛选新增 API Key / 错误类型下拉,列表新增 RAG 列与刷新按钮
- 详情 Tab 扩展 FAQ / 工具调用 / 对话上下文,Prompt 关键词搜索高亮
- 新增会话时间线抽屉、调用趋势图(Chart.js 双轴折线)
缺陷修复:
- MCP 工具事件采集改用 ToolContext 显式收集器,修复 Reactor 流式跨线程丢 ThreadLocal 导致 toolCallsJson 为空
- 趋势统计 GROUP BY 别名改为 date_trunc 表达式,修复 PostgreSQL 语法错误
- 详情表格移除重复 row-key,新增 /error-types 与 /trend 接口
|
2 months ago |
wanghanlin
|
2fe322aa7d
|
完成「LLM 调用追踪面板」开发
|
2 months ago |
wanghanlin
|
61b0ae5639
|
feat(sensitive-word): 敏感词管理页布局与交互优化
- 工具栏新增级别筛选、统计提示,表格新增备注/更新时间列
- 状态列改为 t-switch 一键启用/禁用(失败自动回滚)
- 编辑弹窗加宽并新增启用开关、保存 loading、必填校验
- 批量导入提示成功/跳过重复数,删除确认带词内容
- 后端 list 接口新增 level 级别过滤参数
|
2 months ago |
wanghanlin
|
a8cb53b171
|
fix(mcp): MCP 客户端服务端重启后自动重连
|
2 months ago |
wanghanlin
|
6590ac762d
|
feat(role): 客服角色 MCP 工具授权
- 修正 allowedMcpTools 空列表语义:仅无角色(null)回退为全部,空列表=严格禁止
- 三个对话入口区分「无角色」与「角色无授权」,无角色向后兼容允许全部
- 工具注册名引入 configId 命名空间(mcp_<configId>_<name>),避免跨 Server 同名工具冲突
- 新增 GET /mcp-server/tools 接口,返回按 Server 分组的可用工具清单
- 更新角色 MCP 授权后清理 AssistantApp ChatClient 缓存,改动即时生效
- listRoles 解析 allowed_mcp_tools JSONB 为 string[],避免 PGobject 原样返回
- 前端 RoleManager 新增「MCP 工具授权」区块,接入保存/脏检测/全部授权
|
2 months ago |
wanghanlin
|
0205af7b72
|
fix(app): SSE 流式输出保留行尾空白避免 Markdown 标题损坏
新增 preserveTrailingWhitespace 方法,缓冲以空白结尾的 chunk 与下一 chunk 合并后发出,规避前端 SSE 逐行 trim 导致的行尾空格丢失(如 "## " 标题标记被拼成 "##标题")。
- 捕获内部订阅并注册 onCancel/onDispose,下游取消时同步取消上游,避免资源泄漏
- 尾部空白缓冲设 256 上限,防止纯空白输出导致 buffer 无界增长
- onError 先 flush 已缓冲内容再传播,避免已生成文本丢失
- 空白判定改用 Character.isWhitespace,对齐前端 trim 语义
|
2 months ago |