初始化
This commit is contained in:
178
docs/agent_lifecycle.md
Normal file
178
docs/agent_lifecycle.md
Normal file
@@ -0,0 +1,178 @@
|
||||
# AI Agent 生命周期详解
|
||||
|
||||
## 概述
|
||||
|
||||
本文档详细描述中医AI Agent的完整生命周期,以"患者主诉生成病历"和"病历生成处方"两个核心场景为例。
|
||||
|
||||
---
|
||||
|
||||
## 通用生命周期(6个阶段)
|
||||
|
||||
```
|
||||
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌──────────┐ ┌─────────┐ ┌─────────┐
|
||||
│ ①感知 │───▶│ ②规划 │───▶│ ③检索 │───▶│ ④工具 │───▶│ ⑤反思 │───▶│ ⑥输出 │
|
||||
│ │ │ │ │ │ │ 调用 │ │ 校验 │ │ │
|
||||
└─────────┘ └─────────┘ └─────────┘ └──────────┘ └─────────┘ └─────────┘
|
||||
▲ │
|
||||
│ │
|
||||
└────────────────────── 记忆沉淀(长期学习) ◀──────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 场景A:患者主诉 → 生成病历
|
||||
|
||||
### 时序图
|
||||
|
||||
```
|
||||
患者/医生 Go服务(Controller) Agent Runner LLM MaxKB 规则引擎
|
||||
│ │ │ │ │ │
|
||||
│ POST /emr/gen │ │ │ │ │
|
||||
│──────────────────▶│ │ │ │ │
|
||||
│ │ CreateSession │ │ │ │
|
||||
│ │─────────────────────▶│ │ │ │
|
||||
│ │ │ 注入System Prompt │ │ │
|
||||
│ │ │─────────────────▶│ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ 思考:需要检索病历模板 │ │
|
||||
│ │ │ 调用工具:maxkb_retrieve │ │
|
||||
│ │ │───────────────────────────────────────────────▶│
|
||||
│ │ │ │ │ RAG检索 │
|
||||
│ │ │ │ │ 返回规范片段 │
|
||||
│ │ │◀────────────────────────────────────────────────│
|
||||
│ │ │ │ │ │
|
||||
│ │ │ 生成病历初稿 │ │ │
|
||||
│ │ │─────────────────▶│ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ 规则校验 │ │ │
|
||||
│ │ │──────────────────────────────────────────────────────────▶│
|
||||
│ │ │ │ │ │
|
||||
│ │ │ 有issues?─────Yes──▶ 反思修正循环 │ │
|
||||
│ │ │────No──▶ 输出最终结果 │ │
|
||||
│ │ │ │ │ │
|
||||
│◀─────────────────│ JSON Response │ │ │ │
|
||||
│ │ │ │ │ │
|
||||
```
|
||||
|
||||
### 详细步骤
|
||||
|
||||
| 阶段 | 动作 | 涉及组件 | 代码位置 |
|
||||
|------|------|----------|----------|
|
||||
| ①感知 | 接收HTTP请求,解析JSON,创建Agent会话 | handler.EMRHandler.Generate | internal/handler/emr_handler.go |
|
||||
| ②规划 | LLM分析任务:需要哪些信息?检索什么? | agent.Runner.Run → LLM | internal/agent/runner.go |
|
||||
| ③检索 | 调用MaxKB获取病历模板、术语规范 | tool.MaxKBRetrieveTool | internal/tool/maxkb.go |
|
||||
| ④工具 | 可选:查HIS获取患者病史 | tool.HISTool | internal/tool/agent_tools.go |
|
||||
| ⑤反思 | 规则引擎检查完整性,不通过则修正 | rule.EMRQualityChecker | internal/rule/rule_engine.go |
|
||||
| ⑥输出 | 返回结构化病历JSON + 质控结果 | handler响应封装 | internal/handler/emr_handler.go |
|
||||
|
||||
---
|
||||
|
||||
## 场景B:病历 → 生成处方
|
||||
|
||||
### 时序图
|
||||
|
||||
```
|
||||
医生 Go服务 Agent Runner LLM MaxKB 规则引擎
|
||||
│ │ │ │ │ │
|
||||
│ POST /rx/gen │ │ │ │ │
|
||||
│──────────────────▶│ │ │ │ │
|
||||
│ │ CreateSession │ │ │ │
|
||||
│ │───────────────────▶│ │ │ │
|
||||
│ │ │ System Prompt注入 │ │ │
|
||||
│ │ │─────────────────▶│ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ 辨证:太阳伤寒表实证 │ │
|
||||
│ │ │ 检索经典方剂 │ │ │
|
||||
│ │ │──────────────────────────────────▶│ │
|
||||
│ │ │ │ │ 返回麻黄汤 │
|
||||
│ │ │◀──────────────────────────────────│ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ 生成处方初稿 │ │ │
|
||||
│ │ │─────────────────▶│ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ 配伍禁忌校验 ◀──────────────────────────────────────────────│
|
||||
│ │ │ 剂量校验 ◀──────────────────────────────────────────────│
|
||||
│ │ │ 孕妇安全检查 ◀──────────────────────────────────────────────│
|
||||
│ │ │ │ │ │
|
||||
│ │ │ Blocked? ──Yes──▶ 重新组方(反思循环) │
|
||||
│ │ │────No──▶ 输出处方 │ │
|
||||
│ │ │ │ │ │
|
||||
│◀─────────────────│ JSON Response │ │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ 医生审核确认 │ │ │ │ │
|
||||
│ POST /rx/:id/approve │ │ │ │
|
||||
│──────────────────▶│ 写入审计日志 │ │ │ │
|
||||
│ │──────────────────────────────────────────────────────────────────────▶│
|
||||
│ │ │ │ │ │
|
||||
```
|
||||
|
||||
### 详细步骤
|
||||
|
||||
| 阶段 | 动作 | 涉及组件 | 安全级别 |
|
||||
|------|------|----------|----------|
|
||||
| ①感知 | 接收病历+患者信息,创建会话 | handler.PrescriptionHandler | - |
|
||||
| ②规划 | LLM辨证→确定治则治法→选方思路 | agent.PrescriptionGenerator | - |
|
||||
| ③检索 | MaxKB检索对应证型的经典方剂 | tool.MaxKBRetrieveTool | 知识来源 |
|
||||
| ④工具 | 药典查询验证剂量、HIS查过敏史 | tool.PharmacopoeiaTool | 数据支撑 |
|
||||
| ⑤反思 | **十八反十九畏硬校验** | rule.PrescriptionValidator | 🔴 硬拦截 |
|
||||
| ⑤反思 | 孕妇/儿童剂量调整 | rule.PrescriptionValidator | 🟡 警告 |
|
||||
| ⑤反思 | 过敏史冲突检查 | rule.PrescriptionValidator | 🔴 硬拦截 |
|
||||
| ⑥输出 | 结构化处方 + Human-in-the-Loop | handler响应 + 医生审核 | 🟢 人工兜底 |
|
||||
|
||||
---
|
||||
|
||||
## 安全设计原则
|
||||
|
||||
### 三层防护体系
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ Layer 3: 人工审核(Human-in-the-Loop) │ ← 最后防线
|
||||
│ 医生审核确认每一张处方 │
|
||||
├─────────────────────────────────────────────────┤
|
||||
│ Layer 2: 规则引擎(硬约束,独立于LLM) │ ← 核心防线
|
||||
│ 十八反十九畏 / 剂量上限 / 孕妇禁忌 / 过敏冲突 │
|
||||
├─────────────────────────────────────────────────┤
|
||||
│ Layer 1: MaxKB知识库(事实基础) │ ← 知识防线
|
||||
│ 药典规范 / 经典方剂 / 临床指南 │
|
||||
└─────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 关键原则
|
||||
|
||||
1. **LLM不做最终决策** —— 只负责语言理解和推理,不负责医疗判断
|
||||
2. **规则引擎独立运行** —— 不依赖LLM的自检,用确定性代码做硬校验
|
||||
3. **每次修正都有审计日志** —— 谁在什么时间做了什么修改,全链路可追溯
|
||||
4. **Human-in-the-Loop** —— 处方最终必须经过医生确认才能生效
|
||||
|
||||
---
|
||||
|
||||
## 配置 MaxKB 知识库
|
||||
|
||||
### 快速部署
|
||||
|
||||
```bash
|
||||
# Docker一键启动MaxKB
|
||||
docker run -d --name maxkb -p 8080:8080 1panel/maxkb
|
||||
|
||||
# 访问 http://localhost:8080
|
||||
# 默认账号: admin / MaxKB@123..
|
||||
```
|
||||
|
||||
### 推荐上传的文档
|
||||
|
||||
| 分类 | 文档示例 | 用途 |
|
||||
|------|----------|------|
|
||||
| 药典 | 《中国药典》2020版(中药部分) | 剂量、性味归经、禁忌 |
|
||||
| 方剂 | 《方剂学》教材 / 《伤寒论》原文 | 经典方剂组成与主治 |
|
||||
| 规范 | 《中医病历书写规范》 | 病历模板与质控标准 |
|
||||
| 指南 | 各病种中医诊疗指南 | 辨证分型与治法 |
|
||||
| 内部分享 | 本院名老中医经验方 | 院内知识沉淀 |
|
||||
|
||||
### 获取API Key
|
||||
|
||||
1. 登录MaxKB控制台
|
||||
2. 进入「应用管理」→ 创建应用
|
||||
3. 选择知识库 → 配置模型
|
||||
4. 在「API Key管理」中生成 Key
|
||||
5. 将 Key 和 AppID 填入 `manifest/config/config.yaml`
|
||||
223
docs/architecture.md
Normal file
223
docs/architecture.md
Normal file
@@ -0,0 +1,223 @@
|
||||
# TCM Agent 架构说明(现状版)
|
||||
|
||||
> 更新时间:2026-08-11
|
||||
> 适用版本:加固 + 观测面板落地之后的代码(含 RunLog / 医疗守卫 / DB 配置热加载 / Function Calling 完整协议)
|
||||
|
||||
本文档回答四个问题:**现在长什么样(架构)、一次请求怎么走(流程)、哪里还有坑(隐患)、为什么这样设计(优势)**。
|
||||
|
||||
---
|
||||
|
||||
## 一、架构总览
|
||||
|
||||
### 1.1 系统定位
|
||||
|
||||
Go Agent 是「PHP 主业务系统」的 **AI 增强侧车**:PHP 负责组装 prompt、落库、面向前端;Go 负责知识库检索、ReAct 多步推理、多模型调度与降级。PHP 挂了 Go 没意义,Go 挂了 PHP 可以降级为直连模型(`ai_agent_via_agent=0`)。
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph php[PHP 主系统 xk-api]
|
||||
assist[AiMedicalAssistService<br/>组装 system/user messages]
|
||||
factory[AiAgentFactory<br/>按 ai_agent_via_agent 决定直连或走 Go]
|
||||
stepTable[(xk_ai_generation_step<br/>历史步骤审计表)]
|
||||
end
|
||||
|
||||
subgraph go[Go Agent nl-tcm-agent]
|
||||
auth[middleware.Auth<br/>JWT + SharedSecret 双轨]
|
||||
sem[并发信号量 16<br/>超限 503]
|
||||
enhancer[EnhancerService.Enhance<br/>包装层:统一埋点]
|
||||
guard[medical_guard<br/>医疗相关性守卫]
|
||||
react[ReactLoop<br/>Plan → Think-Act-Observe → Reflection]
|
||||
resolve[resolveClient<br/>DB 优先解析生效模型]
|
||||
runlog[RunLog 环形缓冲<br/>内存 200 条]
|
||||
panel[/agent/view 观测面板/]
|
||||
end
|
||||
|
||||
subgraph db[MySQL z_xk]
|
||||
syscfg[(xk_system_config<br/>生效模型/开关)]
|
||||
aikey[(xk_ai_model / xk_ai_api_key<br/>模型池与密钥 AES 加密)]
|
||||
kbtbl[(xk_kb_* 本地知识库)]
|
||||
end
|
||||
|
||||
subgraph llmv[模型供应商]
|
||||
spark[讯飞 Spark]
|
||||
dsk[DeepSeek]
|
||||
oai[OpenAI 兼容]
|
||||
end
|
||||
|
||||
assist --> factory -->|POST /api/v1/agent/enhance| auth --> sem --> enhancer
|
||||
enhancer --> guard --> react
|
||||
enhancer --> resolve --> syscfg
|
||||
resolve --> aikey
|
||||
react --> spark & dsk & oai
|
||||
react -->|kb_enabled| kbtbl
|
||||
enhancer -->|每次运行埋点| runlog --> panel
|
||||
enhancer -->|steps 随响应返回| assist --> stepTable
|
||||
```
|
||||
|
||||
### 1.2 目录与模块职责
|
||||
|
||||
| 目录 | 职责 | 关键点 |
|
||||
|---|---|---|
|
||||
| `main.go` | 启动入口 | config → dao → llm.InitLLM → agent.InitRunner → router.Setup;`http.Server` 带四组超时;优雅停机 |
|
||||
| `internal/config` | YAML/env 静态配置 | 只做启动期兜底;运行期以 DB 为准 |
|
||||
| `internal/dao` | 数据库访问 | `LoadActiveLLMConfig`(60s TTL 缓存)从 `xk_system_config` 实时解析生效模型;AES 解密密钥 |
|
||||
| `internal/agentcfg` | Agent 行为配置 | 从 `xk_system_config` 读 ReAct 开关、医疗守卫开关、debug 日志开关等 |
|
||||
| `internal/llm` | 模型接入层 | `ProviderFactory` 创建客户端;`ModelRouter` 按场景路由 + `GetByConfig` 按配置指纹缓存/重建;`FallbackChain` 降级链 |
|
||||
| `internal/service` | 业务核心 | `enhancer.go` 主流程、`reactloop.go` ReAct 循环、`medical_guard.go` 医疗守卫、`runlog.go` 运行轨迹缓冲 |
|
||||
| `internal/agent` | 会话式 Runner | `/agent/chat` 用的多轮会话引擎 + TokenBudget(与 EnhancerService 相互独立) |
|
||||
| `internal/kb` | 本地知识库 | V1 关键词检索(NoopEmbedder),读写 `xk_kb_*` 表;V2 预留向量化接口 |
|
||||
| `internal/tool` | Function Calling 工具集 | MaxKB 检索等,注入 ReactLoop 供模型调用 |
|
||||
| `internal/middleware` | 全局中间件 | 日志 / CORS / 双轨鉴权(JWT + SharedSecret) |
|
||||
| `internal/router` | 路由注册 | 业务 API + 运维 API + 两个静态面板(`/kb/view`、`/agent/view`) |
|
||||
| `internal/security/xkaes` | AES 加解密 | 与 PHP `EncryptorService` 同算法,解密 DB 里的 API Key |
|
||||
| `view/` | 前端单页 | `index.html`(知识库后台)、`agent.html`(运行观测面板),Vue3 + Element Plus CDN |
|
||||
|
||||
### 1.3 配置体系(三层,DB 为王)
|
||||
|
||||
```
|
||||
优先级:xk_system_config(DB,运行期实时) > 环境变量 > manifest/config/config.yaml(启动期兜底)
|
||||
```
|
||||
|
||||
- **生效模型**:`ai_active_provider` / `ai_active_model` / `ai_active_api_key_id` 三个键决定当前用哪个模型。Go 端 `dao.LoadActiveLLMConfig` 带 60s TTL 缓存,后台切换最多 1 分钟内全集群生效;PHP 后台保存后还可调 `POST /api/v1/models/invalidate-cache` 立即生效。
|
||||
- **走不走 Go Agent**:独立开关 `ai_agent_via_agent`(PHP `AiAgentFactory` 读取),与「用哪个模型」彻底解耦——这是踩过坑后的关键设计:早期把 `ai_active_provider=agent` 当路由标记,导致模型配置和链路选择互相污染。
|
||||
- **Agent 行为**:`ai_agent_medical_guard`(守卫开关)、`ai_agent_debug_log`(请求体日志开关,含 PHI 默认关)、ReAct 迭代数等,由 `agentcfg` 统一加载。
|
||||
- **客户端缓存与指纹**:`ModelRouter.GetByConfig` 对「model+url+key+provider」做指纹,配置变了自动重建 LLM 客户端,没变就复用连接池。
|
||||
|
||||
---
|
||||
|
||||
## 二、一次 enhance 请求的完整流程
|
||||
|
||||
以 PHP 发起「开方建议」为例:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant PHP as PHP TcmAgentClient
|
||||
participant MW as Auth + 信号量(16)
|
||||
participant EN as EnhancerService.Enhance
|
||||
participant GD as 医疗守卫
|
||||
participant RC as resolveClient
|
||||
participant RL as ReactLoop
|
||||
participant LLM as LLM 供应商
|
||||
participant LOG as RunLog 环形缓冲
|
||||
|
||||
PHP->>MW: POST /agent/enhance {scene, messages, kb_enabled}
|
||||
MW->>MW: Bearer == SharedSecret?并发 <16?
|
||||
MW->>EN: 通过(否则 401 / 503 快速失败)
|
||||
EN->>GD: 白名单/黑名单关键词校验
|
||||
alt 非医疗内容
|
||||
GD-->>EN: 拦截
|
||||
EN->>LOG: 记录 status=3(守卫拦截)
|
||||
EN-->>PHP: 500 + medical_guard step
|
||||
end
|
||||
EN->>RC: 解析生效模型(DB 60s 缓存 → yaml 兜底)
|
||||
RC-->>EN: client + provider + api_key_id
|
||||
EN->>RL: 进入 ReAct 循环
|
||||
RL->>LLM: [1] Planning(输出计划,计划跑题则丢弃)
|
||||
loop Think-Act-Observe(预算内多轮)
|
||||
RL->>LLM: [2] 带 tools 调用(Lite 自动降级纯文本)
|
||||
alt 触发 Function Calling
|
||||
RL->>RL: 执行工具,tool 结果带 tool_call_id 入栈
|
||||
end
|
||||
end
|
||||
RL->>LLM: [3] Reflection 低温自检
|
||||
RL->>LLM: [4] JSON 不合法时自动修复
|
||||
RL-->>EN: content + steps[](每步耗时/token/detail)
|
||||
EN->>LOG: 记录 status=1/2 + 完整 steps
|
||||
EN-->>PHP: {content, provider, model, steps, total_ms}
|
||||
PHP->>PHP: steps 落 xk_ai_generation_step
|
||||
```
|
||||
|
||||
关键细节:
|
||||
|
||||
1. **守卫在最前面**:不花任何 token 就能拒掉「PHP 组装出错 / 接口被滥用」的非医疗请求,同时留下 `medical_guard` 步骤便于定位是谁的问题。
|
||||
2. **每次调用都实时解析模型**:不是启动时定死,后台切模型不用重启 Go。
|
||||
3. **消息序列保证以 user/tool 结尾**:Planning 注入后补 user 帧,兼容 Spark Lite 等严格遵循 OpenAI 协议的模型(曾因 assistant 结尾触发 10003)。
|
||||
4. **网络错误自动重试 1 次**(间隔 1s):只重试连接/超时类错误,「API 返回 xxx」业务错误不重试,避免双倍烧 token。
|
||||
5. **无论成败都写 RunLog**:包装层统一埋点,守卫拦截、配置解析失败这类「PHP 侧看不到」的失败也有记录。
|
||||
|
||||
### 观测面板(/agent/view)
|
||||
|
||||
- **数据链路**:RunLog(内存 200 条)→ `GET /api/v1/agent/runs`(列表摘要)/ `runs/:id`(完整时间线)/ `stats`(成功率、平均耗时、token、按场景分布)。
|
||||
- **三个 Tab**:运行记录(点行弹时间线抽屉)、统计概览、生效配置(复用 `/models/active-config` + `/health`)。
|
||||
- **localStorage 记忆**:当前 Tab(`agent_view_tab`)、鉴权 token(`agent_view_token`)、自动刷新开关(`agent_view_refresh`,5s 轮询)、主题与 KB 页共用 `kb_theme`。
|
||||
- 页面本身放行不鉴权(纯静态无数据),数据 API 走全局 Auth。
|
||||
|
||||
---
|
||||
|
||||
## 三、隐患清单(按风险排序)
|
||||
|
||||
### 高:模型能力短板不是代码能完全兜住的
|
||||
|
||||
- **Lite 模型「计划腔」污染输出**:即使内容是医疗的,输出仍可能带「执行阶段/步骤一」的项目管理腔调(守卫只拦非医疗关键词,拦不住文风跑偏)。实测已复现。
|
||||
- **Reflection 审核不通过时内容照样返回**:目前 reflection 结果只作为附注拼进输出,没有「不合格 → 重试或换模型」的闭环。临床场景下这是最值得补的一环。
|
||||
- 缓解方向:审核不通过时触发一次重生成或 fallback 到更强模型;或在 PHP 侧按 reflection 结果决定是否展示。
|
||||
|
||||
### 高:医疗守卫是关键词规则引擎
|
||||
|
||||
- 白名单/黑名单靠人工维护,存在**误杀**(新病种词不在白名单)与**漏放**(换个说法绕过黑名单)两种风险,且没有命中率统计来指导调词。
|
||||
- 缓解方向:面板已能看到拦截记录,可定期复盘;长期可换成小模型二分类。
|
||||
|
||||
### 中:观测数据是单实例内存态
|
||||
|
||||
- RunLog 重启即清空、多实例部署时各自为政(面板只能看到所连实例的数据)、只保留最近 200 条。当前单实例部署下可接受,**水平扩容前必须重新设计**(落 Redis/DB 或接 Prometheus)。
|
||||
- 同理,**并发限流的 16 是进程内信号量**:多实例时总并发 = 16 × N,且 16 写死在 `router.go`,不可配置。
|
||||
|
||||
### 中:鉴权与暴露面
|
||||
|
||||
- SharedSecret 是**明文字符串比对**且和 KB 管理口令一起写在 `config.yaml`(`qiqi991012`),中间件里还硬编码了开发默认 JWT 密钥。生产必须换强随机值并走环境变量。
|
||||
- `GET /models/active-config` **无鉴权**(key 已脱敏只留尾号,但 provider/model/URL 对外可见)。
|
||||
- CORS 是 `Allow-Origin: *`;panic recovery 会把 recovered 内容原样返回给客户端(可能泄露内部路径/变量名)。
|
||||
|
||||
### 中:超时与重试的边界情况
|
||||
|
||||
- `WriteTimeout=300s` 是兜底,但 ReactLoop 本身**没有整体 deadline**:多轮迭代 + 每轮重试 1 次 + fallback 链,极端情况下可能逼近甚至顶到 300s,届时连接被强制掐断、PHP 只收到断连而非结构化错误。
|
||||
- `isRetryableNetworkError` 靠**错误文案子串匹配**("timeout"、"connection reset"…),Go 版本升级或客户端封装改文案就可能失效——这是无类型错误链下的妥协,脆弱但可用。
|
||||
|
||||
### 低:其他已知瑕疵
|
||||
|
||||
- `tool_calls[].id` 缺失时用 `time.Now().UnixNano()` 生成,理论上高并发同纳秒会撞(概率极低)。
|
||||
- KB V1 是 NoopEmbedder 纯关键词检索,召回质量有限,`ai_kb_source=local` 下检索增强效果打折;V2 接 BGE-M3 前这是已知取舍。
|
||||
- 60s 配置缓存意味着**不调 invalidate-cache 时切换最多延迟 1 分钟**——依赖 PHP 后台保存后主动调那个接口。
|
||||
- 无 Prometheus/metrics 端点,告警只能靠日志和面板人工看。
|
||||
|
||||
---
|
||||
|
||||
## 四、优势(为什么这样设计)
|
||||
|
||||
### 1. 配置热加载 + 指纹缓存:切模型不重启
|
||||
|
||||
后台改 `xk_system_config` → Go 下一次请求自动用新配置(60s 内,或调 invalidate 立即),客户端按指纹复用/重建。对比「启动时读一次配置」的方案,运维成本降了一个量级,这也是本项目踩坑(模型不一致)后重构出来的核心能力。
|
||||
|
||||
### 2. 多层防跑题:守卫 → 锚定 → 计划校验 → 反思
|
||||
|
||||
入口医疗守卫(0 token 拦非医疗)、Planning prompt 医疗锚定、计划输出不含医疗词即丢弃、Reflection 自检——四层针对「轻量模型易被通用指令带偏」的现实问题层层设防。单层都可能漏,叠加后 Lite 这类模型也能稳定输出医疗内容。
|
||||
|
||||
### 3. 故障半径控制:每一层都有降级路径
|
||||
|
||||
- 请求层:信号量满 → 503 快速失败 → PHP 走直连降级,不排队堆积;
|
||||
- 网络层:瞬时抖动自动重试 1 次;
|
||||
- 模型层:主模型挂 → FallbackChain 自动切备用;
|
||||
- 配置层:DB 抖动 → 回落 yaml/env 兜底配置;
|
||||
- 进程层:panic recovery + 优雅停机 + 四组 HTTP 超时防慢连接。
|
||||
|
||||
### 4. 全链路可观测,且观测不依赖被观测对象
|
||||
|
||||
每一步(守卫/检索/plan/llm_call/tool/reflection)都有独立的耗时、token、detail:实时看 Go 内存 RunLog + `/agent/view` 面板(DB 挂了面板照常工作),历史审计查 PHP `xk_ai_generation_step` 表。排障时能精确回答「哪一步、花了多久、模型说了什么」。
|
||||
|
||||
### 5. 协议完整性:换更强模型零改动
|
||||
|
||||
Function Calling 按 OpenAI 完整协议实现(`tool_calls[].id`、`tool_call_id` 回传、`arguments` JSON 字符串),消息序列符合严格校验;今天用 Lite(自动降级纯文本),明天切 Pro/Max/DeepSeek 直接享受工具调用,不用再动协议层。
|
||||
|
||||
### 6. 安全默认值
|
||||
|
||||
API Key AES 加密入库(与 PHP 同算法)、日志默认不打请求体(`ai_agent_debug_log` 显式开启才打,防 PHI 泄漏)、active-config 接口 key 脱敏只留尾号。
|
||||
|
||||
---
|
||||
|
||||
## 五、后续建议(按投入产出比排序)
|
||||
|
||||
1. **Reflection 闭环**:审核不合格时自动重试一次或 fallback 到更强模型(隐患一的直接解法)。
|
||||
2. **ReactLoop 整体 deadline**:用 `context.WithTimeout`(如 240s)包住整个循环,保证永远先于 WriteTimeout 结构化返回。
|
||||
3. **限流阈值进配置**:把 16 挪到 `xk_system_config` 或 config.yaml。
|
||||
4. 生产部署前:换强随机 SharedSecret、收紧 CORS、active-config 加鉴权、panic 响应脱敏。
|
||||
5. 多实例化时:RunLog 与限流改集中式(Redis),或直接接 Prometheus + Grafana 替代自建面板。
|
||||
137
docs/maxkb-ai/01_部署MaxKB.md
Normal file
137
docs/maxkb-ai/01_部署MaxKB.md
Normal file
@@ -0,0 +1,137 @@
|
||||
# 第 1 步:部署 MaxKB 平台
|
||||
|
||||
> 目标:在服务器上跑起来一个 MaxKB,能在浏览器打开它的管理后台。
|
||||
|
||||
---
|
||||
|
||||
## 方式 A:用 1Panel 应用商店装(推荐,最简单)
|
||||
|
||||
你的环境已经是 1Panel,这是最省事的。
|
||||
|
||||
### 步骤
|
||||
|
||||
1. **登录 1Panel 后台**:浏览器打开你的 1Panel(一般 `http://服务器IP:1Panel端口`)
|
||||
|
||||
2. **进入应用商店**:左侧菜单 → **应用商店**
|
||||
|
||||
3. **搜索 MaxKB**:在搜索框输入 `maxkb`
|
||||
|
||||
4. **点击安装**:
|
||||
- 名称:保持默认 `maxkb`
|
||||
- 端口:**改成 `8081`**(重要!不要用默认 8080,会和 Go Agent 冲突)
|
||||
- 数据库:选"外部数据库"或让 MaxKB 自带的(小白选自带即可)
|
||||
- 点"确认"等 1-2 分钟
|
||||
|
||||
5. **等待状态变成"运行中"**
|
||||
|
||||
---
|
||||
|
||||
## 方式 B:用项目里的 docker-compose 装
|
||||
|
||||
如果 1Panel 商店里没有 MaxKB,用项目自带的脚本。
|
||||
|
||||
### 步骤
|
||||
|
||||
1. **SSH 登录服务器**
|
||||
|
||||
2. **进入项目目录**:
|
||||
```bash
|
||||
cd "/path/to/nl-tcm-agent/manifest/docker"
|
||||
```
|
||||
|
||||
3. **⚠️ 先改端口**(项目默认配的是 8080,会和 Go Agent 冲突)
|
||||
|
||||
用 `vim docker-compose.yml` 或 `nano docker-compose.yml`,找到 maxkb 部分:
|
||||
|
||||
```yaml
|
||||
maxkb:
|
||||
image: 1panel/maxkb:latest
|
||||
ports:
|
||||
- "8080:8080" # ❌ 改这里
|
||||
```
|
||||
|
||||
改成:
|
||||
```yaml
|
||||
maxkb:
|
||||
image: 1panel/maxkb:latest
|
||||
ports:
|
||||
- "8081:8080" # ✅ 改成 8081
|
||||
```
|
||||
|
||||
4. **启动 MaxKB**:
|
||||
```bash
|
||||
docker-compose up -d maxkb
|
||||
```
|
||||
|
||||
5. **等 1-2 分钟,看启动日志**:
|
||||
```bash
|
||||
docker logs -f maxkb
|
||||
```
|
||||
看到类似 `Application started on port 8080` 就说明成功了,按 `Ctrl+C` 退出日志。
|
||||
|
||||
---
|
||||
|
||||
## 方式 C:直接 docker run(最朴素)
|
||||
|
||||
如果上面都不方便,一条命令搞定:
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name maxkb \
|
||||
-p 8081:8080 \
|
||||
-v maxkb_data:/app/data \
|
||||
--restart unless-stopped \
|
||||
1panel/maxkb:latest
|
||||
```
|
||||
|
||||
> `-p 8081:8080` 表示把容器内 8080 映射到服务器 8081。**记住你映射的端口,后面要用。**
|
||||
|
||||
---
|
||||
|
||||
## 验证部署是否成功
|
||||
|
||||
### 1. 浏览器访问管理后台
|
||||
|
||||
打开:`http://你的服务器IP:8081`
|
||||
|
||||
> 把 `你的服务器IP` 换成实际 IP。本地开发就是 `http://127.0.0.1:8081`。
|
||||
|
||||
### 2. 看到登录页 → 成功
|
||||
|
||||
第一次会让你设置管理员账号密码,或者用默认账号:
|
||||
- 用户名:`admin`
|
||||
- 密码:`MaxKB@123..`
|
||||
|
||||
### 3. 登录成功,看到控制台
|
||||
|
||||
![MaxKB 登录后会看到欢迎页]
|
||||
|
||||
到这里 MaxKB 部署完成。下一步去上传资料。
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q1:访问不了 8081 端口
|
||||
|
||||
**原因**:服务器防火墙没放端口。
|
||||
|
||||
**解决**:
|
||||
- 云服务器:去云厂商控制台 → 安全组 → 入方向规则 → 加一条"TCP 8081 允许"
|
||||
- 自建机:`sudo ufw allow 8081/tcp`(Ubuntu)或 `sudo firewall-cmd --add-port=8081/tcp --permanent && sudo firewall-cmd --reload`(CentOS)
|
||||
|
||||
### Q2:MaxKB 启动后立刻挂掉
|
||||
|
||||
**原因**:内存不够(MaxKB 至少要 2G 空闲内存)。
|
||||
|
||||
**解决**:
|
||||
- `free -h` 看内存
|
||||
- 不够就加内存,或者关掉其他占内存的容器
|
||||
|
||||
### Q3:1Panel 装的 MaxKB 在哪个端口?
|
||||
|
||||
1Panel 应用商店装完后,在 1Panel → 容器 → 找到 maxkb → 看端口映射。也可以在 1Panel → 应用商店 → 已安装 → maxkb → 详情里看到。
|
||||
|
||||
---
|
||||
|
||||
下一步:[02_上传知识库.md](./02_上传知识库.md)
|
||||
143
docs/maxkb-ai/02_上传知识库.md
Normal file
143
docs/maxkb-ai/02_上传知识库.md
Normal file
@@ -0,0 +1,143 @@
|
||||
# 第 2 步:上传知识库资料
|
||||
|
||||
> 目标:把项目里准备好的 7 个中医资料文件,上传到 MaxKB,让它能"翻书"。
|
||||
|
||||
---
|
||||
|
||||
## 资料文件在哪?
|
||||
|
||||
项目里已经为你准备好了 7 个 Markdown 文件,路径:
|
||||
|
||||
```
|
||||
xk-api/storage/maxkb_seed/
|
||||
├── 01_decoction_methods.md 煎法(先煎/后下/包煎…)
|
||||
├── 02_entrusted_process.md 委托调剂规则
|
||||
├── 03_tcm_dict.md 中医证候 / 治法 / 疾病字典
|
||||
├── 04_icd_diagnosis.md ICD-10 诊断编码
|
||||
├── 05_drug_catalog.md 药品库
|
||||
├── 06_tcm_conflict.md 中医配伍禁忌(十八反十九畏)
|
||||
└── 07_mr_field_spec.md 病历字段规范
|
||||
```
|
||||
|
||||
> 这些就是 AI 在生成病历/处方时需要"翻书"查的固定资料。
|
||||
|
||||
---
|
||||
|
||||
## 在 MaxKB 创建知识库
|
||||
|
||||
### 1. 登录 MaxKB 后台
|
||||
|
||||
浏览器打开 `http://你的服务器IP:8081`,登录。
|
||||
|
||||
### 2. 进入"知识库"菜单
|
||||
|
||||
- **新版(4.x)**:首页就有 **"创建知识库"** 大按钮,直接点
|
||||
- **老版(1.x/2.x)**:左侧菜单 → 点 **知识库**(或 **Knowledge Base**)→ 右上角"创建知识库"
|
||||
|
||||
### 3. 点击"创建知识库"
|
||||
|
||||
首页或知识库列表页有 **创建知识库** 按钮,点击。
|
||||
|
||||
### 4. 填写基本信息
|
||||
|
||||
| 字段 | 填什么 |
|
||||
|---|---|
|
||||
| 知识库名称 | `中医医疗知识库`(随便起,自己认得就行)|
|
||||
| 知识库描述 | `中医诊疗参考资料:煎法、证候、ICD-10、药品库等` |
|
||||
| 知识库类型 | 选 **通用型** / **文档型**(默认即可) |
|
||||
|
||||
点 **下一步**。
|
||||
|
||||
### 5. 选择向量模型
|
||||
|
||||
MaxKB 会让你选"文本向量模型",用来把文字转成数字。
|
||||
|
||||
**推荐选择**:
|
||||
- 如果 MaxKB 自带本地 embedding 模型(如 `m3e-base`):选它,免费
|
||||
- 如果没有:用 MaxKB 默认的,或后续配置 OpenAI embedding(要 API Key)
|
||||
|
||||
> 小白先用默认,跑通再说。
|
||||
|
||||
点 **创建**。
|
||||
|
||||
---
|
||||
|
||||
## 上传资料文件
|
||||
|
||||
### 1. 进入新建好的知识库
|
||||
|
||||
列表里点开 **中医医疗知识库**。
|
||||
|
||||
### 2. 切到"文档"标签
|
||||
|
||||
知识库里有几个 Tab:文档 / 设置。点 **文档**。
|
||||
|
||||
### 3. 点击"上传文档"
|
||||
|
||||
按钮一般叫 **添加文档** 或 **上传文档**。
|
||||
|
||||
### 4. 选择本地文件
|
||||
|
||||
把 `xk-api/storage/maxkb_seed/` 下的 **7 个 md 文件全部选中**,一次性传上去。
|
||||
|
||||
> 也支持 zip / pdf / docx / txt,但我们准备的 md 最准。
|
||||
|
||||
### 5. 等待向量化完成
|
||||
|
||||
上传后每条文档会有"状态"列:
|
||||
- ⏳ **向量化中**:正在处理(每条 1-2 分钟)
|
||||
- ✅ **已就绪 / 成功**:可以用了
|
||||
- ❌ **失败**:点开看错误原因
|
||||
|
||||
**全部变成 ✅ 才能进下一步**。
|
||||
|
||||
> 如果卡很久没动,可能是 embedding 模型没配好,去看 MaxKB 设置 → 模型管理。
|
||||
|
||||
---
|
||||
|
||||
## 验证知识库能搜
|
||||
|
||||
### 1. 在知识库页面找"命中测试"或"搜索测试"
|
||||
|
||||
每个知识库都自带一个测试入口,能让你试搜。
|
||||
|
||||
### 2. 输入测试词
|
||||
|
||||
输入:`痰湿中阻 煎法`
|
||||
|
||||
### 3. 看结果
|
||||
|
||||
应该返回 `01_decoction_methods.md` 或 `03_tcm_dict.md` 的相关片段。
|
||||
|
||||
> 如果搜不到任何东西,说明:
|
||||
> - 文档还没向量化完成 → 等等再试
|
||||
> - 或者文件是空的 → 检查 md 文件是否有内容
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q1:上传报错"不支持的文件类型"
|
||||
|
||||
.md 文件 MaxKB 是支持的。如果报错,把文件后缀改成 `.txt` 或 `.markdown` 再传。
|
||||
|
||||
### Q2:向量化一直失败
|
||||
|
||||
**原因**:embedding 模型没配好。
|
||||
|
||||
**解决**:
|
||||
- MaxKB 后台 → 设置 → 模型管理 → 看是否有可用的 embedding 模型
|
||||
- 没有就加一个:本地 m3e-base(免费)或 OpenAI text-embedding-3-small(要 Key)
|
||||
|
||||
### Q3:上传成功但搜不到内容
|
||||
|
||||
**原因**:可能文档没分段成功,或文字内容是图片(OCR 失败)。
|
||||
|
||||
**解决**:
|
||||
- 进文档详情看"分段"列表
|
||||
- 我们准备的 md 都是纯文字,应该没问题
|
||||
- 如果还不行,单独上传一个文件试试
|
||||
|
||||
---
|
||||
|
||||
下一步:[03_创建应用拿密钥.md](./03_创建应用拿密钥.md)
|
||||
281
docs/maxkb-ai/03_创建应用拿密钥.md
Normal file
281
docs/maxkb-ai/03_创建应用拿密钥.md
Normal file
@@ -0,0 +1,281 @@
|
||||
# 第 3 步:创建智能体并拿 API 密钥
|
||||
|
||||
> 目标:在 MaxKB 里建一个"智能体"(老版本叫"应用"),把它和一个知识库关联起来,再拿到 3 个连接用的钥匙。
|
||||
>
|
||||
> Go Agent 不会直接调"知识库",而是调"智能体",由"智能体"去访问关联的知识库。
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 先看:MaxKB 老版 vs 新版术语对照
|
||||
|
||||
如果你看到的界面里没有"应用"两个字,但有"**智能体**",说明你装的是 **MaxKB 4.x 新版**。两者底层 API 完全一样,只是改了名字:
|
||||
|
||||
| 老版(MaxKB 1.x / 2.x) | 新版(MaxKB 4.x) | 你的代码注释里写的 |
|
||||
|---|---|---|
|
||||
| **应用** | **智能体** | "应用"(代码先写的)|
|
||||
| 创建应用 | 创建智能体 | — |
|
||||
| 简单应用 / 工作流 | 空白创建 / 从模板创建 | — |
|
||||
| 应用信息 | 智能体概览 | — |
|
||||
| API 文档 | API 文档(位置变了,见下文)| — |
|
||||
|
||||
**API 接口路径完全没变**:`/api/application/<AppID>/...` 在新旧版本都能用,Go Agent 代码不用动。
|
||||
|
||||
---
|
||||
|
||||
## 你看到的 4 个按钮都是干嘛的?
|
||||
|
||||
你截图里的 4 个入口:
|
||||
|
||||
| 按钮 | 是不是这一步要点的? | 解释 |
|
||||
|---|---|---|
|
||||
| **创建智能体** | ✅ **就是这个!** | 相当于老版的"创建应用" |
|
||||
| **创建知识库** | ❌ 上一步已做 | 上传中医资料用的,已经做过了 |
|
||||
| **添加工具** | ❌ 不需要 | MaxKB 自己的工具系统(脚本/工作流),我们用不上 |
|
||||
| **添加模型** | ⚠️ 可能要先做 | 给 MaxKB 配大语言模型/向量模型。**如果创建智能体时报错"未配置模型",先回来做这个** |
|
||||
|
||||
---
|
||||
|
||||
## 1. (前置)确认模型已配置
|
||||
|
||||
**新版 MaxKB 强制要求先配模型才能建智能体**。如果你之前没配过,先做这一步:
|
||||
|
||||
### 操作
|
||||
|
||||
1. 首页 → **添加模型** (或左下角"模型管理")
|
||||
2. 至少配 2 类:
|
||||
- **大语言模型**:选 DeepSeek(你自己有 API Key 最便宜)/ 或 OpenAI GPT-4o
|
||||
- **向量模型**:选 `m3e-base`(本地免费)或 `text-embedding-3-small`(OpenAI)
|
||||
|
||||
3. 填写:
|
||||
- 模型类型:选 DeepSeek / OpenAI 等
|
||||
- API Key:你的 Key
|
||||
- Base URL:模型厂商地址
|
||||
|
||||
> 💡 **这个模型是 MaxKB 自己生成对话时用的**。我们 Go Agent 主要走"检索接口"(search),不太会真用它,但 MaxKB 要求智能体必须配模型。
|
||||
|
||||
> 💡 **如果跳过这步,下一步"创建智能体"会一直报错**。
|
||||
|
||||
---
|
||||
|
||||
## 2. 创建智能体
|
||||
|
||||
### 操作
|
||||
|
||||
1. 首页 → **创建智能体**
|
||||
2. 选 **空白创建**(不要选"从模板",模板是人家做好的,不适合我们)
|
||||
3. 填写信息:
|
||||
|
||||
| 字段 | 填什么 |
|
||||
|---|---|
|
||||
| 名称 | `中医诊疗助手`(随便起)|
|
||||
| 描述 | `给 Go Agent 用的知识检索入口` |
|
||||
| 类型 | 保持默认(**简单工作流 / 基础问答**,不要选复杂工作流)|
|
||||
|
||||
4. 进入智能体后,**关键一步:关联知识库**
|
||||
- 在智能体的 **"知识库"** 或 **"资源"** 标签
|
||||
- 点击 **"添加知识库"**
|
||||
- **勾选第 2 步创建的"中医医疗知识库"**
|
||||
- 保存
|
||||
|
||||
5. (可选)在 **"模型"** 或 **"设置"** 标签:
|
||||
- 选一个大模型(DeepSeek 即可)
|
||||
|
||||
6. **点右上角"保存"或"发布"**
|
||||
- 新版 MaxKB 智能体必须**手动发布**才能用
|
||||
- 状态显示"已发布"才算成功
|
||||
|
||||
---
|
||||
|
||||
## 3. 拿到三个钥匙
|
||||
|
||||
### 进入智能体"概览"页面
|
||||
|
||||
在智能体列表里点开你刚建的"中医诊疗助手",看到 **概览** Tab。
|
||||
|
||||
### 🔑 钥匙 1:Base URL
|
||||
|
||||
在概览页面找 **"API 文档地址"** 或 **"API 访问"** 区域:
|
||||
|
||||
```
|
||||
http://192.168.1.100:8081
|
||||
```
|
||||
|
||||
**这就是 Base URL**,注意:
|
||||
- 端口要写你部署时映射的端口(比如 8081)
|
||||
- 不要带末尾 `/`
|
||||
- 要写 Go Agent 能访问到的地址(同机 `127.0.0.1`,跨机用 IP)
|
||||
|
||||
### 🔑 钥匙 2:API Key
|
||||
|
||||
在概览页面点 **"API Key"** 或 **"API 密钥"** 按钮:
|
||||
|
||||
1. 点 **"创建 API Key"**
|
||||
2. 给它一个名字(如 "go-agent")
|
||||
3. 复制出来:
|
||||
|
||||
```
|
||||
application-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
```
|
||||
或新版可能是:
|
||||
```
|
||||
agent-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
```
|
||||
|
||||
> **格式可能以 `application-` 或 `agent-` 开头**,两种都对,**完整复制**即可。
|
||||
>
|
||||
> ⚠️ **关闭窗口后可能再也看不到完整 Key**,所以**当场复制存好**!
|
||||
|
||||
### 🔑 钥匙 3:App ID
|
||||
|
||||
App ID 一般显示在:
|
||||
- **概览页面的"API 文档地址"里**,形如:`http://.../api/application/<这串UUID>/chat/completions`
|
||||
- 或 **API Key 列表的"应用 ID"列**
|
||||
- 或 **浏览器地址栏** URL 里的 UUID
|
||||
|
||||
格式:
|
||||
```
|
||||
a1b2c3d4-e5f6-7890-abcd-ef1234567890
|
||||
```
|
||||
(UUID 格式:8-4-4-4-12)
|
||||
|
||||
> 💡 **快捷找法**:在概览页面点"API 文档"或"Swagger",浏览器打开的 URL 里就包含 App ID。
|
||||
|
||||
---
|
||||
|
||||
## 4. 验证 API 能调通(强烈建议)
|
||||
|
||||
打开命令行(PowerShell / Terminal / cmd 都行),用 curl 测试。
|
||||
|
||||
### 测试 1:对话接口(OpenAI 兼容格式)
|
||||
|
||||
```bash
|
||||
curl -X POST "http://你的服务器IP:8081/api/application/你的AppID/chat/completions" ^
|
||||
-H "Authorization: Bearer 你的APIKey" ^
|
||||
-H "Content-Type: application/json" ^
|
||||
-d "{\"model\":\"deepseek-chat\",\"messages\":[{\"role\":\"user\",\"content\":\"痰湿中阻的煎法\"}]}"
|
||||
```
|
||||
|
||||
> Windows 用 `^` 换行,Linux/Mac 用 `\`。
|
||||
>
|
||||
> 不熟悉 curl 可以直接写一行。
|
||||
|
||||
### 期望返回
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "xxx",
|
||||
"choices": [
|
||||
{
|
||||
"message": {
|
||||
"role": "assistant",
|
||||
"content": "痰湿中阻的方剂常用煎法..."
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 测试 2:检索接口(Go Agent 用的就是这个)
|
||||
|
||||
```bash
|
||||
curl -X POST "http://你的服务器IP:8081/api/application/你的AppID/search" ^
|
||||
-H "Authorization: Bearer 你的APIKey" ^
|
||||
-H "Content-Type: application/json" ^
|
||||
-d "{\"query\":\"痰湿中阻 煎法\",\"top_k\":3}"
|
||||
```
|
||||
|
||||
期望返回:
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"documents": [
|
||||
{"content": "煎法说明……痰湿中阻宜……", "score": 0.85},
|
||||
{"content": "中医证候:痰湿中阻……", "score": 0.78}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> ⚠️ **新版 MaxKB 的 search 接口可能改名了**。如果返回 404,去看"API 文档"(Swagger),找 `/hit-test` 或 `/search` 或 `/embedding/search` 路径。Go Agent 代码 [internal/tool/maxkb.go](../../../../internal/tool/maxkb.go) 第 125 行调的就是 `/api/application/<AppID>/search`,新版可能需要适配(见下文排错)。
|
||||
|
||||
---
|
||||
|
||||
## 5. 常见错误
|
||||
|
||||
### 返回 401 Unauthorized
|
||||
|
||||
**原因**:API Key 错或没传 Authorization 头。
|
||||
|
||||
**解决**:
|
||||
- 重新去智能体 → 概览 → API Key 复制
|
||||
- 确认 Header 是 `Authorization: Bearer application-xxx`(注意 `Bearer ` 后有个空格)
|
||||
|
||||
### 返回 404 Not Found
|
||||
|
||||
**原因**:URL 不对,特别是 App ID 拼错,或者新版接口路径变了。
|
||||
|
||||
**解决**:
|
||||
- 打开智能体 → 概览 → **API 文档**(Swagger)
|
||||
- 在 Swagger 里找"对话接口"或"检索接口"
|
||||
- 复制完整 URL 替换
|
||||
|
||||
### 返回 500 / "应用未发布"
|
||||
|
||||
**原因**:智能体没发布。
|
||||
|
||||
**解决**:
|
||||
- 回到智能体详情
|
||||
- 右上角找 **"发布"** 按钮
|
||||
- 状态变成"已发布"
|
||||
|
||||
### 返回空 documents 数组
|
||||
|
||||
**原因**:知识库里没相关内容,或文档没向量化完。
|
||||
|
||||
**解决**:回第 2 步检查知识库。
|
||||
|
||||
### 创建 API Key 按钮置灰
|
||||
|
||||
**原因**:智能体未发布。
|
||||
|
||||
**解决**:先发布智能体,再创建 API Key。
|
||||
|
||||
---
|
||||
|
||||
## 6. 钥匙清单(待会儿要填)
|
||||
|
||||
把下面这张表填好,下一步要用:
|
||||
|
||||
| 钥匙 | 你的值 |
|
||||
|---|---|
|
||||
| Base URL | `http://____________________:8081` |
|
||||
| API Key | `application-____________________`(或 `agent-____________________`)|
|
||||
| App ID | `________________________________` |
|
||||
|
||||
---
|
||||
|
||||
## 7. ⚠️ 如果新版 search 接口路径不一样怎么办?
|
||||
|
||||
**先做完上面所有步骤**,然后到 [06_修复检索词Bug.md](./06_修复检索词Bug.md) 改完后,**第 7 步验证时如果 kb_retrieval step 一直 status=2**,回来看这里:
|
||||
|
||||
1. 打开智能体概览 → API 文档(Swagger)
|
||||
2. 在 Swagger 里搜索 `/search` 或 `/hit` 或 `/embedding`
|
||||
3. 找到对应的检索接口路径
|
||||
4. 改 Go Agent 代码:`nl-tcm-agent/internal/tool/maxkb.go` 第 125 行:
|
||||
|
||||
```go
|
||||
// 原代码:
|
||||
url := fmt.Sprintf("%s/api/application/%s/search", c.BaseURL, c.AppID)
|
||||
|
||||
// 改成新版路径(示例,根据 Swagger 实际路径):
|
||||
url := fmt.Sprintf("%s/api/application/%s/hit-test", c.BaseURL, c.AppID)
|
||||
```
|
||||
|
||||
5. 重启 Go Agent
|
||||
|
||||
> 也可以告诉我你的 MaxKB 版本和 Swagger 里看到的检索接口路径,我帮你改。
|
||||
|
||||
---
|
||||
|
||||
下一步:[04_配置GoAgent.md](./04_配置GoAgent.md)
|
||||
146
docs/maxkb-ai/04_配置GoAgent.md
Normal file
146
docs/maxkb-ai/04_配置GoAgent.md
Normal file
@@ -0,0 +1,146 @@
|
||||
# 第 4 步:配置 Go Agent 连接 MaxKB
|
||||
|
||||
> 目标:改 Go Agent 的配置文件,让它知道 MaxKB 在哪、用什么钥匙访问。
|
||||
|
||||
---
|
||||
|
||||
## 1. 找到配置文件
|
||||
|
||||
文件位置:
|
||||
```
|
||||
nl-tcm-agent/manifest/config/config.yaml
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 改 maxkb 节点
|
||||
|
||||
打开 config.yaml,找到开头那一段(第 13-17 行附近):
|
||||
|
||||
```yaml
|
||||
# ========== MaxKB 知识库配置 ==========
|
||||
maxkb:
|
||||
base_url: "http://127.0.0.1:8080" # ❌ 这是占位符
|
||||
api_key: "application-xxxxxxxx" # ❌ 这是占位符
|
||||
app_id: "xxxxxxxx-xxxx-xxxx" # ❌ 这是占位符
|
||||
```
|
||||
|
||||
### 改成你在 [第 3 步](./03_创建应用拿密钥.md) 拿到的真实值
|
||||
|
||||
```yaml
|
||||
# ========== MaxKB 知识库配置 ==========
|
||||
maxkb:
|
||||
base_url: "http://192.168.x.x:8081" # ✅ MaxKB 实际地址(注意端口!)
|
||||
api_key: "application-真实APIKey" # ✅ 第 3 步拿到的 API Key
|
||||
app_id: "真实AppID-UUID格式" # ✅ 第 3 步拿到的 App ID
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 三个常见坑
|
||||
|
||||
### ⚠️ 坑 1:地址要写 Go Agent 能访问到的
|
||||
|
||||
| Go Agent 部署位置 | base_url 怎么写 |
|
||||
|---|---|
|
||||
| 同一台服务器(本机) | `http://127.0.0.1:8081` |
|
||||
| Docker 容器内(同一 compose) | `http://maxkb:8080`(用服务名)|
|
||||
| 另一台服务器 | `http://其他服务器IP:8081` |
|
||||
|
||||
**不要写 `localhost`**,因为 Docker 容器里的 localhost 不是宿主机。
|
||||
|
||||
### ⚠️ 坑 2:端口别填错
|
||||
|
||||
- MaxKB 容器内一直是 8080
|
||||
- 但你宿主机映射的是 8081
|
||||
- 所以**外部访问写 8081,容器间互访写 8080**
|
||||
|
||||
### ⚠️ 坑 3:YAML 格式
|
||||
|
||||
- key 后面必须有**一个空格**再写值
|
||||
- 字符串**必须用双引号**(单引号也行,但别一个单一个双)
|
||||
- 缩进必须用空格,不能用 Tab
|
||||
|
||||
```yaml
|
||||
# ✅ 对
|
||||
maxkb:
|
||||
base_url: "http://127.0.0.1:8081"
|
||||
|
||||
# ❌ 错(冒号后没空格)
|
||||
maxkb:
|
||||
base_url:"http://127.0.0.1:8081"
|
||||
|
||||
# ❌ 错(用了 Tab)
|
||||
maxkb:
|
||||
base_url: "http://127.0.0.1:8081"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 重启 Go Agent
|
||||
|
||||
配置改完要重启服务才生效。
|
||||
|
||||
### 本地开发
|
||||
|
||||
```bash
|
||||
cd "/path/to/nl-tcm-agent"
|
||||
# 停掉旧的(Ctrl+C)
|
||||
# 重新启动
|
||||
go run main.go
|
||||
```
|
||||
|
||||
### Docker 部署
|
||||
|
||||
```bash
|
||||
cd "/path/to/nl-tcm-agent/manifest/docker"
|
||||
docker-compose restart agent
|
||||
```
|
||||
|
||||
### 1Panel 部署
|
||||
|
||||
1Panel → 容器 → 找到 tcm-agent → 重启。
|
||||
|
||||
---
|
||||
|
||||
## 5. 看启动日志确认
|
||||
|
||||
启动后看日志,应该看到:
|
||||
|
||||
```
|
||||
[启动] ✅ 中医 AI Agent 服务已启动,监听端口 :8080
|
||||
```
|
||||
|
||||
如果 MaxKB 配置错,启动时一般不会报错(MaxKB 是按需调用的,不启动就调)。所以这一步**不能完全验证配置对**,要进第 7 步验证。
|
||||
|
||||
---
|
||||
|
||||
## 6. 完整配置示例(参考)
|
||||
|
||||
这是一个完整的 maxkb 节点示例(**值是假的,替换成你自己的**):
|
||||
|
||||
```yaml
|
||||
# ========== MaxKB 知识库配置 ==========
|
||||
maxkb:
|
||||
base_url: "http://192.168.1.100:8081"
|
||||
api_key: "application-abcd1234efgh5678ijkl9012mnop3456"
|
||||
app_id: "f4b8a2c1-3d5e-4f6a-9b7c-8d2e1f0a3b5c"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q1:YAML 改完启动报错 `yaml: unmarshal errors`
|
||||
|
||||
**原因**:YAML 格式错了(缩进/引号/冒号空格)。
|
||||
|
||||
**解决**:找个在线 YAML 校验器(如 yamllint.com)粘进去检查。
|
||||
|
||||
### Q2:怎么知道 Go Agent 真的连上了 MaxKB?
|
||||
|
||||
启动时连不上也不会报错。要等真正发起请求时才知道。**先继续下一步配置开关,最后用第 7 步的 curl 测试**。
|
||||
|
||||
---
|
||||
|
||||
下一步:[05_打开PHP开关.md](./05_打开PHP开关.md)
|
||||
135
docs/maxkb-ai/05_打开PHP开关.md
Normal file
135
docs/maxkb-ai/05_打开PHP开关.md
Normal file
@@ -0,0 +1,135 @@
|
||||
# 第 5 步:打开 PHP 端的"启用知识库"开关
|
||||
|
||||
> 目标:在数据库里把"病历场景"和"处方场景"是否走 MaxKB 检索的开关打开。
|
||||
>
|
||||
> PHP 端有 4 个开关,对应 4 个场景。默认都是关的(0),需要手动改成开(1)。
|
||||
|
||||
---
|
||||
|
||||
## 1. 这 4 个开关在哪
|
||||
|
||||
它们存在数据库 `z_xk.xk_system_config` 表里:
|
||||
|
||||
| config_key | 控制 |
|
||||
|---|---|
|
||||
| `ai_agent_kb_enabled_medical_record` | 病历生成是否查 MaxKB |
|
||||
| `ai_agent_kb_enabled_prescription` | 处方生成是否查 MaxKB |
|
||||
| `ai_agent_kb_enabled_prescription_validate` | 处方校验是否查 MaxKB |
|
||||
| `ai_agent_kb_enabled_knowledge_qa` | 知识问答是否查 MaxKB |
|
||||
|
||||
> 这 4 个开关本来就应该在 [20260809/ai_generation_extend_for_agent.sql](../../../../../gs/sql/萧康云医/20260809/ai_generation_extend_for_agent.sql) 执行后就已经插入数据库了。
|
||||
|
||||
---
|
||||
|
||||
## 2. 检查开关是否已存在
|
||||
|
||||
用数据库工具(Navicat / DBeaver / 1Panel 自带的 phpMyAdmin)连 `z_xk` 库,执行:
|
||||
|
||||
```sql
|
||||
SELECT config_key, config_value
|
||||
FROM xk_system_config
|
||||
WHERE config_key LIKE 'ai_agent_kb_enabled_%';
|
||||
```
|
||||
|
||||
### 情况 A:能查到 4 条记录
|
||||
|
||||
太好了,直接进**第 3 步**改值。
|
||||
|
||||
### 情况 B:查不到
|
||||
|
||||
说明 [ai_generation_extend_for_agent.sql](../../../../../gs/sql/萧康云医/20260809/ai_generation_extend_for_agent.sql) 还没执行。先执行这个 SQL 文件,再回来查。
|
||||
|
||||
---
|
||||
|
||||
## 3. 打开开关(改成 1)
|
||||
|
||||
执行 UPDATE 把对应场景的开关改成 `1`:
|
||||
|
||||
```sql
|
||||
-- 病历生成走 MaxKB
|
||||
UPDATE xk_system_config
|
||||
SET config_value = '1', updated_at = UNIX_TIMESTAMP()
|
||||
WHERE config_key = 'ai_agent_kb_enabled_medical_record';
|
||||
|
||||
-- 处方生成走 MaxKB
|
||||
UPDATE xk_system_config
|
||||
SET config_value = '1', updated_at = UNIX_TIMESTAMP()
|
||||
WHERE config_key = 'ai_agent_kb_enabled_prescription';
|
||||
```
|
||||
|
||||
> 如果你暂时只想测试一个场景,只改一条也行。
|
||||
|
||||
### 验证
|
||||
|
||||
再查一次:
|
||||
```sql
|
||||
SELECT config_key, config_value FROM xk_system_config WHERE config_key LIKE 'ai_agent_kb_enabled_%';
|
||||
```
|
||||
|
||||
应该看到:
|
||||
```
|
||||
ai_agent_kb_enabled_medical_record 1
|
||||
ai_agent_kb_enabled_prescription 1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. ⚠️ 清缓存(重要)
|
||||
|
||||
PHP 端 `SystemConfigService` 有 1 小时内存缓存。如果你直接改数据库不开,PHP 可能还读旧值。
|
||||
|
||||
### 方法 A:重启 PHP-FPM(最稳)
|
||||
|
||||
1Panel → 网站 → 找到你的 PHP 站点 → 重启 PHP-FPM。
|
||||
|
||||
或者 SSH:
|
||||
```bash
|
||||
systemctl restart php-fpm
|
||||
# 或
|
||||
service php8.1-fpm restart
|
||||
```
|
||||
|
||||
### 方法 B:等 1 小时
|
||||
|
||||
如果你不急,等 1 小时缓存自动过期。
|
||||
|
||||
### 方法 C:从后台改(推荐)
|
||||
|
||||
如果你已经在 [system-config 页面](../../../../../gs/xk-admin/apps/web-antd/src/views/system/system-config/index.vue) 加了这 4 个 key 的可视化(**注意:当前前端只加了 `ai_react_*` 等 13 个,没有这 4 个 `ai_agent_kb_*`**),可以从后台改并自动清缓存。
|
||||
|
||||
---
|
||||
|
||||
## 5. 开关与场景对应关系(理解记忆)
|
||||
|
||||
| PHP 调用时的 `scene` | 对应的开关 key | 现在的值 |
|
||||
|---|---|---|
|
||||
| `medical_record`(病历)| `ai_agent_kb_enabled_medical_record` | 0 → 改成 1 |
|
||||
| `prescription`(处方)| `ai_agent_kb_enabled_prescription` | 0 → 改成 1 |
|
||||
|
||||
PHP 调用 Go Agent 时会带 `scene=medical_record`,Go Agent **不查开关**,开关完全在 PHP 端决定是否发请求时带 `kb_enabled=true`。
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q1:改完没生效
|
||||
|
||||
99% 是 PHP 缓存。重启 PHP-FPM。
|
||||
|
||||
### Q2:临时关掉怎么办
|
||||
|
||||
把 `config_value` 改回 `0`,再重启 PHP-FPM。
|
||||
|
||||
---
|
||||
|
||||
## 🚨 重要提醒:做完这一步还不够!
|
||||
|
||||
到这里你以为开关闭了,**但实际还是不会触发检索**!
|
||||
|
||||
为什么?因为 PHP 调用 Go Agent 时**没有传"检索关键词"字段**,Go Agent 看到关键词为空,会自动跳过检索。
|
||||
|
||||
下一步**必须**做:[06_修复检索词Bug.md](./06_修复检索词Bug.md)
|
||||
|
||||
---
|
||||
|
||||
下一步:[06_修复检索词Bug.md](./06_修复检索词Bug.md)
|
||||
282
docs/maxkb-ai/06_修复检索词Bug.md
Normal file
282
docs/maxkb-ai/06_修复检索词Bug.md
Normal file
@@ -0,0 +1,282 @@
|
||||
# 第 6 步:⚠️ 必做 — 修复"PHP 不传检索词"的 Bug
|
||||
|
||||
> **这一步是最重要的!不做前面 5 步全白做!**
|
||||
>
|
||||
> 现状:PHP 调用 Go Agent 时**没传"检索关键词"**(context 字段),Go Agent 看到关键词为空就跳过检索,所以 MaxKB 永远不会被查询。
|
||||
|
||||
---
|
||||
|
||||
## Bug 长什么样
|
||||
|
||||
### Go Agent 这边的判断
|
||||
|
||||
文件:`nl-tcm-agent/internal/service/enhancer.go` 第 150 行:
|
||||
|
||||
```go
|
||||
// 三个条件必须全部满足才会去 MaxKB 检索:
|
||||
if req.KBEnabled && s.maxkb != nil && strings.TrimSpace(req.Context) != "" {
|
||||
// 去检索
|
||||
}
|
||||
```
|
||||
|
||||
| 条件 | 现状 | 状态 |
|
||||
|---|---|---|
|
||||
| `req.KBEnabled` | 第 5 步打开了开关 | ✅ |
|
||||
| `s.maxkb != nil` | 第 4 步配了 MaxKB | ✅ |
|
||||
| `req.Context != ""` | **PHP 没传,永远是空串** | ❌ |
|
||||
|
||||
### PHP 这边的调用
|
||||
|
||||
文件:`xk-api/app/Service/common/ai/AiMedicalAssistService.php` 第 722 行(病历)和 906 行(处方):
|
||||
|
||||
```php
|
||||
$this->dispatchShadowIfNeeded([
|
||||
'primary_generation_id' => (int) $row->id,
|
||||
'messages' => $messages,
|
||||
'agent_options' => ['scene' => self::SCENE_MR, 'kb_enabled' => null],
|
||||
// ❌ 没有 'context' 字段
|
||||
...
|
||||
]);
|
||||
```
|
||||
|
||||
**修复方案**:在 `agent_options` 里加 `context` 字段,把患者主诉、证候等关键字段拼成一句检索词。
|
||||
|
||||
---
|
||||
|
||||
## 怎么修(病历场景)
|
||||
|
||||
### 1. 找到调用位置
|
||||
|
||||
文件:`xk-api/app/Service/common/ai/AiMedicalAssistService.php`
|
||||
位置:**第 722 行附近**(`generateMedicalRecord` 方法内的 `dispatchShadowIfNeeded`)
|
||||
|
||||
### 2. 改之前长这样
|
||||
|
||||
```php
|
||||
$this->dispatchShadowIfNeeded([
|
||||
'primary_generation_id' => (int) $row->id,
|
||||
'messages' => $messages,
|
||||
'agent_options' => ['scene' => self::SCENE_MR, 'kb_enabled' => null],
|
||||
'meta' => [
|
||||
'store_id' => $storeId,
|
||||
'register_id' => $registerId,
|
||||
'doctor_id' => $doctorId,
|
||||
'scene' => self::SCENE_MR,
|
||||
'prescription_type' => 0,
|
||||
],
|
||||
], $chat->provider);
|
||||
```
|
||||
|
||||
### 3. 改成这样(加 context)
|
||||
|
||||
```php
|
||||
$this->dispatchShadowIfNeeded([
|
||||
'primary_generation_id' => (int) $row->id,
|
||||
'messages' => $messages,
|
||||
'agent_options' => [
|
||||
'scene' => self::SCENE_MR,
|
||||
'kb_enabled' => null,
|
||||
// 【新增】检索关键词:把主诉 + 现病史关键字 + 既往史关键字拼起来
|
||||
// 这串会被 MaxKB 用来"翻书",命中煎法/证候/ICD-10 等参考资料
|
||||
'context' => $this->buildMrKbQuery($chief, $context),
|
||||
],
|
||||
'meta' => [
|
||||
'store_id' => $storeId,
|
||||
'register_id' => $registerId,
|
||||
'doctor_id' => $doctorId,
|
||||
'scene' => self::SCENE_MR,
|
||||
'prescription_type' => 0,
|
||||
],
|
||||
], $chat->provider);
|
||||
```
|
||||
|
||||
### 4. 新增 `buildMrKbQuery` 私有方法
|
||||
|
||||
在 `AiMedicalAssistService` 类里任意位置(建议放在 `dispatchShadowIfNeeded` 附近)加:
|
||||
|
||||
```php
|
||||
/**
|
||||
* 拼接病历场景的 MaxKB 检索词
|
||||
*
|
||||
* 设计:把临床上最关键的几个字段拼成一串短文本,
|
||||
* MaxKB 会用这串做向量检索,命中相关的煎法/证候/ICD-10 资料。
|
||||
*
|
||||
* 注意:
|
||||
* - 不要太长(建议 < 100 字),否则会稀释关键词
|
||||
* - 不要带患者隐私(姓名/电话),只带医学语义
|
||||
* - 优先放中医术语(证候/治法),次放西医主诉
|
||||
*
|
||||
* @param string $chiefComplaint 主诉(如"胃脘胀满反复发作3年")
|
||||
* @param array $contextFields 规范化后的可选字段(现病史/既往史等)
|
||||
* @return string 检索词(如"胃脘胀满 痰湿中阻 健脾化湿")
|
||||
*/
|
||||
private function buildMrKbQuery(string $chiefComplaint, array $contextFields): string
|
||||
{
|
||||
$parts = [];
|
||||
// 1. 主诉是必填,最优先
|
||||
if ($chiefComplaint !== '') {
|
||||
$parts[] = $chiefComplaint;
|
||||
}
|
||||
// 2. 中医证候(如果前端/历史病历已填)
|
||||
if (!empty($contextFields['tcm_syndrome'])) {
|
||||
$parts[] = (string) $contextFields['tcm_syndrome'];
|
||||
}
|
||||
// 3. 中医治法
|
||||
if (!empty($contextFields['tcm_therapy'])) {
|
||||
$parts[] = (string) $contextFields['tcm_therapy'];
|
||||
}
|
||||
// 4. 西医诊断(用于 ICD-10 匹配)
|
||||
if (!empty($contextFields['western_diagnosis'])) {
|
||||
$parts[] = (string) $contextFields['western_diagnosis'];
|
||||
}
|
||||
// 用空格分隔,去重,限长(防超长 prompt)
|
||||
$query = trim(implode(' ', array_unique($parts)));
|
||||
return mb_substr($query, 0, 200);
|
||||
}
|
||||
```
|
||||
|
||||
> **关于字段名**:`tcm_syndrome / tcm_therapy / western_diagnosis` 是猜测的字段名。
|
||||
> 你需要根据 `normalizeMrContextFields()` 实际接受的字段名调整。看一下文件里这个方法的实现,或者在测试时打印 `$context` 看实际 key。
|
||||
|
||||
---
|
||||
|
||||
## 怎么修(处方场景)
|
||||
|
||||
### 1. 找到调用位置
|
||||
|
||||
文件:`xk-api/app/Service/common/ai/AiMedicalAssistService.php`
|
||||
位置:**第 906 行附近**(`generatePrescription` 方法内的 `dispatchShadowIfNeeded`)
|
||||
|
||||
### 2. 改之前
|
||||
|
||||
```php
|
||||
'agent_options' => ['scene' => self::SCENE_RX, 'kb_enabled' => null],
|
||||
```
|
||||
|
||||
### 3. 改成
|
||||
|
||||
```php
|
||||
'agent_options' => [
|
||||
'scene' => self::SCENE_RX,
|
||||
'kb_enabled' => null,
|
||||
// 【新增】处方场景检索词:主诉 + 证候 + 治法 + 药味
|
||||
'context' => $this->buildRxKbQuery($chief, $mrArr),
|
||||
],
|
||||
```
|
||||
|
||||
### 4. 新增 `buildRxKbQuery` 私有方法
|
||||
|
||||
```php
|
||||
/**
|
||||
* 拼接处方场景的 MaxKB 检索词
|
||||
*
|
||||
* 处方场景更关心:药材功效、配伍禁忌、煎法、委托调剂规则
|
||||
* 所以检索词优先放:证候 + 治法 + 已选药材 + 剂型
|
||||
*
|
||||
* @param string $chiefComplaint 主诉
|
||||
* @param array $mrArr 病历数据(含证候/治法等)
|
||||
* @return string 检索词
|
||||
*/
|
||||
private function buildRxKbQuery(string $chiefComplaint, array $mrArr): string
|
||||
{
|
||||
$parts = [];
|
||||
if ($chiefComplaint !== '') {
|
||||
$parts[] = $chiefComplaint;
|
||||
}
|
||||
if (!empty($mrArr['tcm_syndrome'])) {
|
||||
$parts[] = (string) $mrArr['tcm_syndrome'];
|
||||
}
|
||||
if (!empty($mrArr['tcm_therapy'])) {
|
||||
$parts[] = (string) $mrArr['tcm_therapy'];
|
||||
}
|
||||
// 关键词加权:处方场景一定要查配伍禁忌和煎法
|
||||
$parts[] = '配伍禁忌';
|
||||
$parts[] = '煎法';
|
||||
$query = trim(implode(' ', array_unique($parts)));
|
||||
return mb_substr($query, 0, 200);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 为什么这么设计检索词
|
||||
|
||||
### ✅ 好的检索词
|
||||
|
||||
| 检索词 | MaxKB 会命中 |
|
||||
|---|---|
|
||||
| `胃脘胀满 痰湿中阻 健脾化湿` | 煎法说明 + 证候治法字典 |
|
||||
| `黄芪 党参 补气 配伍禁忌` | 配伍禁忌表 + 药品库 |
|
||||
| `高血压 ICD-10` | ICD-10 诊断字典 |
|
||||
|
||||
### ❌ 坏的检索词
|
||||
|
||||
| 检索词 | 问题 |
|
||||
|---|---|
|
||||
| `张三 男 35岁` | 没医学语义,搜不到任何东西 |
|
||||
| (空字符串) | Go Agent 直接跳过 |
|
||||
| 一大段 1000 字现病史 | 关键词被稀释,命中精度差 |
|
||||
|
||||
---
|
||||
|
||||
## 验证修复成功
|
||||
|
||||
改完后,发起一次病历生成请求,然后查数据库:
|
||||
|
||||
```sql
|
||||
-- 找最新一条 agent 路径的生成记录
|
||||
SELECT id, scene, provider, step_count, total_tokens
|
||||
FROM xk_ai_generation
|
||||
WHERE provider = 'agent'
|
||||
ORDER BY id DESC LIMIT 1;
|
||||
|
||||
-- 看这条记录的子步骤
|
||||
SELECT step_type, status, detail, prompt_tokens, completion_tokens
|
||||
FROM xk_ai_generation_step
|
||||
WHERE generation_id = <上面的id>
|
||||
ORDER BY id;
|
||||
```
|
||||
|
||||
### 成功的样子
|
||||
|
||||
```
|
||||
step_type | status | detail | tokens
|
||||
kb_retrieval | 1 | 命中 5 条相关文档 | 0
|
||||
llm_call | 1 | - | 1234
|
||||
```
|
||||
|
||||
**看到 `kb_retrieval` 且 status=1 就说明 MaxKB 真的被调用了!**
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q1:改完 PHP 报错"undefined index tcm_syndrome"
|
||||
|
||||
字段名不对。打印 `$context` 或 `$mrArr` 看实际 key:
|
||||
|
||||
```php
|
||||
Log::info('[KB query debug]', ['context' => $context, 'mrArr' => $mrArr]);
|
||||
```
|
||||
|
||||
然后根据实际字段名改 `buildMrKbQuery` / `buildRxKbQuery`。
|
||||
|
||||
### Q2:检索词太短搜不到
|
||||
|
||||
至少要有 2-3 个关键词。如果只有主诉一个词,MaxKB 命中可能不准。
|
||||
|
||||
### Q3:检索词太长命中精度差
|
||||
|
||||
限制在 100-200 字以内最好。
|
||||
|
||||
### Q4:影子流量才传 context,主链路不传?
|
||||
|
||||
注意:上面给的代码是改在 `dispatchShadowIfNeeded` 里,**只影响影子流量**。
|
||||
|
||||
如果你要主链路也走检索,需要改的是 **主调 Go Agent 的代码**,而不仅仅是影子流量。
|
||||
|
||||
主链路在哪调?看 `AiAgentFactory::make($provider)->chatCompletions($messages, $options)` 这种调用。把 `$options` 里也加 `context` 字段即可( `$provider === 'agent'` 时才生效)。
|
||||
|
||||
---
|
||||
|
||||
下一步:[07_验证与排错.md](./07_验证与排错.md)
|
||||
207
docs/maxkb-ai/07_验证与排错.md
Normal file
207
docs/maxkb-ai/07_验证与排错.md
Normal file
@@ -0,0 +1,207 @@
|
||||
# 第 7 步:完整验证与排错指南
|
||||
|
||||
> 全部配完后,怎么知道真的接通了?出了问题怎么查?
|
||||
|
||||
---
|
||||
|
||||
## 4 层验证(从外到内)
|
||||
|
||||
每一层独立验证,**从最外层开始**,哪一层失败就查哪一层。
|
||||
|
||||
```
|
||||
[医生请求] → [PHP] → [Go Agent] → [MaxKB]
|
||||
① ② ③ ④
|
||||
```
|
||||
|
||||
### 验证 ④ MaxKB 本身能不能搜
|
||||
|
||||
**目的**:确认知识库内容没问题。
|
||||
|
||||
**方法**:用 curl 直接打 MaxKB:
|
||||
|
||||
```bash
|
||||
curl -X POST "http://你的MaxKB地址:8081/api/application/你的AppID/search" ^
|
||||
-H "Authorization: Bearer 你的APIKey" ^
|
||||
-H "Content-Type: application/json" ^
|
||||
-d "{\"query\":\"痰湿中阻 煎法\",\"top_k\":3}"
|
||||
```
|
||||
|
||||
| 返回结果 | 说明 |
|
||||
|---|---|
|
||||
| `code: 200` + 有 `documents` 数组 | ✅ MaxKB OK |
|
||||
| 401 | API Key 错 |
|
||||
| 404 | URL 或 AppID 错 |
|
||||
| 空 documents | 文档没向量化完 / 内容问题 |
|
||||
|
||||
### 验证 ③ Go Agent 能不能调通 MaxKB
|
||||
|
||||
**目的**:确认 Go 配置正确 + Go ↔ MaxKB 网络通。
|
||||
|
||||
**方法**:用 curl 直接打 Go Agent 的 `/enhance` 接口:
|
||||
|
||||
```bash
|
||||
curl -X POST "http://localhost:8080/api/v1/agent/enhance" ^
|
||||
-H "Content-Type: application/json" ^
|
||||
-d "{\"scene\":\"medical_record\",\"context\":\"胃脘胀满 痰湿中阻\",\"messages\":[{\"role\":\"user\",\"content\":\"测试\"}],\"kb_enabled\":true,\"top_k\":3}"
|
||||
```
|
||||
|
||||
看返回的 JSON:
|
||||
|
||||
| 返回中的 `steps` | 说明 |
|
||||
|---|---|
|
||||
| 有 `step_type: "kb_retrieval"` 且 `status: 1` | ✅ Go ↔ MaxKB 通了 |
|
||||
| 有 `kb_retrieval` 但 `status: 2` | MaxKB 调用失败,看 `detail` 字段 |
|
||||
| 完全没有 `kb_retrieval` | Go 端 kb_enabled 没收到 true,或 context 空 |
|
||||
|
||||
### 验证 ② PHP 端开关和参数
|
||||
|
||||
**目的**:确认 PHP 真的把 `kb_enabled=true` 和 `context` 传给了 Go。
|
||||
|
||||
**方法 A**:在 `TcmAgentClient.php` 加临时日志。
|
||||
|
||||
打开 `app/Service/common/ai/TcmAgentClient.php`,找到 `chatCompletions` 方法构造 `$payload` 的位置,加一行:
|
||||
|
||||
```php
|
||||
Log::info('[TcmAgent payload]', $payload);
|
||||
```
|
||||
|
||||
发起一次病历生成请求,看日志:
|
||||
|
||||
| 现象 | 原因 |
|
||||
|---|---|
|
||||
| `kb_enabled: true` + `context: "..."` | ✅ 参数 OK |
|
||||
| `kb_enabled: false` | system_config 开关没改对 / PHP 缓存 |
|
||||
| `context` 字段不存在或为空 | 第 6 步的代码没改对 |
|
||||
|
||||
**方法 B**:直接查 `xk_ai_generation_step` 表。
|
||||
|
||||
```sql
|
||||
SELECT id, scene, provider, step_count, created_at
|
||||
FROM xk_ai_generation
|
||||
ORDER BY id DESC LIMIT 5;
|
||||
```
|
||||
|
||||
看 `step_count` 字段:
|
||||
- `1`:只有 llm_call,没检索
|
||||
- `2+`:有检索 + LLM(说明 KB 真的被调用了)
|
||||
|
||||
再查子表:
|
||||
```sql
|
||||
SELECT step_type, status, detail, duration_ms
|
||||
FROM xk_ai_generation_step
|
||||
WHERE generation_id = <上面查到的id>;
|
||||
```
|
||||
|
||||
### 验证 ① 真实业务请求
|
||||
|
||||
**目的**:确认从医生点击"生成病历"开始整条链路通。
|
||||
|
||||
**方法**:在小程序/后台发起一次病历生成(`provider=agent`),完成后立即查数据库:
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
g.id, g.scene, g.provider, g.total_tokens, g.duration_ms,
|
||||
(SELECT COUNT(*) FROM xk_ai_generation_step s WHERE s.generation_id = g.id AND s.step_type = 'kb_retrieval' AND s.status = 1) AS kb_hit_count
|
||||
FROM xk_ai_generation g
|
||||
WHERE g.provider = 'agent'
|
||||
ORDER BY g.id DESC LIMIT 1;
|
||||
```
|
||||
|
||||
| kb_hit_count | 说明 |
|
||||
|---|---|
|
||||
| `1` | ✅ 整条链路通,MaxKB 被命中 |
|
||||
| `0` | 中间有断点,回上一层验证 |
|
||||
|
||||
---
|
||||
|
||||
## 排错速查表
|
||||
|
||||
| 症状 | 99% 的原因 | 解决 |
|
||||
|---|---|---|
|
||||
| `kb_retrieval` step 没出现 | PHP 没传 `context` 或开关没开 | 回第 5、6 步 |
|
||||
| `kb_retrieval` status=2 | Go 连不上 MaxKB | 回第 4 步检查 base_url/port |
|
||||
| `kb_retrieval` status=1 但 detail="命中 0 条" | 检索词太偏 / 知识库没相关内容 | 换检索词或上传更多资料 |
|
||||
| 整个请求超时(120s) | MaxKB 卡死或网络断了 | `docker logs maxkb` 看 MaxKB 日志 |
|
||||
| Go Agent 启动报错 | config.yaml 格式错 | 用 yamllint.com 检查 |
|
||||
| PHP 端报 "未配置 Go Agent 地址" | `ai_agent_base_url` 配置项或 .env 没设 | 后台系统配置或 .env 加 `AI_AGENT_BASE_URL` |
|
||||
|
||||
---
|
||||
|
||||
## 看日志的几个位置
|
||||
|
||||
### MaxKB 日志
|
||||
|
||||
```bash
|
||||
docker logs -f maxkb --tail 100
|
||||
```
|
||||
|
||||
### Go Agent 日志
|
||||
|
||||
**直接运行的**:终端看输出。
|
||||
|
||||
**Docker 运行的**:
|
||||
```bash
|
||||
docker logs -f tcm-agent --tail 100
|
||||
```
|
||||
|
||||
**1Panel 部署的**:1Panel → 容器 → tcm-agent → 日志。
|
||||
|
||||
### PHP 日志
|
||||
|
||||
文件位置:`xk-api/storage/logs/laravel-<日期>.log`
|
||||
|
||||
实时看:
|
||||
```bash
|
||||
tail -f storage/logs/laravel-$(date +%Y-%m-%d).log
|
||||
```
|
||||
|
||||
### 数据库步骤表
|
||||
|
||||
最直观的"是否成功"信号源:
|
||||
|
||||
```sql
|
||||
SELECT
|
||||
s.id, s.generation_id, s.step_type, s.status,
|
||||
s.detail, s.duration_ms,
|
||||
FROM_UNIXTIME(s.started_at) AS started_at
|
||||
FROM xk_ai_generation_step s
|
||||
ORDER BY s.id DESC LIMIT 20;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 性能调优(接入后再看)
|
||||
|
||||
### TopK 调多大?
|
||||
|
||||
默认 5。命中太少(< 3)可以调到 8,但别超过 10(会让 prompt 过长、token 成本飞涨)。
|
||||
|
||||
### 检索太慢怎么办?
|
||||
|
||||
- 检查 MaxKB 服务器 CPU/内存
|
||||
- 知识库分段太大 → 在 MaxKB 后台调"分段长度"(建议 300-500 字一段)
|
||||
- 用更快的 embedding 模型
|
||||
|
||||
### 检索结果不准怎么办?
|
||||
|
||||
- 看检索词是否包含中医术语
|
||||
- 在 MaxKB 后台用"命中测试"功能手动试
|
||||
- 文档质量影响大,确保 md 内容结构化(用 `##` 分章节)
|
||||
|
||||
---
|
||||
|
||||
## 成功后的下一步
|
||||
|
||||
接入完成后,可以:
|
||||
|
||||
1. **灰度放量**:在后台把 `ai_ab_test_enabled=1` + `ai_ab_test_experiment_ratio=10`,让 10% 用户先用上 Agent + MaxKB
|
||||
2. **观察对比**:在"AI 影子流量对比"页看主链路 vs Agent 的 token/耗时/相似度
|
||||
3. **逐步放量**:稳定后把 ratio 提到 30 → 50 → 100
|
||||
|
||||
---
|
||||
|
||||
## 全部完成 ✅
|
||||
|
||||
恭喜!如果所有验证都通过,你的中医 AI Agent 已经具备"翻书"能力了。
|
||||
|
||||
回主目录:[README.md](./README.md)
|
||||
387
docs/maxkb-ai/08_本地知识库管理.md
Normal file
387
docs/maxkb-ai/08_本地知识库管理.md
Normal file
@@ -0,0 +1,387 @@
|
||||
# 08 · 本地知识库管理(V1 全文检索版)
|
||||
|
||||
> 适用:MaxKB 免费版没有"纯检索 API"时的备选方案。本地方案直接把知识库内容存在 `z_xk` 数据库里,用 MySQL FULLTEXT 检索,零外部依赖。
|
||||
>
|
||||
> 适合零基础运维 / 业务人员,按步骤操作即可。
|
||||
|
||||
---
|
||||
|
||||
## 一、它是什么?
|
||||
|
||||
把"中医诊疗资料"(煎法、调剂规则、证候字典、ICD-10、药品库等)放到**本地数据库表**里,由 Go Agent 直接检索。
|
||||
|
||||
### 与 MaxKB 的对比
|
||||
|
||||
| 项目 | MaxKB 平台 | 本地知识库(本文档) |
|
||||
|------|------------|----------------------|
|
||||
| 部署 | 单独 Docker 部署 | **零部署**,跟着 MySQL 走 |
|
||||
| 检索 API | 免费版没有 / Pro 版才有 | **免费**(MySQL FULLTEXT) |
|
||||
| 向量化 | 支持 | V1 不支持,V2 接 BGE-M3 |
|
||||
| 中文分词 | 自带 | MySQL `ngram` 分词器(2-gram) |
|
||||
| 管理界面 | 自带 Web UI | `/kb/view` 单页(Vue CDN) |
|
||||
| 适合场景 | 内容多、要向量检索 | **中小规模(几千段以内)**,要快、要省 |
|
||||
|
||||
### 一句话总结
|
||||
|
||||
> V1 用"本地知识库 + 全文检索"先把链路跑通;内容量大了或需要语义匹配时,再切回 MaxKB 或升级 V2 向量化。
|
||||
|
||||
---
|
||||
|
||||
## 二、V1 整体架构
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["PHP AiMedicalAssistService"] -->|"POST /api/v1/agent/enhance"| B["Go Agent / EnhancerService"]
|
||||
B --> C{agentcfg.KB.Source}
|
||||
C -->|local 默认| D["本地知识库检索器<br/>kb.Searcher"]
|
||||
C -->|maxkb 切换| E["MaxKB 客户端<br/>(需要 Pro 版)"]
|
||||
D --> F[("z_xk.xk_kb_chunk<br/>FULLTEXT ngram 索引")]
|
||||
E --> G[[MaxKB 服务]]
|
||||
D --> H["拼成参考资料 system 消息"]
|
||||
E --> H
|
||||
H --> I["调 LLM(DeepSeek/Spark/...)"]
|
||||
I --> J["返回 PHP"]
|
||||
```
|
||||
|
||||
**关键判断点:** `xk_system_config.ai_kb_source` 的值:
|
||||
- `local`(默认)→ 走本地知识库
|
||||
- `maxkb` → 走 MaxKB 平台
|
||||
|
||||
切换是一行 SQL,**无需重启**:
|
||||
|
||||
```sql
|
||||
UPDATE xk_system_config SET config_value = 'local' WHERE config_key = 'ai_kb_source';
|
||||
-- 缓存 60 秒生效;想立即生效调 Go Agent 的 /api/v1/agent/invalidate-cache 接口
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、首次部署(5 步)
|
||||
|
||||
### 步骤 1:导入数据库表结构
|
||||
|
||||
执行 SQL 文件:
|
||||
|
||||
```
|
||||
d:\worker\gs\sql\萧康云医\20260811\kb_local.sql
|
||||
```
|
||||
|
||||
这一步会创建 3 张表 + 写入 6 条 `xk_system_config` 默认配置:
|
||||
|
||||
| 表名 | 作用 |
|
||||
|------|------|
|
||||
| `xk_kb_library` | 知识库(一个 library = 一组文档) |
|
||||
| `xk_kb_doc` | 文档(一个 doc = 一个导入文件) |
|
||||
| `xk_kb_chunk` | 分段(一个 chunk = 检索的最小单元) |
|
||||
|
||||
新增的 6 个配置项:
|
||||
|
||||
| key | 默认值 | 说明 |
|
||||
|-----|--------|------|
|
||||
| `ai_kb_source` | `local` | 知识库源(local/maxkb) |
|
||||
| `ai_kb_embedding_provider` | `noop` | 向量化 provider(V1 不用) |
|
||||
| `ai_kb_embedding_api_key` | (空) | 向量化 API Key(V1 不用) |
|
||||
| `ai_kb_top_k` | `5` | 检索返回条数 |
|
||||
| `ai_kb_similarity_threshold` | `0.5` | 向量相似度阈值(V2 用) |
|
||||
| `ai_kb_search_mode` | `fulltext` | 检索模式(fulltext/vector/blend) |
|
||||
|
||||
### 步骤 2:确认 MySQL 版本和 ngram 支持
|
||||
|
||||
本地知识库 V1 走 **MySQL FULLTEXT + ngram 分词器**,要求:
|
||||
|
||||
- MySQL **5.7.6+**(推荐 8.0+)
|
||||
- InnoDB 引擎(已经是默认)
|
||||
- `innodb_ft_ngram_token_size` 默认是 2(中医术语大多是 2-4 字,2-gram 正合适)
|
||||
|
||||
验证 ngram 是否生效:
|
||||
|
||||
```sql
|
||||
SHOW VARIABLES LIKE 'innodb_ft_ngram_token_size';
|
||||
-- 期望值:2
|
||||
```
|
||||
|
||||
> 如果你的 MySQL 是 8.0 默认配置,以上检查都会通过,不用改任何东西。
|
||||
|
||||
### 步骤 3:重启 Go Agent
|
||||
|
||||
```bash
|
||||
# 在 Go Agent 部署目录
|
||||
go build -o tcm-agent ./cmd/server
|
||||
./tcm-agent
|
||||
```
|
||||
|
||||
启动后日志里应该看到:
|
||||
|
||||
```
|
||||
[router] 已注册路由:POST /api/v1/kb/admin/libraries
|
||||
[router] 已注册路由:POST /api/v1/kb/admin/docs/import
|
||||
...
|
||||
[router] 已挂载静态文件:/kb/view → view/
|
||||
```
|
||||
|
||||
### 步骤 4:打开后台管理页
|
||||
|
||||
浏览器访问:
|
||||
|
||||
```
|
||||
http://你的Go-Agent地址:8080/kb/view
|
||||
```
|
||||
|
||||
(端口看你的 `server.port` 配置)
|
||||
|
||||
打开后会看到三个 Tab:
|
||||
- **知识库**:库 / 文档 / 分段管理
|
||||
- **检索测试**:直接试关键词,看检索效果
|
||||
- **向量化(V2)**:V2 预告,V1 用不到
|
||||
|
||||
### 步骤 5:把 PHP 切到走 Go Agent
|
||||
|
||||
在 PHP 后台的「系统配置」页面,把:
|
||||
|
||||
```
|
||||
ai_active_provider = agent
|
||||
```
|
||||
|
||||
(或者前端在调 AI 生成时显式传 `provider=agent`,详见 [05_打开PHP开关.md](05_打开PHP开关.md))
|
||||
|
||||
---
|
||||
|
||||
## 四、知识库内容从哪来?
|
||||
|
||||
### 方式 A:从 MaxKB 导出(推荐)
|
||||
|
||||
如果你之前已经在 MaxKB 里维护好了内容:
|
||||
|
||||
1. 打开 MaxKB → 进入你的应用 → 知识库
|
||||
2. 选中要导出的文档 → 点「导出」→ 选择 **Excel 格式**
|
||||
3. 下载得到一个 `.xlsx` 文件
|
||||
4. 直接用本地知识库管理页的「导入文档」上传
|
||||
|
||||
**MaxKB 导出的 Excel 默认 3 列:**
|
||||
|
||||
| 列 | 内容 | 必填 |
|
||||
|----|------|------|
|
||||
| 第 1 列 | 分段标题 | 可空 |
|
||||
| 第 2 列 | 分段内容 | **必填** |
|
||||
| 第 3 列 | 关联问题列表(分号分隔) | 可空 |
|
||||
|
||||
> 本地知识库会自动识别表头行(包含"标题"/"内容"字样)并跳过。
|
||||
|
||||
### 方式 B:手动写 Markdown
|
||||
|
||||
适合规则类、列表类内容(如煎法、调剂规则)。
|
||||
|
||||
新建一个 `煎法规则.md`:
|
||||
|
||||
```markdown
|
||||
# 解表剂
|
||||
|
||||
## 麻黄汤
|
||||
麻黄 9g 桂枝 6g 杏仁 6g 炙甘草 3g
|
||||
水煎服,温覆取微汗。
|
||||
|
||||
## 桂枝汤
|
||||
桂枝 9g 芍药 9g 生姜 9g 大枣 3枚 炙甘草 6g
|
||||
水煎服,啜热稀粥助药力。
|
||||
|
||||
# 攻下剂
|
||||
|
||||
## 大承气汤
|
||||
大黄 12g 厚朴 15g 枳实 12g 芒硝 9g
|
||||
水煎,先煮厚朴枳实,后下大黄,溶化芒硝。
|
||||
```
|
||||
|
||||
按 `#`/`##`/`###` 标题切分,每个标题下的一段成为一个 chunk。
|
||||
|
||||
### 方式 C:纯文本(txt)
|
||||
|
||||
无标题的段落文本,按双换行自动切段,每段累计 500 字打包成一个 chunk。
|
||||
|
||||
---
|
||||
|
||||
## 五、典型操作流程
|
||||
|
||||
### 5.1 新建一个库
|
||||
|
||||
1. 打开 `/kb/view`
|
||||
2. 点「新建知识库」
|
||||
3. 填库名(如"中医诊疗资料 v1")、描述
|
||||
4. 来源选「从 MaxKB 导出」或「手动建立」
|
||||
5. 点确定
|
||||
|
||||
### 5.2 导入文档
|
||||
|
||||
1. 在库列表点「进入」选中库
|
||||
2. 点「导入文档(xlsx / md / txt)」
|
||||
3. 选择本地文件上传
|
||||
4. 等几秒(视文件大小),看到提示"导入成功:N 个分段"
|
||||
5. 文档列表里会出现新条目
|
||||
|
||||
> 单文件最大 50MB。如果文件很大建议拆分多个小文件分别导入,方便管理。
|
||||
|
||||
### 5.3 查看分段
|
||||
|
||||
点文档行的「查看分段」可看到切分后的所有 chunk。
|
||||
|
||||
### 5.4 试一试检索
|
||||
|
||||
切到「检索测试」Tab:
|
||||
|
||||
1. 选择库
|
||||
2. 输入检索词(如"痰湿中阻")
|
||||
3. 点「检索」
|
||||
4. 看到结果列表,每条带一个 **score(得分)**:
|
||||
- 得分越高越相关
|
||||
- 得分是 MySQL FULLTEXT BM25 相关度(无固定范围,相对比较即可)
|
||||
- 0 分或没结果说明关键词太冷门
|
||||
|
||||
> **检索技巧:** V1 是 2-gram 分词,关键词用 2-4 字效果最好(如"煎法"、"调剂"、"麻黄汤")。
|
||||
> 太长的句子(如"痰湿中阻怎么治")会被自动切成"痰湿""湿中""中阻""怎么""么治"等 2-gram,仍能匹配,但 shorter query 更精确。
|
||||
|
||||
### 5.5 删除文档 / 库
|
||||
|
||||
- 删除文档:会软删该文档 + 它的所有分段
|
||||
- 删除库:会软删该库 + 库下所有文档和分段
|
||||
|
||||
> 软删除 = `deleted_at` 字段填当前时间戳,不物理删除,便于追溯。如果想物理清理,自行 SQL 操作即可。
|
||||
|
||||
---
|
||||
|
||||
## 六、PHP 端如何配合?
|
||||
|
||||
### 6.1 PHP 调用 Go Agent 时传 context
|
||||
|
||||
PHP 端在 `AiMedicalAssistService` 里组装好检索关键词,作为 `context` 字段传给 Go Agent:
|
||||
|
||||
```php
|
||||
// PHP 端伪代码
|
||||
$payload = [
|
||||
'scene' => 'medical_record',
|
||||
'context' => '痰湿中阻 煎法', // ← 关键:这是检索关键词
|
||||
'messages' => $messages,
|
||||
'kb_enabled' => true,
|
||||
'top_k' => 5,
|
||||
];
|
||||
$response = TcmAgentClient::getInstance()->chatCompletions($messages, [
|
||||
'payload' => $payload,
|
||||
]);
|
||||
```
|
||||
|
||||
详见 [06_修复检索词Bug.md](06_修复检索词Bug.md)。
|
||||
|
||||
### 6.2 Go Agent 端的处理流程
|
||||
|
||||
```
|
||||
PHP POST /api/v1/agent/enhance
|
||||
body.context = "痰湿中阻 煎法"
|
||||
↓
|
||||
[1] 读 agentcfg.KB.Source(默认 local)
|
||||
[2] 调 kb.Searcher.Search:
|
||||
SELECT *, MATCH(title,content) AGAINST('痰湿中阻 煎法' IN BOOLEAN MODE) AS score
|
||||
FROM xk_kb_chunk
|
||||
WHERE library_id = ? AND is_active = 1 AND deleted_at = 0
|
||||
AND MATCH(title,content) AGAINST('痰湿中阻 煎法' IN BOOLEAN MODE)
|
||||
ORDER BY score DESC LIMIT 5
|
||||
[3] 把命中结果拼成 system 消息,插到 messages 头部
|
||||
[4] 调 LLM
|
||||
[5] 返回 { content, steps: [{step_type:'kb_retrieval', ...}, {step_type:'llm_call', ...}] }
|
||||
```
|
||||
|
||||
PHP 端拿到 `steps` 后写入 `xk_ai_generation_step` 子表,记录每次检索的耗时(如果有的话)。
|
||||
|
||||
---
|
||||
|
||||
## 七、常见问题排查
|
||||
|
||||
### Q1:检索结果为空?
|
||||
|
||||
**排查清单:**
|
||||
|
||||
1. 库里是否有分段?管理页「库列表」看 `chunk_count`
|
||||
2. 分段是否启用?`is_active=1`
|
||||
3. 检索词是否太短?(ngram 最少 2 字,单字会匹配不到)
|
||||
4. 直接 SQL 验证:
|
||||
|
||||
```sql
|
||||
-- 检查 FULLTEXT 是否能命中
|
||||
SELECT id, title, LEFT(content, 50), MATCH(title,content) AGAINST('痰湿' IN BOOLEAN MODE) AS score
|
||||
FROM xk_kb_chunk
|
||||
WHERE library_id = 1 AND is_active = 1 AND deleted_at = 0
|
||||
ORDER BY score DESC
|
||||
LIMIT 10;
|
||||
```
|
||||
|
||||
5. 看看 ngram 索引是否建成功:
|
||||
|
||||
```sql
|
||||
SHOW INDEX FROM xk_kb_chunk WHERE Index_type = 'FULLTEXT';
|
||||
-- 期望看到 ft_content 索引,Index_type=FULLTEXT
|
||||
```
|
||||
|
||||
### Q2:检索很慢?
|
||||
|
||||
- 检查 chunk 总数,超过 10 万行时考虑加索引或换 V2 向量检索
|
||||
- 检查 MySQL `innodb_buffer_pool_size` 是否够大(建议 4G+)
|
||||
- 检查 `ft_max_word_len`(默认 84 应该够)
|
||||
|
||||
### Q3:导入 Excel 失败?
|
||||
|
||||
- 确认文件后缀是 `.xlsx`(不支持老版 `.xls` 二进制格式)
|
||||
- 确认文件大小 < 50MB
|
||||
- 看 Go Agent 日志:`kb: 打开 xlsx 失败: ...`,常见原因是文件损坏或格式不对
|
||||
- 用 Excel/WPS 重新另存为 xlsx 再试
|
||||
|
||||
### Q4:切换 maxkb 模式不生效?
|
||||
|
||||
`agentcfg` 有 60 秒缓存。立即生效方法:
|
||||
|
||||
```bash
|
||||
# 调 Go Agent 的缓存失效接口(如果实现了)
|
||||
curl -X POST http://你的Go-Agent地址:8080/api/v1/agent/invalidate-cache
|
||||
```
|
||||
|
||||
或者重启 Go Agent 进程。
|
||||
|
||||
---
|
||||
|
||||
## 八、V2 升级路径(接入 BGE-M3 向量化)
|
||||
|
||||
V1 的设计已经为 V2 留好了所有接口,升级时**只换底层,不动业务**。
|
||||
|
||||
### V2 改造点
|
||||
|
||||
| 模块 | V1 | V2 |
|
||||
|------|------|------|
|
||||
| `kb.Embedder` | `NoopEmbedder`(不做向量) | `BGEM3Embedder`(本地服务) |
|
||||
| `xk_kb_chunk.content_vector` | NULL | 1024 维向量(JSON 数组) |
|
||||
| `xk_kb_chunk.is_vectorized` | 0 | 1(向量化后回填) |
|
||||
| `kb.Searcher` | 仅 FULLTEXT | vector / blend(混合 BM25 + 余弦) |
|
||||
| `ai_kb_search_mode` | `fulltext` | `blend`(推荐) |
|
||||
|
||||
### V2 接入步骤(未来)
|
||||
|
||||
1. 本地部署 BGE-M3 服务(Docker:`curl -X POST http://localhost:8081/embed -d '...'`)
|
||||
2. 把 V1 的 `NoopEmbedder` 换成 `BGEM3Embedder`(新增文件 `embedder_bge.go`)
|
||||
3. 调用 `/api/v1/kb/admin/embed` 触发批量向量化(V2 启用)
|
||||
4. 把 `ai_kb_search_mode` 改成 `blend`
|
||||
5. 重启 Go Agent
|
||||
|
||||
**业务代码(PHP / EnhancerService)零改动。**
|
||||
|
||||
---
|
||||
|
||||
## 九、文件清单(开发参考)
|
||||
|
||||
| 文件 | 作用 |
|
||||
|------|------|
|
||||
| `internal/kb/embedder.go` | Embedder 接口 + NoopEmbedder + V2 工厂 |
|
||||
| `internal/kb/importer.go` | Chunker + Importer(解析 xlsx/md/txt) |
|
||||
| `internal/kb/searcher.go` | Searcher(V1 FULLTEXT / V2 vector) |
|
||||
| `internal/kb/library_service.go` | 库/文档/分段管理业务层 |
|
||||
| `internal/kb/helpers.go` | 小工具函数 |
|
||||
| `internal/dao/kb_dao.go` | 数据访问层(GORM 实体 + CRUD) |
|
||||
| `internal/handler/kb_admin_handler.go` | 9 个 HTTP 端点 |
|
||||
| `internal/router/router.go` | 路由注册 + 静态文件挂载 |
|
||||
| `view/index.html` | 后台管理单页(Vue CDN + Element Plus) |
|
||||
| `internal/agentcfg/agentcfg.go` | KB 配置加载(`ai_kb_*` 系列) |
|
||||
| `20260811/kb_local.sql` | 建表 SQL + 默认配置项 |
|
||||
256
docs/maxkb-ai/MaxKB创建内容.md
Normal file
256
docs/maxkb-ai/MaxKB创建内容.md
Normal file
@@ -0,0 +1,256 @@
|
||||
# MaxKB 智能体创建内容(直接复制版)
|
||||
|
||||
> 本文档专门给 MaxKB 智能体("创建智能体 → 空白创建 → 简易配置")页面用。
|
||||
>
|
||||
> **用法**:在 MaxKB 创建智能体时,每个字段直接对照本文档复制粘贴即可。
|
||||
|
||||
---
|
||||
|
||||
## 智能体基础信息
|
||||
|
||||
| 字段 | 复制这个 |
|
||||
|---|---|
|
||||
| **名称** | `萧康云医中医诊疗助手` |
|
||||
| **描述** | `中医病历生成与处方开具的智能辅助助手,融合中医证候/治法/疾病字典、煎法、配伍禁忌、ICD-10、药品库等专业资料` |
|
||||
| **AI 模型** | 选 `DeepSeek`(或 OpenAI GPT-4o)|
|
||||
| **历史聊天记录** | `0`(病历/处方是单次独立任务,不需要历史上下文)|
|
||||
|
||||
---
|
||||
|
||||
## 1. 系统提示词(直接复制下面整段)
|
||||
|
||||
> 这一段会**固定注入每次对话的开头**,用来给模型定角色、规则、输出格式。
|
||||
|
||||
```
|
||||
你是一位资深的中医诊疗专家,专注于中医病历书写和中药处方开具。
|
||||
你的知识边界严格限定在中医临床诊疗范围内:四诊合参、辨证论治、方剂配伍、煎法调剂、ICD-10诊断、中医证候/治法/疾病字典。
|
||||
|
||||
【核心职责】
|
||||
1. 根据患者主诉、现病史、既往史等临床信息,生成结构化的中医病历(含望闻问切、辨证、治法、方药)
|
||||
2. 根据病历结果开具中药处方(饮片/颗粒/成药),并标注剂量、单位、煎法、委托调剂等业务字段
|
||||
3. 所有回答必须优先参考"已知信息"中提供的知识库内容(煎法、证候、药品库等)
|
||||
|
||||
【回答规则】
|
||||
- 严格基于知识库内容回答,不在资料库中的内容不得编造
|
||||
- 涉及剂量、煎法、配伍禁忌时,必须引用知识库中的具体规则
|
||||
- 输出必须为合法 JSON(除非用户明确要求其他格式)
|
||||
- 处方中所有药材必须来自知识库的药品库,不得杜撰药名
|
||||
- 中医证候、治法、疾病名称必须使用规范术语(参考知识库字典)
|
||||
- 严格避免中医十八反十九畏的配伍禁忌
|
||||
|
||||
【输出风格】
|
||||
- 严肃专业,不寒暄
|
||||
- 字段精简,不带多余解释
|
||||
- 数字用阿拉伯数字,剂量精确到 0.1
|
||||
|
||||
【限制】
|
||||
- 不回答与中医诊疗无关的话题
|
||||
- 不进行西医诊断与西药处方建议
|
||||
- 不给出绝对化的治愈承诺
|
||||
- 涉及急危重症立即建议转诊
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 用户提示词(直接复制下面整段)
|
||||
|
||||
> 这一段会**拼在用户问题之前**,告诉模型"已知信息"和"用户问题"分别在哪个位置。
|
||||
>
|
||||
> ⚠️ **`{data}` 和 `{question}` 是 MaxKB 的内置变量,必须原样保留,不要替换成实际内容**。
|
||||
|
||||
```
|
||||
已知信息:
|
||||
{data}
|
||||
|
||||
任务:基于上述已知信息,结合中医临床规范,完成下述任务。要求所有结论必须有据可查,涉及煎法/配伍/ICD-10 的字段必须引用已知信息中的对应规则。
|
||||
|
||||
用户问题/任务:
|
||||
{question}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 知识库关联设置
|
||||
|
||||
| 字段 | 复制这个 |
|
||||
|---|---|
|
||||
| **关联知识库** | ✅ 勾选 `中医医疗知识库`(第 2 步创建的)|
|
||||
|
||||
### 检索参数(展开"高级设置"后填)
|
||||
|
||||
| 参数 | 推荐值 | 原因 |
|
||||
|---|---|---|
|
||||
| **检索模式** | `混合检索` | 同时用向量+全文,中医术语既需要语义匹配又需要关键词精确匹配 |
|
||||
| **相似度阈值** | `0.5` | 中医术语有同义/近义词,阈值太高会漏掉相关内容 |
|
||||
| **引用分段数 Top-N** | `5` | 既够覆盖一个症状的证候/煎法/药品,又不刷屏 |
|
||||
| **最大引用字符数** | `3000` | 病历/处方任务需要上下文,但又不能让 prompt 爆炸 |
|
||||
| **无引用时的回答策略** | `指定回复:知识库中暂无相关资料,请补充资料后重试` | **不要让模型用通用知识编造**,医疗内容必须可追溯 |
|
||||
| **问题优化** | ✅ 开启 | 用户原始问题(如"胃疼怎么治")会被改写成更适合检索的表述(如"胃脘痛 辨证论治")|
|
||||
|
||||
---
|
||||
|
||||
## 4. 技能(Skills)配置
|
||||
|
||||
> 我们的智能体不需要 MaxKB 的 MCP/工具/Skills —— 因为 Go Agent 已经在调用方做了所有工具编排(Function Calling、ReAct 等)。
|
||||
>
|
||||
> **保持"技能"区域为空**即可。
|
||||
|
||||
如果你将来想让 MaxKB 自己也能调外部接口(比如查 HIS 系统),可以加:
|
||||
|
||||
| 技能类型 | 是否需要 | 说明 |
|
||||
|---|---|---|
|
||||
| **MCP** | ❌ 不需要 | Go Agent 端已有 |
|
||||
| **工具** | ❌ 不需要 | 同上 |
|
||||
| **Skills** | ❌ 不需要 | 同上 |
|
||||
| **子智能体** | ❌ 不需要 | 目前只有一个智能体 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 开场白(可选,给调试用)
|
||||
|
||||
> 这一段是给 MaxKB 自己的"演示"窗口用的,不影响 API 调用。
|
||||
>
|
||||
> MaxKB API 调用(Go Agent 走的路径)不会用到开场白。
|
||||
|
||||
```
|
||||
你好,我是萧康云医中医诊疗助手。
|
||||
我可以帮你:
|
||||
- 根据患者信息生成结构化中医病历
|
||||
- 基于病历开具规范的中药处方
|
||||
|
||||
请提供患者主诉、年龄、性别等临床信息,我会参考中医知识库生成结果。
|
||||
|
||||
快捷问题:
|
||||
- 帮我生成一份"痰湿中阻"证型的病历示例
|
||||
- 黄芪、党参、白术的常用配伍剂量
|
||||
- 痰湿中阻的常用煎法是什么
|
||||
```
|
||||
|
||||
> **快捷问题格式**:`-` 开头,一行一个,MaxKB 会渲染成可点击按钮。
|
||||
|
||||
---
|
||||
|
||||
## 6. 完整字段速查表(创建时对照勾选)
|
||||
|
||||
把下表打印出来,逐项对照不会漏:
|
||||
|
||||
| # | 字段名 | 填什么 | 完成打勾 |
|
||||
|---|---|---|---|
|
||||
| 1 | 名称 | `萧康云医中医诊疗助手` | ☐ |
|
||||
| 2 | 描述 | 见上 | ☐ |
|
||||
| 3 | AI 模型 | DeepSeek | ☐ |
|
||||
| 4 | 系统提示词 | 复制本文档第 1 节 | ☐ |
|
||||
| 5 | 用户提示词 | 复制本文档第 2 节(保留 `{data}` `{question}`)| ☐ |
|
||||
| 6 | 历史聊天记录 | `0` | ☐ |
|
||||
| 7 | 关联知识库 | ✅ 中医医疗知识库 | ☐ |
|
||||
| 8 | 检索模式 | 混合检索 | ☐ |
|
||||
| 9 | 相似度阈值 | `0.5` | ☐ |
|
||||
| 10 | Top-N | `5` | ☐ |
|
||||
| 11 | 最大引用字符数 | `3000` | ☐ |
|
||||
| 12 | 无引用时回答策略 | 指定回复(拒绝编造)| ☐ |
|
||||
| 13 | 问题优化 | ✅ 开启 | ☐ |
|
||||
| 14 | 技能 | 留空 | ☐ |
|
||||
| 15 | 开场白 | 复制本文档第 5 节(可选)| ☐ |
|
||||
| 16 | **发布** | 右上角"保存并发布" | ☐ ⚠️ 必做 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 创建后必做的事 ⚠️
|
||||
|
||||
### 必做 1:发布智能体
|
||||
|
||||
新版 MaxKB **不会自动发布**,必须点右上角 **"保存并发布"**。
|
||||
|
||||
状态从"未发布"变成"**已发布**"才能用 API 调用。
|
||||
|
||||
### 必做 2:在调试窗口测试
|
||||
|
||||
进入智能体 → 调试窗口(右侧预览)→ 输入:
|
||||
|
||||
```
|
||||
患者:男,45岁,胃脘胀满反复发作3年,加重1周。舌苔白腻,脉濡滑。
|
||||
任务:生成中医病历。
|
||||
```
|
||||
|
||||
期望返回:包含"辨证:痰湿中阻"、"治法:健脾化湿、理气和胃"、引用了知识库的煎法/证候资料。
|
||||
|
||||
### 必做 3:拿 API Key
|
||||
|
||||
参见 [03_创建应用拿密钥.md](./03_创建应用拿密钥.md) 第 3 节"拿到三个钥匙"。
|
||||
|
||||
---
|
||||
|
||||
## 8. 常见问题
|
||||
|
||||
### Q1:调试时模型不回答,提示"未配置模型"
|
||||
|
||||
回 MaxKB 设置 → 模型管理 → 添加一个 DeepSeek 大语言模型(带 API Key)。
|
||||
|
||||
### Q2:返回的内容里没有引用知识库
|
||||
|
||||
检查:
|
||||
1. 智能体是否**关联**了知识库(不是只上传,要关联)
|
||||
2. 用户提示词里是否含 `{data}` 变量
|
||||
3. 检索参数:相似度阈值是否过高(建议 0.5)
|
||||
|
||||
### Q3:返回空 JSON 或不合法 JSON
|
||||
|
||||
去系统提示词加一句:
|
||||
```
|
||||
- 输出必须是单层 JSON 对象,不要带 markdown 代码块标记
|
||||
- 所有字符串值必须用双引号
|
||||
```
|
||||
|
||||
### Q4:返回的内容很长带很多解释
|
||||
|
||||
去系统提示词的"输出风格"加:
|
||||
```
|
||||
- 字段精简,不带多余解释
|
||||
- 不要返回"以下是病历..."这种引导语
|
||||
- 直接返回 JSON 内容本身
|
||||
```
|
||||
|
||||
### Q5:API 调用还是返回"未发布"
|
||||
|
||||
确认右上角状态显示"已发布"。**保存 ≠ 发布**,要单独点"发布"按钮。
|
||||
|
||||
---
|
||||
|
||||
## 9. 进阶:如果你以后想做"处方校验"专用智能体
|
||||
|
||||
可以再建一个智能体,专门校验处方合理性:
|
||||
|
||||
**系统提示词(处方校验版)**:
|
||||
|
||||
```
|
||||
你是一位严谨的中医处方审核专家,负责对医生开具的中药处方进行合理性、安全性校验。
|
||||
|
||||
【校验维度】
|
||||
1. 配伍禁忌:检查是否存在十八反、十九畏
|
||||
2. 剂量合理性:单味药剂量是否超出药典上限
|
||||
3. 证型匹配:药味与辨证是否对应
|
||||
4. 煎法标注:是否标注正确的煎法(先煎/后下/包煎等)
|
||||
5. 委托调剂:是否符合委托调剂规则
|
||||
6. 妊娠禁忌:是否包含孕妇禁用药
|
||||
|
||||
【输出格式】
|
||||
返回 JSON:
|
||||
{
|
||||
"passed": true/false,
|
||||
"issues": [
|
||||
{"level": "error/warning/info", "field": "出问题的字段", "reason": "原因", "suggestion": "建议"}
|
||||
],
|
||||
"summary": "总体评价"
|
||||
}
|
||||
|
||||
【规则】
|
||||
- error 级别必须阻断(如配伍禁忌)
|
||||
- warning 级别提醒医生确认(如剂量偏大)
|
||||
- 严格依据知识库中的"中医配伍禁忌"和"药品库",不主观判断
|
||||
```
|
||||
|
||||
> 处方校验智能体走另一个 App ID,PHP 端按 `prescription_validate` 场景调用即可。
|
||||
|
||||
---
|
||||
|
||||
完成创建后:回 [03_创建应用拿密钥.md](./03_创建应用拿密钥.md) 拿 API Key → 继续 [04_配置GoAgent.md](./04_配置GoAgent.md)
|
||||
106
docs/maxkb-ai/README.md
Normal file
106
docs/maxkb-ai/README.md
Normal file
@@ -0,0 +1,106 @@
|
||||
# MaxKB 知识库接入教程(零基础版)
|
||||
|
||||
> 本教程面向**没接触过 MaxKB / RAG / Go Agent** 的同学,从 0 开始一步步带你把中医知识库接到 AI Agent 上。
|
||||
>
|
||||
> 跟着做完后,效果:医生开病历 / 开处方时,AI 会先去知识库里查"煎法 / 委托调剂 / 中医证候 / ICD-10 / 药品库"等固定资料,再生成回答,结果更准、幻觉更少。
|
||||
|
||||
---
|
||||
|
||||
## 这个东西是干嘛的?
|
||||
|
||||
打个比方:
|
||||
- **现在的 AI**:凭脑子里的训练知识回答(脑子里的知识可能过时、可能记错)
|
||||
- **接入 MaxKB 后的 AI**:回答前先去你的资料库翻书,把翻到的内容当作参考再回答(更准、更可控)
|
||||
|
||||
```
|
||||
医生发起请求 ──▶ AI 先去 MaxKB 查相关资料 ──▶ 资料塞进提示词 ──▶ AI 结合资料生成答案
|
||||
↑
|
||||
你录入的知识库
|
||||
(煎法、证候、药品、ICD-10…)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 你需要准备什么
|
||||
|
||||
| 准备项 | 说明 |
|
||||
|---|---|
|
||||
| 一台能装 Docker 的服务器 | 推荐 Linux(你已经在用 1Panel,最简单) |
|
||||
| 服务器至少 4G 内存 | MaxKB + 向量库吃内存,2G 会卡 |
|
||||
| 服务器开放一个端口给 MaxKB | 比如 `8081`(**不要用 8080**,会和 Go Agent 冲突) |
|
||||
| 知识库资料(已为你准备好) | [storage/maxkb_seed/](../../../../opt/1panel/www/sites/xk-api/index/xk-api/storage/maxkb_seed/) 下有 7 个 Markdown 文件 |
|
||||
|
||||
---
|
||||
|
||||
## 学习路径(按顺序看)
|
||||
|
||||
| 文档 | 做什么 | 预计耗时 |
|
||||
|---|---|---|
|
||||
| [01_部署MaxKB.md](./01_部署MaxKB.md) | 在服务器上装一个 MaxKB 平台 | 15 分钟 |
|
||||
| [02_上传知识库.md](./02_上传知识库.md) | 把中医资料传到 MaxKB,让它能搜 | 10 分钟 |
|
||||
| **[MaxKB创建内容.md](./MaxKB创建内容.md)** | **创建智能体时系统提示词/用户提示词/检索参数该怎么填**(直接复制版)| 5 分钟 |
|
||||
| [03_创建应用拿密钥.md](./03_创建应用拿密钥.md) | 在 MaxKB 里建一个"应用",拿到 API 钥匙 | 5 分钟 |
|
||||
| [04_配置GoAgent.md](./04_配置GoAgent.md) | 改 Go Agent 配置文件,让它知道 MaxKB 在哪 | 5 分钟 |
|
||||
| [05_打开PHP开关.md](./05_打开PHP开关.md) | 在数据库里把"启用知识库"的开关打开 | 5 分钟 |
|
||||
| [06_修复检索词Bug.md](./06_修复检索词Bug.md) | ⚠️ **必做**:修复 PHP 不传检索词的 Bug | 10 分钟 |
|
||||
| [07_验证与排错.md](./07_验证与排错.md) | 怎么测试接入是否成功?失败了怎么查? | 按需 |
|
||||
| **[08_本地知识库管理.md](./08_本地知识库管理.md)** | **MaxKB 免费版没有检索 API?改用本地知识库**(零部署、零成本) | 15 分钟 |
|
||||
|
||||
> **怎么选 MaxKB vs 本地知识库?**
|
||||
>
|
||||
> - 你的 MaxKB 是**专业版(Pro)** → 走 [01-07](./01_部署MaxKB.md),体验最好(支持语义检索)
|
||||
> - 你的 MaxKB 是**免费版** → 直接跳到 [08_本地知识库管理.md](./08_本地知识库管理.md),5 步搞定
|
||||
|
||||
**全部做完总耗时:约 55 分钟**
|
||||
|
||||
---
|
||||
|
||||
## 整体架构图(看一眼就懂)
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ 你的服务器 │
|
||||
│ │
|
||||
│ ┌──────────────┐ 检索 ┌──────────────────┐ │
|
||||
│ │ MaxKB 平台 │ ◀───────────── │ Go Agent │ │
|
||||
│ │ (端口 8081) │ ────────────▶ │ (端口 8080) │ │
|
||||
│ │ │ 返回文档片段 │ │ │
|
||||
│ │ 你的中医资料 │ │ - 拼 system 消息 │ │
|
||||
│ │ (煎法/证候) │ │ - 调 DeepSeek │ │
|
||||
│ └──────────────┘ └────────┬─────────┘ │
|
||||
│ │ HTTP │
|
||||
│ ▼ │
|
||||
│ ┌──────────────────┐ │
|
||||
│ │ PHP (xk-api) │ │
|
||||
│ │ │ │
|
||||
│ │ - 拼业务提示词 │ │
|
||||
│ │ - 调 Go Agent │ │
|
||||
│ │ - 写入数据库 │ │
|
||||
│ └────────┬─────────┘ │
|
||||
│ │ │
|
||||
└────────────────────────────────────────────┼──────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ 医生小程序 │
|
||||
└──────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常见名词解释(小白专用)
|
||||
|
||||
| 名词 | 大白话解释 |
|
||||
|---|---|
|
||||
| **MaxKB** | 一个开源的"知识库 + AI"平台,你把资料扔进去,它帮你建索引、做检索,AI 调它就能"翻书" |
|
||||
| **RAG** | Retrieval-Augmented Generation,检索增强生成。就是"先翻书再回答"的技术统称 |
|
||||
| **知识库** | MaxKB 里的概念,相当于一个文件夹,装着一堆相关文档 |
|
||||
| **应用 / 智能体** | MaxKB 里的概念,相当于"一个对外开放的 API 入口",关联到一个或多个知识库。<br>⚠️ **注意版本差异**:MaxKB **老版(1.x/2.x)叫"应用"**,**新版(4.x)叫"智能体"**。两个是同一个东西,底层 API 完全一样。如果你界面里看到的是"智能体",把它当"应用"看就行。 |
|
||||
| **API Key** | 一串密码,调 API 时带着它证明"我是合法用户"。老版以 `application-` 开头,新版可能是 `application-` 或 `agent-` 开头 |
|
||||
| **App ID** | 应用 ID,类似"应用编号",UUID 格式(8-4-4-4-12),调 API 时拼在 URL 里 |
|
||||
| **向量化** | 把文字转成数字数组的过程,方便算相似度。MaxKB 自动做,你不用管 |
|
||||
| **TopK** | 检索时返回"最相关的前 K 条",K 一般填 5(既够用又不刷屏) |
|
||||
|
||||
---
|
||||
|
||||
下一步:开始 [01_部署MaxKB.md](./01_部署MaxKB.md)
|
||||
Reference in New Issue
Block a user