news 2026/9/9 19:50:10

DeepTutor v1.4.2 稳定性版本解析:Gemini 推理默认关闭、认证上下文修复与跨聊天流式渲染加固

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
DeepTutor v1.4.2 稳定性版本解析:Gemini 推理默认关闭、认证上下文修复与跨聊天流式渲染加固

DeepTutor v1.4.2 稳定性版本解析:Gemini 推理默认关闭、认证上下文修复与跨聊天流式渲染加固

【免费下载链接】DeepTutorDeepTutor: Lifelong Personalized Tutoring. https://deeptutor.info/.项目地址: https://gitcode.com/GitHub_Trending/dee/DeepTutor

DeepTutor v1.4.2(发布于 2026.05.28)是构建在 v1.4.1 之上的稳定性与打磨版本,核心解决四类问题:让 Gemini 2.5+ 推理模型在 Visualize 与 chat agent 全链路可用、修复同步 FastAPI 依赖导致认证用户被静默路由到 admin 工作区的回归(源码内记为 #481,发布说明记为 #485)、修正带原生工具调用的推理模型在标签协议下的消息解析,以及把平滑流式渲染铺到每一个聊天界面。阅读本篇后,你将理解这些修复的根因与实现位置,并掌握如何在agents.yamlprovider_registry与前端AssistantResponse层面对齐这些行为。

一、Gemini 2.5+ 推理默认关闭:三段执行路径的单一事实来源

1. 问题根因:thinking 默认开启会烧光 max_tokens 预算

Gemini 2.5 / Gemini 3 系列模型默认启用 thinking。若不显式在请求中发送reasoning_effort: "none",模型会把整个max_tokens预算消耗在推理上,最终对外表现为「空响应体」或「输出被截断」。

v1.4.2 将这一判断集中到deeptutor/services/llm/reasoning_params.py中导出的default_reasoning_effort_for,作为唯一事实来源,供三条互不相同的执行路径复用:

  • OpenAI SDK 路径deeptutor/services/llm/executors.py内,取reasoning_effort or default_reasoning_effort_for(...));
  • aiohttp 兜底路径deeptutor/services/llm/cloud_provider.py,同一定式);
  • reasoning-kwargs 构造器build_openai_compatible_reasoning_kwargs(同上文件)。

2. 实现细节:子串匹配与大小写不敏感

核心实现是_PROVIDER_DEFAULT_OFF_PATTERNS字典 + 子串匹配:

_PROVIDER_DEFAULT_OFF_PATTERNS: dict[str, tuple[str, ...]] = { "gemini": ("gemini-2.5", "gemini-3"), }
def default_reasoning_effort_for(provider: str | None, model: str | None) -> str | None: provider_name = (provider or "").strip().lower() off_patterns = _PROVIDER_DEFAULT_OFF_PATTERNS.get(provider_name) if off_patterns and _matches(model or "", off_patterns): return "none" return None

注意注释中的两个设计点:

  • 使用子串匹配,因此models/gemini-2.5-flash这类带models/前缀的 id 也能命中;
  • provider 名与模型名均做lower()归一化,大小写不敏感。

3. 测试锚定

tests/services/llm/test_reasoning_params.py用参数化用例锁定了这张表:

  • gemini-2.5-flashgemini-2.5-progemini-2.5-flash-lite、大写GEMINI-2.5-FLASHmodels/gemini-2.5-flashgemini-3.0-pro→ 均返回"none"
  • 遗留模型gemini-1.5-*gemini-2.0-flash→ 返回None(不受影响);
  • 其它 provider(openai、deepseek、dashscope)→ 不受影响;
  • 显式传入的reasoning_effort优先级更高("high"会覆盖默认的"none")。

因此,从 v1.4.1 升上来的用户如果之前接入 Gemini 2.5+ 后看到空输出或截断,无需任何配置改动——default-off 行为自动生效。如果你显式配置了高推理强度(如"high"),该值仍优先。

二、Visualize 流水线加固:三条独立故障链路

1. Per-capability max_tokens 默认值(16k)

