| 层 | 名字 | 干什么 | 我方真实实现(文件 / 端点) | 状态 |
|---|---|---|---|---|
| 10 | 前端层 | 对话界面 + 流式渲染 | 本草大脑_v149/frontend/index.html · getReader 流式 | 有 |
| 9 | 会话 / 记忆层 | 多轮 + 长短记忆 | routers/chat.py 会话表 + plugins/memory_layers.py 五层记忆 | 有(超配) |
| 8 | API 网关 | 统一入口 / 鉴权 / 限流 / SSE | 8979(916 端点)+ 8981(144 端点)· _bre_hits 限流 | 有 |
| 7 | Agent 编排 | 调度:想 → 派活 → 执行 → 答 | agents.py route_intent/swarm + plugins/leader.py + 蜂群调度中枢 | 超配 |
| 6 | 工具层 | 查行情 / 识药 / 煎药 / 配伍… | 名册 gen-164 · 165 台 + ask 带参 + federate 联邦 | 超配 |
| 5 | RAG 检索 | 找知识 + 门槛拒答 | 166 个 bre/*.py 规则引擎 + herbs/search · prescriptions/search | 部分(向量未接) |
| 4 | 数据层 | 语料库 + 向量管道 | 种子种苗档案 + backend/kg/ 本体 + 采集蜂 20 表 + 护栏库 | 有 |
| 3 | 微调层 | 自有模型 | train/ lora+dpo+评测全套 · yaocai-q4-v5 已入 ollama | 有(超配) |
| 2 | 模型层 | 出答案的脑子 | 6 模型:qwen2.5:7b / qwen2.5vl:7b / yaocai-q4-v5 / bge-m3 | 有 |
| 1 | 基础设施 | 推理 / 存储 / 服务 | ollama 11434 自部署 + MariaDB 3307 + 80/8979/8981 三服务 | 有 |
★ 一句话:十层我方 8 层齐、其中 3 层是超配(K3 图纸没有的咱有);真缺口只有 ① 向量检索管道(pgvector/bge-m3 已备、未接)② 前端 Markdown / 代码高亮渲染 ③ 会话多轮串接。
我方实现:本地 ollama(端口 11434),模型归档在 D:\ollama_models(OLLAMA_MODELS 环境变量)。不走外脑 API,自己机器上跑——好处:数据不出门、零调用费、断网可用。
给 K3 的话:起步可先接外脑 API(快),但记住这条路是「租脑子」;攒够语料就走我方这条——本地 ollama / vLLM 自部署,模型归自己。
| 端口 | 服务 | 入口 | 作用 |
|---|---|---|---|
| 80 | 静态页服务 | _serve_web.py | 全站 HTML,反代 /api → 8979 |
| 8979 | 药材谷后端 | 后端路由/main.py | 交易/采集/蜂群等 916 个端点 |
| 8981 | 本草大脑底座 | 本草大脑_v149/backend/main.py | 大模型对话 + 166 引擎,144 端点 |
| 3307 | MariaDB | _数据库/mariadb_data | 会话/消息/用户/配额落库 |
| 模型 | 干什么 | 我方用法 |
|---|---|---|
| yaocai-q4-v5 | 药材谷专用(第 5 版微调) | 对话台默认「Yaocaigu-4B」 |
| qwen2.5:7b | 通用对话 | 兜底 / 角色扮演 |
| qwen2.5vl:7b | 视觉理解 | 真读图——拍照识药 |
| bge-m3 | 向量化 | 语义检索(管道待接) |
注意:另有 2 个模型属别的项目,我方页面用白名单 屏蔽过滤,不混用。
真实文件:train/ 下有 lora_train.py(LoRA SFT)· dpo_train.py(偏好对齐)· prepare_sft.py(语料制备)· merge_lora.py(合权重)· evaluate.py(评测)· 数据配方.md。
产出:yaocai-q4-v5 已经练出来并入 ollama。自训服务器:药材谷自己的香港服务器 43.161.221.92(不是别家的机器),训练管线待部署。
K3 可直接抄:这一层就是「合脑子」的车间——素材(prepare)→ SFT(lora)→ 对齐(dpo)→ 合并(merge)→ 评测(evaluate)五步,缺一不可。
种子种苗档案:后端路由/data/seedling.json 等 4 表(含意向单、跳单防控)。
知识图谱本体:本草大脑_v149/backend/kg/ontology_loader.py——五层记忆的语义层会往这里沉淀三元组(见第五节)。
采集蜂数据:后端路由/data/swarm_*.json 共 20 个(行情/资讯/审核/集群…)。
护栏库:backend/guard/(违禁词 / 敏感词 / 内容护栏 / 记忆护栏)——输入输出都要过安检。
我方特色:166 个 bre/*.py——把中医药知识写成确定性规则引擎(配伍禁忌 / 道地 / 炮制 / 采收 / 煎药…)。查得到的可解释、可复现、不会瞎编;这是向量检索给不了的确定性。
已暴露检索端点:GET /api/v1/herbs/search · /api/v1/prescriptions/search(关键词检索)。
缺口(如实说):向量检索管道未接——bge-m3 模型已在册,但「切块 → 向量化 → pgvector → 检索 top5 → 门槛拒答」这条链还没串。这正是 K3 药方二要补的 minScore 0.72 那段。
给 K3 的话:你那边规则 + 向量两条腿都要:规则管「确定的硬知识」(禁忌/剂量),向量管「软资料」(药典全文/行情资讯)。只靠向量会飘,只靠规则不够广。
名册:plugins/agents/manifest.json → version gen-164 · 165 台 · 已接线 164 · 孤儿 0(生成物,跑 tools/rebuild_manifest.py 重生)。
三个通用端点(照抄即可):
GET /api/v1/bre/{engine}/demo # 无参演示
GET /api/v1/bre/{engine}/ask?herb=附子 # 带参真查(#276 新增)
GET /api/v1/bre/federate?herb=附子 # 联邦:19 台并行(#277)
要点:ask 用 inspect 嗅探函数首参名自动传参;federate 扫名册自动发现「接受药材入参」的引擎并行执行——新引擎上线自动入列,不用改代码。这比一个个写 function calling 省事得多。
真实实现:routers/chat.py —— 每轮把 user/assistant 消息写 Session_ / Message 两张表;/api/v1/chat/history 列最近 50 个会话、/{sid}/messages 取回某会话全部消息(这就是「跨会话历史」的真身)。
缺口(如实说):主前端 index.html 发送时 session_id:null → 每次是全新会话,暂未把上一轮历史喂回。后端能力已就绪,前端续聊待接。
真实文件:backend/plugins/memory_layers.py —— FiveLayerMemory(v154·v31 图纸):
| 层 | 装什么 | 机制 |
|---|---|---|
| ① 工作记忆 Working | 当前任务 | dict 键值 |
| ② 短期记忆 Short | 最近对话 | 滑窗 window=10,超窗 pop(0) → 挤进长期摘要 |
| ③ 情景记忆 Episodic | 事件 / 成交 | mark_episode(title,data) |
| ④ 长期记忆 Long | 用户画像 + 摘要 | learn(k,v);老对话压成 summaries |
| ⑤ 语义记忆 Semantic | 实体→事实 | absorb(实体,事实),联动知识图谱本体沉淀三元组 |
# 出 prompt 前取上下文(真代码)
m.context() → {working, recent=short[-5:], episodes=episodic[-3:],
profile=long, knowledge=semantic[:5]}
给 K3 的话:你的「短期滑窗 6 轮 + 长期画像表」是对的,但可以再拆细——添上「情景记忆(干过哪些事)」和「语义记忆(沉淀成图谱)」两层,系统才会越用越像老中医,而不只是记住你叫啥。
真实文件:backend/bre/nightly_consolidation.py —— Consolidator.sleep():白天的日间轨迹 → 压缩短记忆 → 蒸馏实体(absorb 进语义层)→ 去重 → 写明日就绪报告。
每日进化编排:backend/plugins/daily_loop.py —— 一键夜巡四步:好奇心(白天缺口) → 守夜人(睡眠巩固) → 梦境(反事实推演) → 进化闭环(明日任务),服务器 crontab 02:00 跑。
# daily_loop 夜巡(真代码节选) step1 = 好奇心() # 找白天没答上的缺口 step2 = 守夜人.sleep(日间轨迹, 记忆) # 压缩+蒸馏+去重 step3 = 梦境.dream(决策) # 反事实推演 step4 = 进化() # 明日按清单执行
给 K3 的话:记忆不是存了就行,要「睡一觉」才会长脑子——白天积累,夜里压缩蒸馏去重。这条是很多底座忽略的,抄走。
我方另有四张浏览器本地台账(localStorage),把记忆治理做成了可视页面:
| 页 | 键 | 作用 |
|---|---|---|
| AGI 记忆巩固台 | yc_agi_memory | 新经验→向量比对→新增/合并/冲突 |
| AGI 记忆闭环台 | yc_agi_loop | 增量幂等沉淀 + 自动轮询回写 |
| AGI 评审团能力看板 | yc_agi_tracks | 轨迹 / 工具成功 / 评审一致率度量 |
| AGI 冲突预裁台 | yc_agi_governance | 六规则冲突预裁 + 人工留口 |
真实文件:backend/agents.py → route_intent(query, has_image, skills) —— 用关键词/规则把问题分派给对应引擎:
# 真代码节选:问题 → 派哪些引擎 图片 或 skills含identify → ["herb_identify"] # 识药 方/剂量/禁忌/配伍/反/畏 → ["prescription_audit","herb_info"] # 审方 《/古籍/原文/古人 → ["classics"] # 古籍 价格/行情/涨/产地 → ["market","herb_info"] # 行情 写/PPT/方案/合同/文案 → ["writer"] # 代写 种植N亩/投资成本 → ["calculator"] # 测算 兜底 → ["herb_info"]
更高级的决策:plugins/decision_router.py —— DecisionRouter:配了 vLLM 地址就用小模型输出结构化决策 {choice,score,prob};没配就规则兜底(零依赖)。LLM 决策 + 规则兜底双模。
另有:plugins/leader.py identify() 意图路由 + plugins/agents/driver.py 按 manifest 取 engine 并 __import__ 调用(派单执行)。
# agents.py swarm() 真代码节选——多引擎并行 plan = route_intent(query, has_image, skills) if 并行(默认开) and len(plan) > 1: tasks = [协程(识药) if 识药 else 线程池(引擎) for 引擎 in plan] results = await asyncio.gather(*tasks) # ← 真并行,不是排队 else: results = [串行执行每个引擎] content = safety_review(results, plan) # 汇总后过安全复核 return {content, sources, agents=plan}
要点:多个引擎用 asyncio.gather + 线程池真并行(识药是协程、其余同步引擎丢线程池),不是一个个等。K3 的 ReAct 循环(转 3 圈封顶)是串行工具调用;我方这套是「一次派多个、并行收结果」——两条路各有场景:追问式多轮用 ReAct,一次要多源汇总用并行。
真实文件:后端路由/routes/swarm_orchestrator.py —— 定位是「架在底座之上的编排层」,把 任务入队 → 自动派单(按职能匹配蜂群) → 工位执行 → 心跳巡检 → 失败重试 → 熔断 串成自动闭环。
# 派单规则(真代码节选) RULES = { "collect": {组:"采集蜂", 执行器:"swarm_collect", human_gate:False}, "content": {组:"内容蜂", 执行器:"swarm_content", human_gate:False}, ... } # 铁律①:human_gate=True 的职能(发布/资金)自动派单只到「待人工确认」,绝不自动执行
18 个蜂群模块(在 后端路由/routes/):采集/内容/情报/审核/营销/集群/流水线/名册/技能/资金闸门/治理…
给 K3 的话:「分群怎么调度」的答案是——先按职能分群(采集蜂/内容蜂/情报蜂…),再来一个中枢按任务职能自动派单,超权限的(对外发布、花钱)必须留人工闸门。别让 Agent 手里没缰绳。
我方两处定时:① 夜巡(daily_loop,crontab 02:00,见 9.3);② 后端 后台守护线程(security.py / seed_data.py / routers/bre.py 等 6 个模块用 threading 起常驻线程)。
# 与 K3 的 cron 写法对应(我方同构、真实在跑)
cron.schedule('* * * * *', async ()=>{
待办 = 查任务表(下次运行 < 现在)
for 任务 of 待办: 结果 = 执行(); SSE推(用户, 结果); 更新下次运行时间
})
K3 可直接抄:任务表 + 每分钟扫描 + 到点执行 + SSE 推 + 自动算下次时间——正是你文件里那段,逻辑等价。
文件 backend/routers/chat.py。先算完,再按 24 字分块推。
async def gen():
yield f"data: {{'session_id':sid,'agents':[...]}}\n\n"
for i in range(0, len(content), 24):
yield f"data: {{'delta': content[i:i+24]}}\n\n"
yield f"data: {{'sources':[...],'done':True}}\n\n"
return StreamingResponse(gen(),
media_type="text/event-stream")
前端 index.html:getReader() → 按 \n\n 切块 → 解析 data: → 把 d.delta 追加 DOM;d.agents 显示蜂群路由链。
文件 药材谷_本地大模型对话台。模型出一个 token 推一个(TTFT 最低)。
// 对话台真代码
fetch(base()+'/api/chat', {method:'POST',
body: JSON.stringify({model, messages, stream:true,
options:{temperature:0.2, top_p:0.8}})})
// ollama 回 NDJSON,逐行解析:
if(j.message && j.message.content) onToken(j.message.content)
if(j.done) final = j
前端 getReader() + TextDecoder + {stream:true} → 打字机效果。
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
# 每条事件格式: data: {json}\n\n ← 双换行分隔,前端按 \n\n 切块
主前端文件:本草大脑_v149/frontend/index.html(左抽屉 11 项 / 中间 hero+chips → 对话流 / 底部输入框)。
输入框:textarea(问药材、方剂、鉴别、行情…)+ 「+上传照片」+ 模型标识 Yaocaigu-4B · 进阶 + 发送「↑」+ 快捷 chips(药材鉴别/方药解析/煎法推荐/行情速览/配伍禁忌)。回车发送、按钮置灰防重复提交。
输出框:#msgs 消息流(用户气泡右 / 助手气泡左),助手气泡顶部实时显示「蜂群路由中… → herb_info → market · 已作答」。
K3 可照抄的防卡五机关(对应你文件 8.2):① rAF 批量刷 DOM(别每个 token 都 setState)② 句子级渲染(攒够一句再刷)③ AbortController 停止键④ 流式 Markdown 安全渲染 ⑤ 发送防抖。我方侧重 ①②⑤,③④(停止键 / Markdown 渲染)是待补项。
① Markdown / 代码高亮渲染:当前输出是纯文本 textContent 追加,未做 Markdown 流式渲染;② 引用角标:sources 已随流返回,前端未渲染角标;③ 停止键:未接 AbortController。
这三项正是 K3 图纸里比我们细的地方,照抄回去补上即可。
用户输入"当归今天什么价"
① 前端 index.html:send() → 存 user 消息 → POST /api/v1/chat/completions
(session_id:null → 后端新建会话)
② 网关 8981:check_and_consume_quota 配额 → 存 Session_/Message 落库
③ 编排 agents.swarm():route_intent("价格/行情" → ["market","herb_info"])
④ 并行:market + herb_info 两个引擎 asyncio.gather 同时跑
⑤ 汇总 safety_review() 过安全复核 → 得 {content, sources, agents}
⑥ 网关 SSE:先推 {agents} → 按 24 字推 {delta} → 推 {sources, done}
⑦ 前端 getReader → 按 \n\n 切块 → d.delta 追加 DOM → 「已作答」
= 内容先审后发、多引擎并行、前端边收边显
| 维度 | 口诀 | 我方真实对应 |
|---|---|---|
| 输入 | 带画像、带资料 | 五层记忆 context() 注入 + 检索资料拼 prompt |
| 调度 | 先分群、再派单、超权限留闸门 | 蜂群调度中枢 RULES + human_gate 铁律 |
| 输出 | 一块一推、一帧一刷 | SSE 分块 / 真 token 流 + getReader + rAF |
| 记忆 | 短期滑窗、长期入库、夜里睡一觉 | 五层记忆 + 守夜人 + 每日进化编排 |
| 不知道 | 拒答不瞎编 | 规则引擎确定性 + RAG 门槛(待接)+ 安全复核 |