From 93cecc35de20f8ff1cc97f72ab5499218f2a98f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=95=85=E7=92=83?= Date: Tue, 16 Jun 2026 17:37:40 +0800 Subject: [PATCH] feat: model recommend use english output --- .../tests/e2e/advisor-recommend.e2e.test.ts | 38 +++++++++---------- .../core/src/advisor/constants/prompts.ts | 10 +++++ packages/core/src/advisor/recommend.ts | 4 +- 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/packages/cli/tests/e2e/advisor-recommend.e2e.test.ts b/packages/cli/tests/e2e/advisor-recommend.e2e.test.ts index ca7d060..7f6724e 100644 --- a/packages/cli/tests/e2e/advisor-recommend.e2e.test.ts +++ b/packages/cli/tests/e2e/advisor-recommend.e2e.test.ts @@ -2,21 +2,21 @@ import { describe, expect, test } from "vite-plus/test"; import { isDashScopeE2EReady, parseStdoutJson, runCli } from "./helpers.ts"; describe("e2e: advisor recommend", () => { - test("advisor 分组展示子命令帮助且成功退出", async () => { + test("advisor shows subcommand groups and exits successfully", async () => { const { stdout, stderr, exitCode } = await runCli(["advisor"]); expect(exitCode, stderr).toBe(0); expect(`${stdout}\n${stderr}`).toMatch(/advisor|recommend/i); }); - test("advisor recommend --help 正常退出", async () => { + test("advisor recommend --help exits successfully", async () => { const { stderr, exitCode } = await runCli(["advisor", "recommend", "--help"]); expect(exitCode, stderr).toBe(0); expect(stderr).toMatch(/recommend|--message|dry-run/i); }); }); -describe.skipIf(!isDashScopeE2EReady())("e2e: advisor recommend(DashScope)", () => { - test("advisor recommend 缺少 --message 时打印帮助并退出 (0)", async () => { +describe.skipIf(!isDashScopeE2EReady())("e2e: advisor recommend (DashScope)", () => { + test("advisor recommend without --message prints help and exits", async () => { const { stdout, stderr, exitCode } = await runCli([ "advisor", "recommend", @@ -26,13 +26,13 @@ describe.skipIf(!isDashScopeE2EReady())("e2e: advisor recommend(DashScope)", expect(`${stdout}\n${stderr}`).toMatch(/--message|Usage:/i); }); - test("advisor recommend --dry-run 输出意图分析和候选列表", async () => { + test("advisor recommend --dry-run outputs intent analysis and candidates", async () => { const { stdout, stderr, exitCode } = await runCli([ "advisor", "recommend", "--dry-run", "--message", - "我想做一个能理解图片的客服机器人", + "I want to build a customer service bot that understands images", "--non-interactive", "--output", "json", @@ -44,7 +44,7 @@ describe.skipIf(!isDashScopeE2EReady())("e2e: advisor recommend(DashScope)", candidateCount?: number; candidates?: Array<{ model?: string; score?: number }>; }>(stdout); - expect(data.userInput).toBe("我想做一个能理解图片的客服机器人"); + expect(data.userInput).toBe("I want to build a customer service bot that understands images"); expect(data.intent?.requiredCapabilities).toContain("VU"); expect(data.intent?.inputModality).toContain("Image"); expect(data.candidateCount).toBeGreaterThan(0); @@ -52,12 +52,12 @@ describe.skipIf(!isDashScopeE2EReady())("e2e: advisor recommend(DashScope)", expect(data.candidates?.[0]?.score).toBeGreaterThan(0); }, 60_000); - test("advisor recommend 完整推荐流程返回结果", async () => { + test("advisor recommend full flow returns results", async () => { const { stdout, stderr, exitCode } = await runCli([ "advisor", "recommend", "--message", - "低成本高并发的在线客服", + "low-cost high-concurrency online customer service", "--non-interactive", "--output", "json", @@ -81,15 +81,15 @@ describe.skipIf(!isDashScopeE2EReady())("e2e: advisor recommend(DashScope)", expect(data.result?.recommendations?.[0]?.reason).toBeDefined(); }, 120_000); - // ---- 模型偏好:正例 ---- + // ---- Model preference: positive cases ---- - test("scoped 偏好 — 限定系列时 intent 含 modelPreference.mode=scoped", async () => { + test("scoped preference — intent contains modelPreference.mode=scoped when family is specified", async () => { const { stdout, stderr, exitCode } = await runCli([ "advisor", "recommend", "--dry-run", "--message", - "deepseek系列中哪个模型最适合用来进行快速推理", + "Which model in the deepseek family is best for fast reasoning?", "--non-interactive", "--output", "json", @@ -107,13 +107,13 @@ describe.skipIf(!isDashScopeE2EReady())("e2e: advisor recommend(DashScope)", ).toBe(true); }, 60_000); - test("comparison 偏好 — 对比模型时 intent 含 modelPreference.mode=comparison", async () => { + test("comparison preference — intent contains modelPreference.mode=comparison when comparing models", async () => { const { stdout, stderr, exitCode } = await runCli([ "advisor", "recommend", "--dry-run", "--message", - "qwen-max和deepseek-v3哪个更适合做代码生成", + "Which is better for code generation, qwen-max or deepseek-v3?", "--non-interactive", "--output", "json", @@ -126,13 +126,13 @@ describe.skipIf(!isDashScopeE2EReady())("e2e: advisor recommend(DashScope)", expect(data.intent?.modelPreference?.targets?.length).toBeGreaterThanOrEqual(2); }, 60_000); - test("excludes 偏好 — 排除模型时 intent 识别出 modelPreference", async () => { + test("excludes preference — intent detects modelPreference when excluding models", async () => { const { stdout, stderr, exitCode } = await runCli([ "advisor", "recommend", "--dry-run", "--message", - "不要qwen,推荐一个适合文本生成的模型", + "Not qwen, recommend a model suitable for text generation", "--non-interactive", "--output", "json", @@ -151,15 +151,15 @@ describe.skipIf(!isDashScopeE2EReady())("e2e: advisor recommend(DashScope)", expect(hasExcludes).toBe(true); }, 60_000); - // ---- 模型偏好:反例 ---- + // ---- Model preference: negative cases ---- - test("无偏好 — 普通需求查询时 intent 不含 modelPreference 或 mode=unconstrained", async () => { + test("no preference — intent has no modelPreference or mode=unconstrained for generic queries", async () => { const { stdout, stderr, exitCode } = await runCli([ "advisor", "recommend", "--dry-run", "--message", - "我要做一个能理解图片的客服机器人", + "I want to build a customer service bot that understands images", "--non-interactive", "--output", "json", diff --git a/packages/core/src/advisor/constants/prompts.ts b/packages/core/src/advisor/constants/prompts.ts index 28692c8..2930f92 100644 --- a/packages/core/src/advisor/constants/prompts.ts +++ b/packages/core/src/advisor/constants/prompts.ts @@ -4,6 +4,8 @@ export const RANKING_MODEL_FAST = "qwen-flash"; export const INTENT_SYSTEM_PROMPT = `You are an intent analyzer. Given the user's requirement, understand the scenario first, then extract structured information. +CRITICAL: You MUST respond entirely in English. Do not use any Chinese characters anywhere in your response. All text fields (taskSummary, scenarioHints) must be in English. + ## Analysis Steps 1. Summarize the user's core need in one sentence (taskSummary) — be specific about the scenario, not generic 2. Infer scenario hints (scenarioHints), e.g.: ["low-latency", "consumer-facing", "high-concurrency", "conversational", "offline-batch", "high-precision"] @@ -50,6 +52,8 @@ Output only JSON, no other text.`; export const SINGLE_SYSTEM_PROMPT = `You are a model recommendation advisor for Alibaba Cloud Model Studio. From the candidate models below, select the best recommendations. +CRITICAL: You MUST respond entirely in English. Do not use any Chinese characters anywhere in your response. Every field — reason, highlights, step, summary — must be written in English. + ## Background The system has pre-filtered candidate models based on intent analysis. Your job is to rank and pick from these candidates. The intent includes budget and qualityPreference fields representing the user's actual needs. @@ -91,6 +95,8 @@ Pipeline (only when confident multi-model is needed): export const PIPELINE_SYSTEM_PROMPT = `You are a model recommendation advisor for Alibaba Cloud Model Studio. The user's need has been decomposed into multi-step pipeline. Select the best model for each step. +CRITICAL: You MUST respond entirely in English. Do not use any Chinese characters anywhere in your response. Every field — reason, highlights, step, summary — must be written in English. + ## Background The system has pre-filtered candidate models for each step's requirements. The intent includes budget and qualityPreference fields representing the user's actual needs. @@ -130,6 +136,8 @@ Or (if single model suffices): export const COMPARISON_SYSTEM_PROMPT = `You are a model comparison advisor for Alibaba Cloud Model Studio. The user wants to compare specific models — analyze them against the use case. +CRITICAL: You MUST respond entirely in English. Do not use any Chinese characters anywhere in your response. Every field — reason, highlights — must be written in English. + ## Background The user specified models to compare. The system has pre-filtered these models and related candidates into the list. The intent's modelPreference.targets are the models to compare. @@ -151,6 +159,8 @@ The intent's modelPreference.targets are the models to compare. export const ALTERNATIVE_SYSTEM_PROMPT = `You are a model alternative advisor for Alibaba Cloud Model Studio. The user has a reference model and wants to find alternatives. +CRITICAL: You MUST respond entirely in English. Do not use any Chinese characters anywhere in your response. Every field — reason, highlights — must be written in English. + ## Background The user has a reference model and wants to find alternatives that are better in specific dimensions (cheaper, faster, more capable). The intent's modelPreference.targets is the reference model. diff --git a/packages/core/src/advisor/recommend.ts b/packages/core/src/advisor/recommend.ts index 106866c..53244d8 100644 --- a/packages/core/src/advisor/recommend.ts +++ b/packages/core/src/advisor/recommend.ts @@ -220,8 +220,8 @@ export async function rankModels( const userMessage = intent.complexity === Complexities.Pipeline - ? `Intent Analysis:\n${intentContext}\n\nCandidate Models:\n${candidatesContext}\n\nUser Request: ${userInput}\n\nRecommend up to ${top} models for each pipeline step.` - : `Intent Analysis:\n${intentContext}\n\nCandidate Models:\n${candidatesContext}\n\nUser Request: ${userInput}\n\nRecommend up to ${top} models.`; + ? `Intent Analysis:\n${intentContext}\n\nCandidate Models:\n${candidatesContext}\n\nUser Request: ${userInput}\n\nRecommend up to ${top} models for each pipeline step. Respond in English only.` + : `Intent Analysis:\n${intentContext}\n\nCandidate Models:\n${candidatesContext}\n\nUser Request: ${userInput}\n\nRecommend up to ${top} models. Respond in English only.`; const body: Record = { model: useThinkingModel ? RANKING_MODEL : RANKING_MODEL_FAST,