Visualize 在agents.yaml中新增了自己的独立条目,默认16k tokens,且该默认值由DEFAULT_AGENTS_SETTINGS播种。这样,持有旧版data/user/settings/agents.yaml(其中完全没有提及 Visualize)的用户会自动拾取更高上限,无需手工编辑。

关键升级语义:若你之前为了调高 Visualize 的max_tokens而手改过data/user/settings/agents.yaml,你手写的值仍然优先。新的 16k 默认值只播种给「配置文件里根本没提到 Visualize」的用户。

2. SVG / HTML 根节点修剪

当模型在输出外层包裹散文(如Here you go: <svg>…),或把闭合围栏和闭合标签挤在同一行时,generator agent 现在会修剪到最外层<svg>…</svg>/<!doctype>…</html>,保证渲染器永远拿到干净的根节点。

3. Review 步骤 JSON-mode 崩溃 → 优雅降级

大型或复杂 SVG 偶尔会在 review 步骤触发 JSON-mode 转义问题。v1.4.2 不再让整个回合崩溃:Visualize 会记录失败日志,并直接送出未经过 review 的草稿,让用户至少能看到一个已渲染的结果。

三、认证请求落回正确工作区:sync 依赖导致的 ContextVar 丢失修复

1. 根因:FastAPI 对 sync 依赖使用线程池分发

v1.4.1 中require_auth同步FastAPI 依赖。FastAPI 通过anyio.to_thread.run_sync分发 sync 依赖——即在请求上下文的副本下于工作线程中执行:

  1. 依赖内部调用set_current_user(...),把用户安装到「线程的上下文」上;
  2. 线程返回后该上下文被丢弃;
  3. 端点随后读到未设置状态下的默认值,回退到 admin 工作区
  4. 于是每个已认证用户的读写都被静默路由到本地 admin 的数据上。

在 v1.4.1 中,认证用户会因此遭遇会话 404(见tests/api/test_auth_contextvar.py的注释说明)。

2. 修复:依赖全部改为 async def

deeptutor/api/routers/auth.py中:

  • require_authrequire_admin现在是async def,在与端点相同的 asyncio task中执行,因此依赖内写入的ContextVar在下游所有位置可见(require_admin内部以Depends(require_auth)链式依赖,同步 async 化保证整个链留在事件循环上);
  • HTTP 与 WebSocket 入口现在共用同一个_install_current_user辅助函数,保证「由 token payload 解析出的用户对象」跨传输层完全一致:
    • payload is None(即AUTH_ENABLED=false,未要求 JWT)→ 解析为本地 admin 用户;
    • 非空 payload → 经user_from_token_payload解析为带 scope 的CurrentUser
  • 该函数返回 ContextVar 重置 token。HTTP 调用方可忽略(请求随 task 结束而回收);WebSocket 调用方必须持有 token 并在finally中调用reset_current_user,因为 WS 连接的寿命长于依赖解析任务。典型用法见ws_require_auth返回的_WsAuthFailed哨兵分支:认证失败时先ws.close(code=4001)再让调用方立即return

auth.py中还通过_bearer_token_from_header手写解析Authorization: Bearer <token>刻意不使用HTTPBearer——因为它是基于Request注入的类依赖,而 FastAPI 不会为 WebSocket 依赖解析注入 Request,会让挂载 WS 端点的路由直接抛TypeError。手写解析让require_auth保持 HTTP/WS 对称。

3. 回归测试锚点

tests/api/test_auth_contextvar.py钉住了三条不变式:

  1. require_auth/require_admin必须是协程函数(用inspect.iscoroutinefunction断言);
  2. _install_current_user(None)必须安装本地 admin(LOCAL_ADMIN_ID/LOCAL_ADMIN_USERNAME),而不是走 None 路径静默回退;
  3. 端到端用例:AUTH_ENABLED=true+ 合法 token 时,端点内能读到用户 ContextVar,且get_path_service()解析出的聊天库落在data/users/<uid>/前缀下,而非 admin 回退。

四、推理模型 + 原生工具调用:标签协议的修复

1. v1.4.1 的「小聪明」为何有害

