Phase 7a-2: id-9b Modelfile (no-think) + 이드 페르소나 강화
- Modelfile.id-9b 생성: qwen3.5:9b-q8_0 기반, no-think ChatML 템플릿 - 모든 Ollama 호출(8개 노드+2개 Python)에 system: '/no_think' 이중 방어 - Call Haiku/Opus: 이드 페르소나 [자아]/[성격]/[말투]/[응답 원칙]/[기억] 강화 - Call Qwen Response: system 파라미터 분리 + 경량 자아 추가 - Claude API 노드에는 /no_think 미적용 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -22,7 +22,10 @@
|
||||
"name": "IMAP Trigger",
|
||||
"type": "n8n-nodes-base.imapEmail",
|
||||
"typeVersion": 2,
|
||||
"position": [0, 300]
|
||||
"position": [
|
||||
0,
|
||||
300
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
@@ -32,17 +35,23 @@
|
||||
"name": "Parse Mail",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 1,
|
||||
"position": [220, 300]
|
||||
"position": [
|
||||
220,
|
||||
300
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "function httpPost(url, body, { timeout = 15000, headers = {} } = {}) {\n return new Promise((resolve, reject) => {\n const data = JSON.stringify(body);\n const u = require('url').parse(url);\n const mod = require(u.protocol === 'https:' ? 'https' : 'http');\n const req = mod.request({\n hostname: u.hostname, port: u.port, path: u.path,\n method: 'POST',\n headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data), ...headers }\n }, (res) => {\n let body = '';\n res.on('data', c => body += c);\n res.on('end', () => {\n if (res.statusCode >= 400) return reject(new Error(url + ' \\u2192 ' + res.statusCode + ': ' + body.slice(0, 200)));\n try { resolve(JSON.parse(body)); } catch(e) { reject(new Error('JSON parse error: ' + body.slice(0, 200))); }\n });\n });\n req.on('error', reject);\n req.setTimeout(timeout, () => { req.destroy(); reject(new Error(url + ' \\u2192 timeout after ' + timeout + 'ms')); });\n req.write(data);\n req.end();\n });\n}\n\nconst item = $input.first().json;\nconst prompt = `메일을 분류하고 요약하세요. JSON만 출력.\n\n{\n \"summary\": \"한국어 2~3문장 요약\",\n \"label\": \"업무|개인|광고|알림\",\n \"has_events\": true/false,\n \"has_tasks\": true/false\n}\n\n보낸 사람: ${item.from}\n제목: ${item.subject}\n본문: ${item.body.substring(0, 3000)}`;\n\ntry {\n const r = await httpPost(`${$env.GPU_OLLAMA_URL}/api/generate`,\n { model: 'id-9b:latest', prompt, stream: false, format: 'json', think: false },\n { timeout: 15000 }\n );\n const cls = JSON.parse(r.response);\n return [{ json: { ...item, summary: cls.summary || item.subject, label: cls.label || '알림', has_events: cls.has_events || false, has_tasks: cls.has_tasks || false } }];\n} catch(e) {\n return [{ json: { ...item, summary: item.subject, label: '알림', has_events: false, has_tasks: false } }];\n}"
|
||||
"jsCode": "function httpPost(url, body, { timeout = 15000, headers = {} } = {}) {\n return new Promise((resolve, reject) => {\n const data = JSON.stringify(body);\n const u = require('url').parse(url);\n const mod = require(u.protocol === 'https:' ? 'https' : 'http');\n const req = mod.request({\n hostname: u.hostname, port: u.port, path: u.path,\n method: 'POST',\n headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data), ...headers }\n }, (res) => {\n let body = '';\n res.on('data', c => body += c);\n res.on('end', () => {\n if (res.statusCode >= 400) return reject(new Error(url + ' \\u2192 ' + res.statusCode + ': ' + body.slice(0, 200)));\n try { resolve(JSON.parse(body)); } catch(e) { reject(new Error('JSON parse error: ' + body.slice(0, 200))); }\n });\n });\n req.on('error', reject);\n req.setTimeout(timeout, () => { req.destroy(); reject(new Error(url + ' \\u2192 timeout after ' + timeout + 'ms')); });\n req.write(data);\n req.end();\n });\n}\n\nconst item = $input.first().json;\nconst prompt = `메일을 분류하고 요약하세요. JSON만 출력.\n\n{\n \"summary\": \"한국어 2~3문장 요약\",\n \"label\": \"업무|개인|광고|알림\",\n \"has_events\": true/false,\n \"has_tasks\": true/false\n}\n\n보낸 사람: ${item.from}\n제목: ${item.subject}\n본문: ${item.body.substring(0, 3000)}`;\n\ntry {\n const r = await httpPost(`${$env.GPU_OLLAMA_URL}/api/generate`,\n { model: 'id-9b:latest', system: '/no_think', prompt, stream: false, format: 'json', think: false },\n { timeout: 15000 }\n );\n const cls = JSON.parse(r.response);\n return [{ json: { ...item, summary: cls.summary || item.subject, label: cls.label || '알림', has_events: cls.has_events || false, has_tasks: cls.has_tasks || false } }];\n} catch(e) {\n return [{ json: { ...item, summary: item.subject, label: '알림', has_events: false, has_tasks: false } }];\n}"
|
||||
},
|
||||
"id": "m1000001-0000-0000-0000-000000000003",
|
||||
"name": "Summarize & Classify",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 1,
|
||||
"position": [440, 300]
|
||||
"position": [
|
||||
440,
|
||||
300
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
@@ -54,7 +63,10 @@
|
||||
"name": "Save to mail_logs",
|
||||
"type": "n8n-nodes-base.postgres",
|
||||
"typeVersion": 2.5,
|
||||
"position": [660, 300],
|
||||
"position": [
|
||||
660,
|
||||
300
|
||||
],
|
||||
"credentials": {
|
||||
"postgres": {
|
||||
"id": "KaxU8iKtraFfsrTF",
|
||||
@@ -70,7 +82,10 @@
|
||||
"name": "Embed & Save",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 1,
|
||||
"position": [880, 300]
|
||||
"position": [
|
||||
880,
|
||||
300
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
@@ -108,7 +123,10 @@
|
||||
"name": "Is Important?",
|
||||
"type": "n8n-nodes-base.if",
|
||||
"typeVersion": 2.2,
|
||||
"position": [1100, 300]
|
||||
"position": [
|
||||
1100,
|
||||
300
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
@@ -125,7 +143,10 @@
|
||||
"name": "Notify Chat",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [1320, 200]
|
||||
"position": [
|
||||
1320,
|
||||
200
|
||||
]
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
@@ -200,4 +221,4 @@
|
||||
"settings": {
|
||||
"executionOrder": "v1"
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user