P1: robust JSON structured output (markdown fence cleanup, structured-output instruction, subAgent excluded from base schema to prevent gemma4:E4B silence); P2: bge-m3 embeddings via Ollama + cosine search; full pipeline verified on gemma4:E4B
This commit is contained in:
1 parent
a6fde100ca
commit
89b73db8a4
2 files changed
+77
-5
No files matched your search
+25
-5
@@ -45,6 +45,20 @@ export class SparkLLMClient implements LLMClient {
|
||||
constructor(private baseUrl: string, private modelName = 'spark-x2.5-4b') {}
|
||||
|
||||
async generate(context: string, systemPrompt: string): Promise<LLMResult> {
|
||||
// Инструкция structured output — только {thoughts, emotion, decision.reply}.
|
||||
// subAgent НЕ включаем: gemma4:E4B (и другие локальные модели) пумолкают
|
||||
// (пустой ответ), когда subAgent есть в JSON-схеме. subAgent — P3,
|
||||
// появится в sub-agent SDK.
|
||||
const structuredOutput = [
|
||||
'Отвечай ТОЛЬКО валидным JSON без оградок и комментариев.',
|
||||
'Структура:',
|
||||
'{ "thoughts": "собственные мысли mind",',
|
||||
' "emotion": { "valence": 0..1, "arousal": 0..1 },',
|
||||
' "decision": { "reply": "текст ответа или null" }',
|
||||
'}',
|
||||
'thoughts и reply — на русском.',
|
||||
].join('\n');
|
||||
|
||||
// OpenAI-compatible /v1/chat/completions
|
||||
const resp = await fetch(`${this.baseUrl}/v1/chat/completions`, {
|
||||
method: 'POST',
|
||||
@@ -53,7 +67,7 @@ export class SparkLLMClient implements LLMClient {
|
||||
model: this.modelName,
|
||||
response_format: { type: 'json_object' }, // structured output
|
||||
messages: [
|
||||
{ role: 'system', content: systemPrompt },
|
||||
{ role: 'system', content: `${systemPrompt}\n\n${structuredOutput}` },
|
||||
{ role: 'user', content: context },
|
||||
],
|
||||
temperature: 0.7,
|
||||
@@ -69,13 +83,19 @@ export class SparkLLMClient implements LLMClient {
|
||||
}
|
||||
|
||||
function parseSparkOutput(content: string): LLMResult {
|
||||
// 1. Пробуем распарсить JSON (structured output)
|
||||
// 1. Убираем markdown-оградки (```json ... ```), если модель их добавила
|
||||
const cleaned = content
|
||||
.replace(/^```(?:json)?\s*/i, '')
|
||||
.replace(/\s*```$/i, '')
|
||||
.trim();
|
||||
|
||||
// 2. Пробуем распарсить JSON (structured output)
|
||||
let parsed: any = null;
|
||||
try {
|
||||
parsed = JSON.parse(content);
|
||||
parsed = JSON.parse(cleaned);
|
||||
} catch {
|
||||
// fallback: ищем JSON-блок в тексте
|
||||
const match = content.match(/({[\s\S]*})/);
|
||||
// fallback: ищем первый {...} блок в тексте
|
||||
const match = cleaned.match(/({[\s\S]*})/);
|
||||
if (match) {
|
||||
try { parsed = JSON.parse(match[1]); } catch {}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user