DeepTutor v1.4.2 稳定性版本解析:Gemini 推理默认关闭、认证上下文修复与跨聊天流式渲染加固 DeepTutor v1.4.2 稳定性版本解析Gemini 推理默认关闭、认证上下文修复与跨聊天流式渲染加固【免费下载链接】DeepTutorDeepTutor: Lifelong Personalized Tutoring. https://deeptutor.info/.项目地址: https://gitcode.com/GitHub_Trending/dee/DeepTutorDeepTutor v1.4.2发布于 2026.05.28是构建在 v1.4.1 之上的稳定性与打磨版本核心解决四类问题让 Gemini 2.5 推理模型在 Visualize 与 chat agent 全链路可用、修复同步 FastAPI 依赖导致认证用户被静默路由到 admin 工作区的回归源码内记为 #481发布说明记为 #485、修正带原生工具调用的推理模型在标签协议下的消息解析以及把平滑流式渲染铺到每一个聊天界面。阅读本篇后你将理解这些修复的根因与实现位置并掌握如何在agents.yaml、provider_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-flash、gemini-2.5-pro、gemini-2.5-flash-lite、大写GEMINI-2.5-FLASH、models/gemini-2.5-flash、gemini-3.0-pro→ 均返回none遗留模型gemini-1.5-*、gemini-2.0-flash→ 返回None不受影响其它 provideropenai、deepseek、dashscope→ 不受影响显式传入的reasoning_effort优先级更高high会覆盖默认的none。因此从 v1.4.1 升上来的用户如果之前接入 Gemini 2.5 后看到空输出或截断无需任何配置改动——default-off 行为自动生效。如果你显式配置了高推理强度如high该值仍优先。二、Visualize 流水线加固三条独立故障链路1. Per-capability max_tokens 默认值16kVisualize 在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 依赖——即在请求上下文的副本下于工作线程中执行依赖内部调用set_current_user(...)把用户安装到「线程的上下文」上线程返回后该上下文被丢弃端点随后读到未设置状态下的默认值回退到 admin 工作区于是每个已认证用户的读写都被静默路由到本地 admin 的数据上。在 v1.4.1 中认证用户会因此遭遇会话 404见tests/api/test_auth_contextvar.py的注释说明。2. 修复依赖全部改为 async defdeeptutor/api/routers/auth.py中require_auth与require_admin现在是async def在与端点相同的 asyncio task中执行因此依赖内写入的ContextVar在下游所有位置可见require_admin内部以Depends(require_auth)链式依赖同步 async 化保证整个链留在事件循环上HTTP 与 WebSocket 入口现在共用同一个_install_current_user辅助函数保证「由 token payload 解析出的用户对象」跨传输层完全一致payload is None即AUTH_ENABLEDfalse未要求 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(code4001)再让调用方立即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钉住了三条不变式require_auth/require_admin必须是协程函数用inspect.iscoroutinefunction断言_install_current_user(None)必须安装本地 adminLOCAL_ADMIN_ID/LOCAL_ADMIN_USERNAME而不是走 None 路径静默回退端到端用例AUTH_ENABLEDtrue 合法 token 时端点内能读到用户 ContextVar且get_path_service()解析出的聊天库落在data/users/uid/前缀下而非 admin 回退。四、推理模型 原生工具调用标签协议的修复1. v1.4.1 的「小聪明」为何有害v1.4.1 对「带原生工具调用能力的推理模型」做了两处取巧在系统提示中告诉模型可以忽略TOOL/THINK/FINISH/PAUSE标签仅依赖reasoning_contenttool_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 本地 providerdeeptutor/services/provider_registry.py新增lemonade绑定面向AMD Ryzen AI / NPU 运行时ProviderSpec( namelemonade, keywords(lemonade,), env_keyLEMONADE_API_KEY, display_nameLemonade, backendopenai_compat, is_localTrue, detect_by_base_keyword13305, default_api_basehttp://localhost:13305/api/v1, ),自动检测按端口13305探测无需 API keyenv_key为空串场景下不强制校验默认 base URLhttp://localhost:13305/api/v1与 Ollama11434/ LM Studio1234/ llama.cpp8080等本地 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(sslFalse)与 HTTP 层其余部分保持一致。tests/services/config/test_context_window_detection.py新增用例注入 FakeConnector 捕获探针实际使用的连接器参数验证DISABLE_SSL_VERIFY生效时连接器确以sslFalse构造。注意该环境变量在生产环境是被拒绝的deeptutor/services/llm/openai_http_client.py抛LLMConfigError(DISABLE_SSL_VERIFY is not allowed in production)仅在本地自签名服务场景使用。七、测试矩阵与升级指引1. 新增/更新的测试测试文件锚定内容tests/api/test_auth_contextvar.py#485源码记为 #481回归syncrequire_auth丢 ContextVarasync 版本跨依赖边界保留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(sslFalse)2. 从 v1.4.1 升级pip 用户pip install -U deeptutorDocker 用户拉取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),仅供参考