Skip to content

v1.10.0 · AI 对话:能问了,而且看得见"这次发了什么"

Choose a tag to compare

@YJLZSL YJLZSL released this 26 Sep 14:15
· 7 commits to main since this release

[1.10.0] - 2026-09-27 · AI 对话:能问了,而且看得见"这次发了什么"

新增

  • AI 对话。之前 AI 只到"能配、能列模型",不能聊天 —— 配置页摆在那里,
    点进去却发现没地方问问题,这是最尴尬的一种半成品。这一版把它闭环了。

    三条来自 ADR-0017 的硬要求,
    每一条都落在了具体的地方,不是写在文档里的承诺:

    要求 怎么落的
    默认本地、默认不联网 AI 能力仍默认关闭;服务商清单里本机项排最前;关闭时出站 0 字节
    外部服务逐次授权 + 展示将发送的内容 点「发送」先算一遍、弹出完整请求原文(可展开、带字节数),确认后才发出去
    必须有 AI 隐私面板 面板常驻、不许折叠:现在跑在本机还是外部、本次会话已发出多少行数据、一键清空对话
  • "只发结构"是默认值,不是选项。 问关于表格的问题时,默认只把表名、字段名、字段类型
    发出去,一行数据都不带;要把数据行发出去,必须用户自己勾
    「连同当前表格的数据行一起发送」,且每次都要重新勾。本机模型(Ollama / LM Studio /
    指向 127.0.0.1 的自定义地址)不走这条授权 —— 数据没有离开本机,就不该拿"授权"去烦用户
    (ADR-0017 的补充决定)。

  • 数据行有硬上限:一次最多带 20 行、单元格超长截断。这是唯一会把真实数据
    带出本机的路径,"少一点"永远比"多一点"安全,所以上限写死在代码里,界面上不提供"发更多"。

  • 端点是后端决定的,不是前端传的。 前端只说"要发什么",说不了"发去哪" ——
    否则一个被注入的渲染层就能把用户的请求改发到别处,而界面上仍然写着"本机模型"。

  • 多轮上下文上限 8 条(约 4 个来回)。原因很实际:每一轮都要用户授权一次,
    上下文越长,"将发送的内容"预览就越没人会读 —— 那样"展示将要发送的内容"就变成了走过场。

  • 本机地址支持明文 HTTP(只限回环)。本机模型的地址是 http://127.0.0.1:11434/v1
    这种形状(明文 + 非 443 端口),而原来的网络传输层只接受 https。
    现在只给 127.0.0.1 / localhost / [::1] 开口子:到回环的明文流量不会离开本机;
    其他主机一律仍然只允许 https —— 放开任意主机的 http 等于允许用户把自己的数据明文发到公网。

  • 对话记录存在本机(跟数据目录走,换目录不继承),可一键清空;失败的、超时的、
    中途关掉界面的都不会在历史里留半截
    —— 只有完整的一问一答才落历史。

  • 审计:每次对话调用(含失败)记一条只含元信息的记录(时间 / 服务商 / 表 / 模型 /
    实际发出的行数 / 结果)。绝不记数据本体,绝不记 API Key ——
    连服务端的错误响应也不落原文:万一对面把请求体回声回来,那段里就有用户数据,
    而审计是"只记元信息"的地方。所以错误说明只取结构化字段并截断。

  • 本机没有模型时明确说清楚,不静默改走云端(ADR-0017 第 1 条:
    "看起来在本地实际在云端"是这类功能最坏的一种欺骗)。

