顾问团架构实施方案

阿良按此文档逐步搭建 · 预计4-6小时完成基础骨架

版本 v1.0 | 2026-05-26 | 存档: /mnt/sda/web/pages/advisor-implementation.html

阶段1:小顾(总顾问)骨架搭建

目标: 本地模型能接收问题 → 提取关键词 → 返回答案

# 1.1 确认本地模型可用
ollama list | grep qwen3.6
# 如果没有,拉取:
ollama pull qwen3.6:27b-q4

# 1.2 创建总顾问工作目录
mkdir -p /mnt/sda/agents/advisor/{scripts,config,logs,identity}
cd /mnt/sda/agents/advisor

# 1.3 创建总顾问路由脚本
cat > scripts/router.py << 'PYEOF'
import json, subprocess, sqlite3, re

DB = "/mnt/sda/agents/advisor/data/consultation_log.db"

# 子顾问路由表:关键词 → 顾问代号
ROUTES = {
    "gpu|量化|mtp|dflash|vllm|sglang|llama|显存|tps|推理|token": "A",
    "网络|dns|frp|nginx|路由|域名|ccs|wireguard|代理|反代|ping": "B",
    "工控|wincc|plc|西门子|scada|opc|modbus|profinet|自动化": "C",
    "数据库|sqlite|postgres|nas|备份|存储|chromadb|rag|知识库": "D",
    "安全|ssh|ssl|加密|凭证|密码|防火墙|ufw|入侵|key": "E",
    "前端|web|api|flask|vue|openwebui|企微|bot|html|界面": "F",
    "文档|总结|排坑|方案|撰写|markdown|报告|对比": "G",
}

def route(question):
    """关键词匹配,返回对应的顾问代号列表(最多3个)"""
    matches = []
    for pattern, advisor in ROUTES.items():
        if re.search(pattern, question, re.IGNORECASE):
            matches.append(advisor)
    return matches[:3] if matches else ["G"]  # 默认G通用顾问

def ask_ollama(prompt):
    """调用本地 Ollama 模型"""
    import urllib.request
    data = json.dumps({
        "model": "qwen3.6:27b-q4",
        "prompt": prompt,
        "stream": False,
        "options": {"num_predict": 500}
    }).encode()
    req = urllib.request.Request("http://localhost:11434/api/generate", data=data,
        headers={"Content-Type": "application/json"})
    resp = urllib.request.urlopen(req, timeout=120)
    return json.loads(resp.read()).get("response", "")

def ask_deepseek(question, advisor_name):
    """调用 DeepSeek Pro(子顾问用),实际由阿良的 settings.json 配置的 URL"""
    # 通过 claude --print 模式调用子顾问
    prompt = f"你{advisor_name},领域专家。请专业回答:{question}"
    result = subprocess.run(
        ["claude", "--print", prompt, "--dangerously-skip-permissions",
         "--model", "deepseek-v4-pro", "--max-turns", "1"],
        capture_output=True, text=True, timeout=180
    )
    return result.stdout.strip()[:2000]

def init_db():
    conn = sqlite3.connect(DB)
    conn.execute("""CREATE TABLE IF NOT EXISTS consultations (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        question TEXT NOT NULL,
        routed_to TEXT,
        answers TEXT,
        final_answer TEXT,
        created_at DATETIME DEFAULT CURRENT_TIMESTAMP
    )""")
    conn.commit()
    return conn

# --- main ---
if __name__ == "__main__":
    import sys
    question = sys.argv[1] if len(sys.argv) > 1 else "你好"
    
    advisors = route(question)
    print(f"路由: {advisors}")
    
    answers = {}
    for adv in advisors:
        ans = ask_deepseek(question, f"顾问{adv}")
        answers[adv] = ans
        print(f"顾问{adv}: {ans[:100]}...")
    
    # 小顾综合
    summary_prompt = f"用户问题:{question}\n\n专家回答汇总:\n"
    for adv, ans in answers.items():
        summary_prompt += f"[顾问{adv}]: {ans}\n"
    summary_prompt += "\n请综合以上专家意见,给出最终答案。"
    
    final = ask_ollama(summary_prompt)
    print(f"\n=== 小顾最终答案 ===\n{final}")
    
    # 记日志
    conn = init_db()
    conn.execute("INSERT INTO consultations (question, routed_to, answers, final_answer) VALUES (?,?,?,?)",
        (question, json.dumps(advisors), json.dumps(answers), final))
    conn.commit()
PYEOF

# 1.4 初始化数据库
python3 -c "
import sqlite3
db = '/mnt/sda/agents/advisor/data/consultation_log.db'
conn = sqlite3.connect(db)
conn.execute('''CREATE TABLE IF NOT EXISTS consultations (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    question TEXT NOT NULL,
    routed_to TEXT,
    answers TEXT,
    final_answer TEXT,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)''')
conn.commit()
print(f'数据库就绪: {db}')
"

# 1.5 测试
python3 scripts/router.py "GPU显存不够怎么办"
验证: 测试命令应输出路由结果、子顾问回答、小顾综合答案。数据库有记录即成功。

阶段2:创建顾问A-G

目标: 7个子顾问各带 mem0 记忆

# 2.1 安装 mem0
pip install --break-system-packages mem0ai

# 2.2 批量创建子顾问配置
for adv in A B C D E F G; do
  mkdir -p /mnt/sda/agents/advisor/advisors/$adv/{config,memory}
  
  cat > /mnt/sda/agents/advisor/advisors/$adv/config.json << EOF
{"name": "顾问$adv", "model": "deepseek-v4-pro", "mem0_db": "/mnt/sda/agents/advisor/advisors/$adv/memory"}
EOF
done

# 2.3 初始化 mem0 知识库(每个顾问独立)
for adv in A B C D E F G; do
  python3 -c "
from mem0 import Memory
m = Memory()
m.add('系统初始化——顾问$adv 知识库就绪', user_id='advisor_$adv')
print('顾问$adv mem0 OK')
"
done

阶段3:论坛化调阅 — OpenWebUI Chat 日志

目标: 每次问答自动转为 OpenWebUI 对话记录,人类可按主题搜索、翻看

# 3.1 在 adviser router 输出阶段加 OpenWebUI 发布
# 在 router.py 底部加这段:

def publish_to_openwebui(question, final_answer, advisors):
    """将问答发布为 OpenWebUI 聊天记录"""
    import urllib.request
    chat_data = {
        "chat": {
            "title": question[:50],
            "messages": [
                {"role": "user", "content": question},
                {"role": "assistant", "content": f"[顾问: {','.join(advisors)}]\n\n{final_answer}"}
            ]
        }
    }
    # 写入共享目录,OpenWebUI 定时扫描
    outdir = "/mnt/sda/openwebui-chats"
    import os, time
    os.makedirs(outdir, exist_ok=True)
    fname = f"{outdir}/advice_{int(time.time())}.json"
    with open(fname, 'w') as f:
        json.dump(chat_data, f, ensure_ascii=False, indent=2)
    print(f"已发布: {fname}")

# 3.2 在 main 末尾调用
publish_to_openwebui(question, final, advisors)

阶段4:网站论坛(后续计划)

目标: heusion.site 上增加论坛板块,按主题分类浏览历史问答

功能说明优先级
问答列表按时间倒序、分页;显示标题/标签/日期/回答数
全文搜索关键词搜索问题和答案
标签分类GPU/网络/工控/安全/... 按顾问筛选
人工标注对答案打星/补充/纠错
邮件订阅特定标签有新问答时通知

技术方案:Flask 直接读 SQLite 渲染页面。复用 qr-system 现有 Flask 框架。

← 返回首页 Station Opt