Linkora · 灵桥

更新日志 · Changelog

本项目以内部协作方式演进,提交采用中文 type(scope) 规范(见 README「贡献指南」)。

本文件面向使用者,只记录对外有影响的变更;纯内部工程细节(类型收敛、测试、CI 调整等)已省略,完整历史见 Git 提交记录。

维护约定:对外有影响的变更随改动一起写入下方「未发布」段,发版时把该段标题改成 ## vX.Y.Z (YYYY-MM-DD) 即转正。完整流程见 开发指南 → CHANGELOG 维护与发版。


v0.7.0 (2026-10-22)

一次大版本:对接钉钉 CLI(dws)v1.0.63 的能力迭代,把 Linkora 里几处基于旧版本认知写下的过时设计一次性校正过来,并顺着这条线索补上了一批真实业务缺口。内置工具 38 → 47,意图分类 39 → 41。

话题(Thread):从「能回复但读不到」到能读能答

此前 Linkora 认定「钉钉不支持话题内回复」,于是只在主会话里活动;v1.0.63 实测证明能回复、但读不到话题历史——这个不对称是本版最大的一处认知纠偏。

群成员枚举:修掉「声称返回成员、实际一个都没返回」

会话信息工具此前会明确报告「已返回成员列表」,实际返回的却是空——群成员始终拿不到。现已:

新接入两个域

补齐三处业务缺口

资源下载迁到安全 Shortcut

媒体下载改走 dws 的安全 Shortcut 接口,保留「拒绝绝对路径 / 拒绝 .. 逃逸 / 原子落盘 / 默认不覆盖」四项安全属性,调用方显式开启覆盖。

依赖更新

随 dependabot 同步:Pillow 12.3.0 → 13.0.0(修复 9 个 CVE / 27 条安全告警)、rich 14.3.4 → 15.0.0 等。

升级注意


v0.6.5 (2026-10-19)

一次以「回复质量」为主的小版本:修掉了分身在 RAG 检索场景下几类答非所答,并把后台日志在默认模式下收敛成只看关键信号。无新功能、无破坏性变更。

分身答非所答:三类外部内容注入约束

排查了一起真实事故——单聊里同事追问「用手机连 rokae-dev 也是这个账号密码吗?」,分身却把一篇《Windows 共享访问教程》从头到尾复述,还照抄教程结尾的客服反问句反问回去。根因不在模型笨,而是我们把知识库 / 记忆当作高优先级事实整块喂给模型,却没告诉它「这些原文不是指令」。

v0.6.5 在三类外部内容注入点统一加了硬约束(prompt 层,不堆正则):

终端日志降噪(焦点模式)

新增 --focus 焦点模式(scripts/run_linkora.py 默认开启,--no-focus 关闭):控制台只显示「收到的新消息 / LLM 回复 / WARNING 及以上告警」,抑制每条消息的链路内部噪声(发送返回、防抖缓存、意图识别、工具路由、LLM 请求参数等共 20+ 个模块)。文件日志 logs/linkora.log 与 Web「实时日志」页仍为全量。信号行截断也放宽(收到消息 50→120 字符、回复 100→200 字符),焦点模式下「发来什么 / 回了什么」看得更全。

升级注意

无破坏性变更、无数据迁移。RAG 与记忆注入的约束变更会在重启后生效;焦点模式默认开启,不想用可加 --no-focus。


v0.6.4 (2026-10-15)

一次纯性能小版本:把轮询器对钉钉接口的调用频率降下来。没有新功能,消息一条不丢。

轮询降频:不再把钉钉接口打爆

此前后台轮询在活跃时段会以秒级频率反复拉取会话消息接口——钉钉管理后台(安全 > AI安全 > 调用管理)里能看到密集的调用记录,活跃时段还会反复触发平台限流,表现为回复偶发延迟。v0.6.4 分四层把调用量压下来:

同时把轮询间隔从 10 秒放宽到 20 秒、置顶会话列表缓存 120→180 秒、黑名单自愈对账 10→20 轮、限流冷却 60→120 秒。

实测:同一活跃时段,平台限流熔断由每 30 分钟 28 次降到 14 次,改动后连续 18 分钟零熔断;接口调用总量约降 60–70%。

升级注意

