From 172edf402af21fc2e6846a6bdfd27696da48ebe2 Mon Sep 17 00:00:00 2001 From: suguanYang Date: Tue, 25 Aug 2026 19:00:41 +0800 Subject: [PATCH] perf: skip VLM thinking on image inspection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Inspect is OCR and provenance boxes, not multi-step reasoning. Qwen 3.5 Flash thinks by default and that was 20–40s; turning thinking off dropped it to ~8–11s without a clear quality loss. Co-authored-by: Cursor --- .../chat/image-inspection-model.test.ts | 28 +++++++++++++++++++ src/domains/chat/image-inspection-model.ts | 19 +++++++++++++ 2 files changed, 47 insertions(+) diff --git a/src/domains/chat/image-inspection-model.test.ts b/src/domains/chat/image-inspection-model.test.ts index 6181c6d..d5815d3 100644 --- a/src/domains/chat/image-inspection-model.test.ts +++ b/src/domains/chat/image-inspection-model.test.ts @@ -112,6 +112,20 @@ describe("image inspection model", () => { regions: [{ x: 0.4, y: 0.5, w: 0.2, h: 0.1 }], }) expect(result.source).toBe("structured") + expect(generateObject).toHaveBeenCalledWith( + expect.objectContaining({ + providerOptions: { + google: { + thinkingConfig: { + thinkingLevel: "minimal", + }, + }, + alibaba: { + enableThinking: false, + }, + }, + }), + ) }) it("salvages valid structured JSON from failed generateObject text", async () => { @@ -230,6 +244,20 @@ describe("image inspection model", () => { source: "structured_text", }) expect(generateText).toHaveBeenCalledTimes(1) + expect(generateText).toHaveBeenCalledWith( + expect.objectContaining({ + providerOptions: { + google: { + thinkingConfig: { + thinkingLevel: "minimal", + }, + }, + alibaba: { + enableThinking: false, + }, + }, + }), + ) }) it("falls back to analysis-only text when unsupported structured models cannot emit JSON", async () => { diff --git a/src/domains/chat/image-inspection-model.ts b/src/domains/chat/image-inspection-model.ts index 8a498af..237d108 100644 --- a/src/domains/chat/image-inspection-model.ts +++ b/src/domains/chat/image-inspection-model.ts @@ -14,6 +14,22 @@ import { logger } from "@/lib/logger" const VISION_MODEL = process.env.VISION_MODEL ?? CHAT_MODEL const IMAGE_INSPECTION_BATCH_SIZE = 6 +/** + * Inspect is OCR + provenance boxes, not multi-step reasoning. + * Gemini 3 Flash cannot fully disable thinking; `minimal` is the lowest. + * Qwen 3.5 Flash thinks by default on the gateway; turn that off. + */ +const IMAGE_INSPECTION_PROVIDER_OPTIONS = { + google: { + thinkingConfig: { + thinkingLevel: "minimal", + }, + }, + alibaba: { + enableThinking: false, + }, +} + export const imageInspectionResultSchema = z.object({ analysis: z.string(), pages: z @@ -105,6 +121,7 @@ async function generateImageInspectionBatchResult(input: { const response = await generateObject({ model: VISION_MODEL, schema: imageInspectionResultSchema, + providerOptions: IMAGE_INSPECTION_PROVIDER_OPTIONS, messages: [ { role: "user", @@ -170,6 +187,7 @@ async function generateImageInspectionBatchResult(input: { try { const jsonTextResponse = await generateText({ model: VISION_MODEL, + providerOptions: IMAGE_INSPECTION_PROVIDER_OPTIONS, messages: [ { role: "user", @@ -223,6 +241,7 @@ async function generateImageInspectionBatchResult(input: { try { const response = await generateText({ model: VISION_MODEL, + providerOptions: IMAGE_INSPECTION_PROVIDER_OPTIONS, messages: [ { role: "user",