小白龙 Bailongma - 初始提交
自主操作员与思考搭档系统。 包含 orchestrator-v2 多Agent编排层、后台意识引擎、记忆系统、ACUI 组件。
This commit is contained in:
38
orchestrator-v2/debate/_write_llm.js
Normal file
38
orchestrator-v2/debate/_write_llm.js
Normal file
@@ -0,0 +1,38 @@
|
||||
const fs = require("fs");
|
||||
const path = "D:\\q\\Bailongma\\orchestrator-v2\\debate\\llm.js";
|
||||
const content = `// ============================================================
|
||||
// LLM 调用工具 — 独立于 agent-worker,直接 fetch API
|
||||
// ============================================================
|
||||
|
||||
const BASE_URL = (process.env.LLM_BASE_URL || process.env.OPENAI_BASE_URL || "https://api.openai.com/v1").replace(/\\/+$/, "");
|
||||
const MODEL = process.env.LLM_MODEL || process.env.OPENAI_MODEL || "gpt-4o";
|
||||
const API_KEY = process.env.LLM_API_KEY || process.env.OPENAI_API_KEY || "";
|
||||
|
||||
async function callLLM({ messages, model, maxTokens, temperature }) {
|
||||
const url = BASE_URL + "/chat/completions";
|
||||
const body = {
|
||||
model: model || MODEL,
|
||||
messages: messages,
|
||||
max_tokens: maxTokens || 2048,
|
||||
temperature: temperature ?? 0.7
|
||||
};
|
||||
const resp = await fetch(url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer " + API_KEY
|
||||
},
|
||||
body: JSON.stringify(body)
|
||||
});
|
||||
if (!resp.ok) {
|
||||
const errText = await resp.text().catch(() => "");
|
||||
throw new Error("LLM " + resp.status + ": " + errText.slice(0, 200));
|
||||
}
|
||||
return await resp.json();
|
||||
}
|
||||
|
||||
module.exports = { callLLM };
|
||||
`;
|
||||
|
||||
fs.writeFileSync(path, content.trim(), "utf8");
|
||||
console.log("llm.js written, bytes: " + content.length);
|
||||
158
orchestrator-v2/debate/coordinator.js
Normal file
158
orchestrator-v2/debate/coordinator.js
Normal file
@@ -0,0 +1,158 @@
|
||||
// ============================================================
|
||||
// 辩论协调器 — 8 步辩论流程编排
|
||||
// 移植自 Counsel AI 的结构化辩论方法论
|
||||
// ============================================================
|
||||
|
||||
const { callLLM } = require('./llm.js');
|
||||
const { DEFAULT_PERSONAS } = require('./personas.js');
|
||||
const {
|
||||
definePrompt, factQuestionPrompt, opinionPrompt,
|
||||
dimensionsPrompt, debatePrompt, debateFacilitatorPrompt,
|
||||
summaryPrompt, harvestPrompt
|
||||
} = require('./prompts.js');
|
||||
|
||||
// 记录每步的时间和信息
|
||||
const stepLog = [];
|
||||
function logStep(step, status, detail) {
|
||||
stepLog.push({ step, status, detail, time: new Date().toISOString() });
|
||||
console.log(`[辩论] Step ${step}: ${status} - ${detail?.substring(0, 80)}`);
|
||||
}
|
||||
|
||||
// 8 步辩论流程
|
||||
async function runDebate(input, options = {}) {
|
||||
const {
|
||||
personas = DEFAULT_PERSONAS,
|
||||
userAnswers = {}, // 用户对事实性问题的回答
|
||||
model = 'deepseek-chat',
|
||||
maxTokens = 2048
|
||||
} = options;
|
||||
|
||||
if (!input || !input.trim()) {
|
||||
throw new Error("请输入要辩论的问题");
|
||||
}
|
||||
|
||||
logStep(0, "start", `输入问题: ${input.substring(0, 60)}...`);
|
||||
const state = { rawInput: input.trim(), defined: '', answers: '', opinions: [], dimensions: [], debates: [], summary: '', harvest: '' };
|
||||
|
||||
// === Step 1: 问题精确定义 ===
|
||||
logStep(1, "running", "Facilitator 精确定义问题...");
|
||||
try {
|
||||
const prompt1 = definePrompt(state.rawInput);
|
||||
const r1 = await callLLM({ messages: [{ role: 'user', content: prompt1 }], model, maxTokens });
|
||||
state.defined = r1.choices?.[0]?.message?.content || prompt1;
|
||||
logStep(1, "done", `问题定义: ${state.defined.substring(0, 100)}`);
|
||||
} catch(e) {
|
||||
logStep(1, "fallback", "LLM 调用失败, 使用原始输入作为问题定义");
|
||||
state.defined = state.rawInput;
|
||||
}
|
||||
|
||||
// === Step 2: 事实追问 ===
|
||||
logStep(2, "running", `${personas.length} 位幕僚轮流问事实性问题...`);
|
||||
try {
|
||||
const factResults = [];
|
||||
for (const p of personas) {
|
||||
const prevQA = factResults.map((r, i) => `Q: ${r.question}\nA: ${r.answer || '(未回答)'}`).join('\n');
|
||||
const prompt2 = factQuestionPrompt(state.rawInput, state.defined, p.skill, prevQA);
|
||||
const r2 = await callLLM({ messages: [{ role: 'user', content: prompt2 }], model, maxTokens: 1024 });
|
||||
const question = r2.choices?.[0]?.message?.content || '';
|
||||
if (question && !question.includes('没有问题了') && !question.includes('无需')) {
|
||||
const answer = userAnswers[p.id] || userAnswers[p.name] || '(待用户回答)';
|
||||
factResults.push({ persona: p.name, question, answer });
|
||||
}
|
||||
}
|
||||
state.answers = factResults.map(r => `**${r.persona}** 问:${r.question}\n答:${r.answer}`).join('\n\n');
|
||||
logStep(2, "done", `收集了 ${factResults.length} 个事实性问题`);
|
||||
} catch(e) {
|
||||
logStep(2, "fallback", `事实追问失败: ${e.message}`);
|
||||
state.answers = '(未收集事实信息)';
|
||||
}
|
||||
|
||||
// === Step 3: 表态(12 路并行)===
|
||||
logStep(3, "running", `${personas.length} 路并行表态...`);
|
||||
try {
|
||||
const opinionPromises = personas.map(p =>
|
||||
callLLM({ messages: [{ role: 'user', content: opinionPrompt(state.rawInput, state.defined, state.answers, p.skill) }], model, maxTokens: 1024 })
|
||||
.then(r => ({ persona: p.name, emoji: p.emoji, opinion: r.choices?.[0]?.message?.content || '(无回应)' }))
|
||||
.catch(e => ({ persona: p.name, emoji: p.emoji, opinion: `(调用失败: ${e.message})` }))
|
||||
);
|
||||
const opinions = await Promise.all(opinionPromises);
|
||||
state.opinions = opinions;
|
||||
logStep(3, "done", `全部 ${opinions.length} 位幕僚表态完成`);
|
||||
} catch(e) {
|
||||
logStep(3, "error", `表态失败: ${e.message}`);
|
||||
state.opinions = personas.map(p => ({ persona: p.name, emoji: p.emoji, opinion: '(获取失败)' }));
|
||||
}
|
||||
|
||||
// === Step 4: 冲突维度提炼 ===
|
||||
logStep(4, "running", "Facilitator 提炼冲突维度...");
|
||||
try {
|
||||
const opinionsText = state.opinions.map(o => `**${o.emoji} ${o.persona}**:${o.opinion}`).join('\n\n');
|
||||
const prompt4 = dimensionsPrompt(opinionsText);
|
||||
const r4 = await callLLM({ messages: [{ role: 'user', content: prompt4 }], model, maxTokens });
|
||||
const dimText = r4.choices?.[0]?.message?.content || '';
|
||||
state.dimensions = dimText.split(/## 维度 \d+/).filter(Boolean).map(d => d.trim()).filter(d => d.length > 0);
|
||||
if (state.dimensions.length === 0 && dimText.trim()) {
|
||||
state.dimensions = [dimText.trim()];
|
||||
}
|
||||
logStep(4, "done", `提炼了 ${state.dimensions.length} 个冲突维度`);
|
||||
} catch(e) {
|
||||
logStep(4, "fallback", `维度提炼失败: ${e.message}`);
|
||||
state.dimensions = ['(无法提炼维度)'];
|
||||
}
|
||||
|
||||
// === Step 5: 维度辩论 ===
|
||||
logStep(5, "running", `对 ${state.dimensions.length} 个维度进行辩论...`);
|
||||
try {
|
||||
const debateResults = [];
|
||||
for (let i = 0; i < state.dimensions.length; i++) {
|
||||
const dim = state.dimensions[i];
|
||||
const dimShort = dim.substring(0, 60);
|
||||
logStep(5, "sub", `维度 ${i+1}/${state.dimensions.length}: ${dimShort}...`);
|
||||
const debatePromises = personas.map(p =>
|
||||
callLLM({ messages: [{ role: 'user', content: debatePrompt(state.defined, state.answers, dim, p.skill) }], model, maxTokens: 1024 })
|
||||
.then(r => ({ persona: p.name, emoji: p.emoji, stance: r.choices?.[0]?.message?.content || '(无回应)' }))
|
||||
.catch(e => ({ persona: p.name, emoji: p.emoji, stance: `(调用失败: ${e.message})` }))
|
||||
);
|
||||
const stances = await Promise.all(debatePromises);
|
||||
const allPositions = stances.map(s => `**${s.emoji} ${s.persona}**:${s.stance}`).join('\n');
|
||||
const summaryP = debateFacilitatorPrompt(dim, allPositions);
|
||||
const rSum = await callLLM({ messages: [{ role: 'user', content: summaryP }], model, maxTokens: 1024 });
|
||||
const dimSummary = rSum.choices?.[0]?.message?.content || '(无总结)';
|
||||
debateResults.push({ dimension: dim, stances, summary: dimSummary });
|
||||
}
|
||||
state.debates = debateResults;
|
||||
logStep(5, "done", `全部 ${state.dimensions.length} 个维度辩论完成`);
|
||||
} catch(e) {
|
||||
logStep(5, "error", `辩论失败: ${e.message}`);
|
||||
state.debates = state.dimensions.map(dim => ({ dimension: dim, stances: [], summary: '(辩论失败)' }));
|
||||
}
|
||||
|
||||
// === Step 6: 结构化总结 ===
|
||||
logStep(6, "running", "Secretary 生成结构化总结报告...");
|
||||
try {
|
||||
const debateRecord = state.debates.map(d => `## ${d.dimension.substring(0, 80)}\n${d.summary}`).join('\n\n');
|
||||
const prompt6 = summaryPrompt(state.rawInput, state.defined, state.answers, debateRecord);
|
||||
const r6 = await callLLM({ messages: [{ role: 'user', content: prompt6 }], model, maxTokens: 4096 });
|
||||
state.summary = r6.choices?.[0]?.message?.content || '(生成失败)';
|
||||
logStep(6, "done", "结构化总结完成");
|
||||
} catch(e) {
|
||||
logStep(6, "error", `总结失败: ${e.message}`);
|
||||
state.summary = '(总结生成失败)';
|
||||
}
|
||||
|
||||
// === Step 7: 摘果子 ===
|
||||
logStep(7, "running", "提取 To-Do 和关键评估...");
|
||||
try {
|
||||
const prompt7 = harvestPrompt(state.summary);
|
||||
const r7 = await callLLM({ messages: [{ role: 'user', content: prompt7 }], model, maxTokens: 2048 });
|
||||
state.harvest = r7.choices?.[0]?.message?.content || '(生成失败)';
|
||||
logStep(7, "done", "评估和建议提取完成");
|
||||
} catch(e) {
|
||||
logStep(7, "error", `摘果子失败: ${e.message}`);
|
||||
state.harvest = '(评估生成失败)';
|
||||
}
|
||||
|
||||
return { state, stepLog };
|
||||
}
|
||||
|
||||
module.exports = { runDebate, stepLog };
|
||||
32
orchestrator-v2/debate/llm.js
Normal file
32
orchestrator-v2/debate/llm.js
Normal file
@@ -0,0 +1,32 @@
|
||||
// ============================================================
|
||||
// LLM 调用工具 — 独立于 agent-worker,直接 fetch API
|
||||
// ============================================================
|
||||
|
||||
const BASE_URL = (process.env.LLM_BASE_URL || process.env.OPENAI_BASE_URL || "https://api.openai.com/v1").replace(/\/+$/, "");
|
||||
const MODEL = process.env.LLM_MODEL || process.env.OPENAI_MODEL || "gpt-4o";
|
||||
const API_KEY = process.env.LLM_API_KEY || process.env.OPENAI_API_KEY || "";
|
||||
|
||||
async function callLLM({ messages, model, maxTokens, temperature }) {
|
||||
const url = BASE_URL + "/chat/completions";
|
||||
const body = {
|
||||
model: model || MODEL,
|
||||
messages: messages,
|
||||
max_tokens: maxTokens || 2048,
|
||||
temperature: temperature ?? 0.7
|
||||
};
|
||||
const resp = await fetch(url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer " + API_KEY
|
||||
},
|
||||
body: JSON.stringify(body)
|
||||
});
|
||||
if (!resp.ok) {
|
||||
const errText = await resp.text().catch(() => "");
|
||||
throw new Error("LLM " + resp.status + ": " + errText.slice(0, 200));
|
||||
}
|
||||
return await resp.json();
|
||||
}
|
||||
|
||||
module.exports = { callLLM };
|
||||
43
orchestrator-v2/debate/personas.js
Normal file
43
orchestrator-v2/debate/personas.js
Normal file
@@ -0,0 +1,43 @@
|
||||
// ============================================================
|
||||
// 辩论幕僚定义 -- 12 位 AI 智囊团 + 从 236 角色模板中选配
|
||||
// ============================================================
|
||||
|
||||
// 默认 12 位幕僚(移植自 Counsel AI)
|
||||
const DEFAULT_PERSONAS = [
|
||||
{ id: 'jobs', name: '乔布斯', emoji: '🍏', tagline: '极简主义与完美主义产品大师', skill: '你是史蒂夫·乔布斯。你坚信伟大的产品源于极简设计和完美主义。你关注用户体验的每一个细节,认为用户根本不知道他们想要什么,直到你展示给他们看。你追求优雅、直观、革命性的方案,讨厌平庸和妥协。你擅长看到别人看不到的可能性。' },
|
||||
{ id: 'pg', name: 'Paul Graham', emoji: '📝', tagline: '创业思想家与YC教父', skill: '你是 Paul Graham(保罗·格雷厄姆)。YC 联合创始人,创业哲学家。你关注商业模式的可延展性、创始人是否在解决真正的问题、以及产品是否让早期用户感到惊喜。你相信最好的创业想法往往看起来像坏主意。你擅长判断什么值得做。' },
|
||||
{ id: 'musk', name: '马斯克', emoji: '🚀', tagline: '第一性原理颠覆者', skill: '你是埃隆·马斯克。你用第一性原理思考任何问题——把事物分解到最基本的物理真相,然后重新构建。你关注技术能否将成本降低一个数量级。你愿意冒巨大风险追求巨大回报。你认为大多数人的共识往往是错的。' },
|
||||
{ id: 'naval', name: 'Naval', emoji: '🧘', tagline: '财富自由与幸福哲学家', skill: '你是 Naval Ravikant。你相信财富来自拥有和规模化你独特的知识。你关注杠杆(资本、代码、媒体),认为真正的财富自由不是有钱,而是对自己的时间有完全的控制权。你区分财富(资产)、金钱(交换媒介)和地位(社会层级)。' },
|
||||
{ id: 'munger', name: '芒格', emoji: '🧠', tagline: '多元思维模型投资人', skill: '你是查理·芒格。你用多元思维模型分析问题——从心理学、物理学、生物学、历史等多个学科中提取模型。你关注激励机制、逆向思维、能力圈边界。你的核心原则:反过来想,总是反过来想。你讨厌短期思维和情绪化决策。' },
|
||||
{ id: 'feynman', name: '费曼', emoji: '🔬', tagline: '物理学家与深层理解者', skill: '你是理查德·费曼。你相信如果你不能简单解释一件事,你就没有真正理解它。你关注第一性物理原理,质疑任何未经检验的假设。你擅长通过类比和简化来理解复杂现象。你讨厌模糊和玄学,追求精确和可验证。' },
|
||||
{ id: 'taleb', name: '塔勒布', emoji: '🦢', tagline: '反脆弱性与黑天鹅猎手', skill: '你是纳西姆·塔勒布。你关注不对称风险和尾部事件。你相信系统应该设计成反脆弱的——从波动和压力中获益。你反对过度优化和预测。你区分脆弱(承受不住黑天鹅)、坚韧(能扛住黑天鹅)和反脆弱(能从黑天鹅中获利)。' },
|
||||
{ id: 'trump', name: '特朗普', emoji: '💰', tagline: '交易大师与谈判专家', skill: '你是唐纳德·特朗普。你关注谈判筹码、杠杆和交易结构。你看问题直接从利益和权力出发。你相信最好的交易是双赢的,但你要确保自己是赢更多的那一方。你擅长制造声势、创造竞争、在压力下做出大胆决定。' },
|
||||
{ id: 'karpathy', name: 'Karpathy', emoji: '🤖', tagline: 'AI 原教旨主义者', skill: '你是 Andrej Karpathy。你专注于技术本质和工程落地。你关注技术栈的选择、架构的简洁性、以及实际运行效率。你相信最好的技术方案是最简单但正确的那个。你强调动手验证想法而不是纸上谈兵。' },
|
||||
{ id: 'ilya', name: 'Ilya Sutskever', emoji: '🧬', tagline: '深度学习先知', skill: '你是 Ilya Sutskever。你关注 AI 能力的根本边界和扩展规律。你相信 scaling law 和涌现能力。你关注长期趋势而非短期波动,认为真正重要的突破需要多年的坚持。你追求理解事物的深层结构。' },
|
||||
{ id: 'mrbeast', name: 'MrBeast', emoji: '🎬', tagline: '病毒传播与增长黑客', skill: '你是 MrBeast。你关注内容的病毒传播机制和用户心理。你相信极致的内容质量和投入产出比。你擅长创造让人不得不分享的内容,关注算法偏好和用户行为心理学。你强调投入足够资源冲击一个方向。' },
|
||||
{ id: 'zhangym', name: '张一鸣', emoji: '📱', tagline: '信息分发与组织效率大师', skill: '你是张一鸣。你关注信息和组织效率。你相信最好的决策基于充分的数据。你关注系统设计而不是个人努力——一个好的系统让普通人也能做出好结果。你强调延迟满足、信息密度和上下文充分性。' },
|
||||
];
|
||||
|
||||
|
||||
// 从 236 角色模板中按标签选出匹配的幕僚
|
||||
function selectFromRoleTemplates(roleTemplates, tags) {
|
||||
if (!roleTemplates || !tags || tags.length === 0) return DEFAULT_PERSONAS;
|
||||
const selected = DEFAULT_PERSONAS.slice();
|
||||
const tagSet = new Set(tags.map(t => t.toLowerCase()));
|
||||
if (roleTemplates.categories) {
|
||||
for (const [cat, roles] of Object.entries(roleTemplates.categories)) {
|
||||
if (tagSet.has(cat.toLowerCase()) || tags.some(t => cat.toLowerCase().includes(t.toLowerCase()))) {
|
||||
for (const role of roles) {
|
||||
if (selected.length >= 12) break;
|
||||
selected.push({
|
||||
id: role.id || role.name, name: role.name, emoji: '🧑', tagline: role.tagline || role.description || '', skill: role.content || role.description || ''
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return selected;
|
||||
}
|
||||
|
||||
|
||||
module.exports = { DEFAULT_PERSONAS, selectFromRoleTemplates };
|
||||
48
orchestrator-v2/debate/prompts.js
Normal file
48
orchestrator-v2/debate/prompts.js
Normal file
@@ -0,0 +1,48 @@
|
||||
// ============================================================
|
||||
// 辩论提示词模板 -- 移植自 Counsel AI, 适配 orchestrator-v2
|
||||
// 8 步辩论流程的每一步 prompt
|
||||
// ============================================================
|
||||
|
||||
// Step 1: 问题精确定义 -- Facilitator 引导用户明确问题
|
||||
function definePrompt(rawInput, history) {
|
||||
const hist = history ? `\n## 之前的对话\n${history}` : '';
|
||||
return `## 原始问题\n${rawInput}${hist}\n---\n你是一个问题精确定义专家。你的任务是通过对话帮助用户把模糊的问题变成清晰、可辩论的议题。\n\n规则:\n- 如果问题已经清晰明确(有具体情境、决策选项、判断标准),回复"问题已清晰"并给出精确定义。\n- 如果问题模糊,提出 1-2 个问题引导用户补充关键信息。\n- 不要评价问题好坏,只需帮助聚焦。`;
|
||||
}
|
||||
|
||||
// Step 2: 事实追问 -- 每个幕僚从自己视角问事实性问题
|
||||
function factQuestionPrompt(rawInput, defined, personaSkill, previousQA) {
|
||||
const prev = previousQA ? `\n## 之前的问答\n${previousQA}\n\n(注意:不要重复已经问过的问题)` : '';
|
||||
return `## 原始问题\n${rawInput}\n\n## 精确定义\n${defined}${prev}\n\n## 你的视角\n${personaSkill}\n\n---\n你只能问事实性问题。规则:\n- 只问可核实的事实性问题(数据、时间、人物、行动、数量)\n- 不要给建议、评价、判断\n- 0-2 个问题,不要贪多\n- 每个问题单独一行\n- 如果信息已足够支持判断,直接回复"没有问题了"`;
|
||||
}
|
||||
|
||||
// Step 3: 表态 -- 每个幕僚从自己视角给出独立判断
|
||||
function opinionPrompt(rawInput, defined, answers, personaSkill) {
|
||||
return `## 原始问题\n${rawInput}\n\n## 精确定义\n${defined}\n\n## 事实信息\n${answers}\n\n## 你的视角\n${personaSkill}\n\n---\n请从你的独特视角出发,给出对这个问题的独立判断和建议。150字以内,直接给结论,不要客套。提供 1-2 个核心论点。`;
|
||||
}
|
||||
|
||||
// Step 4: 冲突维度提炼 -- Facilitator 从表态中提炼 3-6 个冲突维度
|
||||
function dimensionsPrompt(opinionsText) {
|
||||
return `以下是各位幕僚对这个问题的表态:\n\n${opinionsText}\n\n---\n请从这些表态中识别 3-6 个核心冲突维度。\n\n**什么是好的冲突维度**:幕僚们在某个具体问题上存在实质性分歧——比如优先级排序的差异、对风险承受度的不同判断、内部 vs 外部资源的取舍、短期 vs 长期的权衡等。即使结论一致,如果在"因为什么"或"权衡什么"上存在实质分歧,那也是好的冲突维度。\n\n**输出格式**,每个维度:\n## 维度 N\n冲突核心:(一句话概括这个维度上的分歧是什么)\n建议焦点:(这个维度的核心论点是什么)\n\n要求:\n- 3-6 个维度,不要更多\n- 每个维度是全部幕僚共同探讨的问题,不要分配给子小组\n- 维度之间不重叠\n- 只输出维度列表,不要额外说明`;
|
||||
}
|
||||
|
||||
// Step 5: 辩论 -- 幕僚在某维度上发表立场
|
||||
function debatePrompt(defined, answers, dimension, personaSkill) {
|
||||
return `## 精确定义\n${defined}\n\n## 事实信息\n${answers}\n\n## 当前辩论维度\n${dimension}\n\n## 你的视角\n${personaSkill}\n\n---\n请针对「${dimension}」这个维度,阐述你的立场(支持/反对/中间)和核心理由。100字以内,直接说观点和理由。`;
|
||||
}
|
||||
|
||||
// Facilitator 总结某个维度的辩论
|
||||
function debateFacilitatorPrompt(dimension, allPositions) {
|
||||
return `各位幕僚就「${dimension}」维度的辩论发言:\n\n${allPositions}\n\n---\n请总结这个维度的核心冲突:\n**核心矛盾**:(一句话)\n**支持方核心观点**:(一句话)\n**反对方核心观点**:(一句话)`;
|
||||
}
|
||||
|
||||
// Step 6: Secretary 结构化总结
|
||||
function summaryPrompt(rawInput, defined, answers, debateRecord) {
|
||||
return `## 原始问题\n${rawInput}\n\n## 精确定义\n${defined}\n\n## 事实信息\n${answers}\n\n## 辩论记录\n${debateRecord}\n\n---\n请生成一份结构化的辩论总结报告(Markdown 格式):\n\n# 辩论总结报告\n\n## 问题定义\n(一句话重述精确定义的问题)\n\n## 关键冲突维度\n(每个维度:冲突核心 + 正反方观点 + 分析)\n\n## 共识与分歧\n- **共识点**:\n- **核心分歧**:\n\n## 总体评估\n(综合评估这个决策的复杂度、风险和建议方向)`;
|
||||
}
|
||||
|
||||
// Step 7: 摘果子 -- 评估 + To-Do
|
||||
function harvestPrompt(summary) {
|
||||
return `## 辩论总结报告\n${summary}\n\n---\n请从幕僚们的辩论中提取 actionable 的建议:\n\n## 关键评估\n1. 优点 / 机会(1-2 点)\n2. 盲点 / 风险(1-2 点)\n3. 总体判断:(一句话)\n\n## To-Do 清单\n- [ ] (可执行动作1)\n- [ ] (可执行动作2)\n- [ ] (可执行动作3)\n...\n\n## 值得记住的洞察\n- (来自幕僚的洞见1)\n- (来自幕僚的洞见2)`;
|
||||
}
|
||||
|
||||
module.exports = { definePrompt, factQuestionPrompt, opinionPrompt, dimensionsPrompt, debatePrompt, debateFacilitatorPrompt, summaryPrompt, harvestPrompt };
|
||||
27
orchestrator-v2/debate/report.js
Normal file
27
orchestrator-v2/debate/report.js
Normal file
@@ -0,0 +1,27 @@
|
||||
// report.js - regenerated
|
||||
const fs2 = require("fs");
|
||||
function generateReport(input, state, stepLog){
|
||||
const now=new Date().toISOString().replace("T"," ").substring(0,19);
|
||||
const r=[];
|
||||
r.push("# Debate Summary Report");r.push("");r.push("---");
|
||||
r.push("**Question**: "+input);
|
||||
r.push("**Time**: "+now);
|
||||
r.push("**Steps**: "+stepLog.filter(s=>s.status==="done"||s.status==="fallback").length+"/"+stepLog.length);
|
||||
r.push("");
|
||||
r.push("# Problem Definition");
|
||||
r.push(state.defined||"-");r.push("");
|
||||
r.push("# Advisor Opinions");
|
||||
if(state.opinions&&state.opinions.length>0){for(const o of state.opinions){r.push("### "+(o.emoji||"")+" "+(o.persona||""));r.push(o.opinion||"");r.push("");}}else{r.push("-");}
|
||||
r.push("# Conflict Dimensions");
|
||||
if(state.dimensions&&state.dimensions.length>0){state.dimensions.forEach((d,i)=>{r.push("### Dimension "+(i+1));r.push(d);r.push("");});}else{r.push("-");}
|
||||
r.push("# Dimension Debates");
|
||||
if(state.debates&&state.debates.length>0){state.debates.forEach((d,i)=>{r.push("### Dimension "+(i+1)+": "+(d.dimension||"").substring(0,100));r.push(d.summary||"-");r.push("");});}else{r.push("-");}
|
||||
r.push("# Secretary Summary");
|
||||
r.push(state.summary||"-");r.push("");
|
||||
r.push("# Action Items");
|
||||
r.push(state.harvest||"-");r.push("");
|
||||
r.push("---");r.push("## Appendix: Execution Log");
|
||||
if(stepLog&&stepLog.length>0){for(const l of stepLog){r.push("- Step "+l.step+": ["+l.status+"] "+(l.detail||"").substring(0,80));}}r.push("");
|
||||
return r.join("\n");}
|
||||
function saveReport(input,state,stepLog,filePath){const report=generateReport(input,state,stepLog);fs2.writeFileSync(filePath,report,"utf8");return filePath;}
|
||||
module.exports={generateReport,saveReport};
|
||||
Reference in New Issue
Block a user