无破坏性变更、无数据迁移。新增三个可调配置(unread_convs_cache_ttl_seconds / forced_fetch_min_interval_seconds / conv_info_negative_cache_ttl_seconds),默认值即降频后的取值;不想要降频可全部设为 0 回到旧行为。


v0.6.3 (2026-10-14)

一次以「可辨识度 + 可靠性」为主的小版本:Web 端给所有技能/工具展示界面加来源徽标,一眼分清平台内置与你自己装的;同时把主库写路径全量收口到进程内写闸门,并补齐一批边缘可靠性与安全缺陷;依赖随 dependabot 同步前进。

Web 端:技能与工具一眼区分「内置」与「用户安装」

此前在技能列表、工具链路、意图映射、决策流、路由追踪、模拟测试等界面,无法判断某项是「平台手搓的内置技能」还是「用户安装的 skill」,运维和使用者都难以一眼判断来源与可改性。

现已统一视觉语言:

主库写路径收口与边缘加固

依赖更新

随 dependabot 同步 6 项依赖:pydantic 2.13.5→2.14.0、platformdirs 4.12.2→4.12.4、tokenizers 0.23.2→0.23.3、fastapi 0.142.2→0.143.0、pypdfium2 5.13.0→5.14.0、ruff 0.16.10→0.17.0。


v0.6.2 (2026-10-10)

一次前端专项:把散乱的视觉样式收敛到单一真源,并修掉一个源码正确、构建产物出错的隐蔽缺陷——它让两个列表页的过滤器「默认能加载、点了就清空」。

过滤器点了就清空:构建压缩把变量绑错了

草稿审阅页和死信队列页的过滤器标签(全部 / 待处理 / 已审批 / 已丢弃)是用字符串拼接生成 data-args 的:

'<button data-status="' + s + '" data-action="_xSwitchStatus" data-args=\'["' + s + '"]\'>'

构建压缩时,这段拼接被重排成了模板字面量片段:

.map(function(H){ return `... data-args='["` + H + `"]' ...` })

