77 * @ai -context: 费曼提问与答案评估 IPC handler——AIFeatureDef 注册表模式,经 callWithLocalFallback 支持本地 Ollama 优先/云端网关降级;请求响应契约与网关 Pydantic model 对齐。
88 */
99
10- import { safeHandle } from '../../ipcUtils.js' ;
10+ import { requireArray , requireText , safeHandle } from '../../ipcUtils.js' ;
1111import { logger } from '../../logger.js' ;
12- import { callWithLocalFallback , gatewayUrl , type AIFeatureDef } from '../utils.js' ;
12+ import { callWithLocalFallback , gatewayUrl , parseModelJson , type AIFeatureDef } from '../utils.js' ;
1313import { generateText } from '../ollama/OllamaProvider.js' ;
1414
1515// ================================================================
@@ -33,6 +33,8 @@ function register(): void {
3333 authToken ?: string ;
3434 } ,
3535 ) => {
36+ requireText ( args ?. concept , 'concept' ) ;
37+ requireText ( args ?. explanation , 'explanation' ) ;
3638 const startMs = Date . now ( ) ;
3739 logger . info ( `[AI] [feynman-q] IPC received: concept_length=${ args . concept . length } , explanation_length=${ args . explanation . length } , hasAuth=${ ! ! args . authToken } ` ) ;
3840 logger . debug ( `[AI] [feynman-q] Concept: ${ args . concept . slice ( 0 , 60 ) } ` ) ;
@@ -55,7 +57,8 @@ function register(): void {
5557 const localHandler = async ( ) : Promise < FeynmanQuestionResp > => {
5658 const prompt = `针对概念“${ args . concept } ”和解释“${ args . explanation } ”,生成苏格拉底式追问,返回JSON: {"questions": [{"question": "...", "focus": "..."}]}` ;
5759 const result = await generateText ( prompt , '你是一个费曼学习法追问助手。请仅返回JSON。' , { temperature : 0.7 , maxTokens : 1024 } ) ;
58- const parsed = JSON . parse ( result . content ) ;
60+ // 宽松解析:本地小模型常输出围栏/解释文字,裸 parse 会误降级到云端
61+ const parsed = parseModelJson < Partial < FeynmanQuestionResp > > ( result . content , { } ) ;
5962 return { questions : parsed . questions ?? [ ] , model : result . model , tokens_used : result . tokens_used , latency_ms : result . latency_ms } ;
6063 } ;
6164
@@ -104,6 +107,9 @@ function register(): void {
104107 authToken ?: string ;
105108 } ,
106109 ) => {
110+ requireText ( args ?. concept , 'concept' ) ;
111+ requireArray ( args ?. questions , 'questions' ) ;
112+ requireArray ( args ?. answers , 'answers' ) ;
107113 const startMs = Date . now ( ) ;
108114 logger . info ( `[AI] [feynman-eval] IPC received: concept_length=${ args . concept . length } , questions=${ args . questions . length } , answers=${ args . answers . length } , hasAuth=${ ! ! args . authToken } ` ) ;
109115 logger . debug ( `[AI] [feynman-eval] Concept: ${ args . concept . slice ( 0 , 60 ) } , Q count=${ args . questions . length } ` ) ;
@@ -130,7 +136,8 @@ function register(): void {
130136 const localHandler = async ( ) : Promise < FeynmanAnswerEvalResp > => {
131137 const prompt = `评估用户对概念“${ args . concept } ”的回答,返回JSON: {"understanding_score": 70, "feedback": "...", "strong_points": ["..."], "weak_points": ["..."]}` ;
132138 const result = await generateText ( prompt , '你是一个费曼学习法评估助手。请仅返回JSON。' , { temperature : 0.4 , maxTokens : 1024 } ) ;
133- const parsed = JSON . parse ( result . content ) ;
139+ // 宽松解析:本地小模型常输出围栏/解释文字,裸 parse 会误降级到云端
140+ const parsed = parseModelJson < Partial < FeynmanAnswerEvalResp > > ( result . content , { } ) ;
134141 return { understanding_score : parsed . understanding_score ?? 60 , feedback : parsed . feedback ?? '' , strong_points : parsed . strong_points ?? [ ] , weak_points : parsed . weak_points ?? [ ] , model : result . model , tokens_used : result . tokens_used , latency_ms : result . latency_ms } ;
135142 } ;
136143
0 commit comments