v1.4.1 对「带原生工具调用能力的推理模型」做了两处取巧:

  • 在系统提示中告诉模型可以忽略TOOL/THINK/FINISH/PAUSE标签,仅依赖reasoning_content+tool_calls
  • run_labeled_step内把<think>前导和任何入站 tool-call delta 当作隐式标签解析

实践中两处都出问题:

  • 当工具调用以JSON 形式泄漏进内容流(而不是真正的tool_callsdelta)时,系统没有标签可用于修复,循环会把「JSON 即答案」误判为FINISH
  • 多轮「推理 + 工具」工作流要么浪费迭代做修复重试,要么静默提前终止

2. v1.4.2 的新语义

  • 面向「推理 + 原生工具」的系统提示明确告知模型:推理会显示在单独的 trace 区域,但正式内容流必须以FINISH/TOOL/THINK/PAUSE中的一个精确开头
  • run_labeled_step(见deeptutor/core/agentic/labeled_step.py不再把 tool-call delta 当作标签解析的依据implicit_think_label参数被有意忽略(仅为 API 兼容而保留);
  • 缺失标签一律落到LABEL_UNKNOWNdeeptutor/core/agentic/labels.py中定义为"UNKNOWN"),由 chat 流水线的protocol-repair 路径接管,而不是静默错路由回合;
  • 内联的<think>...</think>前导会被实时流式送入 reasoning 子 trace,并从返回给循环的正式text中剥离——答案区域不再泄漏 provider 原始标记。

由此,测试tests/agents/chat/test_agentic_parallel_tools.py验证了「推理 + 原生工具」路径仍能解析多工具回合;tests/core/test_labeled_step_think_prelude.py更新为「标签始终必需」的语义。

五、平滑流式渲染铺满每个聊天表面

1. 复用主聊天的 rAF 打字机

上周为主聊天引入的 rAF 对齐打字机useSmoothStreamText(见web/hooks/useSmoothStreamText.ts)现已接入web/components/common/AssistantResponse.tsx。于是书本聊天面板、测验追问标签页以及任何渲染 assistant 消息的表面,在流式期间都获得相同的逐帧(frame-aligned)节奏;对已完结消息则退化为 no-op 直通,不干扰历史消息的瞬时渲染。

2. 配套修复三件套

  • Autoscroll 改为 layout 阶段钉住:书本聊天面板与测验追问标签页把自动滚动移到useLayoutEffect,并停止使用scrollIntoView({behavior: "smooth"})——快速流式下平滑动画会与下一帧布局更新竞争,产生可见抖动。现在改为在 layout 阶段做一次scrollTop = scrollHeight钉住,与主聊天上useChatAutoScrollweb/hooks/useChatAutoScroll.ts)的行为一致。
  • 全局 overflow-anchor 抑制:书本聊天面板给滚动容器标记data-chat-scroll-root,使全局的overflow-anchor: none规则生效——当光标上方的代码块回流时,浏览器内置滚动锚定会与手动钉住打架。
  • AssistantResponse 记忆化:组件改为 memoized,当无关的流式兄弟节点更新父级时,已完成的气泡不再重复解析 markdown。

六、侧边栏改版与本地 provider 支持

1. Sidebar Redesign(纯前端)

  • 展开侧边栏的聊天会话列表移入独立的可折叠Recents区域,拥有独立滚动视口——长历史不再把次级导航挤出屏幕;
  • 「New chat」按钮被移除(点击导航中的Chat即会开启新会话);
  • 页脚在 GitHub 链接旁新增 Docs 链接;
  • 每个会话渲染一个确定性、友好的 Lucide 图标(sparkles、leaf、feather、cloud、droplet、sun、moon、flame、star 等),re-render 时不 shuffle;运行中的会话有轻微 wiggle 动画,空闲会话保持静止。

2. Lemonade 本地 provider

deeptutor/services/provider_registry.py新增lemonade绑定,面向AMD Ryzen AI / NPU 运行时

ProviderSpec( name="lemonade", keywords=("lemonade",), env_key="LEMONADE_API_KEY", display_name="Lemonade", backend="openai_compat", is_local=True, detect_by_base_keyword="13305", default_api_base="http://localhost:13305/api/v1", ),
  • 自动检测:按端口13305探测,无需 API key(env_key为空串场景下不强制校验);
  • 默认 base URLhttp://localhost:13305/api/v1
  • 与 Ollama(11434)/ LM Studio(1234)/ llama.cpp(8080)等本地 OpenAI-compat 服务并列,README 的 Docker host-gateway 一节与 provider 配置文档中均已收录。