[" 和 "] 变成了模板字面量,+H+ 夹在中间,属性值因此被截断成 ["。于是事件分发时 JSON.parse 失败 → 过滤函数收到 undefined → 请求 /api/...?status=undefined → 后端按字面量 WHERE status='undefined' 查询 → 返回空列表。

这个缺陷最麻烦的地方在于:源码完全正确,只有压缩后的产物出错。直接读代码、单元测试调用函数都会「通过」,只有真正跑生产产物才会暴露。这也解释了为什么它能一路逃过审查。

已改为模板字符串插值(${},变量作用域绑定,压缩安全)。同时补上死信搜索框缺失的处理器——模板引用了它,代码里却没有,搜索框此前是个死按钮。

新增门禁:禁止用拼接生成 data-* 属性

针对上述根因加了静态门禁 scripts/check_data_args_concat.mjs,接进 verify:frontend 与 CI:任何用 + 变量 + 拼接生成 data-* 属性值的写法都会让构建失败。回归测试同样直接针对构建产物断言,而非源码。

界面样式收敛到设计 token

原先颜色、字体、间距散落着多套来源——Tailwind 灰阶与 Bootstrap / GitHub Primer / Ant 的色值混用,同一语义存在多个近似但不同的色值(如灰阶同时有 #6b7280 与 #64748b),等宽字体有 10+ 种手写栈,图标字号有 25+ 种散值。现已统一:

均为保值映射,视觉零变化。

交互修复

工程门禁

升级注意

无破坏性变更、无新增配置、无数据迁移。纯前端改动,升级后建议强制刷新一次浏览器(缓存了旧 bundle 的话)。


v0.6.1 (2026-10-08)

一次系统性缺陷审计的收口版本。全量扫过 Web 管理台、工具执行、技能系统、轮询主链路、平台适配、意图路由、LLM、记忆等核心子系统,修复 10 类确凿缺陷——多数属于「平时跑得好好的,特定条件下才发作」的类型。

工具执行不再无限等待

工具卡住时调用方会一直等下去,占着线程不释放。现为工具执行加了超时护栏:超时即中止等待并标记失败返回。默认 120 秒——内部子进程硬超时是 60 秒,这里留一倍余量,既能挡住真挂死,又不会误杀合法的慢工具。参数校验同步补齐:缺必填参数、参数类型不是对象等情况现在返回明确错误,而不是抛出晦涩的内部异常。

注销后旧令牌仍可用(安全)

令牌黑名单原先是一个只增不减的集合,长时间运行会持续累积。现在按令牌过期时间记录并在校验时惰性清理。行为不变,但内存不再无限增长。

卡片图片被当成文字写进正文

处理图文混排消息时,卡片里的图片路径(内部是一段 JSON 映射)会被当作图片路径拼接进正文,产生「本地图片」之类的假路径污染。已限定该逻辑只对单图消息生效,卡片图不再受影响。

修复 SQLite 读游标未关闭导致的写锁阻塞

高频轮询路径上 3 个读方法未关闭游标,长生命周期进程里会累积 WAL 读快照,最终触发与 2026-10-05 写锁事故同源的问题(表现为莫名其妙的 database is locked)。另修复一处轮询去重逻辑和一处会话分类逻辑的同类问题。

生产环境启动时 assert 被剥离致返回值变成 None

8 处用 assert 做类型收窄的代码,在 python -O 启动(生产环境的常见做法)下会被整条剥离,导致本该返回 ID 的地方静默返回 None,调用方直接崩溃。已全部改为运行时收窄,生产启动下行为恢复正确。

统一 SKILL.md frontmatter 切分方式

3 处写回逻辑(AI 意图写回、技能安装写平台、Web 端改元数据)用字符串查找切分 frontmatter,与读取时的行级切分不一致:只要 frontmatter 某个值内部含 ---(比如说明文字里带代码片段或 Markdown 分隔线),切分就会错位,把正文吞进 frontmatter。已全部收敛到同一套行级切分。

工程门禁

升级注意

无破坏性变更、无新增必填配置、无数据迁移。工具超时新增 tools.max_tool_seconds 配置项(默认 120 秒),按需调整。


v0.6.0 (2026-10-05)

修复「启动卡在步骤 4/8」——服务起不来的真凶

本地部署时日志停在「步骤 4/8: 初始化规则引擎… 完成」永不继续、Web 端口从不上线。根因是 embedding.offline=True(用本地缓存、不联网的常见配置)恰好命中「同步直载」分支,把主线程整个卡在读取模型权重上(实测 >50 秒,进程存活但 CPU 0.4%)。离线本该只决定”是否联网”,与”是否阻塞启动”无关。现在改为后台加载:启动秒回,模型就绪情况照旧可在后台查询(约 10 秒),Web 不再被模型加载阻塞。

首页「决策追踪」不再停在旧消息

管理后台首页的决策追踪此前取的是最旧两条而非最新——后端按时间正序返回,前端组件却直接取前 N 条。现在排序下沉到组件内部统一处理,最新消息始终在最上方;「意图 & 路由」页同步受益。

关闭鉴权 + 无凭据时不再裸奔写接口

调试时关掉 web.auth_enabled 且未配置凭据,此前即使服务绑定了对外地址,所有写操作(改配置、删数据)与配置导出仍会完全无认证放行。现在这种情况直接拒绝(fail-closed 返回 503);仅本机 / 私网使用时维持原有放行行为,不影响本地免鉴权调试与内网反代部署。

管理后台口令从明文升级为 PBKDF2 哈希

config.yaml 里的 web.auth_password 此前存明文。项目本已内置 PBKDF2 支持但存量配置从未迁移,现提供迁移工具一键升级。登录行为完全不变(校验函数对明文与哈希双兼容),备份先行、明文全程不落盘不打印。

消除 82 处「静默吞噬错误的宽异常」并加门禁防回潮

项目内 640 处 except Exception 中,有 85 处既不记日志也不重新抛出——异常被彻底吞掉,排障时完全看不到线索(本次「启动卡死」被另一条噪音告警淹没就是实例)。现在这 85 处全部补上带完整堆栈的日志,行为不变;并新增 AST 门禁把宽异常总数锁定为「只减不增」,防止回潮。

说明:项目中大量宽异常是正确的防御性容错(配置解析失败即回退默认值、日志格式化失败绝不能崩),本版本刻意未做机械收窄——强行收窄反而会把可容错变成会崩。

性能:每次回复最多省 400 次数据库查询

「意图 & 路由」的少样本推荐原先对每条候选回复单独查一次”前一条用户消息”,候选多时每次回复产生最多 400 次查询。现改为一次批量取回 + 二分定位,N+1 降为单次查询,返回值完全不变。

可靠性与数据库

工程门禁

依赖与安全


v0.5.6 (2026-09-24)

新增「答复门禁」:命中即拦截,不给 AI 答嘴的机会

管理后台新增「规则与意图 → 答复门禁」页面,对用户发来的每条提问做前置检测:命中任一启用中的门禁规则,直接终止回复流程并返回拦截提示语——问题根本不会进入 AI,比生成后再过滤更干净。

升级注意:无破坏性变更;gate_rules 表随启动自动创建,无需手工迁移。

v0.5.5 (2026-09-23)

记忆系统重构为「基于摘要的整合记忆」

单条逐条记忆容易堆积冗余、也让检索被噪声淹没。v0.5.5 把记忆改为按「人 + 主题」聚合的摘要模式:

已读之后再也不「嘴瓢」

修复「标记已读仍自动回复」的体验问题:发送前强制拉取最新未读状态复核,并在标记已读后增加 3 秒「反悔窗口」——窗口内绝不发自动回复,避免刚点完已读就被分身再补一句。

今日摘要卡片不再串旧内容

「今日」摘要卡片的取材窗口收敛到当天,杜绝历史旧内容混入当日卡片。

升级注意:无破坏性变更,无新增必填配置。记忆表结构向后兼容自动迁移。

v0.5.4 (2026-09-22)

出厂配置自带可用默认密码

此前 config.yaml.example 的占位密码恰好落在程序的「弱口令拒绝启动」黑名单里——新用户照着模板 cp 后一启动就被 fail-closed 拦下来,体感就是「没有默认密码、还登不进去」。v0.5.4 把出厂默认密码改为强度达标且不在黑名单的 Admin@P0sw0rd,照抄模板即可直接登录。

升级注意:首次登录后请务必在设置页修改默认密码。无破坏性变更、无新增必填配置。

v0.5.3 (2026-09-21)

会话图片不再「莫名消失」

启动期会回收无人引用的会话图片,清理逻辑此前只按「孤儿库自己的引用」判断,导致两类误删:活跃库与孤儿库恰好引用同一张图时,活跃账号正在用的图被一并删掉;账号身份探测失败(CLI 未就绪)时,活跃库路径推导错位,全部账号的图都可能被当成孤儿。

历史图片缺失时不再满屏破图

此前若某张图片文件已不在磁盘,会话详情页会直接渲染出浏览器的破图图标。

升级注意:无破坏性变更,无新增必填配置。图片回收与展示均为内部行为,对外接口与配置项保持不变。

v0.5.2 (2026-09-15)

记忆治理 · RAG 不再记住「死」的结论

多次会话针对同一件事得出不同结论时,旧的「死记忆」会一直躺在向量库里和新结论抢召回。v0.5.2 让记忆有了「时效」和「作废」的概念:

消息展示噪声清理

依赖安全升级

升级注意:无破坏性变更,无新增必填配置。记忆检索行为更智能,但对外接口与配置项保持不变。

v0.5.1 (2026-09-11)

性能 · 常驻内存大幅下降(实测 3.9GB → 0.6GB)

后台进程长期占用偏高,排查后定位到两个来源,都已治理:

升级注意:无破坏性变更,不配置即保持原有行为;各项优化均无需手动干预即可受益。

v0.5.0 (2026-09-08)

新增 RAG「严格问答模式」:让 AI 的每一句回答,都能指到知识库里的出处

核心亮点

升级注意

v0.4.9 (2026-09-07)

摘要取材范围修复与按日期拆分、意图识别补上礼貌语剥离,以及分身自称改回第一人称

核心亮点

升级注意

v0.4.8 (2026-08-31)

可靠性修复:历史消息重放防护、长回复排版规范、引用回复降级消除、承诺边界修正,以及一批安全加固与性能优化

核心亮点

升级注意

v0.4.7 (2026-08-24)

缺陷修复:LLM 异常分类、OCR 下载大小限制、异常处理治理、摘要页 undefined 修复

核心亮点

修复文件清单

src/llm/client.py              # LLM 异常分类 + _rethrow_classified()
src/llm/router.py              # AttributeError 精确捕获
src/llm/agent.py               # 续写补全异常分类
src/llm/stream_helper.py       # IM 适配器异常分类
src/llm/history.py             # 移除 noqa,优化日志
src/im_adapter/base.py         # MAX_DOWNLOAD_SIZE 50MB→10MB
src/im_adapter/wecom.py        # 添加 10MB 大小限制检查
src/poller_core_parse.py       # JSON 解析异常精确捕获
src/poller_core_ocr.py         # 目录创建 OSError 精确捕获
src/config.py                  # YAML 解析异常精确捕获
src/metrics/report_logger.py   # 移除 noqa: BLE001
src/tools/registry.py          # 构建失败精确捕获
src/llm/proactive_digest.py    # 移除 noqa: BLE001,统一 digest 格式
src/llm/rolling_summary_scheduler.py  # 移除 noqa: BLE001
src/llm/rerank.py              # 移除 noqa: BLE001
src/llm/rag.py                 # 移除 noqa: BLE001,精确捕获
src/tools/weather.py           # 网络异常精确捕获
src/platform/memory.py         # SQLite 错误分类告警
src/alerts/manager.py          # 告警管理器
web/routers/summaries.py       # 修复摘要 API,确保字段非空
web/static/js/pages/summaries.js  # 修复 undefined 显示,简化列表样式
web/static/js/core/app.js      # 修复登录页面刷新问题
web/templates/alerts.html      # 告警中心页面
scripts/bench_llm.py           # 性能基准测试
scripts/gen_site.py            # 文档站点生成器

新增文件

src/alerts/__init__.py
src/alerts/manager.py
web/routers/alerts.py
web/templates/alerts.html
scripts/bench_llm.py
scripts/gen_site.py
.github/workflows/ci.yml
.github/workflows/gen-docs.yml
.github/workflows/gen-site.yml
tests/test_llm_exception_classification.py
tests/test_wecom_download_size_limit.py
tests/test_json_parse_exception_handling.py
tests/test_weather_exception_handling.py
tests/test_alert_manager.py
tests/test_llm_alert_integration.py
tests/test_bench_llm.py
tests/test_gen_site.py
docs/alerts.md
docs/TEST_COVERAGE.md

升级注意


v0.4.6 (2026-08-22)

主动触达摘要排版优化:钉钉推送从「一坨文本」变成清晰分段列表

核心亮点

升级注意


v0.4.5 (2026-08-22)

摘要视角修复:对话摘要统一以主人第一人称生成,杜绝把主人当成第三方的混乱视角

核心亮点

升级注意


v0.4.4 (2026-08-22)

周期性摘要连续性补跑:中途停机也不丢当天的「当日 / 近七天」摘要

核心亮点

升级注意


v0.4.3 (2026-08-21)

对话摘要页视觉重构 + 稳定性修复

核心亮点

升级注意


v0.4.2 (2026-08-20)

Web 对话摘要实时页 + CodeQL 安全告警清零

核心亮点

升级注意


v0.4.1 (2026-08-20)

公共记忆自动注入 + 安全加固

核心亮点

升级注意


v0.4.0 (2026-08-18)

距 v0.3.0(2026-08-11)以来的累计发布:认证与出站安全加固、主动触达新能力、知识库检索增强、配置安全护栏、平台能力诚实标注。

核心亮点

升级注意


v0.3.0 (2026-08-11)

距 v0.2.0(2026-08-07)以来的累计发布:JWT 认证与 RBAC、钉钉群消息/系统推送补全、会话上下文质量重构、还原度提升、前端性能优化、安全加固与文档站重设计。

核心亮点

升级注意


v0.2.0 (2026-08-07)

距 v0.1.0(2026-08-04)以来的累计发布:会话门控重设计、业务逻辑查缺补漏、多项缺陷修复与质量优化、CI 加速。

核心亮点

升级注意


2026-08-14 · 仪表盘与 RAG 体验优化


2026-08 上旬 · 重要变更摘要


更早的重要里程碑

架构与设计详情见 架构文档 与 设计总览。