From 9e9865acb0869ce17e28a219e68c24898fc4571a Mon Sep 17 00:00:00 2001 From: hailin Date: Sat, 7 Feb 2026 01:31:38 -0800 Subject: [PATCH] =?UTF-8?q?fix(tools):=20=E4=BF=AE=E5=A4=8D=20coordinator-?= =?UTF-8?q?tools=20=E4=B8=8E=20immigration-tools=20=E4=B9=8B=E9=97=B4?= =?UTF-8?q?=E7=9A=84=20input=5Fschema=20=E4=B8=8D=E4=B8=80=E8=87=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 问题 全链路检查发现 coordinator-tools.ts(Claude 实际使用的工具定义)与 immigration-tools.service.ts(实际执行器)之间有 4 处 input_schema 不一致, 会导致 Claude 发送的参数无法被正确解析。 ## 修复 ### check_off_topic - coordinator 发 `query`,handler 读 `question` - Fix: handler 同时支持 `query` 和 `question` 两个字段名 ### collect_assessment_info - coordinator 发 `{ userId, field, value }`(单字段模式) - handler 读 `{ category, age, education, ... }`(批量模式) - Fix: handler 同时支持两种输入格式 ### generate_payment - coordinator 旧 schema: `{ userId, serviceType, amount, description }` - handler 需要: `{ serviceType, category, paymentMethod }` - Fix: 更新 coordinator schema 为 `{ serviceType, category, paymentMethod }` - serviceType enum 改为 ASSESSMENT/CONSULTATION/DOCUMENT_REVIEW(匹配 payment-service) - 添加 category enum 和 paymentMethod enum - 移除 userId(从 context 获取)和 amount(由 payment-service 定价) ### save_user_memory - coordinator 旧 schema 多余 `userId`(handler 用 context.userId) - coordinator 发 `importance` 但 handler 不读 - handler 支持 `category` 但 coordinator 未定义 - Fix: coordinator schema 移除 userId,移除 importance,添加 category Co-Authored-By: Claude Opus 4.6 --- .../agents/tools/coordinator-tools.ts | 37 ++++++++++++------- .../claude/tools/immigration-tools.service.ts | 32 +++++++++------- 2 files changed, 41 insertions(+), 28 deletions(-) diff --git a/packages/services/conversation-service/src/infrastructure/agents/tools/coordinator-tools.ts b/packages/services/conversation-service/src/infrastructure/agents/tools/coordinator-tools.ts index 1d7f491..28f0e93 100644 --- a/packages/services/conversation-service/src/infrastructure/agents/tools/coordinator-tools.ts +++ b/packages/services/conversation-service/src/infrastructure/agents/tools/coordinator-tools.ts @@ -298,23 +298,24 @@ export const DIRECT_TOOLS: ToolDefinition[] = [ name: 'save_user_memory', description: '直接保存用户信息到长期记忆。' + - '用于保存关键信息,无需启动完整的记忆管理 Agent。', + '用于保存关键信息,无需启动完整的记忆管理 Agent。' + + 'userId 不需要传,系统自动获取。', input_schema: { type: 'object', properties: { - userId: { type: 'string', description: '用户 ID' }, memoryType: { type: 'string', enum: ['FACT', 'PREFERENCE', 'INTENT'], - description: '记忆类型', + description: '记忆类型:FACT-用户事实,PREFERENCE-偏好,INTENT-意图', }, - content: { type: 'string', description: '记忆内容' }, - importance: { - type: 'number', - description: '重要程度 1-10', + content: { type: 'string', description: '要记住的内容' }, + category: { + type: 'string', + enum: ['QMAS', 'GEP', 'IANG', 'TTPS', 'CIES', 'TECHTAS'], + description: '相关移民类别(可选)', }, }, - required: ['userId', 'memoryType', 'content'], + required: ['memoryType', 'content'], }, isConcurrencySafe: false, }, @@ -346,20 +347,28 @@ export const DIRECT_TOOLS: ToolDefinition[] = [ { name: 'generate_payment', description: - '生成支付链接。仅在用户明确表示要付费或预约服务时使用。', + '生成支付二维码。仅在用户明确表示要付费或预约服务时使用。' + + '需要确认用户选择的服务类别和支付方式后调用。', input_schema: { type: 'object', properties: { - userId: { type: 'string', description: '用户 ID' }, serviceType: { type: 'string', - enum: ['assessment', 'consultation', 'full_service'], + enum: ['ASSESSMENT', 'CONSULTATION', 'DOCUMENT_REVIEW'], description: '服务类型', }, - amount: { type: 'number', description: '金额(HKD)' }, - description: { type: 'string', description: '服务描述' }, + category: { + type: 'string', + enum: ['QMAS', 'GEP', 'IANG', 'TTPS', 'CIES', 'TECHTAS'], + description: '移民类别', + }, + paymentMethod: { + type: 'string', + enum: ['ALIPAY', 'WECHAT', 'CREDIT_CARD'], + description: '支付方式(支付宝、微信、信用卡)', + }, }, - required: ['userId', 'serviceType'], + required: ['serviceType', 'category', 'paymentMethod'], }, isConcurrencySafe: false, }, diff --git a/packages/services/conversation-service/src/infrastructure/claude/tools/immigration-tools.service.ts b/packages/services/conversation-service/src/infrastructure/claude/tools/immigration-tools.service.ts index d489fd9..0236840 100644 --- a/packages/services/conversation-service/src/infrastructure/claude/tools/immigration-tools.service.ts +++ b/packages/services/conversation-service/src/infrastructure/claude/tools/immigration-tools.service.ts @@ -427,7 +427,8 @@ export class ImmigrationToolsService { * Check if question is off-topic - 调用 knowledge-service API */ private async checkOffTopic(input: Record): Promise { - const { question } = input as { question: string }; + // coordinator-tools.ts sends `query`, legacy getTools() sent `question` + const question = (input.query as string) || (input.question as string) || ''; console.log(`[Tool:check_off_topic] Checking: "${question}"`); @@ -456,19 +457,22 @@ export class ImmigrationToolsService { input: Record, context: ConversationContext, ): Promise { - const info = input as { - category: string; - age?: number; - education?: string; - university?: string; - yearsOfExperience?: number; - currentJobTitle?: string; - industry?: string; - annualIncome?: number; - hasHKEmployer?: boolean; - }; + // coordinator-tools.ts sends { userId, field, value } (single-field mode) + // Legacy getTools() sent { category, age, education, ... } (batch mode) + // Support both formats + let info: Record; - console.log(`[Tool:collect_assessment_info] User ${context.userId} - Category: ${info.category}`); + if (input.field && input.value) { + // Single-field mode from coordinator-tools.ts + info = { [input.field as string]: input.value }; + } else { + // Batch mode from legacy getTools() + const { userId: _userId, ...rest } = input; + info = rest; + } + + const category = (info.category as string) || ''; + console.log(`[Tool:collect_assessment_info] User ${context.userId} - Fields: ${Object.keys(info).join(', ')}`); // 保存收集到的信息到用户记忆 const memoryContent = Object.entries(info) @@ -482,7 +486,7 @@ export class ImmigrationToolsService { memoryType: 'FACT', content: `用户评估信息 - ${memoryContent}`, sourceConversationId: context.conversationId, - relatedCategory: info.category, + relatedCategory: category, importance: 80, }); }