性能

  • 翻页不再读整表:10 万行的表翻到中间那一页,从 386ms 降到 0.166ms(约 2300 倍)。
    表格首页在 v1.9.0 已经快了,但点「下一页」走的还是老路径:
    把整张表克隆出来、再逐行反序列化。现在利用一个既有事实 ——
    记录 key 是 rec/<表>/<20 位补零 rowid>,所以 BTreeMap 的字典序就是
    rowid 升序 ——
    直接定位到游标所在位置,只取一页。筛选路径同样省掉了"先克隆整表再反序列化"的重复成本。

    本机实测(perf_baseline --ignored --nocapture,交错采样取中位数,避免别人同时构建的噪声):

    规模 指标 优化前 优化后
    10 万行 游标页 384.07 ms 0.166 ms(约 2300×)
    10 万行 筛选(命中 50 行) 415.18 ms 297.26 ms(−28%)
    1 万行 游标页 32.44 ms 0.181 ms(约 180×)
    1 万行 筛选 33.33 ms 25.36 ms(−24%)

    首页没有变化(前后都在 0.26–0.34ms,属噪声带)。

    没优化到的(如实说):筛选仍然是 O(n) 反序列化 —— 它必须把每行 JSON 都解析出来
    看那一列,10 万行还要 ~297ms。想再快只能上"只解析筛选列"的自定义 visitor 或倒排索引,
    那是另一个量级,这一版没做。

  • 筛选结果与游标翻页用"对拍"验证过:新增的测试把旧算法逐字复刻一份,
    然后新老两条路径逐页对比行集合、顺序、has_more、next_cursor 四项全等
    (5 种排序 × 6 种 limit × 挖洞表;筛选 7 组组合)。改了查询逻辑,就得有东西能证明结果没变 ——
    只看"页数对得上"是不够的。

修复

  • AI 设置里点「保存」看不到任何提示(保存其实成功了)。#ai-save 的处理器在
    主 IIFE 之外,而它调的 toast() 定义在主 IIFE 之内 —— 那句提示抛 ReferenceError,
    于是"保存成功"在界面上表现成"保存失败"。这类"功能成功但提示失败"的 bug 最难被举报清楚
    (用户会反复点、怀疑自己的 Key)。改走 DeskBaseUI.toast,并补了烟测覆盖 ——
    在此之前烟测从不点这个按钮,所以机器一直没发现它。
  • 「拉取模型」对所有厂商都会 404:list_models 无条件拼 {base}/v1/models,
    而厂商清单里 9 家有 8 家的地址已经带版本段(/v1、/v3、/v4),
    于是拼成 /v1/v1/models。对话的地址拼法一直是对的 ——
    同一个 URL 规则写了两遍,就只可能有一个对。现在两处共用一条规则,
    并有测试用同一份输入同时钉住两个函数,防它们再分家。
  • 本机模型连不上时给的是"Win32 错误码 12152":本机模型没启动是 AI 对话最常见的失败,
    而用户没法从那串数字想到"我模型没开"。补了一句人话翻译
    ("本机模型常见:模型服务没启动,或还在加载中")。
  • CHANGELOG.md 里 [1.9.2]/[1.9.1]/[1.9.0] 三节各重复了一遍(内容逐字节相同,
    相隔 147 行)。删掉重复的一份:1957 行 → 1810 行,37 个版本节,每个版本恰好一节。
    这是"同一段内容被写进去两次"的事故 —— 用户看到的更新日志里三个版本各出现两次。

已知问题(如实写)

  • [0.4.0] 那一节的位置仍然不对:它排在文件最前面,在这份倒序日志里位于
    [1.9.2] 之前。这是独立的一处排序欠账,这次没有顺手移动它 ——
    移动整节要重算边界、风险比去重大,混在一起改的话出问题就说不清是哪一步。
  • AI 对话没有真流式输出:回复是一次性拿到的,等待时界面显示「正在思考…」。
    逐字输出是体验升级,代价与做法见 local-docs/reference/32-tech-feasibility.md 第 3 条。
  • 本机模型的响应速度与质量取决于用户自己跑的模型,不是这个程序能决定的。
  • 筛选性能(见上):10 万行 ~297ms,仍是全表反序列化。
  • AI 对话的界面覆盖只到"打开/隐私条/禁用态":真实发一条消息需要真的模型服务
    (本机没跑,测试里也不该真联网),所以**"发出去、收回来"这一段没有自动化覆盖**,
    只验证到 IPC 契约、payload 构造与审计边界这一层。