3. models-endpoint 探测遵循DISABLE_SSL_VERIFY

上下文窗口自动探测(models-endpoint probe)此前未遵循全局 SSL 策略:面对自签名证书的本地推理服务器,探测因无法验证证书而失败,只能回退默认上下文窗口。v1.4.2 中,当设置DISABLE_SSL_VERIFY时,该探测会向 aiohttp session 传入aiohttp.TCPConnector(ssl=False),与 HTTP 层其余部分保持一致。

tests/services/config/test_context_window_detection.py新增用例:注入 FakeConnector 捕获探针实际使用的连接器参数,验证DISABLE_SSL_VERIFY生效时连接器确以ssl=False构造。注意:该环境变量在生产环境是被拒绝的(deeptutor/services/llm/openai_http_client.pyLLMConfigError("DISABLE_SSL_VERIFY is not allowed in production")),仅在本地自签名服务场景使用。

七、测试矩阵与升级指引

1. 新增/更新的测试

测试文件锚定内容
tests/api/test_auth_contextvar.py#485(源码记为 #481)回归:syncrequire_auth丢 ContextVar,async 版本跨依赖边界保留
tests/services/llm/test_reasoning_params.py集中式default_reasoning_effort_for映射表
tests/core/test_labeled_step_think_prelude.py「标签始终必需」新语义;implicit_think_label被忽略
tests/agents/chat/test_agentic_parallel_tools.py推理 + 原生工具路径仍能解析多工具回合
tests/services/config/test_context_window_detection.pymodels 探测尊重DISABLE_SSL_VERIFY,传TCPConnector(ssl=False)

2. 从 v1.4.1 升级

  • pip 用户pip install -U deeptutor
  • Docker 用户:拉取ghcr.io/hkuds/deeptutor:latest
  • 曾手改agents.yaml的用户:你为 Visualize 手写的max_tokens仍生效;16k 只播种给未提及 Visualize 的配置;
  • Gemini 2.5+ 用户:空输出 / 截断问题无需改配置,default-off 自动生效。

说明:文档通篇核心指向当前仓库的deeptutor/web/tests/目录,以上所有行为均可溯源到对应源码与测试,未涉及任何外部能力或性能数据的断言。

【免费下载链接】DeepTutorDeepTutor: Lifelong Personalized Tutoring. https://deeptutor.info/.项目地址: https://gitcode.com/GitHub_Trending/dee/DeepTutor

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/9 19:48:19

【JAVA课程设计/毕业设计】基于SpringBoot的智能在线学习交流平台的设计与实现 基于SpringBoot的师生在线学习交流系统的设计与实现【附源码、数据库、万字文档】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/9/9 19:48:17

【JAVA课程设计/毕业设计】 基于SpringBoot的智慧校园实验室共享预约系统的设计与实现 基于SpringBoot的实验室分时共享预约管理平台的设计与实现【附源码、数据库、万字文档】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/9/9 19:45:52

LocalAI Embeddings 实战指南:从模型接入到对话级 Go 侧 Pooling

LocalAI Embeddings 实战指南&#xff1a;从模型接入到对话级 Go 侧 Pooling 【免费下载链接】LocalAI LocalAI is the open-source AI engine. Run any model - LLMs, vision, voice, image, video - on any hardware. No GPU required. 项目地址: https://gitcode.com/GitH…

作者头像 李华
网站建设 2026/9/9 19:45:38

Spring AI Alibaba Agent长期记忆机制:从ChatMemory到MemoryAdvisor实战

第一次用 Spring AI Alibaba 给 Agent 接“长期记忆”的时候&#xff0c;我犯了个特别低级的错误&#xff1a;给 ChatClient 挂上 MemoryAdvisor 后&#xff0c;我以为它就会自动记住用户了&#xff0c;结果换了个 sessionId 再问&#xff0c;照样什么都不记得。后来翻了半天源…

作者头像 李华