fix(dictionary): 修复 AI 编排系统的错误处理和超时控制
- 修复 orchestrator 中 throw 字符串的问题,改为 throw LookUpError - 为 zhipu.ts 添加 30 秒超时控制,防止 LLM 调用卡死 - stage1 添加 isEmpty 和 isNaturalLanguage 字段验证 - stage2 改为降级处理而非直接失败,提升用户体验 - types.ts 添加 canMap 字段 - AGENTS.md 添加禁止擅自运行 pnpm dev 的说明
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
# LEARN-LANGUAGES 知识库
|
||||
|
||||
**生成时间:** 2026-03-08
|
||||
**提交:** 91c59c3
|
||||
**提交:** 6ba5ae9
|
||||
**分支:** dev
|
||||
|
||||
## 概述
|
||||
@@ -112,6 +112,7 @@ log.error("Failed to fetch folders", { error });
|
||||
- ❌ Server Component 可行时用 Client Component
|
||||
- ❌ npm 或 yarn (使用 pnpm)
|
||||
- ❌ 生产代码中使用 `console.log` (使用 winston logger)
|
||||
- ❌ 擅自运行 `pnpm dev` (不需要,用 `pnpm build` 验证即可)
|
||||
|
||||
## 独特风格
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ export async function executeDictionaryLookup(
|
||||
|
||||
if (!standardFormResult.standardForm) {
|
||||
log.error("[Stage 3] Standard form is empty");
|
||||
throw "无法生成标准形式";
|
||||
throw new LookUpError("无法生成标准形式");
|
||||
}
|
||||
|
||||
log.debug("[Stage 3] Standard form complete", { standardFormResult });
|
||||
|
||||
@@ -55,6 +55,14 @@ export async function analyzeInput(text: string): Promise<InputAnalysisResult> {
|
||||
throw new Error("阶段1:isValid 字段类型错误");
|
||||
}
|
||||
|
||||
if (typeof result.isEmpty !== "boolean") {
|
||||
throw new Error("阶段1:isEmpty 字段类型错误");
|
||||
}
|
||||
|
||||
if (typeof result.isNaturalLanguage !== "boolean") {
|
||||
throw new Error("阶段1:isNaturalLanguage 字段类型错误");
|
||||
}
|
||||
|
||||
// 确保 reason 字段存在
|
||||
if (typeof result.reason !== "string") {
|
||||
result.reason = "";
|
||||
|
||||
@@ -9,7 +9,7 @@ const log = createLogger("dictionary-stage2");
|
||||
* 阶段 2:跨语言语义映射决策
|
||||
*
|
||||
* 独立的 LLM 调用,决定是否需要语义映射
|
||||
* 如果输入不符合"明确、基础、可词典化的语义概念"且语言不一致,直接返回失败
|
||||
* 如果输入不符合"明确、基础、可词典化的语义概念"且语言不一致,则降级使用原始输入
|
||||
*/
|
||||
|
||||
export async function determineSemanticMapping(
|
||||
@@ -86,9 +86,17 @@ b) 输入是明确、基础、可词典化的语义概念
|
||||
result.reason = "";
|
||||
}
|
||||
|
||||
// 如果不应该映射,返回错误
|
||||
// 如果不应该映射,返回降级结果(不抛出错误)
|
||||
// 这样可以让后续阶段使用原始输入继续处理
|
||||
if (!result.shouldMap) {
|
||||
throw new Error(result.reason || "输入不符合可词典化的语义概念,无法进行跨语言查询");
|
||||
log.debug("Semantic mapping not applicable, using original input", {
|
||||
reason: result.reason
|
||||
});
|
||||
return {
|
||||
shouldMap: false,
|
||||
canMap: result.canMap ?? false,
|
||||
reason: result.reason,
|
||||
};
|
||||
}
|
||||
|
||||
if (!result.mappedQuery || result.mappedQuery.trim().length === 0) {
|
||||
@@ -97,6 +105,7 @@ b) 输入是明确、基础、可词典化的语义概念
|
||||
|
||||
return {
|
||||
shouldMap: result.shouldMap,
|
||||
canMap: result.canMap ?? true,
|
||||
coreSemantic: result.coreSemantic,
|
||||
mappedQuery: result.mappedQuery,
|
||||
reason: result.reason,
|
||||
|
||||
@@ -20,6 +20,7 @@ export interface InputAnalysisResult {
|
||||
// 阶段2:语义映射结果
|
||||
export interface SemanticMappingResult {
|
||||
shouldMap: boolean;
|
||||
canMap?: boolean;
|
||||
coreSemantic?: string;
|
||||
mappedQuery?: string;
|
||||
reason: string;
|
||||
|
||||
@@ -2,10 +2,15 @@
|
||||
|
||||
type Messages = { role: string; content: string; }[];
|
||||
|
||||
const LLM_TIMEOUT_MS = 30000;
|
||||
|
||||
async function callZhipuAPI(
|
||||
messages: Messages,
|
||||
model = process.env.ZHIPU_MODEL_NAME,
|
||||
) {
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => controller.abort(), LLM_TIMEOUT_MS);
|
||||
|
||||
const url = "https://open.bigmodel.cn/api/paas/v4/chat/completions";
|
||||
|
||||
const response = await fetch(url, {
|
||||
@@ -22,8 +27,11 @@ async function callZhipuAPI(
|
||||
type: "disabled",
|
||||
},
|
||||
}),
|
||||
signal: controller.signal,
|
||||
});
|
||||
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`API 调用失败: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
@@ -42,4 +50,4 @@ async function getAnswer(prompt: string | Messages): Promise<string> {
|
||||
return response.choices[0].message.content.trim() as string;
|
||||
}
|
||||
|
||||
export { getAnswer };
|
||||
export { getAnswer };
|
||||
|
||||
Reference in New Issue
Block a user